A dumb firecracker: real, disposable machines for versioned agent workspaces
Project description
dud 🧨
A dumb firecracker. Real, disposable microVMs that never go off: virtualize the state, not the machine. Tree in, execute against a real filesystem, diff out. Versioning belongs to the layer above (e.g. nontainer's providers) — dud is deliberately storage-blind, and the machines are deliberately dumb: all the smarts live in state, so any VM can vanish at any moment and nothing of value goes with it.
Status: pre-alpha, all three rungs live. The subprocess backend (real bash, real Python, zero isolation — own-agent-own-laptop posture), the vfkit microVM backend (macOS/HVF), and the firecracker microVM backend (Linux/KVM) all pass the same conformance corpus over the same wire protocol. OCI-image workspaces with pip-layered packages, warm VM pooling with state affinity, a disk-backed scratch plane, and snapshot parking on firecracker (a parked VM is inert files — zero RAM, ~tens-of-ms resume) all work today. See DESIGN.md for the rationale, PLAN.md for the original staging, and ROADMAP.md for what's next.
Quick look
import dud
# backend="subprocess" | "vfkit" | "firecracker" | "vm" (best VM rung
# for this host — config written against "vm" survives new rungs)
with dud.session("vm", image="python:3.12-slim") as s:
s.shell("mkdir -p data && echo 'a,b\n1,2' > data/in.csv")
r = s.python("""
import csv
rows = list(csv.reader(open('data/in.csv')))
cache['n'] = len(rows) # persists across calls (opaque to the host)
emit('status', {'rows': len(rows)})
rows # last expression echoes, REPL-style
""")
print(r.transcript) # the echo
print(r.outputs) # harvested top-level bindings (codec values)
d = s.diff() # {'data/in.csv': b'a,b\n1,2\n'}, deletes=[]
# hand d to your versioned store; dud doesn't care what it is
pooled=True reuses VMs across sessions from a process-wide warm
pool; state="<your content hash>" parks and resumes a workspace
without re-pushing it. On macOS a parked VM stays hot; on firecracker
it's frozen to disk — same contract, better economics.
Host objects cross the boundary as names, not references — guest code gets a proxy whose only power is making allowlisted calls:
s = dud.session(host_objects={"db": my_db}, allow={"db": {"query"}})
s.python("rows = db.query(filter='active')") # ok
s.python("db.drop_all()") # PermissionError, host-side
No pickle ever crosses the wire; cache values are opaque bytes to the host, and everything else rides a tagged json/bytes/file codec.
The ladder
Same guest supervisor, same wire protocol on every rung — only the substrate hardens:
| rung | platform | isolation |
|---|---|---|
subprocess |
any OS | none — dev/CI floor |
vfkit |
macOS (HVF) | real Linux microVM |
firecracker |
Linux/KVM | microVM + snapshot parking (jailer planned) |
The conformance suite in tests/conformance/ is the contract: a rung
that can't pass it unchanged isn't a rung. Requesting a rung the host
can't provide raises (IsolationUnavailable) — nothing silently
degrades.
Development
uv sync --extra dev
uv run pytest
VM-rung conformance needs the rung's platform: on macOS,
DUD_BACKEND=vfkit uv run pytest tests/conformance; the firecracker
corpus runs on any Linux with /dev/kvm — including, on Apple
silicon (M3+), a nested-virt Lima guest (dev/lima-fc.yaml,
dev/fc-test.sh).
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 Distribution
Built Distribution
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 dud-0.1.1.tar.gz.
File metadata
- Download URL: dud-0.1.1.tar.gz
- Upload date:
- Size: 144.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cb6bd2e6b3c2fcf4b35c448fa1fd705ff99d9ca446339c26664fd0fad4194dc6
|
|
| MD5 |
1940138e7c787f5b783a498f80caab1c
|
|
| BLAKE2b-256 |
1adc1b8fe3e9f51f375f57b0c150b00e4e301779c06b40c999f9a7f897866cdd
|
File details
Details for the file dud-0.1.1-py3-none-any.whl.
File metadata
- Download URL: dud-0.1.1-py3-none-any.whl
- Upload date:
- Size: 92.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e1f98df2d387b2cd77dd07dc51b2ca723584127db72dd583f3361e0852ae6582
|
|
| MD5 |
85b9cf318eea7ade51f9fb0abce70837
|
|
| BLAKE2b-256 |
816ed7ee01e716e2509f430b7d0f21af92a0c00f7774a14e06dc5b4df0730e23
|