openclaw - 💡(How to fix) Fix sandbox.mode "non-main" semantics: per-session, not per-agent — counter-intuitive for "main-agent-only" use case [1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#73078Fetched 2026-04-28 06:27:45
View on GitHub
Comments
0
Participants
1
Timeline
0
Reactions
0

agents.defaults.sandbox.mode = "non-main" reads as "non-main agents are sandboxed", but the actual logic in runtime-status.ts treats it per-session, not per-agent. Since every agent has its own main session, "non-main" mode causes every agent's primary conversation (including dynamic peer agents) to bypass sandbox, leaving only sub-sessions / sub-agents inside the sandbox.

This makes the common ops pattern "let admin's main agent run on host for speed, but keep peer/dynamic agents sandboxed for isolation" not directly expressible — it requires a verbose agents.list[] per-agent override.

Root Cause

agents.defaults.sandbox.mode = "non-main" reads as "non-main agents are sandboxed", but the actual logic in runtime-status.ts treats it per-session, not per-agent. Since every agent has its own main session, "non-main" mode causes every agent's primary conversation (including dynamic peer agents) to bypass sandbox, leaving only sub-sessions / sub-agents inside the sandbox.

This makes the common ops pattern "let admin's main agent run on host for speed, but keep peer/dynamic agents sandboxed for isolation" not directly expressible — it requires a verbose agents.list[] per-agent override.

Fix Action

Fix / Workaround

Workarounds (verified working)

Verified on `openclaw 2026.4.23` running as a system service on Debian:

  • main DM: `dispatching to agent (session=agent:main:main)` → no `docker exec`, host-direct, ~5s overhead
  • peer DM: `docker exec -i openclaw-sbx-agent-feishu-...` confirmed in journal, sandbox path intact

Code Example

function shouldSandboxSession(cfg, sessionKey, mainSessionKey) {
    if (cfg.mode === "off") return false;
    if (cfg.mode === "all") return true;
    return sessionKey.trim() !== mainSessionKey.trim();   // "non-main"
}
RAW_BUFFERClick to expand / collapse

Summary

agents.defaults.sandbox.mode = "non-main" reads as "non-main agents are sandboxed", but the actual logic in runtime-status.ts treats it per-session, not per-agent. Since every agent has its own main session, "non-main" mode causes every agent's primary conversation (including dynamic peer agents) to bypass sandbox, leaving only sub-sessions / sub-agents inside the sandbox.

This makes the common ops pattern "let admin's main agent run on host for speed, but keep peer/dynamic agents sandboxed for isolation" not directly expressible — it requires a verbose agents.list[] per-agent override.

Code reference

dist/runtime-status-CiCXoPFR.js:9-12 (≡ src/agents/sandbox/runtime-status.ts):

function shouldSandboxSession(cfg, sessionKey, mainSessionKey) {
    if (cfg.mode === "off") return false;
    if (cfg.mode === "all") return true;
    return sessionKey.trim() !== mainSessionKey.trim();   // "non-main"
}

mainSessionKey is resolved per-agent via resolveAgentMainSessionKey({cfg, agentId}), so for any agent, its own main session matches and bypasses sandbox.

Reproduction

Setup: agents.defaults.sandbox.mode = "non-main", with one main agent (admin DM) and one dynamic feishu-ou_<peer> agent (auto-created via channels.feishu.dynamicAgentCreation).

Result:

SessionSandboxed?
agent:main:main (admin DM)❌ no (expected)
agent:main:<sub> (subagent)✅ yes
agent:feishu-ou_<peer>:main (peer DM)no — surprising
agent:feishu-ou_<peer>:<sub> (subagent)✅ yes

The third row breaks the expectation: peer-facing agents lose sandbox isolation on their primary path.

Real use case this blocks

Single-admin VPS deployment where:

  • Admin (main agent) wants fast DM responses → sandbox bypass acceptable (trusted)
  • External users via dynamic peer agents (feishu-ou_*, wecom-ou_*) → must stay sandboxed (untrusted)

"non-main" does the opposite of what the name suggests for this case. There is no single mode value that expresses it.

Workarounds (verified working)

Per-agent override works, but is verbose and requires duplicating workspace/agentDir paths that defaults would otherwise resolve:

```json { "agents": { "defaults": { "sandbox": { "mode": "all" } }, "list": [ { "id": "main", "workspace": "/home/openclaw/.openclaw/workspace-main", "agentDir": "/home/openclaw/.openclaw/agents/main/agent", "sandbox": { "mode": "off" } } ] } } ```

Verified on `openclaw 2026.4.23` running as a system service on Debian:

  • main DM: `dispatching to agent (session=agent:main:main)` → no `docker exec`, host-direct, ~5s overhead
  • peer DM: `docker exec -i openclaw-sbx-agent-feishu-...` confirmed in journal, sandbox path intact

Proposed fixes (any one would help)

  1. Add a `"main-agent-only"` (or `"main-agent"`) mode with semantics "only the `main` agent bypasses sandbox; every other agent — including their main sessions — runs in sandbox": ```js if (cfg.mode === "main-agent-only") return resolveSessionAgentId(sessionKey) !== "main"; ```
  2. Rename `"non-main"` → `"non-main-session"` to make session-vs-agent scope explicit (with backward-compat alias).
  3. Documentation for `agents.defaults.sandbox.mode`: explicitly call out that `"non-main"` is per-session, and link to the `agents.list[].sandbox` per-agent override pattern as the canonical "main-agent-only" recipe.

(1) is what most users likely want when they read "non-main" today; (2)+(3) are the lower-effort path.

Happy to send a PR for (1) if there's interest.

extent analysis

TL;DR

The most likely fix is to add a new sandbox mode, such as "main-agent-only", to allow only the main agent to bypass the sandbox while keeping other agents, including their main sessions, sandboxed.

Guidance

  • The current "non-main" mode is per-session, not per-agent, causing unexpected behavior for dynamic peer agents.
  • To achieve the desired behavior, consider adding a new mode, such as "main-agent-only", to the agents.defaults.sandbox.mode configuration.
  • Alternatively, renaming the "non-main" mode to "non-main-session" and adding documentation to clarify its per-session scope could also help.
  • A per-agent override using agents.list[] can be used as a workaround, but it is verbose and requires duplicating configuration.

Example

if (cfg.mode === "main-agent-only") return resolveSessionAgentId(sessionKey) !== "main";

This code snippet illustrates the proposed "main-agent-only" mode, where only the main agent's sessions are exempt from sandboxing.

Notes

The proposed fixes aim to address the inconsistency between the expected and actual behavior of the "non-main" mode. However, the best approach may depend on the specific use case and requirements.

Recommendation

Apply workaround: use the per-agent override pattern with agents.list[] until a new mode, such as "main-agent-only", is implemented. This approach allows for more fine-grained control over sandboxing for each agent, although it is more verbose.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix sandbox.mode "non-main" semantics: per-session, not per-agent — counter-intuitive for "main-agent-only" use case [1 participants]