| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
The SQLite of agent sandboxes — a self-hosted sandbox platform for AI agents. One machine, sandboxes that live forever, idle costs nothing.
Status: early development. The daemon, its lifecycle engine, the SDK, the CLI, the web console, the real Docker + gVisor executor, the S3 archiver, and the E2B-compatible API work end to end — the full create → freeze → stop → archive → restore cycle, command execution, file I/O, and the official e2b SDK against real infrastructure. Nothing here is ready for production yet.
Cloud sandbox platforms charge for every second a sandbox exists, so their sandboxes are disposable. Dormice inverts that: you run it on a machine you already pay for, and sandboxes are permanent — they just get cheaper to keep the longer they sit idle.
One command on a bare Ubuntu/Debian x86_64 host (as root):
curl -fsSL https://raw.githubusercontent.com/BitMiracle-AI/Dormice/main/deploy/install.sh | bashBehind a slow connection to the usual sources, add -s -- --mirror cn. The installer is idempotent — re-running it upgrades the code and repairs drift, and never rotates your API token. It ends by running dor doctor, a battery of read-only checks — three of them boot a real gVisor container — that decides whether the install actually succeeded; dor doctor can be re-run on its own at any time.
@dormice/sdk is the native TypeScript client. (Not on npm yet — the first release is queued; inside this repo, pnpm build produces it.)
import { Dormice } from '@dormice/sdk';
const client = new Dormice({
endpoint: 'http://127.0.0.1:3676',
token: process.env.DORMICE_API_TOKEN!,
});
// One key, one sandbox — created, woken or restarted as needed.
// stopAfterSeconds: null makes it a resident agent: it may freeze when
// idle (~50 ms to wake) but never cold-starts.
await client.acquireSandbox('my-agent', { policy: { stopAfterSeconds: null } });
const result = await client.execCommand('my-agent', 'python3 -c "print(6 * 7)"');
console.log(result.exitCode, result.stdout); // 0 42
await client.writeFiles('my-agent', [
{ path: 'notes.txt', content: 'survives freeze and stop' },
]);
await client.destroySandbox('my-agent'); // destroy — the only verb that loses dataThe wire is plain HTTP RPC (POST /acquireSandbox, POST /execCommand, …), so curl works where the SDK doesn't reach, and the dor CLI covers the operator side: dor sandbox ls / exec / push / pull / rebuild / destroy, plus dor doctor. The full native surface is documented in packages/sdk, and runnable versions of these flows live in examples/.
Dormice's users are agents, so the manual comes in a form an agent can install — a skill in the open Agent Skills format:
npx skills add BitMiracle-AI/DormiceOne file, skills/dormice/SKILL.md, teaching a coding agent the whole surface: how to connect, pick between the E2B SDKs / native API / CLI, run commands, move files, and set lifecycle policy. The documentation site is AI-readable too — its build emits /llms.txt, /llms-full.txt, and a plain-markdown .md twin of every docs page.
The daemon speaks the E2B protocol on two prefixes (/e2b/api, /e2b/envd). The official e2b package — unmodified, straight from npm — runs against Dormice with two URLs and an API-key prefix; migrating an application is configuration, not code:
import { Sandbox } from 'e2b';
const sbx = await Sandbox.create({
apiKey: `e2b_${process.env.DORMICE_API_TOKEN}`,
apiUrl: 'http://127.0.0.1:3676/e2b/api',
sandboxUrl: 'http://127.0.0.1:3676/e2b/envd',
});Everything below is exercised by the black-box e2e suite through the official package, and has passed against a real Docker + gVisor daemon:
| Surface | Notes |
|---|---|
| Sandbox.create / connect / kill / list | list filters by state and metadata, and paginates |
| Timeouts | timeoutMs and setTimeout() are real absolute deadlines; lifecycle: { onTimeout: 'pause' } parks the sandbox instead of killing it |
| pause() / resume | explicit pause; connect revives it, files intact |
| commands.run | live streaming (onStdout / onStderr), background + connect / disconnect, sendStdin, kill, list, per-command envs, user: 'root'; a non-zero exit raises the SDK's own CommandExitError |
| pty.* | create / sendInput / resize / kill — a real interactive bash |
| files read / write | text or bytes, streamed, no artificial size cap — the disk quota is the cap |
| uploadUrl() / downloadUrl() | signed URLs: expiry enforced, a tampered signature is a 401 |
| files.list / exists / makeDir / rename / remove | typed errors match the SDK's expectations |
| files.watchDir | streamed events, and the polling watcher API the Python sync SDK uses |
| getHost(port) | port proxy with wake-on-traffic (set DORMICE_SANDBOX_DOMAIN) |
| getMetrics() | one live sample; observing never wakes a frozen sandbox |
Deliberate deltas from the hosted product:
The daemon serves a small web console at http://127.0.0.1:3676/console — sign in with the API token once and it becomes an httpOnly session cookie; the token itself is never stored anywhere the page can read. The console shows every sandbox with its live lifecycle state (the same /listSandboxes the SDK sees), opens a per-sandbox detail view, creates sandboxes (the same idempotent acquire, with the lifecycle knobs), releases them, and has a Connect page with copy-paste snippets for every client (E2B SDK, native SDK, CLI) pointed at your own endpoint.
The daemon listens on 127.0.0.1 only, so reaching it from another machine is a choice you make explicitly, one of two ways:
SSH tunnel (private, zero setup): ssh -L 3676:127.0.0.1:3676 root@host, then open http://127.0.0.1:3676/console.
Reverse proxy for the console, the API, and the E2B surface at once — e.g. Caddy, which also handles TLS certificates automatically once you give it a domain:
your-domain.example {
reverse_proxy 127.0.0.1:3676 {
flush_interval -1
}
}
flush_interval -1 matters: streamed command output is written frame by frame, and a buffering proxy would turn it into one lump at the end. Anything exposed beyond localhost should be HTTPS — the API token and the session cookie travel in every request.
Set the four DORMICE_S3_* variables and idle sandboxes take the last step down: a week after stopping (tunable per sandbox via archiveAfterSeconds), the disk is packed with tar + zstd, shipped to any S3-compatible bucket (AWS, Cloudflare R2, MinIO, Alibaba OSS in S3-compat mode), and freed locally. The next acquireSandbox answers { status: 'restoring', progress } immediately and flips to ready once the disk is back — slow wake-ups are honest, never a silent hang.
DORMICE_S3_ENDPOINT=https://s3.example.com # full URL; MinIO speaks http
DORMICE_S3_BUCKET=dormice-archive
DORMICE_S3_ACCESS_KEY_ID=...
DORMICE_S3_SECRET_ACCESS_KEY=...
# DORMICE_S3_REGION=us-east-1
# DORMICE_S3_FORCE_PATH_STYLE=true # MinIO needs thisUnset, the feature is honestly absent: sandboxes park at stopped forever, and a policy asking to archive is refused rather than silently stored. The bucket must exist; the host needs zstd (install.sh installs it, dor doctor checks it).
The daemon itself runs anywhere Node 22+ runs, with an in-memory fake executor for development. Running real sandboxes needs a Linux host prepared as above — install.sh automates all of it and dor doctor verifies it, but these are the facts underneath:
Pick something else if:
pnpm monorepo:
| Path | What it is |
|---|---|
| packages/shared | Protocol schemas (zod) — the single source of truth for wire types |
| packages/server | The daemon: Fastify + SQLite ledger + lifecycle engine |
| packages/sdk | @dormice/sdk — TypeScript client for the native API |
| packages/cli | dormice command-line tool (dor for short) |
| packages/console | Web console: React SPA, served by the daemon at /console |
| e2e | Black-box suite: boots the built daemon, drives it over the wire |
| examples | Runnable demos: the native SDK, the official e2b package, a resident agent |
pnpm install
pnpm build # the e2e suite boots the built daemon, so build comes first
pnpm typecheck
pnpm lint
pnpm testE2B is a trademark of its respective owner. Dormice is an independent project and is not affiliated with, endorsed by, or sponsored by E2B. References to the e2b package describe interoperability with its published API only.
| Back | FazBrowse Home | New Git URL |