Skip to main content
The Rust SDK brings Nanny’s enforcement boundary into your code. Instead of relying only on process-level limits, you mark individual functions as tools and rules — Nanny governs each call before it executes.

Installation

The SDK ships inside the same crate as the CLI binary. Add it to your project:
Then import what you need:

Passthrough mode

If your agent runs without nanny 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:
When the agent calls fetch_page:
  1. Nanny checks: is fetch_page in the [tools] allowed list?
  2. Nanny checks: has fetch_page exceeded [tools.fetch_page] max_calls?
  3. Nanny charges 10 tokens against the budget.
  4. If any check fails, execution stops immediately — the function body never runs.

Tokens

The tokens 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.
Governance applied automatically:
  • Checked against the [tools] allowed list (tool name: "http_get")
  • Subject to [tools.http_get] max_calls limit
  • Costs 10 tokens per successful call (configurable via [tools.http_get] tokens_per_call)
In passthrough mode (no 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.
Only input and output are required. You can optionally attach model and provider labels — identifiers only, never prompt or response content:
Each call emits an 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:
Rules are evaluated on every tool call. When a rule returns false, Nanny stops execution with:

PolicyContext fields

The ctx 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:
The named set inherits from [limits] and overrides only the declared fields. Nesting #[agent] functions is supported — limits revert to the caller’s set on exit.
webdingo running under nanny run — planner, researcher, and synthesizer agent scopes entering and exiting with structured NDJSON events

Complete example

Run it under Nanny:
Run it without Nanny (macros silent, agent runs normally):

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 an ExecutionStopped event in the log. You do not need to handle stop reasons in your agent code. Nanny handles the exit path.