Mission control for Agent runs.
Crabfleet gives OpenClaw maintainers a fleet dashboard where every Codex crabbox is visible by operator, repo, terminal, and WebVNC state. The OpenClaw app/API canonical URL is https://crabfleet.openclaw.ai; https://crabfleet.ai is the public product/docs entrypoint.
- Fleet-first workflow. Create repo-ready Crabboxes from the app, SSH, or the Go CLI and see org Codex instances grouped by person.
- Board-based workflow. Create cards from prompts, GitHub issues, or PRs. Track them through Todo, Running, Human Review, and Done lanes.
- Issue/PR lookup. Type
#123in search to preview matching GitHub issues or PRs across enabled OpenClaw repos and create a card from the match. - Codex run control. Start durable run attempts, track heartbeats, watch the Ghostty WASM session grid, and take over only when the selected runtime advertises that capability.
- Interactive Crabboxes. Start a standalone Codex CLI workspace for manual cloud work and attach it in the same fullscreen Ghostty grid or WebVNC.
- Steerable GitHub Actions. Register an Actions job as a durable
github_actionssession, stream its PTY outbound into Ghostty, steer it from the browser, and report work state and Codex thread/turn IDs. - Worker-owned sandbox credentials. Built-in Cloudflare Sandbox sessions get placeholder env credentials; Worker-controlled outbound routing injects model and GitHub credentials only for approved upstream requests.
- Diff previews. Card tiles show changed files and totals; the run drawer shows a compact Codiff-style patch view.
- Multi-runtime policy. Auto-select between the Container and Crabbox adapter surfaces based on card overrides, repo workflow defaults, and task requirements.
- Allowlist controls. Restrict access to OpenClaw org members and specific repos through admin-managed allowlists.
- Session history. D1-backed card/run events plus periodically refreshed R2 event, transcript, and summary snapshots with terminal finalization guarantees.
- Repo workflow config. Owners can evaluate
CRABBOX.mdper repo and use it for runtime and merge defaults.
- Cloudflare Workers for the app, API, auth, GitHub lookup, and docs routes.
- D1 + Kysely for typed persistence: users, sessions, allowlists, repos, cards, events, run attempts, interactive sessions, diffs, and repo workflow evaluations.
- Ghostty WebAssembly for the fullscreen attach grid and run log replay.
- Cloudflare Sandbox containers for standalone interactive Codex CLI workspaces with live PTY attach.
- Runtime descriptors for card scheduling evidence and capability display.
- Versioned lifecycle adapter for idempotent external workspace creation, bounded status reconciliation, provider-backed deletion, terminal attachment, and authenticated transient desktop connections.
- Provision endpoint at
/api/provision/interactivethat can use the built-in Sandbox backend or retain a legacy create-only adapter or ClawFleet integration, with durable ownership and a bearer-authenticated standalone PTY route. - SessionControlDO relay for one outbound GitHub Actions runner and multiple authenticated Ghostty viewers per action session.
- R2 session archives for periodically refreshed interactive-session event NDJSON, transcripts, and summaries, finalized at terminal completion.
- GitHub API for OAuth, org/team membership, and issue/PR previews across enabled repos.
Cards currently record scheduling intent, runtime selection, heartbeats, operator actions, and result metadata; they do not launch an autonomous executor. Merge policy is stored but not executed. Interactive sessions are the live execution plane, backed by the built-in Cloudflare Sandbox or a configured lifecycle adapter. Terminal transport uses the Worker multiplex hub; board and fleet state refresh through REST polling.
Use GitHub OAuth for normal browser access, or link an SSH key from the terminal:
ssh link@crabd.shCRABBOX_BOOTSTRAP_TOKEN is only a break-glass recovery path for owners.
Add users/teams to the allowlist and enable repos:
- Navigate to Admin panel
- Add GitHub users (
@login) or teams (@org/team) - Assign roles: owner, maintainer, or viewer
- Add allowed repos (
owner/repo)
- From prompt: New card → enter prompt, select repo; title is optional
- From issue: Search GitHub issues → create card
- From PR: Search GitHub PRs → create card for review/fix
- Running cards show D1 event logs and heartbeat state
- Click "Attach" to open the fullscreen Ghostty WASM session grid
- Click "Take over" only when the active run advertises takeover support
- Click "Watch" for read-only stream
- Click "New crabbox" to request a standalone Codex CLI workspace
- Default runtime is Cloudflare Sandbox; choose Crabbox only when a VNC/desktop adapter is configured
- The OpenClaw deployment routes Container sessions to the built-in Cloudflare Sandbox and Crabbox sessions to the versioned lifecycle adapter
- Deployments without a usable backend retain the session as
pending_adapterwith a visible setup message - Install or build the Go CLI, then run
crabfleet new --repo openclaw/crabfleet "fix the failing check" - Inside a Crabfleet sandbox, the CLI uses
CRABFLEET_SESSION_IDandCRABFLEET_AGENT_TOKENautomatically so Codex can runcrabfleet list, spawn child sessions withcrabfleet new --purpose ..., sendcrabfleet message <id> "...", readcrabfleet transcript <id>, and updatecrabfleet summary <id> "..."
Internal OpenClaw automation registers or resumes a logical action session with:
POST /api/openclaw/action-sessions
Authorization: Bearer CRABBOX_OPENCLAW_TOKEN
Content-Type: application/json
{"workKey":"openclaw/crabfleet:pr:42","workKind":"pr_repair","repo":"openclaw/crabfleet","branch":"fix/pr-42","sourceUrl":"https://github.com/openclaw/crabfleet/pull/42","runUrl":"https://github.com/openclaw/crabfleet/actions/runs/123","purpose":"repair PR 42","summary":"starting repair"}The response contains {session, agentToken, runnerPtyUrl, browserUrl}. runnerPtyUrl includes the rotated session-scoped query credential and works directly with Node's global WebSocket:
const terminal = new WebSocket(runnerPtyUrl);
terminal.onmessage = (event) => process.stdout.write(Buffer.from(event.data));
process.stdin.on("data", (chunk) => terminal.send(chunk));The runner reports heartbeat and durable progress with bearer agentToken to POST /api/agent/interactive-sessions/:id/work-state. Terminal states are completed, blocked, failed, and canceled; active work uses registered or running plus a specific phase.
The full registration, relay, resumption, steering, heartbeat, completion,
cancellation, authentication, archive, and troubleshooting contract is in
docs/github-actions-sessions.md.
- Kanban-style lanes: Todo, Running, Human Review, Done
- Card filtering: all, mine, live
- Search cards by title, repo, or ID
- REST state refresh every 15 seconds, plus immediate refresh after mutations
- Runtime:
auto,container,crabbox - Merge policy: repo default,
open_pr,merge_when_green,fix_until_green_and_merge - Source types: Prompt, Issue, PR
Repo defaults can come from a CRABBOX.md file:
---
runtime:
default: auto
merge:
default_policy: open_pr
---stall_ms, cap, prompt_prefix, and the Markdown body are parsed/stored for future policy work, but only runtime and merge defaults are effective today.
- User and team allowlists with role-based access
- Repo allowlists
- Manual
CRABBOX.mdevaluation with status/error visibility - Concurrent Running-card cap (default: 20)
- Stored retention selection (14, 30, 60 days); cleanup is explicit and state-driven
- Stored merge intent (guarded, maintainers, disabled); Crabfleet does not execute merges
- GitHub OAuth for org members
- Bootstrap token for admin setup and recovery
- Short-lived D1-backed sessions; users reauthenticate after expiry
- Role-based access control (owner, maintainer, viewer)
- Cloudflare account
crabfleet.openclaw.airoute in Cloudflare; legacy OpenClaw app hosts redirect here- GitHub OAuth app (optional but recommended)
- Bootstrap token secret
Pushes to main run .github/workflows/deploy-worker.yml, which checks, tests, builds,
deploys the generic product router, applies remote D1 migrations, and deploys the app
Worker. Configure the repository secret CLOUDFLARE_API_TOKEN with permissions for
Workers deploys and D1 migrations.
crabfleet.openclaw.ai is a Worker Custom Domain declared in the app Wrangler
config. The crabfleet.ai product Custom Domains, stale classic-route cleanup,
and crabd.sh DNS convergence are handled by
scripts/ensure-cloudflare-domains.mjs; set CLOUDFLARE_DNS_API_TOKEN for
manual deploys and when CI should manage those records. Without that
DNS-scoped repository secret, CI skips domain convergence but still fails the
deploy unless the app health endpoint is reachable and both product hosts resolve
to docs.crabfleet.ai. The app Worker keeps the same public-docs redirect as a
defensive fallback, never the authenticated app.
The product router source and deploy configuration live in src/product-router.ts and
wrangler.product.jsonc.
Manual deploy, including domain convergence, is still available:
CLOUDFLARE_API_TOKEN=... \
CLOUDFLARE_DNS_API_TOKEN=... \
pnpm run deploypnpm deploy:product deploys only the generic product Worker, then converges its
two public Custom Domains and stale classic-route cleanup.
Configure these in Cloudflare Workers dashboard. CRABBOX_* names are the runtime/crabbox adapter contract; CRABFLEET_* names are for the public CLI and SSH gateway. The SESSION_LOGS R2 binding points at the crabfleet-session-logs bucket and stores crabbox event archives.
The Crabbox namespace cutover intentionally has no old-name compatibility. Existing browser sessions expire, linked SSH keys must be relinked with ssh link@crabd.sh, and in-flight interactive workspaces should be recreated.
CRABBOX_BOOTSTRAP_TOKEN– Optional owner break-glass token for setup/recoveryCRABFLEET_TRUSTED_PROXY_ORIGIN– Exact HTTPS backend origin on which trusted reverse-proxy assertions are authoritativeCRABFLEET_TRUSTED_PROXY_PUBLIC_ORIGIN– Optional browser-visible HTTPS origin required on mutations and WebSocket upgrades; defaults toCRABFLEET_TRUSTED_PROXY_ORIGINCRABFLEET_TRUSTED_PROXY_SECRET– Shared secret required onX-Crabfleet-Proxy-Secretfor trusted reverse-proxy identityCRABFLEET_TRUSTED_USER_HEADER– Optional trusted identity header name, defaultX-Authenticated-User; the proxy must remove caller-supplied copies before injecting itGITHUB_CLIENT_ID– GitHub OAuth app client ID (optional)GITHUB_CLIENT_SECRET– GitHub OAuth app secret (optional)GITHUB_REDIRECT_URI– Optional authoritative GitHub OAuth callback URL; when set it must be an absolute HTTPS URL with no credentials, query, or fragment and the exact/auth/github/callbackpath. Requests on another host restart login on this configured origin. When absent, the callback defaults to the HTTPS request origin (or literal-loopback HTTP for local development).GITHUB_ORG– GitHub org for membership check (default:openclaw)GITHUB_TOKEN– GitHub token for all enabled repo issue/PR previews and private repoCRABBOX.mdrefreshes (optional; public/default repo paths work without it)CRABBOX_TOKEN_ENCRYPTION_KEY– Optional encryption key for per-session GitHub OAuth tokens; defaults toGITHUB_CLIENT_SECRETCRABBOX_INTERACTIVE_PROVISION_URL– Optional adapter endpoint for standalone Codex CLI workspacesCRABBOX_INTERACTIVE_PROVISION_TOKEN– Optional bearer token sent to the interactive provision endpoint; required when backend URLs below are configured and always required to stop an existing standalone SandboxCRABBOX_STANDALONE_SANDBOX_TTL_SECONDS– Optional built-in standalone Sandbox lifetime, default14400, bounded to 300–86400 secondsCRABBOX_RUNTIME_ADAPTER_URL– Optional fixed base URL for the versioned workspace lifecycle adapter; mutually exclusive withCRABBOX_RUNTIME_ADAPTER_URL_TEMPLATE, takes precedence over the legacy create-only runtime provision URL, and becomes immutable registration identity for each created lifecycle. Nested base paths are preserved; raw query or fragment delimiters are rejected.CRABBOX_RUNTIME_ADAPTER_URL_TEMPLATE– Optional profile-routed alternative containing exactly one{profile}full path segment. Selected profile IDs must be lowercase DNS labels; the resolved URL is validated and persisted with the same immutable lifecycle fence as a fixed adapter URL.CRABBOX_COORDINATOR_ORIGIN– Optional public origin corresponding to theCRABBOX_COORDINATORservice binding. Matching fixed or profile-routed lifecycle and terminal requests use the binding; other adapter origins use normal outbound fetch.CRABBOX_RUNTIME_ADAPTER_TOKEN– Required bearer token for the versioned lifecycle adapter; sent only over HTTPS or literal loopback HTTPCRABBOX_RUNTIME_ADAPTER_NAMESPACE– Required stable tenant namespace when the versioned adapter is enabled; a DNS-safe label of at most 32 characters used in every workspace ID and idempotency keyCRABBOX_RUNTIME_ADAPTER_TTL_SECONDS– Optional requested workspace TTL, default14400CRABBOX_RUNTIME_ADAPTER_IDLE_SECONDS– Optional requested workspace idle timeout, default1800CRABBOX_RUNTIME_PROVISION_URL– Optional generic backend URL used by/api/provision/interactiveCRABBOX_RUNTIME_PROVISION_TOKEN– Optional bearer token sent to the generic runtime backendCRABBOX_CLOUDFLARE_RUNNER_URL– Optional Crabbox Cloudflare container runner URL used by/api/provision/interactiveCRABBOX_CLOUDFLARE_RUNNER_TOKEN– Optional bearer token sent to the Cloudflare runnerCRABBOX_CLOUDFLARE_RUNNER_INSTANCE_TYPE– Optional runner instance type, defaultstandard-4CRABBOX_CLOUDFLARE_RUNNER_WORKDIR– Optional base workdir for provisioned sandboxes, default/workspace/crabboxCRABBOX_CLOUDFLARE_RUNNER_TTL_SECONDS– Optional sandbox TTL, default14400CRABBOX_CLOUDFLARE_RUNNER_IDLE_SECONDS– Optional idle timeout, default1800CRABBOX_PTY_BRIDGE_URL– Optional WebSocket PTY bridge URL/template for live Ghostty attach; requires WSS except literal loopback WS and supports{id},{leaseId},{repo},{branch}, and{runtime}CRABBOX_PTY_BRIDGE_TOKEN– Optional bearer token sent from Crabfleet to the PTY bridgeCRABBOX_CLAWFLEET_URL– Optional ClawFleet dashboard/API URL used by/api/provision/interactiveforcrabboxsessionsCRABBOX_CLAWFLEET_TOKEN– Optional bearer token sent to ClawFleetCRABBOX_CLAWFLEET_PUBLIC_URL– Optional public ClawFleet URL used when building attach/VNC linksCRABBOX_OPENCLAW_TOKEN– Internal bearer token for OpenClaw service crabbox and GitHub Actions session registrationCRABBOX_MULTICODEX_TOKEN– Optional dedicated bearer token for MultiCodex room supervisionCRABFLEET_SSH_GATEWAY_TOKEN/CRABBOX_SSH_GATEWAY_TOKEN– Shared bearer token for the Go SSH gateway internal APICRABFLEET_LOCAL_SANDBOX_BACKUPS– Optional Cloudflare Sandbox checkpoint mode override; defaults to R2 binding uploads, set0for SDK presigned R2 uploadsCRABFLEET_LABEL– Optional tenant label shown in the app, defaultCrabfleetCRABFLEET_CANONICAL_URL– Optional tenant app/API origin, defaulthttps://crabfleet.openclaw.ai; requires HTTPS except literal loopback HTTPCRABFLEET_PRODUCT_URL– Optional tenant product/docs origin, defaulthttps://crabfleet.ai; requires HTTPS except literal loopback HTTPCRABFLEET_SSH_HOST– Optional SSH command host shown in the app, defaultcrabd.shCRABFLEET_PREFERRED_REPO– Optional first/default enabled repo, defaultopenclaw/crabfleetCRABFLEET_DEFAULT_RUNTIME– Optional interactive runtime default,containerorcrabbox; defaults tocontainerCRABFLEET_DEFAULT_PROFILE– Optional opaque runtime-adapter profile, defaultdefaultCRABFLEET_RUNTIME_PROFILES_JSON– Optional bounded JSON array of generic profile descriptors (id,label, optionaltarget, optional booleancapabilities, and optionalcodexSsh) shown to authenticated users when creating Crabbox sessions; when configured,CRABFLEET_DEFAULT_PROFILEmust name one entry.codexSsh.aliasTemplatemay use{providerResourceId},{workspaceId},{sessionId}, and{profile}. OptionalcodexSsh.setupCommandis an argv-like JSON string array: its first item and static items are shell-safe tokens, while any later item may be one complete placeholder. Crabfleet shell-quotes every substituted argument.CRABFLEET_DEV_LOGIN_ENABLED– Explicit local-only development identity login gate; disabled unless exactlytrue, and still restricted to literal localhost requestsOPENAI_API_KEY– Required for built-in Cloudflare Sandbox Codex CLI sessions; injected by the Worker outbound path for Cloudflare Sandbox requests
For example, a deployment can expose two generic desktop profiles without teaching Crabfleet about either provider:
CRABFLEET_DEFAULT_RUNTIME="crabbox"
CRABFLEET_DEFAULT_PROFILE="linux-desktop"
CRABFLEET_RUNTIME_PROFILES_JSON='[{"id":"linux-desktop","label":"Linux","target":"linux","capabilities":{"terminal":true,"desktop":true,"vnc":true},"codexSsh":{"aliasTemplate":"codex-{providerResourceId}","setupCommand":["fleet-connect","{providerResourceId}"]}},{"id":"macos-desktop","label":"macOS","target":"macos","capabilities":{"terminal":true,"desktop":true,"vnc":true}}]'
CRABBOX_RUNTIME_ADAPTER_URL_TEMPLATE="https://controller.example/v1/adapters/{profile}/proxy"The route template can select one outbound lifecycle adapter per profile. Each
adapter remains responsible for its provider mapping and real capabilities. A
configured Codex SSH handoff appears only to a ready session's managers. The
browser copies the deployment-local setup command; it never executes it or
stores provider credentials. That helper must install a concrete OpenSSH alias
whose remote login shell can find an authenticated codex command.
The app Worker includes a once-per-minute cron trigger for bounded runtime lifecycle and terminal-archive reconciliation. Keep the triggers.crons entry when deriving deployment configuration; direct session, PTY, and VNC access also performs CAS-guarded targeted refreshes.
curl -I https://crabfleet.openclaw.ai/healthz
# Should return: 200 OK
curl https://crabfleet.openclaw.ai/docs/spec
# Should return: HTML spec document# Install dependencies
pnpm install
# Build assets
pnpm build
# Run type checks
pnpm check
# Run linter
pnpm lint
# Format code
pnpm formattsgo --noEmitthroughpnpm buildoxlintfor lintingoxfmt --checkfor formatting- SQLite migration smoke checks for D1 schema compatibility
- Structured autoreview before non-trivial commits
- Browser/live smoke checks after deploy
# Start local dev server with D1
wrangler dev
# Apply migrations locally
wrangler d1 migrations apply DB --localThe Worker exposes an internal SSH onboarding API guarded by CRABFLEET_SSH_GATEWAY_TOKEN or CRABBOX_SSH_GATEWAY_TOKEN.
Run the Go gateway next to a host that can accept raw SSH:
CRABFLEET_API_URL=https://crabfleet.openclaw.ai \
CRABFLEET_SSH_GATEWAY_TOKEN=... \
CRABFLEET_SSH_HOST_KEY=/var/lib/crabfleet/ssh_host_ed25519_key \
CRABFLEET_SSH_ADDR=:2222 \
go run ./cmd/crabbox-ssh-gatewayUnknown public keys get a short GitHub OAuth link through ssh link@host. Linked keys can
run whoami, list, new, attach SESSION_ID, and delete SESSION_ID; new creates an
interactive Codex session and attaches. Delete confirms runtime release for versioned lifecycle
adapters; legacy create-only and ClawFleet sessions stop locally and may need provider cleanup.
Production should expose the gateway at crabd.sh as a DNS-only A record.
Use ssh link@crabd.sh once to connect a GitHub-backed SSH key, then run
ssh crabd.sh whoami or ssh crabd.sh list.
The crabfleet CLI is written in Go with Kong and delegates to SSH by default. API mode is available for service contexts with CRABFLEET_SSH_GATEWAY_TOKEN and CRABFLEET_SSH_FINGERPRINT.
brew tap openclaw/tap
brew install crabfleet
go run ./cmd/crabfleet login
go run ./cmd/crabfleet list
go run ./cmd/crabfleet new --repo openclaw/crabfleet "start on the release checklist"
go run ./cmd/crabfleet status <session-id>
go run ./cmd/crabfleet attach <session-id>
go run ./cmd/crabfleet delete <session-id>
go run ./cmd/crabfleet vnc --open <session-id>
go run ./cmd/crabfleet logs <session-id>
go run ./cmd/crabfleet transcript <session-id>
go run ./cmd/crabfleet message <session-id> "check CI"
go run ./cmd/crabfleet summary <session-id> "waiting on CI"
go run ./cmd/crabfleet checkpoints <session-id>
go run ./cmd/crabfleet checkpoint <session-id>
go run ./cmd/crabfleet restore <session-id> <checkpoint-id>
go run ./cmd/crabfleet doctorcrabfleet stop <session-id> remains a compatibility alias for delete.
Tagged releases publish crabfleet with GoReleaser and dispatch the OpenClaw Homebrew tap updater:
git tag v0.1.0
git push origin v0.1.0The release workflow builds macOS, Linux, and Windows archives, then updates openclaw/homebrew-tap through update-formula.yml.
OpenClaw can create repo-ready crabboxes for Discord-triggered work through the internal service endpoint:
curl -fsS https://crabfleet.openclaw.ai/api/openclaw/crabboxes \
-H "authorization: Bearer $CRABBOX_OPENCLAW_TOKEN" \
-H "content-type: application/json" \
-d '{"owner":"@steipete","repo":"openclaw/crabfleet","prompt":"prep the meeting follow-up"}'The created crabbox appears in the fleet grid under the requested owner. Provisioning follows normal interactive-session routing: built-in Sandbox for Container, the versioned adapter for Crabbox, or an intentionally configured legacy path.
crabfleet/
├── src/
│ ├── index.ts # Worker entry point, API routes, auth handlers
│ ├── app.html # Single-page app shell and styles
│ ├── app/ # Preact app modules
│ ├── generated.ts # Build-time generated assets
├── migrations/ # D1 database migrations
├── scripts/ # Build scripts
│ └── generate-assets.mjs
├── cmd/ # Go CLI and SSH gateway entry points
├── internal/
│ ├── fleetapi/ # Shared Go control-plane client and domain contracts
│ ├── fleettext/ # Shared terminal-safe session rendering
│ └── terminalws/ # Shared multiplex terminal protocol client
├── vite.config.mjs # Preact/Vite app bundle config
├── docs/ # Documentation (GitHub Pages)
│ ├── CNAME # docs.crabfleet.ai custom domain
│ └── spec.md # Product spec
└── wrangler.jsonc # Cloudflare Worker config
Full documentation available at docs.crabfleet.ai:
- Quickstart – Get started in 5 minutes
- Architecture – System design and data model
- Cards – Card lifecycle and policies
- Runs – Runtime selection and execution
- GitHub Actions Sessions – Durable runner relay and steering
- Native macOS Client – Prototype scope and security boundary
- Admin – Access control and policies
- API – REST and WebSocket APIs
- Spec – Complete product specification
- All state-changing operations require authentication
- Repo operations require allowlist membership
- Merge policy is stored as intent; Crabfleet does not currently perform merges
- Runtime tokens are scoped and short-lived
- Secrets never logged or stored in D1/R2
- Audit events cover admin changes and interactive-session lifecycle/control mutations
Active development. See CHANGELOG.md for recent updates.
Current phase: deployed OpenClaw control plane with auth, Fleet and Board views, admin controls, durable card attempts, repo workflow evaluation, live interactive sessions, session supervision, GitHub Actions relays, provider-backed Crabbox lifecycle management, R2 archives, and authenticated terminal/desktop access.
Current product boundary: Cards do not yet launch autonomous work or execute merge policy. Those fields remain explicit control-plane intent rather than simulated automation.
MIT License. See LICENSE for details.
Crabfleet is an OpenClaw project, not affiliated with Cloudflare, GitHub, or Anthropic.
This is currently an internal OpenClaw tool. External contributions are not accepted at this time.
For OpenClaw org members: use #crabfleet in Discord or open an issue in the private repo.
