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 enabled — sandbox_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.

Activity

  1. cblage commented on Aug 28, 2026

    @cblage

    FWIW, I got mine to work with network access AND manual approvals with

    INITIAL_AGENT_MODE = 'agent'
    CODEX_CONFIG = '{ "approval_policy": "on-request", "approvals_reviewer": "user", "sandbox_mode": "workspace-write"}'
    
  2. auruhm commented on Sep 29, 2026

    @auruhm

    Confirming this from a different client/setup, with a measurement that may help land one of the open fixes.

    Environment: Zed (macOS, Apple Silicon) driving codex-acp 1.13.1 from agent_servers, Codex CLI 0.157.1. The session runs in the default mode (agent via DEFAULT_AGENT_MODE; INITIAL_AGENT_MODE is not set). This is a plain Agent prompt — no explicit mode change.

    Observed — a network command in the default agent mode fails at DNS resolution, not at the forge:

    $ curl -sS -m 8 -o /dev/null -w '%{http_code}\n' https://api.github.com
    curl: (6) Could not resolve host: api.github.com
    000
    

    The same command through Codex's own sandbox, with the combination this request asks for, works:

    $ codex sandbox -c sandbox_mode=workspace-write -- curl ... https://api.github.com
    curl: (6) Could not resolve host: api.github.com        # 000
    
    $ codex sandbox -c sandbox_mode=workspace-write -c sandbox_workspace_write.network_access=true -- curl ... https://api.github.com
    200
    

    So the only difference between "blind to the network" and "works" is exactly the network_access flag the per-turn policy discards — confirming both halves of the report on 1.13.1.

    I also traced the code path in 1.13.1: AgentMode.Agent (the DEFAULT_AGENT_MODE) hardcodes networkAccess: false, and sendPrompt passes sandboxPolicy: addAdditionalDirectoriesToSandboxPolicy(agentMode.sandboxPolicy, …) into every turn/start; addAdditionalDirectoriesToSandboxPolicy only appends writable roots and never touches networkAccess. A sandbox_workspace_write.network_access = true supplied via CODEX_CONFIG / config.toml reaches thread/start and is then overwritten on the first prompt turn — exactly as described.

    +1 for direction 1 (let CODEX_CONFIG / config.toml widen the selected mode rather than being overwritten): it is the smallest change and would close #310 as well. Both #561 and #368 already implement the network half of it — would love to see one of them merged.

    Current workaround: selecting agent-full-access for the session, which grants unrestricted filesystem access and turns approvals off — far more privilege than a task that only needs git ls-remote / git fetch.

  3. ma-pony commented on Oct 10, 2026

    @ma-pony

    Reproduced this on upstream v2.2.2 and opened #608 with a configuration-based fix.

    For workspace-write turns, it uses an explicit boolean from CODEX_CONFIG first, then Codex's effective config/read result for the working directory, then the existing mode default. This covers config.toml as well as the supplied session configuration, while leaving other sandbox types, writable roots and approvals unchanged.

    The new policy tests reproduce the problem before the change and pass afterward. A native Codex config/read probe also confirmed that the file-backed flag reaches the outgoing workspace-write policy; it made no model requests. Full local tests pass except for three filesystem-watcher failures that also reproduce on the unmodified upstream SHA in this macOS environment. The PR remains Draft pending the release-matrix/CI checks.

    Related to the existing approaches in #561 and #368; this proposal includes the effective file-configuration path rather than changing everyone's default mode.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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