v2.0.0next
HTTP API

The work item object

The three shapes a work item answers in, its stored columns, and the fields that need an explanation, from its status and stop to its budget cap and plan progress.

A work item reaches a client in three shapes, and the route entries name the one each answers with. This page lists the fields of each shape, then explains the ones that need it.

The three shapes

ShapeAnswered byWhat it holds
The stored rowA gate's approve or reject, skip, complete, cancel, and a resume or retry that stops at once.Every column of the item's row, as saved.
The list rowOne per item in GET /api/work-items.A short subset of the columns, and a few computed fields.
The detail objectGET /api/work-items/{id}.The stored row, and the computed fields below.

The stored row

The stored row has one key per column of the item's row. A column that holds JSON comes as text, except the three override columns, which are decoded. It has none of the computed fields, such as display_status, stop or budget_cap.

ColumnTypeMeaning
idstringThe item's id.
titlestringOne line of plain text.
descriptionstring or nullThe brief the agents are given.
repostringThe absolute path of the connected repo.
statusstringactive, needs_human, waiting, rate_limited, paused, completed or abandoned. Work item statuses says what each means.
chain_templatestring or nullThe chain named when the item was filed, or null when none was named.
chain_definitionstring"{}" on an item filed now. The chain is in materialized_chain.
materialized_chainstring or nullThe chain the item runs, frozen when it was filed, as JSON text. null on a row filed before chains were frozen.
run_chainstring or nullThe frozen chain of the run fork the item is executing, as JSON text. null until the first retry, when the filed chain is the run.
current_node_idstring or nullThe node the item stands on. null before it first runs.
current_stepintegerThe step group of that node it last began. 0 unless a wait or a retry resumed the node past its first group.
stop_kindstring or nullWhy the item is stopped, while it is needs_human, waiting or rate_limited. null otherwise. See stop.kind.
retry_atstring or nullWhile rate_limited, when the limit resets and the item may relaunch. null otherwise.
pending_steer_contextstring or nullThe note left while the item was paused, which the next agent launch takes.
escalation_session_idstring or nullThe agent CLI's own session id for the item's escalation thread. null until the first escalation turn.
base_refstring or nullThe commit the item's diff is measured against. null until the item first runs.
branchstring or nullThe git branch the item's worktree, merge request and merge all name. null on a row filed before the column existed, which uses kraft/<id>.
ci_pipeline_refstring or nullThe pipeline the last CI read pinned, as <head_sha>:<pipeline_id>. Empty until the first poll.
bead_idstring or nullThe item's own bead.
bead_cwdstring or nullThe directory of the bd workspace the bead lives in. null on an older row, which uses the instance-wide one.
implements_beadsstring or nullThe bead ids the item implements, as a JSON list. null when none.
attachmentsstring or nullThe spec and plan attached at intake, as a JSON list of {kind, path, ...}. null when none.
submodulesstring or nullThe mount paths of a workspace item's members, as a JSON list. null for any other item.
root_merge_policystring or nullA workspace item's root pointer policy, ignore or bump. null for any other item.
auto_gateinteger1 when agent review of the item's auto_escalate gates is armed, 0 when not.
budget_setinteger1 when the item has its own cap choice, held in budget_usd, and 0 when the policy default applies.
budget_usdnumber or nullThe item's own dollar cap. With budget_set 1, null means no cap.
agent_overridesobject or nullThe item's model and effort override, decoded. null when it has none.
node_overridesobjectThe per-node overrides, {node_id: {field: value}}, decoded. {} when it has none.
policy_overrideobject or nullThe item's own policy override, decoded. null when it has none.
archived_at, archived_bystring or nullWhen the item was archived, and whether by you or auto. null when it is not archived.
created_at, updated_atstringWhen the row was made and last changed, as UTC timestamps.

The list row

The list row is built for the board, from one grouped query, so it leaves out the fields that need a lookup per item, apart from a short progress. It has these keys:

  • From the stored row: id, title, description, repo, status, chain_template, current_node_id, bead_id, created_at, updated_at, retry_at, archived_at and archived_by.
  • chain_definition, as the chain's nodes, which the board draws as a stage bar. attachments, as a decoded list, [] when none.
  • pending_gate, the gate waiting on a person, or null.
  • fallback, the fallback launch the item's latest session started on, or null.
  • display_status, stop, step, mr_ref and progress, as explained below.

It has no agent_overrides, node_overrides or policy_override, and none of the keys only the detail has.

The detail object

The detail object is the stored row, with chain_definition replaced by the chain's nodes and attachments by a decoded list, plus the keys below. Fields that need an explanation covers display_status, stop, test_result, budget_cap, running_time, summary, mr_ref, progress, worktree_exists, worker_sessions, scope_runs and fix_target.

KeyMeaning
effective_chainThe chain with the item's node overrides folded over it.
node_overrides_countHow many nodes have overrides.
rate_limit{count, cap}: the relaunches used and allowed. null unless the item is rate_limited and has a current node.
usageThe item's usage per node and in total: tokens, cost and wall time.
reposOne entry per repository of a multi-repo item. [] for a single-repo item.
escalation_threadsOne entry per escalation thread the item has had, oldest first.
worktree_pathWhere the worktree is, or will be, on the server's disk.
head_shaThe worktree's HEAD commit, or null when there is no worktree.
pending_gateThe gate waiting on a person, or null.
pending_rewindA request-changes review waiting to be honored at its target node, or null.
attemptsThe review's compare picker: the pending gate's attempts. [] with no gate pending.
last_review_shaThe commit the last submitted review was made on, or null.
reject_defaultThe node a rejection would re-enter at. null with no gate pending.
gate_artifactThe kind of document the pending gate decides. null with no gate pending, when the gate declares none, or when the file is not on disk.
stop_reasonThe stop's reason text, or null when the item is not stopped.
suggested_action{action, reason}: what the chain or a repair concluded a person should do, where action is skip, retry or abandon. null when none.
deferred_findingsFindings that never entered the fix loop, listed for the person at the gate.
judge_stop_noteFindings a judge chose to stop chasing since the last resolved gate.
concernsThe done_with_concerns text of each session since the last resolved gate, oldest first.
needs_context_questionThe worker's question, while the item is stopped on one. null otherwise.
steerableWhether a note sent now to POST /api/work-items/{id}/steer or /resume would be accepted.

Fields that need an explanation

FieldMeaning
display_statusList and detail. The board's status badge, one of archived, done, cancelled, paused, running, waiting, needs_you, escalated, failed. Read-only and computed on read rather than stored: see Displayed status.
stopList and detail. null unless the item is needs_human, waiting or rate_limited. See The stop field.
test_resultDetail only. The latest changed-test-scope verification run. See The test_result field.
budget_capDetail only. The item's effective dollar cap and spend. See The budget_cap field.
running_timeDetail only. {running_s, cap_minutes}: the seconds any session ran since the last /retry a person made, against the item-wide time_cap_minutes (null for none). The whole field is null for an item with no frozen chain.
summaryDetail only. A run's progress at a glance. See The summary field.
stepList only. {index, count, name, task} or null, which lets the board draw a row. index and count are as in summary.step. name is the step's id, and task is the latest non-escalation session's task id in it.
mr_refList and detail. The item's merge request, {number, url}, or null. The board draws "merged !139" from it.
progressList and detail. The item's place in its plan. See The progress field.
worktree_existsDetail only. See The worktree_exists field.
worker_sessionsDetail only. One entry per session. repository is the workspace member the session ran in, or null for the item's own repository.
scope_runsDetail only. Every command a changed-test-scope task ran. See The scope_runs field.
fix_targetDetail only. Where a request-changes review restarts, while a gate is pending. See The fix_target field.
agent_overrides, node_overrides, policy_overrideStored row and detail, not the list. The item's overrides, null when the item has none, except node_overrides, which is {}. PATCH sets them: see Changing a work item.

Why the item stopped

The stop field

stop is {kind, node, resume_at, reason} on the list. The detail adds task, attempt and facts. On a cap or budget stop it adds limit, and on a budget stop scope.

facts.cause names why an infra stop happened, when Kraft knows. The facts field lists the values. The failed card chooses its action from it, and an infra stop without one reads as a generic infrastructure stop.

A rate_limit stop's facts also carries fallback and fallback_allowed: the stopped task's declared fallback harnesses, and which of those its resolved policy still allows.

stop.kind

stop.kind is one of twelve values: gate, question, cap, budget, failed, conflict, mr_closed, config, infra, stuck, wait and rate_limit. Stop kinds says what each means, and Why did my item stop? gives each stop's reason with its fix.

A needs_human row saved before database migration 45 has no recorded kind. It reads the kind of its stop event, else question for a reason that starts needs_context:, budget where the event carries budget, cap where it carries capped, else failed. A waiting row with none reads wait and a rate_limited one rate_limit.

stop.limit

A cap or budget stop on the detail also carries limit: {path, key, value, maximum} when a PATCH of the item's policy can raise what stopped it, and omits it when none can.

keyWhat it capspath
max_attempts, timeout_minutesA fix loop's attempts or its clock.The node id.
time_cap_minutes, total_time_cap_minutesThe work item's own cap.""
budget_usdOn a budget stop, the item-wide policy dollar cap.""

value is the limit that stopped it, in attempts, minutes or dollars. maximum is the maxima ceiling or null.

Raise it with PATCH /api/work-items/{id} {policy: {<key>: N}} (item-wide) or {policy: {paths: {<path>: {<key>: N}}}}, then POST /api/work-items/{id}/retry.

There is no limit for:

  • a budget stop on the item's own cap (POST /api/work-items/{id}/budget/raise raises that one), on a node, step or task's budget_usd, a token_budget, the daily cap or spend a harness never reported;
  • a node, step or task's time cap;
  • a gate's or wait's timeout;
  • a loops: cap in policy.yaml;
  • exhausted rate-limit retries;
  • a fix loop whose bound the older node_overrides set.

stop.scope

A budget stop on the detail also carries scope, the cap that stopped it:

scopeThe cap
work_itemThe item's own dollar cap.
usdA budget_usd, item-wide or on a node, step or task, or spend a harness never reported. POST /api/work-items/{id}/budget/raise takes work_item and an item-wide usd.
tokensA token_budget.
dailybudget.daily_usd.

Tests and spend

The test_result field

test_result is {scopes: [{command, scope, passed, exit_code, session_id}], passed}, or null when no scope has finished.

  • One entry per scope, passed or failed. scope is null when the repo's table no longer declares the command, and exit_code when none was recorded. passed is true when every scope passed.
  • An area's setup appears only when it failed.
  • A scope still running is left out.
  • No test counts.
  • session_id is the scope's session. Read its log with GET /api/worker-sessions/{id}/log.

The budget_cap field

budget_cap is {cap_usd, source, key, spent_usd, daily}.

  • cap_usd is whichever cap stops the item first: the lower of its own cap and the item-wide budget_usd of its policy. It is null when neither is set. This holds in the API and in kraft view show --json.
  • key says which cap it is, and the PATCH field that changes it: budget_usd for the item's own cap, policy.budget_usd for the policy one.
  • source is item when the item itself set the reported cap, by its own budget_usd or by its own policy override, and policy when it comes from policy.yaml or the chain. So source: item with key: policy.budget_usd means the item's policy override.
  • spent_usd is the item's own, all-time spend.
  • daily is {spent_usd, cap_usd}: the instance's spend since local midnight against policy.budget.daily_usd, the same two numbers as GET /api/budget/today.

POST /api/work-items/{id}/budget/raise (kraft item raise-budget) raises whichever of the two caps stopped the item.

Progress and the worktree

The summary field

summary is a run's progress at a glance:

{"nodes_done": 3, "nodes_total": 8, "gates_passed": 1, "step": {"index": 2, "count": 2} | null}

nodes_done and nodes_total count against the frozen chain. gates_passed is how many of the completed nodes carry a gate after them (gate_after). step is the current node's step (1-based) out of its own steps, read from its latest non-escalation session's task, when the node declares more than one, and null otherwise.

The progress field

progress is {current, total, title, tasks}, or null when the item has no plan to follow. Each task is {n, title, state, sha}. state is done, current or pending, and sha is the short hash of the newest commit on the item's branch that names the task, or null. Rows on the list carry only current, total and title.

The worktree_exists field

worktree_exists is whether worktree_path is a directory on disk. It is false before the item first runs and after its worktree was reclaimed or deleted.

open-worktree, mr-labels and the viewed routes answer 404 when the directory is missing. The message is "this work item has not started, so it has no worktree yet" for an item that never ran, and "this work item's worktree was removed from disk" for one that did. A retry or resume recreates the directory.

diff and compare check the item's base_ref first. Before the first run it is unset: diff answers 200 with an empty diff and base_ref: null, and compare answers 409. With a base_ref set and the directory gone, both answer 404.

The scope_runs field

scope_runs lists every command a changed-test-scope task ran in its node's current pass, in the order each started, across rounds and repositories. Each entry is {session_id, repository, round, command, passed, exit_code?, scope?, area?, setup?, order?, selected?, pending?, node_id, hook_point}. The node's view draws its scopes from it.

  • passed is null until the command finishes.
  • A command its round picked that has not started yet comes last, pending: true with no session_id, while the node is still running.
  • round is the session's fix-loop round, 0 for the first pass. -1 is the repair an on_failure recovery runs inside a fix-loop node, and the re-measure after it.
  • A retry starts a new pass, so the list keeps only the newest one.
  • It is empty for a chain with no such task.

The fix_target field

fix_target is {gate, node, then, round} while a gate is pending, and null with none pending.

KeyMeaning
gateThe pending gate.
nodeThe node a request-changes review restarts at.
thenThe nodes that run from there before the work returns to the gate.
roundThe round a rejection now would start, {n, max}, counted against the cap the gate's reject loop already snapshotted. null when no cap applies.

GET /api/work-items/{id}/fix-target answers the same shape for a target the reviewer picked: see Fix target.

Copyright © 2026