MVP Plan
This is the historical MVP design record. For current implementation ownership, use Source Map; for user-facing behavior, use How Crabbox Works, CLI, and Features.
#Goal
Build Crabbox as a Go CLI plus Cloudflare coordinator that lets trusted OpenClaw maintainers run local worktrees on shared remote machines with a fast local-agent loop:
- Ask for a machine class.
- Get an idle warm machine or provision a new Hetzner machine.
- Sync the local dirty tree.
- Run a command remotely with streamed output.
- Release or clean up the machine automatically.
The MVP should optimize for a useful maintainer workflow, not generalized cloud scheduling.
#Product Shape
Primary one-shot command:
crabbox run --profile openclaw-check -- pnpm check:changed
Primary agent loop:
crabbox warmup --profile openclaw-check
crabbox run --id cbx_abcdef123456 -- pnpm check:changed
crabbox stop cbx_abcdef123456
Expected user experience:
- Human-readable progress by default.
- Machine-readable
--jsonfor scripts. - No central project secrets store in MVP.
- Local env allowlist only.
- Shared pool for trusted maintainers.
- Warm machines for fast repeated checks.
warmupis first-class, because hydrated boxes shorten the agent feedback loop.- One-shot
run --profile ...is convenience sugar over acquire, sync, run, and release. - TTL cleanup for abandoned leases.
- Explicit
stop/releasefor manual cleanup.
#Product Boundary
Crabbox MVP is an OpenClaw-specific remote testbox loop, not a drop-in replacement for every hosted runner behavior.
Crabbox MVP runs commands over SSH on owned cloud capacity. Actions-backed hydration can run project setup inside a real GitHub Actions job, but direct SSH runs must be explicit about:
- secrets being forwarded from local env only by allowlist;
- no GitHub Actions OIDC or repository secret access in MVP;
- no untrusted multi-tenant execution;
- weaker isolation until per-lease users or disposable machines are implemented;
- caching being local warm-machine state rather than a central cache service.
#Repositories
Current implementation lives in one repo:
openclaw/crabbox: Go CLI, Worker coordinator, docs, release/deploy scripts, and the OpenClaw plugin package.
A separate desired-state fleet repo can still exist later, but it is not part of the current 0.1.0 implementation. Live lease state belongs in Cloudflare Durable Objects.
#MVP Components
Build in this order:
- Repo scaffold
- Go module.
cmd/crabbox.worker/orservices/coordinator/for Cloudflare Worker code.docs/,configs/,scripts/.- CI with build, format, and focused tests.
- Config loading
- Flags override env.
- Env overrides repo-local
crabbox.yaml. - Repo-local config overrides user config.
- Defaults fill anything unset.
- Coordinator API
- Cloudflare Worker validates shared bearer-token auth for non-health routes.
- Cloudflare Access can protect custom routes in front of the Worker.
- Durable Object owns lease state and atomic machine selection.
- Worker calls Hetzner and AWS APIs for create/delete/status.
- Worker exposes JSON API under
/v1.
- Lease lifecycle
POST /v1/leasesacquires or provisions.POST /v1/leases/{id-or-slug}/heartbeatkeeps lease alive.POST /v1/leases/{id-or-slug}/releasereleases or deletes.- Durable Object alarm reaps expired leases.
- Machines have states:
idle,leased,draining,provisioning,failed.
- SSH runner
- MVP transport: public SSH to Hetzner, key-only, locked-down
crabboxuser. - CLI receives machine address and SSH username from the coordinator.
- CLI owns rsync, command execution, streaming output, and exit code propagation.
- Prefer per-lease generated SSH keys over a long-lived shared maintainer key.
- Later transport: Cloudflare Tunnel/Access SSH or SSH CA.
- Sync
- Use
rsyncfor MVP. - Preserve local dirty tree, including uncommitted changes.
- Exclude heavy local folders by profile:
node_modules,.turbo,.git/lfs, caches. - Sync to
/work/crabbox/<lease-id>/<repo-name>. - Remote workdir must remain a valid Git checkout when commands depend on changed-file detection.
- Preferred sync model: warm-clone/fetch the repo at the requested base ref, then rsync the local working tree overlay with deletes.
- Record sync metadata for debugging.
- Hetzner backend
- Create machines from configured image.
- Attach configured SSH key.
- Apply labels:
crabbox=true,profile=...,lease=...,slug=...,owner=...,last_touched_at=...,idle_timeout_secs=...,ttl_secs=...,expires_at=.... - Support warm static pool and ephemeral overflow.
- Implement cleanup for stale ephemeral machines.
- OpenClaw profile
openclaw-checkprofile.- Linux x64 with Crabbox bootstrap plumbing only; Docker, Node 24, pnpm, and other project runtimes come from repo-owned setup or Actions hydration.
- Default TTL: 90 minutes.
- Default machine class configurable, likely
ccx33first. - Env allowlist:
OPENCLAW_*,NODE_OPTIONS, common model/provider keys only when explicitly configured locally. - Persistent warm-machine caches for pnpm and Docker are allowed, but must be separated from synced source state and documented as best-effort speedups.
- Access/auth
- Primary org: GitHub
openclaw. - Cloudflare Access org:
openclaw-crabbox.cloudflareaccess.com. - Cloudflare OTP remains available for early fallback.
- GitHub OAuth app exists under the
openclaworg asCrabbox Access. - GitHub IdP exists in Cloudflare Access as
GitHub OpenClaw. - Fallback Access app exists for
crabbox.clawd.bot.
- Usability pass
crabbox doctor.- Helpful errors for missing
rsync, SSH key, config, Access token, or provider token. --jsonfor every state-inspecting command.- Shell completions.
#Definition Of Done
MVP is done when this works from a local OpenClaw checkout:
crabbox login
crabbox run --profile openclaw-check -- pnpm check:changed
And proves:
- A lease is created.
- A Hetzner machine is selected or provisioned.
- Local files sync.
- Remote command output streams.
- The local exit code matches the remote command exit code.
- Lease is released on success/failure.
- Expired leases are cleaned by idle timeout and TTL cap.
- Machine pool state is visible through
crabbox pool.
#Non-Goals For MVP
- No Kubernetes.
- No central secret storage.
- No full autoscaling scheduler.
- No multi-tenant untrusted execution.
- No Windows/macOS workers.
- No hosted-runner adapter in the first implementation path.
- No attempt to perfectly hide SSH; make it reliable first.
#Known Current Infra Facts
- Direct CLI execution is implemented and verified. It can create/reuse a Hetzner server, bootstrap it, sync a local checkout with rsync, hydrate shallow Git history enough for changed-test detection, run commands over SSH, stream output, and release/delete leases.
- The Cloudflare coordinator and Durable Object lease store are implemented and deployed. The CLI uses them when
CRABBOX_COORDINATORis set, and falls back to direct Hetzner otherwise. - Intended primary domain:
crabbox.openclaw.ai. - Current Cloudflare-manageable fallback domain:
crabbox.clawd.bot. openclaw.aimust be visible as a Cloudflare zone beforecrabbox.openclaw.ai/*can be attached as a Worker route. Current public DNS is on Namecheap nameservers.- Cloudflare account ID and Crabbox Cloudflare token are available in local and MacBook Pro
~/.profile. - The current Crabbox Cloudflare token is
crabbox-deploy, scoped toSteipete@gmail.com's Accountand theclawd.botzone. - The current Crabbox Cloudflare token verifies Workers scripts, Access apps, Access IdPs, Access keys, DNS records, and zone Worker routes.
- Cloudflare Access is enabled.
- Current Access IdPs are OTP and GitHub.
- GitHub OAuth app
Crabbox Accessexists under theopenclaworg for Cloudflare Access. - Crabbox browser login uses a GitHub OAuth callback at
/v1/auth/github/callbackand stores OAuth client values as Worker secrets. - Cloudflare Access GitHub IdP
GitHub OpenClawexists. - Cloudflare Access app
Crabbox Coordinatorexists forcrabbox.clawd.bot. - Worker
crabbox-coordinatoris deployed athttps://crabbox-coordinator.steipete.workers.devand routed fromcrabbox.clawd.bot/*. The canonical target ishttps://crabbox.openclaw.aionce the Cloudflare zone is delegated. - Coordinator auth supports GitHub browser-login user tokens plus shared-token operator automation. Shared-token auth uses
CRABBOX_COORDINATOR_TOKENlocally andCRABBOX_SHARED_TOKENin the Worker. - Hetzner token is available in local and Mac Studio
~/.profile. - The Hetzner account currently hits a dedicated-core quota/resource limit for
ccx63,ccx53, andccx43. Thebeastclass falls back tocpx62until quota is raised. - Public SSH on port 22 was not usable from the tested network path; cloud-init opens SSH on port 2222 and the CLI uses that by default.
- OpenClaw verification through the Cloudflare coordinator on the fallback
cpx62runner passedCI=1 pnpm test:changed:max, completing 61 Vitest shards in 93.66 seconds end-to-end for a warm run, including rsync scan and remote Git hydration. - GitHub org slug is
openclaw. wranglerandhcloudare not assumed to be globally installed; usenpx wranglerand direct Hetzner API or document install steps.
#Next Implementation Milestones
- Raise Hetzner dedicated-core quota so
beastcan useccx63instead of falling back tocpx62. - Add GitHub org/team allowlisting for browser-login user tokens.
- Delegate
openclaw.aito Cloudflare or provide a token that can create/manage that zone, then attachcrabbox.openclaw.ai/*. - Add Cloudflare Access service-token support for non-browser CLI use on fallback routes.
- Add one-shot
run --profilecleanup semantics coverage in integration tests. - Add coordinator drain controls beyond release/delete.
- Re-run OpenClaw
pnpm test:changed:maxonccx63and compare against the current Crabbox baseline.