block / block/buzz

Codex agents cannot reach the relay: the injected CODEX_CONFIG network override is discarded by codex-acp's agent mode

Open
#6,983 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
32.7k
Forks
4.3k
Avg merge
1d 13h
Merged PRs (30d)
253

Description

### Summary

On macOS, Codex-backed agents cannot post anything to a channel. They receive the event, run their turn, and fail at
the last step: every `buzz messages send` from inside the agent's tool sandbox is refused at the OS level. Claude
Code-backed agents in the same channel are unaffected.

Buzz already ships a fix for this. `codex_network_env` injects

```
CODEX_CONFIG={"sandbox_workspace_write":{"network_access":true}}
```

for Codex agents, documented as opening the macOS Seatbelt sandbox so `buzz-cli` can reach the relay. The variable is
built correctly and reaches the process. **It just never affects the session's sandbox policy**, because
`@agentclientprotocol/codex-acp` derives that policy from a predefined agent mode instead, and the default mode
hardcodes `networkAccess: false`.

### Environment

- Buzz 0.5.20 (macOS, distributed `.app`), macOS 26.5.2 (arm64)
- `@agentclientprotocol/codex-acp` 1.7.0 (bundled under `Application Support/Buzz/node-tools`)
- Self-hosted relay reached over a private WireGuard-style overlay hostname

### Symptom

From the agent's session log, first with the configured relay URL:

```
buzz messages send --channel --reply-to --content '...'
→ {"error":"network_error","message":"network error: error sending request for url
(https:///query): client error (Connect): dns error: failed to lookup
address information: nodename nor servname provided, or not known"}
```

then, after the agent tried `localhost` on its own — no name resolution needed, and it still fails:

```
buzz --relay http://localhost:3000 messages send ...
→ {"error":"network_error","message":"network error: error sending request for url
(http://localhost:3000/query): client error (Connect):
tcp connect error: Operation not permitted (os error 1)"}
```

`Operation not permitted` on a loopback connect is the Seatbelt sandbox refusing the socket, not a relay or DNS
problem. Running the same bundled CLI from a normal shell on the same machine resolves the host and proceeds to
authentication, which isolates the difference to the sandbox the agent's tools run in.

### Root cause

`CODEX_CONFIG` does reach the process. Read from the live `codex-acp` and `codex app-server` processes:

```
CODEX_CONFIG={"sandbox_workspace_write":{"network_access":true}}
```

`codex-acp` reads it (`dist/index.js`, `startCodexServer`: `const configString = process.env["CODEX_CONFIG"]`) and
passes it to the client as config overrides. But the **session sandbox policy does not come from that config** — it
comes from an `AgentMode` constant:

| mode id | sandbox policy | approvals |
|---|---|---|
| `read-only` | `workspaceWrite`, `networkAccess: false` | on-request |
| `agent` (default) | `workspaceWrite`, **`networkAccess: false`** | on-request |
| `agent-full-access` | `dangerFullAccess` | never |

The mode is selected by `INITIAL_AGENT_MODE`, falling back to `DEFAULT_AGENT_MODE = AgentMode.Agent`:

```js
static getInitialAgentMode() {
const predefinedAgentMode = process.env["INITIAL_AGENT_MODE"];
if (predefinedAgentMode) {
return _AgentMode.find(predefinedAgentMode) ?? _AgentMode.DEFAULT_AGENT_MODE;
} else {
return _AgentMode.DEFAULT_AGENT_MODE;
}
}
```

Buzz does not set `INITIAL_AGENT_MODE`, and `buzz-acp` does not send `session/set_mode`. So the effective policy is
`AgentMode.Agent`'s, which the session log confirms exactly:

```json
{"approval_policy": "on-request",
"approvals_reviewer": "auto_review",
"sandbox_policy": {"type": "workspace-write", "network_access": false},
"permission_profile": {"type": "managed", ...}}
```

Note `approval_policy: on-request` — but there is no human at a terminal to approve, so an approval prompt in this
context is equivalent to a hard failure even setting the network issue aside.

Relevant Buzz code: `crates/buzz-acp/src/config.rs` (`codex_network_env`) and `crates/buzz-acp/src/acp.rs` (the
`CODEX_CONFIG` merge in `AcpClient::spawn`). Both are correct in themselves; the assumption that breaks is the doc
comment's claim that the adapter forwards this "as a session-level config override" that reaches the Seatbelt
policy.

### Verification of the diagnosis

Setting `INITIAL_AGENT_MODE=agent-full-access` on the agent (via **Edit Agent → Advanced → Environment
variables**, which is not a reserved key) and restarting it changes the session policy and fixes the symptom
immediately:

```json
{"approval_policy": "never",
"sandbox_policy": {"type": "danger-full-access"},
"permission_profile": {"type": "disabled"}}
```

```
buzz messages send ... → {"accepted": true, "event_id": "", "message": ""}
```

No `Operation not permitted` and no DNS error in the new session. Buzz was not modified.

### Why this is worth fixing rather than documenting

`agent-full-access` is a poor workaround. It is the only mode that enables the network, and it simultaneously drops
the filesystem restriction and disables approvals entirely. There is no mode that grants network access while
keeping `workspaceWrite`, so users who need Codex agents to function must give them substantially more privilege
than the feature requires.

A secondary problem: an invalid `INITIAL_AGENT_MODE` value silently falls back to the default
(`find(modeId) ?? DEFAULT_AGENT_MODE`) with no warning, so a typo is indistinguishable from the bug being unfixed.

### Suggested fixes

1. **Set `INITIAL_AGENT_MODE` when spawning Codex agents**, next to the existing `CODEX_CONFIG` injection. This is
the smallest change entirely within Buzz, but it inherits the over-privilege problem above.
2. **Have `codex-acp` merge `CODEX_CONFIG`'s `sandbox_workspace_write.network_access` into the selected mode's
sandbox policy** rather than letting the mode override it. This is the fix that matches what the Buzz code
comment already assumes, and it keeps the workspace-write file restriction. Requires an upstream change.
3. **Log the effective sandbox policy at agent startup.** Right now a Codex agent that cannot reach the network
looks identical to one that is merely slow — it emits reactions and then ends its turn with nothing. Surfacing
`network_access` at startup would have made this a one-minute diagnosis.

If option 1 ships alone, please also document that Codex agents run without approval gating, since that is a
meaningful change in posture compared to what the mode name suggests.

Contributor guide

Open the contributing guide

Research direction

Start with crates/buzz-acp/src/config.rs and crates/buzz-acp/src/acp.rs, then inspect codex-acp's dist/index.js handling of CODEX_CONFIG and INITIAL_AGENT_MODE. Reproduce the session policy with a Codex agent and compare it with the environment override. Done means the selected fix enables relay access without unintended privilege expansion, with the effective policy or fallback behavior made clear.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, rust
Domain
devtools, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.