> ## 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}
# Starts a governor and runs [start].cmd from nanny.toml underneath it
nanny run --serve

# Append arguments to that command
nanny run --serve -- --verbose
```

***

## Options

| Flag              | Type   | Default        | Description                                                                                                                                                                                                    |
| ----------------- | ------ | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--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   | —              | Start the governance server, and launch `[start].cmd` underneath it when `nanny.toml` declares one. Omit `[start]` for a headless governor. See [Governance server](#governance-server) below.                 |
| `--no-sync`       | flag   | —              | Do not forward events to Nanny Cloud for this run, even if `NANNY_API_KEY` is set. Enforcement is unaffected. See [Connect to Nanny Cloud](/v0.6/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, 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.6/concepts/event-log) to stdout. `ExecutionStarted` is always first; `ExecutionStopped` is always last:

```json theme={null}
{"event":"ExecutionStarted","ts":1711234567000,"run_id":"a1b2c3d4","seq":0,"command":"python agent.py","allowed_tools":["web_search","send_outreach"],"tool_labels":{"web_search":["reads_untrusted"],"send_outreach":["external_effect"]},"config_hash":"9f2a41c8"}
{"event":"RulesDeclared","ts":1711234567100,"run_id":"a1b2c3d4","seq":1,"rules":[{"name":"no_send_after_read","version":"1.0.0","pack":"nanny:recommended"}]}
{"event":"ToolAllowed","ts":1711234567120,"run_id":"a1b2c3d4","seq":2,"tool":"web_search","cleared_by":["no_send_after_read"]}
{"event":"RuleDenied","ts":1711234572000,"run_id":"a1b2c3d4","seq":3,"tool":"send_outreach","rule_name":"no_send_after_read","cleared_by":[]}
{"event":"ExecutionStopped","ts":1711234572000,"run_id":"a1b2c3d4","seq":4,"reason":"RuleDenied","tokens_spent":380,"elapsed_ms":5000}
```

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

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

***

## Governance server

`nanny run --serve` starts a long-lived **governance server**. Other processes and machines connect to it with `nanny run --join=<appId>`, and every tool call from every connected agent is evaluated against one shared set of rules.

Whether it also runs an app of its own is decided by `nanny.toml`:

* **`[start]` present.** The governor launches that command underneath itself, in one process. One container, one command, no launcher script. Trailing arguments after `--` append to it.
* **`[start]` absent.** A headless governor, for the case where the apps live elsewhere and arrive via `--join`.

Launching an app does not make the governor exclusive: it is still a server, and other processes can still join it, each with its own run id. Every run writes to the same log, and each event carries the `run_id` that tells them apart.

Use it for everything. A single process gets a governor on loopback with no
certificates and no setup, and several processes or machines get the same
governor with an address and a bundle. One shape means the thing you run in
development is the thing you run in production.

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>] [-- <args>]
```

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. Loopback is plain HTTP; non-loopback requires 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.6/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.6/guides/rust-sdk) or [Python SDK guide](/v0.6/guides/python-sdk).
