OpenAI Codexcodex-cli 0.154 · macOS, Linux, WSL, Windows
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
26 small wins to finish your pathNext lesson

Permission profiles

Three built-in profiles decide how wide the boundary is. This lesson runs all three and watches the difference.

ProfileWhat the documentation says
:read-onlyKeeps local command execution read-only
:workspaceAllows writes inside the active workspace roots and the system temp directories
:danger-full-accessRemoves local sandbox restrictions, for when that breadth is intentional

Read only

bash
codex sandbox -P :read-only -- python3 -c "open('a.txt','w').write('x')"
Captured from a real run
PermissionError: [Errno 1] Operation not permitted: 'a.txt'

The same refusal as lesson 3, now asked for by name.

Workspace

bash
codex sandbox -P :workspace -- python3 -c "open('a.txt','w').write('x'); print('wrote a.txt')"
Captured from a real run
wrote a.txt

The write went through, because the file is inside the workspace. This is the profile most real work happens in: the agent can edit your project and run your tests without asking, and cannot touch the rest of the machine.

The part people miss

Workspace is described in terms of writes, so it is easy to assume the network is included. It is not.

bash
codex sandbox -P :workspace -- python3 -c "import urllib.request; print(urllib.request.urlopen('https://example.com').status)"
Captured from a real run
urllib.error.URLError: <urlopen error [Errno 8] nodename nor servname provided, or not known>

Not a refusal message, a DNS failure: from inside the sandbox the name does not resolve. A test suite that fetches something, or an install that reaches a registry, fails like this. Knowing the shape of that error saves an hour.

Full access

bash
codex sandbox -P :danger-full-access -- python3 -c "import urllib.request; print('status', urllib.request.urlopen('https://example.com').status)"
Captured from a real run
status 200
bash
codex sandbox -P :danger-full-access -- python3 -c "open('/tmp/outside.txt','w').write('ok'); print('wrote /tmp/outside.txt')"
Captured from a real run
wrote /tmp/outside.txt

Both limits gone in the same profile: the network answers and a file outside the project is written. The name is doing its job, and the two runs above are what it means in practice.

Choosing

SituationProfile
Reading an unfamiliar repository:read-only
Normal work in a repository you own:workspace
An install or a test suite that genuinely needs the networkWiden deliberately, for that run
Anything you cannot describeNot full access

You can also write your own profile under [permissions.<name>] in the config file and make it the default, which is lesson 13. An organisation can restrict which profiles are even selectable.

The habit to keep
Test the profile, do not assume it. Every claim on this page is a command you can run in ten seconds, and that habit is worth more than remembering the table.
Try it yourself
  • Run your project's test suite under :workspace and see whether it needs the network.
  • Find the one command in your workflow that genuinely needs to leave the sandbox. Lesson 7 is about that.

This is what real progress feels like.