A task is a work item seen through the API: one request with its conversation, runs and outputs. A run is one agent execution. The foreman path starts several runs per task; agents can start subagents, so runs form a tree whose first run is the task's root. When a stage finishes, the foreman adds a short update to the conversation, for example "Implement done. Next: Verify." When a run ends on a temporary platform error (the network or the egress proxy away during a restart, a provider overloaded), Kiln retries it after 5 s, 20 s and 60 s, and then runs the stage again after 1, 2, 5, 10, 20 and 30 minutes. None of this reaches the conversation or asks anyone; the task stops only when all of it fails.
Dispatching work
curl -X POST "$KILN_URL/api/v1/factories/webapp/runs" -H "authorization: Bearer $KILN_TOKEN" \
-H 'content-type: application/json' \
-d '{"prompt": "Fix the rounding bug in invoices", "ticket_ref": "linear:PAY-123", "mode": "plan"}'The reply has taskId, the first runId when one started, runUrl, state and foremanAgent. ticket_ref is <source>:<id> (linear:, jira:, github:owner/repo#12, or anything else, kept as is). branch makes the task work on that branch.
One task per incident: a report that matches an open task joins it instead of starting new work. The match is by identity first: correlation_key (an incident id or alert fingerprint), alert payload fields such as fingerprint, dedup_key or incident_id, the tracker issue, the source URL or the pull request. Reports from a different source (an alert and a Slack message) also match by content when they share enough salient words such as service names, hosts and error codes. The reply then carries deduplicated: { into, reason, score } (POST /api/v1/work-items answers 200 instead of 201), the report and its files are added to the task, and every place it was reported hears the updates. Pass "dedupe": false to always start a new task. The triage agent can also fold a task into an open one it recognises as the same work. Tune it per factory:
deduplication: { enabled: true, windowHours: 24, threshold: 0.5 }Modes: normal; plan (the factory always writes a plan or spec first and waits for a person to approve it before anything is built); orchestrate (the foreman and implement agents are told to split the work across subagents).
Task stages
| Stage | Kiln states |
|---|---|
TRIAGE |
received, triaging |
SPEC |
planning, awaiting_spec |
IMPLEMENT |
building, awaiting_preview |
REVIEW |
reviewing, handed_off |
COMPLETE |
complete |
CANCELLED |
cancelled, failed |
PATCH …/tasks/{id} may set any stage. COMPLETE needs decide:merge and closes the task as a person's confirmation; CANCELLED cancels it and every run and subagent still going. DELETE is a soft delete. Task outputs (PLAN, PULL_REQUEST, SCREENSHOT, FILE, EXTERNAL_REFERENCE) come newest first.
Run states and sources
| State | Meaning |
|---|---|
QUEUED |
Waiting for a self-hosted worker. |
CLAIMED |
A worker took it and is preparing the sandbox. |
INPROGRESS |
The agent is working. |
BLOCKED |
Waiting on a person: an interrupt or a paused run. |
SUCCEEDED, FAILED, ERROR, CANCELLED |
Finished. FAILED means the task could not be done as asked; ERROR means the platform failed. |
The coarse task_status filter groups them: running, blocked, failed, cancelled, complete. Each run also has a source (LINEAR, SLACK, GITHUB_WEBHOOK, API, CLI, MCP, WEB_APP, SCHEDULED_AGENT, ORCHESTRATION, SELF_IMPROVEMENT, BENCHMARK_TRIAL, CUSTOM_WEBHOOK, …), a title, creator and executor, rootRunId, and up to 20 immutable metadata keys you can filter on with metadata[key]=value.
GET /api/v1/runs filters by state, task_status, source, factory_uid, ancestor_run_id, artifact_type, q, creator, mine=true, dates and metadata, sorts with sort_by, and pages with cursor.
Errors
Errors carry a code from the catalog (GET /api/v1/errors): for example budget_exceeded, insufficient_credits, integration_not_configured, environment_setup_failed (FAILED) and internal_error, resource_unavailable, infrastructure_timeout, agent_process_failed (ERROR). Kiln retries internal_error and resource_unavailable on the same run up to three times before it reports the run.
Talking to a run
POST /runs/{id}/followups {message, attachments}steers a live run, or continues a finished one in a new run with the same agent, branch and task.POST /runs/{id}/interruptstops what the agent is doing; the run isBLOCKEDuntil a follow-up.GET /runs/{id}/timeline,/conversationand/transcriptshow what happened;/scoresits scores.PUT /runs/{id}/sharing {publicAccess: "VIEWER" | "EDITOR" | null}shares the run with signed-in people who cannot otherwise see the factory.- With the factory's
followUpPermission: RUN_CREATOR, follow-ups, steering and interrupts come only from the person who started the run (the first run of a continuation chain), its task's requester, or a factory admin; others getnot_authorized(403). See factory.yaml. - Agents stay alive for follow-ups for
idleTimeoutMinutes(default 10, 60 for subagents).
Subagents and run tokens
A running agent gets KILN_RUN_TOKEN and the Kiln MCP server. With it, it may:
- read its own task and the runs of its task or run tree, message its task, and upload files;
- start subagents:
POST /runs/{id}/spawn(MCPspawn_agent) or several at once withrun-agents(run_agents). The child'sspawnableBydecides who may start it; nesting stops at five levels. Three options shape a subagent:name: lowercase letters, digits and dashes, unique among the runs of the tree. The agent can then use the name instead of the run id infollowups,interruptand the other run calls. A continuation keeps the name, so it always means the latest run of that line of work.fork: true: the child's prompt starts with the parent's conversation so far (its request, its messages and people's steering), then the brief. Without it the child gets only the brief.report: true: when the child finishes, fails, is stopped or runs out of budget, or asks a question, the parent gets a follow-up with a report: the child's name, title, summary, branch, the reason (finished,failed,stopped,out_of_budgetorneeds_input) and the question. A live parent is steered with it; a parent that finished continues in a new run. No polling is needed;
- ask the requester a question (
POST /runs/{id}/questions, MCPask_user) with single- or multi-select options and a recommended option, and read the answer from the gate; - propose a definition change (
propose_definition_change) that people review in the inbox; - call
complete_task, which closes the task only after its pull request merged.
A run token cannot decide gates, write definitions, see other tasks or factories, merge or approve.