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 --serve

# 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.3

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.3
File Size Uploaded Provenance
nanny_sdk-0.6.3.tar.gz 82.1 kB With provenance Details

Built distribution (wheel)

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

Total release size: 113.6 kB

Release files / nanny_sdk-0.6.3.tar.gz

Download URL nanny_sdk-0.6.3.tar.gz
Size 82.1 kB
Tags Source
SHA-256 checksum
How to use checksums
c1841a4849e7ff93f7542003666a2ef3a73cc0ba5afe2a8deb967029c3c03e58
BLAKE2b-256 checksum
How to use checksums
f3f84f132852d1dfab8e97688628cb0948bc82c2c6542dd6027f58955123610a
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 Sep 3, 2026.

Transparency log

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

Download URL nanny_sdk-0.6.3-py3-none-any.whl
Size 31.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
44ef6fc0960172657cfaec2fc3a063ba82b8c77761b41b3a91c99f2f05397ccd
BLAKE2b-256 checksum
How to use checksums
e8460cc47c7cab90a2e8bd632bd94d543a2bce6e2e9665401fe8f82e03aa39fc
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 Sep 3, 2026.

Transparency log

Security for nanny-sdk 0.6.3

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.3.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 Sep 3, 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