Skip to main content

Format

The event log is NDJSON, one JSON object per line, emitted in chronological order. Every object has an "event" field identifying its type and a "ts" field with a Unix timestamp in milliseconds.

Output destination

Events go to stdout. Nanny’s own output, the startup block and any warning, goes to stderr, so redirecting stdout gives you the event log by itself:
Your agent’s own stdout still passes through, since it inherits the stream, so a consumer that wants only events filters for lines beginning with {. In a container, redirect nothing. The runtime collects stdout already and every log shipper reads it from there. A Datadog agent, for example, needs no Nanny configuration at all:
If you do want a file inside a container, redirect in the entrypoint rather than piping, so Nanny stays PID 1 and still receives SIGTERM:
Durable delivery is Cloud’s job, not the log’s. Nothing on disk survives a container that is replaced. When NANNY_API_KEY is set, undelivered batches are held in .nanny/spool/ and sent on the next run, which is the path worth mounting a volume for. See Connect to Nanny Cloud.

Guaranteed events

Every execution emits exactly these two events, in this order:

ExecutionStarted

Always the first event. Emitted immediately before the child process is spawned.

ExecutionStopped

Always the last event of a complete run. Emitted on every exit path: clean exit, a policy stop, an error, or a signal.
If this event is missing from a run, the process crashed. That absence is itself a fact worth reading. reason is one of four: ToolDenied, RuleDenied, AgentCompleted, or ManualStop. Only the first two are policy violations.

SDK events

When the Rust SDK macros or Python SDK decorators are active, additional events are emitted for each tool call. These appear between ExecutionStarted and ExecutionStopped: ToolDenied and RuleDenied are distinct denial events. ToolDenied means the tool was not permitted at all; RuleDenied means the tool was permitted but a rule blocked this specific call. ToolFailed is different from both: the tool was allowed and called, but hit a runtime error. No tokens are recorded for a failure.

Using the log

The event log is designed to be piped into standard tools: