Skip to content

FLT-2 · run_agent result contract (canonical schema)

Status: v1 — frozen 2026-07-14. Two implementations follow this document and must stay byte-compatible on the wire:

Implementation Language Where
fleet-harness wrappers Python src/fleet_harness/contract.py (this repo)
fleet-dispatch run-agent C# fleet-dispatch repo (separate session, in flight)

Changing a field means changing both implementations and bumping the version note here in the same change. The Python wrappers are shaped so they can later delegate to fleet-dispatch run-agent as a subprocess — identical shapes are what make that swap a one-line change.

Shape

Every agent invocation — any vendor CLI, local Ollama, or the future C# host — resolves to exactly one JSON object:

{
  "status": "completed",
  "summary": "Added null-guard to PathFor and a regression test.",
  "changed_files": ["src/Store/PathFor.cs", "tests/PathForTests.cs"],
  "tests_attempted": ["dotnet test → 174/174 passed"],
  "known_risks": ["traversal behavior on UNC paths untested"],
  "needs_human_review": false
}

Fields

Field Type Semantics
status string enum Terminal outcome of the invocation. One of completed, failed, timed_out, rate_limited, approval_required. Nothing else, ever.
summary string One paragraph, human-readable, what happened. Empty string allowed, never null.
changed_files string[] Repo-relative paths the agent believes it changed. A claim, not truth — hosts must measure ground truth from git diff (FLT-3). Empty array when nothing changed.
tests_attempted string[] Commands the agent says it ran, with claimed outcomes. Unverified — the validation gate reruns tests itself and its exit code is the only trusted signal.
known_risks string[] Anything a reviewer should double-check. Hosts may append their own entries (e.g. "CLI exited 1 despite completed claim").
needs_human_review bool Agent or host asserts a human must look before this work lands. Hosts may set it true; they must never set it false over an agent's true.

status semantics

Value Meaning Host reaction
completed Agent believes the task is done. Proceed to review + validation. Belief ≠ truth.
failed Errored or gave up. Escalate to next agent on the ladder.
timed_out Host killed it at the timeout. Escalate; consider retry with larger budget.
rate_limited Vendor throttled the account. Escalate to a different vendor now; this vendor retries later.
approval_required Agent stopped at a decision it may not make (destructive step, ambiguous spec). Route to the human gate with whatever partial work exists.

Parsing rules (defensive, both implementations)

CLI agents emit free-form text; the contract block is requested via a prompt suffix, so parsing must survive non-compliance:

  1. Prefer the last fenced ``json block containing a"status"` key.
  2. Else the last bare top-level {...} that parses and has "status".
  3. Unknown status string → coerce to failed (a malformed claim of success is not success).
  4. Unknown extra fields → drop. Missing list fields → empty list. Missing needs_human_reviewfalse.
  5. Nonzero process exit + "completed" claim → downgrade to failed, append a known_risks entry, set needs_human_review: true.
  6. No parseable block at all: exit 0 → completed with output tail as summary, a known_risks note, and needs_human_review: true; exit ≠ 0 → failed. Rate-limit markers in output → rate_limited.

Invocation quirks the host owns (not part of the wire shape)

  • codex exec --json <prompt> — parse the JSONL event stream.
  • claude -p <prompt>.
  • agy --model "Gemini 3.1 Pro (High)" -p <prompt>never -m; stdin must be closed (< NUL / stdin=DEVNULL) or agy hangs.
  • grok -p <prompt> — prompt hard-capped at 32 KB.
  • All agents run with stdin closed, inside an isolated git worktree, under a host-owned timeout. Hosts own worktree creation, diff collection, retries, and escalation — agents never do.