nextv2.0.0
Chain file keys

Result file

The JSON file a task writes at $KRAFT_RESULT_PATH, and every field Kraft reads from it.

Every agent and subprocess task gets KRAFT_RESULT_PATH in its environment: the path of a JSON file it writes before it exits. Kraft reads the task's status, findings, verdict, and usage back from it. The file is run/results/<session id>.json under $KRAFT_HOME, and it stays after the session ends.

Who must write it

  • An agent task must. Kraft's instructions to every agent say what to write. An agent that exits cleanly without a result file ends failed.
  • An agent's turn must not leave a background job running. For a harness that declares a log format, a turn that ends with one ends the task failed, even when the file says done. A needs_context stop keeps its status. The last line of the session log and a background_jobs_abandoned event name each job.
  • A subprocess task may. Without one, its exit code decides. See Subprocess tasks.

Examples

A review that found one problem:

$KRAFT_RESULT_PATH
{
  "status": "done",
  "session_summary_ref": ".engineering/sessions/2c1f.md",
  "findings": [
    {
      "severity": "important",
      "message": "The retry loop never backs off, so a down server gets hammered.",
      "file": "src/client.py",
      "line": 42,
      "source_plugin": "code-review"
    }
  ]
}

A fix-loop judge's ruling, with its reasoning in concerns:

$KRAFT_RESULT_PATH
{
  "status": "done",
  "verdict": "stop_needs_human",
  "concerns": "The same two findings came back after three repairs."
}

A task that cannot go on without an answer:

$KRAFT_RESULT_PATH
{
  "status": "needs_context",
  "question": "Which of the two config loaders should the new key go through?"
}

Fields

The file is one JSON object. Kraft ignores keys it does not know.

FieldTypeRead fromMeaning
statusstringevery taskHow the task went. See status.
concernsstringevery taskWith done_with_concerns, why. From a judge or a gate review, the reasoning.
questionstringevery taskWith needs_context, what the task needs to know. The item stops with it.
session_summary_refstringevery taskThe session summary's path, relative to the repo root.
findingsarraymeasuring tasksWhat a review or check found. See findings.
verdictstringa fix-loop judge, a gate's auto_reviewSee verdict.
suggested_actionobjectthe last task a node ran before it stoppedWhat a person should do next. See suggested_action.
usageobjectevery taskToken counts. See usage.
cost_usdnumberevery taskWhat the session cost. See usage.
modelstringevery taskThe model that did the work.

status

ValueSet byMeaning
doneThe taskThe task finished.
done_with_concernsThe taskThe task finished but doubts the result; concerns says why. The node goes on. A repair in an on_failure recovery that ends this way stops the item and waits for you.
failedThe taskThe task could not finish.
needs_contextThe taskThe task is missing information; question says what. The item stops and waits for you, with the question.
config_errorKraftThe task could not run as configured, for example a command that does not exist.
capped_outKraftA cap or a wait ran out.
pausedKraftYou paused the item.

A task never writes the three Kraft statuses. A file that is not valid JSON, is not UTF-8, has no status, or has a status that is not one of the four task values ends the task failed, and that includes a file that names a Kraft status. An empty file counts as no file. See how the status is decided.

A task that needs an answer should ask for everything at once: each question costs a new run.

findings

Each entry is an object:

KeyRequiredMeaning
severityyescritical, important or minor. Which ones open a fix loop is findings.loop_severities in policy.yaml.
messageyesWhat is wrong and why.
source_pluginyesWho found it, such as code-review.
filenoThe path, relative to the repo root.
linenoAn integer. Not part of the finding's identity, so an approximate line is fine.
same_asnoThe 16-character tag of a finding from an earlier round that this one restates. Only a tag the task was shown counts; any other is ignored.

An entry missing a required key, or with an unknown severity, is dropped. The findings_measured event counts dropped entries under dropped, per task.

A finding's identity across rounds is its same_as, or else a hash of source_plugin, file and message. The fix loop's stuck check and the judge's history read it. See Fix loop and judge.

verdict

Written byValuesAnything else
A fix loop's judgecontinue, stop_needs_human, stop_downgrade. See The judge.continue
A gate's auto_reviewapprove, reject, fixed (it repaired the worktree and the node runs again), undecided. reject and fixed need concerns, which becomes the steer for the re-run.undecided: the gate waits for you

A verdict from a task that ended failed or needs_context does not count, whatever it says: Kraft reads it as the "Anything else" value in the table.

suggested_action

A recovery that concludes no repair can help ends failed and writes a suggested_action:

$KRAFT_RESULT_PATH
{"status": "failed", "suggested_action": {"action": "retry", "reason": "the registry was down"}}

action is skip, retry or abandon, and reason is one sentence. Any other action is ignored. When the item stops, kraft view show prints the reason and the one command that takes the action, in this form:

retry: <reason>
run: kraft item retry <ID>

The command is kraft item skip ID, kraft item retry ID, or kraft item abandon --yes ID. With no reason, the first line is the action alone.

A stop caused by infrastructure always suggests retry, with no recovery involved. Infrastructure here means a CI pipeline that failed for the forge's own reasons, an automated reviewer that errored, or a cancelled run with no successor coming.

usage

Kraft reads a session's tokens and cost from the result file first, and from the agent's log after that when the harness declares a log format. A harness that reports usage only through the result file is asked to write it there.

KeyMeaning
usage.input_tokensInput tokens used.
usage.output_tokensOutput tokens used.
usage.cache_creation_input_tokensCache-write tokens, counted as billed input.
usage.cache_read_input_tokensCache-read tokens, counted as billed input.
cost_usdWhat the session cost, at the top level of the file, not inside usage. Also read as total_cost_usd. Leave it out when you do not know it, rather than guess.
modelThe model that did the work, at the top level of the file.
  • Subprocess tasks: how a command's exit code and result file become a status.
  • Fix loop and judge: how findings and a judge's verdict drive the loop.
  • Events: findings_measured and the other events a result file produces.
Copyright © 2026