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:{.
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:
SIGTERM:
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.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 betweenExecutionStarted 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.