Spec lineage: this implements the fused design of the sibling specs The Kitty (Pear pot + WDK settlement) and PunditPay (QVAC paying pundit). This document describes what is actually built in this repository.
flowchart TD
subgraph CORE[src/core โ pure, deterministic, no I/O]
OPS[ops.js<br/>builders + structural validation]
RED[reducer.js<br/>invariant-enforcing state machine]
SPL[split.js<br/>ฮฃ-preserving payout math]
SET[settlement.js<br/>escrowless leg planner]
MON[money.js<br/>integer micro-USDโฎ]
CAN[canonical.js<br/>stable stringify + blake2b state hash]
end
subgraph P2P[src/p2p]
POT[pot.js โ TreblePot<br/>Corestore โ Autobase โ Hyperbee]
INV[invite.js โ treble1โฆ z32 codec]
end
subgraph WAL[src/wallet]
FAC[index.js โ createTrebleWallet<br/>+ Transaction Policy caps + bond accounts]
SIM[sim-wallet.js โ custom WDK WalletManager]
LED[sim-ledger.js โ disclosed local USDโฎ ledger]
end
subgraph AGT[src/agent]
STR[strategies.js โ 3 personas]
QBR[brains/qvac.js โ completion tool-calling]
HBR[brains/heuristic.js โ DISCLOSED fallback]
SEAT[seat.js โ AgentSeat: the seam]
end
UI[index.html + app.js โ Pear desktop]
CLI[src/cli.js โ demo / create / join]
RED --> POT
OPS --> POT
POT --> CLI & UI & SEAT
FAC --> SEAT & CLI & UI
SIM --> FAC
LED --> SIM
STR & QBR & HBR --> SEAT
SET --> CLI & UI & SEAT
Every peer feeds the same linearized ops through reduce(state, op, { from })
โ a pure function that never throws on input and rejects illegal ops with
deterministic reasons. from is the hex key of the Hypercore writer the op
arrived on, so authority is enforced by Hypercore signatures, not claims in
the payload.
Op lifecycle: open โ add-writer โ join โ stake โ pick โ lock โ vote(โ finality โ splits) โ settle, plus display-only notes (the agent's rationale rides a
pick.note).
Role capability matrix (enforced in the reducer, tested over the wire):
| capability | human member | AI agent member |
|---|---|---|
| join / stake / pick | โ | โ (identical rules) |
grant writers (add-writer) |
โ | โ agent-cannot-add-writers |
| lock at kickoff | โ | โ agent-cannot-lock |
| vote on the result | โ (if staked) | โ agent-has-no-result-authority |
- Corestore โ Autobase 7: each participant appends to their own input
core; the
applyhandler runs the reducer and writesstate+event/<seq>records to a Hyperbee view (valueEncoding: json). Because the view is derived only from view+nodes, Autobase's undo/reapply reordering stays correct. - Security-critical wiring:
host.addWriter()is called only when the reducer accepts anadd-writerop. A rejected grant (e.g. the agent seating an accomplice) never gains base write capability โ covered by an explicit attack test. - Hyperswarm: the pot topic is the bootstrap key's discovery key; the
treble1โฆinvite (z32 of the bootstrap key) is the membership secret. Connections are Noise-encrypted by Hyperswarm itself. - Seat requests: a tiny Protomux channel (
treble/1/hello) rides the same replication stream; a human approves โadd-writerop โ capability.
createTrebleWallet({ engine, ledger, agentPolicy })builds a realnew WDK(seed)instance. Engines:simโSimWalletManager extends WalletManagerfrom@tetherto/wdk-wallet, settling on a disclosed deterministic local ledger (SimLedger). Because it plugs into the real WDK pipeline, the REAL policy engine governs it.solanaโ dynamic import of@tetherto/wdk-wallet-solana(devnet); same call sites, real chain.
- Agent policy (
agentPolicy: { perTxCap, sessionCap }) registers a real WDK Transaction Policy: one ALLOW rule for bounded USDโฎ transfers, one explicit DENY (so violations carrypolicyId/ruleName), and WDK's default-deny covers everything else (the governed agent cannot evensign()arbitrary payloads). The cumulative cap reads executed transfers from the ledger, sosimulate.*can never drain the budget. - Bond accounts: staking ring-fences the buy-in into the participant's
own per-pot sub-account (
bondIndexFor(potKey)โ deterministic derivation index). Self-custody is preserved; the stake-time receipt is real.
Escrowless and deterministic: winners self-release min(stake, payout) from
their own bond; losers' bonds pay winners' remainders, matched greedily in
ascending id order. Invariants: every winner made exactly whole, every loser
pays exactly their stake, ฮฃ moved == pot. The trust gap (a peer refusing
to execute their legs) is documented in docs/AUDIT_REPORT.md โ the
tamper-evident debt record survives refusal; on-chain escrow is the v2 path.
requestAndWaitForSeatโ hello โ a human grants roleagent.joinwith its wallet address.- Policy pre-flight โ
account.simulate.transfer(...)against its own WDK policy; a DENY makes the agent decline the pot on the ledger (bounded autonomy you can see). - Brain forms the pick:
brains/qvac.js(realcompletion()+submit_picktool on Qwen3 1.7B,run.eventsโtoolCall) orbrains/heuristic.js(deterministic, always labeled). Same decision boundary either way. stakeBond(real receipt) โstake+pick(note: rationale)ops.- On finality: executes its settlement legs and appends
settle.
- Ops from different writers are causally concurrent until replicated; Autobase linearizes deterministically. The pot's social contract is that peers converge long before kickoff (minutes, not milliseconds); the reducer stays safe either way โ a pick that linearizes after the lock is rejected on every peer identically. See AUDIT_REPORT "pick/lock window".
- Both sides of a replication pair must
update()for acks to flow โ the bench and tests tick both peers.
| Surface | Runtime | Verified in this repo by |
|---|---|---|
| CLI demo / create / join / agent | Node โฅ 20 | npm run e2e, npm test |
| Desktop UI | Pear (pear-electron) | same modules as CLI; UI logic parses under Node |
| Tests / CI | Node 20/22/24, no optional deps | GitHub Actions 6-stage pipeline |
| QVAC brain | Node (Bare-ready per SDK) | code path + arg normalization tested; model runs on dev hardware |