Skip to main content

The three limit types

Every Nanny execution is governed by three independent limits. Any one of them can stop a run.

Timeout

The wall-clock time limit in milliseconds. The moment the child process has been running for timeout ms, Nanny kills it — regardless of what it’s doing.
Timeout enforcement requires no instrumentation — it works for any process in any language.

Steps

The maximum number of agent steps allowed. Requires #[nanny::tool] (Rust) or @tool (Python) to report tool calls.

Tokens

The maximum number of tokens the agent may spend. Each tool declares its token cost per call; Nanny tracks the running total and stops the moment the budget is exhausted.

Named limit sets

In a multi-agent system, each agent has a different risk profile. The analysis agent makes expensive API calls — it deserves a tight token ceiling. The reporter just writes a file — it barely needs a budget at all. Named limit sets let each role get exactly the ceiling it deserves, configured once in nanny.toml.
Named sets inherit from [limits] and override only the fields you declare. In the example above, [limits.ingestion] inherits from the global [limits] and overrides all three fields. A set that only declares timeout would inherit steps and tokens from the base. Each agent activates its own set via the @agent("role") decorator:
Or activate a named set from the CLI for the entire run:

What happens when a limit is hit

  1. Nanny kills the child process immediately — no grace period, no way for the agent to catch or delay the stop.
  2. An ExecutionStopped event is emitted with the reason.
  3. A human-readable message is printed to stderr: nanny: stopped — TimeoutExpired.
  4. Nanny exits with code 1.
The stop reasons are: