fork() for AI agents — snapshot, branch, and merge live agent state.
Project description
ProcessFork
git for AI agents. Snapshot, fork, and merge live LLM sessions in 8 ms.
↑ Replay it locally: asciinema play demo/processfork-demo.cast
Why
You're 4 hours into a refactor with Claude Code. The agent has read 200 files, run 47 tests, opened a database, started a dev server. Then it suggests a destructive change.
Today: lose everything, undo by hand, or restart.
With ProcessFork: pf snapshot → 8 ms → safe. Try 12 alternatives in parallel, merge the winner back, ship the whole session to a teammate.
It's git — snapshot, branch, merge, push, clone — but for live AI agent state.
Highlights
- ⚡ 8 ms snapshots. Full agent state — model + KV-cache + files + tools + reasoning — into one content-addressed
.pfimg. - 🌳 Real fork & merge. 12 parallel attempts share storage automatically (CoW). Merge the winner with a real 3-way diff (files, tools, trace) — git-style
<<<<<<<markers and all. - 🔒 Won't double-send your email. HMAC-chained tool-call ledger; restored agents see prior side-effects as facts, not as actions to re-issue. (ACRFence-resistant.)
- 🤝 Drop-in for Claude Code, LangGraph, OpenInterpreter, vLLM, SGLang, AutoGen, CrewAI.
- 📦 Single binary, MIT, Rust core, Python + TypeScript SDKs. 200+ tests.
Quick start (60 seconds)
# install the CLI:
cargo install processfork # → `pf` on your $PATH
# snapshot a directory:
mkdir /tmp/sandbox && echo "fn main() {}" > /tmp/sandbox/main.rs
pf snapshot --agent-id demo --fs-root /tmp/sandbox
# → sha256:1c2497b0… ⏱ 8 ms
# edit something, snapshot again, see the diff:
echo "fn main() { println!(\"hi\") }" > /tmp/sandbox/main.rs
pf snapshot --agent-id demo --fs-root /tmp/sandbox --name v2
pf log
pf diff <first-cid> <second-cid>
Prefer Python? pip install processfork. TypeScript? npm install @processfork/sdk.
The full 60-second demo (snapshot → fork ×12 → merge → push → clone on a fresh store) is bash demo/script.sh. Runs end-to-end on a laptop. No GPU, no API keys.
When you'd reach for it
| Situation | Command |
|---|---|
| Agent about to do something destructive | pf snapshot pre-rm-rf |
| Stuck — want to try 12 approaches in parallel | pf fork -n 12 --explore "fix bug" |
| Hand a complex session to a teammate | pf push hf://you/session-name |
| Time-travel debug ("when did it go wrong?") | pf log then pf checkout <CID> |
| RL rollout fabric for agent training | snapshot, fan out, score, merge |
Use it with your stack
| Adapter | Status | What it gives you |
|---|---|---|
| Claude Code | ✅ ships v1.0 | /snapshot, /fork, /merge slash-commands inside any session |
| LangGraph | ✅ ships v1.0 | drop-in BaseCheckpointSaver over the FS+env+trace+effects layers |
| OpenInterpreter | ✅ ships v1.0 | interpreter.snapshot("pre-rm-rf") then .checkout("pre-rm-rf") |
| AutoGen | ✅ ships v1.0 | atomic FS+env+trace+effects snapshot across an agent group |
| CrewAI | ✅ ships v1.0 | CrewMemory drop-in; every step time-travelable |
| vLLM | 🟡 mock ships v1.0 · live = Modal lane | mock: K/V page bytes + manifest persist & restore via the SDK; live (Modal A10G): V0 engine bit-exact, V1 engine output-equivalent (see "What does/doesn't ship" below) |
| SGLang | 🟡 mock ships v1.0 · live = Modal lane | mock: RadixCache k_buffer/v_buffer page round-trip; live: scaffolded — Modal lane reaches the parity stub but full radix-tree replay is v1.1 |
How it works
ProcessFork captures the five things that together make up a live agent — atomically — into one content-addressed file. Each layer ships at a different maturity level in v1.0.x:
| Layer | What it captures | v1.0.x status |
|---|---|---|
| World | Filesystem (full), env (default-redacted), browser DOM (CDP). In-flight subprocesses captured via pf snapshot --criu-pid <PID> (Linux + criu CLI; v1.0.12). Without --criu-pid, the procs blob is a procs.unsupported.v1 placeholder. |
✅ FS + env ship; 🟡 procs ships on Linux+CRIU (see adapters/pf-criu/) |
| Effects | Append-only ledger of tool calls, HMAC-chained per entry (ACRFence). | ✅ ships (CLI + Python SDK + TS SDK + 5 adapters) |
| Trace | Chat + tool-call message log | ✅ ships |
| Model | LoRA / IA³ / full-finetune weight diffs, in-place TTT updates. The format and TIES+DARE merge math ship and are exercised on the Modal A10G lane; the generic CLI snapshot path produces an empty LoRA envelope because the layer is populated by adapters (vLLM/SGLang/etc.), not by walking a directory. | 🟡 format ships; CLI path is placeholder; adapter-populated |
| Cache | Paged KV-cache, content-addressed per page (CoW across forks). Same shape: format + page math ship; the generic CLI snapshot produces an empty page manifest; the vLLM/SGLang adapters populate it for real. | 🟡 format ships; CLI path is placeholder; adapter-populated |
Identical content shares storage automatically — 12 parallel forks use ~1.004× the space of one in the operator's matrix run, well under the < 1.5× budget. The merge engine handles each layer with the right algorithm: git-style 3-way diff for files (conflict markers materialize; resolution UI is v1.1), TIES + DARE for model weights, the HMAC effects chain that defends against semantic-rollback attacks (ACRFence), and an LLM-summarized "what branch B learned" patch injected into branch A's reasoning trace without re-prefilling the cache.
What does and doesn't ship in v1.0.x
Production-credible today (independent retest, 12/12 matrix passing):
pf snapshot/pf checkoutfor filesystem sandboxes, with default secret-shaped env redaction.- HMAC-chained effects ledger end-to-end (CLI + Python + TS), tamper detected by
pf verify. - Fork & merge: 12 forks at ~1.004× storage; clean and conflicting merges produce content-addressed merged CIDs with Git-style markers in conflict files.
- File:// (and OCI / S3 / HF) registry transport.
- 5 adapters (Claude Code, LangGraph, OpenInterpreter, AutoGen, CrewAI) over the FS + env + trace + effects layers.
- vLLM/SGLang mock mode: K/V page bytes + manifest persist into the store and read back on checkout.
Tractable today (v1.0.12 closed three of these from v1.0.11):
- Live in-flight subprocess capture ✅ via
processfork-criu(Linux +criuCLI required).pf snapshot --criu-pid <PID>writes a realprocs.criu.v1bundle (CRIU images tarball + JSON header). On macOS / Windows / non-criu Linux, the command exits with a clear "CRIU unavailable" message — no silent half-state. Validation runs on the operator's Linux box; the format + gating + non-Linux skip path is unit-tested everywhere. Seeadapters/pf-criu/README.mdfor the full caveat list (this lane has the same shape as the Modal vLLM lane: code ships, validation lives on a host the upstream CI doesn't have). - Conflict-merge resolution UI ✅ via
pf merge-resolve/pf merge-finalize. Whenpf mergeproduces conflicts, drop the merged FS into a workdir, hand-edit the marker files, then finalize into a single-parent image. The finalize step refuses to ship as long as files still contain<<<<<<<(override with--force). Round-trip regression-tested on macOS. - Loud warning on empty engine layers ✅. The generic CLI snapshot now emits a multi-line stderr warning that model + cache are placeholders and only the FS+env+trace+effects layers were captured. Suppress with
--allow-empty-engine-layersonce your CI has internalized the boundary.
Not yet production-ready, though the format and code paths exist:
- Local PF_HAS_GPU=1 vLLM/SGLang test (
examples/06,examples/07,pf-cache/tests/cache_bit_exact_vllm.rs). These exit 2 with a "use the adapter packages directly + Modal lane" pointer — they were operator-runs-it skeletons that never got a self-contained subprocess flow. The Modal A10G lane (scripts/gpu-validate-modal.py) does run vLLM end-to-end and emits the JSONs inbenchmarks/gpu-validation/. - Bit-exact KV-cache restore on vLLM V1 engine. The Modal lane shows V0 engine
bit_exact: truefor 38 619 KV pages but V1 engine = output-equivalent (first-80-chars match), not bit-exact, on TinyLlama-1.1B. V1'scollective_rpcworker scheduling has internal non-determinism that ProcessFork cannot eliminate from the outside. Workaround for bit-exact replay today: pin to vLLM V0 engine + passenforce_eager=Trueto disable CUDA graphs, e.g.LLM(..., enforce_eager=True)orvllm serve ... --enforce-eager. The V1 path stays output-equivalent until upstream lands deterministic batch scheduling — seeadapters/pf-vllm/README.mdfor the full workaround note. - Generic CLI model/cache layer capture. The generic
pf snapshotproduces empty model + cache envelopes — these layers are populated through adapters (vLLM/SGLang/etc.), not by walking a directory. If you want the model+cache layers populated, use the vLLM or SGLang adapter from inside your engine process. The empty path now warns loudly by default.
→ Architecture deep-dive · Three-way merge protocol · Engineering specs
Status
v1.0.12 tagged. Closes three of the four "not-yet-production-ready" items v1.0.11 made explicit. Conflict-merge resolution UI ships as pf merge-resolve + pf merge-finalize — round-trip regression-tested on macOS. Live in-flight subprocess capture ships as the new processfork-criu adapter + pf snapshot --criu-pid <PID> flag (Linux + criu CLI required; format/gating tested everywhere; live criu dump/criu restore validation runs on the operator's Linux box, same shape as the Modal vLLM lane). Empty engine layers now emit a multi-line stderr warning by default (suppress with --allow-empty-engine-layers); the empty model+cache envelopes carry a note: generic-cli-empty field so downstream tooling can detect them. The fourth item — V1-engine bit-exact KV restore — is a vLLM-side change beyond ProcessFork's reach; the V0 + enforce_eager=True workaround is now documented in adapters/pf-vllm/README.md for callers who need byte-identical replay today. cargo deny check: still advisories ok, bans ok, licenses ok, sources ok.
| metric | observed | target |
|---|---|---|
| Snapshot p50, synthetic 4-layer fixture (macOS arm64) | 7.9 ms | < 500 ms p99 |
| Snapshot p50, real GPU host (Modal A10G, 64 × 4 KiB) | 42 ms (warm) | < 500 ms p99 |
| KV-cache restore, vLLM V0 engine + TinyLlama-1.1B on A10G | bit_exact: true — 38 619 KV pages, regenerated text byte-identical (JSON) |
out_a == out_b byte-equal |
KV-cache restore, vLLM V1 engine (collective_rpc) |
output-equivalent, not bit-exact — first-80-chars match across snapshot/restore on 38 599 KV pages (JSON); bit_exact: false field is the source of truth |
out_a == out_b byte-equal (target unmet on V1) |
| Cache capture, 64 pages | 531 µs | — |
| 12-fork ÷ 1-fork storage ratio (auditor's matrix) | 1.004× | ≤ 1.5× |
| Total Rust tests passing | 204 (incl. v1.0.12 merge-resolve/finalize + criu-pid macOS gate) | — |
| Python SDK + Claude + CRIU adapter tests | 25 passed, 2 skipped (CRIU Linux-only paths) | — |
| TS SDK smoke tests | 8 (incl. 3 v1.0.10 regressions) | — |
Synthetic-fixture numbers come from cargo bench --workspace. GPU numbers come from modal run scripts/gpu-validate-modal.py; raw JSON lives in benchmarks/gpu-validation/ and the breakdown in benchmarks/RESULTS.md. The local PF_HAS_GPU=1 paths in examples/06 and examples/07 are not the validation path — they exit 2 with a Modal-lane pointer; the validation IS the Modal lane, and the JSONs above are its output.
Install
cargo install processfork # Rust CLI (the `pf` binary)
pip install processfork # Python SDK
npm install @processfork/sdk # TypeScript SDK
Per-adapter packages (one each on PyPI):
pip install processfork-claude-code
pip install processfork-langgraph
pip install processfork-openinterpreter
pip install "processfork-vllm[vllm]" # needs CUDA + vllm ≥ 0.10
pip install "processfork-sglang[sglang]" # needs CUDA + sglang ≥ 0.5
pip install "processfork-autogen[autogen]"
pip install "processfork-crewai[crewai]"
pip install processfork-criu # Linux only; needs `criu` CLI on $PATH
Build from source if you want to hack on it:
git clone https://github.com/manav8498/processfork && cd processfork
cargo build --release -p processfork # → target/release/pf
Full build-from-source instructions in docs/install.md. Pre-built wheels cover macOS arm64, Linux x86_64, and Linux aarch64; macOS Intel + Windows wheels arrive in v1.0.1 (operator: same package, just more platforms).
Repo layout
crates/ Rust workspace (10 crates: pf-core, pf-cache, pf-world, pf-effects,
pf-model, pf-merge, pf-registry, processfork (CLI, the `pf` binary), pf-py, pf-ts)
adapters/ 7 first-party integration packages
benchmarks/ PFBench harness + Criterion microbench
docs/ mdBook source (25+ pages)
examples/ 8 self-contained runnable examples
demo/ 60-second demo recording script
Docs
Your first fork (5 min) · 60-second demo · Architecture · Merge protocol · Security model · Performance tuning · Engineering specs
Contributing
PRs welcome. The bar is cargo fmt, cargo clippy --all-targets -- -D warnings, cargo test --workspace, plus a green coverage delta. See CONTRIBUTING.md.
License
MIT.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file processfork-1.0.12-cp39-abi3-win_amd64.whl.
File metadata
- Download URL: processfork-1.0.12-cp39-abi3-win_amd64.whl
- Upload date:
- Size: 1.4 MB
- Tags: CPython 3.9+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
52cc987e8ca4ba2698af85b25f7e732d60d108821042317957c08cc36b3f77f7
|
|
| MD5 |
dec1e698ac8eb1c98edb97bb90263177
|
|
| BLAKE2b-256 |
9df9b3f1b866672738cea9afede810e5e6f2173e89ce3f2a5ad0b03d9425d6ad
|
Provenance
The following attestation bundles were made for processfork-1.0.12-cp39-abi3-win_amd64.whl:
Publisher:
release.yml on manav8498/processfork
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
processfork-1.0.12-cp39-abi3-win_amd64.whl -
Subject digest:
52cc987e8ca4ba2698af85b25f7e732d60d108821042317957c08cc36b3f77f7 - Sigstore transparency entry: 1467493454
- Sigstore integration time:
-
Permalink:
manav8498/processfork@9cdf094fd30c10be6458bbad48a0ee414ffd54a2 -
Branch / Tag:
refs/tags/v1.0.12 - Owner: https://github.com/manav8498
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9cdf094fd30c10be6458bbad48a0ee414ffd54a2 -
Trigger Event:
push
-
Statement type:
File details
Details for the file processfork-1.0.12-cp39-abi3-manylinux_2_28_x86_64.whl.
File metadata
- Download URL: processfork-1.0.12-cp39-abi3-manylinux_2_28_x86_64.whl
- Upload date:
- Size: 1.6 MB
- Tags: CPython 3.9+, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
77897fc56e5540d594d96cfff35ffa78e8f63692bc3613e80149ceeaf37ec189
|
|
| MD5 |
5076de3adaabc785b1dd7195d3202482
|
|
| BLAKE2b-256 |
611d2a4288980703b425d7ebc6f0be3af9bd10a5a77748342586319dd5c8a4e6
|
Provenance
The following attestation bundles were made for processfork-1.0.12-cp39-abi3-manylinux_2_28_x86_64.whl:
Publisher:
release.yml on manav8498/processfork
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
processfork-1.0.12-cp39-abi3-manylinux_2_28_x86_64.whl -
Subject digest:
77897fc56e5540d594d96cfff35ffa78e8f63692bc3613e80149ceeaf37ec189 - Sigstore transparency entry: 1467492636
- Sigstore integration time:
-
Permalink:
manav8498/processfork@9cdf094fd30c10be6458bbad48a0ee414ffd54a2 -
Branch / Tag:
refs/tags/v1.0.12 - Owner: https://github.com/manav8498
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9cdf094fd30c10be6458bbad48a0ee414ffd54a2 -
Trigger Event:
push
-
Statement type:
File details
Details for the file processfork-1.0.12-cp39-abi3-manylinux_2_28_aarch64.whl.
File metadata
- Download URL: processfork-1.0.12-cp39-abi3-manylinux_2_28_aarch64.whl
- Upload date:
- Size: 1.5 MB
- Tags: CPython 3.9+, manylinux: glibc 2.28+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
50fef1b19926a0c9ac75655cea69c85138a06218b4f87c65f50984333cdbecef
|
|
| MD5 |
c227ccd9c31d5ec1dd38d8e0d9436169
|
|
| BLAKE2b-256 |
b7186928304cb2b9997e950ee984314f5850aef22a46bab802db6245a16c4e99
|
Provenance
The following attestation bundles were made for processfork-1.0.12-cp39-abi3-manylinux_2_28_aarch64.whl:
Publisher:
release.yml on manav8498/processfork
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
processfork-1.0.12-cp39-abi3-manylinux_2_28_aarch64.whl -
Subject digest:
50fef1b19926a0c9ac75655cea69c85138a06218b4f87c65f50984333cdbecef - Sigstore transparency entry: 1467493794
- Sigstore integration time:
-
Permalink:
manav8498/processfork@9cdf094fd30c10be6458bbad48a0ee414ffd54a2 -
Branch / Tag:
refs/tags/v1.0.12 - Owner: https://github.com/manav8498
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9cdf094fd30c10be6458bbad48a0ee414ffd54a2 -
Trigger Event:
push
-
Statement type:
File details
Details for the file processfork-1.0.12-cp39-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: processfork-1.0.12-cp39-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.3 MB
- Tags: CPython 3.9+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1f1764f59d2dae091c869e5c917683847359d6cbdae40a209dbf4e8ef65b83a7
|
|
| MD5 |
e2f6e18b4c46083c9049ab8df2dc3e45
|
|
| BLAKE2b-256 |
3da88a6fc4ac2ab7c68b6ed73b847d68268e11f729f5e887a094f67831c1e0f7
|
Provenance
The following attestation bundles were made for processfork-1.0.12-cp39-abi3-macosx_11_0_arm64.whl:
Publisher:
release.yml on manav8498/processfork
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
processfork-1.0.12-cp39-abi3-macosx_11_0_arm64.whl -
Subject digest:
1f1764f59d2dae091c869e5c917683847359d6cbdae40a209dbf4e8ef65b83a7 - Sigstore transparency entry: 1467492863
- Sigstore integration time:
-
Permalink:
manav8498/processfork@9cdf094fd30c10be6458bbad48a0ee414ffd54a2 -
Branch / Tag:
refs/tags/v1.0.12 - Owner: https://github.com/manav8498
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9cdf094fd30c10be6458bbad48a0ee414ffd54a2 -
Trigger Event:
push
-
Statement type:
File details
Details for the file processfork-1.0.12-cp39-abi3-macosx_10_12_x86_64.whl.
File metadata
- Download URL: processfork-1.0.12-cp39-abi3-macosx_10_12_x86_64.whl
- Upload date:
- Size: 1.5 MB
- Tags: CPython 3.9+, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
767c818b17de3e83440186a650eb1fb500e6d5ee582230563ab132d3d00246c5
|
|
| MD5 |
4ca5a949f433c85a32decf39e4c5a42a
|
|
| BLAKE2b-256 |
7dd575254ad5fada909c4cdffa9a2013aa1d1b19a3a926854132e0dc8a076270
|
Provenance
The following attestation bundles were made for processfork-1.0.12-cp39-abi3-macosx_10_12_x86_64.whl:
Publisher:
release.yml on manav8498/processfork
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
processfork-1.0.12-cp39-abi3-macosx_10_12_x86_64.whl -
Subject digest:
767c818b17de3e83440186a650eb1fb500e6d5ee582230563ab132d3d00246c5 - Sigstore transparency entry: 1467493100
- Sigstore integration time:
-
Permalink:
manav8498/processfork@9cdf094fd30c10be6458bbad48a0ee414ffd54a2 -
Branch / Tag:
refs/tags/v1.0.12 - Owner: https://github.com/manav8498
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9cdf094fd30c10be6458bbad48a0ee414ffd54a2 -
Trigger Event:
push
-
Statement type: