Skip to main content

Nanny

nanny-sdk

Python SDK for Nanny: the authorization and audit layer for AI agents that take real-world actions.

@tool, @rule, and @agent decorators that enforce tool allowlists, per-tool call caps, and custom rules per function call. Works with LangChain, CrewAI, or any Python agent framework.

pip install nanny-sdk

Full docs: docs.nanny.run


How it works

Nanny runs as a parent process via nanny run. The SDK decorators communicate with it at each tool call, so the call is authorized before the function body executes. Outside nanny run, every decorator is a no-op, zero overhead in development and CI.

# Governed, enforcement active
nanny run

# Passthrough, decorators silent, agent runs normally
python agent.py
uv run agent.py

@tool: declare a governed tool

from nanny_sdk import tool

@tool()
def fetch_page(url: str) -> str:
    import httpx
    return httpx.get(url).text

Before fetch_page runs, Nanny checks the allowlist, the per-tool call cap, and every registered rule, and records 10 tokens against the run. If any check refuses, a NannyStop exception is raised and the function body never executes.

Async functions work identically:

@tool()
async def fetch_page(url: str) -> str:
    async with httpx.AsyncClient() as client:
        r = await client.get(url)
        return r.text

instrument: automatic LLM token tracking

import nanny_sdk, openai

client = openai.OpenAI()
nanny_sdk.instrument(client)   # one line, done

Call once at startup. Every LLM completion response is intercepted and its token counts are recorded automatically, no @tool decorator needed on the LLM call itself. Tokens are measured for attribution, never enforced: no token count stops a run.

Supported: OpenAI, Groq, Together AI, Azure OpenAI, LiteLLM, Anthropic, Mistral, Google Gemini (google-genai), Cohere v2. No-op in passthrough mode.

For providers that report prompt-caching usage (OpenAI, Anthropic, DeepSeek, Gemini), instrument also captures cache_read/cache_write, a finer, reporting-only split of input, never additional tokens and never used for enforcement.


@rule: enforce a custom policy

from nanny_sdk import rule

@rule("no_sensitive_files")
def block_sensitive(ctx) -> bool:
    path = ctx.last_tool_args.get("path", "")
    return ".env" not in path and "secret" not in path

Rules run before every @tool call. Return False to stop execution with RuleDenied. The ctx object exposes requested_tool, last_tool_args, tool_labels, tool_call_history, and now_ms.


@agent: name a phase of the run

In a multi-agent system a denial is worth attributing to the phase that caused it:

from nanny_sdk import agent

@agent("researcher")
def run_research_loop(query: str) -> str:
    ...

Names a phase of the run for the duration of the function, so the audit log can attribute each verdict to the phase that produced it. The scope exits on return and on exception. Any name works: a scope labels, it does not look anything up. Want a phase to be a genuinely separate run, with its own stop state and history? See run_scope below.


run_scope: an independent run, safely, even concurrently

@agent labels a phase within one run. If a phase should be a genuinely separate run, with its own stop state and its own tool call history, that is a new run. A threaded or async server handling several independent sessions at once needs one per session:

import nanny_sdk

with nanny_sdk.run_scope() as run_id:
    ...  # every governed call in this thread or task uses this run_id

Each call gets its own run id, isolated per thread and per asyncio task, so two runs in flight at once in the same process never clobber each other's stop state or tool call history. Pass an explicit run_id to resume a specific run instead of minting a fresh one. Every caller that never calls this is unaffected, resolution falls through to NANNY_RUN_ID exactly as before.


nanny.toml example

[start]
cmd = "uv run agent.py"

[tools]
allowed = ["fetch_page", "search"]

[tools.fetch_page]
max_calls       = 30
reads_untrusted = true

[tools.search]
reads_untrusted = true

The five labels (reads_untrusted, external_effect, destructive, moves_money, reads_sensitive) describe what a tool is. Rules read labels rather than tool names, which is what lets a rule written for one app govern another.

Cloud sync isn't a config field. Set NANNY_API_KEY and every nanny run on that machine forwards its event log automatically. No key, no sync.


Stop reasons

When an action is refused, a NannyStop exception is raised with one of these reasons:

Reason Cause
ToolDenied Tool not in the allowlist
RuleDenied A rule returned False
AgentCompleted Clean exit
ExecutionStopped This run was already stopped by an earlier call
BridgeUnavailable Enforcement was active but became unreachable, fails closed, never continues ungoverned

Both refusals are policy decisions. Nanny bounds what an agent may do, not how much it may consume.


Requirements

  • Python 3.11+
  • httpx (only runtime dependency)
  • nanny CLI:
    • macOS: brew tap nanny-run/nanny && brew install nannyd
    • Linux: curl -fsSL https://install.nanny.run | sh
    • Windows: irm https://install.nanny.run/windows | iex

Metadata

Release files for nanny-sdk 0.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for nanny-sdk 0.6.0
File Size Uploaded Provenance
nanny_sdk-0.6.0.tar.gz 78.6 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for nanny-sdk 0.6.0
File Interpreter ABI Platform
nanny_sdk-0.6.0-py3-none-any.whl Python 3 none any Details

Total release size: 107.5 kB

Release files / nanny_sdk-0.6.0.tar.gz

Download URL nanny_sdk-0.6.0.tar.gz
Size 78.6 kB
Tags Source
SHA-256 checksum
How to use checksums
c200dc109900b1e79160b7de9f19f7ecea743093bd0855b36371c251095ffe17
BLAKE2b-256 checksum
How to use checksums
da589e82be289afa1d75778f8a07e3a3304b176ec05143b20e52526db7e1780c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.

Transparency log

Release files / nanny_sdk-0.6.0-py3-none-any.whl

Download URL nanny_sdk-0.6.0-py3-none-any.whl
Size 28.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2a9c408919841a2aac35ac724e6116aa2014010ff2ec1a4d04f91afbec0ccf1d
BLAKE2b-256 checksum
How to use checksums
8c1b2ba7a619a8c1911c73b7bea21ecd2ccfbea917423982699d2a2c43b011bc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.

Transparency log

Security for nanny-sdk 0.6.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for nanny_sdk-0.6.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page