Skip to content

Agent output format

Agent mode (--agent, or --format agent) is a compact, stable text contract for coding agents. It exists alongside JSON, not instead of it: agent mode is for short action acknowledgements that a human can scan and an agent can pattern-match without a JSON parser, while --json remains the complete machine-readable API. See output modes for the high-level picture and the CLI reference for per-command flags.

This page documents the agent format as a contract. Tooling may rely on the guarantees described here.

Selecting the mode

kata list --agent                 # agent text
kata list --json                  # full JSON envelope
kata list --format agent          # equivalent to --agent
kata list --format human          # default terminal output
  • --json and --agent are aliases for --format json and --format agent.
  • Passing several output-mode flags that resolve to the same mode is valid (--format agent --agent). Flags that resolve to different modes are a usage error before the command runs.
  • --quiet is orthogonal: a suppression flag, not a mode. In agent mode it may suppress the OK ... success header where a command already has quiet behavior, but it never suppresses an ERR ... line.
  • --format is reserved globally for output mode. kata import selects its source format with --source-format <kata|beads>.

Stability contract

Agent output is plain UTF-8 with no ANSI styling. Its shape is stable:

  • In non-quiet agent mode the first token is always OK for success or ERR for failure. Success goes to stdout; failure goes to stderr with a nonzero exit code.
  • The second token is the command or record kind: create, comment, list, show, event, and so on. The literal kata appears only on a top-level parse error before a subcommand runs.
  • Remaining first-line fields are stable positional fields where this document specifies them, and key=value otherwise. Field order is part of the contract.
  • New fields may be appended to a line or block. Existing field names, first tokens, and their meanings do not change without an agent-format version bump.
  • List-valued fields are comma-separated with no spaces (labels=bug,safari).
  • Nullable free-form fields are omitted when absent. Agent output never emits sentinel values such as owner=null or owner=unowned, because a user could legitimately choose those exact strings as an owner name.
  • Values containing whitespace, quotes, or control characters are double-quoted with Go/JSON-style escaping; simple tokens stay unquoted.

Version

The current agent format version is 1. A breaking change bumps this integer. Discover it without parsing JSON:

$ kata version --agent
OK version version=0.0.0 agent_format=1

The same value appears as agent_format in kata version --json; the complete JSON schema is documented in the CLI reference. Ordinary command output does not repeat the version, to keep transcripts small.

Errors

ERR list not_found: no .kata.toml ancestor and no git ancestor
Hint: run "kata init --project <name>" in the workspace root, or pass --project <name>
  • The first line is ERR <command> <kind>: <message>.
  • Create idempotency and look-alike conflicts append the existing issues' qualified refs, for example ERR create conflict: 1 existing issue matches this title (example-project#abc4).
  • <kind> reuses the CLI error taxonomy: usage, validation, not_found, conflict, confirm, daemon_unavailable, checks_failed, internal. checks_failed means kata doctor completed and found failed checks; consult its findings for the setup problems and suggested fixes.
  • An optional second line, Hint: <next step>, names a command or flag that can resolve the error. It is always a single line.
  • A top-level parse error, before any subcommand runs, uses kata as the command token: ERR kata usage: unknown command "cretae".
  • In --format json errors include daemon-provided details in error.data and next-step guidance in error.hint when present. An absent or empty hint is omitted. Human errors print that guidance on a second hint: line; agent errors use a separate Hint: line.

Success shapes

Mutations

A mutation line names what happened and which issue changed, with changed= and reused= flags where they apply, followed by block lines:

OK create abc4
Issue: abc4 "Fix login race"
Status: open
OK close abc4
Issue: abc4 "Fix login race"
Status: closed
Reason: done
Evidence: commit:3a401a8
OK delete abc4
Issue: abc4 "Fix login race"
Status: deleted
Undo: kata restore abc4 --agent

An Undo: line is emitted only when the follow-up is factual and mechanically correct. Generic Next: guidance is intentionally not part of the format.

Reads

A read emits an OK <command> count=<n> header followed by one row per record:

OK list count=3
- issue=abc4 status=open priority=2 owner=agent-a labels=bug,safari title="Fix login race" revision=4
- issue=def7 status=open labels=architecture title="Control channel" revision=1
- issue=j9k2 status=closed title="Old task" revision=3

List and search headers include complete=true|false when the daemon returns page metadata. A page with continuation adds next_cursor=...; a list requested with --include-total also adds total=<n>. Treat the cursor as opaque and continue with the same filters. See CLI reference for the CLI flags and HTTP listing for the scan contract.

Empty reads emit the header with count=0 and no rows:

OK search count=0 query="login race"

kata update --check --agent appends package ownership fields after the existing result fields, in this order:

OK update update_available=true current=v0.14.1 latest=v0.14.2 distribution=homebrew upgrade_hint="brew upgrade kata" package_release_may_lag=true

The field order is update_available, current, latest, distribution, optional upgrade_hint, then package_release_may_lag. Ordinary archives emit distribution="" package_release_may_lag=false and omit upgrade_hint. Install-capable forms on package-managed builds use the existing usage error shape and exit code 2:

ERR update usage: Homebrew manages this installation; run 'brew upgrade kata' instead

The check reads Kata's GitHub release feed, so a reported release can appear before the owning package manager publishes it.

Federation quarantine discovery

kata federation quarantine list --agent emits one row per active quarantine:

OK federation-quarantine-list count=1
- project=spoke-project project_id=7 quarantine_id=3 direction=push first_event=41 last_event=44 event_count=4 created_at=2026-07-10T12:00:00Z error="hub rejected batch"

The row field order is project, project_id, quarantine_id, direction, first_event, last_event, event_count, created_at, and error. An empty list emits only OK federation-quarantine-list count=0.

kata federation quarantine show <id> --agent emits the owning project and batch summary followed by one row per quarantined event UID:

OK federation-quarantine-show quarantine_id=3
- project=spoke-project project_id=7 direction=push first_event=41 last_event=44 event_count=4 created_at=2026-07-10T12:00:00Z error="hub rejected batch"
- event_uid=01HZNQ7VFPK1XGD8R5MABCD4EA
- event_uid=01HZNQ7VFPK1XGD8R5MABCD4EB

The event UID rows preserve the order recorded for the quarantined batch. Operators can inspect these read-only commands before invoking the separately confirmed quarantine retry or quarantine skip mutation.

kata search appends a mode= field to its header (lexical, hybrid, or semantic) reporting the strategy actually run. When the embedding endpoint is configured but could not serve a query, the search falls back to lexical and a degraded=<reason> field follows mode=; it is omitted when the query was not degraded. Result rows carry matched= listing the contributing sources (FTS column names), and a row gains semantic in that list when the vector leg matched it:

OK search count=1 query="auth redirect duplicates" mode=hybrid
- issue=abc4 score=0.0312 status=open matched=title,semantic title="Login callback double-submits on Safari" owner=agent-a priority=1 revision=4 excerpt="The callback can submit twice after the auth redirect."

Search rows append owner, priority, revision, and a body excerpt when present. The excerpt is at most 160 characters and centers the first query match when possible, folding case and diacritics like lexical search. kata show <ref> --agent remains the complete record and emits Revision: after Priority:. List rows append revision after title. Existing fields keep their names, positions, and meanings, so agent_format stays 1. A daemon without [search.embeddings] reports mode=lexical and omits degraded=. It includes the same added issue context.

Teams, project access, bridges and root keys

The team and project-access commands follow the mutation and read shapes. teams list is a read with one row per team; teams show reports its members as a comma-separated list and omits members= when the team is empty, as projects access omits teams= for visibility=all:

OK teams count=1
- team=reviewers uid=01HZNQ7VFPK1XGD8R5MABCD4EA revision=2
OK teams-create team=reviewers uid=01HZNQ7VFPK1XGD8R5MABCD4EA
OK teams-show team=reviewers uid=01HZNQ7VFPK1XGD8R5MABCD4EA revision=2 members=alice,bob
OK teams-members-add team=01HZNQ7VFPK1XGD8R5MABCD4EA actor=alice
OK teams-members-remove team=01HZNQ7VFPK1XGD8R5MABCD4EA actor=alice
OK projects-access project=spoke-project visibility=teams revision=3 teams=01HZNQ7VFPK1XGD8R5MABCD4EA

The bridge and root-key commands emit one line each. warning= appears only when the daemon reported one, and key_file= only when the daemon has a key file path:

OK federation-bridge-connect project=spoke-project status=ready direction=bidirectional hub=example-hub upstream_account=member local_account=local-member
OK federation-bridge-status project=spoke-project state=connected direction=bidirectional credential_status=active hub=example-hub upstream_account=member local_account=local-member
OK federation-bridge-disconnect project=spoke-project status=disconnected warning="the hub grant was not revoked"
OK federation-root-key-repin project=hub-project status=ready method=unsigned_repin key_id=01HZ... previous_key_id=01HY... creates_key_file=true active_relay_enrollments=2 key_file=/srv/kata/federation-root.key

Single-result next

kata next --agent is an intentional exception to the usual read shape of a count=<n> header followed by n rows. It emits exactly one compact record when a ready issue is selected:

OK next issue=abc4 priority=1 owner=agent-a title="Fix callback race"

The field order is issue, optional priority, optional owner, then title. Absent priority and owner values are omitted rather than rendered as sentinels. A cross-project selection uses a qualified value such as issue=example-project#abc4.

An empty ready set is also a successful single record:

OK next found=false

With --full, the success header identifies the selected ref and is followed by the same detail fields and sections as kata show --agent:

OK next abc4
Issue: abc4 "Fix callback race"
Status: open
Owner: agent-a
Labels: bug
Priority: 1

The show sections for labels, body, metadata, links, comments, and leases are included when present. Their existing ordering and omission rules apply.

Compact issue status

kata status <ref> --agent keeps the authenticated identity, assignment, and lease state separate on one line:

OK status issue=abc4 project=example-project issue_status=open revision=4 actor=agent-a actor_source=daemon auth=db_token instance=01HZNQ7VFPK1XGD8R5MABCD4AB owner=agent-a assignment_expires_on=2026-09-02T12:30:00Z hold=assigned

The fixed field order is issue, project, issue_status, revision, actor, actor_source, auth, instance, optional owner, optional assignment_expires_on, and hold. An active or expired lease then appends optional holder, holder_instance, lease_kind, and expires_at; pending leases append pending_leases. Hold state is one of active, expired, pending, assigned, unassigned, or closed. assigned identifies an open issue with a live owner assignment and without a live or pending lease. A successful temporary kata claim yields hold=assigned and assignment_expires_on; once due it yields hold=expired until cleanup records the expiry, then hold=unassigned until another hold applies. actor_source is daemon when the daemon authenticated the actor; otherwise it is the client-side source reported by kata whoami. Use kata show <ref> --agent when the body, comments, metadata, links, or lease violations are needed.

Events

Non-tail reads use a header plus rows; tail mode is stream-safe and emits exactly one line per event:

OK events count=2 next_after_id=44
- id=42 type=issue.created issue=abc4 actor=agent-a
- id=43 type=issue.commented issue=abc4 actor=codex
OK event id=42 type=issue.created issue=abc4 actor=agent-a

kata events --tail --json is newline-delimited JSON; kata events --tail --agent is one agent line per event and never emits multi-line blocks.

Multiline text

Bodies and comments are preserved in fenced text blocks:

OK show abc4
Issue: abc4 "Fix login race"
Status: open
Revision: 4
Body:
```text
Safari can double-submit the callback.
```
  • No silent truncation is allowed. If truncation is ever introduced, the metadata fields immediately precede the field they describe and are emitted as a pair, <Field>-Truncated: true and <Field>-Bytes: <full-byte-count>, never one without the other.
  • A fenced block uses at least three backticks and the text info string. If the content itself contains a triple-backtick sequence, a longer fence is chosen so the block stays valid Markdown.

Guarantees

  • --json is never weakened or removed; it stays the complete structured API.
  • Agent mode does not change daemon API responses; it is purely a CLI rendering of the same data.
  • Agent mode is not the default.
  • Interactive commands (kata tui) and daemon startup (kata daemon start) reject agent mode with a usage error rather than launching.