> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.nvidia.com/nemoclaw/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.nvidia.com/nemoclaw/_mcp/server.

# Network Policies

> Baseline network policy, filesystem rules, and operator approval flow.

NemoClaw runs with a deny-by-default network policy.
The sandbox can only reach endpoints that are explicitly allowed.
OpenShell intercepts any request to an unlisted destination and prompts the operator to approve or deny it in real time through the TUI.

## Baseline Policy

Deep Agents sandboxes use an agent-specific baseline policy in `agents/langchain-deepagents-code/policy-additions.yaml` so the managed `dcode` runtime can reach inference, GitHub, and package endpoints while keeping the same deny-by-default model.
Deep Agents uses strict Landlock compatibility, so sandbox startup fails when OpenShell cannot enforce the managed filesystem policy.

### Filesystem

| Path                                                                | Access     |
| ------------------------------------------------------------------- | ---------- |
| `/sandbox`, `/tmp`, `/dev/null`, `/dev/pts`                         | Read-write |
| `/usr`, `/lib`, `/proc`, `/dev/urandom`, `/app`, `/etc`, `/var/log` | Read-only  |

`/dev/pts` is the pseudo-terminal (devpts) directory.
It is writable so PTY-based tools (`tmux`, `script`, and interactive shells) can allocate a terminal.
Without it, those tools fail with `fork failed: Permission denied`.

The sandbox process runs as a dedicated `sandbox` user and group.

For Deep Agents, Landlock enforcement is strict.
If the kernel or runtime cannot enforce the managed filesystem policy, sandbox startup fails closed.

### Network Policies

The following endpoint groups are allowed by default:

| Policy              | Endpoints                                    | Binaries                                                                        | Rules                                                                           |
| ------------------- | -------------------------------------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| `managed_inference` | `inference.local:443`                        | `/usr/local/bin/dcode`, `/opt/venv/bin/python3*`, `/opt/venv/lib/python3.13/**` | POST to OpenAI-compatible completion and embedding paths, GET to model listings |
| `github`            | `github.com:443`, `api.github.com:443`       | `/usr/bin/git`, `/usr/local/bin/dcode`, `/opt/venv/bin/python3*`                | Full access to the listed hosts                                                 |
| `pypi`              | `pypi.org:443`, `files.pythonhosted.org:443` | `/opt/venv/bin/python3*`, `/opt/venv/bin/pip3*`                                 | GET and HEAD for package installation                                           |

All endpoints use TLS termination and are enforced at port 443.

Deep Agents is a terminal-oriented harness.
NemoClaw does not configure messaging channel bridges for Deep Agents today, and the baseline policy does not include Tavily, LangSmith, MCP hosts, or arbitrary web endpoints.
Apply maintained presets such as `github`, `pypi`, or `tavily` only when the sandbox needs that access.

<a id="policy-tiers" />

## Policy Tiers

During onboarding, the wizard prompts for a policy tier that determines the default set of presets applied on top of the baseline policy.
The baseline policy is always applied regardless of the selected tier.

| Tier               | Presets included                                                                                                                                                                                                           | Description                                                                                                                                                                                                                                                                                                                          |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Restricted         | No tier defaults                                                                                                                                                                                                           | Starts from the baseline policy. Web search or messaging integrations selected earlier can still suggest their required presets; deselect them during policy review for baseline-only access. Restricted suppresses other agent-required additions; reapply them later with `policy-add` only after reviewing the additional egress. |
| Balanced (default) | `npm`, `pypi`, `huggingface`, `brew`, selected `brave` or `tavily` web search preset                                                                                                                                       | Full dev tooling and web search when you select a provider the active agent supports. No messaging platform access. Apply the `weather` preset explicitly if your agent needs read-only weather lookups.                                                                                                                             |
| Open               | `npm`, `pypi`, `huggingface`, `brew`, selected `brave` or `tavily` web search preset, `weather`, `public-reference`, `slack`, `discord`, `telegram`, `wechat` (experimental), `whatsapp` (experimental), `jira`, `outlook` | Broad access across third-party services including messaging, productivity, weather, and public-reference APIs.                                                                                                                                                                                                                      |

After selecting a tier, a combined preset and access-mode screen lets you include or exclude individual presets and toggle each between read (GET only) and read-write (GET + POST/PUT/PATCH) access.
Tier-default presets are pre-selected; additional presets can be added from the built-in preset list available to the sandbox's active agent.
NemoClaw filters tier defaults and built-in preset choices by the active agent's supported integrations.

Deep Agents can use the maintained `tavily` opt-in path, but messaging channel presets are omitted because the terminal harness does not run a NemoClaw messaging bridge today.
NemoClaw automatically suggests the preset that matches the selected provider and removes stale web search presets during resume reconciliation when you switch providers or disable web search.
Explicit custom preset lists and manual interactive selections remain operator-controlled.

When LangChain Deep Agents Code is onboarded with `--observability`, NemoClaw adds the `observability-otlp-local` preset on Balanced and Open tiers.
The Restricted tier suppresses this agent-required preset during onboarding and rebuild reconciliation.
An operator can add it manually after reviewing the additional egress, but the next Restricted reconciliation removes it.
The applied set therefore reflects the chosen tier *plus* any agent-required presets, so `policy-list` may show one or more presets that do not appear in the tier table above.
The `policy-list` provenance tags are inferred from the current tier YAML and the active agent at display time and are not persisted per preset.
A preset whose name matches an entry in the sandbox's current tier definition is labelled `[from <tier> tier]` even when an operator added it manually with `policy-add` after onboarding; agent-specific preset names are only labelled `[from <agent> agent]` when the active agent matches.
Claude Code direct egress is not included in any policy tier.
If you install and run the Claude Code CLI inside the sandbox with its own credentials, apply the `claude-code` preset explicitly.
Normal NemoClaw Anthropic inference still routes through the OpenShell gateway.

Tier definitions are stored in `nemoclaw-blueprint/policies/tiers.yaml`.

In non-interactive mode, set the tier with `NEMOCLAW_POLICY_TIER`:

```bash
NEMOCLAW_POLICY_TIER=open nemo-deepagents onboard --non-interactive --yes-i-accept-third-party-software
```

Unset, blank, or whitespace-only `NEMOCLAW_POLICY_TIER` values use the `balanced` default.
In non-interactive onboarding, a non-blank value that does not match a known tier exits before preflight, gateway, or inference side effects and lists the valid options.
Interactive onboarding ignores an invalid environment value and shows the normal tier prompt.

### Inference

The baseline policy allows only the `local` inference route.
External inference providers are reached through the OpenShell gateway, not by direct sandbox egress.

### Local OTLP Trace Export

The `observability-otlp-local` preset supports the opt-in LangChain Deep Agents Code trace path.
It is not a general remote observability policy.

| Preset                     | Destination                    | Binary                   | Rules                        |
| -------------------------- | ------------------------------ | ------------------------ | ---------------------------- |
| `observability-otlp-local` | `host.openshell.internal:4318` | `/opt/venv/bin/python3*` | Exact `POST /v1/traces` only |

The sandbox sends OTLP/HTTP protobuf traces to a collector that the operator runs on the host.
The managed exporter uses standard OTLP transport headers but does not accept operator-supplied custom or authentication headers.
Remote backend endpoints and credentials stay in that collector.
The policy does not allow direct LangSmith, Jaeger, Phoenix, or other backend egress from Deep Agents Code.
Changing the collector's downstream exporter requires no sandbox policy change.

OpenShell observes Deep Agents Code export as the managed Python interpreter, so this permission is process-wide for `/opt/venv/bin/python3*` rather than limited to the `dcode` launcher.
Sandbox Python can forge spans and resource attributes.
The explicit `--observability` opt-in can export bounded prompts, responses, tool arguments, tool results, and operational metadata.
Managed size and recognized-key redaction do not detect secrets embedded in ordinary content values.
The collector must enforce the operator's filtering and redaction requirements before forwarding traces, and it must not treat span fields such as `service.name` as authenticated tenant identity.
For a safe host binding, policy recovery commands, a runnable collector, and end-to-end verification, refer to [Export Traces Through a Local Collector](../get-started/quickstart#export-traces-through-a-local-collector).

## Operator Approval Flow

When the agent attempts to reach an endpoint not listed in the policy, OpenShell intercepts the request and presents it in the TUI for operator review.
The flow has these steps:

1. The agent makes a network request to an unlisted host.
2. OpenShell blocks the connection and logs the attempt.
3. The TUI command `openshell term` displays the blocked request with host, port, and requesting binary.
4. The operator approves or denies the request.
5. If approved, the endpoint is added to the running policy for the session.

To try this, run the walkthrough:

```bash
./scripts/walkthrough.sh
```

This opens a split tmux session with the TUI on the left and the agent on the right.

## Modifying the Policy

### Static Changes

Edit `agents/langchain-deepagents-code/policy-additions.yaml` and re-run the onboard wizard:

```bash
nemo-deepagents onboard
```

### Dynamic Changes

Apply policy updates to a running sandbox without restarting:

```bash
openshell policy update <sandbox-name> --add-endpoint api.example.com:443:read-only:rest:enforce
```

To replace the live policy with a complete raw policy file, start from the live policy and use `openshell policy set`.
Requires OpenShell 0.0.72+ for the round-trippable `policy get --base` and `policy set --wait` syntax.

```bash
# shellcheck shell=bash
# Source-of-truth review:
# invalidState: OpenShell 0.0.72 policy get --base emits metadata before the --- YAML header.
# sourceBoundary: OpenShell CLI output is owned by the separate OpenShell project.
# whyNotSourceFix: NemoClaw pins OpenShell but cannot change that upstream formatter here.
# regressionTest: test/policy-roundtrip-docs.test.ts validates this shared docs pattern.
# removalCondition: remove this pipeline after pinned OpenShell emits clean raw YAML.
tmp_policy=$(mktemp)
openshell policy get --base <sandbox-name> \
  | awk 'found { print } /^---$/ { found = 1 } END { if (!found) exit 1 }' \
  > "$tmp_policy" \
  && grep -q '^version:' "$tmp_policy" \
  && grep -q '^network_policies:' "$tmp_policy" \
  && mv "$tmp_policy" current-policy.yaml
```

Edit or review `current-policy.yaml`, then apply it:

```bash
openshell policy set --policy current-policy.yaml --wait <sandbox-name>
```