> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nanny.run/llms.txt
> Use this file to discover all available pages before exploring further.

# nanny run

> Run a command under Nanny enforcement.

Spawns a child process under full Nanny enforcement. Reads `nanny.toml` from the current directory and kills the process the moment any limit is crossed.

```bash theme={null}
nanny run [OPTIONS] [-- ARGS...]
```

***

## Examples

```bash theme={null}
# Run with base [limits] (reads [start].cmd from nanny.toml)
nanny run

# Run with a named limit set
nanny run --limits=researcher
```

***

## Options

| Flag              | Type   | Default        | Description                                                                                                                                                                                                    |
| ----------------- | ------ | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--limits=<name>` | string | —              | Activate a named limit set from `nanny.toml`. Inherits from `[limits]`.                                                                                                                                        |
| `--join=<appId>`  | string | —              | Join an existing governance server by app id (from that server's `.nanny/app.json`), instead of enforcing locally. Explicit and app-id-only: never a name, never auto-detected. Not compatible with `--serve`. |
| `--serve`         | flag   | —              | Run as the governance server that other processes and machines join, instead of launching a command. See [Governance server](#governance-server) below.                                                        |
| `--no-sync`       | flag   | —              | Do not forward events to Nanny Cloud for this run, even if the machine is logged in. Enforcement is unaffected. See [Connect to Nanny Cloud](/v0.5/guides/managed-mode).                                       |
| `--config=<path>` | path   | `./nanny.toml` | Path to config file.                                                                                                                                                                                           |

***

## Exit codes

| Code | Meaning                                                                            |
| ---- | ---------------------------------------------------------------------------------- |
| `0`  | Process exited cleanly (`AgentCompleted`)                                          |
| `1`  | Nanny stopped the process, a spawn failure occurred, or an internal error occurred |

***

## Stderr

When Nanny stops a process it prints the reason to stderr:

```
nanny: stopped — TimeoutExpired
nanny: stopped — BudgetExhausted
nanny: stopped — MaxStepsReached
nanny: stopped — ToolDenied
nanny: stopped — RuleDenied
```

This message is separate from the structured event log, which goes to stdout (or a configured file).

***

## Event log

Every run emits [NDJSON events](/v0.5/concepts/event-log) to stdout. `ExecutionStarted` is always first; `ExecutionStopped` is always last:

```json theme={null}
{"event":"ExecutionStarted","ts":1711234567000,"limits":{"steps":100,"tokens":1000,"timeout":30000},"limits_set":"[limits]","command":"python agent.py"}
{"event":"ToolAllowed","ts":1711234567120,"tool":"http_get"}
{"event":"StepCompleted","ts":1711234567800,"step":1}
{"event":"ExecutionStopped","ts":1711234572000,"reason":"BudgetExhausted","steps":12,"tokens_spent":1000,"elapsed_ms":5000}
```

Pipe to a file to keep your agent's own output separate:

```bash theme={null}
nanny run > nanny.log
```

***

## Governance server

`nanny run --serve` starts a long-lived **governance server** instead of launching a command. Other processes and machines connect to it over TCP with `nanny run --join=<appId>`, and every tool call from every connected agent counts against one shared budget and step limit. For a single-process agent you don't need this: plain `nanny run` is enough.

Starting a server requires `nanny init` to have already run in that directory: the server's state is keyed by the app's permanent `app_id`, not a global path, so two unrelated apps' servers on one machine never collide.

```bash theme={null}
nanny run --serve [--addr <addr>] [--cert <path>] [--key <path>] [--ca <path>]
```

It reads `nanny.toml` from the current directory and blocks until stopped (`nanny stop` or `CTRL-C`).

### Serve flags

| Flag     | Type           | Default                     | Description                                                                                                    |
| -------- | -------------- | --------------------------- | -------------------------------------------------------------------------------------------------------------- |
| `--addr` | socket address | `127.0.0.1:62669`           | Listen address. The governance API and HTTP proxy share this port. Loopback = plain HTTP; non-loopback = mTLS. |
| `--cert` | path           | `~/.nanny/certs/server.crt` | Server TLS certificate PEM. Required only for non-loopback addresses.                                          |
| `--key`  | path           | `~/.nanny/certs/server.key` | Server TLS private key PEM. Required only for non-loopback addresses.                                          |
| `--ca`   | path           | `~/.nanny/certs/ca.crt`     | CA certificate PEM used to validate agent client certs. Required only for non-loopback addresses.              |

The bind address sets the security posture: **loopback** (`127.0.0.1`) is plain HTTP for same-machine agents; a **non-loopback** address (`0.0.0.0`) makes mTLS mandatory, and the server refuses to start without certs. For cross-machine setup, certificates, and connecting agents, see the [Governance server guide](/v0.5/guides/governance-server).

### Manage a running server

```bash theme={null}
nanny status                  # current directory's own app, by .nanny/app.json
nanny status --app=<appId>    # or target a specific app explicitly

nanny stop                    # SIGTERM, then a 10-second graceful drain
nanny stop --app=<appId>
```

Both commands default to the current directory's own `app_id` when `--app` is omitted. `nanny status` reads `~/.nanny/servers/<appId>/server.addr` and probes the server (exit `0` if reachable, `1` otherwise). `nanny stop` reads the PID from `~/.nanny/servers/<appId>/server.pid` and sends `SIGTERM` (on Windows, `taskkill /F`).

### Relocating the state directory

Set `NANNY_HOME` to put `.nanny/servers/` (and everything else normally under `~/.nanny/`) somewhere other than the home directory:

```bash theme={null}
NANNY_HOME=/opt/nanny nanny run --serve
NANNY_HOME=/opt/nanny nanny run --join=<appId>
```

Both sides of a `--serve`/`--join` pair need the same `NANNY_HOME` to find each other's state. Falls back to the OS home directory when unset.

***

For per-function governance (marking individual tools and rules in code), see the [Rust SDK guide](/v0.5/guides/rust-sdk) or [Python SDK guide](/v0.5/guides/python-sdk).
