agentleFS
vaultysvaultys/VaultysClaw/CLAUDE.md

VaultysClaw

CLAUDE.md84 starsChanged 6 months agoMITView on GitHub

VaultysClaw is an agent identity and trust platform. A control plane (Next.js + WebSocket server) maintains an append-only ledger of signed capability certificates bound to VaultysId DIDs, and decides what every Actor — agent, device, sensor, or human — is allowed to do. Clients connect over WebSocket, prove their identity with a Challenger handshake, and receive certificates they can verify offline. Monorepo: pnpm workspaces + Turborepo. Outside the pnpm workspace:

  • Reads credentials
  • Installs packages

The file

We split this CLAUDE.md into the rules it gives an agent

1 rule. About 0 are common, 0 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    packages/policy and packages/trust stay pure: No Prisma, Next.js, or WebSocket coupling.

    line 209

≈ “Common” is an estimate: at least 1 in 5 of the 26,980 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
CLAUDE.md

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Overview

VaultysClaw is an agent identity and trust platform. A control plane (Next.js + WebSocket server) maintains an append-only ledger of signed capability certificates bound to VaultysId DIDs, and decides what every Actor — agent, device, sensor, or human — is allowed to do. Clients connect over WebSocket, prove their identity with a Challenger handshake, and receive certificates they can verify offline.

Monorepo: pnpm workspaces + Turborepo.

PackageDescriptionCLAUDE.md
packages/policyCertificate wire format (sign/verify/pack), AgentCapability, CertScope, resource limits, runtime enforcement gates. Pure, no I/O.→
packages/trustTrust ledger engine: ABAC/multi-certificate permission resolution (resolvePermission) over the CapabilityCertificate ledger. Pure, no I/O.→
packages/sharedThe webhook event catalog + the LLM provider union. Deliberately tiny.→
packages/controlplaneThe control plane: Next.js App Router admin console + WebSocket server, Prisma/Postgres, the certificate ledger.→
packages/sdkTypeScript client for the control plane's protocol — handshake, capability state, certificate-status refresh, resolvePermission. The counterpart of sdk-go/.→
packages/webhook-dispatcherStandalone worker: consumes events from BullMQ, signs them (HMAC) and POSTs to endpoints; also fans out to Apprise notification channels.→
packages/videosNarrated demo videos of the console: Playwright drives the real control plane on its own stack (docker/video.env, 3013 / ws 8093 / pg 5436) with a live simulated fleet, then a Remotion intro/outro + ffmpeg mix. Same pipeline as VaultysHub's.→
packages/simulatorFleet simulator: thousands of real-VaultysId Actors — plus the people who own them — driven at a live control plane, on its own isolated stack.→

Outside the pnpm workspace:

DirectoryDescription
sdk-go/Go client SDK — authz (a port of resolvePermission), grant (offline packcert verification), rules (signed rule sets).
vaultysclaw-sensor/Go workload sensor: detects local AI/agent processes and reports classified telemetry to the control plane. Also hosts the tier-1 interception proxy. What it recognises as AI is data, not code: the built-in rules are internal/config/default-catalog.yaml (embedded), extended by a hot-reloadable operator catalog. Add a newly-released harness to a catalog file, never to the detector — see vaultysclaw-sensor/docs/DETECTION_CATALOG.md.
conformance/The TS↔Go contract. permission-vectors.json (37 cases) is run by both packages/trust and sdk-go/authz; capability-names.json (31 cases) by both packages/policy and sdk-go/capability; grant-fixture.json, rules-fixture.json and kindconfig-fixture.json are TypeScript-signed fixtures the Go side verifies. Never change a fixture without re-running both suites.
docs-site/Docusaurus documentation site.

Commands

# Development
pnpm install
pnpm controlplane:dev          # docker up --wait + control plane dev server
pnpm controlplane:docker:up    # just its docker stack (postgres 5433 / redis 6381 / apprise 8000)
pnpm controlplane:docker:down
pnpm controlplane:webhook:dev  # webhook dispatcher against the controlplane schema (own terminal)
pnpm sensor:start              # the Go sensor against a local collector

# Fleet simulator — its own isolated stack (postgres 5434 / control plane 3003, ws 8083), never
# your dev database. docker/simulator.env is the single source of truth for its coordinates.
pnpm simulator:up              # database + migrations + build + control plane
pnpm simulator:demo            # 2,000 estate + 5,000 agent Actors against it, owned by 1,400 people
pnpm simulator stats           # what that control plane currently holds
pnpm simulator people          # (re)mint the human population and reassign agent ownership
pnpm simulator admin --passphrase "…"   # mint an admin human + export its VaultysID for the browser
pnpm demo:ecw                  # ECW demonstrator: drone fleet + drone console at localhost:3012
pnpm simulator:down            # stop, keeping the data ( :nuke also deletes the volume )

# Demo videos — their own stack again (docker/video.env), see packages/videos/CLAUDE.md
pnpm video:up                  # database + migrations + build
pnpm generate:videos           # → packages/videos/.generated-videos/<name>.<lang>.mp4 + .srt

# Build / quality
pnpm build                     # all packages via Turborepo
pnpm lint
pnpm type-check
pnpm format

# Testing — supported suites are per-package; root __tests__ contains excluded legacy tests
pnpm test                                            # turbo run test, all packages
pnpm --filter @vaultysclaw/policy test
pnpm --filter @vaultysclaw/trust test                # includes the conformance vectors
pnpm --filter @vaultysclaw/controlplane test
pnpm --filter @vaultysclaw/webhook-dispatcher test
cd sdk-go && go test ./...                           # the Go half of conformance
cd vaultysclaw-sensor && go test ./...

The dispatcher must point at the same Postgres the control plane writes to, not just one with the same schema — otherwise jobs are consumed and every event reports zero targets while the console shows an active subscription. controlplane:webhook:dev sources packages/controlplane/.env for exactly this reason; don't write that URL down a second time.

packages/webhook-dispatcher has no Prisma schema of its own — run pnpm controlplane:webhook:prisma (or the controlplane:webhook:dev script, which does it for you) to copy the control plane's schema in and generate a client, or its type-check and tests fail on a missing PrismaClient export.

Communication Protocol

Clients connect to the control plane via WebSocket. Messages follow the typed envelope in packages/controlplane/lib/protocol.ts — deliberately small: identity, registration, the certificate/status protocol, actor_config, and sensor_telemetry.

Actor lifecycle:

  1. Client connects → register → VaultysId Challenger handshake (auth_challenge)
  2. Unknown DID → PendingRegistration row + registration_pending; known DID → auth_complete
  3. Admin approves, choosing capabilities → the control plane starts a second, independent service: "certificate" Challenger exchange (cert_challenge) → cert_issued
  4. A client re-checks its grant with cert_status_request → a control-plane-signed cert_status_response it can verify, cache, or staple
  5. Kind-specific config (and signed policy artefacts) arrive as actor_config

Certificates are signed artefacts, not session state: packages/policy verifies them with no network and no database. See docs/CERTIFICATE_WEB_OF_TRUST.md.

Capabilities

A capability is either a built-in (a closed list in packages/policy/src/types.ts) or an admin-defined custom vendor:action name from the control plane's registry (docs/CUSTOM_CAPABILITIES.md). Both travel through identical machinery — the same certificates, CertScope scoping, expiry, revocation and resolvePermission.

Three things to know before touching this area:

  • AgentCapability is no longer a closed union, so exhaustiveness checking does not apply. A switch or Record<AgentCapability, …> over it silently stops being checked instead of failing to compile — always give such a map an explicit fallback.
  • Never validate a capability name by hand. assertValidCapabilityName / isCustomCapability in packages/policy are the only grammar, mirrored in sdk-go/capability and pinned by conformance/capability-names.json. Changing the grammar means changing both and the table.
  • Deleting a registry entry is a mass revoke. handleCertStatusRequest filters held custom capabilities against the live registry before signing a cert_status_response, so a deleted name stops resolving on every holder's next refresh. That signed response — not the stored certificate row — is what a client keeps.

Kill switches

The reversible emergency control, alongside (not instead of) revocation: an admin can suspend every grant org-wide or per-workspace and put it all back with no certificate re-issuance.

  • Nothing is written to the certificate ledger. Suspension is computed from a separate KillSwitch row at the moment a decision is made — packages/controlplane/lib/kill-switch.ts is the single predicate, and every enforcement point calls it. Revocation stays the one-way ledger write it always was.
  • CertificateStatus is still the closed four-value union. A suspended certificate is signed as revoked while its row stays active. No new state means packages/policy, packages/trust, sdk-go/ and the conformance/ fixtures are untouched by this feature — if a change here starts wanting a fifth status, reconsider the change rather than the fixtures.
  • Humans are always exempt. admin_console_access is itself a certificate capability, so a switch that covered humans would lock every admin out of the only UI that can disarm it.

See packages/controlplane/CLAUDE.md → "Kill switches" for the four enforcement points and the sensor-telemetry tradeoff.

Webhooks & Notification Channels

One event pipeline, two kinds of delivery. A domain event is recorded in the audit log and enqueued on a BullMQ queue; a standalone worker delivers it as a signed HTTP POST and as a rendered human-facing alert through Apprise.

domain event → recordEvent()          → AuditLogEntry row (awaited)
 (controlplane/lib/audit.ts)          → enqueueWebhook() → BullMQ "webhooks" (Redis)
                                          → webhook-dispatcher:
                                             load active Webhook subscriptions → filter by event
                                             → sign (HMAC-SHA256) + POST
                                             load active NotificationChannels → render
                                             → POST to the Apprise API
  • Event catalog is the single source of truth: packages/shared/src/webhooks.ts (WEBHOOK_EVENTS, WebhookEventDef, WebhookJob, WEBHOOK_QUEUE_NAME, getWebhookEvent).
  • Emit via recordEvent({ eventType, payload, performedBy, targetType, targetId }) (packages/controlplane/lib/audit.ts) — never enqueueWebhook directly from a domain site. One call drives both the audit trail and delivery.
  • Sanitized payloads: build with an explicit per-entity helper in packages/controlplane/lib/webhook-payloads.ts — allow-lists only, never a secret. enqueueWebhook additionally runs stripSensitive as defence in depth.
  • BullMQ prefix: the control plane's producer uses prefix: "vaultysclaw-controlplane"; a dispatcher instance serving it must set BULLMQ_PREFIX to the same value.
  • Requires Redis. Producers are fire-and-forget and no-op when REDIS_URL is unset.

Adding or changing a webhook event — ALWAYS update the docs

The /admin/integrations/webhooks/docs reference is generated from data you must keep current. Whenever you add, remove, or change the payload of an event, do all of this in the same change:

  1. Catalog — add/edit the entry in packages/shared/src/webhooks.ts (type, label, description, group). This drives both the config UI and the docs.
  2. Emit — add/adjust the recordEvent call at the domain site.
  3. Payload builder — update the matching helper in packages/controlplane/lib/webhook-payloads.ts (explicit allow-list — never add a secret field).
  4. Notification template — add a renderer to RENDERERS in packages/webhook-dispatcher/src/render.ts, or the event silently never reaches a channel.
  5. Docs example — update EXAMPLE_PAYLOADS in packages/controlplane/lib/webhook-docs.ts. A new event with no entry falls back to {} in the docs — that is a bug, not acceptable.
  6. Verify — confirm every event has a non-empty, secret-free example, and pnpm type-check is clean.

Note stripSensitive matches the substring apikey case-insensitively, so a boolean field named hasApiKey is silently deleted from delivered payloads. Name such flags hasProviderKey.

Environment Variables

VariablePackagePurpose
DATABASE_URLcontrolplane, webhook-dispatcherPostgreSQL connection string (Prisma)
REDIS_URLcontrolplane, webhook-dispatcherRedis URL for the BullMQ webhook queue
BULLMQ_PREFIXwebhook-dispatcherMust match the producer's prefix (vaultysclaw-controlplane)
WEBHOOK_TIMEOUT_MSwebhook-dispatcherPer-endpoint delivery timeout (default 10000)
APPRISE_API_URLcontrolplane, webhook-dispatcherSelf-hosted Apprise API base URL. Unset turns Notification Channels off entirely; webhook delivery is unaffected.
NEXTAUTH_URL / APP_URLcontrolplaneBrowser-facing base URL; used to build adminUrl deep links (APP_URL wins)
NEXTAUTH_SECRETcontrolplaneNextAuth session secret
CONTROLPLANE_PORT / CONTROLPLANE_WS_PORTcontrolplaneHTTP + WebSocket ports (defaults 3001 / 8081)
LITELLM_BASE_URL / LITELLM_MASTER_KEYcontrolplaneDeployment-time fallback for the Model Registry. The Setting rows an admin edits under Integrations → Models win, and the master key is stored encrypted there (lib/vault.ts).

Design rules

  • packages/policy and packages/trust stay pure. No Prisma, Next.js, or WebSocket coupling; signing takes a VaultysId, enforcement takes an injected clock. packages/controlplane is the only place their outputs get persisted or driven by I/O.
  • Humans are Actors (kind: "human"), not a separate identity or permission table. There is no role field anywhere — access is a ledger lookup (lib/access-control.ts's hasCapability).
  • A Server Action must authorize itself. Next.js dispatches an action as a POST to its own endpoint without re-running the layout it is defined under, so the admin_console_access gate in app/admin/layout.tsx does not protect it. Start every mutating admin action with await requireAdmin() (lib/require-admin.ts).
  • Never change a conformance/ fixture on one side only — the TS and Go suites both consume them, and that is the entire point.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.