On this page

Documentation

Run coding agents in a container on your computer. Choose what they can read and reach, then review the work they produce.

The idea

An agent needs to edit files and run commands to finish a coding task. On your computer, those same permissions can let it read private keys, upload code or delete the wrong folder. co:op limits the files and network destinations it can reach.

co:op runs the agent in a box: a disposable container with your project mounted inside. Your home folder, SSH keys, cloud credentials and other projects are not mounted into the box. Known secret files in the project, such as .env files and private keys, appear empty to the agent. The agent can edit the visible project files and run commands in the container.

Interactive sessions, forks, loops and preset roles use the same container protections.

One exception: an editor connected over ACP can act on your computer for the agent, with the editor's own permissions. See Editors.

Install

co:op runs on macOS and Linux, on amd64 or arm64 machines. You need Git and a container runtime. The installer downloads a single executable; you do not need Go or a copy of the source:

  • curl -fsSL https://coop.dryga.com/install.sh | sh

The script puts coop in ~/.local/bin. If it finds a container runtime, it also builds the sandbox image and runs coop doctor to check it. If you install the runtime later, run those two steps yourself:

  • coop build --egress open && coop doctor

Use Docker to run an online provider, including with open networking. It supports the helper that keeps provider credentials outside the box. Apple container on macOS 26+ can run commands with open networking and no credentials. If both are installed, co:op chooses Docker.

The command downloads and runs a script from coop.dryga.com, served by GitHub Pages from this repository’s main branch. The script verifies the release checksum with a local SHA-256 tool and stops if verification fails.

If cosign is on your PATH, the script also verifies that the checksum came from the exact release workflow and tag. To check the download before running the installer, use the manual steps.

You can also build co:op from source:

  • git clone https://github.com/AndrewDryga/coop && cd coop && make install

Quickstart

For your first run, follow the Claude Code and Codex sandbox walkthrough. Check file and network access, then run a small task and review its changes.

Sign in once, then run the setup and launch commands from your project directory:

  • coop login claude# sign in, once per account
  • coop init# set up the project
  • coop claude# start the agent in the box

For a new project, coop init creates settings and a task queue with filtered networking. It preserves existing project settings. coop claude starts Claude Code in the box.

Arguments after the agent’s name go to the agent, so coop claude --continue resumes your last session. co:op handles a few options itself, including --peer and --egress. Put an option after -- to send it to the agent instead.

For a bigger or riskier change, you don't have to work in your checkout at all. Write the work down as a task, and let a fork do it in its own copy while you keep working:

  • coop tasks add "Add JSON output"# queue the work
  • coop fork feature claude --loop# a fork works on it
  • coop fork review feature# review it like a PR
  • coop fork merge feature# then merge it

Before you start the fork, fill in the generated task.md with the problem, what done means, the approach and the subtasks. More in Forks and The loop.

Run an agent

coop claude is one way into the box. The other agents start the same way, and so do a plain shell and a single command when you want to work in the box yourself:

  • coop claude# Claude Code
  • coop codex# Codex, in the same box
  • coop gemini# Gemini
  • coop grok# Grok
  • coop shell# a shell in the box
  • coop run -- npm test# one command in the box

Every agent starts with its permission prompts turned off, so it works through a task without stopping to ask at each step.

Why permission prompts are off

The container limits which files and network destinations the agent can access. Within those limits, it can work without asking you to approve each command. Review the files it changes before running them on your computer.

Before the agent starts, co:op shows you what it set up: which secrets it hid, which account it signed in with and what the box can reach on the network.

~/code/shop $ coop claudeProtecting secrets  ✓ 2 secret paths hidden from the boxConnecting account  ✓ Claude (default) · Signed inConfiguring network access  ✓ Anthropic endpoints allowed  ✓ Everything else blockedStarting Claude Code

The sandbox

The box is a disposable container with your repo mounted inside. Its mounts determine which host files the agent can access.

co:op mounts your repo at the same path it has on your computer. The agent edits your real files, so changes appear in your editor as it works. The standard setup also mounts that repository’s agent settings and history, plus a shared dependency cache. It does not mount your other projects.

Each repository keeps its own agent settings and conversations. The box cannot read other projects’ conversations. A helper outside the box authenticates provider requests, keeping reusable credentials away from the agent. The agent can change its local settings and history; review changes you do not trust before using them again.

Your Git identity, not the box's

The agent commits as you. co:op gives the box a trimmed Git config with your name and email, your global gitignore and commit.gpgsign=false, but never your signing key, so the box's commits are authored by you and left unsigned.

If your global Git config has commit.gpgsign=true, co:op signs agent commits on your computer, where your key stays. It does this when an interactive run exits, after each coop loop cycle, and during coop fork merge.

Editor sessions do not sign commits automatically. Run coop sign to sign the current branch’s unpushed commits. This lets agent work meet a protected main branch’s signature requirement.

Hiding secrets

Your repo is in the box, and repos hold secrets of their own: .env files, private keys, live API tokens. co:op hides those by name before the agent starts, and coop check-secrets finds the ones hiding inside ordinary files.

co:op covers known secret files with empty read-only files, and secret directories with empty read-only directories. These include .env, *.pem, *.tfvars, secrets/, .ssh and other common names. The agent can see the names but cannot read or change their contents.

Templates ending in *.example, *.sample or *.template stay visible so the agent can understand your configuration.

The built-in list can't know where your repo keeps its own secrets, like live keys in config/stripe.live.json. List those in a .coopignore file at the repo root, one pattern per line, and they're hidden the same way. Comments go on their own lines:

.coopignore

# a file name, hidden at any depth
prod.yml
# a path from the repo root
config/stripe.live.json
# a folder, hidden whole
vault/

Use .coopignore to hide project files from the agent. .gitignore controls Git, not the box. An ignored file such as serviceAccount.json is still readable if no hiding rule covers it. Add private files to .coopignore.

A token inside an ordinary source file remains readable. coop check-secrets scans files you would commit for known provider tokens and long random values assigned to secret-like names. It reports each match as file:line so you can inspect and remove it.

~/code/shop $ coop check-secrets✗ 1 possible secret found  config/client.go:12    OpenAI API keyRemove real secrets from files you intend to commit.If this is a false positive, add this entry to .coopsecretsignoreand replace <reason> with an explanation:  # config/client.go — OpenAI API key  fp-v1:b2758b3a796f81888b6f896f9c420ee855608fdcb828dfc2b83f736768171a6c # <reason>

Add --include-ignored to check files Git ignores too. The command fails if it finds a possible secret or cannot finish scanning, so you can use it before a run or in CI. If you have confirmed a finding is a false positive, record the exception in .coopsecretsignore.

Networking

Filtered networking allows the box to reach its AI provider and the destinations you approve. Other connections are blocked. Visible files and prompts can still be sent to an allowed destination.

coop init turns filtering on for a new project, with egress: filtered in .agent/project.yaml. The box can then reach its provider's own endpoints, like api.anthropic.com for Claude, and nothing more until you approve it. The block works on the network itself, not through a proxy setting, so curl, an SDK and any subprocess are blocked the same way.

When the agent needs more, such as a documentation site, add a rule to the same file:

.agent/project.yaml

box:
  egress: filtered
  egress_rules:
    - to: {domain: "docs.example.com"}
      protocol: tls
      ports: [443]

A rule takes effect only after you approve it with coop approve in your terminal, so an agent can't widen its own access by editing the file. The coop net commands show what the box can reach, and what it tried:

  • coop approve# approve the project's rules
  • coop net# what a new run here can reach
  • coop net inspect# a run's connections and blocks
  • coop net blocked <host># how to allow a blocked host

Besides filtered, a project can be open (everything) or offline (no network), and open needs your approval too. Filtering also protects API keys: if you sign in with one, the real key stays outside the box and the agent gets a stand-in that works only for that run.

Before the first filtered run, co:op checks that Docker can enforce the rules. It repeats those checks when the saved results are no longer valid. Run coop net setup to check ahead of time. The networking guide explains the available rules and each provider’s access.

Prove it

coop doctor tests these protections. It starts a box, tries to break out of it, and shows the result of each check.

The checks use a temporary project and test secrets, not your files or credentials. They test secret hiding, host access, privileges, offline networking, task and credential access, and what a fork contains:

~/code/shop $ coop doctorChecking the Coop box on the Docker runtimeProtecting secrets  ✓ .env is hidden  ✓ .envrc is hidden  ✓ Terraform variable files are hidden  ✓ Private keys are hidden  ✓ Custom .coopignore paths are hidden  ✓ Secret directories are empty  ✓ Links cannot reveal hidden secrets  ✓ Hidden secret files cannot be written  ✓ Environment templates stay readable  ✓ Source files stay readable  ✓ The test secret cannot be readHost access and privileges  ✓ The host Coop CLI is absent  ✓ The host Docker socket is absent  ✓ The box runs as a non-root user  ✓ Linux capabilities are removed  ✓ The process limit is enforced (4096)Offline access  ✓ Offline mode leaves only the loopback interfaceTask access  ✓ The task channel exposes only its 8 task tools  ✓ Calls outside the task tools are refused  ✓ Changes to a task held by another process are refused  ✓ The assigned task can be updatedCredentials and settings  ✓ Claude's native home is available  ✓ Host account grants stay outside Claude's home  ✓ Codex's native home is hidden from Claude  ✓ Gemini's native home is hidden from Claude  ✓ Grok's native home is hidden from Claude  ✓ Claude's saved login takes priority over its environment key  ✓ Codex's environment key is hidden from Claude  ✓ Gemini's environment key is hidden from Claude  ✓ The box can write its settings directoryFork handoff  ✓ .env is absent from the clone  ✓ .envrc is absent from the clone  ✓ Secret directories are absent from the clone  ✓ Private keys are absent from the clone  ✓ Tracked source files are present in the clone  ✓ The test secret is absent from the clone  ✓ The clone's origin is a local path✓ All 37 checks passed

Run it after you install, after you update co:op and whenever you change your config. If a check fails, it tells you what to fix.

Toolchain and services

Build the language tools your project needs into its image, and configure databases as services. Later runs can reuse them instead of installing everything again.

If your repo has an asdf .tool-versions file, coop init writes an .agent/Dockerfile to install those versions in the image. You can request this setup explicitly with coop init --stack asdf; it also requires that version file.

Databases and caches run next to the box as project services, each in its own disposable container that the box reaches by name. They're opt-in: coop init asks, or you pass --services postgres,redis. From then on:

  • coop up# start and wait until healthy
  • coop claude# reach them by Compose name
  • coop down# stop them, keep their data
  • coop down --delete-volumes# also delete their data

Services use the same secret-hiding rules as the box, and their published ports listen only on your computer. In filtered mode, the box can reach a service only after you approve a to: {service: "db"} rule.

In filtered mode, those services run on a private network with no direct internet access. Their HTTPS requests pass through the filter. If you change a service’s definition, review and approve it again.

coop up prints the service names from Compose when they are ready. If it cannot read the service list, it starts nothing and reports the problem.

Agents can change data in services they can reach, so use disposable development databases. Deleting their volumes cannot be undone; co:op asks you to confirm first.

coop update updates co:op and rebuilds the box with fresh system packages. To rebuild only the box, use coop update --box-only. Use coop build for a rebuild from the pinned base, or coop build --egress filtered for a filtered project. These commands keep the agent versions fixed to those checked for your co:op release.

Credentials and failover

Each agent runs on an account, and a long run can hit its usage limit. If you sign in to more than one account, co:op switches to the next one instead of stopping.

Each account you sign in to becomes a named credential:

  • coop login claude@work# sign in to a work account
  • coop login claude@personal# and a personal one
  • coop credentials# list accounts and sign-ins

When a loop hits a limit on one account, it moves to another and keeps going, and waits only when every account is at its limit. Limits are tracked per model and account, so claude:opus@personal stays usable while claude:opus@work waits for its reset. Switching loses no work, because the loop keeps its progress in the task queue and the repo.

A loop uses all your signed-in accounts without any setup: a bare provider:model step in its target ladder covers every account, the default first. A pinned provider:model@account runs on just that one, and coop credentials <agent> <name> default chooses the account a plain coop <agent> uses.

API keys

To use an API key, put ANTHROPIC_API_KEY for Claude, OPENAI_API_KEY for Codex or GEMINI_API_KEY for Gemini in ~/.config/coop/agents/env. On Docker, these work with open or filtered networking. A helper keeps the real key outside the box. Subscription credentials stay outside too.

Other Claude and Codex token variables, Vertex’s GOOGLE_API_KEY and Grok’s XAI_API_KEY are refused. See the credential reference for supported sign-in methods.

A key in this file becomes the provider’s default credential. A bare KEY line reads the value from your shell and is skipped if unset. Later entries replace earlier ones.

When you run a named account you signed in to, co:op leaves the environment key out of that run. This prevents the key from overriding the chosen account, even if you made that account the default.

Check limits and usage

coop usage shows account limits, reset times and an estimate of what the last 30 days of tokens would cost at API prices. Use coop usage codex@work for one account without changing your default.

The estimate includes subscription use. It flags incomplete history, missing prices and editor history it cannot assign to an account. It excludes web and phone use, other machines and charges unrelated to tokens. Checking quota uses the selected account on the host and sends no model prompt.

Pick the model

You choose the model separately from the account: for one run in the target, like claude:opus, or for good in a preset.

  • coop claude:opus# one run on the big model
  • coop claude:opus/xhigh# at extra-high reasoning effort
  • coop claude:opus@work# on a specific account
  • coop frontier# a preset's lead and roles
  • coop models# the models each agent offers

The model in the target overrides every default; see the full order. co:op passes the name to the provider’s CLI without validating it. A model works if that installed CLI supports it. An invalid name produces the provider’s error.

Add reasoning effort after a slash in the target, as in claude:opus/xhigh or codex/high. The values are low, medium, high, xhigh and max; the provider decides which it supports.

co:op passes the value to Claude’s --effort, Codex’s model_reasoning_effort or Grok’s --reasoning-effort without validating it. For supported Gemini models, it maps low and high to the model’s thinking setting. A thinking setting in your own Gemini config takes precedence.

You can use model/effort, such as opus/high, in targets, preset fallback lists, .agent/loop.yaml and COOP_<AGENT>_MODEL.

Second opinions

Different models have different blind spots. For a hard call, the lead agent can ask another model for a second opinion, while it stays the only one changing your code.

  • coop claude --peer codex --peer gemini# two models to ask
  • coop acp claude --peer codex# from an editor

Add --peer <agent> to an interactive run, loop, fork loop or ACP session. You can choose a peer’s model and effort, but not its account. co:op enables only the selected peers and keeps their reusable credentials outside the box. coop-consult asks them for read-only advice. The lead decides what to do, edits files, runs checks and commits.

Why it stays simple

The lead chooses when to ask a peer. Peers cannot edit the repository or ask other peers, so the lead remains responsible for the result.

Presets

A preset keeps a whole team in one file: the lead, its fallback models and the roles it hands work to. Use one when a lead works with the same helpers every time.

In the orchestrator pattern, a lead model plans the work and reviews the results while helpers handle specific roles. Each role is billed at its own model’s price.

coop init installs workflow skills but does not create starter subagents. Define roles in .agent/presets/<name>/preset.yaml. Then use the preset name wherever you would choose an agent: coop <name>, coop loop <name>, coop acp <name> or a fork.

  • coop presets init# write the starter "frontier" preset
  • coop presets# list presets, with any errors
  • coop loop frontier# run the loop with it

The lead’s agent: setting accepts one target or an ordered list of fallbacks. The loop tries them in that order. A target such as provider:model uses all signed-in accounts; provider:model@account selects just one. Each role has a mode that determines how the lead calls it:

Mode What it is
native A subagent in the lead's session. co:op creates coop-<role> from the role's model and prompt, using the client's own format. Set subagent: to use one you already have. Every lead in the preset must use the role's provider. Otherwise co:op stops before launch and tells you which role to change.
consult A read-only peer, asked with coop-consult <role>. It runs the role's target or ladder, with the role's prompt as its persona, and can't edit files.
delegate A worker that can write, run with coop-delegate. It may edit the working tree but never commits; the lead reviews the diff, runs the checks and commits. It falls back to the next model only while the tree is unchanged.

Here is a preset with one role in each mode:

preset.yaml

lead:
  agent: [claude:claude-opus-5-5, claude:claude-fable-5-1@work]
roles:
  thinker:                         # thinks in the lead's session
    mode: native
    agent: claude:claude-fable-5-1 # a coop-thinker subagent
    prompt: roles/thinker.md
  critic:                          # read-only cross-vendor review
    mode: consult
    agent: [codex:gpt-6-astra, grok:grok-4.5]
  fast:                            # cheap work that edits files
    mode: delegate
    agent: [gemini:gemini-3.8-flash, codex:gpt-6-luna]
What co:op generates from it

co:op tells the lead which roles are available, when to use them and how to call them. It provides the coop-consult and coop-delegate helpers and creates each native coop-<role> subagent inside the box. These generated files do not change your repo.

coop presets init creates editable starter prompts under roles/. A target on the command line, such as claude:opus@work, overrides the preset’s lead.

Consult and delegate fallbacks skip providers you have not signed in to. co:op prepares access to each usable target while keeping reusable provider credentials outside the box. A consult replays its saved conversation when it switches targets. A delegate can switch only if the failed attempt left all files and Git history unchanged.

Forks

A fork gives the agent its own copy of your repo. You review its work like a pull request and decide what to merge.

A fork is a disposable local clone of your repo. Its origin points to the local project, not a hosted repository. The clone starts from committed source, so uncommitted, Git-ignored secrets do not come along. Secrets already in Git history can remain.

When to reach for a fork

Use a fork to work on a larger change or try several approaches while keeping your original checkout available. Review the result before merging it. Ordinary forks still share some Git storage and trust the agent with Git metadata; the isolated mode described in the fork reference provides stronger separation.

Work in the fork, review it, then merge. coop fork review shows the commits and changed files. During merge, co:op rebases the work onto your current branch for a linear history. This happens on your computer, where co:op can sign the commits with your key.

~/code/shop $ coop fork api codex --loop -dCreating fork: api  /Users/you/code/shop-forks/api✓ Started fork api in the background  Agent: codex  Logs:  coop fork logs api --follow  Stop:  coop fork stop api~/code/shop $ coop fork lsForks  api · ready to merge · updated 4 minutes ago    Agent: codex    Branch: api    Tasks: 1 ready to merge    Changes: +88 −6Review a fork: coop fork review <name>~/code/shop $ coop fork review api --statChanges in fork api  Into: main  2 commits · 3 files · +88 −6Commits  9c41e2a webhook: verify Stripe signatures  3a7f0db webhook: dedupe replayed events by idFiles  code:    M  src/webhook/handler.ts  +40 -6    A  src/webhook/verify.ts  +24 -0  tests:    A  tests/webhook.test.ts  +24 -0Project checks will run when you merge.~/code/shop $ coop fork merge apiMerge fork api into main  2 commits · +88 −6Merge these commits? [Y/n] yRebasing onto mainRunning project checks  Running: npm test✓ Merged fork api into main

If you configure a project check, co:op runs it before merging changes into your branch. Set gate: in .agent/project.yaml, for example gate: make check. The line created by coop init is commented out until you enable it.

The check runs in the box on the rebased code. If it fails, nothing is merged and your branch stays unchanged. Use coop fork review --gate to run it before merging.

The merge also stops on anything risky coming in: secret-shaped content, files over 5 MB, and files that run on your computer, like Git hooks, .envrc, editor and agent settings, Compose files, Dockerfiles, CI config and new npm install scripts. Review them, then merge with --force; the checks still run.

With --loop, a fork works through tasks on its own: it takes them from your project's .agent/tasks/ queue one at a time, they stay in progress while you review the fork, and merging it completes them.

The loop

The overnight task queue walkthrough takes you through your first unattended run, including how to stop, resume and review the work.

Most agent work is a queue of small, well-defined tasks. coop loop works through the queue on its own, overnight and through usage limits.

The loop starts a fresh agent session for each task. The agent reads the task, does the work, runs your checks and commits the result. The loop moves on until no eligible task remains or it reaches --max-tasks.

--max-tasks pauses before final review and exits 0 on a successful pause. Run the same command without the limit to finish the review; a pause is not verified completion.

Each task is a folder under .agent/tasks/, and the folder it sits in is its state. Fill in each generated task.md before you start, so the agent knows what done means:

  • coop tasks add "Fix the flaky test"# a folder per task
  • coop loop claude# work the queue
  • coop loop claude --peer codex# with a peer to ask

In a monorepo, list the members under subprojects: in a committed .agent/project.yaml, and one loop works every member's queue.

~/code/shop $ coop loop frontier━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Task 1 - Attempt 1 Make POST /checkout idempotent Agent  claude:claude-opus-5-5/xhigh@work Queue  0 completed · 1 active · 2 pending · 0 blocked━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━Starting claude:claude-opus-5-5/xhigh@work✦ A retried checkout charges twice. I’ll key each order on its Idempotency-Key, so a replay returns the first charge.✎ Edit src/payments/checkout.ts⚙ Bash npm test✓ Task completed: Make POST /checkout idempotent━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Task 2 - Attempt 1 Cache the /health DB probe Agent  claude:claude-opus-5-5/xhigh@work Queue  1 completed · 1 active · 1 pending · 0 blocked━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━Starting claude:claude-opus-5-5/xhigh@work✦ The probe counts orders on every call. Caching it for five seconds takes that load off the database.✎ Edit src/health.ts✓ Task completed: Cache the /health DB probe━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Task 3 - Attempt 1 Rate-limit the public API Agent  claude:claude-opus-5-5/xhigh@work Queue  2 completed · 1 active · 0 pending · 0 blocked━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━Starting claude:claude-opus-5-5/xhigh@work✎ Edit src/middleware/rate-limit.ts⚙ Bash npm test✓ Task completed: Rate-limit the public API──────────────────────────────────────────────────────────────── Final review · Round 1 of 3 Agent  claude:claude-opus-5-5/xhigh@work Tasks  3 completed──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── Final review · 1 task needs more work  Rate-limit the public API Continuing the task queue────────────────────────────────────────────────────────────────━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Task 3 - Attempt 2 Rate-limit the public API Agent  claude:claude-opus-5-5/xhigh@work Queue  2 completed · 1 active · 0 pending · 0 blocked━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━Starting claude:claude-opus-5-5/xhigh@work✦ Internal callers were throttled too. The limit now applies only to public routes.✎ Edit src/middleware/rate-limit.ts✓ Task completed: Rate-limit the public API──────────────────────────────────────────────────────────────── Final review · Round 2 of 3 Agent  claude:claude-opus-5-5/xhigh@work Tasks  1 completed────────────────────────────────────────────────────────────────✓ All tasks passed final review · 3/3 done

While the loop works, coop tasks watch shows the live board, including any running forks. For a status line in your shell prompt or tmux, coop prompt prints the repo's state on one line (task counts, and fork or loop activity); it only reads, so it's safe on every redraw.

Final review

When the queue is empty, a final review compares the completed tasks with their requirements and Git history. It reopens unfinished work, and the loop works those tasks again.

By default, review gets three to five rounds, depending on how much the run completed. Tasks still needing work then wait for your decision. Add project-specific review requirements under signoff.prompt in .agent/loop.yaml, such as updating the changelog or regenerating docs. A task that fails one is reopened.

Usage limits

When the agent hits a usage limit, the loop reads the reset time from the agent's output and waits. If you've signed in to another account, it switches to that account and keeps going.

Decisions

When the agent needs your decision, it moves the task to 50_blocked/ and writes a decision.md with the question, options and recommendation. The loop continues with other tasks. When nothing else can run, it exits with status 3 to report that a decision is needed.

Run coop tasks decisions -i to answer the questions and unblock their tasks, then run coop loop again. Use --preflight to unblock tasks you have already answered. To postpone one, run coop tasks park <id> or press :b in the decision walkthrough. It keeps the question in the backlog; coop backlog promote returns it to the queue.

Good fits

Small refactors, moving one pattern across dozens of files, a test-coverage or lint list, or the Friday cleanup queue you'd never get to by hand: any work made of many small, checkable steps.

The .agent/ folder

Everything the loop works from lives in the .agent/ folder that coop init creates. It's the same for every agent, and the agent reads it on every start and after each compaction. The work queue (tasks/ and the backlog) is local working state that Git ignores; the knowledge and settings beside it are committed, so they travel with the project.

Path What it's for
tasks/ The work queue: a folder per task under 00_todo/, 10_in_progress/, 50_blocked/ and 99_done/. The folder a task sits in is its state; the numbers sort ls in order, and coop tasks shows the plain names. Local working state.
the backlog Work for later, as task folders in tasks/xx_backlog/ (coop backlog). Loops never pick it up; coop backlog promote <id> moves an item into 00_todo/ when it's ready.
kb/ The knowledge base: maps of each part of the code, and the traps and gotchas the code doesn't show. Agents keep it current as they work.
kb/rules/ Your taste, as rules: each correction becomes a "do X, not Y" card.
skills/ The workflow skills (spec, work, sweep, investigate, review-board, verify-api); each agent's own folder links to them.
presets/ Team recipes: a lead and its roles, like thinker, critic and fast. See Presets.
project.yaml Project settings: a monorepo's members, the dev server ports co:op publishes, the box's network setting, and the checks a fork must pass to merge.
loop.yaml The stages of coop loop (preflight, work, between, verify and signoff), and the models and prompts they use.

Parallel forks

One loop is one agent working one queue. To get through a queue faster, run several forks at once, each taking the next task from the same queue.

Start one fork per agent, with --loop -d so it works in the background. co:op hands each fork one task at a time from the shared .agent/tasks/ queue, so no two forks do the same work:

  • coop fork api frontier --loop -d# the frontier team
  • coop fork web codex@work --loop -d# one on Codex
  • coop fork deps gemini --loop -d# and one on Gemini
  • coop tasks watch# every fork's tasks
  • coop fork merge --all# merge them all

Each fork names a target or a preset, whose lead ladder its loop rotates through; give forks that run at once different accounts, so they don't share one limit. coop fork ls shows each fork's state, and coop fork logs <name> -f its output.

Why run parallel forks

When agents write code quickly, reviewing it takes most of your time. Run the agents in parallel and review their forks in batches.

Evaluations

Use evaluations to compare models, presets or loop recipes on repeatable tasks. A separate verifier grades the finished work; the model does not grade itself.

Start with a free preview

The shipped core suite has three small coding tasks. This command launches no container or provider and spends nothing:

  • coop eval run core codex --timeout 35m --dry-run

A real run needs a sign-in (coop login codex), a working container runtime and a current co:op box image. If the image is missing, run coop build --egress open from a folder without a project Dockerfile. The build may download dependencies. Then run the suite and read the result:

  • coop eval run core codex --timeout 35m# run it for real
  • coop eval inspect# read the result

A real run uses your provider account and may spend credits, and a preview checks only the plan, not your credentials or whether the runtime is ready. --timeout is a total time limit, not a money cap; each case also has its own timeout. More configurations or repetitions mean more paid work.

Compare before and after

To check whether a change helped:

  1. Run a suite and inspect the result.
  2. Change your model, preset, loop recipe or co:op build, then run the same suite with the same number of repetitions.
  3. Use coop eval runs to find the two run IDs, then coop eval compare <before-id> <after-id>. The argument order decides which run is the baseline. Inspect and compare show each configuration's short fingerprint and co:op build.

Choose a suite

  • core: three single-agent tasks. Use provider targets, such as codex:gpt-6.1-sol/xhigh, not presets.
  • queue: ten tasks through the real loop, including review and signoff. Use targets or presets, and allow hours, not minutes. For your frontier preset, try coop eval run queue frontier --timeout 2h. Add --loop-config .agent/loop.yaml to test your recipe.
  • Your own: coop eval init ./evals/my-suite creates a working example. Edit suite.yaml, files/greeting/ and the separate verifiers/greeting/verify.sh. The verifier's README explains grading.
  • An example in the source tree: examples/evals/maintenance/ has shell, Python and Node maintenance loops. Its checks confirm that unfinished starting versions fail and completed reference versions pass. It demonstrates a custom comparison, not an official benchmark or a shipped starter.

Each target after the suite is a separate configuration, not a fallback. --repeat 3 runs every case three times, and --jobs 2 allows two agent trials at once, though each loop trial works its tasks in order. coop help eval run lists every option.

Understand failures before spending again

When a run doesn't go as hoped, coop eval inspect shows the trials that didn't pass, their recorded causes, and where to find saved diagnostics and kept workspaces; add a run ID to read an older run. Each trial ends in one of these states:

  • failed: the independent verifier rejected the work.
  • error: running or grading couldn't produce a verdict. A provider's quota refusal is not a model-quality failure.
  • timed_out or pending: the trial ran out of time or didn't start. Grading is incomplete.

Incomplete grading means the comparison has no definitive winner. For a sign-in or quota refusal, check coop credentials <agent>. For a timeout, check the case’s suite.yaml limit and the run’s --timeout.

A run with no final summary may still be running or may have been interrupted. You can inspect it, but cannot compare or resume it. Trying again starts a new paid run. Review provider output for private data before sharing it.

Each trial has a private workspace without the source repository’s Git history. The model cannot read the hidden verifier. That verifier runs afterward in a separate container with no credentials or network access.

Trials exclude your MCP servers. co:op turns off native web search and fetch for the candidate and its managed peers and delegates, while leaving terminal and file tools available. This relies on the client following the setting; it is not a firewall that inspects each request. Regular runs keep their normal web tools.

Results describe the tested workload, not provider performance in general. Code size can help you review a change, but is not a quality score.

Compare two runs

Run the same tasks before and after your change, with the same number of repeats. Test one model or preset configuration in each run.

compare checks that the saved workloads match. If it cannot match the runs, it shows their results separately. It also reports missing or damaged records.

The report shows what changed; you decide whether the result is useful. The evaluation guide explains how the results are compared.

Editors

To steer the agent from your editor instead of a terminal, co:op serves it over ACP, the Agent Client Protocol. Any editor that supports ACP can then drive the agent in the box.

coop acp [target|preset] speaks ACP over stdio, so you add co:op as a custom agent in an editor that supports the protocol. Zed supports it today, and others are adding it. The setup is the same everywhere, with one entry for each target or preset you use; in Zed's settings.json, for example:

Zed settings.json

{
  "agent_servers": {
    "coop": {
      "type": "custom",
      "command": "coop",
      // one target; pin it like "claude:opus/xhigh@work"
      "args": ["acp", "claude"]
    },
    "coop · second opinion": {
      "type": "custom",
      "command": "coop",
      // a named peer; the target pins the lead's model
      "args": ["acp", "claude:opus/xhigh", "--peer", "codex"]
    }
  }
}

Pin the model, reasoning effort and account in co:op's target inside args (provider[:model][/effort][@account]), not in the editor's own options. The toolbar menus start on that target, and you can still switch them from there.

co:op sits between the editor and the agent, so in the editor:

  • A plain session's toolbar has Preset, Provider and Account menus; a session running a preset keeps the Preset menu.
  • Switching accounts, or between models of one provider, keeps the conversation. Switching providers starts a new session and carries over the messages and a one-line note for each tool call, as closely as it can.
  • At a usage limit, co:op moves to your next signed-in account and sends your prompt again, or waits for the nearest reset if every account is at its limit.
  • A box restart (coop build, coop update or running out of memory) replays the handshake, so your editor stays connected.

The agent’s permission prompts stay off, just as in a terminal run. ACP also lets it ask your editor to read files, write files or run commands on your computer. co:op forwards these requests; the editor controls their permissions.

Terminal and loop runs do not have this editor channel. See the ACP security note before connecting an editor.

To open a dev server from the box in your browser, list its port under serve: in a committed .agent/project.yaml and bind the server to 0.0.0.0 inside the box. The thread then shows the address the box publishes it on, http://localhost:<port>.

Desktop apps don't always get your shell's PATH. If your editor can't find coop, use the full path from command -v coop as the command.

MCP and remote sessions

Agents also use MCP servers, and co:op itself can run as a worker for another system.

Define MCP servers once, outside your repo, and co:op makes them available to supported agents, within the project's network setting, while keeping eligible HTTP tokens outside the box. The MCP guide covers local commands, remote HTTP servers, tokens and network settings.

As a remote worker, co:op connects out over TLS to a compatible controller, which supplies each job's repository, model targets, network access and limits; co:op fetches the code and runs the model. The worker keeps its private state and model credentials on its own machine, and needs Git, Git LFS and a supported container runtime:

  • coop sessions connect --controller <url> --token-file <path>

The worker connector guide has the details.

Detailed guides

Find settings, examples and explanations for each part of co:op.

  • Networking

    Choose which network destinations an agent can reach, and review access before a run.

  • Sandbox, images and services

    Control visible files, prepare a project image, and run databases and development servers beside your agent.

  • Agents, accounts and presets

    Sign in, choose models and accounts, and configure presets, teammates and instructions.

  • Forks and review

    Work in a separate copy of your project. Review the changes and checks before merging them.

  • Task queues and loops

    Set up a task queue for an agent to work through on its own, with decisions and a final review.

  • Editors and MCP

    Connect an editor or MCP server and check which actions run on your computer or in the container.

  • Configuration

    Find project settings, environment variables, configuration files and exit codes.

  • Usage and billing reports

    Connect your provider's billing reports and compare reported costs with local usage estimates.

  • Evaluations

    Run repeatable checks to compare changes to models, presets and loops. Keep the results for review.

  • Worker API

    Connect a worker and manage sessions, turns, evidence and publication through the worker API.

  • Command reference

    Look up co:op commands and options, with examples of how to use them.

Configuration

co:op works with its defaults. These are the settings you're most likely to change.

Set them as environment variables or in ~/.config/coop/coop.conf; the last three work only as environment variables.

Variable What it does
COOP_GATE Overrides the project’s gate: setting: the check command run inside the box, such as make check.
COOP_EGRESS filtered lets the box reach only its AI provider and the destinations you approve; coop init sets it for the project. open, the built-in default, leaves the network open. none starts a box without network access, including access to the model. Changing this setting does not disconnect an already-running box.
COOP_RUNTIME Force docker or container instead of detecting one (detection prefers Docker).
COOP_MEMORY, COOP_CPUS Cap the box's memory and CPUs, like 4g and 2.
COOP_<AGENT>_MODEL An agent's default model everywhere it runs, like COOP_CLAUDE_MODEL=opus.
COOP_CAFFEINATE On by default: while a loop runs, macOS caffeinate keeps the machine from sleeping. Set 0 to turn it off.
COOP_HOMES On by default: each selected agent’s repository settings and history are mounted into the box. COOP_HOMES=0 keeps them out, so an agent can't read your agents' settings; presets and peers need them, so those runs stop with an error.
COOP_SPINNER On by default: the live spinners animate. Set 0 or false to freeze the spinners and stop the loop's fast redraws while debugging or recording.
COOP_CONF Moves the coop.conf file co:op reads its COOP_* defaults from.
NO_COLOR Set to any value to turn off color everywhere (no-color.org).

On Docker, the box also runs with every Linux capability dropped, no-new-privileges and a process limit. The configuration reference lists every variable.

Troubleshooting

The problems people hit most, and the quickest fix for each.

Symptom Fix
"no container runtime found" Install Docker for online provider runs, then run coop build --egress open && coop doctor. To pick it explicitly, set COOP_RUNTIME=docker. Apple container supports raw uncredentialed open-network workloads only.
"image … not built" Run the coop build command the message names: --egress open, or --egress filtered for a project with filtered networking.
Sign-in hangs, or "usage limit reached" Run coop login <agent> again. A subscription limit resets on a schedule, and a loop waits for it on its own. An editor session moves to your next signed-in account and sends your prompt again.
Gemini says its Google sign-in client is no longer supported Run host coop login gemini and paste an AI Studio API key from the link it shows. Existing importable plain OAuth accounts also work through the broker; encrypted-only caches cannot be imported. Vertex GOOGLE_API_KEY is refused in every network mode.
A background loop won't stop Watch it with coop fork logs <name> -f, and stop it with coop fork stop <name>.
A secret is still visible Add its path to .coopignore. coop check-secrets finds secrets hiding inside files.
"permission denied" writing ~/.cache or build caches Check who owns the cache volume: coop-cache for the default user, or coop-cache-<uid>-<gid> on Linux (see id -u and id -g). If it has the wrong owner, save anything useful, remove only that idle volume, then run coop build. Never loosen your credential folder's permissions.
go or gofmt: "No version is set for command go" The box installs toolchains from .tool-versions with asdf. Add the golang version there. A filtered box installs it only at build time, so run coop build after. COOP_NO_ASDF=1 turns this off.
A pinned tool is installed but "not found" in a login shell A login shell (sh -lc, bash -l) reads /etc/profile, which resets PATH and drops asdf's shims. The box adds them back with an /etc/profile.d file; rebuild an older box with coop build to get it.
"box image is stale … run 'coop build'" You changed .agent/Dockerfile or .tool-versions since the image was built. Run coop build, and the warning goes away.
A merge refuses Commit or stash a dirty tree first. If the policy flagged a secret or a large file, review it, then pass --force. Without a terminal, pass --yes. If the gate failed on the rebased tree, the merge rolled back: fix it and run the merge again.
Zed can't find the agent Zed has to launch coop from a shell where it's on PATH (the installer puts it in ~/.local/bin). Give Zed the full path if needed, and check that coop acp runs in a terminal first.
An editor session misbehaves Turn on tracing: set COOP_ACP_TRACE=1 in the agent server's env, or touch ~/.config/coop/acp-debug, which also works on a server that's already running. co:op writes the editor and box traffic to ~/.config/coop/acp-trace-<pid>.log, which is size-bounded and pruned. It holds prompts and file contents, so treat it as sensitive.
A loop's live view shows provider activity wrong Run the loop with COOP_STREAM_TRACE=1. Each attempt writes the raw JSON lines and co:op's rendered lines under .agent/runs/<run>.streams/. They may hold prompts, tool inputs and model output, so treat them as sensitive.
A scaffolded Postgres 18 db exits 1 on coop up Older scaffolds mounted pgdata at /var/lib/postgresql/data, which Postgres 18 and later refuses. In .agent/compose.yml, move the mount up to /var/lib/postgresql. New scaffolds already do this.

The command reference lists every command's flags, and coop help (or coop <command> --help) is the live reference. Stuck on something that isn't covered? Open an issue.