DashClaw Project Details (Governance Runtime)
July 10, 2026 · View on GitHub
DashClaw is decision infrastructure for AI agents. It provides the governance layer between agents and external systems: policy evaluation before execution, human approval when needed, durable action records, terminal outcome tracking, and evidence that operators can audit later.
DashClaw is not an agent framework and not an observability-only product. It does not try to help agents do work. It governs work that agents are about to do or claim they completed.
What this file is authoritative for
This file is the source of truth for DashClaw's product boundary, runtime architecture, primary surfaces, and integration model.
Generated inventories remain authoritative for generated facts:
| Fact | Source |
|---|---|
| Complete API route inventory | docs/api-inventory.md and docs/api-inventory.json generated from app/api/**/route.ts |
| Stable OpenAPI contract | docs/openapi/critical-stable.openapi.json generated by npm run openapi:generate |
| SDK parity by domain | docs/sdk-parity.md |
| Durable execution finality spec | docs/architecture/durable-execution-finality.md |
As of this verification (2026-07-07), generated API inventory reports 120 routes: 38 stable, 17 beta, 65 experimental.
Product boundary
DashClaw owns
- Attribution: which agent attempted which action, with
agent_id, optionalagent_name, org scoping, and fleet lineage — every row carries its harness session (harness_session_id), subagent leaves carry their instance uuid (subagent_uuid), and spawn rows carry the spawned agent's uuid (outcome_metadata.spawned_agent_uuid), so a multi-agent fan-out is joined from evidence at read time, never guessed. - Policy decisions: allow, block, or require approval, evaluated before the action proceeds — mechanically enforced on hook/capability surfaces, honored by cooperative callers (
docs/architecture/enforcement-boundary.md). - Human-in-the-loop approval: approval queues and chat/native approval bridges.
- Action ledger: durable
action_recordsrows with status, risk, reasoning, assumptions, costs, tokens, and trace data. - Terminal outcomes: one-shot action outcome finality through
GET/POST /api/actions/:actionId/outcome. - Operational signals: stale actions, lost confirmations, assumption drift, degraded integrations, and policy-relevant alerts.
- Evidence: replayable action detail, traces, graphs, artifacts, and evidence bundles.
DashClaw does not own
- Agent planning or task execution.
- Wallets, chain anchoring, or on-chain proof systems.
- Tool/provider-specific business logic.
- Cross-project canonical key standards, except as caller-supplied fields that DashClaw can store and enforce, such as
idempotency_key.
Primary UI surfaces
| Surface | Path | Purpose |
|---|---|---|
| Approvals inbox | /approvals | The one primary human surface: what your agent just tried, what is frozen and waiting on you, two buttons per item. Multi-select inline + bulk approve/deny over a capped, SSE-live event stream; a flood banner collapses approval storms with pause-rule and bulk-resolve controls, and pending approvals are never auto-resolved. |
| Decisions | /decisions | Visual ledger of governed actions with risk composition, matched policies, approver, outcome status, and replay links. |
| Replay | /replay/[actionId] | Action-level evidence view for a single governed decision. |
| Policies | /policies | Interruption-contract cockpit: a plain-English contract of when agents interrupt you (grants, shields as "Add protection"), a review feed of silently-recorded warns with Fine / Always allow / Tighten verdicts, plus policy generation, simulation, calibration review, and import/proof surfaces. |
| Calibration | /calibration | Calibrated interruption controller: operator sets a target false-interruption rate; an online adaptive-conformal threshold learns from approve/deny verdicts (distribution-free bound), with anytime-valid per-agent e-process alarms. Shadow mode records what it would do on every decision (_calibration sibling); active mode is tighten-only (raises to require_approval, never loosens, never touches block); loosening evidence routes to the /policies proposal rails. Default off; admin-gated POST /api/calibration/controller. Theory: docs/architecture/governance-core-theory.md. |
| Setup | /setup | Readiness verification, instance health, setup proof, migration helper entry points, write-path health (live doctor canary verdicts proving the heartbeat/action-ledger/guard-audit write paths land), the live host canary (hourly external probes of the production hosts as a real client, reported via POST /api/live-canary), and enforcement liveness: the probe verdict card (#enforcement-liveness, holding/stale/broken) proving the pretool hook seam actually holds held actions, where a probe that has silently stopped running renders stale, never green. |
| Doctor | /doctor | In-app diagnostics from GET /api/doctor, grouped by category, with one-click fixes (admin keys) via POST /api/doctor/fix. |
| Connect | /connect | Path to first governed action, including hosted trial provisioning when DASHCLAW_HOSTED=true. |
| Proof | /proof | Self-governance evidence: the AI maintainer's own changes run through a live DashClaw instance. Supporting evidence, linked from the footer and about context, not the front door. |
Runtime architecture
DashClaw is organized into two layers to keep the governance boundary clear.
Tier 1: Core governance runtime
These routes define the minimum DashClaw category. They are stable or runtime-critical and should remain small, well-documented, and backward compatible.
| Route | Purpose | Notes |
|---|---|---|
/api/guard | Policy evaluation before execution | Returns allow, block, or require approval — an advisory decision point the calling surface enforces (see docs/architecture/enforcement-boundary.md). |
/api/actions | Create, list, and delete action records | POST accepts idempotency_key; duplicate (org_id, idempotency_key) creates return the existing row with idempotent_replay: true. |
/api/actions/:actionId | Read or PATCH legacy lifecycle outcome fields | Legacy completion/update path. Durable finality uses the separate /outcome route. |
/api/actions/:actionId/outcome | Durable terminal outcome | One-shot pending -> completed/partial/failed; lost_confirmation is system-owned. |
/api/actions/:actionId/trace | Action trace | Read-only evidence path. |
/api/actions/:actionId/graph | Execution graph | Nodes and edges around an action, assumptions, and trace data. |
/api/approvals/:actionId | Human approval decision | Also reachable via legacy rewrite /api/actions/:id/approve. |
/api/assumptions | Reasoning integrity records | Assumption tracking linked to actions. |
/api/signals | Runtime/anomaly signals | Signal listing and detection outputs. |
/api/policies | Policy CRUD | Guard policy management, including the non_fabrication policy type. |
/api/policies/generate | Iterative natural-language policy generator | Dry-run returns { drafts, assumptions, clarifications } and never dead-ends; accepts answered clarifications to refine. Authored from Policies → Custom → AI generator. |
/api/policies/modes | Policy Modes catalog | GET lists the built-in operating modes (Claude Code, OpenClaw, SOC 2, …); each compiles to a pack of ordinary guard policies. See docs/policy-modes.md. |
/api/policies/modes/preview | Preview a mode | POST { mode_id } → generated policy list + decision summary + best-effort friction simulation. No writes; unknown mode → 400. |
/api/policies/modes/import | Apply a mode | POST { mode_id } (admin) compiles the mode into normal guard policies (active, _mode-tagged in rules); re-applying reactivates + refreshes existing-by-name policies (idempotent). Mirrors /api/policies/import. |
/api/policies/contract | Interruption contract view | GET renders the org's active policies into the plain-English ContractView (interrupts / silent / hard stops / grants / custom, with 7-day fire counts and a friction estimate). Backs the /policies cockpit. |
/api/policies/review | Review feed | GET returns warn decisions since the review cursor, grouped by action shape, plus recent interrupts. Backs the /policies "To review" queue. |
/api/policies/review/verdict | Review verdicts | POST { verdict, shape? } (admin): fine advances the cursor, always_allow mints a scoped allow-grant, tighten mints a protected-path / require-approval policy, mark_all_reviewed clears the queue. |
/api/calibration/controller | Calibrated interruption controller | GET snapshot (mode, target rate, calibrated θ, observed vs target, per-agent e-process alarms, adjudication events); POST (admin, audit-logged) sets mode off|shadow|active / target rate, resets an agent alarm or the calibrated state. Backs /calibration. Theory + guarantees: docs/architecture/governance-core-theory.md. |
/api/policies/proposals | Policy-tuning proposals | GET returns per-policy interruption stats (rolling window) + rule-based tuning proposals with evidence; POST { action: dismiss|undismiss, proposal_id, reason? } (admin) records dismissals. Accepting = the human PATCHes /api/policies; nothing auto-applies. Backs the /policies "Tuning proposals" section. |
/api/policies/tightening | Tightening proposals (findings → proposals) | GET computes proposals on read from ungoverned-allow guard decisions, grouped (action_type × riskLevel); POST { action: ratify|dismiss|undo, proposal_id, proposal, reason? } (admin): ratify creates the ACTIVE require_approval policy server-side, dismiss records why (content-stable tp_ ids stop re-proposing), undo removes the judgment but keeps a created policy. Decisions persist in tightening_proposal_decisions (drizzle 0042). Backs the /policies "Tightening proposals" section. |
/api/policies/loosening | Loosening proposals (the tightening mirror, roadmap v4.5) | GET computes proposals on read from interrupt-approval outcomes at (policy, action_type) grain — an envelope action type approved ~100% of the time (bar 0.95, minFired 10, minResolved 5) proposes a scope carve-out (relax_policy_scope); a policy always overridden with no surgical fix (protected_path, rate_limit, envelope-emptying) proposes deactivation (deactivate_policy); risk_threshold policies excluded (tuning owns that direction); synthetic traffic excluded in SQL. POST { action: ratify|dismiss|undo, proposal_id, proposal, reason? } (admin): ratify rebuilds the patch server-side from CURRENT rules and applies it (self-suppresses via the policy's updated_at evidence-window reset), dismiss records why (content-stable lp_ ids stop re-proposing), undo removes the judgment but keeps the change (change_kept). Decisions persist in loosening_proposal_decisions (drizzle 0051). Backs the /policies judgment-spine "Loosening" group. |
/api/integrity/jwks | Published signing public key (JWKS) | Public. Also at /.well-known/jwks.json. Used to re-verify proof receipts and compliance bundles. |
/api/integrity/verify | Re-verify a receipt or signed bundle | Public, stateless. POST { receipt } or { bundle } → { ok }. |
/api/health | System readiness | Public health/readiness surface. |
/api/keys | API key management | Stable key lifecycle and reveal path. |
/api/messages | Assumption-notification ack seam | Slim GET/PATCH surface the pretool hook uses to acknowledge assumption alerts. The full messaging / threads / handoffs product was removed in v5; only the assumption-ack residue survives, backed by agent_messages. |
/api/mcp | Streamable HTTP MCP endpoint | Remote MCP transport for DashClaw tool calls and resources. OAuth-protected (Bearer) for Claude custom connectors; x-api-key still works for managed agents. |
/api/oauth/* | OAuth 2.1 authorization server | DCR + PKCE S256 so the Claude consumer app can add /api/mcp as a custom connector. Public discovery at /.well-known/oauth-{authorization-server,protected-resource}. See docs/CLAUDE-DESKTOP-PLUGIN.md. |
Route aliases in next.config.js preserve legacy paths such as /api/actions/signals, /api/actions/assumptions, and /api/actions/:id/approve. New integrations should prefer the canonical routes above.
Tier 2: Governance extensions
These modules consume core runtime data and add operator value without changing the category boundary.
| Domain | Representative routes or surfaces | Purpose |
|---|---|---|
| Artifacts | /api/artifacts/* | Durable artifacts linked to actions, plus signed evidence bundles. GET /api/artifacts/evidence-bundle signs via app/lib/integrity/bundle (the compliance-era signed export folded into the Prove layer). |
| Capability invoke seam | GET /api/capabilities, /api/capabilities/[id]/invoke, /api/capabilities/[id]/access/check | The dashclaw_invoke enforcement seam: server-executed HTTP capabilities pass through guard + per-agent access rules + the action ledger before they run. Inert by default post-cull — there is no in-product create path; capabilities are fed by manual SQL. |
| Sessions and coverage | /api/sessions/*, GET /api/coverage, GET /api/agents/fanouts | Session lifecycle + retrospection used by the coding-agent hooks and SDK; per-turn expected-vs-recorded tool-use coverage (close_source provenance, explicit "no evidence" state); and a fan-outs view of recent multi-agent harness sessions. |
| Operations summary | GET /api/operations/summary | Read-only runtime metrics over the ledger. |
Durable execution finality (v2.13.3)
Durable finality closes the gap between "this action was approved" and "this action definitely completed."
| Primitive | Detail |
|---|---|
| State column | action_records.outcome_status with pending, completed, partial, failed, lost_confirmation. |
| Agent endpoint | POST /api/actions/:actionId/outcome records completed, partial, or failed. |
| Poll endpoint | GET /api/actions/:actionId/outcome returns current outcome plus elapsed_ms. |
| One-shot rule | First terminal outcome wins. Later POSTs return 409 { error: "outcome already set", current_status }. |
| Lost confirmation | /api/cron/outcome-sweep marks stale pending outcomes as lost_confirmation. |
| Timeout | Per-org DASHCLAW_OUTCOME_TIMEOUT_MINUTES setting, default 15, clamped [1, 1440]. |
| Idempotency | POST /api/actions accepts caller-supplied idempotency_key; duplicates replay the existing row. |
| SDKs | Node and Python expose report/get outcome helpers plus idempotency-key derivation helpers. |
Vercel Hobby cron runs the sweep daily. Operators who need tighter detection can run the same endpoint externally at their own cadence with Authorization: Bearer $CRON_SECRET, or use Vercel Pro with an hourly cron.
Agent identity (Phase 2 / 2b / 2c)
/api/guard resolves agent identity on three independent axes, each recorded on
its own column of guard_decisions and returned on the guard response. None
overloads verification_status; an absent or invalid token always fails soft to
the Phase 1 trust-on-assertion path (body agent_id), never blocking on
infrastructure failure. Full setup guide: docs/agent-identity.md.
| Phase | Question | Column | Mechanism |
|---|---|---|---|
| 2 — verification | Who signed the token? | verification_status | app/lib/jwks-verifier.ts verifies an Authorization: Bearer <JWT> against the issuer's JWKS ({iss}/.well-known/jwks.json, cached 1 h, 30 s circuit breaker, SSRF-guarded). EdDSA / RS256–512 / ES256–512. On verified, JWT sub overrides body agent_id. Values: `verified |
| 2b — replay | Has this token been reused? | replay_status | app/lib/repositories/jti-replay.repository.js records (issuer, jti) in jwt_replay_log (race-free ON CONFLICT DO NOTHING). First use unique, second replayed. Values: `not_applicable |
| 2c — binding | Is this token bound to this call? | act_status | app/lib/act-binding.ts recomputes a SHA-256 over the canonical (action, target, goal) tuple and compares it to the token's urn:dashclaw:act-binding claim. Values: `not_applicable |
Enforcement is mode-gated. Since v3.6 (2026-07-04) the verified-JWT defaults
fail closed — flipped while the verified fleet was measurably empty, so no
existing traffic changed behavior; API-key callers resolve not_applicable
and are never touched by these knobs:
| Env var | Modes | Default | Blocks on |
|---|---|---|---|
DASHCLAW_ALLOWED_ISSUER / DASHCLAW_JWT_AUDIENCE | (set / unset) | unset = any | restrict trusted issuers / validate aud |
DASHCLAW_JTI_REPLAY_PROTECTION | off / best_effort / required | required | replayed/exp_too_far always; unavailable/not_present only under required |
DASHCLAW_JTI_MAX_TTL_SECONDS | integer | 86400 | rejects tokens whose exp exceeds the cap (exp_too_far) |
DASHCLAW_ACT_BINDING | off / best_effort / required | best_effort | mismatch under best_effort+required; not_present/unsupported_typ/ctx_incomplete only under required |
DASHCLAW_ACT_BINDING_TYP | csv | action-binding/v1 | accepted binding typ allowlist |
Schema: drizzle/0008 (verification), 0010/0011 (replay), 0012 (action
binding). The legacy public-key pairing flow (/api/pairings, RSA) remains for
older integrations but is no longer the primary identity surface.
Non-fabrication & signed evidence
The non_fabrication guard policy adds a deterministic non-fabrication guarantee: given an action's outbound content and a source_of_truth (allowed/required facts, forbidden patterns, extract options), the verifier in app/lib/integrity/ confirms that every operational token (currency, date, percentage, and caller-registered patterns like account/invoice IDs) traces verbatim to an allowed fact, that every required fact is present, and that no forbidden pattern appears — returning pass or block with structured violations. It is fail-closed: any error or a missing/malformed source-of-truth blocks, and on_violation: require_approval routes through the existing multi-channel approval flow. Each decision is recorded in guard_decisions (new evidence column) with a signed, independently re-verifiable Ed25519 proof receipt, and the compliance exporter now emits a signed, hash-chained bundle instead of unsigned markdown/JSON. The instance signing key is hybrid (env DASHCLAW_SIGNING_KEY_JWK or auto-generated into server_signing_keys) and published at /.well-known/jwks.json; receipts and bundles re-verify via POST /api/integrity/verify. A signature proves integrity, the verdict, the ruleset version, and the issuer — not time-of-issuance (no trusted timestamp) or the semantic correctness of token-free prose. Schema: drizzle/0013. Crypto reuses the single canonicalization in app/lib/canonical-json.ts; the published Ed25519 keys use the same JWKS format the runtime's app/lib/jwks-verifier.ts already consumes, but receipt/bundle signing and verification run through app/lib/integrity/{sign,keys}.js on node:crypto directly.
Integration model
DashClaw is intentionally multi-surface. Claude Code hooks are one strong integration path, not the product identity.
| Path | Best for | Artifact |
|---|---|---|
| MCP server | MCP-capable agents, Claude Desktop/Code, managed agents, remote tool access | @dashclaw/mcp-server, POST /api/mcp |
| Claude custom connector (OAuth) | The Claude consumer app (web chat / Desktop / Cowork) — paste a URL, no API key in the UI | POST /api/mcp + /api/oauth/* (DCR + PKCE), docs/CLAUDE-DESKTOP-PLUGIN.md |
| Node SDK | JavaScript/TypeScript agents and apps | sdk/dashclaw.js, npm package dashclaw (version in sdk/package.json) |
| Python SDK | Python agents and backend workflows | sdk-python/dashclaw/client.py |
| Claude Code hooks | Coding-agent tool governance (incl. sub-agent spawns and delegated work; per-harness identity via installer-written --agent-id, sub-agents as distinct fleet identities by default — see hooks/README.md "Sub-agent governance & tracking") without per-call SDK code | hooks/, npm run hooks:install, plugins/dashclaw/.claude-plugin/ |
| Codex plugin | Codex coding-agent governance via field-compatible hook schema | cli/lib/codex/, dashclaw install codex, plugins/dashclaw/.codex-plugin/ |
| Hermes Agent plugin | Per-turn governance context injection, secret redaction, and session-lifecycle hooks | .hermes/hooks/, plugins/dashclaw/.hermes-plugin/, scripts/install-hermes-plugin.{sh,ps1} |
| OpenClaw plugin | OpenClaw lifecycle-native governance | packages/openclaw-plugin/ |
| REST API | Custom frameworks and direct integrations | app/api/**/route.ts, generated inventory/OpenAPI docs |
| Webhooks and approvals | Operator notification and external systems | Slack/Discord/Telegram adapters, webhook routes, approval bridges |
Webhook delivery formats per destination host: *.logic.azure.com gets the Teams Workflows envelope, and hooks.slack.com, discord.com, and events.pagerduty.com get platform-native payloads; every other destination receives the generic byte-identical JSON payload.
Framework examples exist for OpenAI, Anthropic, LangGraph, CrewAI, AutoGen, Claude Managed Agents custom tools, Claude Managed Agents MCP, and Claude Managed Agents MCP plus Governance Skill. See examples/README.md.
SDK surface area
DashClaw ships a Node SDK and a Python SDK. The DEPRECATED dashclaw/legacy subpath was removed in v5.0.0 as promised.
| Surface | Entry point | Version or role |
|---|---|---|
| Canonical Node SDK | import { DashClaw } from 'dashclaw' from sdk/dashclaw.js | npm package dashclaw; the SDK for all work (version tracked in sdk/package.json). |
| Python SDK | sdk-python/dashclaw/client.py | Broad Python surface with route-contract parity for critical domains. |
The canonical Node SDK currently exposes 31 public methods in sdk/dashclaw.js and the Python SDK 51 in sdk-python/dashclaw/client.py (both reproducible via npm run sdk:count — excludes the constructor and _-private methods). The Node surface includes:
- core governance:
guard,createAction,updateOutcome,getAction,approveAction,getPendingApprovals,waitForApproval,recordAssumption - durable finality:
reportActionOutcome,getActionOutcome,reportActionSuccess,reportActionFailure,reportActionPartial,deriveIdempotencyKey - action graph (
getActionGraph), risk signals (getSignals), security scanning (scanPromptInjection), sessions (createSession/getSession/updateSession/listSessions/getSessionEvents) - agent pairing/identity enrollment:
createPairing,waitForPairing - governed execution wrappers:
runGoverned,guardedFetch,actionContext - side-effect-free dry-run:
simulatePolicy(replays a proposed policy against recent historical actions) - team tasks (Node-only, fleets-and-teams amendment):
createTeamTask,appendTeamTaskEvent,updateTeamTask
Use docs/sdk-parity.md for domain-level parity and consolidation status.
Operations and deployment
Required local commands
| Command | Purpose |
|---|---|
npm run lint | ESLint. |
npm run docs:check | Validate source-of-truth doc metadata and generated-doc expectations. |
npm run route-sql:check | Guard against direct route SQL growth. |
npm run openapi:check | Ensure stable OpenAPI artifact is current. |
npm run api:inventory:check | Ensure generated API inventory is current. |
npm test -- --run | Full Vitest suite in CI mode. |
npm run sdk:integration:python | Python SDK integration harness, live-network cases skipped by default. |
PYTHONPATH=sdk-python python -m unittest discover -s sdk-python/tests -p "test_sdk_v2_surface.py" | Targeted Python v2 surface test. |
npm run bundles:refresh | Mirror the governance skill + hooks into plugins/dashclaw/ and rebuild the download zips. |
CI/CD expectations
Every PR to main should keep these clean:
npm run lintnpm run docs:checknpm run route-sql:checknpm run openapi:checknpm run api:inventory:checknpm test -- --run
Release-readiness passes may additionally run SDK integration checks, startup smoke checks, and migration checks when the target environment is safe.
Deployment runbooks
docs/hosted-deployment-runbook.md- the canonical hosted deployment guide (Neon, Vercel, Cloudflare Turnstile, DNS, cleanup, rollback; beginner-friendly). Supersedesdocs/ops/hosted-deployment.md, which is now a pointer.docs/HOSTED_TRIAL_RUNBOOK.md- the post-deploy flip checklist for the hosted trial / activation funnel.scripts/setup.mjsandscripts/init-self-host-env.mjs- local/self-host setup helpers.scripts/auto-migrate.mjs- idempotent migration runner used by deploy/setup paths.npm run doctor/dashclaw doctor- local and remote diagnostic entry points backed byapp/lib/doctor/.
Core libraries
| Library | Role |
|---|---|
app/lib/db.ts | Neon/Postgres connection. |
app/lib/org.ts | Org resolution, scoping, and roles. |
app/lib/guard.ts | Policy evaluation engine. |
app/lib/repositories/actions.repository.js | Action ledger, durable outcome, idempotency, trace/graph data access. |
app/lib/security.ts | Sensitive-data scanning and redaction. |
app/lib/events.ts | Org-scoped event publish layer. |
app/lib/signals.ts | Runtime signal/anomaly computation. |
app/lib/readiness.mjs | Setup/readiness checks. |
app/lib/doctor/ | Shared diagnostic engine for API, CLI, and local doctor scripts. |
app/lib/integration-health.ts | Integration credential health checks. |
app/lib/notification-adapters/ | Slack, Discord, Linear, GitHub, Email notification adapters. |
app/lib/telegramApprovals.ts | Telegram approval messages and inline callbacks. |
app/lib/discordApprovals.ts | Discord approval messages and interaction bridge. |
app/lib/capability-invoke.ts | Governed HTTP capability invocation (the dashclaw_invoke seam). |
app/lib/template-vars.ts | Template variable substitution. |
app/lib/billing.ts | Token-cost pricing helpers (backs guard cost estimation). |
app/lib/policy-generator.ts | Natural-language policy generation. |
app/lib/predictive-risk.ts | Statistical and optional LLM-assisted risk scoring. |
Category enforcement
DashClaw is decision infrastructure, not an agent framework.
Rule: if a feature helps an agent achieve a goal, it is outside the core runtime unless it is explicitly framed as a governed capability. If a feature helps an operator govern, approve, verify, audit, or recover agent actions, it belongs in DashClaw.