> ## Documentation Index
> Fetch the complete documentation index at: https://felimet-hub.jmcores.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 05-3 NemoClaw Anatomy: NVIDIA's Hardened Shell for Always-On Agents

> NemoClaw is not another agent framework -- it is a hardened shell that wraps OpenClaw or Hermes inside an OpenShell sandbox. This unit dissects its origins, core technology, three-layer stack, configuration files, four security guardrails, and design lessons, then helps you evaluate the trade-offs of running your own agent inside NemoClaw.

export const FrameworkMap = ({lang = "zh", title, layers = []}) => {
  const t = lang === "en" ? {
    hint: "Click a module to see details",
    layer: "Layer",
    module: "Module",
    responsibilities: "Responsibilities",
    path: "Key path",
    relations: "Connected to",
    noSelect: "Select a module above"
  } : {
    hint: "點模組卡片查看職責與關係",
    layer: "層",
    module: "模組",
    responsibilities: "職責",
    path: "關鍵路徑",
    relations: "連結到",
    noSelect: "點上方模組查看詳細說明"
  };
  const [selected, setSelected] = useState(null);
  const safe = Array.isArray(layers) ? layers : [];
  const PALETTE = {
    blue: {
      base: "#5b6c8f",
      bg: "#5b6c8f18",
      border: "#5b6c8f55",
      label: "#46587a"
    },
    purple: {
      base: "#8a6f8e",
      bg: "#8a6f8e18",
      border: "#8a6f8e55",
      label: "#6f5673"
    },
    yellow: {
      base: "#c9a35b",
      bg: "#c9a35b18",
      border: "#c9a35b55",
      label: "#9a7a3c"
    },
    green: {
      base: "#8a9a7b",
      bg: "#8a9a7b18",
      border: "#8a9a7b55",
      label: "#6a7a5c"
    },
    teal: {
      base: "#6f9290",
      bg: "#6f929018",
      border: "#6f929055",
      label: "#527472"
    },
    rose: {
      base: "#ab7269",
      bg: "#ab726918",
      border: "#ab726955",
      label: "#8e564e"
    },
    amber: {
      base: "#b9835c",
      bg: "#b9835c18",
      border: "#b9835c55",
      label: "#96683f"
    }
  };
  const ROTATION = ["blue", "purple", "yellow", "green", "teal", "rose"];
  const getColor = (layer, index) => {
    const key = layer.color && PALETTE[layer.color] ? layer.color : ROTATION[index % ROTATION.length];
    return PALETTE[key];
  };
  const sel = (() => {
    if (!selected) return null;
    for (let li = 0; li < safe.length; li++) {
      const layer = safe[li];
      const m = layer.modules.find(m => m.id === selected);
      if (m) return {
        module: m,
        layerLabel: layer.label,
        color: getColor(layer, li)
      };
    }
    return null;
  })();
  const css = `
.fm-root{--fm-bg:#FAF8F3;--fm-surface2:rgba(0,0,0,0.022);
  --fm-border:rgba(0,0,0,0.08);--fm-text:#2b2722;--fm-dim:#6f6a62;
  --fm-faint:#9a9490;--fm-accent:#bf7551;--fm-card-bg:#fff;
  border:1px solid var(--fm-border);border-radius:14px;background:var(--fm-bg);
  color:var(--fm-text);overflow:hidden;font-family:inherit;}
.dark .fm-root{--fm-bg:#1b1a18;--fm-surface2:rgba(255,255,255,0.025);
  --fm-border:rgba(255,255,255,0.07);--fm-text:#e7e3da;
  --fm-dim:#a8a299;--fm-faint:#6a6560;--fm-card-bg:rgba(255,255,255,0.04);}
.fm-head{padding:13px 18px 11px;display:flex;align-items:center;gap:10px;border-bottom:1px solid var(--fm-border);flex-wrap:wrap;}
.fm-head-ic{color:var(--fm-accent);flex-shrink:0;}
.fm-head-title{font-size:14px;font-weight:700;letter-spacing:0.01em;flex:1;}
.fm-head-hint{font-size:11.5px;color:var(--fm-faint);}
.fm-layers{padding:14px 16px 10px;display:flex;flex-direction:column;gap:12px;}
.fm-layer{}
.fm-layer-label{font-size:10.5px;font-weight:700;letter-spacing:0.06em;text-transform:uppercase;
  margin-bottom:7px;display:flex;align-items:center;gap:6px;}
.fm-layer-label::after{content:"";flex:1;height:1px;opacity:0.4;}
.fm-modules{display:flex;flex-wrap:wrap;gap:8px;}
.fm-module{display:flex;flex-direction:column;gap:3px;padding:9px 13px;border-radius:9px;
  border:1px solid var(--fm-border);background:var(--fm-card-bg);cursor:pointer;
  transition:border-color .15s,background .15s,box-shadow .15s;text-align:left;
  min-width:120px;max-width:220px;flex:1 1 120px;}
.fm-mod-name{font-size:13px;font-weight:600;line-height:1.3;color:var(--fm-text);}
.fm-mod-summary{font-size:11.5px;line-height:1.5;color:var(--fm-dim);}
.fm-mod-path{font-size:10.5px;font-family:ui-monospace,"Cascadia Code","Consolas",monospace;
  color:var(--fm-faint);margin-top:2px;word-break:break-all;}
.fm-arrow{display:flex;justify-content:center;padding:2px 0;}
.fm-panel{border-top:1px solid var(--fm-border);padding:14px 18px;background:var(--fm-surface2);min-height:80px;}
.fm-panel-empty{display:flex;align-items:center;justify-content:center;height:60px;
  font-size:12.5px;color:var(--fm-faint);}
.fm-panel-layer{font-size:10.5px;font-weight:700;letter-spacing:0.06em;text-transform:uppercase;
  margin-bottom:5px;}
.fm-panel-name{font-size:16px;font-weight:700;margin-bottom:6px;line-height:1.3;}
.fm-panel-path{font-size:11px;font-family:ui-monospace,"Cascadia Code","Consolas",monospace;
  color:var(--fm-faint);margin-bottom:10px;word-break:break-all;}
.fm-panel-sec{font-size:10.5px;font-weight:700;letter-spacing:0.05em;text-transform:uppercase;
  color:var(--fm-dim);margin-bottom:5px;margin-top:10px;}
.fm-panel-detail{font-size:13.5px;line-height:1.65;color:var(--fm-dim);}
.fm-rels{display:flex;flex-wrap:wrap;gap:6px;margin-top:4px;}
.fm-rel{font-size:11.5px;padding:3px 9px;border-radius:20px;}
@media (max-width:600px){
  .fm-modules{flex-direction:column;}
  .fm-module{max-width:100%;}
  .fm-head-hint{display:none;}
}
`;
  return <div className="fm-root">
      <style>{css}</style>
      <div className="fm-head">
        <svg className="fm-head-ic" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
          <rect x="2" y="3" width="20" height="5" rx="2" />
          <rect x="2" y="10" width="20" height="5" rx="2" />
          <rect x="2" y="17" width="20" height="5" rx="2" />
        </svg>
        {title && <span className="fm-head-title">{title}</span>}
        <span className="fm-head-hint">{t.hint}</span>
      </div>

      <div className="fm-layers">
        {safe.map((layer, li) => {
    const c = getColor(layer, li);
    return <div className="fm-layer" key={layer.id || li}>
              <div className="fm-layer-label" style={{
      color: c.label
    }}>
                <span>{layer.label}</span>
                <span style={{
      flex: 1,
      height: "1px",
      background: c.border,
      display: "block"
    }} />
              </div>
              <div className="fm-modules">
                {(layer.modules || []).map(mod => {
      const isActive = selected === mod.id;
      return <button key={mod.id} type="button" className="fm-module" style={isActive ? {
        borderColor: c.base,
        background: c.bg,
        boxShadow: "0 0 0 3px " + c.base + "22"
      } : {}} onMouseEnter={e => {
        if (!isActive) {
          e.currentTarget.style.borderColor = c.base;
          e.currentTarget.style.background = c.bg;
        }
      }} onMouseLeave={e => {
        if (!isActive) {
          e.currentTarget.style.borderColor = "";
          e.currentTarget.style.background = "";
        }
      }} onClick={() => setSelected(selected === mod.id ? null : mod.id)}>
                      <div className="fm-mod-name" style={isActive ? {
        color: c.label
      } : {}}>{mod.name}</div>
                      {mod.summary && <div className="fm-mod-summary">{mod.summary}</div>}
                      {mod.path && <div className="fm-mod-path">{mod.path}</div>}
                    </button>;
    })}
              </div>
              {li < safe.length - 1 && <div className="fm-arrow">
                  <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke={getColor(safe[li + 1] || layer, li + 1).base} strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" style={{
      opacity: 0.5
    }}>
                    <path d="M12 5v14M5 15l7 7 7-7" />
                  </svg>
                </div>}
            </div>;
  })}
      </div>

      <div className="fm-panel">
        {sel ? <div>
            <div className="fm-panel-layer" style={{
    color: sel.color.label
  }}>{t.layer}: {sel.layerLabel}</div>
            <div className="fm-panel-name">{sel.module.name}</div>
            {sel.module.path && <div className="fm-panel-path">{sel.module.path}</div>}
            {sel.module.detail && <div>
                <div className="fm-panel-sec">{t.responsibilities}</div>
                <div className="fm-panel-detail">{sel.module.detail}</div>
              </div>}
            {sel.module.relations && sel.module.relations.length > 0 && <div>
                <div className="fm-panel-sec">{t.relations}</div>
                <div className="fm-rels">
                  {sel.module.relations.map((r, i) => <span className="fm-rel" key={i} style={{
    background: sel.color.bg,
    color: sel.color.label,
    border: "1px solid " + sel.color.border
  }}>{r.to}{r.label ? " — " + r.label : ""}</span>)}
                </div>
              </div>}
          </div> : <div className="fm-panel-empty">{t.noSelect}</div>}
      </div>
    </div>;
};

export const ArchFlow = ({nodes = [], lang = "zh"}) => {
  const t = lang === "en" ? {
    flow: "Data flow",
    hint: "Click any stage to see what it does",
    stage: "Stage"
  } : {
    flow: "資料流",
    hint: "點任一階段看它做什麼",
    stage: "階段"
  };
  const safe = Array.isArray(nodes) ? nodes : [];
  const [active, setActive] = useState(0);
  if (safe.length === 0) return null;
  const idx = Math.min(active, safe.length - 1);
  const current = safe[idx];
  const css = `
  .af-root{--af-bg:#FAF8F3;--af-surface:rgba(191,117,81,0.06);--af-surface2:rgba(0,0,0,0.025);--af-border:rgba(0,0,0,0.09);--af-text:#2b2722;--af-dim:#6f6a62;--af-faint:#8a8378;--af-rail:rgba(0,0,0,0.12);--af-accent:#bf7551;border:1px solid var(--af-border);border-radius:14px;background:var(--af-bg);color:var(--af-text);overflow:hidden;}
  .dark .af-root{--af-bg:#1b1a18;--af-surface:rgba(207,138,104,0.09);--af-surface2:rgba(255,255,255,0.03);--af-border:rgba(255,255,255,0.08);--af-text:#e7e3da;--af-dim:#a8a299;--af-faint:#8a8378;--af-rail:rgba(255,255,255,0.13);--af-accent:#cf8a68;}
  .af-head{padding:13px 18px 11px;display:flex;align-items:center;gap:9px;flex-wrap:wrap;border-bottom:1px solid var(--af-border);}
  .af-head-ic{color:var(--af-accent);flex-shrink:0;}
  .af-head-t{font-size:12px;font-weight:700;letter-spacing:.6px;color:var(--af-dim);text-transform:uppercase;}
  .af-head-h{font-size:12px;color:var(--af-faint);}
  .af-grid{display:flex;gap:0;align-items:stretch;}
  .af-list{flex:1 1 0;min-width:0;padding:12px 12px 16px;}
  .af-node{display:flex;align-items:stretch;gap:10px;width:100%;text-align:left;background:transparent;border:none;cursor:pointer;padding:0;color:inherit;font:inherit;-webkit-tap-highlight-color:transparent;}
  .af-railcol{width:22px;flex-shrink:0;display:flex;flex-direction:column;align-items:center;}
  .af-dot{width:9px;height:9px;border-radius:50%;margin-top:14px;background:var(--af-faint);opacity:.5;flex-shrink:0;transition:background .15s,box-shadow .15s,opacity .15s;}
  .af-line{width:2px;flex:1 1 0;background:var(--af-rail);min-height:10px;}
  .af-body{flex:1 1 0;min-width:0;padding:9px 12px;margin:2px 0;border-radius:9px;border:1px solid transparent;transition:background .15s,border-color .15s;}
  .af-node:hover .af-body{background:var(--af-surface2);}
  .af-node-on .af-body{background:var(--af-surface);border-color:rgba(191,117,81,.30);}
  .af-node-on .af-dot{background:var(--af-accent);opacity:1;box-shadow:0 0 0 4px rgba(191,117,81,.15);}
  .af-label{font-size:14.5px;font-weight:550;line-height:1.45;}
  .af-node-on .af-label{color:var(--af-accent);}
  .af-detail{width:300px;flex-shrink:0;border-left:1px solid var(--af-border);padding:16px 18px;background:var(--af-surface2);}
  .af-detail-k{font-size:11px;font-weight:700;letter-spacing:.5px;text-transform:uppercase;color:var(--af-accent);margin-bottom:7px;}
  .af-detail-l{font-size:16px;font-weight:600;margin-bottom:9px;line-height:1.35;}
  .af-detail-d{font-size:13.5px;line-height:1.65;color:var(--af-dim);}
  @media (max-width:640px){.af-grid{flex-direction:column;}.af-detail{width:auto;border-left:none;border-top:1px solid var(--af-border);}}
  `;
  return <div className="af-root">
      <style>{css}</style>
      <div className="af-head">
        <svg className="af-head-ic" xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect width="8" height="8" x="3" y="3" rx="2" /><path d="M7 11v4a2 2 0 0 0 2 2h4" /><rect width="8" height="8" x="13" y="13" rx="2" /></svg>
        <span className="af-head-t">{t.flow}</span>
        <span className="af-head-h">{t.hint}</span>
      </div>
      <div className="af-grid">
        <div className="af-list">
          {safe.map((n, i) => <button key={i} type="button" className={"af-node" + (i === idx ? " af-node-on" : "")} onClick={() => setActive(i)} onMouseEnter={() => setActive(i)}>
              <div className="af-railcol">
                <div className="af-dot" />
                {i < safe.length - 1 && <div className="af-line" />}
              </div>
              <div className="af-body">
                <div className="af-label">{n.label}</div>
              </div>
            </button>)}
        </div>
        <div className="af-detail">
          <div className="af-detail-k">{t.stage} {idx + 1} / {safe.length}</div>
          <div className="af-detail-l">{current.label}</div>
          <div className="af-detail-d">{current.detail}</div>
        </div>
      </div>
    </div>;
};

export const LearnerPrimer = ({items = [], lang = "zh"}) => {
  const t = lang === "en" ? {
    title: "Before this unit, be honest with yourself",
    sub: "If you can't answer these, that gap is exactly what this unit closes."
  } : {
    title: "讀這個單元前，先誠實面對",
    sub: "這幾題答不出來，正是這個單元要替你補的洞。"
  };
  const css = `
  .lp-root{--lp-bg:#FAF7F1;--lp-surface:rgba(191,117,81,0.05);--lp-border:rgba(0,0,0,0.09);--lp-edge:rgba(191,117,81,0.42);--lp-text:#2b2722;--lp-dim:#6f6a62;--lp-accent:#bf7551;border:1px solid var(--lp-border);border-left:3px solid var(--lp-edge);border-radius:13px;background:var(--lp-bg);color:var(--lp-text);overflow:hidden;margin:1.25rem 0;}
  .dark .lp-root{--lp-bg:#1b1a18;--lp-surface:rgba(207,138,104,0.07);--lp-border:rgba(255,255,255,0.08);--lp-edge:rgba(207,138,104,0.5);--lp-text:#e7e3da;--lp-dim:#a8a299;--lp-accent:#cf8a68;}
  .lp-head{display:flex;align-items:center;gap:9px;padding:13px 18px 11px;border-bottom:1px solid var(--lp-border);background:var(--lp-surface);}
  .lp-ic{color:var(--lp-accent);flex-shrink:0;}
  .lp-htx{display:flex;flex-direction:column;gap:1px;min-width:0;}
  .lp-title{font-size:14px;font-weight:650;line-height:1.3;letter-spacing:.01em;}
  .lp-sub{font-size:12px;color:var(--lp-dim);line-height:1.4;}
  .lp-list{list-style:none;margin:0;padding:10px 18px 14px;display:flex;flex-direction:column;gap:0;}
  .lp-item{display:flex;align-items:baseline;gap:11px;padding:7px 0;font-size:14px;line-height:1.6;border-top:1px solid var(--lp-border);}
  .lp-item:first-child{border-top:none;}
  .lp-mark{flex-shrink:0;color:var(--lp-accent);font-size:13px;font-weight:700;line-height:1.55;font-variant-numeric:tabular-nums;opacity:.85;}
  .lp-q{flex:1 1 0;min-width:0;color:var(--lp-text);}
  @media (max-width:620px){.lp-head{padding:12px 14px 10px;}.lp-list{padding:8px 14px 12px;}}
  `;
  return <div className="lp-root">
      <style>{css}</style>
      <div className="lp-head">
        <svg className="lp-ic" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10" /><circle cx="12" cy="12" r="6" /><circle cx="12" cy="12" r="2" /></svg>
        <span className="lp-htx">
          <span className="lp-title">{t.title}</span>
          <span className="lp-sub">{t.sub}</span>
        </span>
      </div>
      <ul className="lp-list">
        {items.map((q, i) => <li className="lp-item" key={i}>
            <span className="lp-mark">{String(i + 1).padStart(2, "0")}</span>
            <span className="lp-q">{q}</span>
          </li>)}
      </ul>
    </div>;
};

<LearnerPrimer
  lang="en"
  items={[
"NemoClaw is not an agent framework; it is a hardened shell.",
"Without OpenClaw or Hermes running inside it, NemoClaw has no meaning.",
"An always-on agent with no guardrails lets a prompt injection run with full host permissions.",
"Security policy buried in a docker run command -- how does the next maintainer audit that?",
"When upgrading upstream forces a rebase on your hardening layer, that is not design, that is debt.",
"Treating SSRF validation as 'remember to enable it' is already too late.",
"Agent logic unchanged, only the blueprint updated -- that is what separation of concerns looks like.",
]}
/>

<Info>
  **What this unit solves**

  NemoClaw is an open-source reference stack released by NVIDIA in March 2026. It runs always-on AI agents (OpenClaw, Hermes) inside an OpenShell sandbox. Rather than reinventing an agent framework, it provides a CLI onboarding flow, YAML blueprints, SSRF validation, network policies, and managed inference -- all of which transform an existing agent into a persistent service that an enterprise operations team can actually trust. This unit dissects NemoClaw from six angles: origins, core technology, system structure, configuration files, security, and design lessons, and positions it against [05-1](/en/code-agent/case-studies/openclaw), [05-2](/en/code-agent/case-studies/hermes-agent), and [05-4](/en/code-agent/case-studies/three-approaches-comparison).
</Info>

## Learning objectives

* [ ] Explain where NemoClaw sits in the stack (not another agent framework -- it is the hardening layer above OpenClaw/Hermes)
* [ ] Describe the three-layer architecture: OpenShell sandbox, NemoClaw CLI/Blueprint, and the OpenClaw or Hermes agent inside
* [ ] State the responsibilities of `blueprint.yaml`, `policies/`, and `model-specific-setup/`
* [ ] List NemoClaw's four security guardrails (network policies, credential sanitization, SSRF validation, Docker capability drops) and the attack surface each addresses
* [ ] Evaluate the trade-offs of running your own agent inside NemoClaw

***

## 1. Origins and positioning

* **Release date**: 2026-03-16, open-sourced by NVIDIA at GTC 2026, Apache 2.0 license (as of 2026-06)
* **Why it exists**: always-on agents (persistent connections, message-triggered) introduce new enterprise attack surfaces: prompt injection coercing the agent to call external APIs, dependency upgrades smuggling backdoors, container escapes, and credentials leaking through error messages. NemoClaw provides a hardening template that keeps full agentic capability while satisfying an ops team
* **Relationship with [05-1 (OpenClaw)](/en/code-agent/case-studies/openclaw) and [05-2 (Hermes-Agent)](/en/code-agent/case-studies/hermes-agent)**: wraps both, does not replace either. Without an agent running inside it, NemoClaw has no purpose
* **Selection rationale**: OpenShell (NVIDIA's own sandbox engine) + Claude Code-style sub-agent + default OpenClaw compatibility + dual CLI alias support for Hermes
* **Compatibility with existing OpenClaw mechanisms**: the `nemoclaw/` Commander plugin injects commands; OpenClaw's heartbeat, SOUL.md, and skills mechanisms require no modification

## 2. Core technology

* **Dual-language stack** (per the official AGENTS.md):
  * TypeScript: CLI core (`src/lib/`) and OpenClaw plugin (`nemoclaw/src/`)
  * YAML: blueprints (`nemoclaw-blueprint/blueprint.yaml`) and policies (`nemoclaw-blueprint/policies/`)
  * Bash/Python: scripts, E2E tooling
  * CommonJS (`bin/`): stable entry-point launcher, versioned separately from the TypeScript build output
* **OpenShell sandbox**: each agent runs in an isolated runtime; toolset and network access are constrained (sandbox details discussed in [05-4](/en/code-agent/case-studies/three-approaches-comparison))
* **Managed inference**: `@aws-sdk/client-bedrock-runtime` + routing layer + `model-specific-setup` registry handles cross-provider compatibility for the same agent
* **Four security guardrails**: network policies, credential sanitization, SSRF validation, Docker capability drops (Section 5)
* **Multi-agent support**: native OpenClaw (default) and Hermes (via `NEMOCLAW_AGENT=hermes` env var, CLI alias `nemohermes`)
* **Runtime requirement**: Node.js >= 22.16.0 (declared in `engines`, implying use of newer V8 and ESM features)

## 3. System structure: how the three layers compose

<ArchFlow
  lang="en"
  nodes={[
{ label: "NemoClaw CLI", detail: "TypeScript core (src/lib/): onboard, credentials, inference, policies, preflight, runner. bin/ exposes two stable entry points -- nemoclaw.js and nemohermes.js." },
{ label: "Blueprint (YAML)", detail: "nemoclaw-blueprint/blueprint.yaml declares sandbox structure, default policies, and inference routing. policies/ governs egress; model-specific-setup/ manages the agent-to-model compatibility registry." },
{ label: "OpenShell sandbox", detail: "Each agent runs in an isolated OpenShell runtime. Toolset and network access are enforced by the shell. The sandbox boundary is the unit of security auditing." },
{ label: "OpenClaw (default)", detail: "TypeScript agent core. skills/, heartbeat, and channels are fully preserved. The nemoclaw/ Commander plugin injects shell-level commands without forking upstream." },
{ label: "Hermes (optional)", detail: "Python agent. Activated by NEMOCLAW_AGENT=hermes; CLI alias nemohermes; run_agent.py is the entry point. Both agents share one NemoClaw package -- no reinstall needed to switch." },
]}
/>

<FrameworkMap
  lang="en"
  title="NemoClaw Three-Layer Stack"
  layers={[
{
  id: "hardened-shell",
  color: "rose",
  label: "Hardened shell layer — NemoClaw core and blueprint",
  modules: [
    {
      id: "cli-core",
      name: "CLI core",
      path: "src/lib/",
      summary: "TypeScript: onboard, credentials, inference, policies, preflight, runner",
      detail: "The NemoClaw control plane. Handles initial onboarding, credential management, preflight security checks, inference routing, and runtime orchestration. Exposes two stable entry points via bin/: nemoclaw.js and nemohermes.js. Neither forks upstream OpenClaw or Hermes; NemoClaw wraps them.",
      relations: [{ to: "blueprint.yaml", label: "reads policy from" }, { to: "OpenShell", label: "starts sandbox" }],
    },
    {
      id: "blueprint",
      name: "blueprint.yaml",
      path: "nemoclaw-blueprint/blueprint.yaml",
      summary: "Sandbox structure, default policies, inference routing",
      detail: "The single source of truth for the entire stack. Declares sandbox structure, default network policies, and inference routing. Distinct from the agent's openclaw.json: the blueprint is 'what ops requires'; the workspace config is 'what the agent prefers.' Changing the blueprint requires a sandbox restart.",
      relations: [{ to: "policies/", label: "references egress rules" }, { to: "model-specific-setup/", label: "references compatibility registry" }],
    },
    {
      id: "policies",
      name: "policies/",
      path: "nemoclaw-blueprint/policies/",
      summary: "Network egress rules (YAML)",
      detail: "YAML-defined egress control rules. Governs which outbound network destinations the sandboxed agent can reach. Auditable in version control; changes do not require rebuilding the image.",
      relations: [{ to: "blueprint.yaml", label: "referenced by" }],
    },
    {
      id: "model-setup",
      name: "model-specific-setup/",
      path: "nemoclaw-blueprint/model-specific-setup/",
      summary: "Agent-to-model compatibility registry (JSON)",
      detail: "Records compatibility between agent versions and model endpoints. Allows NemoClaw to apply model-specific workarounds without changing agent code. Updated independently from blueprint policy.",
      relations: [{ to: "blueprint.yaml", label: "referenced by" }],
    },
  ],
},
{
  id: "sandbox",
  color: "amber",
  label: "Sandbox layer — isolation boundary",
  modules: [
    {
      id: "openshell",
      name: "OpenShell",
      path: "nemoclaw/src/blueprint/",
      summary: "Isolated runtime: toolset and network access enforced by the shell",
      detail: "Each agent runs in an isolated OpenShell runtime. Toolset scope and network access are enforced by the shell boundary, not by agent-side configuration. This is the unit of security auditing: if a prompt injection escapes, it is contained to the OpenShell instance, not the host.",
      relations: [{ to: "OpenClaw", label: "runs inside" }, { to: "Hermes", label: "runs inside (optional)" }],
    },
    {
      id: "ssrf-validation",
      name: "SSRF validation",
      path: "nemoclaw/src/blueprint/",
      summary: "Server-side request forgery guard on all outbound agent requests",
      detail: "Validates all outbound requests made by the agent against the policy allowlist before they leave the sandbox. Implemented in the blueprint runner, not the agent. Treating SSRF validation as 'remember to enable it' is a design flaw; NemoClaw enforces it at the harness level.",
      relations: [{ to: "policies/", label: "validates against" }],
    },
  ],
},
{
  id: "agent",
  color: "green",
  label: "Agent layer — pluggable inner agent",
  modules: [
    {
      id: "openclaw-inner",
      name: "OpenClaw (default)",
      path: "agents/openclaw/",
      summary: "Default inner agent; skills, heartbeat, and channels fully preserved",
      detail: "The default agent running inside NemoClaw. All OpenClaw capabilities (skills, heartbeat scheduling, multi-channel routing) are preserved. The nemoclaw/ Commander plugin injects shell-level commands without forking upstream OpenClaw code.",
      relations: [{ to: "OpenShell", label: "contained by" }, { to: "Hermes", label: "interchangeable with" }],
    },
    {
      id: "hermes-inner",
      name: "Hermes (optional)",
      path: "agents/hermes/",
      summary: "Python agent; activated by NEMOCLAW_AGENT=hermes, entry via run_agent.py",
      detail: "Alternative inner agent. Activated by setting NEMOCLAW_AGENT=hermes or using the nemohermes CLI alias. run_agent.py is the entry point. Both agents share one NemoClaw package installation; no reinstall is needed to switch between them.",
      relations: [{ to: "OpenShell", label: "contained by" }, { to: "OpenClaw (default)", label: "interchangeable with" }],
    },
  ],
},
]}
/>

Component map (per official AGENTS.md):

| Path                                       | Language         | Responsibility                                                           |
| ------------------------------------------ | ---------------- | ------------------------------------------------------------------------ |
| `bin/`                                     | JavaScript (CJS) | CLI launcher (`nemoclaw.js` / `nemohermes.js`) and compatibility helpers |
| `src/lib/`                                 | TypeScript       | CLI core: onboard, credentials, inference, policies, preflight, runner   |
| `nemoclaw/`                                | TypeScript       | OpenClaw plugin (Commander extension)                                    |
| `nemoclaw/src/blueprint/`                  | TypeScript       | Runner, snapshot, SSRF validation, state management                      |
| `nemoclaw/src/commands/`                   | TypeScript       | Slash commands, migration state                                          |
| `nemoclaw/src/onboard/`                    | TypeScript       | Onboarding config                                                        |
| `nemoclaw-blueprint/`                      | YAML             | Blueprint definition and network policies                                |
| `nemoclaw-blueprint/policies/`             | YAML             | Network egress rules                                                     |
| `nemoclaw-blueprint/model-specific-setup/` | JSON             | Agent-to-model compatibility registry                                    |
| `agents/openclaw/`, `agents/hermes/`       | Assets           | Agent deployment assets                                                  |
| `.agents/skills/`                          | Markdown         | 11 user skills plus maintainer and contributor tiers                     |

<Tip>
  **The fastest way to understand a repo: read AGENTS.md first**

  NemoClaw's own `AGENTS.md` is the structured "how this project works" summary written for agents to consume -- more structured than the README, faster to grasp than the source. When approaching any unfamiliar open-source project, locating the `AGENTS.md` / `CLAUDE.md` / `CONTRIBUTING.md` trio first is the time-saving shortcut.
</Tip>

## 4. Configuration files: four layers of customization

YAML-primary, TypeScript-secondary, divided into four layers:

### 4.1 Blueprint: single source of truth for the entire stack

* `nemoclaw-blueprint/blueprint.yaml`: declares sandbox structure, default policies, inference routing
* Distinction from the agent workspace's `openclaw.json`: the blueprint is "the state ops wants," the workspace config is "the agent's own preferences." Keeping them separate prevents users from accidentally overwriting enterprise policies
* Changing the blueprint requires a sandbox restart; changing workspace config is hot-reload

### 4.2 Network policies: egress control

* Location: `nemoclaw-blueprint/policies/`
* Behavior: allowlist external targets, block SSRF, restrict ports and protocols
* Rationale: the largest attack surface for an always-on agent is prompt injection coercing it to call an external API to exfiltrate data or upload a token. Network policy is the last gate before traffic leaves the host
* Customization: via `nemoclaw manage policy` or direct YAML editing

### 4.3 Model-specific setup: compatibility registry

* Location: `nemoclaw-blueprint/model-specific-setup/*.json`
* Contents: which agent maps to which provider, what special headers or parameters are required
* Use case: the same OpenClaw agent running against Bedrock vs. vLLM needs different system-prompt prefixes and token limits; this registry collapses that difference into one declarative file
* Lesson: treat "model/service compatibility" as declarable data, not hardcoded agent logic

### 4.4 Skills: documentation the agent reads

* Location: `.agents/skills/`, three audience tiers
  * `nemoclaw-user-*` (10 files, end users: overview, get-started, configure-inference, configure-security, manage-policy, manage-sandboxes, monitor-sandbox, deploy-remote, agent-skills, reference)
  * `nemoclaw-maintainer-*` (project maintainers)
  * `nemoclaw-contributor-*` (codebase contributors)
* Load mechanism: use `nemoclaw-skills-guide` skill to get the full directory and decision tree
* Design observation: audience segmentation treated as first-class metadata, not collapsed into a single tier

### User-side config directory: `~/.nemoclaw/`

Sections 4.1 through 4.4 cover the hardening configuration you (or ops) declare inside the repo's `nemoclaw-blueprint/` -- committed to version control, expressing "what this stack should look like." Separately, there is a set of files outside the repo, under your home directory: the runtime state generated by the CLI when you run `nemoclaw onboard`. This is what the CLI reads and writes day to day (as of 2026-06):

<Tree>
  <Tree.Folder name="~/.nemoclaw" defaultOpen>
    <Tree.File name="config.json · onboarding state, inference route configuration" />

    <Tree.File name="sandboxes.json · sandbox registry (with metadata)" />

    <Tree.File name="credentials.json · user API keys (plaintext JSON, file mode 600)" />

    <Tree.File name="onboard.json · onboarding configuration snapshot" />

    <Tree.Folder name="state" defaultOpen>
      <Tree.File name="nemoclaw.json · runtime execution state" />
    </Tree.Folder>
  </Tree.Folder>
</Tree>

Three points:

* **Division between `~/.nemoclaw/` and the repo blueprint**: the blueprint (`nemoclaw-blueprint/blueprint.yaml`) is a declarative blueprint committed to version control; `~/.nemoclaw/` is the runtime state produced by onboarding on this specific machine and is not committed. The former is design; the latter is current machine state.
* **A second OpenClaw config lives inside the sandbox**: the sandbox container holds `/sandbox/.openclaw/openclaw.json` (agent config, model, gateway) and `.config-hash` (SHA256 integrity check). This is inside the container, not on the host, and maps directly to the `openclaw.json` discussed in [05-1](/en/code-agent/case-studies/openclaw) -- just managed by NemoClaw inside the sandbox.
* **Uninstall removes all of `~/.nemoclaw/`**: because runtime state and design blueprint are separate, uninstalling clears home-directory state without touching the repo blueprint.

<Warning>
  **`credentials.json` is plaintext -- no encryption, no OS keychain**

  NemoClaw writes user-supplied API keys as plaintext JSON to `~/.nemoclaw/credentials.json`, relying only on file mode 600 for access control. The official documentation states it does not encrypt the file and does not integrate with the operating system keychain. Exclude it from cloud sync (iCloud, OneDrive, Dropbox) and broad backup policies; otherwise plaintext keys will be synced to the cloud. By contrast, the provider inference token is injected by the OpenShell gateway at egress and never written to the host disk -- a better security model. The plaintext exposure risk is concentrated in `credentials.json`.
</Warning>

## 5. Security: four guardrails and the attack surface each covers

| Guardrail                                | Implementation                   | Attack surface                                                                     | What to verify                                               |
| ---------------------------------------- | -------------------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------ |
| Network policies                         | `nemoclaw-blueprint/policies/`   | Agent coerced to call external APIs, SSRF, token exfiltration                      | Default-deny? Can a plugin bypass the policy?                |
| Credential sanitization                  | `src/lib/credentials`            | API keys and tokens leaking via logs or error messages                             | Does the log auto-redact? Which secret types are recognized? |
| SSRF validation                          | `nemoclaw/src/blueprint/ssrf.ts` | Agent fetches a URL that hits an internal metadata service (169.254.169.254, etc.) | Rejects loopback / link-local / RFC1918?                     |
| Docker capability drops + process limits | OpenShell runtime                | Container escape, CPU/memory exhaustion                                            | Default drop ALL caps? `no-new-privileges` set?              |

<Warning>
  **Security is a deployment prerequisite, not an add-on feature**

  The very first badge in NemoClaw's README is "Security: Report a Vulnerability," and SECURITY.md requires vulnerabilities to be submitted through NVIDIA PSIRT or a PGP-encrypted channel -- not as public issues. **This signals the intended context: the hardening layer is not decoration; it is the prerequisite for deploying an always-on agent in an enterprise environment.** If you want to run OpenClaw or Hermes in an enterprise setting, do not put it into production without an equivalent hardening layer.
</Warning>

## 6. What to internalize: six design lessons

* **Shell as policy**: rather than letting the agent decide whether it can reach external networks, the shell declares (YAML blueprint) and enforces (OpenShell + policy engine). Security policy and agent logic are fully decoupled
* **Managed inference as a cross-cutting concern**: model compatibility is not the agent code's problem; it is the deployment layer's. The `model-specific-setup` registry makes "same agent, multiple models" declarable data
* **Three-tier documentation**: user / maintainer / contributor each get their own skill set, avoiding the information overload of one README serving everyone
* **Plugin, not fork**: `nemoclaw/` is an OpenClaw plugin (Commander extension), not a fork. Upgrading upstream requires no rebase
* **Dual CLI alias**: `nemoclaw` (OpenClaw) and `nemohermes` (Hermes) share one package; switching agents requires no reinstall
* **Sandbox boundary as audit unit**: OpenShell is both runtime and audit boundary. The same agent in two sandboxes is two audit units; events are independently traceable

<Note>
  **Mapping this to your own deployment**

  Suppose you want to deploy a team-internal OpenClaw to staging:

  <Steps>
    <Step title="Write the blueprint">
      After `git clone` of OpenClaw, write `nemoclaw-blueprint/blueprint.yaml` describing which internal APIs the agent may call, which external hosts are blocked, and which inference provider to use.
    </Step>

    <Step title="Run onboard">
      Run `npx nemoclaw onboard`; the guided flow auto-generates `policies/` and `model-specific-setup/`.
    </Step>

    <Step title="Deploy to staging">
      `npx nemoclaw deploy-remote` pushes to staging.
    </Step>

    <Step title="Monitor">
      On staging, use `npx nemoclaw monitor-sandbox` to observe SSRF attempts, policy violations, and credential exposure events.
    </Step>

    <Step title="Switch inference provider">
      Need to change providers? Edit the corresponding JSON in `model-specific-setup/` and restart the sandbox. Agent code is untouched.
    </Step>
  </Steps>

  This path demonstrates the "agent logic unchanged, only the blueprint updated" benefit: upgrading OpenClaw upstream does not force a rebase of your hardening layer.
</Note>

## 7. Questions to ask yourself

* Does your always-on agent have equivalent four-guardrail coverage? If not, what is the exposed risk surface?
* Is your blueprint or policy expressed as code (version-controlled, auditable) or buried in a `docker run` command or Helm values file?
* When you upgrade your agent's upstream, is the hardening layer preserved as-is or forced into a rebase?
* Is your skill or documentation segmentation fixed or does it drift as the agent evolves?
* Is your SSRF validation and credential sanitization "on by default" or "remember to enable it"?

## 8. An analogy

NemoClaw is like putting a mobile robot inside a reinforced glass display case: the robot itself is unchanged (OpenClaw stays OpenClaw, Hermes stays Hermes), but the case decides what it can touch, what it cannot, who it can see, and who can see it. **The case's policies (YAML blueprint) are version-controlled; the robot's personality (SOUL.md) is also version-controlled. The two layers are managed separately.**

## 9. Positioning against 05-1, 05-2, and 05-4

| Dimension         | 05-1 OpenClaw                        | 05-2 Hermes-Agent          | 05-3 NemoClaw                                          |
| ----------------- | ------------------------------------ | -------------------------- | ------------------------------------------------------ |
| Role              | Agent core                           | Agent core                 | Hardened shell for agents                              |
| Language          | TypeScript                           | Python                     | TypeScript + YAML + Bash                               |
| Sandbox           | Optional (`agents.defaults.sandbox`) | 6 terminal backends        | Mandatory (OpenShell)                                  |
| Network policy    | Tool-level                           | Tool-level                 | Blueprint + policy engine                              |
| Inference routing | Client-side                          | Client-side                | Managed inference + registry                           |
| Skill loading     | `skills/`                            | `skills/` (progressive)    | `.agents/skills/` three-tier                           |
| Enterprise-ready  | No (local-first, personal)           | No (local-first, personal) | Yes (policy-as-code + formal vulnerability disclosure) |

***

## Hands-on exercises

<Steps>
  <Step title="Read AGENTS.md">
    After `git clone https://github.com/NVIDIA/NemoClaw`, run `cat AGENTS.md` and map its content against this unit's "System structure" section. The project's own AGENTS.md is the most authoritative "how this project works" summary.
  </Step>

  <Step title="Examine a blueprint">
    Read `nemoclaw-blueprint/blueprint.yaml` and one example from `nemoclaw-blueprint/policies/` to get a concrete feel for what policy-as-code looks like.
  </Step>

  <Step title="Observe three-tier naming">
    Run `gh api repos/NVIDIA/NemoClaw/contents/.agents/skills --jq '.[].name'` to list all skills and observe the naming convention across user / maintainer / contributor tiers.
  </Step>
</Steps>

## Common pitfalls

* **Thinking NemoClaw is another agent framework**: it is a hardened shell with no `AIAgent` main loop of its own. Without OpenClaw or Hermes running inside it, NemoClaw has no meaning
* **Treating the blueprint as an ordinary config file**: the blueprint is the declared desired state of enterprise policy; changing it requires a sandbox restart and a passing preflight check. Do not bypass preflight by directly editing a running sandbox
* **Mixing `nemoclaw` and `nemohermes` commands**: the two manage onboarding for different agents. Mixing them writes OpenClaw configuration into a Hermes sandbox (the directory structures differ)
* **Ignoring `model-specific-setup/` version compatibility**: upgrading a model provider without updating the registry causes the agent to assume the new model has the old model's capabilities, producing silent failures

## Self-check

<Check>
  **Self-check**

  1. Can you draw a stack diagram showing the relationship between OpenShell, NemoClaw, and OpenClaw?
  2. Can you state the attack surface each of the four security guardrails addresses?
  3. Can you explain why `nemoclaw-blueprint/` uses YAML rather than TypeScript or JSON?
  4. Can you evaluate what would need to change -- and what could be preserved -- if you moved your existing OpenClaw deployment into NemoClaw?
</Check>

## Sources and further reading

Factual claims are grounded in official documentation; fast-changing items are annotated as of 2026-05.

<div className="references">
  * \[1] NVIDIA, "NemoClaw," GitHub repository, Apache 2.0, Mar. 2026. [https://github.com/NVIDIA/NemoClaw](https://github.com/NVIDIA/NemoClaw) (as of 2026-06)

  * \[2] NVIDIA, "NemoClaw Documentation," official docs. [https://docs.nvidia.com/nemoclaw/latest/](https://docs.nvidia.com/nemoclaw/latest/) (as of 2026-06)

  * \[3] NVIDIA, "How It Works," NemoClaw Docs. [https://docs.nvidia.com/nemoclaw/latest/about/how-it-works.html](https://docs.nvidia.com/nemoclaw/latest/about/how-it-works.html) (as of 2026-06)

  * \[4] NVIDIA, "Architecture Reference," NemoClaw Docs. [https://docs.nvidia.com/nemoclaw/latest/reference/architecture.html](https://docs.nvidia.com/nemoclaw/latest/reference/architecture.html) (as of 2026-06)

  * \[5] NVIDIA, "Ecosystem Positioning," NemoClaw Docs. [https://docs.nvidia.com/nemoclaw/latest/about/ecosystem.html](https://docs.nvidia.com/nemoclaw/latest/about/ecosystem.html) (as of 2026-06)

  * \[6] NVIDIA, "Inference Options," NemoClaw Docs. [https://docs.nvidia.com/nemoclaw/latest/inference/inference-options.html](https://docs.nvidia.com/nemoclaw/latest/inference/inference-options.html) (as of 2026-06)

  * \[7] NVIDIA, "Network Policies Reference," NemoClaw Docs. [https://docs.nvidia.com/nemoclaw/latest/reference/network-policies.html](https://docs.nvidia.com/nemoclaw/latest/reference/network-policies.html) (as of 2026-06)

  * \[8] NVIDIA, "Sandbox Hardening," NemoClaw Docs. [https://docs.nvidia.com/nemoclaw/latest/deployment/sandbox-hardening.html](https://docs.nvidia.com/nemoclaw/latest/deployment/sandbox-hardening.html) (as of 2026-06)

  * \[9] NVIDIA, "Security Best Practices," NemoClaw Docs. [https://docs.nvidia.com/nemoclaw/latest/security/best-practices.html](https://docs.nvidia.com/nemoclaw/latest/security/best-practices.html) (as of 2026-06)

  * \[10] NVIDIA, "SECURITY.md -- Vulnerability Disclosure," NemoClaw GitHub. [https://github.com/NVIDIA/NemoClaw/blob/main/SECURITY.md](https://github.com/NVIDIA/NemoClaw/blob/main/SECURITY.md) (as of 2026-06)
</div>

* Related: [05-1](/en/code-agent/case-studies/openclaw) OpenClaw agent core; [05-2](/en/code-agent/case-studies/hermes-agent) Hermes-Agent core; [05-4](/en/code-agent/case-studies/three-approaches-comparison) three-approach comparison (includes in-depth sandbox discussion); [01-6](/en/code-agent/foundations/harness-engineering) harness engineering six components (NemoClaw's security shell is a complete real-world instance of the security-boundaries component).
