Learning NemoClaw

04 · Policies and Guardrails

This is the file you will actually come back to. It answers: "my agent can't reach X — how do I open it?" and "why is it locked down like this?"

Everything is in NemoClaw/nemoclaw-blueprint/policies/:

policies/
├── openclaw-sandbox.yaml              # the baseline, applied to every NemoClaw sandbox
├── openclaw-sandbox-permissive.yaml   # a relaxed variant for experimentation
└── presets/
    ├── brave.yaml   brew.yaml   discord.yaml   github.yaml
    ├── huggingface.yaml   jira.yaml   npm.yaml   outlook.yaml
    ├── pypi.yaml   slack.yaml   telegram.yaml

The anatomy of the baseline policy

openclaw-sandbox.yaml has four sections. Read them in this order — it's the mental order you'll think about the sandbox in.

1. filesystem_policy — read‑only by default

filesystem_policy:
  include_workdir: false              # MUST stay false — see below
  read_only:
    - /usr, /lib, /proc, /dev/urandom, /app, /etc, /var/log
    - /sandbox                        # home dir is READ-ONLY
    - /sandbox/.openclaw              # gateway config is IMMUTABLE
  read_write:
    - /tmp
    - /dev/null
    - /sandbox/.openclaw-data         # writable agent/plugin state (symlink target)
    - /sandbox/.nemoclaw              # plugin state

Why this is weird and important:

Consequence: filesystem policy is locked at sandbox creation (Landlock). If you change it, you need nemoclaw onboard to recreate.

2. process — drop privileges

process:
  run_as_user: sandbox
  run_as_group: sandbox

Combined with OpenShell's seccomp, this is why the agent runs as a non‑root user. Also locked at creation.

3. network_policies — the egress allowlist

Each named block is a policy bound to specific binaries, allowing specific hosts, ports, methods, paths. Here is the shape of the allowlist that ships by default:

Policy block Allowed for these binaries Hosts Methods/paths
claude_code /usr/local/bin/claude api.anthropic.com, statsig.anthropic.com, sentry.io Anthropic: POST /v1/messages, POST /v1/messages/batches, GET /v1/messages/batches/**, POST /v1/complete. Sentry: GET /** onlyPOST is blocked to prevent exfil.
nvidia /usr/local/bin/claude, /usr/local/bin/openclaw integrate.api.nvidia.com, inference-api.nvidia.com POST /v1/chat/completions, POST /v1/completions, POST /v1/embeddings, GET /v1/models, GET /v1/models/**
clawhub openclaw, node clawhub.ai GET /**, POST /** — plugin discovery + install
openclaw_api openclaw, node openclaw.ai GET /**, POST /** — auth flows
openclaw_docs openclaw docs.openclaw.ai GET /** — docs are read‑only
npm_registry openclaw, npm, node registry.npmjs.org GET /** — fetch packages, never publish

Things to notice:

4. Presets — opt‑in extensions

Each file in policies/presets/ is a small policy fragment you can add via nemoclaw <name> policy-add. For example, presets/telegram.yaml:

preset:
  name: telegram
  description: "Telegram Bot API access"

network_policies:
  telegram_bot:
    name: telegram_bot
    endpoints:
      - host: api.telegram.org
        port: 443
        rules:
          - allow: { method: GET,  path: "/bot*/**" }
          - allow: { method: POST, path: "/bot*/**" }
          - allow: { method: GET,  path: "/file/bot*/**" }
    binaries:
      - { path: /usr/local/bin/node }

Notice /bot*/** — the bot token is in the URL path, but because OpenShell terminates TLS it can inspect and template it. The sandbox holds a placeholder token; the L7 proxy rewrites it to the real one stored in the OpenShell telegram provider.

"How do I open a new egress path?" — the decision tree

Is this a one‑off, exploratory, session‑local allow?
   └── yes → let the agent try; it'll fail; approve in `openshell term`.
              Session‑scoped, not persisted.

Is there already a preset for this integration?
   └── yes → nemoclaw <name> policy-add                  (interactive, confirms endpoints)
   └── yes → nemoclaw <name> policy-add --dry-run        (preview first)

Is it a new integration you want saved for everyone?
   └── add or edit a file in nemoclaw-blueprint/policies/presets/*.yaml
       then nemoclaw onboard (rebuilds/retargets the sandbox)

Is it something the *baseline* should always allow?
   └── edit nemoclaw-blueprint/policies/openclaw-sandbox.yaml
       then nemoclaw onboard
       (also works without rebuild for network-only changes:
        openshell policy set <name> --policy file.yaml --wait)

Rule: prefer presets over editing the baseline. The baseline is the "least common denominator" everyone inherits; presets are the user‑visible opt‑in surface.

Approving live in openshell term

When the agent hits a blocked host, OpenShell logs it and surfaces it in the TUI:

openshell term

You see the destination host, port, binary, and HTTP method/path. You approve or deny. Approved endpoints are merged into the sandbox's running policy as a new durable revision and persist across sandbox restarts — they are not written back into your YAML file, but they do survive reboots of the sandbox. They only reset when you destroy and recreate the sandbox (e.g. via nemoclaw onboard). This matters in practice: if you approve a broad CDN once in a hurry, it stays approved until a recreate — so for anything you wouldn't want lingering, either deny it, or put it into a preset with appropriate scoping and re‑onboard.

Seeing the approval loop for the first time: the NemoClaw repo ships scripts/walkthrough.sh, which opens a split tmux session with the OpenShell TUI on the left and an agent on the right, so you can watch blocks appear and approve them live while the agent is actively trying things. It requires tmux and NVIDIA_API_KEY. This is the fastest way to feel how the approval loop works without having to build a whole scenario yourself.

Remote sandboxes: SSH in and run openshell term on the host, or port‑forward the gateway.

The four layers again, in "what do I do" form

Layer If I want to change it How
Filesystem Make a new path writable, or lock one down Edit openclaw-sandbox.yaml filesystem_policy, run nemoclaw onboard (Landlock is locked at creation).
Process Change user/group, seccomp profile Edit openclaw-sandbox.yaml process:, run nemoclaw onboard.
Network Add/remove hosts, methods, paths Edit baseline or preset → nemoclaw onboard. Or openshell policy set for hot‑reload. Or approve live in openshell term.
Inference Change backing model or provider openshell inference set --provider <p> --model <m> (hot). Or rerun nemoclaw onboard to persist the choice via blueprint profile.

Three "why is it designed this way" notes you'll appreciate

  1. Static vs dynamic policy lifecycles exist because Landlock and seccomp are kernel‑level and apply at process start; you can only tighten them at runtime, never loosen. OpenShell therefore locks filesystem/process at creation and keeps network/inference hot‑swappable.
  2. Binary pinning is not belt‑and‑suspenders — it's the thing that lets a single sandbox host several agents/tools (claude, openclaw, node, npm) without each one inheriting everyone else's reach. Policy scoping is by binaries: path, not by a global "sandbox allowlist".
  3. The sandbox trusts nothing it stores. All high‑value secrets live in OpenShell providers on the host. The sandbox holds placeholders. This is why nemoclaw onboard explicitly filters DISCORD_BOT_TOKEN, SLACK_BOT_TOKEN, TELEGRAM_BOT_TOKEN, and provider API keys out of the sandbox creation command — so they can't leak as build args.

You've now got the concepts, the commands, and the policies. The back‑of‑napkin rule remains:

OpenClaw is the app. OpenShell is the jail. NemoClaw is how you put the app in the jail reproducibly, with NVIDIA's hardening defaults and a single command.

If you can run something in OpenClaw, you can run it in NemoClaw — either untouched inside the sandbox, or after adding a policy preset, or after flipping an inference profile. Doc 03 is the translation layer; this doc is the guardrails.

When you outgrow the presets

Everything above is the hand-curated NemoClaw view. When you need the full YAML schema — every field, every enforcement mode, every TLS option OpenShell supports — go upstream to the NVIDIA OpenShell docs:


Next: 05-nemoclaw.md — deeper dive into the NemoClaw integration layer (plugin, blueprint, onboarding lifecycle).