@tool, @rule, and @agent decorators that enforce limits per function call.
Passthrough mode
When running outsidenanny run, every decorator 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, a
NannyStopexception is raised — the function body never runs.
Tokens
Thetokens argument is required. 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 Python:
instrument — automatic LLM token tracking
Call nanny_sdk.instrument(client) once at agent startup to automatically report LLM token usage to Nanny’s budget. Every completion response is intercepted and its token counts are debited from the same ledger that @tool charges against.
- OpenAI, Groq, Together AI, Azure OpenAI, LiteLLM — any client with a
chat.completions.createmethod - Anthropic —
client.messages.create - Mistral —
client.chat.complete - Google Gemini (
google-genaiSDK) —client.models.generate_content - Cohere v2 —
cohere.ClientV2
instrument returns the same client unchanged — it patches the method in-place. In passthrough mode (outside nanny run), it is a no-op: no wrapping, no overhead.
@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 raises:
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. Use last_tool_args for content-based enforcement:
step_count, tokens_spent, tool_call_counts, and tool_call_history reflect the actual execution state at the moment your rule runs.

@agent — activate named limits for a scope
In a multi-agent system, each agent has a different role and a different risk profile. The analysis agent makes expensive API calls and deserves a tight token ceiling. The reporter just writes a file and barely needs a budget at all. @agent activates the right named limit set when each role runs, then reverts automatically when it’s done.
[limits] and overrides only the declared fields.
Works identically for async functions. Limits revert on exit whether the function returns normally or raises.

What happens on stop
When Nanny stops execution, it raises aNannyStop exception. All stop reasons are distinct subclasses:
BridgeUnavailable is raised when Nanny’s enforcement layer is active but unreachable during rule evaluation or a tool call. Nanny fails closed — the agent does not continue ungoverned. Like all NannyStop subclasses it extends BaseException, so it propagates through broad except Exception handlers in agent frameworks without being swallowed.
You do not need to handle stop reasons in most agent code. They propagate up the call stack and terminate the process via nanny run. Catching them is useful in test code and at the CLI entry point.

Complete example
Multi-agent pattern
The canonical use case: a pipeline where each agent has a specific role, a specific budget, and access to only the tools it needs. This is themetrics_crew pattern — four specialized agents, each governed independently.
- Per-role budget: hitting the analysis budget doesn’t kill the reporter
- Least-privilege tool access: each agent only receives the tools it needs; calling outside its role raises
ToolDeniedimmediately - Loop detection: the
@rulefires client-side before Nanny’s enforcement layer is contacted — the denied tool never runs and no tokens are charged - Full audit trail: every tool call, every limit activation, every stop reason logged to NDJSON

examples/python/metrics_crew for the complete working implementation of this pattern with four agents, Plotly chart generation, and a full incident report output.
Framework integration
LangChain
Stack@lc_tool (outer) and @nanny_tool (inner). LangChain registers the function for dispatch; Nanny intercepts every call regardless of which model or API style invoked it:
tool.run(args) → LangChain validates args → Nanny wrapper intercepts → enforcement check → if allowed, file is read.
CrewAI
Same stacking pattern. CrewAI’s@tool decorator and Nanny’s @tool decorator both wrap the function — Nanny’s wrapper fires on every tool.run() call inside the crew:
examples/python/dev_assist for a complete LangGraph integration and examples/python/metrics_crew for the canonical multi-agent governance example with four specialized agents, per-role limits, and per-role tool allowlists.