The "why not just parallel-prompt the LLM 3 times?" rebuttal demo.
A small coding agent inside the source sandbox builds a Python
package, runs a failing test (populating __pycache__/), and
writes a 50 MiB synthetic "vendored.bin" representing things a
real agent accumulates (pip caches, downloaded weights, compiled
extensions). We forkd branch the source. Three grandchildren
each apply a different fix strategy. The state evidence shows:
- The 50 MiB
vendored.binis byte-identical across all 4 agents (md5 verified). - The
__pycache__/directory is byte-identical at the moment of branch — after each child re-imports, its own__pycache__/diverges (because the source file changed). - Each child's
mathy/__init__.pyafter applying its strategy is different — minimal sed, full rewrite, skip-the-tests. - Test outcomes diverge: the first two strategies actually fix the bug; the "skip" strategy backfires when one of the expected-failure tests accidentally passes.
This is the filesystem analog of the langgraph-react demo's conversation-history fork. Same primitive; different state.
To run 3 "fix attempts" via API-only parallelism, each request
would have to carry the entire /workspace directory — files,
binary cache, populated __pycache__/. That's:
- 50 MiB synthetic vendored data
- Several KiB of compiled
.pycbytecode - ~20 source files of various sizes
Not just wasteful (3× the bytes uploaded). Technically impossible above ~50 KiB on most LLM APIs. And the LLM doesn't even understand binary blobs.
forkd's BRANCH primitive sidesteps this entirely: the children inherit the source's address space copy-on-write. The 50 MiB appears in each child the moment they're spawned, no transfer needed.
Prereqs: a running forkd-controller daemon, the langgraph
snapshot tag (or any python3-capable tag — setup-source.sh
only needs stdlib).
export FORKD_URL=http://127.0.0.1:8889
export FORKD_TOKEN=$(cat /etc/forkd/token)
bash recipes/coding-agent-fork/demo.shArtifacts land in recipes/coding-agent-fork/results/<unix-ts>/:
summary.md— per-agent state evidence + divergent codesummary.json— machine-readablebranch.json— daemon's BRANCH response with pause_msstate-evidence.txt— raw md5s{source,minimal,rewrite,skip}-init-py.txt— each agent'smathy/__init__.pyafter their strategy ran{source,minimal,rewrite,skip}-agent.log— full per-agent shell log incl. unittest output
A real run (2026-05-19, 3.3 s pause) is committed under
results-2026-05-19/ — see
results-2026-05-19/summary.md
for the divergent code + test outcomes.
| Strategy | What it does | Test outcome |
|---|---|---|
minimal.sh |
One-line sed to flip a - b → a + b |
✅ passed |
rewrite.sh |
Full function rewrite with type-checks | ✅ passed |
skip.sh |
Decorate tests with @unittest.expectedFailure |
❌ failed (one test unexpectedly passed and broke the contract) |
The pedagogical bonus: the lazy skip strategy backfires because
test_add_zero (0 - 0 == 0) accidentally passes despite the bug —
unittest flags this as an "unexpected success" and fails the suite.
This is the kind of thing only branch-and-compare reveals.
/tmp is mounted as tmpfs inside the guest by
rootfs-init/forkd-init.sh —
each VM has its own per-instance RAM-backed /tmp. BRANCH captures
this in memory.bin. Children inherit byte-identical tmpfs
contents on restore.
Using /workspace on the rootfs ext4 would NOT work: the rootfs
file is shared (loop-mounted) across all sandboxes from the same
snapshot. Three children writing concurrently to the same on-disk
inode would corrupt the journal.
If you're writing your own forkd recipe and need writable shared
state across forks, always put it under /tmp.
- The 50 MiB blob is synthetic. A real "coding agent" might have
GiB of state (pip's
site-packages/, downloaded model weights, vendored sources). forkd's pause window scales roughly with memory image size (seebench/pause-window/RESULTS-v0.2.md); testing with realistic blob sizes is on the v0.3 roadmap. - This demo uses shell scripts as the "agent". A real coding agent calls an LLM. The langgraph-react recipe shows the LLM path; this one shows the filesystem-state path. Both primitives compose.