Network is off by default — and how to widen the fence on purpose
The refactor’s done. The next ticket is a small one: budgetcli got a transaction in euros, and to record it in your reports the service needs to convert it to your home currency at the rate on the transaction date. You ask Codex to fetch that rate from the exchange-rate API the service already has a client for. You’re in on-request × workspace-write — the comfortable daily cell from the last two lessons — so you expect it to just work.
It doesn’t. And the way it fails is the single most important thing to understand about the workspace-write sandbox.
The wall you didn’t know was there
Section titled “The wall you didn’t know was there”> fetch today's EUR→USD rate from the exchange-rate API and cache it
⎿ Read src/budgetcli/fx.py
⏵ Running: python -c "import httpx; httpx.get('https://api.exchangerate.host/latest')" ✗ Network is disabled in this sandbox. The workspace-write sandbox blocks outbound network access by default.Read that carefully, because the instinct is to think the agent did something wrong. It didn’t. In workspace-write, outbound network access is off by default. The sandbox lets the agent write files inside your project — but reaching the internet is a separate permission, and it starts closed. “Can write the project” and “can phone the internet” are two different capabilities, and workspace-write grants only the first.
This is a deliberate, valuable default, and it’s worth sitting with why before you reach to switch it off. Most of the real damage an agent could do with your financial data needs the network: exfiltrating a secret, posting your transactions to some endpoint, pulling and running code from a URL. A sandbox that can write your project but can’t open a socket has had its most dangerous capability removed by default. The agent hitting this wall isn’t a bug you route around — it’s the protection working, asking you to make an explicit decision before data starts leaving your machine.
Opening network on purpose
Section titled “Opening network on purpose”When the network is what the task legitimately needs — as it is here, the rate API is a real dependency — you open it deliberately, in config, scoped to the workspace-write sandbox:
# ~/.codex/config.toml or .codex/config.toml[sandbox_workspace_write]network_access = trueNow, and only now, the agent’s call to the exchange-rate API goes through. The rest of the workspace-write fence is untouched — still can’t write outside the project, still the same approval checkpoint — you’ve widened exactly one capability, the one this task actually requires, and left the rest of the wall standing. That’s the discipline the two-axis model keeps pushing you toward: open the specific thing, not the whole machine. Reaching for danger-full-access to “just let it use the internet” would also hand it your entire filesystem; turning on network_access gives it the internet and nothing else.
Widening which directories it can write
Section titled “Widening which directories it can write”The same scoped-widening logic applies to the filesystem. You keep your downloaded bank statements in ~/budget-data/, outside the repo — sensible, since you don’t want raw financial exports in git. But the importer needs to read and write there, and workspace-write fences the agent to the project. Two ways to extend that fence, both surgical:
A one-off, per launch — --add-dir adds a writable root for this session only:
codex -s workspace-write --add-dir ~/budget-dataOr persistently, in the same [sandbox_workspace_write] block, with writable_roots:
[sandbox_workspace_write]network_access = truewritable_roots = ["~/budget-data"]Either way the agent can now write ~/budget-data and the project — and still nothing else. Note what you did not do: you didn’t switch to danger-full-access to get the data directory. The official guidance is explicit that --add-dir is the preferred move precisely because it grants the one directory you need instead of the whole disk. Keep the wall; cut one door in it.
The shape of the lesson
Section titled “The shape of the lesson”Both halves of this lesson are the same move. workspace-write ships with a tight, sensible fence: the project directory, no internet. When a task genuinely needs more reach, you don’t tear the fence down — you widen it by the exact amount required and no more. network_access opens the network; writable_roots and --add-dir open specific directories. The keys, their defaults, and a couple of related toggles (exclude_slash_tmp, exclude_tmpdir_env_var) are documented in the config reference and the sandbox docs.
You’ve now set both dials by hand and widened the fence twice. But you’ve also typed the same flags over and over, and tweaked config.toml for one task that the next task shouldn’t inherit. There’s a cleaner way to carry a whole trust posture around as one named thing — bundle the axes into a profile.