Skip to content

No agent mode exposes workspace-write *with* network access #406

Description

@marcelo-apxr

Summary

codex itself supports workspace-write sandboxing with network access enabledsandbox_mode = "workspace-write" plus [sandbox_workspace_write] network_access = true. None of codex-acp's three agent modes exposes that combination, and no configuration path can reach it.

The result is that a host application driving codex-acp has only two usable options:

mode sandbox network
read-only readOnly
agent (default) workspaceWrite
agent-full-access dangerFullAccess, approval never

So enabling network for an agent means giving up the workspace boundary and approvals at the same time. There is no way to say "keep the workspace sandbox, allow network".

Why this matters

Our use case is an automated code-review agent. It runs in a checkout, and its job legitimately ends in network calls — git ls-remote / git fetch against the forge, then posting the review back. Under the default agent mode every one of those fails, and the run ends with nothing to do. The only mode that lets it work is agent-full-access, which also removes the workspace boundary and silences approvals — considerably more privilege than the task needs, for an agent whose whole design premise is that its worst case should be a wrong opinion.

Running the same prompt through the codex CLI directly works exactly as wanted:

codex exec --strict-config -s workspace-write -c sandbox_workspace_write.network_access=true "…"
→ sandbox: workspace-write [workdir, /tmp, $TMPDIR] (network access enabled)
→ git ls-remote … succeeded

--strict-config accepts the key, so it is a recognised setting — it just cannot be reached through ACP.

Cause

Two things combine.

1. The modes are hardcoded. AgentMode defines exactly three statics, and Agent — which is DEFAULT_AGENT_MODE — fixes networkAccess: false:

static Agent = new _AgentMode(
  "agent", "Agent", "Read and edit files, and run commands.",
  "on-request",
  { type: "workspaceWrite", writableRoots: [], networkAccess: false,
    excludeTmpdirEnvVar: false, excludeSlashTmp: false },
  "workspace-write"
);

Nothing constructs an AgentMode anywhere else, and AgentMode.find() resolves only against those three — including for INITIAL_AGENT_MODE, where an unrecognised value falls back to agent silently.

2. Config cannot widen it, because the policy is re-asserted every turn. CODEX_CONFIG does reach the session — CodexAcpClient keeps it as this.config, createSessionConfig() merges it, and it is sent as the config field of thread/start. But sendPrompt then passes the mode's policy into every turn/start:

return await this.codexClient.runTurn({
  threadId: request.sessionId,
  input,
  approvalPolicy: agentMode.approvalPolicy,
  sandboxPolicy: addAdditionalDirectoriesToSandboxPolicy(agentMode.sandboxPolicy, additionalDirectories),});

There is no conditional, and addAdditionalDirectoriesToSandboxPolicy only appends writable roots — it never touches networkAccess. So a sandbox_workspace_write.network_access = true supplied via config.toml or CODEX_CONFIG is transmitted at thread start and then overwritten on the first prompt turn.

This is observable from the host side: a session run this way records

sandbox_policy  = {"type":"workspace-write","network_access":false,…}
sandbox_mode    = null
approval_policy = "on-request"

— an explicit turn-level policy object rather than a config-level mode string.

There is a subtlety worth flagging for anyone debugging this: runReview and runGoalSet do not send a sandboxPolicy, so the thread-level config still governs those. That makes it possible to see config-supplied network settings appear to work on one path while silently having no effect on ordinary prompts.

Versions

Observed on 1.1.14. Verified still present in 1.3.0 (latest at time of writing) — the Agent static still carries networkAccess: false, and sendPrompt still passes sandboxPolicy: addAdditionalDirectoriesToSandboxPolicy(agentMode.sandboxPolicy, …) into runTurn. So upgrading does not address it.

Relationship to #310

Same chokepoint, different missing capability. #310 asks for granular approval policy from config.toml, and a commenter there additionally wants sandbox-off-with-approvals-on. This request is the other axis — keep the workspace sandbox and the approval behaviour exactly as agent has them, and only allow network. Neither is a superset of the other, but a fix that decouples the policy dimensions from the three presets would resolve both.

Possible directions

Roughly in increasing order of scope, and entirely your call which fits the project:

  1. Let CODEX_CONFIG / config.toml widen the selected mode rather than being overwritten — i.e. treat the mode as a default and the config as an override at turn construction. This is the smallest change and would close Sandbox and approval policies from config.toml are ignored #310 too.
  2. Add a fourth mode, e.g. agent-network: workspaceWrite + networkAccess: true, approval still on-request. Cheap and explicit, but adds a preset rather than removing the coupling.
  3. Make networkAccess selectable independently of the sandbox type — a config knob or an ACP session option — which is the general form of the problem both this and Sandbox and approval policies from config.toml are ignored #310 describe.

Happy to test a patch against our setup if that would help; we drive codex-acp over ACP stdio from a host application and can report what a real run records.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions