Streaming JSON
Amp’s CLI can print each message as a JSON object on its own line. Use this output for programmatic integrations or to monitor a conversation as it runs.
Basic Usage
Use --stream-json with --execute to output streaming JSON instead of plain text.
Pass a prompt as an argument:
$ amp --execute "what is 3 + 5?" --stream-json Continue an existing thread:
$ amp threads continue --execute "now add 8 to that" --stream-json Provide the prompt through stdin:
$ echo "analyze this code" | amp --execute --stream-json Streaming JSON input mode (see below for more information):
$ echo '{"type":"user","message":{"role":"user","content":[{"type":"text","text":"what is 2+2?"}]}}' | amp --execute --stream-json --stream-json-input The --stream-json flag requires --execute mode. Add --stream-json-thinking to include
assistant thinking blocks. This extends the schema and is not compatible with Claude Code.
Each conversation starts with an init system message. User and assistant messages follow, and a
final result message contains the result and run statistics. Amp emits each message as a separate
JSON object.
Example Output
Simple math query:
$ amp --execute "what is 3 + 5?" --stream-json
{"type":"system","subtype":"init","cwd":"/Users/orb","session_id":"T-f9941a55-3765-421e-972f-05dc1138c3a3","tools":["Bash","create_file","edit_file","glob","Grep","mcp__postgres__query","Read","read_mcp_resource","read_web_page","Task","todo_read","todo_write","undo_edit","web_search"],"mcp_servers":[{"name":"postgres","status":"connected"}]}
{"type":"user","message":{"role":"user","content":[{"type":"text","text":"what is 3 + 5?"}]},"parent_tool_use_id":null,"session_id":"T-f9941a55-3765-421e-972f-05dc1138c3a3"}
{"type":"assistant","message":{"type":"message","role":"assistant","content":[{"type":"text","text":"8"}],"stop_reason":"end_turn","usage":{"input_tokens":10,"cache_creation_input_tokens":16256,"cache_read_input_tokens":0,"output_tokens":99,"max_tokens":968000,"service_tier":"standard"}},"parent_tool_use_id":null,"session_id":"T-f9941a55-3765-421e-972f-05dc1138c3a3"}
{"type":"result","subtype":"success","duration_ms":5400,"is_error":false,"num_turns":1,"result":"8","session_id":"T-f9941a55-3765-421e-972f-05dc1138c3a3"} Tool usage example:
$ amp --execute "list files using a tool" --stream-json
{"type":"system","subtype":"init","cwd":"/Users/orb/project","session_id":"T-d2fc4acc-dd1d-497f-9609-ed0da22a7c95","tools":["Bash","create_file","edit_file","glob","Grep","mcp__postgres__query","Read","read_mcp_resource","read_web_page","Task","todo_rea d","todo_write","undo_edit","web_search"],"mcp_servers":[{"name":"postgres","status":"connected"}]}
{"type":"user","message":{"role":"user","content":[{"type":"text","text":"list files using a tool"}]},"parent_tool_use_id":null,"session_id":"T-d2fc4acc-dd1d-4 97f-9609-ed0da22a7c95"}
{"type":"assistant","message":{"type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_019cyniPYrSgaJitUSMyxyNV","name": "read", "input":{"path":"/Users/orb/project"}}],"stop_reason":"tool_use","usage":{"input_tokens":10,"cache_creation_input_tokens":13150,"cache_read_input_tokens": 0,"output_tokens":111,"max_tokens":968000,"service_tier":"standard"}},"parent_tool_use_id":null,"session_id":"T-d2fc4acc-dd1d-497f-9609-ed0da22a7c95"}
{"type":"user","message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"toolu_019cyniPYrSgaJitUSMyxyNV","content":"[\"index.js\",\"README.md\"] ","is_error":false}]},"parent_tool_use_id":null,"session_id":"T-d2fc4acc-dd1d-497f-9609-ed0da22a7c95"}
{"type":"assistant","message":{"type":"message","role":"assistant","content":[{"type":"text","text":"Two files: index.js and README.md"}],"stop_reason":"end_tu rn","usage":{"input_tokens":7,"cache_creation_input_tokens":133,"cache_read_input_tokens":13150,"output_tokens":13,"max_tokens":968000,"service_tier":"standard "}},"parent_tool_use_id":null,"session_id":"T-d2fc4acc-dd1d-497f-9609-ed0da22a7c95"}
{"type":"result","subtype":"success","duration_ms":7363,"is_error":false,"num_turns":2,"result":"Two files: index.js and README.md","session_id":"T-d2fc4acc-dd1d-497f-9609-ed0da22a7c95"} Message Schema
When --stream-json-thinking is enabled, assistant content may include thinking and redacted_thinking blocks.
Messages returned from the streaming JSON API use this schema:
type StreamJSONMessage =
// An assistant message
| {
type: 'assistant'
message: {
type: 'message'
role: 'assistant'
content: Array<
| {
type: 'text'
text: string
}
| {
type: 'tool_use'
id: string
name: string
input: Record<string, unknown>
}
| {
type: 'thinking'
thinking: string
}
| {
type: 'redacted_thinking'
data: string
}
>
stop_reason:
'end_turn' | 'max_tokens' | 'stop_sequence' | 'tool_use' | 'pause_turn' | 'refusal' | null
usage?: {
input_tokens: number
cache_creation_input_tokens?: number
cache_read_input_tokens?: number
cache_creation?: {
ephemeral_5m_input_tokens: number
ephemeral_1h_input_tokens: number
}
output_tokens: number
max_tokens?: number
service_tier?: 'standard' | 'enterprise'
}
}
parent_tool_use_id: string | null
session_id: string
}
// A user message in streaming JSON output
| {
type: 'user'
message: {
role: 'user'
content: Array<
| {
type: 'text'
text: string
}
| {
type: 'tool_result'
tool_use_id: string
content: string
is_error: boolean
}
>
}
parent_tool_use_id: string | null
// Set on the message Amp sends the agent when a background subagent ends: the `id` of
// the `tool_use` that started it
subagent_tool_use_id?: string
session_id: string
}
// A background subagent (a Task call with `mode: "async"`, or a Claude Code `Agent` call that
// runs in the background) stopped running
| {
type: 'system'
subtype: 'subagent_finished'
// The `id` of the `tool_use` that started it
tool_use_id: string
status: 'completed' | 'failed' | 'cancelled'
session_id: string
}
// The last message when the run succeeds
| {
type: 'result'
subtype: 'success'
duration_ms: number
duration_api_ms?: number
is_error: false
num_turns: number
result: string
session_id: string
usage?: {
input_tokens: number
cache_creation_input_tokens?: number
cache_read_input_tokens?: number
cache_creation?: {
ephemeral_5m_input_tokens: number
ephemeral_1h_input_tokens: number
}
output_tokens: number
max_tokens?: number
service_tier?: 'standard' | 'enterprise'
}
permission_denials?: string[]
}
// The last message when the run fails
| {
type: 'result'
subtype: 'error_during_execution' | 'error_max_turns'
duration_ms: number
duration_api_ms?: number
is_error: true
num_turns: number
error: string
session_id: string
usage?: {
input_tokens: number
cache_creation_input_tokens?: number
cache_read_input_tokens?: number
cache_creation?: {
ephemeral_5m_input_tokens: number
ephemeral_1h_input_tokens: number
}
output_tokens: number
max_tokens?: number
service_tier?: 'standard' | 'enterprise'
}
permission_denials?: string[]
}
// The first message in a conversation
| {
type: 'system'
subtype: 'init'
cwd: string
session_id: string
tools: string[]
mcp_servers: {
name: string
status:
| 'awaiting-approval'
| 'authenticating'
| 'connecting'
| 'reconnecting'
| 'connected'
| 'denied'
| 'failed'
| 'blocked-by-registry'
}[]
agent_mode?: string
// Background subagents still running when this process attached to the thread, for
// example ones an earlier process started before it was killed
subagents: {
// The `id` of the Task `tool_use` that started it
tool_use_id: string
description: string
}[]
}
// A system error
| {
type: 'system'
subtype: 'error_max_turns' | 'error_during_execution'
error: string
session_id: string
} Streaming JSON Input
Use --stream-json-input to let Amp read messages from stdin until it closes. Each line must be a
complete JSON object that uses this schema:
type StreamJSONInputMessage = {
type: 'user'
steer?: boolean
message: {
role: 'user'
content: Array<
| {
type: 'text'
text: string
}
| {
type: 'image'
source_path?: string
source: {
type: 'base64'
media_type: 'image/jpeg' | 'image/png' | 'image/gif' | 'image/webp'
data: string
}
}
>
}
} For example, use jq -c to emit a text and image message as one line:
$ jq -c . <<'EOF' | amp -x --stream-json --stream-json-input
{
"type": "user",
"message": {
"role": "user",
"content": [
{
"type": "text",
"text": "what do you see?"
},
{
"type": "image",
"source_path": "file:///Users/alice/images/example.jpg",
"source": {
"type": "base64",
"media_type": "image/jpeg",
"data": "..."
}
}
]
}
}
EOF source_path is optional. If you omit it, Amp generates one. The declared media_type must match
the decoded image bytes. User image blocks are accepted as input but omitted from streamed user messages on stdout so the output remains compatible with Claude Code.
The --stream-json-input flag requires --stream-json.
When you use --stream-json-input, Amp exits only after the assistant is done and stdin has closed. This allows a program to send several user messages during one conversation.
Amp also waits for background subagents to finish before it exits. The Task tool starts them with mode: "async"; in Claude Code threads, the Agent tool starts them when it runs in the
background. An assistant message with stop_reason: "end_turn" can arrive while they are still
running. When one stops, Amp prints a subagent_finished system message with the id of the tool_use that started it. If it completed or failed, Amp normally then sends the agent a user message about it, marked with the same ID in subagent_tool_use_id, which starts another turn. In
Claude Code threads, Claude Code tells its agent itself, and that user message shows the same
report. The result message is the only signal that the run is over.
Background subagents keep running when the Amp process that started them exits. When you continue
the thread with amp threads continue, the init message lists the ones still running in subagents, and each later ends with its own subagent_finished message.
If you send a message while the agent is busy, Amp queues it. Its user message appears on stdout
when Amp starts the turn for it, not when Amp receives it. Output before that user message
belongs to earlier work, such as a turn that Amp resumes when you continue a thread.
This script sends three messages:
#!/usr/bin/env bash
send_message() {
local text="$1"
echo '{"type":"user","message":{"role":"user","content":[{"type":"text","text":"'$text'"}]}}'
}
{
send_message "what's 2+2?"
sleep 10
send_message "now add 8 to that"
sleep 10
send_message "now add 5 to that"
} | amp --execute --stream-json --stream-json-input This script produces the following output:
$ ./script.sh
{"type":"system","subtype":"init","cwd":"/Users/orb","session_id":"T-addfb7a4-61d9-41e1-890b-7330aa54087a","tools":["Bash","create_file","edit_file","glob","Grep","mcp__postgres__query","Read","read_mcp_resource","read_web_page","Task","todo_read","todo_write","undo_edit","web_search"],"mcp_servers":[{"name":"postgres","status":"connected"}]}
{"type":"user","message":{"role":"user","content":[{"type":"text","text":"what's 2+2?"}]},"parent_tool_use_id":null,"session_id":"T-addfb7a4-61d9-41e1-890b-7330aa54087a"}
{"type":"assistant","message":{"type":"message","role":"assistant","content":[{"type":"text","text":"4"}],"stop_reason":"end_turn","usage":{"input_tokens":10,"cache_creation_input_tokens":13993,"cache_read_input_tokens":0,"output_tokens":67,"max_tokens":968000,"service_tier":"standard"}},"parent_tool_use_id":null,"session_id":"T-addfb7a4-61d9-41e1-890b-7330aa54087a"}
{"type":"user","message":{"role":"user","content":[{"type":"text","text":"now add 8 to that"}]},"parent_tool_use_id":null,"session_id":"T-addfb7a4-61d9-41e1-890b-7330aa54087a"}
{"type":"assistant","message":{"type":"message","role":"assistant","content":[{"type":"text","text":"12"}],"stop_reason":"end_turn","usage":{"input_tokens":10,"cache_creation_input_tokens":36,"cache_read_input_tokens":13993,"output_tokens":76,"max_tokens":968000,"service_tier":"standard"}},"parent_tool_use_id":null,"session_id":"T-addfb7a4-61d9-41e1-890b-7330aa54087a"}
{"type":"user","message":{"role":"user","content":[{"type":"text","text":"now add 5 to that"}]},"parent_tool_use_id":null,"session_id":"T-addfb7a4-61d9-41e1-890b-7330aa54087a"}
{"type":"assistant","message":{"type":"message","role":"assistant","content":[{"type":"text","text":"17"}],"stop_reason":"end_turn","usage":{"input_tokens":10,"cache_creation_input_tokens":36,"cache_read_input_tokens":14029,"output_tokens":43,"max_tokens":968000,"service_tier":"standard"}},"parent_tool_use_id":null,"session_id":"T-addfb7a4-61d9-41e1-890b-7330aa54087a"}
{"type":"result","subtype":"success","duration_ms":21639,"is_error":false,"num_turns":3,"result":"17","session_id":"T-addfb7a4-61d9-41e1-890b-7330aa54087a"} Set the top-level steer field to true if Amp should handle a queued message at the next
interruption point while the agent is busy.
Claude Code Compatibility
Amp’s stream JSON output tries to be compatible with Claude Code’s format as much as possible.
When --stream-json-thinking is enabled, the output includes extra content block types that are not
part of Claude Code’s public schema.