Skip to main content

The execution boundary

When you run nanny run, Nanny becomes the parent process of your agent. It reads [start].cmd from nanny.toml, spawns it as a child, and owns the process lifecycle — it decides when the process lives and when it dies. The moment any limit is crossed, Nanny kills the child process immediately — the process cannot catch, delay, or prevent the stop. An ExecutionStopped event is emitted with the reason, and Nanny exits with a non-zero status code.

What Nanny enforces

All three limits are enforced on every run:
LimitRequirementBehaviour
timeoutNone — works for any processKilled when wall-clock time exceeds the configured value
stepsRust SDK or Python SDKKilled when step count reaches the configured limit
costRust SDK or Python SDKKilled when accumulated cost reaches the configured budget
Timeout enforcement works for any process in any language — no SDK required. Step and cost enforcement require the agent to report tool calls — either via the Rust SDK macros or the Python SDK decorators.

Passthrough mode

When running outside nanny run, every macro becomes a no-op:
#[tool(cost = 10)]
fn search(query: &str) -> String {
    // runs normally, no enforcement
}
This means you can ship instrumented code and run it in development, CI, and production without Nanny — until you explicitly wrap it with nanny run. The behaviour is identical either way.