# @shadowclone/clones

Runs clones: Claude Code or Codex works for the owner, as the owner, in Docker on a machine that the owner owns. The owner starts a clone from the CLI or the MCP server on that machine. The CLI and the MCP server call it. [Design record 049](../../docs/design/049-clones.md) explains the design.

<!-- package-facts:start -->

(generated by `bun run guides`; do not edit by hand)

- Package name: `@shadowclone/clones`
- Workspace dependencies: `@shadowclone/bot`, `@shadowclone/core`, `@shadowclone/redact`
- External dependencies: `smol-toml`, `zod`
- Export subpaths: `.`

<!-- package-facts:end -->

## Owns

- `src/config/`: the clone config schema, the providers and their secrets, and the host paths.
- `src/node/`: `localNode` and its `start`, `list`, `get`, `send`, `answer`, and `stop` operations.
- `src/node/` also holds the run folders, the inbox, the request and record schemas, the progress lines, and the admission rules.
- `src/run/`: the run program inside the clone image (`runClone`), with target resolution, the workspace, git hooks, engine, review stages, save, and finish steps.
- `src/run/drive/`: the Claude Code and Codex drivers and `superviseEngine`, which delivers messages and answers and waits for an answer.
- `src/run/ask/`: the `shadowclone_ask` MCP server that runs inside the clone.
- `src/serve/`: `serveClones`, the Docker launcher, and the launchd or systemd service.
- `src/setup/`: setup on this machine, the secrets file, the summary, and the checks.
- `image/Dockerfile`: the clone image that `release.yml` publishes to GHCR.

## Rules

- A clone starts only from a request in its run folder, which `localNode().start` writes. Nothing on GitHub starts a clone.
- `serveClones` is the only writer of `record.json`. It holds the `serve.lock` lock, so one machine runs one `serve`.
- `serve` runs at most `parallelClones` clones, and one clone at a time for a ChatGPT plan login.
- A container that exits with no final progress line is `failed`. A queued clone with a stop marker never starts.
- `serve` delivers each inbox line to a running clone once. `answer` accepts only an open question.
- A Claude message interrupts the turn and arrives as a new user turn. A Codex message uses `turn/steer`.
- A clone with an open question waits at most 30 minutes, then takes its recommended option and skips each destructive step.
- The final report passes through `redactSecrets` before it leaves the container.
- `start` refuses a repository with no setup and a setup from an earlier config version. It also refuses a clone over `dailyClones` and a second active clone for one issue or pull request. It holds the `start.lock` lock from the check to the written request.
- shadowclone never reads a model login or the GitHub token. The owner pastes them into the secrets file. Docker gets the secrets file path only.
- A clone never pushes to the default branch. The pre-push hook refuses it. Setup changes none of the repository settings.
- A review runs the toolchain only on a pull request that the owner wrote in this repository. Other reviews turn the network off.
- Setup refuses a ChatGPT plan login on a public repository, and a repository that the owner cannot push to.

## Tests

Run `bun test` in this folder, or `bun test packages/clones` from the root. `src/fixtures.ts` has a fake GitHub, a sample config, and a temporary clones folder. `src/serve/fakeLaunch.ts` replaces Docker in the serve tests. The hook tests use real `git` in a temporary folder. No test needs an account or Docker.

To try a branch in Docker, run `bun run stage`, then `npm pack` in `packages/cli/out/package` with `--pack-destination packages/clones/image`. Build with `--build-arg SHADOWCLONE_PACKAGE=/tmp/shadowclone-build/<file>.tgz`, and pass the tag to `clone setup --image`.

Update this file in the same commit when you change the package purpose, public exports, dependencies, or a rule above.
