Before you start
You’ll need:
- A Mac or Linux computer with Git installed and Docker running
- A Claude account with Claude Code access
Why use a sandbox?
Coding agents run commands, install packages, and change files. A mistake can affect more than the project you’re working on. An attacker can also hide instructions in content the agent reads, tricking it into running harmful commands. This is called prompt injection.
A sandbox limits what the agent can access and how much damage it can do if something goes wrong. You can give it room to work without giving it access to everything.
co:op runs Claude Code in a Docker container on your computer:
- File access is limited to the project and folders you share.
- Secret files appear empty or cannot be read.
- Networking is restricted to the provider and allowed services and websites.
- Your provider API key or sign-in token is not mounted into the container.
Claude Code can still edit the files it can see and send their contents to Anthropic. Its work counts toward your subscription limits.
Install co:op and sign in
curl -fsSL https://coop.dryga.com/install.sh | sh
If the installer asks you to update your PATH, run the command it prints. Then check the version:
coop version
coop 12.0.1
The installer runs a downloaded script. Check the installation reference for release verification.
Next, sign in:
coop login claude
Follow the Claude sign-in instructions shown in your terminal. co:op uses the models and usage limits included in your Claude subscription.
Already use Claude Code?
co:op keeps separate Claude history and settings for each project. Inside the container, Claude reads ~/.claude/settings.json. See where agent settings live before changing them.
Using a custom image?
Use co:op’s standard image for this walkthrough. It includes node, curl and Git, which the examples need. A custom image may not include them.
Create a test project
To try co:op, run these commands to create a test project. Use the same terminal window throughout the walkthrough:
coop_demo_dir=$(mktemp -d "$HOME/coop-sandbox-demo.XXXXXX") && cd "$coop_demo_dir" && git init && printf '%s\n' '# co:op sandbox demo' > README.md && git add README.md && git -c user.name='Sandbox demo' \ -c user.email='sandbox-demo@example.invalid' \ -c commit.gpgsign=false \ commit -m 'Create sandbox demo' && coop init
coop init sets filtered networking for this new project.
Create a file with a fake secret:
(umask 077; set -C; printf '%s\n' 'COOP_DEMO_VALUE=not-a-real-secret' > .env.coop-demo) && wc -c < .env.coop-demo
34
We’ll use this fake secret to check that co:op hides it from the agent.
Start Claude Code
Run this command to check your setup:
coop doctor
Checking the Coop box on the Docker runtime Protecting secrets ✓ .env is hidden ✓ .envrc is hidden … ✓ All 37 checks passed
Start Claude Code:
coop_review_base=$(git rev-parse HEAD) && coop claude --egress filtered
The first command saves the starting commit ID so you can review all changes later. On the first filtered launch, co:op also checks that Docker can enforce its network rules.
Can I use another container runtime?
This sign-in setup requires Docker with filtered networking. Host networking and Apple’s container runtime are not supported.
Why the agent runs without approval prompts
Claude Code has a built-in sandbox for its Bash tool. Here, co:op’s Docker container limits its file and network access.
co:op starts Claude with --dangerously-skip-permissions inside the container. Claude can work without asking permission for every command, within the file and network access you allow.
The agent can also read or change this project’s saved history and settings.
Verify how co:op hides secrets
Ask Claude to run:
wc -c README.md .env.coop-demo
macOS
21 README.md wc: .env.coop-demo: Operation not permitted 21 total
Linux
21 README.md 0 .env.coop-demo 21 total
The agent can read README.md, but co:op blocks access to the secret or shows it as an empty file.
Files matching .env.* are protected automatically. To hide other files or folders, add them to .coopignore.
To scan project files for credentials, open a second terminal in the demo folder and run:
coop check-secrets --include-ignored
✓ No possible secrets found Checked project files, including Git-ignored files the box can read.
Verify that Claude can’t read your login credentials
To keep Claude from reading or leaking your login credentials, co:op gives it placeholders and adds the real credentials outside the sandbox when forwarding requests to Anthropic. Ask Claude to run this script to check what it received:
node <<'JS' const fs = require('node:fs'); const path = require('node:path'); try { if (process.env.COOP_BOX !== '1') throw new Error(); const marker = 'coop-native-claude-v1'; const auth = JSON.parse(fs.readFileSync( path.join(require('node:os').homedir(), '.claude/.credentials.json'), 'utf8')); const oauth = auth.claudeAiOauth || {}; if (process.env.CLAUDE_CODE_OAUTH_TOKEN !== marker || oauth.accessToken !== marker || oauth.refreshToken || process.env.ANTHROPIC_API_KEY || process.env.ANTHROPIC_AUTH_TOKEN) { throw new Error(); } console.log('PASS: Claude uses public stand-ins, with no refresh token in this login file'); } catch { console.error('FAIL: the expected Claude credential setup was not verified'); process.exitCode = 1; } JS
PASS: Claude uses public stand-ins, with no refresh token in this login file
If the check fails, investigate without printing credentials or pasting them into a prompt. Commands such as env, printenv and cat can expose them.
See what the agent can connect to
Leave the agent running. In another terminal, open the demo project folder and run:
coop net
coop net check https://example.com
✗ example.com:443 is blocked — no approved rule allows it.
coop net check checks the rules without visiting the website. In this new project, example.com should be blocked. If it is allowed, check that you’re in the demo folder.
By default, restricted networking lets Claude reach Anthropic’s services to sign in and use your account. You can allow more websites later.
MCP servers connected through Claude.ai remain available to Claude Code. To add local MCP servers, follow the MCP setup guide.
Watch a website get blocked
Back in the agent session, ask it to visit example.com:
curl --noproxy '*' --fail --silent --show-error \ --connect-timeout 5 --max-time 15 \ --output /dev/null --write-out 'HTTP %{http_code}\n' \ https://example.com/
curl: (6) Could not resolve host: example.com HTTP 000
The request should fail, but an error alone does not tell you why. Quit Claude Code, then list its network sessions:
coop net runs
Recent network runs RUN WHEN ACTIVITY 317fc92d today 18:51 no external connections · 8 blocked
Find the session you just closed by its start time. Here, its run ID is 317fc92d. Replace that ID with yours in the command below to see why the request was blocked:
coop net blocked example.com --run 317fc92d
example.com was blocked Run 317fc92d · today at 18:51 No approved rule allowed this DNS lookup. It happened 4 times. The record has no connection type or port to use in a rule.
Allow just one website
In the demo’s .agent/project.yaml, add this rule under the existing box entry. Keep the other settings:
.agent/project.yaml · example.com rule
box:
egress: filtered
egress_rules:
- to: {domain: "example.com"}
protocol: tls
ports: [443]coop approve
NETWORK RULES (+ new) + example.com:443 · TLS ✓ Approved for new runs and running editor sessions
coop net check https://example.com
Approve only the new rule for example.com on TLS port 443. It allows this website, not its subdomains or other ports. The check should now say it is allowed.
coop claude --egress filtered
The new Claude Code session uses the updated rules. A session already running would keep the old ones. Ask the agent to try the request again:
curl --noproxy '*' --fail --silent --show-error \ --connect-timeout 5 --max-time 15 \ --output /dev/null --write-out 'HTTP %{http_code}\n' \ https://example.com/
HTTP 200
If it still fails, check the new run’s network receipt for the reason. Leave filtered networking on.
Now give the agent a small task:
Example prompt
Add one sentence to README.md explaining that this is a sandbox demo. Run git diff --check and show its exit status. Do not install dependencies or commit the change. Stop after showing the diff.
Check the diff and command output, then quit Claude Code so co:op can finish recording the session’s network activity.
Read the network receipt
List the sessions again to find the one where you allowed example.com:
coop net runs
Recent network runs RUN WHEN ACTIVITY baf22d50 today 18:52 1 connection 317fc92d today 18:51 no external connections · 8 blocked
Here, the session with allowed traffic is baf22d50. Replace it with your run ID below to inspect its traffic:
coop net inspect baf22d50
Network run baf22d501bca66d3a7622b59e8ef001c
Allowed 1 connection · 773 B sent · 5.4 KB received
example.com:443 · TLS
…
The first session showed example.com blocked. This one shows a connection to example.com:443.
For the full record, including whether the session and cleanup finished, use JSON:
coop net inspect baf22d50 --json
{
"receipt": {
"finality": "final",
"completeness": "complete",
"cleanup_outcome": "complete"
}
}
The values shown above mean the run ended, its network record is complete, and cleanup finished. Follow up on any warnings. UNKNOWN means co:op could not measure something. It does not mean zero.
To export the receipt:
coop net export baf22d50
What does the export include?
coop net inspect … --json puts these fields under receipt. In an export, they are at the top level.
Exports hide remote names and addresses by default. Add --include-addresses to include them, and review the file before sharing it. The digest is a checksum, not a signature. See what the network record measures.
Review changes and fix problems
Back in the original terminal where you started the agent, review what the agent changed:
git status --short && git log --oneline "$coop_review_base"..HEAD && git diff "$coop_review_base"
git diff --check "$coop_review_base" && printf 'Diff check passed\n'
Diff check passed
This compares the project with the commit saved before the agent started, including changes it staged or committed. Open any untracked files separately. Git does not include their contents in the diff.
Claude sign-in expired or the account is wrong
Exit Claude, run coop login claude and sign in with the right account. Then start a new session. Use co:op’s login command rather than Claude’s login or logout commands inside the container.
If you use API billing instead, co:op supports ANTHROPIC_API_KEY. Follow the API-key setup. ANTHROPIC_AUTH_TOKEN and CLAUDE_CODE_OAUTH_TOKEN are not supported.
A dependency or documentation request is blocked
Run coop net blocked <host> in your terminal, replacing <host> with the blocked hostname. Add the access you need to .agent/project.yaml, then run coop approve. Restart the agent to use the new rules.
The networking guide explains the rules. If Docker or a sandbox check fails, fix the reported problem before trying again with filtered networking.
Ready to use your own project? Follow the general sandbox walkthrough to protect its secrets, set up its tools and approve its network access. Each project needs its own approval. Review and test the agent’s changes before keeping them.
For longer jobs, the overnight walkthrough shows how to run a task queue. You can delete the test project at $coop_demo_dir when you’re finished. This does not sign you out.
Using another coding agent?
- Run Codex CLI in a sandbox
ChatGPT device sign-in, API accounts and Codex settings.
- Run Gemini CLI in a sandbox
AI Studio keys, Google routes and supported authentication.
- Run Grok CLI in a sandbox
Grok device sign-in, account access and network rules.