Architecture
Provenonce is split into three independent services. Each can be deployed, scaled, and replaced independently.
System Overview
┌─────────────────────────────────────────────────────────┐
│ AI Agent (SDK) │
│ @provenonce/sdk — BeatAgent class │
│ • Registers (with or without wallet) │
│ • Purchases SIGIL (identity classification) │
│ • Sends heartbeats (paid liveness proofs) │
│ • Verifies lineage proofs locally │
└──────────┬──────────────────────┬───────────────────────┘
│ HTTPS │ HTTPS
▼ ▼
┌─────────────────────┐ ┌────────────────────────────────┐
│ Beats Service │ │ Registry Service │
│ beats.provenonce.dev│ │ provenonce.io/api/v1/* │
│ │ │ │
│ • VDF computation │◄─│ • Agent state (Supabase) │
│ • Solana anchors │ │ • Registration + wallets │
│ • SPL Memo write │ │ • SIGIL + heartbeat │
│ • Stateless (no DB)│ │ • Ed25519 lineage proofs │
│ │ │ • Imports anchors from Beats │
└─────────┬───────────┘ └──────────┬─────────────────────┘
│ │
▼ ▼
┌─────────────────────┐ ┌─────────────────────┐
│ Solana (devnet) │ │ Supabase │
│ SPL Memo anchors │ │ Agent state │
│ │ │ Anchors (verified) │
└─────────────────────┘ └─────────────────────┘Service Responsibilities
| Service | Purpose | Database | Deploys |
|---|---|---|---|
| Beats | VDF math + Solana anchors | None (stateless) | beats.provenonce.dev |
| Registry | Agent identity, SIGIL, heartbeats, lineage proofs | Supabase | provenonce.io |
| SDK | Client library for agents | None | npm @provenonce/sdk |
Agents do not compute VDF 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
(no deadline, no penalty)
│
▼
┌──────────────────────┐
Resume │ Stale │
◄────────│ (market-determined │
heartbeat │ standing) │
└──────────────────────┘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 lineage proof (24h validity)
- Stale — If an agent stops sending heartbeats, it becomes stale. Standing is market-determined, not server-enforced. No penalty.
- Resume — A stale agent resumes by sending a new heartbeat. No resync required.
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, chain-agnostic) │
│ • No wallet (default) — identity only │
│ • Solana self-custody (Model A, opt-in) │
│ • 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 lineage proof │
│ │ (Ed25519, 24h expiry) │
│ │ 7. Update heartbeat ───►│
│ │◄────────────────────────│
│◄── 8. { lineage_proof } │ │Data Flow: Lineage Proof Verification
Lineage proofs are Ed25519-signed and can be verified offline:
Agent / Verifier Registry
│ │
│ GET /.well-known/ │
│ provenonce-authority.json ──────►│
│◄── { public_key_hex } ──────────────│
│ │
│ Provenonce.verifyProofLocally( │
│ 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
(VDF of prev + index) Supabase global_anchors
│
▼
Write SPL Memo
to Solana