Documentation / Claude Code

Run Claude Code in a sandbox.

Run Claude Code on your project with secrets hidden and network access under your control. This walkthrough takes you from setup to a working sandbox, with checks to see how it protects your files and connections.

In this walkthrough

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?