@haven_ai/signer 0.1.0-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,108 @@
1
+ # @haven_ai/signer
2
+
3
+ The Haven **edge signer**. It holds the delegate key locally and signs — and
4
+ that's all it does. It pairs with the hosted, keyless `@haven_ai/mcp-server`:
5
+ the hosted server constructs and relays, this signs. The key never leaves this
6
+ process, and only signatures (and the standard x402 header) ever come out.
7
+
8
+ Design: [`docs/architecture/07-edge-signer.md`](../../docs/architecture/07-edge-signer.md).
9
+ Contract: [`docs/architecture/06-hosted-mcp-connect-flow.md`](../../docs/architecture/06-hosted-mcp-connect-flow.md).
10
+
11
+ ## Two ways to use it
12
+
13
+ **As a local MCP signer** (for Claude Desktop / Code / Cursor) — run it
14
+ alongside the hosted Haven connection:
15
+
16
+ ```sh
17
+ HAVEN_DELEGATE_KEY=0x... npx @haven_ai/signer
18
+ # or
19
+ npx @haven_ai/signer --credentials /path/to/haven-agent.json
20
+ ```
21
+
22
+ On first launch, the signer prints the delegate address, any wallet/network
23
+ metadata found in the credential file, and the sign-only tool list. It refuses
24
+ to start until acknowledged with either `HAVEN_SIGNER_ACK=<hash>` or
25
+ `npx @haven_ai/signer --credentials /path/to/haven-agent.json --ack`.
26
+
27
+ It exposes two stdio MCP tools:
28
+
29
+ | Tool | Does | Emits |
30
+ |---|---|---|
31
+ | `haven_sign` | Sign the `payload_hash` from `haven_pay` / `haven_x402_authorize`; for x402, record `x402.expected` and return a binding | `{ signature }` or `{ signature, x402_binding }` |
32
+ | `haven_x402_sign_header` | Build + sign the EIP-3009 `X-PAYMENT` header only when `payment_required` matches the recorded `x402_binding` | `{ payment_header }` |
33
+
34
+ **As a library** (for SDK / autonomous agents):
35
+
36
+ ```ts
37
+ import { createEdgeSigner } from '@haven_ai/signer'
38
+
39
+ const signer = createEdgeSigner(process.env.HAVEN_DELEGATE_KEY!)
40
+ const signature = signer.signPaymentHash(payloadHash)
41
+ const funding = signer.signX402FundingHash(payloadHash, {
42
+ resourceUrl,
43
+ merchantTo,
44
+ amount,
45
+ asset,
46
+ network,
47
+ auth,
48
+ })
49
+ const { paymentHeader } = await signer.buildX402PaymentHeader(paymentRequired, funding.x402Binding)
50
+ ```
51
+
52
+ ## Orchestration
53
+
54
+ ```
55
+ hosted: haven_pay -> { payment_id, payload_hash }
56
+ local: haven_sign -> { signature }
57
+ hosted: haven_submit -> { status, tx_hash }
58
+ ```
59
+
60
+ x402 (two delegate signatures, both local):
61
+
62
+ ```
63
+ hosted: haven_x402_authorize -> { payment_id, payload_hash, x402.expected }
64
+ local: haven_sign + expected -> funding signature + x402_binding
65
+ hosted: haven_submit -> funds Safe -> delegate EOA
66
+ local: haven_x402_sign_header -> X-PAYMENT header only if binding matches
67
+ agent: retry merchant with X-PAYMENT
68
+ ```
69
+
70
+ For x402, pass `x402.expected` from the hosted `haven_x402_authorize` response
71
+ unchanged into the local `haven_sign` call. The signer records that context and
72
+ returns a process-local `x402_binding`; pass that binding into
73
+ `haven_x402_sign_header` after `haven_submit` confirms. The signer refuses to
74
+ authorize the merchant header when the fresh merchant challenge has a different
75
+ amount, merchant recipient, resource URL, token asset, or network than the
76
+ recorded funding intent, and consumes the binding after one successful header.
77
+ The expected context must also carry Haven's `auth` signature; configure
78
+ `HAVEN_X402_BINDING_SIGNER` (or `x402_binding_signer` in the credential file) so
79
+ the signer can reject locally invented or tampered x402 contexts before signing
80
+ the funding hash.
81
+
82
+ ## Custody
83
+
84
+ The delegate key is read from `HAVEN_DELEGATE_KEY` or a `--credentials` file's
85
+ `delegate_key` (with a permissive-file warning). It stays in this process. The
86
+ signer makes no network calls — it can't leak the key to Haven or anyone else.
87
+ It needs no `api_key`: identity lives with the hosted connection, not here.
88
+
89
+ Connect Agent 2 may create the signer credential file locally during setup. In
90
+ that flow Haven receives the public signing address, proof, API-key hash/prefix,
91
+ and install status only; the plaintext API key and delegate key stay in local
92
+ protected storage/runtime config.
93
+
94
+ ## Local audit
95
+
96
+ Every MCP signing operation appends a JSONL row locally. File-backed runs write
97
+ next to the credential as `<credential>.signer-audit.jsonl`; env-only runs use
98
+ `~/.haven/signer-audit.jsonl`. Rows include timestamp, tool, payload hash, and
99
+ delegate address. They never include the delegate key, signature, or x402
100
+ payment header.
101
+
102
+ ## Hot-wallet minimization
103
+
104
+ Standard x402 briefly funds the delegate EOA before the merchant settles the
105
+ EIP-3009 authorization. Keep delegate balances transient: use small/reset-bound
106
+ x402 allowances, retry the original merchant session only after funding
107
+ confirms, and reconcile or sweep stranded delegate balances when the merchant
108
+ retry fails or does not settle before authorization expiry.