Architecture
Provenonce is split into three independent services. Each can be deployed, scaled, and replaced independently.
Beats is independently usable as a public clock/timestamp service: an integrator can call Beats APIs without creating an agent in the Registry.
System Overview
┌─────────────────────────────────────────────────────────┐
│ AI Agent (SDK) │
│ @provenonce/sdk — BeatAgent class │
│ • Registers (with or without wallet) │
│ • Purchases SIGIL (identity classification) │
│ • Sends heartbeats (paid liveness proofs) │
│ • Verifies passports locally │
└──────────┬──────────────────────┬───────────────────────┘
│ HTTPS │ HTTPS
▼ ▼
┌─────────────────────┐ ┌────────────────────────────────┐
│ Beats Service │ │ Registry Service │
│ beats.provenonce.dev│ │ provenonce.io/api/v1/* │
│ │ │ │
│ • Hash chain work │◄─│ • Agent state (Supabase) │
│ • Solana anchors │ │ • Registration + wallets │
│ • SPL Memo write │ │ • SIGIL + heartbeat │
│ • Stateless (no DB)│ │ • Ed25519 signed passports │
│ │ │ • Imports anchors from Beats │
└─────────┬───────────┘ └──────────┬─────────────────────┘
│ │
▼ ▼
┌─────────────────────┐ ┌─────────────────────┐
│ Solana │ │ Supabase │
│ SPL Memo anchors │ │ Agent state │
│ │ │ Anchors (verified) │
└─────────────────────┘ └─────────────────────┘Service Responsibilities
| Service | Purpose | Database | Deploys |
|---|---|---|---|
| Beats | Sequential hash chain + Solana anchors | None (stateless) | beats.provenonce.dev |
| Registry | Agent identity, SIGIL, heartbeats, passports | Supabase | provenonce.io |
| SDK | Client library for agents | None | npm @provenonce/sdk |
Agents do not compute hash chains for heartbeats. The Beats service computes global anchors on Solana; agents interact with the Registry for identity, paid heartbeats, and proofs. Agents may compute sequential work only when they want to unlock spawning (temporal gestation).
Current Production Policy
- Registration can be no-wallet (identity-only) or wallet-bound.
- Paid routes enforce BYO wallet by default:
POST /api/v1/sigilPOST /api/v1/agent/heartbeatPOST /api/v1/agent/reissue-proof
- Agents registered without wallet can upgrade later via:
POST /api/v1/agent/walletchallenge + finalize flow
- Child registration requires
spawn_authorizationminted by parent spawn preflight.
Agent Lifecycle
Register Purchase SIGIL Heartbeat
────────► ────────────► ──────────►
(periodic)
┌──────────┐ ┌──────────────┐ ┌──────────────────────┐
│ Unborn │───►│ Registered │───►│ Active │
│ │ │ (DB record, │ │ (SIGIL purchased, │
│ │ │ opt. wallet)│ │ sending heartbeats) │
└──────────┘ └──────────────┘ └──────────┬───────────┘
│
Heartbeats lapse
│
▼
┌──────────────────────┐
Resume │ Stale │
◄────────│ (market-determined) │
heartbeat │ │
└──────────┬───────────┘
│ 60+ anchors missed
▼
┌──────────────────────┐
Resync │ Frozen │
◄────────│ (DMS enforced) │
└──────────────────────┘State Transitions
- Register — SDK creates agent identity in the database (with optional wallet)
- (Optional) Link wallet — No-wallet agents can attach BYO wallet later for paid routes
- Purchase SIGIL — Agent selects an identity class (
narrow_task,autonomous,orchestrator) and pays via on-chain transaction - Compute beats (free) — Agent computes/submits beat proofs to accumulate spendable spawn balance
- Spawn children (optional) — Parent mints spawn authorization, child registers, parent finalizes spawn
- Heartbeat — Agent sends periodic heartbeats with payment; each heartbeat returns a fresh Ed25519-signed Passport (24h validity)
- Stale — If an agent stops sending heartbeats, it becomes stale. Standing is market-determined. No penalty yet.
- Frozen — If an agent misses 60+ consecutive anchors, the DMS cron freezes it. Heartbeats are rejected.
- Resume — A stale agent resumes by sending a heartbeat. A frozen agent must first resync.
Three-Layer Identity
Every agent has three independent identity layers:
┌─────────────────────────────────────────────┐
│ Layer 1: API Key (pvn_...) │
│ • HMAC-signed, stateless │
│ • Used for all API operations │
│ • Rotatable without identity change │
├─────────────────────────────────────────────┤
│ Layer 2: Beat Hash (0x...) │
│ • SHA-256 of registration data │
│ • Immutable, defines lineage │
│ • Parent → child chain │
├─────────────────────────────────────────────┤
│ Layer 3: Wallet (optional, multi-chain) │
│ • No wallet (default) — identity only │
│ • Operator-provided wallet (Model B) │
│ • Ethereum BYO (EIP-191 signature) │
│ • Private key never sent to server │
│ • Children are API-key identities (no child │
│ wallet assigned at registration) │
└─────────────────────────────────────────────┘Beat Counters
Registry exposes two beat counters with different meanings:
lifetime_beats: total beats ever accepted for the agentavailable_beats: spendable beats remaining for spawn costs
Spawn gating uses available_beats, not lifetime_beats.
Data Flow: Heartbeat
Agent Registry Supabase
│ │ │
│ 1. POST /agent/heartbeat │ │
│ { payment_tx }─────────►│ │
│ │ 2. Validate API key │
│ │ 3. Load agent state ────►│
│ │◄────────────────────────│
│ │ 4. Verify payment_tx │
│ │ 5. Get current anchor │
│ │ 6. Sign passport │
│ │ (Ed25519, 24h expiry) │
│ │ 7. Update heartbeat ───►│
│ │◄────────────────────────│
│◄── 8. { passport } │ │Data Flow: Passport Verification
Passports are Ed25519-signed and can be verified offline:
Agent / Verifier Registry
│ │
│ GET /api/v1/.well-known/ │
│ authority-key ─────────────────►│
│◄── { public_key_hex } ──────────────│
│ │
│ BeatAgent.verifyPassportLocally( │
│ proof, public_key_hex │
│ ) │
│ → true/false (no server needed) │Anchor Chain
The Beats service writes a new global anchor to Solana every minute. The Registry imports these anchors into Supabase. Heartbeats reference the current anchor, linking agent liveness to the on-chain timeline.
Beats Cron (every 1 min) Registry Cron (every 1 min)
│ │
▼ ▼
Read latest anchor Fetch latest from Beats
from Solana via fetchBeatsAnchor()
│ │
▼ ▼
Compute next anchor Verify + store in
(hash chain of prev + index) Supabase global_anchors
│
▼
Write SPL Memo
to Solana