BaoBun is a fork of Bun that adds an ambient distributed runtime on top of the standard Bun toolkit. It stays automatically synchronized with upstream Bun every 3 days, so you always get the latest Bun features and fixes alongside the additions here.
Everything Bun does, BaoBun does. The additions are layered on top without changing any existing APIs or behavior.
When you run scripts with --filter across workspace packages, BaoBun caches the result of each script by a fingerprint of its inputs:
SHA256(cache_version + package_name + script_name + script_content + bun_version + lockfile_hash)
On a subsequent run where nothing has changed, the cached stdout is replayed instantly and the script is not re-executed. Results are only cached on exit code 0. Any change to script content, bun.lock, or Bun version automatically invalidates the relevant entries.
No configuration required. The cache directory is resolved automatically:
$BAO_CACHE_DIRif set$XDG_CACHE_HOME/baobunif$XDG_CACHE_HOMEis set~/.baobun/cacheotherwise
# First run — executes all scripts, populates cache
bun run build --filter="*"
# Second run (no changes) — replays from cache, near-instant
bun run build --filter="*"packages/baobun/ is a Bun-native HTTP server for sharing cache artifacts across machines or CI agents.
# Start the cache server backed by local disk
bun packages/baobun/src/cli.ts cache serve --port 7832
# Start with an S3-compatible backend (AWS, R2, MinIO)
bun packages/baobun/src/cli.ts cache serve --s3-bucket my-cache-bucket
# Check server health
bun packages/baobun/src/cli.ts cache status
# Remove entries older than 30 days
bun packages/baobun/src/cli.ts cache clean --older-than 30Environment variables:
| Variable | Purpose |
|---|---|
BAO_CACHE_DIR |
Local cache directory |
BAO_CACHE_TOKEN |
Bearer auth token for the server |
BAO_CACHE_PORT |
Server port (default: 7832) |
BAO_S3_BUCKET |
S3 bucket name |
BAO_S3_ENDPOINT |
Custom S3 endpoint (R2, MinIO, etc.) |
BAO_S3_REGION |
S3 region |
The resource governor daemon prevents out-of-memory crashes when multiple agents or CI jobs run bun test concurrently on the same machine. It enforces a system memory budget (75% of total RAM) across all test processes using a FIFO slot queue.
bun test acquires a slot automatically — no code changes needed. If the daemon is not running, bun test proceeds normally. When slots are exhausted, processes queue and notify you:
[baobun] waiting for test slot (queue position 3, 2048/24576MB free) — start daemon: bun packages/baobun/src/cli.ts daemon status
# Start the daemon (runs in background)
bun packages/baobun/src/cli.ts daemon start
# Check active slots, queue depth, and memory budget
bun packages/baobun/src/cli.ts daemon status
# Stop the daemon
bun packages/baobun/src/cli.ts daemon stopExplicit HTTP API (for CI agents that want richer metadata):
# Acquire a slot before running tests
curl -s -X POST http://localhost:7831/acquire \
-H 'Content-Type: application/json' \
-d '{"pid":$$,"label":"my-test-suite","memory_mb":1024}'
# → {"granted":true,"slot_id":"abc123"}
# Release the slot when done
curl -s -X POST http://localhost:7831/release \
-H 'Content-Type: application/json' \
-d '{"slot_id":"abc123"}'| Variable | Purpose |
|---|---|
BAO_DAEMON_PORT |
Daemon HTTP port (default: 7831) |
BAO_DAEMON_SOCK |
Daemon Unix socket path (default: ~/.baobun/daemon.sock) |
When BAO_MESH=1 is set and the daemon has connected peers, BaoBun turns your local network into a transparent compute mesh. Work is routed to idle machines automatically — no changes to your code required.
The daemon uses UDP multicast to discover other BaoBun daemons on the local network. Peers perform a version and lockfile handshake before accepting work — execution only happens between machines running the same project (same bun.lock hash) and the same BaoBun version, preventing silent cross-version divergence.
When BAO_MESH=1 and a mesh peer has idle test slots, bun test executes on that peer instead of the local machine. The local process becomes a thin client: it submits the command, streams stdout/stderr back, and exits with the remote exit code. From the developer's perspective it looks identical to a local run.
BAO_MESH=1 bun test my-suite.test.ts
# → executes on the peer with the most idle capacity
# → stdout/stderr streamed back locally
# → exits with the remote exit codeEvery fallback condition (no daemon, no peers, peer at capacity, network error) falls through transparently to local execution — BAO_MESH=1 is always safe to set.
distribute() serializes a JavaScript function and its arguments, routes execution to the best available node in the mesh, and returns the deserialized result. Falls back to local execution when no daemon is running.
import { distribute } from "baobun";
// Executes on the best available machine (local or remote)
const result = await distribute((a: number, b: number) => a + b, [1, 2]);
// → 3
// CPU-intensive work routes automatically to idle peers
const results = await Promise.all(
chunks.map(chunk => distribute(processChunk, [chunk]))
);Functions are transmitted as source strings. Arguments and return values use Node.js structured clone (node:v8), which supports: primitives, Buffer, TypedArray, Map, Set, RegExp, Date, and nested objects.
Limitations: closures that capture variables from their enclosing scope will not have access to those variables on the remote — pass everything explicitly via args.
The placement scheduler tracks which peers have recently executed work with a given content fingerprint. When a warm peer is available, work is routed there first to maximize cache hits before falling back to idle-slot routing.
BaoBun emits OpenTelemetry spans natively from Zig for the parts of the runtime that matter most for distributed debugging: test slot acquisition, workspace script execution, mesh routing decisions, and filesystem operations.
Key spans:
| Span | Emitted by |
|---|---|
bun.governor/acquire_slot |
bao_governor.zig — records queue position, mesh routing decision, and all mesh attributes |
bun.filter_run/script |
filter_run.zig — records cache hit/miss, script fingerprint, duration |
bun.fs/readlink, bun.fs/mkdir |
bao_tracer.zig — filesystem ops during test runs |
OTEL mesh attributes on bun.governor/acquire_slot:
| Attribute | Type | Meaning |
|---|---|---|
mesh.enabled |
bool | Whether BAO_MESH=1 was set |
mesh.delegated |
bool | Whether execution was routed to a peer |
mesh.executed_on |
string | Node ID of the peer that ran the test |
mesh.peer_count |
int | Number of connected peers at routing time |
mesh.route_reason |
string | delegated / no_peers / no_slots / no_daemon / mesh_error |
mesh.duration_ms |
int | Remote execution duration |
BaoBun builds exactly like Bun. See Bun's build documentation for platform-specific prerequisites.
git clone https://github.com/FullyAutonomous/BaoBun.git
cd BaoBun
# Debug build
bun bd
# Run something with the debug build
bun bd run my-script.ts
bun bd test path/to/test.tsThe debug binary is at ./build/debug/bun-debug. Use bun bd <command> rather than invoking it directly.
BaoBun syncs with oven-sh/bun automatically every 3 days via a GitHub Action. Conflicts are surfaced as issues. The sync preserves BaoBun-specific files (README.md, CLAUDE.md, packages/baobun/, src/cli/bao_cache.zig, src/cli/bao_governor.zig, src/cli/bao_otel.zig, src/cli/bao_tracer.zig) through the merge.
| File | Purpose |
|---|---|
src/cli/bao_cache.zig |
Fingerprinting engine and local disk cache |
src/cli/bao_governor.zig |
Resource governor client — acquires test slots and handles mesh delegation |
src/cli/bao_otel.zig |
Native OpenTelemetry span emitter |
src/cli/bao_tracer.zig |
Filesystem operation tracer |
src/cli/filter_run.zig |
Cache intercept inside the workspace script runner |
packages/baobun/src/daemon.ts |
Daemon process — Unix socket + HTTP, mesh coordinator |
packages/baobun/src/mesh/transport.ts |
UDP multicast discovery and WebSocket RPC transport |
packages/baobun/src/mesh/scheduler.ts |
Warm-cache-aware placement scheduler |
packages/baobun/src/mesh/client.ts |
Mesh client — submit work units and closures to peers |
packages/baobun/src/mesh/closure_worker.ts |
Executes serialized closures via node:vm |
packages/baobun/src/distribute.ts |
distribute() public API |
packages/baobun/src/cli.ts |
Daemon and cache server CLI |
- What is Bun?
- Installation
- Quickstart
- TypeScript
bun runbun installbun testBun.build- Filter (workspace scripts)
- Node.js compatibility
- Bun APIs
BaoBun is built on Bun by Oven. The workspace filtering, topological task ordering, and monorepo task orchestration in Bun were inspired by Turborepo by Vercel, Inc. (MIT licensed).
