agent-machines
Persistent Workers. Replaceable machinery.
Agent Machines is the Worker system for persistent digital labor. Describe a responsibility or choose a trusted specialist, then keep its identity, memory, instructions, schedules, files, permissions, abilities, history, and evidence while runtimes, models, tools, and sandboxes change underneath it.
The routing wedge is “OpenRouter for agents and containers.” The larger product is a creation environment for long-running Workers: Lovable/Bolt/v0-shaped composition with ChatGPT-simple access to the first useful result. People do not want a bare sandbox or another disposable chat. They want a Worker that owns a job, remains inspectable, and is still there tomorrow.
Live site: https://www.agent-machines.com Source: https://github.com/Kevin-Liu-01/agent-machines
Table of contents
- What it is
- The product invariant
- The core idea: dual routing
- Control plane v2
- Browser Agent Console
- Deploy → Bootstrap → Attach → Talk
- The streaming gateway
- The harness
- Architecture
- Provider capability matrix
- Quick start
- CLI
- Web app
- Dashboard surfaces
- Repository layout
- Data boundaries and security
- Further reading
What it is
One account to route the machinery, compose the Worker, and access the result:
| Analogy | Meaning |
|---|---|
| OpenRouter for agents and machines | Route runtime, model, substrate, and abilities without binding the Worker to one vendor |
| Lovable / Bolt / v0 for Workers | Describe a responsibility and assemble a long-running Worker, or start from a trusted template |
| ChatGPT-simple access | Sign in, connect the services it may use, and reach the first useful result before infrastructure enters the conversation |
The intended interaction is four steps: describe or choose → connect → assign → supervise. Models, runtimes, sandboxes, terminal transports, scheduling, recovery, and migration disappear beneath that experience.
Two audiences:
- Humans choose useful specialists or compose them from primitives, then watch, approve, inspect, and move the fleet.
- Other agents drive the same API/CLI surface so a head Worker can provision, route, observe, and tear down subordinate Workers.
The product invariant
The Worker is durable. Everything underneath is replaceable.
| Keep with the Worker | Replace beneath it |
|---|---|
| Identity, responsibility, memory, instructions, schedules | Agent runtime, model path, sandbox provider |
| Files, permissions, abilities, history, evidence | Skills/MCP/CLI wiring, terminal transport, persistence mode |
| Desired state, approval boundaries, output contract | Scheduler, placement policy, cost/health route |
Replaceable does not mean identical. Every provider and runtime declares what it can actually do; the control plane exposes only supported operations. The stable Worker abstraction preserves the user relationship while necessary infrastructure differences remain visible.
The core idea: dual routing
Most products lock you into one runtime or one cloud. Agent Machines routes both axes independently. Every substrate implements a single MachineProvider interface (provision / state / wake / sleep / destroy / exec / streamExec), so the rest of the system is provider-agnostic.
| Axis | Options | Abstraction |
|---|---|---|
| Agent runtime | Hermes, OpenClaw, Claude Code, Codex CLI | bootstrap phase recipes + launch commands |
| Substrate | E2B, Sprites.dev, Vercel Sandbox, Dedalus Machines | MachineProvider (web/lib/providers/*) |
| Model upstream | Vercel AI Gateway, OpenRouter, native OpenAI / Anthropic keys, custom OpenAI-compatible fallback | router presets + per-machine credential gate |
A credential gate blocks provisioning when the chosen runtime has no usable model upstream or the substrate has no key, so spin-up never fails silently downstream.
v2 lifecycle cutover. Hosted
MachineProvideris now a compatibility facade over the mux provider adapters, so vendor SDK code has one home. The new control-plane kernel consumes those adapters through public and hosted runtime drivers. Every hosted lifecycle mutation now submits a durable operation before provider work.UserConfig/MachineRefremains as the dashboard's compatibility projection, while the operation journal uses atomic JSON locally or transactional Supabase in hosted deployments. The latter requires migration009_control_plane_v2.sql. The exact ledger is docs/CONTROL-PLANE-V2.md.
Control plane v2: declarative Workers
src/control-plane is the new lifecycle kernel. Callers submit desired Worker
state; a leased, idempotent reconciler owns provision, bootstrap, cold-start,
sleep, live provider migration, scheduled dispatch, repair, and teardown.
Requests and cron ticks may disappear without owning the Worker: unfinished
operations remain in the journal and expired leases can be reclaimed.
import {
AgentMachinesControlPlane,
JsonFileControlPlaneStore,
MuxWorkerRuntimeDriver,
createMux,
} from "agent-machines";
const plane = new AgentMachinesControlPlane(
new JsonFileControlPlaneStore(".agent-machines/control-plane.json"),
new MuxWorkerRuntimeDriver(createMux()),
);
await plane.apply({
id: "repo-coder",
spec: {
name: "Repo coder",
runtime: "claude-code",
sandbox: "e2b",
migrationPolicy: "live",
schedules: [],
},
});
await plane.drain(); // a request, queue consumer, or cron reconciler can do this
The local package ships in-memory and atomic JSON journal adapters; the hosted
app adds a tenant-scoped Supabase adapter with fenced leases and atomic RPCs.
Worker detail exposes operation history and retry, and the internal cron tick
is also the recovery consumer. See
docs/CONTROL-PLANE-V2.md for the exact boundary.
Browser Agent Console (live CLI in the browser)
The headline capability and the hardest engineering problem in the repo: you operate the real agent CLI (Codex, Claude Code, Hermes, OpenClaw) from a browser tab, on a remote worker, with no local terminal and no tunnel.
The problem
The most capable agent tools ship as terminal programs (CLIs), not chat widgets. A live browser terminal normally requires a long-lived WebSocket PTY server in the middle, relaying every keystroke. Vercel added WebSocket Functions in June 2026, but a socket invocation is still bounded and cannot own durable terminal state. The session therefore stays on the worker while a pinned Function accelerates the live data plane.
- assume a local terminal (
claude/codexon your laptop), excluding non-terminal users, or - wrap the agent in a chat UI and lose the full TUI/CLI experience, or
- ship their own terminal locked to their own sandbox infra, or
- bolt on a relay/tunnel they then have to operate.
The inversion
Stop hosting the session in the API. Put the session on the worker; keep the control plane stateless.
- Session lives on the box. A persistent
tmuxsession (amconsole) holds the PTY, the agent process, and scrollback. It survives serverless cold starts and function timeouts. - Fast path (native-PTY substrates). One authenticated Vercel WebSocket Function pins one provider PTY and attaches it to
amconsole; input, output, and resize stay on that connection. - Portable fallback. HTTP
tmux send-keysinput plus offset-aware SSEtail -foutput remains available anywhereexecexists. - Session durability is unchanged. Socket reconnects reattach to worker-owned tmux; the Function never owns the shell or its scrollback.
exec is the only primitive each substrate must provide, so the same UI works across Dedalus, E2B, Sprites, and Vercel.
Browser (xterm.js)
| input/output/resize <--> /api/dashboard/terminal/socket (pinned WebSocket)
| fallback keystrokes --> /api/dashboard/terminal/input (tmux send-keys -H)
| fallback output <-- /api/dashboard/terminal/stream (SSE tail -f)
v
Next.js control plane (Clerk auth, resolve machine + provider creds)
v
provider.openPty (native fast path) or provider.exec / streamExec (fallback)
v
Remote VM: tmux "amconsole" + pipe-pane --> /tmp/am-console.log
v
Agent CLI running inside the pane (codex | claude | hermes | openclaw)
The closest predecessor is AWS CloudShell, a real browser terminal, but it is locked to the AWS ecosystem. This is CloudShell-shaped, substrate-agnostic, and wired to agent CLIs. Worker-owned tmux makes both the native-PTY WebSocket lane and the HTTP/SSE fallback reconnectable instead of tying session lifetime to an API process.
Performance notes
The interactive console is tuned to feel close to local:
- parallel xterm bundle load and
tmuxsession attach, - snapshot paint on connect (
capture-pane), so the screen is never blank, requestAnimationFrame-batched writes to xterm,- immediate flush for control keys and a zero-delay coalesce for raw printable input,
- a direct browser-to-worker WebSocket with one primary lane plus five preconnected failover lanes and deduplicated 12ms retry,
- correlated browser-to-PTY acknowledgements with a rolling 20-sample p95 SLO badge,
- an HTTP/SSE fallback with ordered input coalescing for non-native lanes,
- per-user
getUserConfigcache (10s) and machine-state cache (3s), - E2B sandbox connect reuse (45s) within a warm serverless instance,
tmuxpre-installed during bootstrap so the first attach never triggers a package install.
Production proof on 2026-08-14: the authenticated E2B dashboard reported a 41ms latest acknowledgement and 89ms p95 across 20 human inputs. A location-aware Sprite managed Service reached 10.8ms p50 across 100 paced inputs, with 87/100 below the 50ms target; periodic provider-proxy stalls produced 75.6ms p95 and 80.8ms max. The worker PTY write itself remained sub-millisecond. The UI therefore treats 50ms as a strict target and visibly reports breaches instead of claiming a hard internet latency guarantee.
Full write-up: knowledge/BROWSER-AGENT-CONSOLE.md. Engineering spec: web/docs/sandbox-terminal-gateway.md.
Deploy → Bootstrap → Attach → Talk
The primary dashboard flow is now runtime → sandbox → live console. The
sandbox click submits one POST /api/dashboard/control-plane/workers intent;
the hosted compatibility adapter owns these stages:
- Declare. Create the durable Worker recipe: runtime, sandbox intent, model route, memory, and live-migration policy.
- Provision + bootstrap. The adapter creates the provider machine, records its
MachineRef, and schedules phase-aligned bootstrap (web/lib/bootstrap/runner.ts). Each phase tees tobootstrap.logand persistsbootstrapState. - Attach. The browser opens the terminal page with
?launch=1, attaches thetmuxconsole, and paints the pane snapshot. - Talk. The agent CLI auto-launches inside the pane and you interact line by line, including full-screen TUIs.
Bootstrap phases are split into CORE_BOOTSTRAP_PHASES (must succeed; gateway marked ready) and POST_GATEWAY_BOOTSTRAP_PHASES (best-effort, e.g. browser tooling) so a slow optional install can't block the agent from coming online.
The streaming gateway (capability-tiered)
Two output paths reuse the same SSE event contract (started · output · idle · error) so the UI is identical regardless of substrate capability.
- Interactive console (
/api/dashboard/terminal/*): live PTY over tmux-over-exec, described above. - One-shot exec (
/api/dashboard/exec/stream) and bootstrap tail (/api/dashboard/bootstrap/stream): run a command, stream stdout/stderr while it runs.
Streaming prefers each provider's native primitive and only falls back to log-tail polling for substrates that physically cannot stream. The callback-to-generator adapter lives in web/lib/providers/stream-util.ts (bridgeExecStream).
The agent's HTTP chat gateway (Hermes :8642 / OpenClaw :18789) is now optional. The console path is exec-first and needs no public URL or Cloudflare tunnel; POST /api/chat degrades gracefully to "use the Terminal console" when a machine has no public gateway URL. Machine bearer tokens never become NEXT_PUBLIC_*.
The harness (registry-driven)
A worker is a runtime plus a composable harness. The app derives every count at runtime from the registries (web/lib/platform/harness.ts reads web/data/skills.json and web/data/mcps-catalog.json). The numbers written into this table are a snapshot of those registries, kept honest by src/lib/public-claims.test.ts, which fails if a published count and the registry disagree.
| Layer | Source | Notes |
|---|---|---|
| Skills | knowledge/skills/<name>/SKILL.md |
161 skills; synced to ~/.agent-machines/skills/ on deploy/reload |
| MCP servers | knowledge/mcps catalog |
39 servers; credential-gated (Vercel, Stripe, Supabase, Clerk, Figma, PostHog, Sentry, Datadog, Linear, Slack, GitHub, and more) |
| Service routes | loadout registry | MCP → CLI → skill preference per vendor |
| CLIs | bootstrap install | agent-browser, Playwright, gh, curl, jq, sqlite3, and more |
| Agent-native tools | per runtime | vary by runtime; Hermes is richest (terminal, fs, browser, vision, cron, memory, delegate) |
| Registry (install) | web/lib/dashboard/registry/* |
2,595 searchable items in the 2026-08-14 production audit: official MCP registry (paginated cache), skills.sh, npm CLIs, bundled loadout catalog, Cursor plugin scan, GitHub/URL manifests |
| Workers | preset + Memory bundle | deployable specialist templates (runtime, router, persona), distinct from raw machine provisioning |
| Memory bundles | portable harness slice | persona, rules, abilities; install into any runtime or export as a prompt |
Skills follow the SKILL.md protocol: procedures saved to the machine compound over time and cannot be exported out of a stateless chat product.
Loadout vs registry: Loadout is what is already active on a machine (skills, MCPs, service routes). Registry is the install catalog: search, add to loadout, sync on deploy/reload.
Architecture
you
| browser / CLI / API
v
Declarative Worker API --------------- dashboard / SDK / CLI
| operation journal + lifecycle reconciler
v
WorkerRuntimeDriver ------------------ MuxWorkerRuntimeDriver
| hosted bridge: Clerk UserConfig + MachineRef during cutover
v
MachineProvider ---------------- E2B | Sprites | Vercel Sandbox | Dedalus
| provision / state / wake / sleep / destroy / exec / streamExec
v
persistent worker (provider home: /home/user | /home/sprite | /vercel/sandbox | /home/machine)
|
|-- tmux "amconsole" interactive browser console (PTY over exec)
|-- :8642 / :18789 gateway optional HTTP chat (exec-first; no tunnel required)
|-- ~/.agent-machines/ skills, mcps, chats, crons, sessions, logs, artifacts
|-- <home>/agent-machines/ git checkout, used for knowledge reload
v
model upstream (Vercel AI Gateway | OpenRouter | native OpenAI/Anthropic | custom)
Provider capability matrix
Every substrate implements MachineProvider; streaming tier depends on the SDK.
| Substrate | streamExec primitive |
Streaming tier |
|---|---|---|
| E2B | commands.run(cmd, { onStdout, onStderr }), bridged to a generator |
native stream |
| Sprites | spawn() process stdout / stderr Readables, bridged |
native stream |
| Vercel Sandbox | Command.logs() async iterator on a detached command |
native stream |
| Dedalus | none (REST exec returns output only after completion) | poll fallback |
Native tiers relay output frame by frame with no extra exec calls. The poll fallback launches a detached command, tees combined output to a temp log, and polls new bytes until an exit-marker file appears.
Which lanes are proven, and on which surface. The multiplexer's own adapters (src/mux/providers/*) have run every agent on every substrate live. Latest full run, 2026-08-05: 12 of 16 cells pass -- all four harnesses on E2B, Sprites and Vercel Sandbox, none of four on Dedalus, every green cell asserted to return the exact sentinel text through the normalized event stream. Two Dedalus cells lost the run to one intermittent vendor defect (machine_not_found on a machine its own API reports as running) and two more passed the run but failed to tear down, which now counts as red. An earlier run on 2026-08-01 was 16 of 16 but gated on the exit code alone; docs/MUX-RESULTS.md says what each vintage proves. That run exercised the mux, not the table above: the hosted control plane's MachineProvider adapters are a second implementation of the same four vendors and are not covered by it. Convergence is item 0 of docs/ROADMAP.md.
Quick start
git clone https://github.com/Kevin-Liu-01/agent-machines
cd agent-machines
cp .env.example .env
npm install
npm run deploy # CLI path (Hermes); or use /dashboard/setup for any provider
Requires Node ^20.19 or >= 22.12. Not merely ">= 20": require("agent-machines")
resolves through the module-sync export condition, which only those Nodes match,
and older ones cannot require() an ES module at all.
Agent Machines SDK
Create a user-scoped key in Dashboard → Settings → Developer API, then use the same provision → bootstrap → run flow from code:
export AGENT_MACHINES_URL=https://your-app.vercel.app
export AGENT_MACHINES_API_KEY=am_live_...
import { AgentMachines } from "agent-machines";
const am = new AgentMachines();
const agent = await am.create({
agent: "codex",
sandbox: "e2b",
model: "openai/gpt-5.2", // codex speaks the OpenAI Responses API
});
const result = await agent.run("Inspect this repository and fix the failing test.");
console.log(result.text);
model is optional and defaults to the agent's own upstream: codex gets an
OpenAI id, claude-code an Anthropic one, and the gateway runtimes (hermes,
openclaw) get the account default. Pairing an agent with a model its upstream
cannot serve -- agent: "codex" with model: "anthropic/..." -- is refused by
create() instead of provisioning a machine that 404s on its first turn. See
docs/UPSTREAMS.md for the measured per-upstream wire
formats and the model-id namespacing rule.
The key is displayed once and stored only as a SHA-256 hash. Rotating it
invalidates the previous key immediately. Set bootstrap: false on the client
only when you intend to bootstrap the machine yourself.
The multiplexer (no control plane required)
The same package ships a direct-to-substrate multiplexer: it talks to E2B, Sprites, Vercel Sandbox and Dedalus itself, installs the agent harness, and streams normalized events. No hosted control plane, no API key of ours -- just your provider keys. See docs/MUX.md for the architecture and docs/MUX-RESULTS.md for measured latencies.
agent-machines.json in your project root:
{
"keys": { "anthropic": "env:ANTHROPIC_API_KEY" },
"providers": { "e2b": "env:E2B_API_KEY", "sprites": "env:SPRITES_TOKEN" },
"sandboxes": { "primary": "e2b", "backups": ["sprites"] },
"agents": { "default": "claude-code" }
}
import { createMux } from "agent-machines";
const mux = createMux();
const machine = await mux.create({
agent: "claude-code",
sandbox: "auto", // route, don't pin
constraints: { pty: "native", maxRuntimeMs: 3_600_000 },
optimize: "cost", // opt-in, off by default
});
for await (const event of machine.run("review this repo", { runKey: "review-42" })) {
if (event.type === "text") process.stdout.write(event.delta);
}
const pty = await machine.pty(); // real terminal, native PTY where available
console.log(machine.attempts); // why it landed where it landed
// Application-level live handoff: warm target, drain managed runs, final
// stable state delta, verify, then atomically repoint the name. Processes
// restart from durable state; this is not a cross-provider RAM transplant.
await mux.migrate("coder", { to: "sprites", mode: "live" });
sandbox: "auto" walks primary -> backups through five stages, in this order:
- Credentials. Lanes the config cannot authenticate are dropped, with the missing variables named. Fail closed.
- Constraints. Lanes that cannot satisfy
constraintsare dropped, and the attempt records the dimension that failed (constraint: "pty"). An unprovable vendor fact reads asunknownand rejects rather than being hoped for. - Price, only with
optimize: "cost": cheapest modeled total first, and a lane whose vendor publishes no rate sorts last rather than being read as free. - Learned selection, only for
autowith nooptimize: lanes are ordered by a score over this machine's own run traces -- task success first, then cost per successful result, then time to first output. - Health. A rolling window per substrate puts a lane that is failing right now at the back.
Only the first two stages ever remove a lane. The last three return
permutations, because an incident that opened every circuit -- or a policy that
has learned to dislike every lane -- must not make create() impossible.
Provisioning errors fail over to the next lane, and every decision lands in
machine.attempts with its reason, health state, modeled price and learned
score.
What stage 4 is and is not: it is a deterministic scorer over the local JSONL
trace store, shrunk toward a prior by sample count so one lucky run cannot
outrank a long record, and it only ever reorders the lanes that survived
stages 1 and 2. It is not a bandit (no exploration), it does not override a
pinned sandbox or an explicit optimize, its evidence is local to one host,
and the hosted dashboard has none of it.
Failover is placement-time only. A run that dies mid-stream comes back with
truncated: true and is not replayed. runKey is an idempotency key, not a
retry: a second run() with the same key returns the stored result instead of
executing the agent twice. Each run also appends one trace record to a day shard
in ~/.agent-machines/traces/ -- placement attempts, time to first event, and
cost kept split into modeled sandbox compute and harness-reported model spend,
with the total present only when both halves are known.
CLI
npm run deploy # provision + bootstrap Hermes
npm run deploy:openclaw # provision + bootstrap OpenClaw
npm run chat -- "message" # chat with the active machine's gateway
npm run status # active machine state
npm run logs # tail gateway logs
npm run shell # exec a shell command on the machine
npm run wake / sleep / destroy -- --yes
npm run reload # git-pull the repo on the VM and re-sync knowledge
npm run doctor # environment + machine health checks
npm run benchmark # cross-substrate boot/exec/IO benchmarks
Multiplexer commands (direct to substrate, no control plane):
npm run mux -- run --agent claude-code "review my repo" # streamed one-shot
npm run mux -- term --agent codex --name coder # interactive agent PTY
npm run mux -- shell --name coder # raw PTY on the sandbox
npm run mux -- ls # named machines
npm run mux -- migrate --name coder --to sprites --live # drain + final delta + cutover
npm run mux -- rm --name coder # destroy a named machine
Read-only reporting, which works on a fresh install with no keys and no traces:
npm run mux -- routes # the five routing stages, and what each did
npm run mux -- routes --needs '{"pty":"native"}' --agent codex
npm run mux -- routes --optimize cost --json
npm run mux -- stats --since 24h # task success, time to first output,
# cost per successful result, truncation rate
npm run mux -- health # circuit state, samples and cooldown per substrate
stats reports those four numbers per harness@substrate lane; routes adds
the learned score and the sample count behind it when the policy ran. A number
nobody measured renders as unknown -- never 0, never a dash -- because
zero is the best possible value for a cost, so a zero-filled unknown would
report the lane nobody can price as the cheapest one available.
Live-test every harness on every credentialed substrate:
npx tsx scripts/mux-live-test.ts
Web app
cd web
cp .env.local.example .env.local
npm install
npm run dev
Open http://localhost:3210.
Configure Clerk for authenticated routes:
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=...
CLERK_SECRET_KEY=...
Production note: use Clerk production keys (
pk_live_…/sk_live_…) on the deployed domain. Development keys carry strict rate limits and store metadata on a separate instance.
Key routes
| Route | Purpose |
|---|---|
/ |
landing: dual-gear hero (runtime × substrate), capabilities, loadout, architecture |
/dashboard |
fleet overview, activity, gateway health, usage summary |
/dashboard/setup |
route runtime + substrate, credentials, provision |
/dashboard/machines |
fleet supervision, stats/heatmaps, per-machine focus (?focus=) |
/dashboard/machines/[id] |
machine detail: usage charts, gateway, bootstrap, quick actions |
/dashboard/machines/[id]/terminal |
Browser Agent Console (interactive + one-shot) |
/dashboard/machines/[id]/chat |
gateway chat for a machine |
/dashboard/machines/[id]/agents |
per-machine agent/runtime context |
/dashboard/workers |
deployable presets (runtime + router + Memory bundle) |
/dashboard/memory |
owned Memory bundles (persona, rules, abilities) |
/dashboard/registry |
browse/install tools, skills, MCPs, CLIs (2,595 items in the 2026-08-14 production audit) |
/dashboard/loadout |
active stack on a machine: skills, MCPs, service/task routes |
/dashboard/skills /mcps /cron |
harness libraries + scheduled jobs |
/dashboard/usage |
cost and utilization rollups (Supabase-backed) |
/dashboard/benchmarks |
cross-substrate boot/exec matrix |
/dashboard/settings |
per-account API keys and router defaults |
/dashboard/sessions /logs /artifacts /cursor |
observation surfaces |
Command palette (⌘K) jumps across machines, registry, loadout, and console routes.
Dashboard surfaces
Beyond provision-and-chat, the control plane is a fleet operations desk:
| Surface | What it does |
|---|---|
| Machines | Live state, bootstrap phase, gateway probe, split-view chat (?focus=), deploy-and-talk entry |
| Workers | Two-click runtime → sandbox launch plus reusable recipes with model route and Memory |
| Memory | Portable persona + rules + abilities; import/export; referenced by Workers |
| Registry | Unified search over MCP registry, skills.sh, npm, bundled catalog, and Cursor plugins; add to loadout |
| Loadout | Ranked service routes (MCP → CLI → skill), task routes, trusted add-ons already on the machine |
| Cron | User-defined schedules stored in config; /api/internal/cron/tick (Vercel Cron every 5 min) evaluates and execs on machines |
| Usage / metrics | Supabase-backed utilization, activity timeline, per-machine charts; collector runs on cron tick + on-demand |
| Benchmarks | Compare E2B, Sprites, Dedalus, Vercel on boot, exec, streaming tier |
Supabase is required for durable metrics, usage, and activity. Without it, the app falls back to Clerk metadata only. See web/.env.local.example.
Repository layout
agent-machines/
src/ SDK + CLI + mux + declarative control plane
control-plane/* intent, operations, stores, reconciler, mux driver
web/ Next.js control plane (site + dashboard + provider adapters)
app/api/dashboard/terminal/* Browser Agent Console
app/api/dashboard/registry/* unified install catalog search
app/api/internal/cron/tick scheduler + metrics collector (Vercel Cron)
lib/providers/* MachineProvider (e2b | sprites | dedalus | vercel)
lib/dashboard/registry/* MCP registry, skills.sh, npm, bundled adapters
lib/bootstrap/runner.ts browser bootstrap (phase recipes)
lib/dashboard/terminal-session.ts tmux-over-exec session logic
lib/metrics/collector.ts usage + machine metrics → Supabase
docs/WHITEPAPER.md public technical whitepaper
docs/sandbox-terminal-gateway.md engineering spec
docs/README.md internal doc index
knowledge/ skills, mcps, VISION.md, AGENTS.md, BROWSER-AGENT-CONSOLE.md
mcp/ cursor-bridge MCP server
Data boundaries and security
- Clerk private metadata stores provider API keys, the Cursor key, gateway bearer tokens, and the full
UserConfig. - Clerk public metadata only exposes redacted setup state and machine summaries.
- All agent state (runtime, app data, skills, sessions, crons, config) lives under
<provider home>/.agent-machines/. - The VM repo checkout (
<provider home>/agent-machines/) is used only for knowledge reloads. - Machine gateway bearers are server-only and never shipped to the client as
NEXT_PUBLIC_*. - App-Router error boundaries (
app/dashboard/error.tsx,app/global-error.tsx) keep a single component crash from white-screening the dashboard.
Further reading
| Doc | What it covers |
|---|---|
docs/MUX.md |
the multiplexer architecture: five routing stages, capabilities, price, health, learned selection, traces, idempotency |
docs/MUX-RESULTS.md |
every measured number, and the findings that changed the implementation |
docs/ROADMAP.md |
what exists vs what is promised, per pillar, with the file that proves each claim |
docs/UPSTREAMS.md |
which model key drives which harness, verified against the live APIs |
docs/WHITEPAPER.md |
technical whitepaper: primitives, patterns, architecture |
knowledge/VISION.md |
product vision and defensibility |
knowledge/BROWSER-AGENT-CONSOLE.md |
full Browser Agent Console architecture + positioning |
knowledge/BROWSER-AGENT-CONSOLE-EXPLAINER.md |
four-paragraph plain-language explainer |
knowledge/AGENT-MACHINES-EXPLAINER.md |
three-paragraph whole-product explainer |
web/docs/sandbox-terminal-gateway.md |
streaming gateway engineering spec |
web/docs/README.md |
internal doc index (engineering + knowledge) |
web/README.md |
control-plane app details |
knowledge/FLEET-DASHBOARD-2026-05-22.md |
fleet UX research + live-fire notes |
License
MIT.
No comments yet
Be the first to share your take.