[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-76089":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":18,"stars30d":19,"stars90d":16,"forks30d":16,"starsTrendScore":20,"compositeScore":21,"rankGlobal":10,"rankLanguage":10,"license":22,"archived":23,"fork":23,"defaultBranch":24,"hasWiki":25,"hasPages":23,"topics":26,"createdAt":10,"pushedAt":10,"updatedAt":34,"readmeContent":35,"aiSummary":36,"trendingCount":16,"starSnapshotCount":16,"syncStatus":37,"lastSyncTime":38,"discoverSource":39},76089,"forkd","deeplethe\u002Fforkd","deeplethe","Fork() for AI agent microVMs. Spawn 100 children in ~100ms from a warm parent; BRANCH a live VM in ~150ms. KVM-isolated, snapshot CoW.","",null,"Rust",2062,158,35,6,0,97,746,1713,357,28.6,"Apache License 2.0",false,"main",true,[27,28,29,30,31,32,33],"ai-agents","copy-on-write","kvm","microvm","rust","sandbox","snapshot","2026-06-12 02:03:39","\u003Cbr\u002F>\n\n\u003Cdiv align=\"center\">\n  \u003Cpicture>\n    \u003Csource media=\"(prefers-color-scheme: dark)\" srcset=\"docs\u002Flogo-dark.svg\">\n    \u003Cimg alt=\"forkd\" src=\"docs\u002Flogo.svg\" width=\"220\">\n  \u003C\u002Fpicture>\n\u003C\u002Fdiv>\n\n\u003Cbr\u002F>\n\u003Cbr\u002F>\n\n\u003Cp align=\"center\">\n  \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fdeeplethe\u002Fforkd\u002Factions\">\u003Cimg alt=\"CI\" src=\"https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Factions\u002Fworkflow\u002Fstatus\u002Fdeeplethe\u002Fforkd\u002Fci.yml?branch=main&style=flat-square&label=ci\">\u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fdeeplethe\u002Fforkd\u002Freleases\">\u003Cimg alt=\"Release\" src=\"https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Fv\u002Frelease\u002Fdeeplethe\u002Fforkd?style=flat-square&color=4c956c\">\u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fpypi.org\u002Fproject\u002Fforkd\u002F\">\u003Cimg alt=\"PyPI\" src=\"https:\u002F\u002Fimg.shields.io\u002Fpypi\u002Fv\u002Fforkd?style=flat-square&color=3776ab&logo=pypi&logoColor=white\">\u003C\u002Fa>\n  \u003Ca href=\".\u002FLICENSE\">\u003Cimg alt=\"License\" src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flicense-Apache--2.0-blue?style=flat-square\">\u003C\u002Fa>\n  \u003Ca href=\".\u002FREADME-zh.md\">\u003Cimg alt=\"中文 README\" src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FREADME-%E4%B8%AD%E6%96%87-red?style=flat-square\">\u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fdeeplethe\u002Fforkd\u002Fstargazers\">\u003Cimg alt=\"Stars\" src=\"https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Fstars\u002Fdeeplethe\u002Fforkd?style=flat-square&color=eab308&logo=github\">\u003C\u002Fa>\n\u003C\u002Fp>\n\n\u003Cbr\u002F>\n\n## Fork 100 microVMs in 101 ms.\n\nA microVM sandbox runtime for **AI agent fan-out**. Children fork\nfrom a warmed parent snapshot, inheriting its address space\ncopy-on-write instead of cold-booting their own kernel.\n\nforkd is built on Firecracker. The parent VM boots once, imports\nyour runtime (Python + your dependencies, a JIT-warmed JVM, an\nalready-loaded ML model) and is paused to disk. Each child is a\nseparate Firecracker process that `mmap`s the parent's memory image\nwith `MAP_PRIVATE`; the kernel implements copy-on-write at the page\nlevel, so children share the parent's resident memory until they\ndiverge.\n\nThe result is two properties at once: per-child KVM isolation, and a\nspawn cost that's closer to `fork(2)` than to a cold-boot VM.\n\n\u003Cbr\u002F>\n\n## Demo: branch a thinking agent\n\nA 24-second walkthrough of the LangGraph branch-and-fan-out demo —\nsource agent runs a ReAct loop, gets BRANCHed mid-thought, three\ngrandchildren each receive a different steering hint, all three\nproduce divergent itineraries while inheriting the same prior\nreasoning state.\n\n![forkd branch-and-fan-out demo](.\u002Fdocs\u002Fassets\u002Fdemo-en.gif)\n\nHeadline divergence: the source (no hint) picks Nishiki Market for\nDay 1; all three hinted children independently substitute Arashiyama\nBamboo Grove. The cost-focused child also adds \"may be pricey\"\nannotations the others don't. **The model wasn't told to swap places**\n— each hint perturbed the next LLM call, the rest of the prior\nreasoning came along unchanged.\n\nFull mechanism + numbers + raw transcripts in\n[`recipes\u002Flanggraph-react\u002F`](.\u002Frecipes\u002Flanggraph-react\u002F) and\n[`recipes\u002Flanggraph-react\u002FDEMO.md`](.\u002Frecipes\u002Flanggraph-react\u002FDEMO.md).\n\n### And: filesystem state, not just reasoning\n\nFor the \"but couldn't you just call the LLM 3 times in parallel?\"\nobjection, see [`recipes\u002Fcoding-agent-fork\u002F`](.\u002Frecipes\u002Fcoding-agent-fork\u002F) —\na 50 MiB binary blob travels byte-identically across all 4 sandboxes\nthrough a single BRANCH. Three grandchildren each apply a different\nfix to a buggy Python package; their `__pycache__\u002F` and edits stay\nisolated, but the 50 MiB inheritance is shared. Bytes can't fit in\na prompt. **3.3 s pause for the BRANCH operation.**\n\n\u003Cbr\u002F>\n\n## Properties\n\n- **Hardware isolation.** Each child is its own Firecracker microVM\n  backed by KVM. Escape requires a hypervisor or kernel vulnerability,\n  not a `runc` regression.\n- **Warmed runtimes inherit for free.** Imports, JIT compilation, model\n  weights, prefetched caches — anything the parent did is already\n  resident in the child.\n- **Real Linux per child.** Multi-vCPU, full TCP networking, `apt\n  install`, outbound HTTPS. Unlike function-level snapshot runtimes\n  that trade single-vCPU + serial-I\u002FO for raw spawn speed, forkd\n  children can run real Python servers, model inference, or any\n  workload that needs a full kernel.\n- **Multi-tenant by construction.** Per-child network namespace, per-\n  child cgroup v2 memory limit, independent `\u002Fdev\u002Furandom` re-seeded\n  by `vmgenid` (Linux 5.20+).\n- **Built for agent fan-out.** AI agent workloads that fan out into\n  many short-lived sandboxes — code-interpreter, tool-use, evaluation\n  rollouts — are the design point. The warmed parent collapses the\n  per-request `import numpy` \u002F `import torch` cost across the entire\n  cohort.\n- **Operable.** Daemon process owning state, REST API on Unix or TCP,\n  Prometheus `\u002Fmetrics`, append-only JSON audit log, systemd unit.\n- **Open source.** Apache 2.0, no vendor SDK.\n\n\u003Cbr\u002F>\n\n## Benchmarks\n\nSame Linux host (Ubuntu 24.04, Linux 6.14, 20 vCPU, 30 GiB, KVM).\nWorkload: spawn 100 sandboxes that each run `import numpy;\nnumpy.zeros(5).tolist()`.\n\n![Spawn time at N=100](.\u002Fbench\u002Fchart-spawn-100.png)\n\n![Host memory per sandbox](.\u002Fbench\u002Fchart-memory-per.png)\n\n| Backend | Wall-clock at N=100 | Memory delta per sandbox | Notes |\n|---|---:|---:|---|\n| **forkd** | **101 ms** | **0.12 MiB** | fork-from-warm via snapshot CoW |\n| CubeSandbox¹ | 1.06 s | 5 MiB | RustVMM microVM, cold-boot (pool fast path) |\n| BoxLite² | 113.2 s | — | KVM microVM, cold-boot OCI rootfs |\n| OpenSandbox³ | 122.0 s | — | Docker runtime via abstraction layer |\n| Firecracker cold-boot | 759 ms | 84 MiB | raw VM boot, no orchestration |\n| gVisor (runsc) | 288.6 s | — | userspace kernel container |\n| Docker (runc) | 335.3 s | 4 MiB | standard container runtime |\n\n¹ CubeSandbox: 1.06 s wall-clock is the **fast-path** N=100 figure on\nthis host (1056 ± 14 ms over five runs, 100 % success every run),\nmeasured with a bench script that pre-warms Python's\n`ThreadPoolExecutor` to keep client-side lazy-init out of the\ntiming. An earlier slow-path measurement on the same host returned\n20.3 s with 77\u002F100 success — that template had a 2 GiB\nwritable-layer size that didn't match the default 1 GiB pool, so\nevery sandbox went through a live `mkfs.ext4 + reflink-copy`; after\nthe upstream maintainer at\n[#235](https:\u002F\u002Fgithub.com\u002FTencentCloud\u002FCubeSandbox\u002Fissues\u002F235)\nclarified the distinction, we added `2Gi` to\n`pool_default_format_size_list` and re-ran. The host runs cube\n**v0.2.0**, which carries a ~50 ms latency regression that\n[PR #234](https:\u002F\u002Fgithub.com\u002FTencentCloud\u002FCubeSandbox\u002Fpull\u002F234)\nfixes in v0.2.1; the value above is the v0.2.0 baseline. Cube\nadvertises **\u003C60 ms** single-instance cold-start on a 96 vCPU\nhost; we did not retest that shape. See\n[`bench\u002FCUBESANDBOX.md`](.\u002Fbench\u002FCUBESANDBOX.md) for the full\nmethodology, both rows, and the `cmdTimeout` race we filed two PRs\nupstream against\n([#236](https:\u002F\u002Fgithub.com\u002FTencentCloud\u002FCubeSandbox\u002Fpull\u002F236) \u002F\n[#237](https:\u002F\u002Fgithub.com\u002FTencentCloud\u002FCubeSandbox\u002Fpull\u002F237)).\n\n² BoxLite is optimised for one long-lived stateful Box per workload,\nnot 100 concurrent fresh microVMs. The cold fan-out is included for\ndirect comparability. See [`bench\u002FBOXLITE.md`](.\u002Fbench\u002FBOXLITE.md).\n\n³ OpenSandbox is an abstraction layer over Docker \u002F K8s \u002F gVisor \u002F\nKata \u002F Firecracker; the number is for its default Docker runtime.\nSee [`bench\u002FOPENSANDBOX.md`](.\u002Fbench\u002FOPENSANDBOX.md).\n\nReproduce: `bench\u002Fbench-spawn-100.sh` then `bench\u002Fgenerate_charts.py`.\n\nFor one sandbox doing the same numpy expression two ways:\n\n| Call | Time | What it does |\n|---|---:|---|\n| `sandbox.eval(\"numpy.zeros(5).tolist()\")` | 1 ms | Reuses the warmed Python in PID 1 |\n| `sandbox.commands.run(\"python3 -c '...'\")` | 96 ms | Cold subprocess re-imports numpy |\n\n\u003Cbr\u002F>\n\n## How it works\n\n```mermaid\nflowchart TB\n    %% ─── parent ───────────────────────────────────────────────\n    subgraph PARENT[\"Parent VM (booted once, warmed)\"]\n        direction TB\n        runtime[\"PID 1\u003Cbr\u002F>Python + numpy + your deps\u003Cbr\u002F>imported into RAM\"]\n    end\n\n    PARENT -- \"pause + snapshot\" --> SNAP[\"Snapshot on disk\u003Cbr\u002F>memory.bin (CoW source)\u003Cbr\u002F>vmstate (vCPU + devices)\"]\n\n    %% ─── controller ───────────────────────────────────────────\n    CLIENT[\"Client (CLI \u002F Python SDK)\"] -- \"POST \u002Fv1\u002Fsandboxes n=100\" --> CTL[\"forkd-controller\u003Cbr\u002F>REST · auth · audit · \u002Fmetrics\"]\n    CTL -- \"restore_many_with(...)\" --> SNAP\n\n    %% ─── children ─────────────────────────────────────────────\n    subgraph CHILDREN[\"100 Child Firecracker processes (kernel CoW per page)\"]\n        direction LR\n        subgraph NS1[\"netns forkd-child-1\"]\n            C1[\"Child 1\u003Cbr\u002F>mmap MAP_PRIVATE\u003Cbr\u002F>cgroup memory.max\"]\n        end\n        subgraph NS2[\"netns forkd-child-2\"]\n            C2[\"Child 2\u003Cbr\u002F>mmap MAP_PRIVATE\u003Cbr\u002F>cgroup memory.max\"]\n        end\n        subgraph NSN[\"netns forkd-child-100\"]\n            CN[\"Child 100\u003Cbr\u002F>mmap MAP_PRIVATE\u003Cbr\u002F>cgroup memory.max\"]\n        end\n    end\n\n    SNAP -. \"shared file\u003Cbr\u002F>(read-mostly)\" .-> C1\n    SNAP -. \"shared file\" .-> C2\n    SNAP -. \"shared file\" .-> CN\n\n    %% ─── network ──────────────────────────────────────────────\n    C1 -- \"veth\" --> BR[\"host bridge forkd-br0\u003Cbr\u002F>MASQUERADE\"]\n    C2 -- \"veth\" --> BR\n    CN -- \"veth\" --> BR\n    BR --> UPLINK((\"uplink → internet\"))\n\n    %% styling\n    classDef parent fill:#e8f3ec,stroke:#4c956c,color:#1f2933;\n    classDef snap   fill:#fff3df,stroke:#d4a259,color:#1f2933;\n    classDef ctl    fill:#e6efff,stroke:#5b7dba,color:#1f2933;\n    classDef child  fill:#ffffff,stroke:#52606d,color:#1f2933;\n    classDef net    fill:#f1f3f5,stroke:#8d99ae,color:#1f2933;\n    class PARENT,runtime parent;\n    class SNAP snap;\n    class CTL,CLIENT ctl;\n    class NS1,NS2,NSN,C1,C2,CN child;\n    class BR,UPLINK net;\n```\n\nSee [`DESIGN.md`](.\u002FDESIGN.md) for the full design and the open\nproblems the architecture leaves on the table.\n\n\u003Cbr\u002F>\n\n## How forkd compares\n\nThe sandbox-runtime space has a wide spread of designs. The table\nbelow summarises positioning of forkd against the most-cited\nopen-source projects. Numbers in quotes are **as advertised by the\nupstream project** unless they match a row in our benchmark chart\nabove. forkd does not measure other projects on workloads they were\nnot designed for.\n\n| Project | Primitive | Cold-start (N=100) | Fork-from-warm | Quotas | Auth \u002F TLS | License |\n|---|---|---|:---:|---|---|---|\n| **forkd** | Firecracker + snapshot CoW | **101 ms** | ✓ | cgroup `memory.max` | bearer + rustls | Apache 2.0 |\n| [CubeSandbox][cs] | RustVMM + KVM microVM | 1.06 s¹ | \"coming soon\" | \u003C5 MiB \u002F instance | not in OSS | Apache 2.0 |\n| [Daytona][dy] | OCI workspace | \u003C90 ms² | ✗ | per workspace | API keys (platform) | **AGPL-3.0** |\n| [OpenSandbox][os] | Docker \u002F K8s + gVisor \u002F Kata \u002F FC | 122 s | ✗ | via runtime | gateway (k8s) | Apache 2.0 |\n| [E2B][e2b] | Firecracker (in [infra][e2b-infra]) | not in OSS | ✗ | platform | API keys (cloud) | Apache 2.0 |\n| [BoxLite][bl] | KVM \u002F Hypervisor.framework + OCI | 113 s | ✗ stateful Box | KVM + seccomp | egress policy only | Apache 2.0 |\n| Modal | proprietary snapshot fork | not public | ✓ | ✓ | ✓ | proprietary |\n| Firecracker raw | microVM only | 759 ms | manual | n\u002Fa | n\u002Fa | Apache 2.0 |\n| Docker (runc) | OCI container | 335 s | ✗ | cgroups | n\u002Fa | Apache 2.0 |\n| gVisor (runsc) | userspace kernel | 289 s | ✗ | cgroups | n\u002Fa | Apache 2.0 |\n\n¹ Wall-clock at N=100 concurrent on this **bare-metal** host (`systemd-detect-virt: none`, i7-12700, 20 vCPU, no nested virt). This is the **fast-path** number — `pool_default_format_size_list` was extended to include the template's writable-layer size, so each sandbox reuses a pre-formatted pool entry rather than going through a live `mkfs.ext4 + reflink-copy`. 1056 ± 14 ms over five runs, 100 % success every run, measured with a bench script that pre-warms Python's `ThreadPoolExecutor` to keep client-side lazy-init out of the timing. Host runs cube **v0.2.0**, which carries a ~50 ms latency regression that [PR #234](https:\u002F\u002Fgithub.com\u002FTencentCloud\u002FCubeSandbox\u002Fpull\u002F234) fixes in v0.2.1 — the figure above is the v0.2.0 baseline. An earlier slow-path measurement on the same host (writable-layer size that didn't match the default pool) returned 20.3 s with 77\u002F100 success — that mismatch was on our side and the maintainer corrected it at [#235](https:\u002F\u002Fgithub.com\u002FTencentCloud\u002FCubeSandbox\u002Fissues\u002F235). Cube advertises **\u003C60 ms** single-instance cold-start (P99 200 ms at N=100 concurrent) under the fast-path configuration on a 96 vCPU host — that figure isn't disputed and we did not retest it here. Note also that this row compares **fork-from-warm (forkd)** with **cold-start (every other project)**; they're different operating points by design, not equivalent primitives. See [bench\u002FCUBESANDBOX.md](.\u002Fbench\u002FCUBESANDBOX.md) for the full methodology, both rows, and the upstream cmdTimeout race we filed PRs [#236](https:\u002F\u002Fgithub.com\u002FTencentCloud\u002FCubeSandbox\u002Fpull\u002F236) \u002F [#237](https:\u002F\u002Fgithub.com\u002FTencentCloud\u002FCubeSandbox\u002Fpull\u002F237) against.\n² Daytona's advertised number; we did not measure it (workspace runtime, not a fan-out-comparable shape).\n\n[cs]: https:\u002F\u002Fgithub.com\u002FTencentCloud\u002FCubeSandbox\n[dy]: https:\u002F\u002Fgithub.com\u002Fdaytonaio\u002Fdaytona\n[os]: https:\u002F\u002Fgithub.com\u002Falibaba\u002FOpenSandbox\n[e2b]: https:\u002F\u002Fgithub.com\u002Fe2b-dev\u002FE2B\n[e2b-infra]: https:\u002F\u002Fgithub.com\u002Fe2b-dev\u002Finfra\n[bl]: https:\u002F\u002Fgithub.com\u002Fboxlite-ai\u002Fboxlite\n\n**Where forkd fits.**\n\n- **Code interpreters and Jupyter-kernel sandboxes.** Each conversation\n  turn or tool call spawns a fresh kernel; the warmed parent carries\n  the SciPy \u002F ML runtime, so per-request `import numpy` \u002F `import torch`\n  collapses to zero. This is the design point — the workload shape\n  Anthropic \u002F OpenAI \u002F Modal code-interpreter products are all on.\n- **Evaluation harnesses.** Hundreds of repository checkouts or test\n  rollouts in parallel — SWE-bench-style — without paying Docker\n  cold-start per task.\n- **Per-user code execution at fan-out scale.** Many short-lived\n  sandboxes sharing one warmed parent, each child KVM-isolated by\n  construction.\n- **Untrusted-code execution in CI.** `git clone`, `pip install`,\n  `pytest` inside a real Linux VM, not a container namespace.\n- **Self-hosted alternative to managed sandbox SaaS.** One Linux box\n  with KVM, single-binary daemon, Apache 2.0 — no per-second cloud\n  fees, no vendor lock-in.\n\n**Where the others fit better.** CubeSandbox: faster pure cold-start\n(\u003C60 ms advertised). Daytona: workspace runtimes where each user owns\none long-lived sandbox. OpenSandbox: one orchestration API across\nmultiple isolation backends. BoxLite: embeddable, daemon-less,\ncross-platform (macOS via Hypervisor.framework). Modal: the closed-\nsource managed system with the same primitive.\n\n**Where forkd is wrong.** Function-level snapshot runtimes that give\nup real Linux (single-vCPU, serial I\u002FO only) beat forkd's ~100 ms by\nan order of magnitude — at the cost of not running real Python\nservers, `apt install`, or outbound HTTPS.\n\n\u003Cbr\u002F>\n\n## Enterprise deployment FAQ\n\nSkim answers for platform \u002F procurement teams scoping forkd:\n\n**Can we deploy on Kubernetes?** Yes — one forkd-controller Pod hosts N sandbox children; the K8s scheduler runs **once** at Pod creation regardless of fan-out (vs one Pod-per-sandbox in Kata \u002F Firecracker-on-K8s designs). A starter manifest ships at [`packaging\u002Fk8s\u002F`](.\u002Fpackaging\u002Fk8s\u002F). Requires nodes with `\u002Fdev\u002Fkvm` + cgroup v2; managed K8s (GKE \u002F EKS \u002F AKS) typically needs a metal SKU or explicit nested-virt to qualify.\n\n**How many sandboxes fit in one Pod?** With a 512 MiB warmed Python+numpy parent, rough sizing:\n\n- **~1 actively-running agent per vCPU** (compute-bound bottleneck)\n- **~50 idle-pooled agents per 8 GiB Pod RAM** (process-state bottleneck, not memory)\n\nMeasured CoW overhead at N=100 is **0.12 MiB \u002F child** on top of the parent ([bench\u002F](.\u002Fbench\u002F)), so memory rarely caps fan-out — vCPU + process count dominate. Heavier parents (browser, ML inference) hit the ceiling sooner; measure with yours.\n\n**How do existing agents connect?**\n\n- **REST** — `POST \u002Fv1\u002Fsandboxes n=100`, language-agnostic, bearer-token auth\n- **Python SDK** — `from forkd import Sandbox` (drop-in for `from e2b import Sandbox`)\n- **LangGraph \u002F AutoGen \u002F CrewAI** — through the Python SDK, no special glue\n- **MCP** — `pip install forkd-mcp` ships an MCP server for Claude Desktop \u002F Claude Code \u002F Cursor \u002F Cline. See [`sdk\u002Fmcp\u002F`](.\u002Fsdk\u002Fmcp\u002F)\n\n**Production case shapes (from production users + this repo's recipes):**\n\n- **AI code interpreter** — one warmed parent (SciPy \u002F torch pre-imported), fork-per-conversation-turn. Recipe: [`e2b-codeinterpreter\u002F`](.\u002Frecipes\u002Fe2b-codeinterpreter\u002F)\n- **SWE-bench-style parallel evals** — N parallel repo checkouts, each child runs `pytest` isolated. Recipe: [`coding-agent\u002F`](.\u002Frecipes\u002Fcoding-agent\u002F)\n- **Per-user code exec at scale** — shared warmed parent, child KVM-isolated per user\n- **Untrusted CI** — `git clone + pip install + pytest` inside a real Linux VM, not a container namespace\n- **Fork-per-test isolated databases** — recipe: [`postgres-fixture\u002F`](.\u002Frecipes\u002Fpostgres-fixture\u002F) — ready-to-query postgres at ~10 ms per child instead of ~2 s of fresh `initdb`\n\n\u003Cbr\u002F>\n\n## Quick start\n\nRequires: x86_64 Linux with KVM, Ubuntu 22.04 or newer.\n\n### Fastest path — pull a pre-built snapshot from the Hub\n\n```bash\npip install forkd\nsudo bash scripts\u002Fsetup-host.sh           # KVM + tap device, one-time\nsudo bash scripts\u002Fnetns-setup.sh 3        # per-child network namespaces\n\n# 14.5 MiB pack (a Python 3.12 + LangGraph-ready snapshot) → 15s download.\nforkd pull deeplethe\u002Flanggraph-react\n\n# Fork 3 children sharing the parent's memory.\nsudo -E forkd fork --tag langgraph -n 3 --per-child-netns\n```\n\nSee [`docs\u002FHUB.md`](.\u002Fdocs\u002FHUB.md) for the registry model + how to\npublish your own snapshot pack.\n\n### From-source path — build your own warmed parent\n\n```bash\n# 1. Host setup: KVM, Firecracker, Rust, KSM, hugepages, tap device.\nsudo bash scripts\u002Fsetup-host.sh\nsudo bash scripts\u002Fhost-tap.sh\ncargo build --release\nsudo install -m 0755 target\u002Frelease\u002F{forkd,forkd-controller} \u002Fusr\u002Flocal\u002Fbin\u002F\n\n# 2. Build a warmed rootfs from a Docker image.\nsudo bash scripts\u002Fbuild-rootfs.sh python:3.12-slim python-rootfs.ext4 1536 python3-numpy\n\n# 3. Fetch a kernel.\ncurl -O https:\u002F\u002Fs3.amazonaws.com\u002Fspec.ccfc.min\u002Ffirecracker-ci\u002Fv1.10\u002Fx86_64\u002Fvmlinux-6.1.141\n\n# 4. Run a one-shot sandbox.\nsudo -E forkd run --image python:3.12-slim --kernel .\u002Fvmlinux-6.1.141 \\\n    -- python3 -c \"import numpy; print(numpy.zeros(5).sum())\"\n# 0.0\n```\n\n### Multi-child fork-out\n\n```bash\n# Provision N per-child network namespaces (one-time per N).\nsudo bash scripts\u002Fnetns-setup.sh 100\n\n# Create a tagged parent snapshot.\nsudo forkd snapshot --tag pyagent \\\n    --kernel .\u002Fvmlinux-6.1.141 \\\n    --rootfs .\u002Fpython-rootfs.ext4 \\\n    --tap forkd-tap0\n\n# Fork 100 children sharing the parent's memory.\nsudo -E forkd fork --tag pyagent -n 100 --per-child-netns --memory-limit-mib 256\n\n# Talk to one of them.\nsudo forkd eval --child forkd-child-42 -- \"numpy.zeros(100).sum()\"\n```\n\n### Python SDK\n\nIn-guest agent (E2B-compatible):\n\n```python\nfrom forkd import Sandbox   # drop-in for `from e2b import Sandbox`\n\nwith Sandbox() as sb:\n    print(sb.commands.run(\"uname -a\").stdout)\n    print(sb.eval(\"numpy.zeros(5).tolist()\"))    # reuses warmed PID 1\n```\n\nController daemon (lifecycle + branching):\n\n```python\nfrom forkd import Controller\n\nc = Controller()                                  # http:\u002F\u002F127.0.0.1:8889\nchildren = c.spawn_sandboxes(\"pyagent\", n=1, per_child_netns=True)\nsb_id = children[0][\"id\"]\n\n# … drive sb_id via in-guest Sandbox, then branch before a risky step:\nbranch = c.branch_sandbox(sb_id, tag=\"checkpoint-1\")\ngrandchildren = c.spawn_sandboxes(branch[\"tag\"], n=5)  # speculative fan-out\n```\n\nSee [`docs\u002Fdesign\u002Fbranching.md`](.\u002Fdocs\u002Fdesign\u002Fbranching.md) for the\nfork-from-warm tree model and use cases.\n\n### MCP server\n\nFor Claude Desktop, Claude Code, Cursor, and any other\n[MCP](https:\u002F\u002Fmodelcontextprotocol.io\u002F)-aware client:\n\n```bash\npip install forkd-mcp\n# then add to claude_desktop_config.json:\n#   \"mcpServers\": { \"forkd\": { \"command\": \"forkd-mcp\" } }\n```\n\nThe server exposes `spawn_sandboxes`, `exec_command`, `eval_code`,\nand five other tools — the agent can fork and drive forkd microVMs\ndirectly. See [`sdk\u002Fmcp\u002FREADME.md`](.\u002Fsdk\u002Fmcp\u002FREADME.md).\n\n### Pre-built recipes\n\nSkip the rootfs design step — pick one of the [`recipes\u002F`](.\u002Frecipes\u002F)\nand run its `build.sh`:\n\n| Recipe | When to pick |\n|---|---|\n| [`python-numpy\u002F`](.\u002Frecipes\u002Fpython-numpy\u002F) | Reproduce the benchmark; lightest Python + numpy |\n| [`e2b-codeinterpreter\u002F`](.\u002Frecipes\u002Fe2b-codeinterpreter\u002F) | AI code-interpreter agents (E2B SDK-compatible) |\n| [`jupyter-kernel\u002F`](.\u002Frecipes\u002Fjupyter-kernel\u002F) | Notebook \u002F SciPy stack pre-imported; ~1 ms per kernel |\n| [`coding-agent\u002F`](.\u002Frecipes\u002Fcoding-agent\u002F) | SWE-bench \u002F coding agents with `git` + dev tools |\n| [`nodejs\u002F`](.\u002Frecipes\u002Fnodejs\u002F) | JS \u002F TS workloads, Playwright fan-out |\n| [`playwright-browser\u002F`](.\u002Frecipes\u002Fplaywright-browser\u002F) | Browser-driving agents (computer-use, web research, UI test gen). Fork warmed Chromium at ~10 ms |\n| [`agent-workbench\u002F`](.\u002Frecipes\u002Fagent-workbench\u002F) | Kitchen sink — browser + VSCode + Jupyter + MCP |\n| [`postgres-fixture\u002F`](.\u002Frecipes\u002Fpostgres-fixture\u002F) | Fork-per-test isolated postgres; ready-to-query in ~10 ms instead of ~2 s of fresh initdb |\n\n### Snapshot Hub (skip the rootfs build entirely)\n\nOnce a parent snapshot is built (yours or someone else's), `forkd pack`\nships it as a single `.tar.zst` file with a manifest + per-file sha256.\nOther hosts pull and resume forking in seconds, no Docker round-trip:\n\n```bash\n# producer host\nforkd pack --tag pyagent --out pyagent.forkd-snapshot.tar.zst\n# 23× compression typical — pyagent's 512 MiB memory.bin → ~22 MiB on disk\n\n# upload to an R2 \u002F S3 bucket\nforkd push --tag pyagent \"https:\u002F\u002F\u003Cyour-presigned-PUT-url>\"\n\n# consumer host\nforkd pull https:\u002F\u002Fhub.example.com\u002Fpyagent.forkd-snapshot.tar.zst\nforkd fork --tag pyagent -n 100 --per-child-netns   # already warm\n```\n\n`forkd images` lists local snapshots with their sizes. Integrity is\nverified on unpack via the manifest's sha256s.\n\n\u003Cbr\u002F>\n\n## Operating in daemon mode\n\nThe controller daemon owns the registry of snapshots and live\nsandboxes, exposes the REST API, and writes structured audit logs.\nRecommended for any deployment beyond local development.\n\n```bash\nsudo install -m 0644 packaging\u002Fsystemd\u002Fforkd-controller.service \u002Fetc\u002Fsystemd\u002Fsystem\u002F\nsudo mkdir -p \u002Fetc\u002Fforkd\nsudo bash -c 'head -c 32 \u002Fdev\u002Furandom | base64 > \u002Fetc\u002Fforkd\u002Ftoken'\nsudo chmod 600 \u002Fetc\u002Fforkd\u002Ftoken\nsudo systemctl enable --now forkd-controller\n```\n\nThen drive it over HTTP:\n\n```bash\nTOKEN=$(sudo cat \u002Fetc\u002Fforkd\u002Ftoken)\ncurl -H \"Authorization: Bearer $TOKEN\" -X POST http:\u002F\u002F127.0.0.1:8889\u002Fv1\u002Fsandboxes \\\n     -H 'Content-Type: application\u002Fjson' \\\n     -d '{\"snapshot_tag\":\"pyagent\",\"n\":5,\"per_child_netns\":true,\"memory_limit_mib\":256}'\n# [{\"id\":\"sb-67a1b3-0000\",\"pid\":...,...}, ...]\n\ncurl -H \"Authorization: Bearer $TOKEN\" http:\u002F\u002F127.0.0.1:8889\u002Fmetrics\n# forkd_sandboxes_active 5\n```\n\nFull API reference: [`docs\u002FAPI.md`](.\u002Fdocs\u002FAPI.md).\nOperator runbook: [`docs\u002FRUNBOOK.md`](.\u002Fdocs\u002FRUNBOOK.md).\nSecurity posture: [`docs\u002FSECURITY.md`](.\u002Fdocs\u002FSECURITY.md).\n\n\u003Cbr\u002F>\n\n## Repository layout\n\n```\ncrates\u002F\n  forkd-vmm\u002F            Firecracker wrapper: BootConfig, Vm, Snapshot, cgroup\n  forkd-cli\u002F            `forkd` binary (snapshot, fork, run, exec, eval,\n                        pack\u002Funpack\u002Fpull\u002Fpush\u002Fimages, cleanup)\n  forkd-controller\u002F     `forkd-controller` daemon: REST, registry, audit\nrootfs-init\u002F\n  forkd-init.sh         PID 1 inside the guest; mounts pseudo-fs, launches agent\n  forkd-agent.py        TCP server on :8888 inside the guest (ping\u002Fexec\u002Feval)\nsdk\u002Fpython\u002F             E2B-compatible Python SDK\nsdk\u002Fmcp\u002F                MCP server (`forkd-mcp`) — drive forkd from\n                        Claude Desktop \u002F Claude Code \u002F any MCP client\nscripts\u002F                Host-side helpers (KVM, Firecracker, netns, rootfs)\npackaging\u002Fsystemd\u002F      systemd unit for the controller\npackaging\u002Fk8s\u002F          Starter Kubernetes manifest for forkd-controller\nrecipes\u002F                Pre-built parent-rootfs recipes (python-numpy,\n                        e2b-codeinterpreter, jupyter-kernel, coding-agent,\n                        nodejs, playwright-browser, agent-workbench,\n                        postgres-fixture). See recipes\u002FREADME.md.\nbench\u002F                  Benchmark harness, chart generators, results\ndocs\u002F                   API.md, SECURITY.md, RUNBOOK.md\n```\n\n\u003Cbr\u002F>\n\n## Status\n\nAlpha. The fork-on-write primitive, controller daemon, REST API,\nauth, audit logging, cgroup memory limits, Prometheus metrics, and\nPython SDK are in place and exercised by 25 unit + integration tests\nin CI. On-disk formats and API shapes may still change before 1.0.\n\nProduction-readiness items not yet in this release:\n\n- Multi-node scheduling (one daemon = one host).\n- Default-deny egress on per-child netns (today: shared MASQUERADE\n  rule; users wanting an allow-list policy add their own `iptables`\n  rules per netns).\n- cpu.max, io.max, pids.max quotas beyond the existing\n  `memory.max`.\n- Third-party security audit.\n\nRoadmap (v0.3 candidates + production-readiness gaps): [docs\u002FROADMAP.md](.\u002Fdocs\u002FROADMAP.md).\nIssue-level tracking: [GitHub issues](https:\u002F\u002Fgithub.com\u002Fdeeplethe\u002Fforkd\u002Fissues).\nRelease notes per version: [CHANGELOG.md](.\u002FCHANGELOG.md).\nSecurity posture and past advisories: [docs\u002FSECURITY.md](.\u002Fdocs\u002FSECURITY.md).\n\n**v0.3 phase 1 shipped (v0.3.0 + v0.3.1)** — diff-snapshot BRANCH\ncuts source-pause window from **29.3 s to 205 ms (143×) on a 4 GiB\nSSD source** (idle); typical agent workload (30-300 MiB dirty)\n**6-15×**. Multi-BRANCH on the same sandbox works in v0.3.1 — 5\nconsecutive diff BRANCHes give a **14× aggregate** downtime reduction\nvs Full. Full table and honest caveats in\n[`bench\u002Fpause-window\u002FRESULTS-v0.3.md`](.\u002Fbench\u002Fpause-window\u002FRESULTS-v0.3.md);\n75-trial sweep raw data in `bench\u002Fpause-window\u002F*-sweep-*.csv`.\nOpt in by setting `\"diff\": true` on `POST \u002Fv1\u002Fsandboxes\u002F:id\u002Fbranch`.\n\nThe win is the source's **downtime**, not the total BRANCH API\nlatency: a background `cp` of the source's memory.bin runs in\nparallel with the source itself, then the diff window closes,\nsource resumes, the diff is merged onto the pre-copied output.\nSource TCP connections, kvmclock, and timers see a ~200 ms gap\ninstead of 29 s. Total BRANCH API time is still bandwidth-bound\non the cp; the trade-off favors live BRANCH from a long-running\nagent.\n\nv0.3.1's multi-BRANCH support uses the previous BRANCH's output as\nthe chain head — no separate shadow file, zero extra storage. If\nthe user `DELETE`s an intermediate BRANCH snapshot, the chain\ndetects the missing file and falls back to the source-tag base with\na logged warning. Full design:\n[`docs\u002Fdesign\u002Fdiff-snapshots.md`](.\u002Fdocs\u002Fdesign\u002Fdiff-snapshots.md).\n\nThe bigger v0.4+ candidate, live-fork via memfd + uffd_wp, is\ntracked in [issue #101](https:\u002F\u002Fgithub.com\u002Fdeeplethe\u002Fforkd\u002Fissues\u002F101).\nScaffolding (`crates\u002Fforkd-uffd\u002F`, `MemoryBackend::Userfault` enum,\ndesign doc) stays as a starting point if\u002Fwhen the cost-benefit\nchanges. We explicitly chose **not** to fork Firecracker — phase 1's\n143× cleared 85 % of the original target headroom on vanilla\nupstream, and the memfd value-add (the only reason to fork) doesn't\nadd capability we don't already have via `mmap MAP_PRIVATE`.\n\n> **0.1.4 contains daemon security fixes.** Two HIGH-class\n> validation gaps in `POST \u002Fv1\u002Fsandboxes` (path-traversal via\n> `snapshot_tag`) and `packaging\u002Fk8s\u002F` (placeholder bearer token\n> accepted at startup) affected 0.1.0–0.1.3 inclusive; users on\n> those versions should upgrade. Full advisories in\n> [docs\u002FSECURITY.md#past-advisories](.\u002Fdocs\u002FSECURITY.md#past-advisories).\n> 0.1.3 also fixed a CLI `--tag` path-traversal (affected 0.1.0–0.1.2).\n\n\u003Cbr\u002F>\n\n## Contributing\n\nPull requests welcome. Before opening one, please:\n\n1. Open an issue describing what you want to change. APIs are still\n   moving; we'd rather align early than ask you to rewrite the patch.\n2. `cargo fmt --all && cargo clippy --all-targets -- -D warnings && cargo test --all` locally.\n3. Sign-off your commits (`git commit -s`).\n\n\u003Cbr\u002F>\n\n## Star history\n\n\u003Ca href=\"https:\u002F\u002Fstar-history.com\u002F#deeplethe\u002Fforkd&Date\">\n  \u003Cpicture>\n    \u003Csource media=\"(prefers-color-scheme: dark)\" srcset=\"https:\u002F\u002Fapi.star-history.com\u002Fsvg?repos=deeplethe\u002Fforkd&type=Date&theme=dark\">\n    \u003Cimg alt=\"Star History Chart\" src=\"https:\u002F\u002Fapi.star-history.com\u002Fsvg?repos=deeplethe\u002Fforkd&type=Date\">\n  \u003C\u002Fpicture>\n\u003C\u002Fa>\n\n\u003Cbr\u002F>\n\n## License\n\nApache 2.0. See [LICENSE](.\u002FLICENSE) and [NOTICE](.\u002FNOTICE).\n","forkd 是一个用于快速创建微虚拟机沙箱的项目，特别适用于AI代理的分支扩展。它能够在101毫秒内从预热的父级快照中启动大量微虚拟机，这些子虚拟机通过写时复制机制继承父级的地址空间，从而避免了冷启动开销。基于Firecracker技术构建，forkd支持Python环境、JIT预热的JVM或已加载的机器学习模型等运行时环境的高效复用。该项目非常适合需要高密度、低延迟虚拟化环境的应用场景，如多实例AI推理服务、在线游戏服务器等，确保每个实例既享有KVM级别的隔离性，又能实现接近原生进程`fork(2)`的速度优势。",2,"2026-06-11 03:54:25","CREATED_QUERY"]