# ADR-0002 — `git worktree` per trial, not containers

**Status:** accepted · **Date:** 2026-07-26

## Context

Every trial needs a clean checkout at the task's `base_commit`, with the config variant in place,
that the agent may freely mutate. Trials run concurrently. Environment setup (`uv sync`,
`npm ci`) is slow and must not run per trial.

## Decision

`git worktree add --detach` per trial, into `~/.cache/ablate/worktrees/<trial_id>`, with an
environment cache keyed on `(base_commit, lockfile hash)` hardlinked in. Removed after the trial
unless `--keep-worktrees`.

## Rejected: Docker container per trial (the SWE-bench model)

Genuinely better isolation — network, filesystem, system packages, and protection against an
agent that decides to `rm -rf ~`. It is what SWE-bench does, with layered image caching.

Rejected for v1 on three grounds:
1. **It breaks the five-minute promise.** Requiring Docker, then building an image per repo,
   turns a 6-minute first run into a 25-minute one and loses users who don't have Docker running.
2. **It doesn't match the environment under study.** Users care how the agent behaves on *their*
   machine with *their* toolchain. A containerized run measures a different environment and, if
   the image is wrong, measures it badly.
3. **Auth and network plumbing.** The agent needs API credentials and network egress inside the
   container. Solvable, but it is a weekend of yak-shaving in a four-weekend budget.

**Revisit** as an opt-in `--sandbox docker` in v2, and treat it as required for any future
hosted/CI-shared-runner mode.

## Rejected: fresh `git clone` per trial into a tmpdir

Simple and obviously correct. Rejected on cost: a full clone per trial for a large repo is
gigabytes of IO ×80 trials. Worktrees share one object database and cost a checkout.
`git clone --local --shared` narrows the gap but is strictly worse than a worktree.

## Rejected: one checkout, `git reset --hard` between trials

Cheapest, and fatally serializing — it forecloses concurrency, which is the only thing making a
25-minute run possible. Also leaks untracked files between trials in ways that are hard to
notice and would silently corrupt results.

## Consequences

- **Isolation is filesystem-only, and only within the repo.** An agent can still reach the
  network, install global packages, or write outside the worktree. Documented as a limitation,
  mitigated by preferring `--allowedTools` over `--dangerously-skip-permissions`, and by running
  the CI path on a disposable runner.
- Worktrees can leak on crash. Needs a `ablate clean` command and a startup sweep of stale
  worktrees older than 24h.
- Repos using submodules or LFS need extra handling; detect and warn rather than silently
  producing a broken checkout.
