Repo Atlas · AI-dev library
AlphaClaw
The watchdog body: a harness that keeps one OpenClaw agent alive on a rented cloud box — spawns it, watches it, backs it up, heals it, and upgrades it, all from a browser.
What it is
OpenClaw is a personal AI agent you normally run on your own laptop. But laptops sleep. AlphaClaw is the body (it calls itself a "harness") that runs that agent on a cloud server instead: one Node process that spawns the OpenClaw gateway as a child, puts a password-protected web dashboard in front of it, commits the agent's workspace to GitHub every hour, and restarts it when it crashes. The launch blog says it plainly: "Same assistant. Same channels. Same workspace. Different failure mode." AlphaClaw adds no intelligence of its own — "AlphaClaw manages infrastructure; OpenClaw handles the AI."
Glossary map
| Shared term | AlphaClaw's word | Where it lives |
|---|---|---|
| body vs brain | "harness" vs OpenClaw | this whole repo is a body; the agent-OS is a pinned npm dependency |
| self-repair loop | "auto-repair" | lib/server/watchdog.js |
| restore ladder | "persistent storage rules" | lib/setup/gitignore + core prompts |
| advisory prose vs mechanical rail | "protected" vs "locked" paths | browse-file-policies.json |
| update clock | hourly sync · 120s health poll · 2s env watch | hourly-git-sync.sh |
| skill | gog-cli skill (assembled per connected service) | lib/setup/skills/gog-cli/ |
Ecosystem roles
The stack has three layers. The platform (Render, Railway, Docker) provides a container and a persistent disk at /data. AlphaClaw is the supervisor process inside it: Express server on port 3000, dashboard, watchdog, git sync. OpenClaw is the hosted agent: a child process on loopback port 18789 that owns the actual AI work, channels (Telegram, Discord, Slack, WhatsApp), and the workspace under /data/.openclaw. Not part of this repo: OpenClaw itself, the models, and the deploy templates (separate repos).
touches marks components that mutate the hosted agent's world (config, workspace, process). watches marks components that only observe. That split is this atlas's color code throughout.
Key decisions
The repo rendered as answers to the library's canonical questions. IDs are the cross-atlas comparison keys (R-bank is the DRAFT Agent Runtime bank proposed from the herdr session — AlphaClaw is the second body-class repo to answer it).
C1 Source of truth
- Chose
- Two-tier: the persistent disk
/dataholds everything; a GitHub "workspace repo" holds a committed subset chosen by a deny-by-default gitignore (*ignored, then allowlist:openclaw.json,workspace/**,skills/**,hooks/transforms/**,cron/jobs.json). - Why
"If an agent action breaks something, you have versioned history to roll back to." — Render launch blog
- Trade-off
- What survives total loss is only the allowlist. All five SQLite stores (
db/**), secrets (.env), channel pairings, and device identities are deliberately never committed — a fresh volume means re-onboarding. See Step 8. - Links
- lib/setup/gitignore · bin/alphaclaw.js (git-sync)
C2 Trust & safety boundaries
- Chose
- One
SETUP_PASSWORDgates the dashboard and all setup APIs, backed by a two-tier lockout persisted in SQLite (per-IP and global; 5 fails in 10 min → 60s lock, doubling to a 900s cap, surviving restarts). The/v1proxy has its own timing-safe bearer check and throttle. Inbound webhooks and Gmail push get almost nothing from AlphaClaw — they are relayed to OpenClaw, which enforces its own hook token. - Why
"AlphaClaw is a convenience wrapper — it intentionally trades some of OpenClaw's default hardening for ease of setup." — README Security Notes
The README then enumerates each trade in a table: one password vs pairing codes, one-click pairing, auto-approved first CLI device, query-string tokens.- Trade-off
- The soft edges are real: the password compare isn't timing-safe (the throttle is the mitigation), "protected" files can still be overwritten via an "Edit anyway" button, the first CLI device is approved as a side effect of the UI polling
GET /api/devices, and there is no untrusted-content defense anywhere — webhook and email bodies reach the agent byte-for-byte. - Links
- routes/auth.js · login-throttle.js · routes/pairings.js · README Security Notes
C3 Cost model
- Chose
- Observability, not caps. A tiny OpenClaw plugin (usage-tracker) is installed into the hosted agent and writes every model call's token counts into a shared SQLite ledger. AlphaClaw prices the ledger with a hardcoded per-model table and renders per-agent, per-session, and per-cron-run breakdowns.
- Trade-off
- Nothing stops runaway spend — there is no budget cap or kill switch. And the price table is a maintenance treadmill: a model missing from cost-utils.js silently shows $0.00 (a repo plan doc exists specifically to fix that).
- Links
- lib/plugin/usage-tracker/index.js · lib/server/cost-utils.js · cron-service.js
C4 Integration surface
- Chose
- Many doors, one agent: chat channels (Telegram/Discord/Slack/WhatsApp) paired through the UI; named webhooks with per-hook transform modules; an opt-in OpenAI-compatible
/v1API so other apps can use the agent as a backend; a managed remote-MCP entry written intoopenclaw.jsonfrom env vars; Google Workspace via thegogCLI. - Why
- The
/v1door carries an explicit warning:"OpenClaw treats /v1/chat/completions as a full operator-access surface. A caller with a valid OPENCLAW_GATEWAY_TOKEN can run any tool the configured agent profile allows." — README
- Trade-off
- Every door is a door into the same fully-privileged agent. AlphaClaw's answer is disclosure plus token hygiene (see the MCP token scrubbing in Step 2), not isolation.
- Links
- routes/proxy.js · webhook-middleware.js · gateway.js
C5 Extension model
- Chose
- Three units of extension, each with a clear owner. User-owned: webhook transform modules (
.mjsfiles at a mandated path convention). Harness-owned: the injected prompt files and the gog-cli skill, which AlphaClaw re-stamps on every boot and locks in the file editor (server returns 403: "This file is managed by AlphaClaw and cannot be edited"). Plugin: the usage-tracker installed into OpenClaw's own plugin system. - Why
- The gog-cli skill is even assembled from state: gog-skill.js composes the skill file from only the Google services the user actually connected.
- Trade-off
- The managed/user split is enforced by a hand-curated path list; anything not on it is user territory with zero guardrails.
- Links
- webhooks.js · gog-skill.js · browse-file-policies.json
C6 Honesty discipline draft question
- Chose
- Two mechanisms. (1) The injected core prompt requires the agent to end every workspace mutation with a "Changes committed" summary containing the linked commit hash — a claim that carries its own receipt. (2) The Doctor's fix flow mints a one-time token; the agent may only call the completion callback after applying and verifying the fix:
"Do not call the completion callback if the fix was not applied or verification failed. Explain the problem to the user instead." — doctor/service.js
- Trade-off
- Both are advisory prose to an LLM, not mechanical rails — but the commit-hash format makes false claims cheaply checkable, and the token makes "fixed" a deliberate act rather than a mood.
- Links
- core-prompts/AGENTS.md · doctor/service.js · fix-completion.js
R1 Durability boundary draft bank
- Chose
- A three-rung restore ladder, stated to the agent itself in its injected prompt: the container is ephemeral ("/tmp and other temp locations do not survive redeploys"); the volume
/datasurvives restarts and redeploys; the GitHub repo survives volume loss but returns only the committed allowlist. No boot-time clone exists — an empty volume means re-running onboarding and choosing "Import existing setup." - Trade-off
- The bottom rung is lossy by design: secrets, pairings, and all history stay dead. The matrix is published in prose (README + core prompts), not as a table — you learn the exact losses in Step 8.
- Links
- core-prompts/AGENTS.md · openclaw-config-restore.js
R2 Agent state model draft bank
- Chose
- Two orthogonal axes plus flags: lifecycle (
stopped / running / restarting / crashed / crash_loop / configuration_error) and health (unknown / healthy / degraded / unhealthy), with a separate observedsafeMode. The most opinionated state isconfiguration_error: OpenClaw exiting with code 78 (EX_CONFIG) latches restarts off. - Why
"The contract is 'do not restart until the config is fixed' — restarting blindly recreates the restart storm the gateway is trying to prevent." — watchdog.js
- Trade-off
- State truth degrades silently: after any cold restart the gateway is no longer a tracked child, so exit events never fire again and crash detection falls back to the 120-second health poll (explorer finding, Step 7).
- Links
- watchdog.js · constants.js (thresholds)
R3 State authority draft bank
- Chose
- Exactly one supervisor owns restarts — and the weaker signal is switched off, not merged: AlphaClaw launches the gateway with
OPENCLAW_NO_RESPAWN=1, forbidding OpenClaw from restarting itself. Intended-vs-crashed exits are separated by a PID set (expectedExitPids), and the EX_CONFIG latch is guarded against being overwritten by an in-flight health probe. - Why
- The same move herdr's "state authority" names: two restart authorities would fight (double restarts, masked crash loops), so install the better one and disable the other.
- Trade-off
- OpenClaw's own crash-loop breaker ("safe mode") stays authoritative for channels — AlphaClaw only observes it via
/readyzand reports; resuming channels is a manual button. Authority is split by subject, per the rule. - Links
- openclaw-runtime-env.js · gateway.js · watchdog.js
R4 Attention routing draft bank
- Chose
- Alerts ride the agent's own paired chat channels — the watchdog reads OpenClaw's pairing files to find where the human already talks to the bot, and sends its 🐺-headed notices there (Telegram/Discord/Slack/WhatsApp). Slack even threads recovery under the crash message. Incidents are deduped so one outage is one notification, not one per health check.
- Trade-off
- No pairing, no alerts: a fresh or restored deployment has empty pairing files and fails silently until the human re-pairs a channel.
- Links
- watchdog-notify.js · AGENTS.md (notice format spec)
R5 Agent self-orchestration draft bank
- Chose
- The hosted agent is a first-class operator of its own harness. Its injected prompt orders it to act rather than deflect ("If a command or tool is available to you… execute it yourself first"); it creates webhooks, runs plain
git(a shim injects credentials only inside the workspace repo), and closes Doctor fix loops by callingalphaclaw doctor finding completewith a one-time token. The Doctor even asks the agent to audit its own workspace. - Trade-off
- Self-audit shares fate with the thing audited: the diagnosis path runs over the same gateway the watchdog is monitoring, so it is unavailable exactly when the gateway is down. What the agent may not do is bounded by the locked-path list, not a capability system.
- Links
- core-prompts/TOOLS.md · lib/scripts/git (shim) · doctor/service.js
R8 Self-replacement draft bank
- Chose
- Update npm packages in a temp directory, then
cp -afthe files over the livenode_modules— nevernpm installin place. - Why
"Running npm install directly in the app dir causes EBUSY on Docker because npm tries to rename directories that the running process holds open. Copying individual files (cp -af) avoids the rename syscall entirely." — openclaw-version.js
- Trade-off
- An OpenClaw update only restarts the child gateway; an AlphaClaw self-update must kill the whole container (exit 1 so the platform restarts it), leaving a marker file on the volume that a fresh boot replays — because on ephemeral filesystems the freshly-installed files themselves don't survive the restart. Git-pinned installs refuse in-place updates entirely: "updates come from redeploying the pinned ref." Full mechanism in Step 9.
- Links
- alphaclaw-version.js · openclaw-version.js · self-dependency.js
The life of one hosted agent
Nine steps, from the deploy button to replacing your own organs. Amber parts touch the agent's world; blue parts watch it.
Step 1 · Day zero
Deploy with two secrets, wizard the rest
The deploy form asks for almost nothing — a setup password and a GitHub token. The blog frames this as a decision: "The Render deploy form does not become a dumping ground for every secret your agent might need." Everything else happens in a browser wizard afterward. If you already had an agent, the import path clones your old workspace repo, scans it, and — the best part — hunts for plaintext secrets in the config: 34 known config paths, 27 vendor key prefixes (sk-ant-, ghp_, xoxb-…), and a name heuristic. Found secrets are shown for review, moved into .env, and the config file is rewritten to hold ${ENV_REF} references instead. The server re-validates every approved secret against its own scan by fingerprint — the browser can rename a variable but cannot inject a value the scanner never saw.
.env, configs keep references, so the repo that later gets committed never holds plaintext.- import-scanner.js watches — classifies the clone: config, env files, skills, cron jobs, webhooks, credentials, managed conflicts.
- secret-detector.js watches — three-channel secret hunt; masks values as
abcd****wxyzfor review. - import-applier.js touches — applies the import; scrubs the same secret everywhere it appears, longest value first.
- onboarding/workspace.js touches — seeds the workspace and the bootstrap prompt files.
Step 2 · Boot
Spawn the agent, stamp its discipline
Every boot, AlphaClaw spawns openclaw gateway run as a child on loopback port 18789, handing it the entire environment plus a redirected HOME — and one crucial flag: OPENCLAW_NO_RESPAWN=1, so the agent cannot restart itself (see decision R3). Before the spawn it re-stamps the discipline files — AGENTS.md and a templated TOOLS.md — into every agent workspace's hooks/bootstrap/ directory, and rewrites the managed MCP entry in openclaw.json, scrubbing any plaintext token back to a ${REMOTE_MCP_API_TOKEN} reference. Readiness detection is charmingly fragile: it greps the child's stdout for the string "listening on".
- gateway.js touches — spawn, env injection, config rewriting, readiness grep, plugin preflight.
- openclaw-runtime-env.js touches — adds the compile cache and the
OPENCLAW_NO_RESPAWN=1flag. - startup.js touches — the onboarded boot sequence: re-sync prompts, reload env, sync channels, start gateway, start watchdog.
- core-prompts/TOOLS.md touches — the stamped instructions, templated with the live dashboard URL and connected Google accounts.
Step 3 · The front door
Four doors, four different locks
Everything shares one public port, but the doors differ wildly in lock quality. The dashboard and setup APIs need the password-derived session cookie, with a persistent two-tier lockout behind it. The /v1 API needs the gateway token, compared timing-safe, with its own throttle. Webhooks get no AlphaClaw auth at all — the request is normalized (a ?token= query parameter is promoted into a bearer header, then deleted from the URL) and relayed for OpenClaw to judge. Gmail push is the weakest door: a plain string compare on a query token, and Google's signed identity token is never verified.
- routes/auth.js watches — session HMAC is keyed by the setup password itself: rotate the password, log everyone out.
- login-throttle.js watches — per-IP and global lockout state in SQLite; survives restarts.
- routes/proxy.js watches — the /v1 boundary; strips cookies both directions ("a stray Set-Cookie crossing the AlphaClaw boundary would be a real leak").
- webhook-middleware.js watches — normalizes, logs (with key-based redaction), relays byte-for-byte.
- gmail-push.js watches — the weak door: query-token compare, no JWT verification, no throttle.
Step 4 · Serve
A message arrives; the agent works; git gets a receipt
Normal operation barely involves AlphaClaw: Telegram talks to the gateway, the agent does its work in the workspace under /data/.openclaw. AlphaClaw's influence is the stamped discipline: the agent must commit workspace changes and end its reply with a "Changes committed" summary linking the commit hash. To make that possible without handing the agent a token, AlphaClaw installs a git shim at /usr/local/bin/git that injects GITHUB_TOKEN credentials — but only when the working directory is inside the workspace repo. The agent can also reach back into its own harness: create webhooks, call the setup APIs, run the CLI.
- lib/scripts/git touches — the shim: resolves the real git, computes the effective cwd (including
-C), injects credentials only inside the workspace repo. - git-askpass touches — answers
x-access-token/$GITHUB_TOKEN. - core-prompts/AGENTS.md touches — "No YOLO system changes", plan-before-build, commit discipline.
- routes/browse/ touches — the human's parallel hands: browser file editor with per-file git restore.
Step 5 · Watch
Ledgers for tokens, health, and incidents
Observation runs on five separate SQLite ledgers under /data/db/ — usage, watchdog events, doctor runs, webhook requests, auth throttle. The clever bit is how usage gets in: AlphaClaw installs a plugin inside OpenClaw that records every model call's token counts into the shared database; AlphaClaw then prices them with its hardcoded table and renders the Usage and Cron tabs. Health is polled every 120 seconds; a live browser terminal (a real shell on the box) covers whatever the dashboards don't.
- usage-tracker/index.js watches — the informant plugin; WAL-mode SQLite writes.
- cost-utils.js watches — the hardcoded price table; unknown model → $0.00.
- cron-service.js watches — run history, trends, per-run usage for scheduled jobs.
- watchdog-terminal.js touches — a real shared shell in the browser; 15-minute idle kill.
- db/watchdog/ watches — incident ledger, 30-day retention, routine green checks filtered from view.
Step 6 · Hourly rhythm
The backup clock: commit the allowlist, drop the noise
A root cron entry fires hourly-git-sync.sh every hour. Before committing, it runs a noise filter: if the cron bookkeeping files changed only in runtime metadata (lastRun, timestamps, run counts), it restores them — "Runtime metadata only; restore cleanly so it doesn't create noise commits." Then alphaclaw git-sync stages everything the deny-by-default gitignore allows, commits as "AlphaClaw Agent", and pushes. The commit message is a timestamp; the history is the rollback story from decision C1.
- hourly-git-sync.sh touches — the clock's hand; re-written from the packaged copy on every boot if it drifted.
- onboarding/cron.js touches — installs the system cron entry at
/etc/cron.d. - bin/alphaclaw.js touches —
git-synccommand: rebase-pull, stage, commit, push; per-PID temp askpass. - lib/setup/gitignore watches — the deny-by-default allowlist that defines "what survives".
Step 7 · Break & heal
The self-repair loop, with teeth and gaps
A crash relaunches the gateway immediately — no backoff. Three crashes inside 300 seconds is a crash loop: the watchdog stops restarting, opens an incident, and notifies. Only if auto-repair is enabled (it is off by default, despite the "self-healing" headline) does it run openclaw doctor --fix --yes, relaunch, and verify with a health check. Two states break the loop deliberately: exit code 78 latches restarts off until a human fixes the config, and OpenClaw's own "safe mode" breaker (channels suppressed, health still green) is merely observed and reported — resuming channels is a button, not an automatism.
The exploration surfaced real gaps between headline and code: the repair-attempt cap notifies "paused" but never actually pauses; the repair command inherits a 15-second timeout while the separate Doctor service grants itself 10 minutes; and the watchdog's repair (openclaw doctor, OpenClaw's deterministic CLI) is an entirely different system from AlphaClaw's Doctor tab (an LLM that audits the workspace and is forbidden to change anything).
- watchdog.js touches — the state machine, crash classification (stderr grep for "already listening" = not a crash), repair orchestration.
- watchdog-notify.js watches — 🐺-format notices to whatever channels are paired.
- doctor/service.js watches — the other doctor: LLM workspace audit, advisory-only, skipped entirely when a deterministic workspace fingerprint says nothing changed.
- doctor/bootstrap-context.js watches — deterministic budget model of prompt injection; warns before OpenClaw silently trims oversized files ("keep first 70%, last 20%, cut the middle").
- routes/watchdog.js touches — manual repair (force), resume-channels, settings.
Step 8 · Die & come back
The restore ladder: three rungs, honestly lossy
What returns after a failure depends on which layer died. A process restart loses nothing — the boot sequence re-stamps prompts and relaunches the gateway. A redeploy keeps everything because /data is a persistent volume. Volume loss drops you to the bottom rung: nothing is auto-cloned; you re-run onboarding, import from the workspace repo, and get back exactly the committed allowlist. Secrets must be re-entered, channels re-paired, and every ledger starts empty.
- openclaw-config-restore.js touches — the one automatic restore: fetches
openclaw.jsonfrom the remote if it vanished locally while.gitsurvived. - onboarding/index.js touches — the import path: clone, scan, review, apply; re-inits git, deletes replaceable bootstrap paths.
- env.js touches —
.envread/write/watch; the file that never rides the ladder.
Step 9 · Upgrade
Replacing organs while the patient runs
Both packages update by the same trick (decision R8): install into a temp directory, then cp -af over the live node_modules, avoiding the rename syscall that EBUSYs on Docker. Updating OpenClaw then restarts only the child gateway. Updating AlphaClaw itself must restart the container — so before exiting it writes a marker file to the persistent volume, and the next boot replays the install, because on ephemeral filesystems the freshly-copied files were themselves lost in the restart. A strategy detector picks the right story per platform (Render, Railway, Docker, managed, git-pinned) — and git-pinned installs get told to redeploy instead.
- alphaclaw-version.js touches — strategy detection, self-install, restart orchestration.
- openclaw-version.js touches — the child's update: copy trick + gateway restart, guarded by an in-progress flag.
- self-dependency.js watches — finds who installed AlphaClaw and how it's pinned; one boolean (git vs npm) gates the whole update UX.
Full roster
Every capability, grouped by job. touches mutates the hosted agent's world; watches only observes.
| Component | What it does | |
|---|---|---|
| Lifecycle | ||
| gateway.js | touches | Spawns, restarts, and configures the OpenClaw gateway child; owns the managed MCP entry. |
| watchdog.js | touches | Health polling, crash classification, crash-loop detection, auto-repair, safe-mode observation. |
| startup.js | touches | The onboarded boot sequence: prompts, env, channels, gateway, watchdog — in that order. |
| bin/alphaclaw.js | touches | CLI: start, git-sync, telegram topics, doctor completion callback; installs shims and cron on boot. |
| alphaclaw-version.js / openclaw-version.js | touches | In-place updates for harness and agent via the temp-install + copy trick. |
| Boundary | ||
| routes/auth.js + login-throttle.js | watches | Password gate, HMAC session cookie, persistent two-tier lockout. |
| routes/proxy.js | watches | Routes dashboard and /v1 traffic to the loopback gateway; cookie stripping; bearer auth. |
| webhook-middleware.js + webhooks.js | touches | Webhook CRUD, transform-module scaffolding, request normalization and logged relay. |
| routes/pairings.js | touches | Channel and device pairing approvals; the one-time CLI auto-approve latch. |
| gmail-push.js + gmail-watch.js | touches | Gmail Pub/Sub push intake and guided watch setup. |
| routes/browse/ | touches | Browser file explorer: read, edit, diff, per-file git restore; locked/protected path policy. |
| State & sync | ||
| hourly-git-sync.sh + cli/git-runtime.js | touches | The hourly backup clock with runtime-noise filtering. |
| scripts/git + git-askpass | touches | The credential shim: plain git works for the agent, token injected only inside the repo. |
| openclaw-config-restore.js | touches | Boot-time restore of a missing openclaw.json from the remote. |
| onboarding/import/ | touches | Workspace import: scan, secret detection, review, apply-with-scrubbing. |
| env.js | touches | .env read/write/watch with self-write loop guard; masked logging. |
| Injected into the agent | ||
| core-prompts/AGENTS.md + TOOLS.md | touches | The stamped discipline: no YOLO changes, plan-before-build, commit receipts, harness self-service. |
| skills/gog-cli/ + gog-skill.js | touches | Google Workspace skill, assembled from only the services actually connected. |
| plugin/usage-tracker/ | watches | The informant: an OpenClaw plugin logging every model call to the shared ledger. |
| Observation & advice | ||
| doctor/ | watches | LLM workspace audit with fingerprint-gated reuse, prompt-budget truncation warnings, token-verified fix completion. |
| cost-utils.js + db/usage/ | watches | Prices the token ledger; per-agent/session/run breakdowns. |
| cron-service.js | watches | Cron run history, trends, calendar. |
| watchdog-notify.js | watches | Incident notices over the agent's own paired channels. |
| watchdog-terminal.js | touches | Live shared shell in the browser. |
The dashboard — 15 tabs (routes/): General, Agents, Chat, Browse, Usage, Cron, Nodes, Watchdog, Doctor, Models, Providers, Envars, Webhooks, Telegram, plus the Welcome wizard. 198 Preact components, no framework build — htm tagged templates. | ||