Getting started
Quick path
After installing (step 1), run bunker init in the repo. It is the whole first run in one guided pass, eight steps with a progress line, a one-line "why this matters" for each, and a default on every question:
[1/8] Welcome what bunker does, needs and writes; a rough cost note
[2/8] Claude token `claude setup-token`, validated
[3/8] GitHub identity the exact token checklist + a pre-filled link, validated live
[4/8] Toolchain detects npm/pnpm/yarn/bun, composer, python, cargo, go, monorepos; you can edit setup and verify
[5/8] Sandbox image builds the image, runs setup and verify once as an unattended run will, shows the tail
[6/8] Merge safety a CI workflow (as a PR) and a ruleset requiring it, or the exact clicks
[7/8] Spend and models a daily cap (default $20), optional monthly cap, models
[8/8] Labels then a guided first task: a tiny issue, run attended, no auto-mergeNothing is written or created before a confirm that names the file or setting. Re-running bunker init skips what is already ✓ and says so, and Ctrl-C leaves no half-written files. bunker init --yes takes every default and never reads input; it does not open PRs or change repo settings, and lists at the end the steps that need you. bunker init --explain <step> re-reads a step (for example --explain github). NO_COLOR=1 turns off colour and glyphs. bunker doctor is read-only and safe to re-run any time; it exits 1 while anything required is missing. The steps below are the same setup done by hand.
1. Install
curl -fsSL https://raw.githubusercontent.com/dbggr/bunker/main/install.sh | sh
bunker --versioninstall.sh checks the prerequisites (git, bun, docker, gh, claude), builds the latest release tag into ~/.local/share/bunker and links ~/.local/bin/bunker; see the README. The base image's Dockerfile is embedded in the binary and built on first use, so Docker (or Podman) must be running.
2. Authenticate Claude
claude setup-tokenCopy .env.example to ~/.config/bunker/.env and set CLAUDE_CODE_OAUTH_TOKEN to the token it printed. One file covers every repo. A repo can override it in its own .bunker/.env (gitignored). Precedence: exported variables > <repo>/.bunker/.env > ~/.config/bunker/.env.
Models are chosen per role (implementer, reviewer, auditor): BUNKER_MODEL sets all of them, BUNKER_IMPLEMENTER_MODEL / BUNKER_REVIEWER_MODEL / BUNKER_AUDITOR_MODEL one role, in the same .env files. Flags win: --implementer-model, --reviewer-model, --auditor-model, and --model for all. Per role: role flag > --model > role env > BUNKER_MODEL > Claude Code's default. The model is shown when each role starts, in the run log, in the PR body and in --ui.
3. Create a scoped GitHub token
Set BUNKER_GH_TOKEN in the same .env. bunker's own gh and git calls use it instead of your login. Create a fine-grained token (GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens), restricted to the one repository, with a short expiry and exactly these permissions:
- Contents: Read and write
- Pull requests: Read and write
- Issues: Read and write
- Metadata: Read (added automatically)
- Actions: Read (optional): lets the PR shepherd read the log of a failed CI job and hand it to a fix agent. Without it the shepherd cannot see why a check is red, so it labels the PR
bunker:failedand notifies you instead
Nothing else. See security.md for why.
4. Set up the repo
In the target repo:
.bunker/config.toml: one file for the repo settings (bunker initwrites it):tomlsetup = "bun install" # runs in each worktree before the agent (worktrees have no node_modules) verify = "bun test && bun run typecheck" # must pass before anything is pushed (or pass --verify) copy = [".env"] # optional: gitignored files your tests need, copied into each worktreeverifyis read from origin's default branch, so an agent cannot edit it for its own run, and it runs in the sandbox. Copied files are never committed and.env*values are redacted from logs; paths outside the repo are rejected. Other top-level keys:verify_network(give sandboxed verify the network),verify_retries(fix rounds when verify fails, default 1),check(a command such as a typecheck, run isolated before each review, its output goes to the reviewer) andcontext(repo files inlined into the prompts). Tables:[models],[skills],[watch](includingtriage_every),[merge](merge.mode = "manual"leaves PRs for you to merge),[clean](logs_days) and[notify]; all are listed in cli.md. Spend caps for every repo,max_cost_dayandmax_cost_month, go in~/.config/bunker/config.toml. A leftover.bunker/setupor.bunker/verifyfile is an error (move it intoconfig.toml); the older.bunker/copyfile still works.bunker doctorshows the effective value and source of every key..bunker/Dockerfile(optional): adds the repo's toolchain to the agent image. Start withFROM bunker-claude. See concepts.md.On GitHub: enable "Allow auto-merge", and make a CI check required on the default branch.
--mergehands the merge to GitHub, which merges only when the required checks pass; without auto-merge, or when the repository rulesets (GET rules/branches/<default>) show no required status check or cannot be read, bunker refuses (merge-failed) rather than merge immediately. Require the check with a repository ruleset (Settings → Rules → Rulesets): the fine-grained token can read rulesets but not classic branch protection, which needs Administration (see security.md).
Commit these files; the Dockerfile is read from the agent's worktree.
5. First run
From the repo's main checkout:
bunker issue 12bunker implements issue 12 in a worktree, reviews it, runs verify and opens a PR. Read the PR before trusting the loop.
6. Scale up
Label issues bunker:queued, then work the queue:
bunker queue --mergeOr leave it running unattended:
bunker watch --for 5h --max-cost-day 10bunker watch implies bunker queue --merge, so it needs verify in config.toml. Watch the run with bunker ui. Every flag is in cli.md; if something goes wrong see troubleshooting.md.
Optional: a separate GitHub identity
Everything above uses your own PAT, so every PR is authored by you and GitHub won't let you approve it. If you want separate attribution, or "auto-merge, but only after I approve", give bunker its own identity. This is opt-in; with only BUNKER_GH_TOKEN set nothing changes, and bunker init asks (default no).
Not yet tested end to end against a real repository; tracked in #372.
A GitHub App (preferred). Create a private App with no webhook and the permissions Contents, Pull requests and Issues: Read and write; Metadata, Actions, Checks and Statuses: Read. Don't grant Workflows. Install it on the repo, generate a private key, and set in ~/.config/bunker/.env:
BUNKER_APP_ID=<app id>
BUNKER_APP_PRIVATE_KEY_PATH=~/.config/bunker/bunker-app.pem # chmod 600At run start bunker signs a JWT with the key, finds the repo's installation (GET /repos/{owner}/{repo}/installation), mints an installation token (POST /app/installations/{id}/access_tokens) and uses it for push, PR, issue, comment and label calls. Tokens last an hour; bunker renews them before they expire. The key and the tokens are never passed into a sandbox, and output is redacted.
A bot account. Create a GitHub user for bunker, add it as a collaborator, and set BUNKER_BOT_GH_TOKEN to its fine-grained PAT (same permissions as above). It takes the place of BUNKER_GH_TOKEN.
If both are configured the App wins. If the App can't mint a token bunker stops; it does not fall back to your PAT. Commits still carry your configured git author. The maintainer gate and trusted-comment rules still key on the human maintainer: comments by the bot never count as trusted. bunker doctor shows which identity is in use and whether it can read the repo, issues and PRs.
Recipe: require your approval before merge. Because the PR author is now the bot, you can approve it:
- Settings → Rules → Rulesets (or branch protection) for the default branch: require a pull request with 1 approving review, plus your CI check.
- Allow auto-merge in Settings → General.
- bunker opens the PR and enables auto-merge; it waits for CI and your approval.
- Approve the PR; auto-merge lands it.