Installation
The SDK ships inside the same crate as the CLI binary. Add it to your project:Passthrough mode
If your agent runs withoutnanny run, every macro is a no-op. The function executes normally with no enforcement overhead:
#[tool] — declare a governed tool
Mark a function as a tool that Nanny should track and charge against the budget:
fetch_page:
- Nanny checks: is
fetch_pagein the[tools] allowedlist? - Nanny checks: has
fetch_pageexceeded[tools.fetch_page] max_calls? - Nanny charges 10 tokens against the budget.
- If any check fails, execution stops immediately — the function body never runs.
Tokens
Thetokens argument is required. It is the number of tokens charged per call.
Set it to 0 for tools you want tracked but not charged:
Matching the tool allowlist
The tool name used for allowlist checks is the function name as declared in Rust:nanny::http_get — built-in HTTP tool
nanny::http_get is a built-in governed HTTP GET function. It requires no #[tool] annotation — Nanny applies allowlist, call-count, and token enforcement automatically.
- Checked against the
[tools] allowedlist (tool name:"http_get") - Subject to
[tools.http_get] max_callslimit - Costs 10 tokens per successful call (configurable via
[tools.http_get] tokens_per_call)
nanny run), nanny::http_get makes the request directly with no enforcement overhead.
nanny::report_usage — report LLM token usage
#[tool(tokens = N)] charges a declared token cost per call. To charge the actual tokens an LLM used, report them after the call with nanny::report_usage. Hand Nanny the token counts already present on the response — Nanny debits input + output from the budget.
input and output are required. You can optionally attach model and provider labels — identifiers only, never prompt or response content — and, if your provider’s response reports it, cache_read/cache_write (a finer split of input, never additional tokens beyond it):
LlmUsageRecorded event to the log. report_usage is fire-and-forget: it never blocks your agent and never panics. In passthrough mode (no nanny run) it is a no-op.
Rust reports usage explicitly, one call per LLM response. In Python,
nanny_sdk.instrument(client) does the same thing automatically by wrapping the client — Rust cannot patch a client at runtime, so the reporting is an explicit call instead.#[rule] — declare an enforcement rule
A rule is a function that returns a verdict on whether execution should continue.
Return true to allow, false to deny:
false, Nanny stops execution with:
PolicyContext fields
Thectx parameter gives you a snapshot of the current execution state:
Rules are evaluated before the tool runs —
requested_tool is set to the tool name being checked.
#[agent] — activate named limits for a scope
Mark a function to run under a named limit set from nanny.toml.
When the function is entered, Nanny switches to those limits; when it exits, limits revert:
[limits] and overrides only the declared fields.
Nesting #[agent] functions is supported — limits revert to the caller’s set on exit.

nanny::fresh_run — starting a fresh run mid-process
#[agent(...)] changes which ceiling the run’s one running total is
checked against; it does not give a scope its own budget (see
Named sets share one counter).
If your process runs multiple, independent phases back to back and you
want each one to start from zero rather than inherit whatever an earlier
phase already spent, that’s a new run, Nanny’s real unit of
governance: one cumulative counter, one stop state, “a stop is final.”
nanny run --serve / --join): the server keys independent state per run, so a stop
in the run you just left has zero effect on the one you’re starting. Under
local nanny run (no --serve), one process is already always exactly
one run, so this is a safe no-op there. Mirrors nanny_sdk.fresh_run() on
the Python side.
Complete example
What happens on stop
When Nanny stops execution inside an instrumented function, the macro propagates the stop signal by panicking with a structured message. The panic is caught by the Nanny runtime — your agent process exits cleanly with a non-zero code and anExecutionStopped event in the log.
You do not need to handle stop reasons in your agent code. Nanny handles the exit path.