Problem Statement
NemoClaw bakes a single primary agent into the sandbox openclaw.json at onboard time. The only agent-level config currently supported is agents.defaults.model. There is no way to define additional static agents in agents.list[] through the NemoClaw environment variable interface.
OpenClaw supports a multi-agent model where a primary agent can spawn child agent sessions (sessions_spawn) targeting a configured agentId. Those secondary agents are defined in agents.list[] in openclaw.json with their own workspace path, agentDir, tool policy, and spawn depth. Today there is no supported path to bake those entries into the config during NemoClaw onboarding — they would have to be written manually inside the sandbox after startup, which is not reproducible across re-onboards.
Proposed Design
New env var: NEMOCLAW_EXTRA_AGENTS_JSON
Operators provide a JSON array of agent config objects (one entry per secondary agent). NemoClaw base64-encodes it and passes it as a Docker build ARG, mirroring the pattern already used for MCP servers, messaging channels, and web config.
Format (JSON array, passed as NEMOCLAW_EXTRA_AGENTS_JSON):
[
{
"id": "research",
"workspace": "/sandbox/.openclaw-data/workspace-research",
"agentDir": "/sandbox/.openclaw-data/agents/research",
"tools": {
"profile": "minimal",
"allow": ["web_search", "web_fetch", "memory_search", "read", "write", "sessions_yield"],
"deny": ["exec", "gateway", "cron", "sessions_spawn", "process"]
},
"subagents": {
"maxSpawnDepth": 0
}
}
]
Operator shell encoding:
NEMOCLAW_EXTRA_AGENTS_JSON='[{"id":"research",...}]'
src/lib/onboard.ts
Read NEMOCLAW_EXTRA_AGENTS_JSON from process.env. If set and non-empty, base64-encode and pass as NEMOCLAW_EXTRA_AGENTS_JSON_B64 ARG to the docker build command (same pattern as NEMOCLAW_MCP_SERVERS_B64, NEMOCLAW_WEB_CONFIG_B64, etc.).
Dockerfile
- Add
ARG NEMOCLAW_EXTRA_AGENTS_JSON_B64=W10= (default: empty JSON array []).
- In the Python config bake block, decode and merge into
agents.list[]:
extra_agents = json.loads(base64.b64decode(os.environ.get('NEMOCLAW_EXTRA_AGENTS_JSON_B64', 'W10=') or 'W10=').decode('utf-8'));
if extra_agents:
config.setdefault('agents', {})['list'] = extra_agents
The per-agent workspace and agentDir fields contain absolute sandbox paths. The existing migration-state.ts post-start rewrite already handles agents.list[0] path rewrites — that mechanism remains unchanged and covers the primary agent only.
Security considerations
Secondary agent tool policies must be explicitly configured by the operator via the JSON. The Dockerfile bake should pass the array through as-is without adding implicit tool grants. Per-agent maxSpawnDepth: 0 and explicit deny lists should be expressible in the JSON and honored by OpenClaw's agent loader.
Alternatives Considered
- Post-start config injection — Writing
openclaw.json inside the sandbox after startup. Not reproducible; openclaw.json is baked as root:root 444 to prevent tampering, so this would require a privilege escalation step.
- Separate NemoClaw command to register agents — A
nemoclaw agent add subcommand that modifies the running sandbox config. Adds runtime complexity; baking at image build time is simpler and more auditable.
- Single mega-agent with all tools — Give the primary agent all tools. Violates least-privilege; the primary agent should not have web search tools that expose it to prompt injection from arbitrary web content.
Agent Investigation
Codebase findings:
src/lib/onboard.ts — reads NEMOCLAW_MCP_SERVERS, NEMOCLAW_WEB_CONFIG_B64, NEMOCLAW_MESSAGING_CHANNELS, and others from process.env then encodes/passes them as Docker ARGs. No reading of any NEMOCLAW_EXTRA_AGENTS* variable.
Dockerfile Python block — config = {'agents': {'defaults': {'model': {...}}}, ...} — only agents.defaults is set. No agents.list key is written. The block does handle mcp_servers, memory_plugin_cfg, msg_channels — the pattern for adding extra_agents is identical.
nemoclaw/src/commands/migration-state.ts — rewrites agents.list[0].workspace and agents.list[0].agentDir after container start (path adjustment for sandbox bind mounts). This is not a baking mechanism and only touches index 0; it does not conflict with this feature.
NemoClaw/agents/hermes/manifest.yaml — defines Hermes as an alternative binary (Nous Research model agent), not an OpenClaw multi-agent config entry. Unrelated to this feature.
- No existing issues or in-progress branches for this feature were found.
Problem Statement
NemoClaw bakes a single primary agent into the sandbox
openclaw.jsonat onboard time. The only agent-level config currently supported isagents.defaults.model. There is no way to define additional static agents inagents.list[]through the NemoClaw environment variable interface.OpenClaw supports a multi-agent model where a primary agent can spawn child agent sessions (
sessions_spawn) targeting a configuredagentId. Those secondary agents are defined inagents.list[]inopenclaw.jsonwith their own workspace path, agentDir, tool policy, and spawn depth. Today there is no supported path to bake those entries into the config during NemoClaw onboarding — they would have to be written manually inside the sandbox after startup, which is not reproducible across re-onboards.Proposed Design
New env var:
NEMOCLAW_EXTRA_AGENTS_JSONOperators provide a JSON array of agent config objects (one entry per secondary agent). NemoClaw base64-encodes it and passes it as a Docker build ARG, mirroring the pattern already used for MCP servers, messaging channels, and web config.
Format (JSON array, passed as
NEMOCLAW_EXTRA_AGENTS_JSON):[ { "id": "research", "workspace": "/sandbox/.openclaw-data/workspace-research", "agentDir": "/sandbox/.openclaw-data/agents/research", "tools": { "profile": "minimal", "allow": ["web_search", "web_fetch", "memory_search", "read", "write", "sessions_yield"], "deny": ["exec", "gateway", "cron", "sessions_spawn", "process"] }, "subagents": { "maxSpawnDepth": 0 } } ]Operator shell encoding:
NEMOCLAW_EXTRA_AGENTS_JSON='[{"id":"research",...}]'src/lib/onboard.tsRead
NEMOCLAW_EXTRA_AGENTS_JSONfromprocess.env. If set and non-empty, base64-encode and pass asNEMOCLAW_EXTRA_AGENTS_JSON_B64ARG to the docker build command (same pattern asNEMOCLAW_MCP_SERVERS_B64,NEMOCLAW_WEB_CONFIG_B64, etc.).DockerfileARG NEMOCLAW_EXTRA_AGENTS_JSON_B64=W10=(default: empty JSON array[]).agents.list[]:The per-agent
workspaceandagentDirfields contain absolute sandbox paths. The existingmigration-state.tspost-start rewrite already handlesagents.list[0]path rewrites — that mechanism remains unchanged and covers the primary agent only.Security considerations
Secondary agent tool policies must be explicitly configured by the operator via the JSON. The Dockerfile bake should pass the array through as-is without adding implicit tool grants. Per-agent
maxSpawnDepth: 0and explicitdenylists should be expressible in the JSON and honored by OpenClaw's agent loader.Alternatives Considered
openclaw.jsoninside the sandbox after startup. Not reproducible;openclaw.jsonis baked as root:root 444 to prevent tampering, so this would require a privilege escalation step.nemoclaw agent addsubcommand that modifies the running sandbox config. Adds runtime complexity; baking at image build time is simpler and more auditable.Agent Investigation
Codebase findings:
src/lib/onboard.ts— readsNEMOCLAW_MCP_SERVERS,NEMOCLAW_WEB_CONFIG_B64,NEMOCLAW_MESSAGING_CHANNELS, and others fromprocess.envthen encodes/passes them as Docker ARGs. No reading of anyNEMOCLAW_EXTRA_AGENTS*variable.DockerfilePython block —config = {'agents': {'defaults': {'model': {...}}}, ...}— onlyagents.defaultsis set. Noagents.listkey is written. The block does handlemcp_servers,memory_plugin_cfg,msg_channels— the pattern for addingextra_agentsis identical.nemoclaw/src/commands/migration-state.ts— rewritesagents.list[0].workspaceandagents.list[0].agentDirafter container start (path adjustment for sandbox bind mounts). This is not a baking mechanism and only touches index 0; it does not conflict with this feature.NemoClaw/agents/hermes/manifest.yaml— defines Hermes as an alternative binary (Nous Research model agent), not an OpenClaw multi-agent config entry. Unrelated to this feature.