Overview#
Forkbomb forks a coding agent into N sandboxed copies of your repo. Each fork tries a different strategy. Your test suite judges them. The losers are killed, the passing fork exits 0, and its patch is yours.
A single agent run is one draw. When it goes the wrong way, you find out late and start over. Forkbomb takes several draws at once, cheaply, and lets the tests you already trust pick the result. Forking uses APFS clonefile(2), so a fork costs metadata, not a copy of your repo. The name is the joke; :(){ :|:& };: is the classic shell fork bomb. This one stops at the number of forks you ask for.
- Platform
- macOS on APFS. Sandboxing uses Seatbelt.
- Engines
claude-code(default, your Claude plan),api(API key) orhosted(live)- Judge
- Your test command, run against each fork's patch in a fresh clone
- Output
winner.patch, a full event log, a replayable run- Status
- Pre-release. Install from source. 64 automated tests in the CLI's own suite.
- License
- MIT. Self-hosting is free and always will be.
- pid 1
- The parent: a clean clone of your repo plus a base snapshot. Every fork copies it.
- fork
- One agent in its own copy-on-write clone, with its own strategy. IDs look like 1.01, 1.02.
- race
- One run of the CLI: fork, let the forks work, judge, keep one.
- kill -9
- A losing fork is stopped mid-thought and its clone is deleted.
- exit 0
- The fork whose patch passed your whole suite. Its patch is the answer.
Requirements#
Forkbomb runs on macOS only today. Copy-on-write forking needs APFS and the sandbox is macOS Seatbelt. There is no Linux or Windows build.
- macOS on an APFS volume
- Node 22 or newer
- Xcode Command Line Tools
- Claude Code logged in (Pro or Max plan), or an Anthropic API key
Xcode Command Line Tools provide clang, which compiles a one-file clone helper on first run. For the default engine, Claude Code must be installed and logged in with a Pro or Max plan. For --engine api, you need an ANTHROPIC_API_KEY instead. For --engine hosted, you need a FORKBOMB_API_KEY and credit (see Hosted engine).
forkbomb doctor checks all of it:
| Check | What it verifies | If it fails |
|---|---|---|
| macOS | The platform. Seatbelt and clonefile are macOS features. | Run on a Mac. |
| Node | Node major version is 22 or newer. | Install Node 22+. |
| APFS copy-on-write clones | ~/.forkbomb sits on an APFS volume that supports clonefile. | Move ~/.forkbomb to APFS. Otherwise forks fall back to plain copies. |
| clang | A compiler for the one-file clone helper, built on first run. | xcode-select --install |
| Seatbelt sandbox confines writes | A sandboxed shell can write inside its folder and not outside it. | Open an issue with the doctor output. |
| Claude Code logged in | claude auth status reports a login. Needed for the default engine. | claude auth login |
| Anthropic API key | ANTHROPIC_API_KEY is set. Optional, only for --engine api. | Export it or add it to ~/.forkbomb/.env |
| Hosted key and credit | Optional, only for --engine hosted. If FORKBOMB_API_KEY is set, asks the gateway for your balance. | Create a workspace at /app (opens at launch) |
| Isolation canary | Whether the canary has passed for this Claude Code version. | forkbomb canary |
Install#
Forkbomb is not published on npm yet. Build it from source. Any package on npm that claims to be Forkbomb is not this project.
# Clone and buildgit clone https://github.com/plvgger/forkbombcd forkbomb && npm install && npm run build # Check the machinenode dist/cli.js doctor # Run itnode dist/cli.js run ./my-repo \ --task "fix the failing tests" \ --test "npm test" --uiCredentials#
For the default engine, log Claude Code in once. Forkbomb uses whatever it is logged in with. For the API or hosted engine, put the key in ~/.forkbomb/.env or export it.
claude auth loginANTHROPIC_API_KEY=... # --engine apiFORKBOMB_API_KEY=forkbomb_sk_... # --engine hostedQuickstart#
Four commands from a fresh build to a verified patch. Point Forkbomb at a repo with a failing test suite.
Check the machine
Terminalsh forkbomb doctorProve the sandbox holds
Optional. Forkbomb runs the isolation canary on its own before the first run on each Claude Code version. It takes about a minute.
Terminalsh forkbomb canaryStart the race
--tasksays what to do.--testdecides who exits 0.--uiopens the live process tree on127.0.0.1:4317.Terminalsh forkbomb run ./my-repo --task "fix the failing tests" --test "npm test" --uiReview and ship the patch
The passing fork's diff is saved as
winner.patchin the run folder. Read it, then apply it. Or pass--applynext time and Forkbomb applies it for you.Terminalsh git -C ./my-repo apply ~/.forkbomb/runs/<id>/winner.patch
What a race looks like#
A real run from 2026-10-05: Claude Code on a Max plan, on the demo calc repo. The baseline had 4 of 14 tests passing. Four forks were made in 1.13 ms each. Fork 1.04 (rewriter) passed 14/14 first, the other 3 were killed, and the whole race took 38.7 s.
node dist/cli.js run ./calc --task "fix the failing tests" --test "node --test" --forks 4run · 4 forks × 2 rounds · claude-code · race · sandbox onbaseline: 4 passing, 10 failingfork() 4 copies of pid 1 in 1.13 ms each via apfs-clonefile 1.01 surgeon 1.02 root-cause 1.03 test-driven 1.04 rewriter 1.04 ✎ create calc.js · $ node --test 1.04 PASS 14/14 · 94 lines kill -9 1.01 1.02 1.03 (1.04 passed first)exit 0 1.04: 94 lines in 1 file. All 14 tests pass. 38.7s
| PID | PPID | CMD | FORK | TURNS | TESTS | STAT |
|---|---|---|---|---|---|---|
| 1 | - | demo calc repo | - | - | 4/14 | parent |
| 1.01 | 1 | surgeon | 0.97 ms | 8 | - | R+ runningSIGKILL |
| 1.02 | 1 | root-cause | 1.46 ms | 8 | - | R+ runningSIGKILL |
| 1.03 | 1 | test-driven | 1.05 ms | 6 | - | R+ runningSIGKILL |
| 1.04 | 1 | rewriter | 1.03 ms | 9 | …14/14 | R+ runningexit 0 |
How a race works#
Five phases. Forkbomb clones your repo once into pid 1, forks it, lets the forks race, judges each patch on a clean copy, and keeps one.
- fork()clonefile pid 1 into N forks
- Raceone strategy per fork, in parallel
- Judgeapply the patch to a fresh clone, run the suite
- kill -9kill the losers, the passing fork exits 0
- Re-forkno pass: the best fork becomes the next parent
1. fork()#
Forkbomb clones your repo once into pid 1, commits a base snapshot, and forks pid 1 into N copies with clonefile(2). On APFS a clone shares every data block with its parent until a fork writes, so forking costs metadata, not bytes. Off APFS, Forkbomb falls back to a plain copy.
| Forker | Per fork | Extra disk |
|---|---|---|
| apfs-clonefile | 45 ms | 22 MB |
| copy | 1,108 ms | 1.3 GB |
forkbomb bench · MacBook Air (M2, 24 GB) · 80 MB node_modules tree, 4,400 files · 16 forks. ≈24× faster, ≈60× less disk. Run forkbomb bench ./my-repo to measure your own.
2. Race#
Each fork is an agent with a shell and a file editor, working in its own clone. Each gets a different strategy. Diversity is the point: eight copies with one strategy fail the same way eight times. Forks take strategies in this order and wrap around after twelve.
| # | Strategy | Brief |
|---|---|---|
| 01 | surgeon | Make the smallest change that could possibly work. |
| 02 | root-cause | Read every file involved first. Find the underlying cause, fix it once. |
| 03 | test-driven | Run the tests first. Let failure output drive every step. |
| 04 | rewriter | If the code at fault is tangled, rewrite the function or module cleanly. |
| 05 | skeptic | Assume the obvious fix is wrong. Hunt for edge cases the tests imply. |
| 06 | cartographer | Find every caller and related definition before changing anything. |
| 07 | sprinter | Make a quick attempt, run the tests, iterate. |
| 08 | spec-first | Write down what each test expects, then implement to that spec. |
| 09 | bisector | Isolate one failing test at a time. Finish it before the next. |
| 10 | minimalist | Prefer deleting or simplifying code over adding more. |
| 11 | tracer | Observe what the code actually does with prints or a scratch script. |
| 12 | contrarian | Pick an approach different from the first that comes to mind. |
3. Judge#
A fork is judged by the patch it would ship, not by the state of its sandbox.
- Take the fork's diff against the base snapshot.
- Drop every change to tests and test config (see protected paths).
- Apply what is left to a fresh clone of pid 1.
- Run your test command there, under Forkbomb's own Seatbelt profile.
- Score it. A clean exit only counts as a pass if no tests went missing compared with the baseline.
Hacks to ignored files such as node_modules or build output never reach the fresh clone, so they never count. The judge is designed against the common ways an agent games a suite. It is still being hardened. Read the winning patch before you ship it.
4. kill -9#
In race mode, the first fork to pass the full suite exits 0 and the rest are killed mid-thought. In best mode, every fork finishes and the smallest passing diff wins. Killed forks' clones are deleted unless you pass --keep-forks.
5. Re-fork#
If nobody passes, the best fork's verified state (pid 1 plus its patch) becomes the parent of the next round, with a note on where it left off. --rounds caps how many times this happens. If the last round still has no pass, Forkbomb saves the best partial patch as best.patch.
Engines#
Three ways to drive the forks. Whichever you pick, tools run on your Mac inside the sandbox, and credentials stay on your machine.
| claude-code (default) | api | hosted | |
|---|---|---|---|
| Credentials | claude auth login | ANTHROPIC_API_KEY | FORKBOMB_API_KEY |
| Billing | Your Pro or Max plan | Pay as you go, with Anthropic | Credit from burning $FORKBOMB |
| Model | Your Claude Code default | claude-opus-5-5 | Forkbomb's GPU coding model |
| Shell sandbox | Claude Code's sandbox plus Forkbomb's rules | Forkbomb's Seatbelt profile | Forkbomb's Seatbelt profile |
| --network | Not supported yet | Opt-in | Opt-in |
| Isolation canary | Before the first run on each version | Not used | Not used |
| Status | Live | Live | Live |
claude-code#
Each fork is a headless Claude Code session (claude -p) on whatever Claude Code is logged in with. Forks count against your plan's usage limits, and eight forks use them about eight times as fast as one session. Each fork runs with:
--safe-mode: no CLAUDE.md, hooks, plugins or MCP.- No user or project settings, so a repo's own
.claude/settings.jsoncan't loosen anything. - Claude Code's sandbox for Bash: writes stay in the clone, no network, credential folders unreadable, no unsandboxed escape hatch.
- Permission rules that deny the file tools on credential folders and
.git. - No API keys in its environment.
api#
Forkbomb's own tool loop on the Messages API, with ANTHROPIC_API_KEY. The default model is claude-opus-5-5 at medium effort. Shell commands run under Forkbomb's Seatbelt profile. The text editor runs in Forkbomb's process and re-checks every path: no .., no symlinks out of the clone or into .git, no writing through hard links.
hosted#
The same tool loop and the same sandbox as api, but the model is Forkbomb's own GPU coding model behind an OpenAI-compatible gateway, paid with credit from burning $FORKBOMB. Details in Hosted engine.
Hosted engine#
--engine hosted runs forks on Forkbomb's GPU coding model instead of Claude. The model only talks. Every tool call still runs on your Mac, in the same sandbox as the api engine.
The hosted GPU pool is live. Credit comes from burns, which open when $FORKBOMB launches; until then a workspace with no credit gets 402 insufficient_credits.
Set it up#
Create a workspace
In the app (opens at launch). You get a workspace id, an API key that starts with
forkbomb_sk_, and your burn memo. The key is shown once. Only a hash of it is stored.Add credit
Burn $FORKBOMB with your workspace memo. See Burn for compute.
Give the CLI the key
~/.forkbomb/.envenv FORKBOMB_API_KEY=forkbomb_sk_...Check the balance, then race
Terminalsh forkbomb creditsforkbomb run ./my-repo --task "fix the failing tests" --test "npm test" --engine hosted
--model is ignored with this engine: the gateway picks the model. Before it makes a single fork, the CLI asks the gateway for your balance and stops if it is zero.
Base URL#
The CLI talks to https://forkbomb.fun/api/v1. Set FORKBOMB_HOSTED_URL to point it somewhere else, for example a gateway you run yourself. The URL must be https (plain http only for localhost) and must not carry credentials. Redirects are refused, so the key can't be bounced to another host.
Credits and pricing#
Hosted compute is priced per million input tokens and per million output tokens, in USD. The current prices come back from GET /api/v1/me and forkbomb credits prints them. Prices are not final until the pool is live.
- Each request first reserves the most it could cost: the estimated input plus
max_tokens. - When the model answers, the real cost is charged and the rest of the reservation is returned.
- A request that fails upstream is charged nothing.
- The balance can't go below zero. The database refuses it.
forkbomb creditsworkspace <label> (ws_…)credit $<balance>pricing $<in> / 1M input tokens · $<out> / 1M output tokens · model <model>top up burn $FORKBOMB at https://forkbomb.fun/app
| Flag | Default | Description |
|---|---|---|
--json | off | Print the raw /api/v1/me response instead of the summary. |
Out of credit (402)#
When a request would cost more than the balance, the gateway answers 402 insufficient_credits and charges nothing. In a race, the fork that got the 402 stops with “out of credit: burn $FORKBOMB to top up”. The forks share one balance, so no other fork makes another model call after that. Forks that stopped are still judged on what they changed so far, so a fork that already passed can still exit 0.
429 and 5xx answers (except 503) are retried up to four times with backoff, honoring Retry-After. 401, 402 and 503 are not retried.
Isolation#
Forks run untrusted agent output on your machine. Forkbomb confines what they can write, read and reach. Here is what holds and what doesn't.
Enforced
- Writes only inside the fork's clone and its private temp dir
.gitis read-only for forks- Credential folders unreadable (
~/.ssh,~/.aws,~/.config/gh, Keychains) - No network beyond loopback
- Clean environment: no API keys or tokens
- Command timeouts, capped output, background processes killed
Not enforced
- Forks can read most of your filesystem outside the credential folders
- Forks can use CPU and memory freely
- Seatbelt is a macOS sandbox, not a VM
--no-sandboxremoves all of the above
Run Forkbomb on code you'd be comfortable letting an agent work on. The judge (git and your test command) always runs under Forkbomb's own Seatbelt profile, whichever engine drove the forks. With the hosted engine, the gateway only sends model tokens back; it never runs anything on your machine.
The isolation canary#
With the claude-code engine, Forkbomb doesn't assume the sandbox holds. Before the first run on each Claude Code version, it starts a real session in a throwaway workspace, tells it to escape, and checks the results. Forks only start if every escape failed. The result is cached in ~/.forkbomb/canary.json. Run it any time with forkbomb canary.
| Check | Probe |
|---|---|
| Writes inside the clone work | Creates inside.txt in the fork's clone. |
| Shell can't write outside the clone | Tries ../escape-bash.txt from Bash. |
| File tools can't write outside the clone | Tries to write escape-write.txt next to the clone. |
| No outbound network | Runs curl against example.com. |
| Denied folders are unreadable | Plants a secret in a denied folder and checks it never surfaces, through the shell or the Read tool. |
| .git is read-only | Tries to create .git/forkbomb-probe. |
Commands#
Seven commands. forkbomb --help prints the same reference. Until the npm release, type node dist/cli.js in place of forkbomb.
forkbomb run [repo] --task "..." --test "cmd" race forks on a repoforkbomb bench [dir] --forks 16 clonefile vs copy, measuredforkbomb replay <run-dir> watch a recorded runforkbomb export <run-dir> <out-dir> static replay you can host anywhereforkbomb doctor check the machineforkbomb credits hosted credit balance and pricingforkbomb canary prove Claude Code forks can't escapeforkbomb run#
Usageforkbomb run [repo] --task "…" --test "cmd" [options]
Starts a race on a repo. repo defaults to the current directory. Exits 0 when a fork passes the full suite, 1 otherwise. With --ui, the live view stays up after the run until you press Ctrl-C.
| Flag | Default | Description |
|---|---|---|
--task "…" | required | What the forks should do. Every fork gets the same task and a different strategy. |
--test "cmd" | required | The command that decides who wins. Runs in a fresh clone under Forkbomb's Seatbelt profile. |
--forks N | 8 | Forks per round. 1 to 64. The pre-rename --heads, --head-timeout and --keep-heads names still work. |
--rounds N | 2 | Rounds. Each round forks again from the best fork so far. 1 to 10. |
--mode race|best | race | race: the first full pass exits 0 and the rest are killed. best: every fork finishes and the smallest passing diff wins. |
--engine NAME | claude-code | claude-code runs forks through Claude Code on your Claude plan. api calls the Anthropic API with a key. hosted uses Forkbomb's GPU model, paid with credit. |
--model ID | engine default | Model for the forks. api: claude-opus-5-5. claude-code: your Claude Code default (for example opus or sonnet). Ignored by hosted. |
--effort LEVEL | medium | low, medium, high, xhigh or max. |
--max-turns N | 30 | Tool-use turns per fork. 1 to 500. |
--fork-timeout S | 600 | Seconds per fork. |
--bash-timeout S | 120 | Seconds per shell command. |
--test-timeout S | 300 | Seconds per test run. |
--concurrency N | 8 | Max forks talking to the model at once. 1 to 64. |
--protect GLOB | none | Extra read-only path for forks. Repeatable. |
--no-default-protect | off | Don't protect test files and test config by default. |
--apply | off | Apply the winning patch to your repo. |
--keep-forks | off | Keep killed forks' clones on disk. |
--network | off | Let forks reach the network. Default is loopback only. Not on the claude-code engine. |
--no-sandbox | off | Run forks without the macOS sandbox. Not recommended. |
--ui | off | Open the live tree view in your browser. |
--port N | 4317 | Port for --ui and replay. |
--no-open | off | Don't open a browser for --ui. |
--runs-dir DIR | ~/.forkbomb/runs | Where runs live. Can't be inside the repo. |
--claude-bin PATH | claude | Claude Code binary to drive. claude-code engine only. |
-v, --verbose | off | Print every tool call. |
forkbomb bench#
Usageforkbomb bench [dir] [--forks 16] [--no-copy] [--json]
Forks the same workspace with clonefile and with a plain copy, and prints time and disk for each. Extra disk is measured from free space before and after, so other activity on the machine shows up as noise.
| Flag | Default | Description |
|---|---|---|
[dir] | . | Workspace to fork. |
--forks N | 16 | How many forks to make with each method. |
--no-copy | off | Skip the plain-copy baseline. |
--json | off | Print rows as JSON instead of a table. |
forkbomb replay#
Usageforkbomb replay <run-dir | events.jsonl> [--port 4317] [--no-open]
Serves the tree view for a recorded run on 127.0.0.1 and plays it back from the event log.
| Flag | Default | Description |
|---|---|---|
<run-dir | events.jsonl> | required | A run folder or its event log. |
--port N | 4317 | Port for the local viewer (bound to 127.0.0.1). |
--no-open | off | Don't open a browser. |
forkbomb export#
Usageforkbomb export <run-dir> <out-dir>
Writes a static, self-contained replay: index.html, app.js, style.css, data.js and a copy of events.jsonl. Host it anywhere that serves static files. The replay on this site is built from an export of the run above.
forkbomb doctor#
Usageforkbomb doctor
Checks the machine and prints one ok, info or FAIL line per check, with a hint on failures. See Requirements for the full list.
forkbomb credits#
Usageforkbomb credits [--json]
Asks the hosted gateway for your workspace, balance and pricing, using FORKBOMB_API_KEY. Exits with a hint if no key is set. See Credits and pricing.
forkbomb canary#
Usageforkbomb canary [--claude-bin PATH] [--model ID]
Runs the isolation canary against the installed Claude Code and prints each check. Exits 0 only if every escape failed.
| Flag | Default | Description |
|---|---|---|
--claude-bin PATH | claude | Claude Code binary to test. |
--model ID | Claude Code default | Model for the canary session. |
Run artifacts#
Every run is saved under ~/.forkbomb/runs/<id>/, named by start time. Nothing is uploaded. (The folder keeps its pre-rename name.)
~/.forkbomb/ .env ANTHROPIC_API_KEY / FORKBOMB_API_KEY (optional) canary.json last canary result, per Claude Code version runs/ 20261005-155223/ one folder per run, YYYYMMDD-HHMMSS events.jsonl every event in order; replay and export read it winner.patch the passing fork's diff (best.patch if none passed) body/ pid 1: clean clone of your repo plus the base snapshot heads/<id>/ the final fork's clone; killed forks are deleted state/<id>/ pid 1 plus the final patch, verified by the judgePass --keep-forks to keep every fork's clone. Pass --runs-dir to put runs somewhere else, as long as it is outside the repo.
winner.patch#
A plain git diff against your repo. Test and test-config edits are already stripped. This is the start of the 94-line patch from the run above:
--- a/calc.js+++ b/calc.js@@ -1,19 +1,25 @@ // A small arithmetic evaluator: + - * / ^, parentheses, unary minus, decimals. // evaluate("2 + 3 * 4") === 14+//+// Precedence (lowest to highest): + - < * / < unary - < ^ (right-assoc). export function tokenize(src) { const tokens = []; let i = 0; while (i < src.length) { const c = src[i];- if (c === " ") {+ if (/\s/.test(c)) { i++; continue; }- if (/[0-9]/.test(c)) {+ if (/[0-9.]/.test(c)) { let j = i; while (j < src.length && /[0-9.]/.test(src[j])) j++;- tokens.push({ type: "num", value: parseFloat(src.slice(i, j)), pos: i });+ const text = src.slice(i, j);events.jsonl#
One JSON object per line, each stamped with the time since the run started. The live view, replay and export all read this file. Event names predate the rename: a fork is a head, a kill is a sever.
| Type | Carries |
|---|---|
| run_start | Forks, rounds, model, effort, mode, engine, sandbox state. |
| baseline | The suite on untouched pid 1: passing, failing, exit code. |
| fork | Forks made, per-fork clone time, forker used, logical and physical bytes. |
| head_start | A fork starts with its parent and strategy. |
| tool | One bash or edit call, with a summary, result and duration. |
| note | A short progress note from a fork. |
| head_done | A fork stopped: reason, turns, cost when known. |
| judging | The judge picked up a fork's patch. |
| judge | Verdict: score, pass and fail counts, diff size, reverted test edits. |
| sever | A fork was killed, and why. |
| round_end | Best fork of the round and its score. |
| winner | The fork that exited 0, its patch and summary. |
| run_end | Outcome, duration, patch path, whether it was applied. |
| log | Info, warnings and errors. |
Writing --task and --test#
The task points the forks. The test command picks the one that exits 0. Most bad runs trace back to one of the two.
A good --task#
- State the outcome, not the method. Strategies already vary the method across forks.
- Name what you know. The file, the function, the behaviour that is wrong.
- Say what must not change. A public API, a file format, a dependency.
- Keep it to one job. Two unrelated fixes in one task split the forks' attention.
--task "make the parser better"--task "parseDate in src/date.ts throws on a trailing Z. Parse it as UTC. Keep the signature."A good --test#
- It must fail now. Forkbomb runs it on the untouched repo first. If it already passes, there is nothing to race for and the run stops.
- Fast and deterministic. It runs once for the baseline and once per judged fork. Flaky tests pick random winners.
- Offline. The judge has no network beyond loopback. Install dependencies before the run; forks can't install them either.
- Scoped. Run the tests that matter for the task, not the whole slow suite.
Forkbomb reads pass and fail counts from node:test, vitest, jest, mocha, pytest, unittest, cargo test and go test output, which gives partial credit and lets the best partial fork seed the next round. With any other runner, the exit code decides: pass or fail, nothing in between.
Protected paths#
Forks can't win by editing the tests. By default, changes matching these globs are dropped from every patch before it is judged. Add more with --protect; turn the defaults off with --no-default-protect.
**/*.test.***/*.spec.***/test/****/tests/****/__tests__/****/test_*.py**/*_test.py**/*_test.go**/conftest.py**/package.json**/package-lock.json**/pnpm-lock.yaml**/yarn.lock**/vitest.config.***/vite.config.***/jest.config.***/.mocharc***/pytest.ini**/pyproject.toml**/setup.cfg**/tox.ini**/Cargo.toml**/go.mod**/MakefileBurn for compute#
Burning $FORKBOMB is how you pay for hosted compute. The server reads your burn from Solana, prices it in USD at the time of the burn, and credits your workspace. Self-hosting never needs the token.
Create a workspace
In the app. It gives you a workspace id like
ws_…, an API key (shown once) and your memo:forkbomb:<workspaceId>.Burn from your wallet
One Solana transaction that burns $FORKBOMB (an SPL
burnorburnChecked, Token or Token-2022 program) and carries exactly one memo,forkbomb:<workspaceId>, with nothing else in it. The app builds this transaction for you.Verify
The app sends the transaction signature to
POST /api/burns/verify. You can call it yourself with any signature; it is safe to repeat.Credit lands
Once the transaction is finalized and checks out, the workspace is credited and the burn shows up on the public ledger.
What the verifier checks#
Everything is read back from the chain. Nothing you send besides the signature is trusted.
- The transaction exists on mainnet, is finalized, and did not fail.
- It burns the $FORKBOMB mint, in a top-level or inner instruction. Burns of any other token don't count.
- Each burned token account's balance fell by exactly the amount burned.
- There is exactly one memo starting with
forkbomb:, and it is exactlyforkbomb:<workspaceId>. - The workspace in the memo exists.
- There is a price for the burn's block time (next section).
How a burn is priced#
The server samples the token's USD price every 5 minutes (Jupiter, with DexScreener as a fallback). For a burn at block time T, the price is the lowest of three numbers:
- the time-weighted average price from T − 15 min to T + 5 min,
- the first sample at or after T,
- the last sample at or before T.
USD value = tokens burned × that price. Credit is the USD value at the credit rate, which is 1.0 by default: one dollar of burned value buys one dollar of compute credit, rounded down to the micro-dollar. Pricing uses the burn's own block time, so verifying later changes nothing, and taking the lowest of three numbers means a short price spike can't be farmed. A burn with fewer than two samples in its window is rejected as too_old_for_price, unless it is under 10 minutes old; then the price is the lower of the latest sample and a live quote.
Verified once, credited once#
The transaction signature is the key. Verifying the same signature again returns the stored record with status already_credited. Two verifies racing each other still credit once. A single burn worth more than a per-burn cap is recorded with status review (HTTP 202) and credits nothing until a person checks it.
What credit is, and isn't#
Credit is
- Prepaid hosted compute, in USD
- Spent per token by the hosted gateway
- Tied to one workspace
- Never below zero
Credit is not
- Refundable or withdrawable
- Transferable to another workspace
- Backed by buybacks, yield or revenue share
- Needed to self-host. The CLI stays free and MIT
The full terms are on the terms page.
The public ledger#
Every verified burn is public on /burns and from GET /api/ledger: signature, wallet, amount, price, USD value, credit and block time. Workspace ids are left out. Every row can be checked on Solana with its signature.
API reference#
The hosted gateway and the burn endpoints. JSON in, JSON out. The gateway speaks the OpenAI Chat Completions format, so any OpenAI-compatible client works with a base URL change.
- Gateway base URL
https://forkbomb.fun/api/v1- Auth
Authorization: Bearer forkbomb_sk_…on/api/v1/*- Errors
- OpenAI shape:
{error:{message,type,code}} - Status
- Hosted pool: live. Burns open at token launch.
{ "error": { "message": "Insufficient credits: this request needs up to $<max cost> and the workspace has $<balance> remaining. Burn tokens to add credit.", "type": "billing_error", "code": "insufficient_credits" }}/api/v1/chat/completions#
Bearer keyOpenAI-compatible chat completions on Forkbomb's GPU model. This is what --engine hosted calls.
modelis ignored; responses sayforkbomb-hosted.messages,tools,tool_choice,temperature,stop,seed,response_formatand the other common fields pass through.max_tokensdefaults to 8,192 and is capped at 32,768. Body up to 4 MB, 2,048 messages.stream: trueworks, withstream_options.include_usage. A stream stops the GPU when you disconnect and bills only what was streamed.- Every answer carries
x-request-cost-usdandx-credits-remaining-usd(streams send them in a final comment line).
curl https://forkbomb.fun/api/v1/chat/completions \ -H "Authorization: Bearer $FORKBOMB_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"forkbomb-hosted","messages":[{"role":"user","content":"hello"}]}'| Code | HTTP | Meaning |
|---|---|---|
| invalid_api_key | 401 | Missing or unknown key. Send Authorization: Bearer <key>. |
| insufficient_credits | 402 | The request could cost more than the balance. Nothing is charged. |
| rate_limited | 429 | Per-workspace request limit. Wait for Retry-After. |
| upstream_unavailable | 503 | The GPU pool isn't provisioned (no Retry-After: don't retry) or is warming up (Retry-After set). Nothing is charged. |
| upstream_busy | 503 | The pool is at capacity. Retry after Retry-After. Nothing is charged. |
| upstream_error | 502 | The model failed or cut off. Nothing is charged. |
| invalid_* | 400 | Bad body: messages, tools, max_tokens, stream or JSON. |
/api/v1/me#
Bearer keyYour workspace, spendable balance and current pricing. forkbomb credits prints this.
{ "workspace": { "id": "ws_…", "label": "…", "createdAt": "…" }, "credits": { "balanceMicroUsd": <integer>, "balanceUsd": <number> }, "pricing": { "inputPerMTokUsd": <number>, "outputPerMTokUsd": <number>, "model": "…" }}balanceMicroUsd is the exact integer. The Usd numbers are for display.
/api/burns/verify#
Public, rate limitedVerify a burn by its signature and credit the workspace named in its memo. Idempotent.
// request{ "signature": "<base58 transaction signature>" } // 200 credited or already_credited · 202 held for review{ "burn": { "signature": "…", "workspaceId": "ws_…", "owner": "<wallet>", "mint": "…", "amountUi": "…", "priceUsd": "…", "usdValue": "…", "creditMicroUsd": <integer>, "slot": <integer>, "blockTime": "…", "verifiedAt": "…", "status": "credited" | "already_credited" | "review" }}| Code | HTTP | Meaning |
|---|---|---|
| invalid_signature | 400 | Not a base58 Solana transaction signature. |
| not_configured | 503 | The token has not launched yet. Burns open at launch. |
| not_found | 404 | No transaction with this signature on Solana mainnet. |
| not_finalized | 409 | Seen, but not finalized yet. Retry in about 30 seconds. |
| failed_tx | 422 | The transaction failed on chain. Nothing was burned. |
| no_burn | 422 | The transaction burns no token, or zero tokens. |
| wrong_mint | 422 | It burns a different token. |
| balance_mismatch | 422 | The burn amount doesn't match the token account's balance change. |
| bad_memo | 422 | No memo, more than one forkbomb: memo, or extra text in it. |
| unknown_workspace | 422 | The memo names a workspace that doesn't exist. |
| too_old_for_price | 422 | No price sample in the 30 minutes before the burn, or too few around it, to price it. |
| price_unavailable | 503 | No price right now. Retry in a few minutes. |
| rpc_error | 502 | The Solana RPC didn't answer. Retry shortly. |
| rate_limited | 429 | Too many verify calls from one address. Wait for Retry-After. |
/api/ledger#
PublicEvery verified burn, newest first, with totals. Workspace ids are left out.
UsageGET /api/ledger?limit=50&cursor=<nextCursor>
{ "burns": [ { "signature": "…", "owner": "<wallet>", "mint": "…", "decimals": <integer>, "amountUi": "…", "priceUsd": "…", "usdValue": "…", "creditMicroUsd": <integer>, "slot": <integer>, "blockTime": "…", "status": "credited" | "review" } ], "totals": { "burnedUi": "…", "burnedUsd": "…", "burns": <integer>, "creditedMicroUsd": <integer> }, "nextCursor": "…" | null}limit is 1 to 100, default 50. Amounts and prices are decimal strings, so nothing is lost to floating point.
/api/price#
PublicThe latest price sample and the 15-minute time-weighted average. All fields are null before launch.
{ "mint": "…" | null, "latest": { "ts": "…", "priceUsd": "…", "source": "jupiter" | "dexscreener" } | null, "twap": { "windowMinutes": 15, "priceUsd": "…", "samples": <integer> } | null}/api/workspaces#
Public, rate limitedCreate a workspace. The app calls this for you. The API key is in this response and nowhere else, ever.
// request (label optional, up to 64 characters){ "label": "my laptop" } // 201{ "workspace": { "id": "ws_…", "label": "my laptop", "createdAt": "…" }, "apiKey": "forkbomb_sk_…", "burnMemo": "forkbomb:ws_…" }Troubleshooting#
Each entry starts with the line the CLI prints. Values in angle brackets come from your run. Pre-rename builds print hydra: where these say forkbomb:.
Claude Code isn't logged in#
forkbomb: Claude Code isn't logged in. Run `claude auth login` with your Claude subscription, then try again.Run claude auth login and sign in with a Pro or Max plan. If claude isn't on your PATH at all, install Claude Code, point Forkbomb at it with --claude-bin, or use --engine api.
Isolation check failed#
forkbomb: isolation check failed, so no forks were started. See above.The canary got out somewhere, so Forkbomb refused to start any forks. The FAIL lines above the message name each check that broke. This usually follows a Claude Code update. Re-run forkbomb canary; if it still fails, open an issue with the output. Use --engine api in the meantime.
Not on APFS#
FAIL APFS copy-on-write clones (~/.forkbomb is not on APFS; forkbomb will fall back to plain copies)Forkbomb still runs, but forks are full copies: slower and much larger on disk. Keep ~/.forkbomb (or --runs-dir) on an APFS volume, and the repo on the same volume.
Tests already pass#
warn: The test suite already passes. Nothing for the heads to do.The baseline passed, so no forks were made. Check that --test runs the tests that describe the change you want. Write a failing test first, then start the race.
No fork passed#
warn: No head passed the whole suite. Best was <head> (<strategy>) at <score>%.Nobody exited 0. The best partial patch is saved as best.patch. Sharpen the task, add rounds with --rounds, add forks, or raise --max-turns and --fork-timeout if forks ran out of room.
No API key#
forkbomb: no API key. Set ANTHROPIC_API_KEY, or put ANTHROPIC_API_KEY=... in ~/.forkbomb/.env. Or use --engine claude-code to run on your Claude subscription.Only applies to --engine api. The default engine doesn't need a key.
No hosted key#
forkbomb: no hosted API key. Create a workspace at https://forkbomb.fun/app, then set FORKBOMB_API_KEY or put FORKBOMB_API_KEY=... in ~/.forkbomb/.env.Only applies to --engine hosted and forkbomb credits. The key is shown once when you create a workspace. If you lost it, create a new workspace.
Out of hosted credit#
forkbomb: no hosted credit left. Burn $FORKBOMB to top up at https://forkbomb.fun/appBurn $FORKBOMB with your workspace memo, wait for the verify to land, and check with forkbomb credits. Or switch to --engine api or --engine claude-code, which never need credit.
Hosted pool warming up#
forkbomb: the hosted pool is warming up or unreachable after 4 retries (upstream_unavailable: …). Try again shortly, or use --engine api or --engine claude-code.GPU workers shut down after a quiet spell, and the first request after that waits while one starts and loads the model. Nothing was charged. Retry in a minute, or use one of the other engines.
--network with Claude Code#
forkbomb: --network isn't supported with --engine claude-code yet.Forks on the claude-code engine have no network. Vendor or pre-install what they need, or use --engine api --network.
FAQ#
Is Forkbomb on npm?
Not yet. Build it from source as shown in Install. There is no published package under any name, so don't install one that claims to be Forkbomb.
Do I need the token to use it?
No. Self-hosting is free and MIT: the claude-code and api engines never touch a wallet or a chain. $FORKBOMB only buys credit for the optional hosted engine.
Does it need API credits?
No. The default engine runs forks on your Claude Code login, so a Pro or Max plan works. Forks count against the plan's usage limits, and N forks use them roughly N times as fast as one session.
Does it run on Linux or Windows?
No. Copy-on-write forking needs APFS and the sandbox is macOS Seatbelt. Off macOS the CLI refuses to start unless you pass --no-sandbox, which removes isolation entirely. Don't.
Does Forkbomb send my code anywhere?
With claude-code or api, forks send what any Claude session sends to Anthropic, and nothing reaches us. With hosted, the model's prompts go through the Forkbomb gateway to the GPU that runs the model; we don't store prompts or completions. There is no telemetry either way. The live view and replay bind to 127.0.0.1, and runs stay in ~/.forkbomb.
Can a fork game the tests?
The judge is built against the common ways: test edits are dropped, the patch is applied to a fresh clone, ignored files don't carry over, and runs where tests went missing don't count as a pass. It isn't proof against everything and is still being hardened. Read the patch before you ship it.
How many forks should I run?
The default is 8. There are twelve strategies, so past twelve forks they repeat. More forks cost more plan usage, API spend or credit; the speed of forking isn't the limit.
Does it work with Python, Go or Rust?
Nothing in Forkbomb is tied to JavaScript. The forks edit files and the judge runs your command. It reads counts from pytest, unittest, go test and cargo test, and falls back to the exit code for anything else.
Is it affiliated with Anthropic?
No. Forkbomb is an independent open-source project. It drives Claude Code and the Anthropic API on your own account; it isn't made or endorsed by Anthropic.