Architecture

Cavalry runs as three long-lived processes backed by Postgres and an S3- compatible object store. Each process has a distinct failure-isolation profile; you can scale them independently.

Processes

  • apps/web — Next.js control plane. Serves the UI, the tRPC API, and inbound webhooks (GitHub App, Slack interactions).
  • apps/gateway — Hono HTTP service. Every install flows through here. Evaluates policy, serves cached artifacts, proxies upstream registries, and exposes the MCP endpoint.
  • services/worker — pg-boss-backed background runner for git syncs, audit webhook delivery, and Slack approval posts.

Shared infrastructure

  • PostgreSQL 16 — single source of truth for all metadata. pg-boss creates its own schema; Cavalry uses the public schema.
  • S3-compatible storage — content-addressed tarballs for every published and proxied skill. MinIO works locally.

Data flow: developer installs a skill

  1. Developer runs cavalry install tessl:stripe/stripe.
  2. CLI resolves the token + gateway URL, sends GET to /v1/proxy/tessl/stripe/stripe/:version/artifact.
  3. Gateway authenticates the token, loads the org's policies, and calls the pure policy engine. On deny it returns 403 with problem+json; on pending approval it creates an approval row and returns 202; on allow it proceeds.
  4. Cache hit? Serve from storage. Cache miss? Fetch upstream, content-address, store, record install + audit event.
  5. CLI streams the tar.gz into .cavalry/skills/<ns>/<name> and verifies the sha256.

Data flow: git-backed skill sync

  1. Platform team installs the Cavalry GitHub App on their org.
  2. They connect a repo as a skill source; Cavalry probes cavalry.yaml and kicks off an initial sync.
  3. Developer pushes a tag matching the configured pattern ({skill}/v{version} by default).
  4. Webhook verifies the HMAC signature, dedupes by delivery id, and enqueues a git-sync job.
  5. Worker: acquires a Postgres advisory lock, reads the skill directory via the provider API (no clone), builds a deterministic tarball, inserts an immutable skill_version row, emits skill.published.
  6. Force-pushed tags are detected and raise a skill_repo.force_push_detected security event. The existing version is never re-derived.

Security boundaries

  • Cavalry never writes to customer git repositories on the content path. Any UI-driven edit opens a pull request.
  • Installs are always served from content-addressed storage. A git or upstream outage does not affect previously-synced installs.
  • skill_versions are immutable. Once inserted, they are never updated. Force-pushes raise an alert instead of rewriting history.
  • Secrets (registry tokens, Slack bot tokens, webhook signing keys) are envelope-encrypted at rest via AES-256-GCM keyed off CAVALRY_ENCRYPTION_KEY.