output-formats.md

July 4, 2026 · View on GitHub

acpx streams agent activity in three output modes plus two modifiers. Pick the one that matches your consumer: a human terminal, an automation pipeline, or a script that only wants the final answer.

text (default)

Human-readable stream:

  • assistant text as it arrives
  • [thinking] blocks for reasoning chunks
  • [tool] <title> (<status>) blocks with output, diff previews, and plan updates
  • [done] <stopReason> at the end
acpx codex 'review the auth module'
[thinking] Reading src/auth and looking for token validation
[tool] Read src/auth/index.ts (completed)
[tool] Run grep -n 'verifyToken' src/auth (completed)
  output:
    src/auth/jwt.ts:42:export function verifyToken
The auth module is structured as …
[done] end_turn

text is best for interactive use. It is not stable for parsing — error messages, prompts, and progress updates can change between releases.

json

NDJSON stream of raw ACP JSON-RPC messages on stdout:

acpx --format json codex exec 'review changed files' \
  | jq -r 'select(.method=="session/update")'
{"jsonrpc":"2.0","id":"req-1","method":"session/prompt","params":{"sessionId":"019c…","prompt":"hi"}}
{"jsonrpc":"2.0","method":"session/update","params":{"sessionUpdate":"agent_message_chunk","content":{"type":"text","text":"Hello"}}}
{"jsonrpc":"2.0","id":"req-1","result":{"stopReason":"end_turn"}}

Hard rules for json:

  • No acpx-specific event envelope wrapping ACP messages.
  • No synthetic type / stream / eventVersion keys injected onto raw ACP traffic.
  • No payload key renaming.

What you read on stdout is the same wire-level JSON that would have crossed the ACP transport, in submission order.

compare is the exception because it runs multiple one-shot sessions and emits a summarized CompareRow[] payload under --format json instead of interleaving raw ACP streams.

stderr can still contain prompts, progress, or warnings. If your script reads only stdout, that is fine. If you pipe both, see --json-strict below.

--format json --json-strict

Strict JSON suppresses non-JSON output that would otherwise land on stderr:

acpx --format json --json-strict codex exec 'list TODO comments' > events.ndjson

--json-strict requires --format json. It guarantees:

  • stdout is one ACP JSON-RPC message per line
  • stderr stays quiet for non-error informational output

This is the right combination for "fully machine-consumed pipelines that should fail visibly on real errors."

quiet

Final assistant text only — no tool blocks, no thinking, no [done]:

SUMMARY=$(acpx --format quiet codex exec 'one-line summary of this branch')
echo "$SUMMARY"

When the adapter includes final token usage and cost metadata in the prompt result, acpx emits that to stderr in quiet mode. stdout stays as the assistant text only.

If a quiet prompt fails, acpx exits non-zero and emits exactly one single-line diagnostic to stderr:

[acpx] error: <CODE> [<DETAIL_CODE>] <message>

DETAIL_CODE is omitted when unavailable. Embedded line endings in the message are replaced with spaces. The diagnostic never goes to stdout; quiet stdout remains reserved for any assistant text the adapter produced. This stderr contract applies to direct and queued prompts; it does not change the json or --json-strict streams.

quiet is unaffected by --suppress-reads because it does not print tool call output to begin with.

--suppress-reads

Replaces raw read-file payloads with a placeholder so logs stay readable when an agent reads a large file:

ModeEffect of --suppress-reads
textRead-like tool outputs render as [read output suppressed].
jsonACP fs/read_text_file responses and read-like tool-call outputs replace raw contents.
quietNo effect (quiet mode prints assistant text only).
acpx --suppress-reads codex exec 'inspect repo and report tool usage'

The replacement preserves the surrounding ACP message shape so json consumers can still parse the stream — only the content payload is masked.

Session-control command output

Session-control query commands emit summarized JSON shapes (not ACP wire traffic) under --format json:

Commandtextjsonquiet
sessions listTSV: id title cwd updatedAt meta{ _meta, source, sessions, cursor, cwd, nextCursor } for ACP list, or local records with --local/fallbackone id per line
sessions showkey/value linesfull session record objectrecord id
sessions historyTSV: timestamp role textPreview{ entries: [...] }record id
sessions prunesummary + pruned ids and time{ action, dryRun, count, bytesFreed, pruned }one pruned id per line
sessions new/ensurerecord idrecord + acpxRecordId/acpxSessionId/(agentSessionId)record id
statuskey/value linesfull status objectstate token

Closed sessions are marked [closed] in text and quiet.

Identity fields in JSON

Session-control JSON always includes:

FieldMeaning
acpxRecordIdLocal record id (also what text/quiet print)
acpxSessionIdAcpx-side session id
agentSessionIdProvider-native id, only present when the adapter exposes one

Do not assume the acpxRecordId can be passed to a native provider CLI. Use agentSessionId for that, when present.

Picking a mode

Use casePick
Interactive use, you are the readertext (default)
Save full transcript for later replayjson (or --format json --json-strict)
Pipe into jq and parse events--format json or --json-strict
Capture only the final answer in a script--format quiet
Long agent runs that read large filesadd --suppress-reads
Anywhere stdout must be 100% JSON--format json --json-strict

See also