Building in the Cloud with Codex, Safely

deeshee2 pts0 comments

Building in the cloud with Codex, safely | ivan.codes

For the last few months I've been building an environment where an agent can work on backend code without me watching it. I run Codex with approvals off and don't follow the output, which only works if everything around the run is doing the job supervision would otherwise do.

Prompting has been almost none of that work, since the mistakes that matter come from the agent filling in operational details nothing in the codebase told it, and those surface weeks later under load rather than in the diff.

These are the guardrails I've settled on: an AGENTS.md the model reads on every run, a sandbox policy for the shell it gets, codex exec for the run itself, a stack where the infrastructure isn't the agent's to guess at, a local environment with traces to check its own work against, and a preview environment for the pull request to land in before any of it reaches my AWS account.

What goes in AGENTS.md

Codex reads AGENTS.md on every run, merging from the outside in: ~/.codex/AGENTS.md, then the file at the git root, then any file in directories between the root and the working directory, with the closest file taking precedence on conflicts.

Conventions with a non-obvious answer are worth writing down, along with the commands that let the agent establish whether it's finished. Most of the rest is style guidance the model would infer anyway from the surrounding code.

# Orders API

Encore.ts application. One directory per service.

- Infrastructure is declared in code. Do not add Terraform, Dockerfiles, or<br>docker-compose — `encore run` provisions everything locally.<br>- Migrations are numbered `N_description.up.sql` and append-only. Never edit<br>an existing migration.<br>- Queries use tagged templates: db.query`SELECT ... ${value}`. Never the<br>raw* variants, which take a plain string and will accept concatenation.<br>- Credentials come from secret("Name"), never process.env.

Before reporting done, run:<br>encore check<br>encore test

An agent with no verification command stops when the code looks finished, which for infrastructure code is usually some distance before it is.

That's the whole file, and nothing else goes in it. Everything I've seen of skills and similar packaging suggests they bloat the context more than they help, which matches the way the trend has been going.

Isolation: sandbox, container, or VM

An agent running with approvals off will eventually run a command you would not have approved. The common answers are a throwaway VM, a container, or a remote environment, and any of them are fine. Codex also ships its own sandbox, which is the lowest-friction option because there is nothing to set up. If you already run agents somewhere disposable, this section is optional and you can skip to the next one.

Codex executes model-generated commands under bubblewrap and seccomp on Linux, and Seatbelt on macOS, in one of three modes. read-only permits no writes, workspace-write permits writes inside the working directory while keeping .git read-only and blocking network access, and danger-full-access removes both restrictions. Approval policy is a separate setting. The codex sandbox subcommand applies a policy to any command without involving the model, which is how I check what a mode does:

$ codex sandbox -c sandbox_mode=workspace-write -- bash -c 'echo hi > ~/escape.txt'<br>bash: line 1: /home/andout/escape.txt: Read-only file system

$ codex sandbox -c sandbox_mode=workspace-write \<br>-- bash -c 'curl -sm5 -o /dev/null https://example.com; echo exit=$?'<br>exit=6

Exit code 6 is curl's couldn't-resolve-host, so the lookup never left the sandbox.

Whichever route you take, isolation covers files and sockets and not the environment it inherits, so shell_environment_policy is worth setting alongside the mode. The config I run with:

sandbox_mode = "workspace-write"<br>approval_policy = "on-request"

[sandbox_workspace_write]<br>network_access = false

[shell_environment_policy]<br>inherit = "core"

inherit = "core" keeps PATH, HOME, USER, SHELL, TMPDIR and the locale variables, and drops the rest of what the shell was carrying.

Running tasks with codex exec

Once the file and the sandbox are in place there's nothing to sit and watch, so the run goes through codex exec rather than the TUI. It takes the task as an argument and the sandbox mode as a flag:

$ codex exec -s workspace-write \<br>"Add an order-created event. Publish it from the orders service when an<br>order is created, and add a subscription in notifications that sends a<br>confirmation email using the existing sendEmail helper."

Dependencies are already installed by this point and a local Encore environment doesn't call out, so network access stays off for these runs and the tasks that genuinely need it are rare.

If the result comes back close but wrong, codex exec resume --last continues that session with its context intact. The bare codex resume picker skips non-interactive sessions unless you pass...

codex sandbox environment agent code file

Related Articles