Skip to content

JSON events

malac --json prints every event of the main agent and its subagents as one JSON object per line. The same events drive the terminal, the web UI and the VS Code extension. See Plain mode and scripting for usage.

Every line has these fields, plus the fields of its event type:

Field Type Meaning
agent string Id of the agent the event belongs to; empty for update
seq integer Sequence number, increasing across all agents
at string Timestamp, RFC 3339 in UTC
type string Event type, below

Agent ids are the session ids used by malac -r and malac sessions show.

Type Fields When
agent_started label, parent, model, cwd An agent starts. parent is null for the main agent.
model_changed model The agent switched models
user_message text A prompt or follow-up arrives
text_delta text Streamed answer text
thinking_delta text Streamed reasoning
tool_call_streaming tool The model is writing a tool call
assistant_message message A complete assistant message
tool_started call_id, tool, summary, input A tool call starts
tool_finished call_id, tool, output, is_error, millis A tool call ends. output is a preview of the result.
permission_requested request_id, call_id, tool, summary, input A call waits for approval
permission_resolved request_id, allowed The approval was answered
todos items The task list changed; each item has content and status
usage turn, total, context_tokens Token usage after a model request
compacted summary The conversation was compacted
notice level (info, warning, error), message A message for the user, such as a retry
turn_finished status, text A turn ended; text is the final answer
agent_finished status, report A subagent finished; report is what it returned
update status A newer malac is available or installed

status in turn_finished and agent_finished is completed, cancelled or failed.

Count tool calls by tool:

jq -r 'select(.type == "tool_started") | .tool' events.jsonl | sort | uniq -c

Fail a CI step when any approval was refused (calls blocked by a deny rule never ask, so they produce no permission events; the refusal goes back to the model as the tool’s result):

if jq -e 'select(.type == "permission_resolved" and .allowed == false)' events.jsonl > /dev/null; then
echo "a tool call was denied"
exit 1
fi

Show what each subagent reported:

jq -r 'select(.type == "agent_finished") | "\(.agent): \(.report)"' events.jsonl

malac is created by lobirus and released under the MIT license. About malac