A computer is one HTTP call away. nehemiahd boots a Firecracker
microVM — jailed, resource-capped, network-isolated — and hands you a serial console, a VNC
display, or an AI that drives it. Snapshot-restore means a shell is ready in ~3 ms. Machines self-destruct when their TTL expires — or
pass "persistent": true to keep one running until you delete it.
Run your own nehemiahd (see the repo) and point everything at your deployment. It listens on this by default:
http://localhost:8080Boot a machine and read it back:
# boot a shell (python3 + node), 60s TTL
curl -s -X POST http://localhost:8080/v1/machines \
-H 'content-type: application/json' \
-d '{"template":"python","ttl_seconds":60}'
# → {"id":"m-1a2b3c4d","mode":"snapshot","boot_ms":3,
# "template":"python","expires_at":"..."}| POST | /v1/machines | Boot a machine. Body: {template, ttl_seconds, net} |
| GET | /v1/machines | List running machines |
| GET | /v1/machines/{id} | Fetch one machine |
| DELETE | /v1/machines/{id} | Destroy a machine now |
| POST | /v1/machines/{id}/exec | Run one command → {output, exit_code}. Body: {command, timeout_seconds} |
| POST | /v1/machines/{id}/extend | Reset a machine's TTL. Body: {ttl_seconds} |
| POST | /v1/machines/{id}/branch | Fork a running machine into a live clone. ?count=N → N clones from one snapshot |
| POST | /v1/machines/{id}/publish | Freeze the machine as a named template. Body: {name} — then launch {template: name} |
| GET | /v1/templates | List templates (built-ins + published) |
| DELETE | /v1/templates/{name} | Delete a published template |
| GET | /v1/machines/{id}/screenshot | PNG screenshot of a desktop |
| POST | /v1/machines/{id}/upload | Upload a file to /root (X-Filename header) |
| GET | /v1/machines/{id}/download?path=… | Download a file from the machine |
| GET | /healthz | Liveness + running count |
Templates: python (headless shell, snapshot, ~3 ms) and desktop (GUI over VNC). ttl_seconds is clamped to 15–900. Pass "net": true to give the machine
internet (cold-boots instead of snapshot; pip/npm/apk install work). Guests are NAT'd and egress-firewalled. File
transfer and previews (below) need a connected machine — a desktop, or a shell with net. Pass "persistent": true for a
machine with no TTL (runs until you delete it) — honored only when the server sets NEHEMIAH_ALLOW_PERSISTENT=1, else it falls back to the TTL.
Interactive channels upgrade to WebSocket (binary frames):
| /v1/machines/{id}/tty | Interactive guest-agent PTY — binary frames both ways |
| /v1/machines/{id}/vnc | RFB/VNC framebuffer for desktop machines |
| /v1/machines/{id}/agent | Local/self-hosted computer-use agent; managed cloud returns not_supported |
| /v1/machines/{id}/shell-agent | Local/self-hosted terminal agent; managed cloud returns not_supported |
Run a server inside a connected machine and open its port through nehemiahd — works locally (over a tunnel) and on public deployments, no wildcard DNS:
http://localhost:8080/v1/machines/<machine-id>/web/<port>/An OpenAI-compatible gateway — Claude runs on Anthropic, everything else routes through
OpenRouter (set your own NEHEMIAH_OPENROUTER_KEY).
| POST | /v1/chat/completions | Chat completions (streaming + non-streaming) |
| GET | /v1/models | List available models |
curl -s http://localhost:8080/v1/chat/completions \
-H 'content-type: application/json' \
-d '{"model":"claude-sonnet-4-6","messages":[{"role":"user","content":"hi"}]}'Managed volumes are disabled in the private beta until durable volume/revision-count quotas, global transfer admission, and the machine attach/save path are complete. Machine disks are ephemeral.
Attach on launch: POST /v1/machines with {"volume":"vol-…"} restores the volume into /root first.
An Effect-native client lives in the repo at packages/sdk (not on npm) — Schema-validated
responses, typed errors, a streaming serial console, retries built in:
import { Effect, Stream } from 'effect';
import { make } from 'nehemiah-sdk';
const nehemiah = make({ baseUrl: 'http://localhost:8080' });
Effect.runPromise(
Effect.gen(function* () {
const vm = yield* nehemiah.createMachine({ template: 'python', ttlSeconds: 60 });
console.log(vm.id, vm.mode, `${vm.boot_ms}ms`);
// the serial console is a Stream; the socket closes with the Scope
yield* Effect.scoped(
Effect.gen(function* () {
const tty = yield* nehemiah.connectTty(vm.id);
yield* tty.send('print("hello from a microVM")\n');
yield* tty.output.pipe(Stream.runForEach((b) => Effect.sync(() => process.stdout.write(b))));
})
);
yield* nehemiah.destroyMachine(vm.id);
})
);Also: listMachines, getMachine(id), branchMachine(id). Errors are tagged (RequestError, ResponseError).
Let any AI — Claude Desktop, Cursor, … — spin up and drive a computer over the Model Context Protocol. It lives in the repo at packages/mcp (not on npm yet); run it from
source and point your MCP client at it:
{
"mcpServers": {
"nehemiah": { "command": "node", "args": ["/path/to/packages/mcp/index.mjs"] }
}
}Cloud tools: launch_computer, run_command, preview_url, fork_computer, and stop_computer.
Host-local run_task and screenshot are advertised only for local/self-hosted targets; managed callers can run their own agent inside
the guest.