warden docs + study material: WALLET.md, products lineup, llms.txt, lecture 10
- WALLET.md: the product manual (one idea, trust posture table, R4 gate,
quickstart, MCP surface, self-proving card, firewall, taxonomy)
- docs/products.md: four production-ready deployment profiles
(solo/airgap/treasury/choir) with honest built-vs-wired boundaries
- llms.txt: agent-native discovery manifest at repo root
- README: warden intro + lecture 10 pointer
- notebooks/10_verified_custody_wallet.ipynb: ratchet-rule lecture (toy
3-of-3 -> real four proven forks -> counterparty recomputes a card's
inclusion proof); course README + notebook test updated
- 83 tests green
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 21:46:27 +00:00
|
|
|
|
# warden — the verified-custody wallet
|
|
|
|
|
|
|
|
|
|
|
|
warden is the acting end of pacta. Where the rest of the project *decides*
|
|
|
|
|
|
which cryptographic code is trustworthy, warden *runs on that decision*:
|
|
|
|
|
|
it builds an Ed25519 custody boundary out of the four independently
|
|
|
|
|
|
proven curve25519-dalek forks, and puts them to work guarding money-
|
|
|
|
|
|
adjacent signatures — inbound and outbound.
|
|
|
|
|
|
|
|
|
|
|
|
It is agent-native first. The primary interface is an MCP server; a human
|
|
|
|
|
|
CLI is provided for operation and inspection. The design research behind
|
|
|
|
|
|
that choice is in [docs/agent-native.md](docs/agent-native.md).
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## The one idea
|
|
|
|
|
|
|
|
|
|
|
|
**Inbound acceptance requires a unanimous quorum of provably-equivalent
|
|
|
|
|
|
verifiers. Outbound signatures must pass the same quorum before release.**
|
|
|
|
|
|
|
|
|
|
|
|
Each quorum member is an Ed25519 verifier compiled from a source workspace
|
|
|
|
|
|
whose correctness certificates are machine-checked in Lean 4 and replay-
|
|
|
|
|
|
attested in the public [Lean Transparency Log](https://ltl.zkdefi.org).
|
|
|
|
|
|
The four members — `dalek`, `anza`, `risc0`, `betrusted` — are genuinely
|
|
|
|
|
|
different codebases, but each is *proven* to decide the same predicate:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
accept(A, m, R, s) ⇔ decompress(R) = [k](−A) + [s]B
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Classic N-version programming hopes independent implementations won't
|
|
|
|
|
|
share a bug. warden doesn't hope: on the proven domain the members
|
|
|
|
|
|
*cannot* disagree about semantics, so a runtime disagreement is not a
|
|
|
|
|
|
difference of opinion — it is evidence of build corruption, a memory
|
|
|
|
|
|
fault, or tampering. That turns "the verifiers disagreed" from a shrug
|
|
|
|
|
|
into an alarm with a machine-checked guarantee behind it.
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Trust posture (read this before trusting it)
|
|
|
|
|
|
|
|
|
|
|
|
| surface | assurance |
|
|
|
|
|
|
|---|---|
|
|
|
|
|
|
| inbound verification | **custody-grade** — quorum of certificate-covered verify paths |
|
|
|
|
|
|
| outbound firewall (verify-after-sign) | **custody-grade** — same quorum |
|
|
|
|
|
|
| outbound signing itself | **trusted base** — the attested artifact, not a third implementation; not covered by any theorem |
|
|
|
|
|
|
| SHA-512 | opaque oracle inside the theorems |
|
|
|
|
|
|
| wire parsers | outcomes are hypotheses |
|
|
|
|
|
|
| reproducible builds, side channels | not claimed (that is R5) |
|
|
|
|
|
|
| ML-DSA / PQC | fail-closed: no proven implementation exists |
|
|
|
|
|
|
|
|
|
|
|
|
The asymmetry is the point: warden is strongest exactly where it matters
|
|
|
|
|
|
most for custody — deciding whether an inbound authorization is real — and
|
|
|
|
|
|
honest about the weaker outbound edge, which it fences with the firewall.
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Anatomy of a wallet
|
|
|
|
|
|
|
|
|
|
|
|
A wallet is a directory of evidence, not a database of secrets:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
capsule.json the sealed custody capsule: quorum members, their attested
|
|
|
|
|
|
source commits, the transparency-log receipts that
|
|
|
|
|
|
authorized them (the R4 gate), and the policy in force
|
|
|
|
|
|
ledger.jsonl append-only, SHA-256 hash-chained event log
|
|
|
|
|
|
keys/ wallet identities (local signer keys are 0600; the airgap
|
|
|
|
|
|
identity has no private key on this host)
|
|
|
|
|
|
incidents/ quorum divergences and firewall quarantines, full trails
|
|
|
|
|
|
receipts/ refusal receipts — signed, machine-actionable
|
|
|
|
|
|
quarantine/ signatures the firewall refused to release
|
|
|
|
|
|
airgap/ outbox/inbox for the Precursor-style gap signer
|
|
|
|
|
|
latch.json present and latched=true when custody is frozen
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Every state change — inbound verify, outbound sign, refusal, incident,
|
|
|
|
|
|
latch, unlatch — is a hash-chained ledger entry. `pacta wallet
|
|
|
|
|
|
verify-ledger` recomputes the chain; a single altered byte anywhere in
|
|
|
|
|
|
the history is caught.
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## The R4 gate, in executable form
|
|
|
|
|
|
|
|
|
|
|
|
`pacta wallet init` refuses to create a wallet unless, **for every member**:
|
|
|
|
|
|
|
|
|
|
|
|
1. the built binary's provenance names an attested source commit;
|
|
|
|
|
|
2. the evidence dir holds that component's attestation + inclusion receipt;
|
|
|
|
|
|
3. the attestation re-validates locally — verdicts are **re-derived from
|
|
|
|
|
|
observed axiom cones**, never taken from the provider's label;
|
|
|
|
|
|
4. the local score reaches the required tier (default **R4**);
|
|
|
|
|
|
5. the receipt's inclusion proof verifies against its signed tree head,
|
|
|
|
|
|
under the log public key you pass;
|
|
|
|
|
|
6. the source commit the binary was compiled from matches the attested one.
|
|
|
|
|
|
|
|
|
|
|
|
Miss any of these and wallet creation fails with the reasons listed. A
|
|
|
|
|
|
custody wallet that cannot show its evidence has no business existing.
|
|
|
|
|
|
|
|
|
|
|
|
`--trusted-provider` is **required**: you must name whose *observations*
|
|
|
|
|
|
you are consuming. You are never asked to trust their verdicts.
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Quickstart
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 0. one-time: build the dogfood signer + the four quorum members
|
|
|
|
|
|
pacta dogfood-build --source <…>/curve25519-dalek-source
|
|
|
|
|
|
pacta wallet build-quorum --sources-root <…>/sources # dalek anza risc0 betrusted
|
|
|
|
|
|
|
|
|
|
|
|
# 1. fetch fresh evidence for each fork from the live log
|
|
|
|
|
|
for c in dalek anza risc0 betrusted; do
|
|
|
|
|
|
pacta log-fetch --url https://ltl.zkdefi.org \
|
|
|
|
|
|
--component ${c}-ed25519-verified --out-dir ./evidence
|
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
|
|
# 2. create the wallet (R4 gate)
|
|
|
|
|
|
pacta wallet init --wallet ./my-warden --evidence ./evidence \
|
|
|
|
|
|
--log-public-key ./log.pub --trusted-provider local-pacta-provider
|
|
|
|
|
|
|
|
|
|
|
|
# 3. inspect
|
|
|
|
|
|
pacta wallet status --wallet ./my-warden
|
|
|
|
|
|
pacta wallet card --wallet ./my-warden # the self-proving custody card
|
|
|
|
|
|
|
|
|
|
|
|
# 4. serve the agent-native surface
|
|
|
|
|
|
pacta wallet mcp --wallet ./my-warden # stdio JSON-RPC MCP server
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Agent-native surface (MCP)
|
|
|
|
|
|
|
warden hardening round: policy engine, ledger rotation, MCP UX, treasury LIVE, ops docs
Tier 2:
- request_signature decomposed into named gates (latch, freshness,
intent, policy, signer, firewall)
- ledger: O(1) tail-read appends under a dedicated lock file (survives
rotation rename); hash-chained segment rotation at policy
ledger.rotate_at; verify-ledger walks all segments to genesis;
archive tampering detected (tested)
- docs/threat-model.md (attacker matrix 1-9, proven-vs-trusted, design
invariants) + docs/runbook-latch.md (diagnose-first recovery)
- lecture 10: executable corrupt-a-member exercise (capsule pin catches
one appended byte), honest note on what the pin does NOT stop
Lightweight policy engine (POLICY_DENIED wired):
- policy.json: per-request/per-day amount ceilings, counterparty
allow/deny lists, per-identity overrides; rules make their intent
fields mandatory; daily sums from the ledger
-
Agent UX:
- signed refusal receipts travel inside MCP errors (receipt +
receipt_path in structuredContent)
- airgap over MCP: request_signature signer=airgap + request_id,
new airgap_pending tool; park -> list -> device answers -> complete
(tested end-to-end)
- all 8 tools carry readOnly/destructive annotations
- sliding-window rate limiter per tool class (custody/verify/liveness);
RATE_LIMITED refusal code; surface control, not ledgered
warden-treasury LIVE:
- treasury.py: stdlib base58, compact-u16, legacy+v0 wire parsing;
every required signature quorum-verified over exact message bytes;
completeness gap named in every verdict; RPC fetch uses response as
bytes only
-
- live-quorum test: synthetic Solana tx signed with wallet key ->
authentic via 4 proven forks; flipped byte -> not authentic
100 tests green (was 85).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 11:38:42 +00:00
|
|
|
|
`pacta wallet mcp` speaks MCP over stdio JSON-RPC. Eight outcome-first
|
|
|
|
|
|
tools with read-only/destructive annotations; strict input schemas;
|
|
|
|
|
|
results carry evidence; errors are structured objects that include the
|
|
|
|
|
|
signed refusal receipt, never prose. Tool classes are rate-limited
|
|
|
|
|
|
(custody 30/min, verify 120/min, liveness 240/min).
|
warden docs + study material: WALLET.md, products lineup, llms.txt, lecture 10
- WALLET.md: the product manual (one idea, trust posture table, R4 gate,
quickstart, MCP surface, self-proving card, firewall, taxonomy)
- docs/products.md: four production-ready deployment profiles
(solo/airgap/treasury/choir) with honest built-vs-wired boundaries
- llms.txt: agent-native discovery manifest at repo root
- README: warden intro + lecture 10 pointer
- notebooks/10_verified_custody_wallet.ipynb: ratchet-rule lecture (toy
3-of-3 -> real four proven forks -> counterparty recomputes a card's
inclusion proof); course README + notebook test updated
- 83 tests green
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 21:46:27 +00:00
|
|
|
|
|
|
|
|
|
|
| tool | does |
|
|
|
|
|
|
|---|---|
|
|
|
|
|
|
| `wallet_status` | custody posture: members/tiers, latch, ledger head + chain integrity, counts |
|
|
|
|
|
|
| `verify_inbound` | run the quorum on (payload, signature, public_key); unanimity or a classified incident |
|
|
|
|
|
|
| `request_signature` | intent-bound outbound signing through the firewall; refusal object on any gate |
|
|
|
|
|
|
| `custody_card` | the self-proving card (embedded inclusion proofs; recompute, don't believe) |
|
|
|
|
|
|
| `posture_challenge` | nonce → firewalled, signed posture attestation with the quorum trail |
|
|
|
|
|
|
| `list_incidents` | divergences and quarantines, newest-first |
|
|
|
|
|
|
| `explain_refusal` | fetch a refusal receipt by index (or latest) |
|
warden hardening round: policy engine, ledger rotation, MCP UX, treasury LIVE, ops docs
Tier 2:
- request_signature decomposed into named gates (latch, freshness,
intent, policy, signer, firewall)
- ledger: O(1) tail-read appends under a dedicated lock file (survives
rotation rename); hash-chained segment rotation at policy
ledger.rotate_at; verify-ledger walks all segments to genesis;
archive tampering detected (tested)
- docs/threat-model.md (attacker matrix 1-9, proven-vs-trusted, design
invariants) + docs/runbook-latch.md (diagnose-first recovery)
- lecture 10: executable corrupt-a-member exercise (capsule pin catches
one appended byte), honest note on what the pin does NOT stop
Lightweight policy engine (POLICY_DENIED wired):
- policy.json: per-request/per-day amount ceilings, counterparty
allow/deny lists, per-identity overrides; rules make their intent
fields mandatory; daily sums from the ledger
-
Agent UX:
- signed refusal receipts travel inside MCP errors (receipt +
receipt_path in structuredContent)
- airgap over MCP: request_signature signer=airgap + request_id,
new airgap_pending tool; park -> list -> device answers -> complete
(tested end-to-end)
- all 8 tools carry readOnly/destructive annotations
- sliding-window rate limiter per tool class (custody/verify/liveness);
RATE_LIMITED refusal code; surface control, not ledgered
warden-treasury LIVE:
- treasury.py: stdlib base58, compact-u16, legacy+v0 wire parsing;
every required signature quorum-verified over exact message bytes;
completeness gap named in every verdict; RPC fetch uses response as
bytes only
-
- live-quorum test: synthetic Solana tx signed with wallet key ->
authentic via 4 proven forks; flipped byte -> not authentic
100 tests green (was 85).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 11:38:42 +00:00
|
|
|
|
| `airgap_pending` | parked gap-signing requests and whether the device answered |
|
warden docs + study material: WALLET.md, products lineup, llms.txt, lecture 10
- WALLET.md: the product manual (one idea, trust posture table, R4 gate,
quickstart, MCP surface, self-proving card, firewall, taxonomy)
- docs/products.md: four production-ready deployment profiles
(solo/airgap/treasury/choir) with honest built-vs-wired boundaries
- llms.txt: agent-native discovery manifest at repo root
- README: warden intro + lecture 10 pointer
- notebooks/10_verified_custody_wallet.ipynb: ratchet-rule lecture (toy
3-of-3 -> real four proven forks -> counterparty recomputes a card's
inclusion proof); course README + notebook test updated
- 83 tests green
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 21:46:27 +00:00
|
|
|
|
|
|
|
|
|
|
Refusal codes (every refusal names one): `EVIDENCE_REQUIRED`,
|
|
|
|
|
|
`POLICY_DENIED`, `CUSTODY_LATCHED`, `EVIDENCE_STALE`, `MALFORMED_INTENT`,
|
warden hardening round: policy engine, ledger rotation, MCP UX, treasury LIVE, ops docs
Tier 2:
- request_signature decomposed into named gates (latch, freshness,
intent, policy, signer, firewall)
- ledger: O(1) tail-read appends under a dedicated lock file (survives
rotation rename); hash-chained segment rotation at policy
ledger.rotate_at; verify-ledger walks all segments to genesis;
archive tampering detected (tested)
- docs/threat-model.md (attacker matrix 1-9, proven-vs-trusted, design
invariants) + docs/runbook-latch.md (diagnose-first recovery)
- lecture 10: executable corrupt-a-member exercise (capsule pin catches
one appended byte), honest note on what the pin does NOT stop
Lightweight policy engine (POLICY_DENIED wired):
- policy.json: per-request/per-day amount ceilings, counterparty
allow/deny lists, per-identity overrides; rules make their intent
fields mandatory; daily sums from the ledger
-
Agent UX:
- signed refusal receipts travel inside MCP errors (receipt +
receipt_path in structuredContent)
- airgap over MCP: request_signature signer=airgap + request_id,
new airgap_pending tool; park -> list -> device answers -> complete
(tested end-to-end)
- all 8 tools carry readOnly/destructive annotations
- sliding-window rate limiter per tool class (custody/verify/liveness);
RATE_LIMITED refusal code; surface control, not ledgered
warden-treasury LIVE:
- treasury.py: stdlib base58, compact-u16, legacy+v0 wire parsing;
every required signature quorum-verified over exact message bytes;
completeness gap named in every verdict; RPC fetch uses response as
bytes only
-
- live-quorum test: synthetic Solana tx signed with wallet key ->
authentic via 4 proven forks; flipped byte -> not authentic
100 tests green (was 85).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 11:38:42 +00:00
|
|
|
|
`SIGNER_UNAVAILABLE`, `FIREWALL_QUARANTINE`, `PENDING_AIRGAP`,
|
|
|
|
|
|
`RATE_LIMITED`.
|
warden docs + study material: WALLET.md, products lineup, llms.txt, lecture 10
- WALLET.md: the product manual (one idea, trust posture table, R4 gate,
quickstart, MCP surface, self-proving card, firewall, taxonomy)
- docs/products.md: four production-ready deployment profiles
(solo/airgap/treasury/choir) with honest built-vs-wired boundaries
- llms.txt: agent-native discovery manifest at repo root
- README: warden intro + lecture 10 pointer
- notebooks/10_verified_custody_wallet.ipynb: ratchet-rule lecture (toy
3-of-3 -> real four proven forks -> counterparty recomputes a card's
inclusion proof); course README + notebook test updated
- 83 tests green
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 21:46:27 +00:00
|
|
|
|
|
|
|
|
|
|
### The custody card is self-proving
|
|
|
|
|
|
|
|
|
|
|
|
Unlike an A2A agent card that you take on the operator's signature, the
|
|
|
|
|
|
warden card embeds, per member, the transparency-log **inclusion proof**
|
|
|
|
|
|
and **signed tree head**. A counterparty recomputes the Merkle roots and
|
|
|
|
|
|
checks the STH signature against the log key it already pins — trust by
|
|
|
|
|
|
recomputation, not by assertion. See `verify_posture_attestation` and the
|
|
|
|
|
|
log's own `verify.py` for the ~40-line client side.
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
warden hardening round: policy engine, ledger rotation, MCP UX, treasury LIVE, ops docs
Tier 2:
- request_signature decomposed into named gates (latch, freshness,
intent, policy, signer, firewall)
- ledger: O(1) tail-read appends under a dedicated lock file (survives
rotation rename); hash-chained segment rotation at policy
ledger.rotate_at; verify-ledger walks all segments to genesis;
archive tampering detected (tested)
- docs/threat-model.md (attacker matrix 1-9, proven-vs-trusted, design
invariants) + docs/runbook-latch.md (diagnose-first recovery)
- lecture 10: executable corrupt-a-member exercise (capsule pin catches
one appended byte), honest note on what the pin does NOT stop
Lightweight policy engine (POLICY_DENIED wired):
- policy.json: per-request/per-day amount ceilings, counterparty
allow/deny lists, per-identity overrides; rules make their intent
fields mandatory; daily sums from the ledger
-
Agent UX:
- signed refusal receipts travel inside MCP errors (receipt +
receipt_path in structuredContent)
- airgap over MCP: request_signature signer=airgap + request_id,
new airgap_pending tool; park -> list -> device answers -> complete
(tested end-to-end)
- all 8 tools carry readOnly/destructive annotations
- sliding-window rate limiter per tool class (custody/verify/liveness);
RATE_LIMITED refusal code; surface control, not ledgered
warden-treasury LIVE:
- treasury.py: stdlib base58, compact-u16, legacy+v0 wire parsing;
every required signature quorum-verified over exact message bytes;
completeness gap named in every verdict; RPC fetch uses response as
bytes only
-
- live-quorum test: synthetic Solana tx signed with wallet key ->
authentic via 4 proven forks; flipped byte -> not authentic
100 tests green (was 85).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 11:38:42 +00:00
|
|
|
|
## The spending policy (POLICY_DENIED)
|
|
|
|
|
|
|
|
|
|
|
|
Optional `policy.json` in the wallet directory - the rules you would give
|
|
|
|
|
|
a teenager with a debit card, checked before the signer ever runs:
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"outbound": {
|
|
|
|
|
|
"max_amount_per_request": 100.0,
|
|
|
|
|
|
"max_amount_per_day": 500.0,
|
|
|
|
|
|
"counterparty_allowlist": ["alice"],
|
|
|
|
|
|
"counterparty_denylist": ["mallory"]
|
|
|
|
|
|
},
|
|
|
|
|
|
"identities": { "warden": { "max_amount_per_request": 10.0 } },
|
|
|
|
|
|
"ledger": { "rotate_at": 100000 }
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Amount rules bind on `intent.amount`; list rules bind on
|
|
|
|
|
|
`intent.counterparty` - policy makes those fields **mandatory**, so a
|
|
|
|
|
|
request that omits them is refused, never waved past. Daily ceilings sum
|
|
|
|
|
|
the released amounts in the ledger's last 24 hours per identity.
|
|
|
|
|
|
Per-identity overrides win over `outbound` defaults. No `policy.json`
|
|
|
|
|
|
means unrestricted (and `wallet_status` says so). `pacta wallet policy
|
|
|
|
|
|
--wallet <dir> --init-template` writes a starter file.
|
|
|
|
|
|
|
|
|
|
|
|
## Surface controls and the ledger's diet
|
|
|
|
|
|
|
|
|
|
|
|
The MCP layer rate-limits by tool class (custody 30/min, verify 120/min,
|
|
|
|
|
|
liveness 240/min) so a hostile counterparty cannot grind the signer or
|
|
|
|
|
|
bloat the audit trail; rate refusals are surface events, not custody
|
|
|
|
|
|
events, and are not ledgered. The ledger itself appends in O(1) (only
|
|
|
|
|
|
the tail is read, under a dedicated lock file, fsynced) and rotates into
|
|
|
|
|
|
hash-chained archive segments at `ledger.rotate_at` entries -
|
|
|
|
|
|
`verify-ledger` walks the whole chain across segments back to genesis.
|
|
|
|
|
|
|
|
|
|
|
|
## warden-treasury (Solana)
|
|
|
|
|
|
|
|
|
|
|
|
`pacta wallet treasury-verify` takes a wire-format Solana transaction
|
|
|
|
|
|
(from a file, or fetched by signature via `--rpc-url`), parses it locally
|
|
|
|
|
|
(stdlib; legacy and v0), and quorum-verifies **every required signature**
|
|
|
|
|
|
over the exact message bytes - including through the `anza` member, the
|
|
|
|
|
|
certificate-covered verify path of the code Solana validators run. The
|
|
|
|
|
|
RPC is demoted from oracle to bandwidth: it can withhold transactions
|
|
|
|
|
|
(the verdict names this completeness gap explicitly), but it cannot
|
|
|
|
|
|
manufacture one the quorum will accept. Every check lands in the ledger
|
|
|
|
|
|
with a treasury context.
|
|
|
|
|
|
|
warden docs + study material: WALLET.md, products lineup, llms.txt, lecture 10
- WALLET.md: the product manual (one idea, trust posture table, R4 gate,
quickstart, MCP surface, self-proving card, firewall, taxonomy)
- docs/products.md: four production-ready deployment profiles
(solo/airgap/treasury/choir) with honest built-vs-wired boundaries
- llms.txt: agent-native discovery manifest at repo root
- README: warden intro + lecture 10 pointer
- notebooks/10_verified_custody_wallet.ipynb: ratchet-rule lecture (toy
3-of-3 -> real four proven forks -> counterparty recomputes a card's
inclusion proof); course README + notebook test updated
- 83 tests green
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 21:46:27 +00:00
|
|
|
|
## The signing firewall (verify-after-sign)
|
|
|
|
|
|
|
|
|
|
|
|
Outbound is: **intent → sign → firewall → release**.
|
|
|
|
|
|
|
|
|
|
|
|
1. **intent** — a structured envelope whose `purpose` is recorded (the
|
|
|
|
|
|
ledger stores *why*, not only *what*) and whose `payload_sha256` binds
|
|
|
|
|
|
the request to exact bytes.
|
|
|
|
|
|
2. **sign** — either the local dogfood signer or the airgap/Precursor
|
|
|
|
|
|
signer (seed never on this host; request parked in `airgap/outbox`,
|
|
|
|
|
|
response read from `airgap/inbox`).
|
|
|
|
|
|
3. **firewall** — the fresh signature faces the full quorum. This is the
|
|
|
|
|
|
textbook fault-injection countermeasure: a glitched or tampered signer
|
|
|
|
|
|
is caught before anything leaves the building.
|
|
|
|
|
|
4. **release** — only unanimity releases. A rejected self-signature is
|
|
|
|
|
|
**quarantined, never returned**, and custody **latches**.
|
|
|
|
|
|
|
|
|
|
|
|
A latched wallet refuses all outbound with `CUSTODY_LATCHED`, and — by
|
|
|
|
|
|
design — its refusals arrive **unsigned**: a wallet that no longer trusts
|
|
|
|
|
|
its own boundary does not certify its apologies. `pacta wallet unlatch
|
|
|
|
|
|
--note "<why>"` is a deliberate operator act; the note is recorded
|
|
|
|
|
|
permanently in the ledger next to the latch it releases.
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Divergence taxonomy
|
|
|
|
|
|
|
|
|
|
|
|
The forks' accept() predicates are *allowed* to differ only on documented
|
|
|
|
|
|
degenerate inputs (anza rejects `A = 0` and a legacy excluded-small-order-
|
|
|
|
|
|
`R` list). warden fails closed regardless; the taxonomy only grades the
|
|
|
|
|
|
alarm:
|
|
|
|
|
|
|
|
|
|
|
|
| classification | when | verdict | incident |
|
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
| `unanimous-accept` | all accept | accept | — |
|
|
|
|
|
|
| `unanimous-reject` | all reject | reject | — |
|
|
|
|
|
|
| `semantic-edge` | disagree AND a documented edge flag applies | reject | note |
|
|
|
|
|
|
| `unexplained` | disagree with no explanation (or a member errored) | reject | **tamper → latch** |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Product lineup
|
|
|
|
|
|
|
|
|
|
|
|
warden ships as one core with four production-ready deployment profiles —
|
warden hardening round: policy engine, ledger rotation, MCP UX, treasury LIVE, ops docs
Tier 2:
- request_signature decomposed into named gates (latch, freshness,
intent, policy, signer, firewall)
- ledger: O(1) tail-read appends under a dedicated lock file (survives
rotation rename); hash-chained segment rotation at policy
ledger.rotate_at; verify-ledger walks all segments to genesis;
archive tampering detected (tested)
- docs/threat-model.md (attacker matrix 1-9, proven-vs-trusted, design
invariants) + docs/runbook-latch.md (diagnose-first recovery)
- lecture 10: executable corrupt-a-member exercise (capsule pin catches
one appended byte), honest note on what the pin does NOT stop
Lightweight policy engine (POLICY_DENIED wired):
- policy.json: per-request/per-day amount ceilings, counterparty
allow/deny lists, per-identity overrides; rules make their intent
fields mandatory; daily sums from the ledger
-
Agent UX:
- signed refusal receipts travel inside MCP errors (receipt +
receipt_path in structuredContent)
- airgap over MCP: request_signature signer=airgap + request_id,
new airgap_pending tool; park -> list -> device answers -> complete
(tested end-to-end)
- all 8 tools carry readOnly/destructive annotations
- sliding-window rate limiter per tool class (custody/verify/liveness);
RATE_LIMITED refusal code; surface control, not ledgered
warden-treasury LIVE:
- treasury.py: stdlib base58, compact-u16, legacy+v0 wire parsing;
every required signature quorum-verified over exact message bytes;
completeness gap named in every verdict; RPC fetch uses response as
bytes only
-
- live-quorum test: synthetic Solana tx signed with wallet key ->
authentic via 4 proven forks; flipped byte -> not authentic
100 tests green (was 85).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 11:38:42 +00:00
|
|
|
|
see [docs/products.md](docs/products.md). Operational docs: the attacker
|
|
|
|
|
|
matrix in [docs/threat-model.md](docs/threat-model.md) and the
|
|
|
|
|
|
[latch-recovery runbook](docs/runbook-latch.md). In one line each:
|
warden docs + study material: WALLET.md, products lineup, llms.txt, lecture 10
- WALLET.md: the product manual (one idea, trust posture table, R4 gate,
quickstart, MCP surface, self-proving card, firewall, taxonomy)
- docs/products.md: four production-ready deployment profiles
(solo/airgap/treasury/choir) with honest built-vs-wired boundaries
- llms.txt: agent-native discovery manifest at repo root
- README: warden intro + lecture 10 pointer
- notebooks/10_verified_custody_wallet.ipynb: ratchet-rule lecture (toy
3-of-3 -> real four proven forks -> counterparty recomputes a card's
inclusion proof); course README + notebook test updated
- 83 tests green
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 21:46:27 +00:00
|
|
|
|
|
|
|
|
|
|
- **warden-solo** — a single agent's custody sidecar (local signer).
|
|
|
|
|
|
- **warden-airgap** — signing behind a Precursor/Betrusted hardware gap.
|
|
|
|
|
|
- **warden-treasury** — trust-minimized chain watching (re-verify with the
|
|
|
|
|
|
chain's own proven verifier; the RPC is demoted to bandwidth).
|
|
|
|
|
|
- **warden-choir** — N wardens cross-witnessing each other's ledgers.
|