Core Security Properties
These four properties are enforced at every layer of the stack — cryptographic, application, and database.
- Server never sees plaintext. All encryption and decryption happens client-side.
- Closed, invite-only enrollment. No public discovery. Every device is explicitly approved by the owner.
- Device-bound keys. Private keys are generated locally and never leave the device.
- Strict tenant isolation via RLS. Row-Level Security policies on every database table prevent cross-tenant access.
System Architecture
Components
Clients
AgentVault supports three client types, all sharing the same cryptographic library (@agentvault/crypto):
Owner App (Expo Universal)
Owner App (Expo Universal)
The owner app runs on iOS, Android, and web from a single Expo codebase. It handles:
- Authentication via Clerk (JWT issuance, session management)
- Key generation (Ed25519 identity + X25519 ephemeral keypairs)
- Double Ratchet encryption for every outbound message
- Device management (invite, approve, revoke)
- Key storage in platform-appropriate secure storage (SecureStore on native, IndexedDB on web)
Agent Plugin (@agentvault/agentvault)
Agent Plugin (@agentvault/agentvault)
The Node.js plugin integrates with OpenClaw and other agent frameworks:
- 3-line configuration in the agent’s config file
- Automatic enrollment on first run (key generation, invite consumption, fingerprint display)
- Persistent encrypted state on disk for subsequent runs
- WebSocket connection for real-time bidirectional messaging
- Message handler that decrypts inbound messages, passes them to agent logic, and encrypts responses
Client SDK (@agentvault/client)
Client SDK (@agentvault/client)
A standalone TypeScript SDK for third-party integrations:
- API key authentication (no Clerk dependency)
- TOFU key exchange (Trust On First Use)
- Double Ratchet E2E encryption via the shared crypto library
- Programmatic access to all AgentVault APIs
Backend (FastAPI)
The backend is a Python FastAPI application that handles:| Responsibility | Details |
|---|---|
| Enrollment | Invite generation, token validation (BLAKE2b hashes only), device approval |
| Message relay | Stores ciphertext in PostgreSQL BYTEA columns, relays via WebSocket |
| WebSocket | Real-time bidirectional relay using Redis pub/sub for horizontal scaling |
| Tenant isolation | RLS policies on every table, tenant_id scoping on every query |
| Rate limiting | Redis-backed limits (enrollment: 5/IP/10min, messaging: 60/min) |
Database (PostgreSQL)
All data is stored in PostgreSQL 16 with Row-Level Security enabled on every table:- tenants — Tenant identity and status
- users — Clerk-authenticated users with RBAC roles
- devices — Device identity keys (public only), fingerprints, status
- invites — BLAKE2b hashed tokens (raw tokens never stored)
- conversations — Owner-to-agent session metadata
- messages —
header_blob(BYTEA) +ciphertext(BYTEA). No plaintext columns exist.
Cache and Pub/Sub (Redis)
Redis 7 serves two functions:- WebSocket relay — Redis pub/sub routes messages between connected clients, enabling horizontal scaling across multiple backend instances.
- Rate limiting — Sliding window counters for enrollment, polling, and messaging endpoints.
Cryptographic Primitives
| Function | Primitive | Why |
|---|---|---|
| Key exchange | X25519 (Diffie-Hellman) | Industry standard via libsodium crypto_scalarmult |
| Signing | Ed25519 | Device identity keys, proof-of-possession during enrollment |
| Symmetric encryption | XChaCha20-Poly1305 | 192-bit nonce eliminates nonce reuse risk (unlike AES-GCM’s 96-bit nonce) |
| KDF | HKDF-SHA-512 | Ratchet key derivation |
| Hashing | BLAKE2b | Invite token hashing, device fingerprints |
XChaCha20-Poly1305 was chosen over AES-256-GCM specifically because its 192-bit nonce is safe to generate randomly with negligible collision probability. In a high-volume messaging system, AES-GCM’s 96-bit nonce creates a reuse risk that would result in full plaintext recovery. If FIPS compliance is later required, AES-256-GCM is a swap, not a rewrite.
Protocol Stack
Double Ratchet (1:1 Messaging)
Every owner-to-agent conversation uses the Double Ratchet protocol (the same algorithm underlying Signal):- X3DH key agreement during enrollment establishes a shared secret
- Symmetric ratchet advances the chain key with every message
- DH ratchet rotates the key agreement with every reply
- Forward secrecy — old message keys are deleted after decryption
Message Flow
Infrastructure
| Component | Service | Notes |
|---|---|---|
| App server | DigitalOcean Droplet | 2 vCPU / 4GB, Docker deployment |
| Database | DO Managed PostgreSQL 16 | Automated backups, SSL, connection pooling |
| Cache/PubSub | DO Managed Redis 7 | TLS (rediss://), pub/sub for WebSocket relay |
| Auth | Clerk | JWT issuance, session management, custom domain |
| Frontend | Expo (EAS Build) + Vercel | Native apps via EAS, web SPA on Vercel |
| DNS/SSL | Cloudflare | Free tier, DDoS protection |
Monorepo Structure
What’s Next
Zero-Knowledge Architecture
Deep dive into what the server can and cannot see.
Threat Model
Security goals, threat actors, and mitigations.
Protocol Flows
Visual sequence diagrams for enrollment, messaging, and device management.