@bnbagent/studio-cli 0.0.6-alpha.7 → 0.0.6-alpha.9

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.
@@ -1,85 +1,50 @@
1
1
  ---
2
2
  name: bnbagent-studio-buying-via-8183
3
- description: When the user is acting as ERC-8183 buyer finding a provider, getting a quote, buying a service, fetching the deliverable, and deciding to approve / dispute / reject the work. Owns the buyer-side decision tree for the entire job lifecycle including settle-window timing (24h dispute window), dispute governance flow, and `Submission deadline has passed` recovery.
3
+ description: When the user is acting as ERC-8183 buyer - finding a provider, getting a quote, buying a service, fetching the deliverable, and deciding to approve / dispute / reject the work. Owns the buyer-side decision tree for the entire job lifecycle including settle-window timing (24h dispute window), dispute governance flow, and `Submission deadline has passed` recovery.
4
4
  ---
5
5
 
6
- > **Reference file** of the `bnbagent-studio` router skill installed at `bnbagent-studio/references/` and loaded on demand (not a standalone skill). Route here via the router's decision tree.
6
+ > **Reference file** of the `bnbagent-studio` router skill - installed at `bnbagent-studio/references/` and loaded on demand (not a standalone skill). Route here via the router's decision tree.
7
7
 
8
8
  # bnbagent-studio-buying-via-8183
9
9
 
10
- > **v1 scope note:** v1 is **seller-only** buyer flows are **NOT**
11
- > the main v1 payment path. The x402 buyer kernel survives only as the Agent's
12
- > *automatic* LLM top-up (`@bnbagent/studio-runtime/x402`, budget-gated, not an LLM tool),
13
- > and the erc8183 `buyWorkflow` survives as an **underlying capability** still
14
- > reachable via the `bag erc8183 buy/status/fetch/settle` CLI. Full buyer-side
15
- > *product* flows (a buyer agent, buyer-side negotiation wrapping) are deferred
16
- > to v2. The CLI procedure below still works for manual / testing use.
10
+ > **v1 scope note:** v1 is **seller-only** - buyer flows are **NOT** the main v1 payment path. The x402 buyer kernel survives only as the Agent's _automatic_ LLM top-up (`@bnbagent/studio-runtime/x402`, budget-gated, not an LLM tool), and the erc8183 `buyWorkflow` survives as an **underlying capability** still reachable via the `bag erc8183 buy/status/fetch/settle` CLI. Full buyer-side _product_ flows (a buyer agent, buyer-side negotiation wrapping) are deferred to v2. The CLI procedure below still works for manual / testing use.
17
11
 
18
- Procedure for **buyer-side flow**: have your agent (or you directly via CLI)
19
- purchase a service from another ERC-8183 seller, verify the deliverable, and
20
- close out the job with the right `settle` action.
12
+ Procedure for **buyer-side flow**: have your agent (or you directly via CLI) purchase a service from another ERC-8183 seller, verify the deliverable, and close out the job with the right `settle` action.
21
13
 
22
- Audience: Claude Code in a v0.0.x workspace with a funded wallet (tBNB + U).
23
- The buying CLI (`bag erc8183 buy/status/fetch/settle`) targets the **Agent
24
- sub-project's** wallet — these commands resolve to `<workspace>/app/agent/`
25
- automatically when run from the workspace root.
14
+ Audience: Claude Code in a current TypeScript workspace with a funded wallet (tBNB + U). The buying CLI (`bag erc8183 buy/status/fetch/settle`) targets the **Agent sub-project's** wallet - these commands resolve to `<workspace>/app/agent/` automatically when run from the workspace root.
26
15
 
27
- > **Protocol facts** (independent of the local filesystem layout): 24h dispute
28
- > window, `0x17be5b7b` revert, `expired_at` arithmetic.
16
+ > **Protocol facts** (independent of the local filesystem layout): 24h dispute window, `0x17be5b7b` revert, `expired_at` arithmetic.
29
17
 
30
18
  **Different from**:
31
- - `bnbagent-studio-operating.md` (same directory) — generic ops (dev / doctor / balance / RPC); jumps here for buyer-specific decisions
32
- - `bnbagent-studio-adding-to-project` — covers wiring a buyer tool set into an existing project (the static setup, not the runtime decisions)
33
- - `bnbagent-studio-selling-via-8183.md` (same directory) — the mirror playbook for the seller side (`on_job`, dispute defense)
34
19
 
35
- This skill owns: **buy fetch approve/dispute/reject loop**, whether
36
- driven via CLI or the agent's LLM calling `erc8183_buyer_set` tools.
20
+ - `bnbagent-studio-operating.md` (same directory) - generic ops (dev / doctor / balance / RPC); jumps here for buyer-specific decisions
21
+ - `bnbagent-studio-adding-to-project` - covers wiring a buyer tool set into an existing project (the static setup, not the runtime decisions)
22
+ - `bnbagent-studio-selling-via-8183.md` (same directory) - the mirror playbook for the seller side (`on_job`, dispute defense)
23
+
24
+ This skill owns: **buy → fetch → approve/dispute/reject loop**, whether driven via CLI or the agent's LLM calling `erc8183_buyer_set` tools.
37
25
 
38
26
  ## Buyer settle decision tree (load this skill when the user hits any of these)
39
27
 
40
28
  `SUBMITTED` job → buyer has three options, **time-gated by the on-chain dispute window**:
41
29
 
42
30
  | Action | Allowed | What happens |
43
- |---|---|---|
31
+ | --- | --- | --- |
44
32
  | `bag erc8183 settle <id> --action approve` | **After 24h dispute_window has passed** (chain enforces; reverts with `0x17be5b7b` if early) | Job → `COMPLETED`; seller receives U |
45
33
  | `bag erc8183 settle <id> --action dispute` | **Within dispute_window** | Opens governance flow; quorum vote decides; refund possible |
46
34
  | `bag erc8183 settle <id> --action reject` | **Only if you're a quorum voter, not the buyer** | Job → `REJECTED` via governance |
47
35
 
48
- If the buyer agent (or LLM) is about to call `settle --action approve` and it's
49
- been <24h since SUBMITTED, **wait** or use `dispute`. Don't try to retry
50
- through the revert — read the error and pick the right action.
36
+ If the buyer agent (or LLM) is about to call `settle --action approve` and it's been <24h since SUBMITTED, **wait** or use `dispute`. Don't try to retry through the revert - read the error and pick the right action.
51
37
 
52
- Common error: `Submission deadline has passed` → buyer set `expiredAt` too
53
- short (< dispute_window). Fix: re-buy with `--deadline-min ≥ 1` (the buy
54
- flow now auto-adds dispute_window).
38
+ Common error: `Submission deadline has passed` → buyer set `expiredAt` too short (< dispute_window). Fix: re-buy with `--deadline-min ≥ 1` (the buy flow now auto-adds dispute_window).
55
39
 
56
40
  ## Preconditions
57
41
 
58
42
  - `bag doctor` is clean (or only warns on LLM key)
59
- - For a paid job, the wallet has ≥ 0.05 tBNB (gas) and enough U for the budget
60
- plus slack. On BSC testnet the
61
- ERC-8183 kernel writes (`createJob` / `fund` deposit / `settle` …) are
62
- gas-sponsored via the SDK's MegaFuel paymaster **when they target the
63
- canonical contracts**, so you spend far less tBNB than
64
- that — but **not zero**: `fund` sends an ERC-20 `approve` (a token call, not
65
- sponsored) when the token allowance is too low — typically just the first fund,
66
- since studio approves a floored cap that later jobs reuse. Keep a little tBNB for
67
- it. (Mainnet is never sponsored.) Sponsorship is granted per target contract
68
- by the paymaster policy: a custom/QA stack selected via the
69
- `ERC8183_*_ADDRESS` overrides is normally **not** covered, so every write
70
- self-pays gas (the SDK logs `… is not sponsorable on this network;
71
- self-paying gas` and falls back automatically) — keep tBNB for the whole
72
- flow, or set `BNBAGENT_USE_PAYMASTER=0` to skip the per-transaction
73
- sponsorship probe and self-pay directly. For a FREE job, use `--budget-u 0`:
74
- no U balance, ERC-20 approval, or token escrow is needed, but the ERC-8183
75
- writes still need the selected gas/paymaster path and a zero-price-compatible
76
- commerce/router/policy stack — today that means a custom stack, so expect the
77
- writes to self-pay gas as above.
43
+ - For a paid job, the wallet has ≥ 0.05 tBNB (gas) and enough U for the budget plus slack. On BSC testnet the ERC-8183 kernel writes (`createJob` / `fund` deposit / `settle` …) are gas-sponsored via the SDK's MegaFuel paymaster **when they target the canonical contracts**, so you spend far less tBNB than that - but **not zero**: `fund` sends an ERC-20 `approve` (a token call, not sponsored) when the token allowance is too low - typically just the first fund, since studio approves a floored cap that later jobs reuse. Keep a little tBNB for it. (Mainnet is never sponsored.) Sponsorship is granted per target contract by the paymaster policy: a custom/QA stack selected via the `ERC8183_*_ADDRESS` overrides is normally **not** covered, so every write self-pays gas (the SDK logs `… is not sponsorable on this network; self-paying gas` and falls back automatically) - keep tBNB for the whole flow, or set `BNBAGENT_USE_PAYMASTER=0` to skip the per-transaction sponsorship probe and self-pay directly. For a FREE job, use `--budget-u 0`: no U balance, ERC-20 approval, or token escrow is needed, but the ERC-8183 writes still need the selected gas/paymaster path and a zero-price-compatible commerce/router/policy stack - today that means a custom stack, so expect the writes to self-pay gas as above.
78
44
  - You know the **provider's wallet address** (the seller agent's address)
79
- - The seller is **reachable** (its A2A agent is deployed somewhere); discoverable
80
- via the provider's `bag erc8004 resolve <agent_id>` endpoint URI
45
+ - The seller is **reachable** (its A2A agent is deployed somewhere); discoverable via the provider's `bag erc8004 resolve <agent_id>` endpoint URI
81
46
 
82
- ## Stage 1 Pre-flight checks
47
+ ## Stage 1 - Pre-flight checks
83
48
 
84
49
  ```bash
85
50
  # 1. Confirm wallet + balances
@@ -91,27 +56,15 @@ bag erc8004 resolve <provider_agent_id>
91
56
  # → returns the agent_uri; decode it (base64 data: URI) to verify the endpoint URL
92
57
  ```
93
58
 
94
- If the provider's endpoint URL points somewhere reachable (e.g. an `https://`
95
- AgentCore runtime URL), proceed. If it's `http://localhost:...`, that means you
96
- must be on the same host.
59
+ If the provider's endpoint URL points somewhere reachable (e.g. an `https://` AgentCore runtime URL), proceed. If it's `http://localhost:...`, that means you must be on the same host.
97
60
 
98
- ## Stage 2 (Optional) Negotiate price
61
+ ## Stage 2 - (Optional) Negotiate price
99
62
 
100
- **v0.0.x**: `@bnbagent/studio-runtime` *does* wrap the buyer-side negotiation
101
- handshake (`@bnbagent/studio-runtime/erc8183` `negotiateWithSeller`, wired into
102
- the buy workflow). It fires automatically when you buy by `--agent-id` (resolves
103
- the seller's endpoint from its ERC-8004 record, then POSTs `/negotiate`); pass
104
- `--no-negotiate` to skip it. When you buy by `--provider <addr>` you supply the
105
- budget directly and assume the price was agreed off-chain.
63
+ The current `@bnbagent/studio-runtime` wraps the buyer-side negotiation handshake (`@bnbagent/studio-runtime/erc8183` `negotiateWithSeller`, wired into the buy workflow). It fires automatically when you buy by `--agent-id` (resolves the seller's endpoint from its ERC-8004 record, then POSTs `/negotiate`); pass `--no-negotiate` to skip it. When you buy by `--provider <addr>` you supply the budget directly and assume the price was agreed off-chain.
106
64
 
107
- If you want to talk to the seller manually, the seller now exposes its
108
- `negotiate` skill over **A2A** (the seller's ERC-8004 endpoint URI is an A2A base
109
- URL): send an A2A `message/send` JSON-RPC call carrying a `DataPart`
110
- `{"skill": "negotiate", "task_description": "...", "terms": {...}}` (+ the seller's
111
- OAuth2 Bearer when deployed). The reply data part is the signed `NegotiationResult`
112
- quote. But you don't need this for v0.0.x — go straight to buy.
65
+ If you want to talk to the seller manually, the seller now exposes its `negotiate` skill over **A2A** (the seller's ERC-8004 endpoint URI is an A2A base URL): send an A2A `message/send` JSON-RPC call carrying a `DataPart` `{"skill": "negotiate", "task_description": "...", "terms": {...}}` (+ the seller's OAuth2 Bearer when deployed). The reply data part is the signed `NegotiationResult` quote. For the normal CLI flow, go straight to buy.
113
66
 
114
- ## Stage 3 Buy
67
+ ## Stage 3 - Buy
115
68
 
116
69
  ```bash
117
70
  bag erc8183 buy --provider <provider_addr> "<task description>" \
@@ -129,34 +82,22 @@ bag erc8183 buy --provider <provider_addr> "<task description>" \
129
82
  --budget-u 0 --deadline-min 30 --network bsc-testnet
130
83
  ```
131
84
 
132
- > **Task can be passed two ways** (both accepted): as a positional argument
133
- > `bag erc8183 buy --provider <addr> "<task>"` OR via the flag
134
- > `bag erc8183 buy --provider <addr> --task "<task>"`. Pass it once — supplying
135
- > both at the same time is an error.
85
+ > **Task can be passed two ways** (both accepted): as a positional argument `bag erc8183 buy --provider <addr> "<task>"` OR via the flag `bag erc8183 buy --provider <addr> --task "<task>"`. Pass it once - supplying both at the same time is an error.
136
86
 
137
87
  The 4 on-chain steps run sequentially:
138
88
 
139
89
  1. `createJob(provider, expiredAt, description)` → returns `job_id`
140
90
  2. `registerJob(jobId)`
141
91
  3. `setBudget(jobId, rawBudget)`
142
- 4. `fund(jobId, rawBudget, approveFloor=rawBudget)` auto-approves U only
143
- when the positive budget needs allowance; budget 0 skips approval and escrow
92
+ 4. `fund(jobId, rawBudget, approveFloor=rawBudget)` - auto-approves U only when the positive budget needs allowance; budget 0 skips approval and escrow
144
93
 
145
94
  Output prints 4 tx hashes + `job_id`. Note the `job_id` for later.
146
95
 
147
- **Gotcha**: `expired_at = now + deadline_minutes*60 + dispute_window` (24h). This
148
- is intentional — the chain enforces that submission must happen before
149
- `expired_at - dispute_window`. If you set `deadline_minutes=30`, the seller has
150
- 30 min to submit (then a 24h dispute window starts).
96
+ **Gotcha**: `expired_at = now + deadline_minutes*60 + dispute_window` (24h). This is intentional - the chain enforces that submission must happen before `expired_at - dispute_window`. If you set `deadline_minutes=30`, the seller has 30 min to submit (then a 24h dispute window starts).
151
97
 
152
- ## Stage 4 Wait for SUBMITTED
98
+ ## Stage 4 - Wait for SUBMITTED
153
99
 
154
- The single seller runtime has **no standalone poller** after funding, send a
155
- `notify_funded` A2A message to the seller ("I funded job X, please deliver"). The
156
- seller **acks `accepted` immediately and delivers in the background**, so you do
157
- **not** get the deliverable in the A2A reply — you poll the chain for it. The
158
- seller also sweeps other funded jobs on each `notify_funded` (in the background,
159
- deduped). Check status:
100
+ The single seller runtime has **no standalone poller** - after funding, send a `notify_funded` A2A message to the seller ("I funded job X, please deliver"). The seller **acks `accepted` immediately and delivers in the background**, so you do **not** get the deliverable in the A2A reply - you poll the chain for it. The seller also sweeps other funded jobs on each `notify_funded` (in the background, deduped). Check status:
160
101
 
161
102
  ```bash
162
103
  bag erc8183 status <job_id>
@@ -167,31 +108,21 @@ Statuses:
167
108
  - `OPEN` → not yet funded (shouldn't see this after Step 3)
168
109
  - `FUNDED` → waiting for seller to pick up + submit
169
110
  - `SUBMITTED` → ready to fetch + settle
170
- - `EXPIRED` → seller missed the deadline; use `bag erc8183 settle --action ...` or
171
- the SDK's `mark_expired` / `claim_refund`
111
+ - `EXPIRED` → seller missed the deadline; use `bag erc8183 settle --action ...` or the SDK's `mark_expired` / `claim_refund`
172
112
 
173
- Delivery is no longer instant: because the seller works in the background, the
174
- wait is however long its work takes (seconds to minutes). Poll until `SUBMITTED`,
175
- then read `deliverable_url` (Stage 5). If it stays `FUNDED`, either no one sent
176
- `notify_funded` (and the sweep hasn't run — the seller may be scaled to zero), or
177
- the seller's background work failed or hasn't finished yet — re-send
178
- `notify_funded` to nudge it while the runtime is warm. (Also possible: a config
179
- mismatch, most often `expired_at` too soon — but the workflow auto-fixes this now.)
113
+ Delivery is no longer instant: because the seller works in the background, the wait is however long its work takes (seconds to minutes). Poll until `SUBMITTED`, then read `deliverable_url` (Stage 5). If it stays `FUNDED`, either no one sent `notify_funded` (and the sweep hasn't run - the seller may be scaled to zero), or the seller's background work failed or hasn't finished yet - re-send `notify_funded` to nudge it while the runtime is warm. (Also possible: a config mismatch, most often `expired_at` too soon - but the workflow auto-fixes this now.)
180
114
 
181
- ## Stage 5 Fetch the deliverable
115
+ ## Stage 5 - Fetch the deliverable
182
116
 
183
- The single seller runtime serves **no** job-query endpoint the deliverable is read
184
- back from the on-chain submission (the `submit` tx carries the `deliverable_url`,
185
- typically `ipfs://...`) and the IPFS object. Get the URL via CLI:
117
+ The single seller runtime serves **no** job-query endpoint - the deliverable is read back from the on-chain submission (the `submit` tx carries the `deliverable_url`, typically `ipfs://...`) and the IPFS object. Get the URL via CLI:
186
118
 
187
119
  ```bash
188
120
  bag erc8183 fetch <job_id>
189
121
  ```
190
122
 
191
- Prints the `deliverable_url`. Fetch it yourself (e.g. via an IPFS gateway) to read
192
- the `DeliverableManifest`: `{"chain_id", "contracts", "job_id", "response": {"content": ..., "content_type": ...}, "metadata": {...}}`.
123
+ Prints the `deliverable_url`. Fetch it yourself (e.g. via an IPFS gateway) to read the `DeliverableManifest`: `{"chain_id", "contracts", "job_id", "response": {"content": ..., "content_type": ...}, "metadata": {...}}`.
193
124
 
194
- ## Stage 6 Settle
125
+ ## Stage 6 - Settle
195
126
 
196
127
  ```bash
197
128
  # Happy path: accept the deliverable. NOTE: must wait 24h dispute_window first.
@@ -206,18 +137,16 @@ bag erc8183 settle <job_id> --action reject
206
137
 
207
138
  Returns a tx hash. Verify on BscScan.
208
139
 
209
- **On `--action approve` revert with `0x17be5b7b`**: chain refuses because
210
- `submitted_at + dispute_window > now`. Either wait the remaining time or
211
- use `--action dispute` for immediate effect.
140
+ **On `--action approve` revert with `0x17be5b7b`**: chain refuses because `submitted_at + dispute_window > now`. Either wait the remaining time or use `--action dispute` for immediate effect.
212
141
 
213
- ## Stage 7 Verify on-chain settlement
142
+ ## Stage 7 - Verify on-chain settlement
214
143
 
215
144
  ```bash
216
145
  bag erc8183 status <job_id>
217
146
  # Expect: status COMPLETED (after approve) or unchanged SUBMITTED (after dispute, until voters resolve)
218
147
  ```
219
148
 
220
- Check seller's U balance increased (minus platform fee see `CommerceClient.platform_fee_bp()`).
149
+ Check seller's U balance increased (minus platform fee - see `CommerceClient.platform_fee_bp()`).
221
150
 
222
151
  ## End-to-end smoke (one-shot, for testing your setup)
223
152
 
@@ -232,12 +161,9 @@ bag erc8183 status $JOB
232
161
  bag erc8183 settle $JOB --action dispute
233
162
  ```
234
163
 
235
- For the FREE regression, change the budget to `0` and confirm the compatible
236
- contract job still reaches `FUNDED` and `SUBMITTED` without an ERC-20 approval
237
- or balance change.
164
+ For the FREE regression, change the budget to `0` and confirm the compatible contract job still reaches `FUNDED` and `SUBMITTED` without an ERC-20 approval or balance change.
238
165
 
239
- This is the exact end-to-end flow used to validate real-chain buying. See the
240
- references below for the canonical picture.
166
+ This is the exact end-to-end flow used to validate real-chain buying. See the references below for the canonical picture.
241
167
 
242
168
  ## Reference
243
169
 
@@ -1,26 +1,21 @@
1
1
  ---
2
2
  name: bnbagent-studio-extending-signing
3
- description: When the user wants the agent's wallet to sign EIP-712 typed data for anything beyond BSC U-token transfers e.g. integrate a new x402 service, custom commerce contract, or any TypedData primary type beyond TransferWithAuthorization/ReceiveWithAuthorization. Also covers diagnosing `PolicyViolation` / `X402PolicyError` at runtime and how to safely extend `[wallet.signing]` extra_domains / extra_primary_types in studio.toml.
3
+ description: When the user wants the agent's wallet to sign EIP-712 typed data for anything beyond BSC U-token transfers - e.g. integrate a new x402 service, custom commerce contract, or any TypedData primary type beyond TransferWithAuthorization/ReceiveWithAuthorization. Also covers diagnosing `PolicyViolation` / `X402PolicyError` at runtime and how to safely extend `[wallet.signing]` extra_domains / extra_primary_types in studio.toml.
4
4
  ---
5
5
 
6
- > **Reference file** of the `bnbagent-studio` router skill installed at `bnbagent-studio/references/` and loaded on demand (not a standalone skill). Route here via the router's decision tree.
6
+ > **Reference file** of the `bnbagent-studio` router skill - installed at `bnbagent-studio/references/` and loaded on demand (not a standalone skill). Route here via the router's decision tree.
7
7
 
8
8
  # bnbagent-studio-extending-signing
9
9
 
10
- Procedure for **extending the EIP-712 signing allowlist** in a bnbagent-studio project.
11
- Audience: Claude Code helping a user who hit `PolicyViolation` or wants to integrate a non-default x402 service / custom contract.
10
+ Procedure for **extending the EIP-712 signing allowlist** in a bnbagent-studio project. Audience: Claude Code helping a user who hit `PolicyViolation` or wants to integrate a non-default x402 service / custom contract.
12
11
 
13
- > **v0.0.1 path note**: signing is an **Agent-only** concern. `signing.ts` lives
14
- > at `<workspace>/app/agent/src/signing.ts` and is called by the
15
- > `SellerAgentExecutor` skills (`negotiate` / `notify_funded`) — it is **never** an
16
- > LLM-callable tool. The `[wallet.signing]` config lives in
17
- > `<workspace>/app/agent/studio.toml`. The workspace is a thin root plus the one
18
- > `app/agent/` sub-project; every command and edit below targets `app/agent/`.
12
+ > **Current path note**: signing is an **Agent-only** concern. `signing.ts` lives at `<workspace>/app/agent/src/signing.ts` and is called by the `SellerAgentExecutor` skills (`negotiate` / `notify_funded`) - it is **never** an LLM-callable tool. The `[wallet.signing]` config lives in `<workspace>/app/agent/studio.toml`. The workspace is a thin root plus the one `app/agent/` sub-project; every command and edit below targets `app/agent/`.
19
13
 
20
14
  **Different from**:
21
- - `-operating` — general ops & doctor / balance / job status
22
- - `funding-pieverse-llm` Pieverse LLM credit lifecycle (the money)
23
- - `-adding-to-project` adds capabilities (`bnbagent-sdk` modules)
15
+
16
+ - `-operating` - general ops & doctor / balance / job status
17
+ - `funding-pieverse-llm` - Pieverse LLM credit lifecycle (the money)
18
+ - `-adding-to-project` - adds capabilities (`bnbagent-sdk` modules)
24
19
 
25
20
  This skill is specifically the **signing-permission** axis. Funding is "do I have the money"; signing policy is "is the wallet allowed to sign this".
26
21
 
@@ -29,7 +24,7 @@ This skill is specifically the **signing-permission** axis. Funding is "do I hav
29
24
  Every EIP-712 signature goes through SDK `SigningPolicy.strictDefault()`. By default the wallet only signs:
30
25
 
31
26
  | Allowed | Domain | Primary types |
32
- |---|---|---|
27
+ | --- | --- | --- |
33
28
  | U-token mainnet | chain `56`, `0xcE24439F2D9C6a2289F741120FE202248B666666` | `TransferWithAuthorization`, `ReceiveWithAuthorization` |
34
29
  | U-token testnet | chain `97`, `0xc70B8741B8B07A6d61E54fd4B20f22Fa648E5565` | (same) |
35
30
 
@@ -38,40 +33,40 @@ Everything else (`Permit`, `PermitSingle`, `PermitBatch`, foreign contracts, for
38
33
  Two layers wrap this:
39
34
 
40
35
  | Layer | What it gates | Where configured | Can agent change at runtime? |
41
- |---|---|---|---|
42
- | L2 HTTP host | which servers the x402 buyer is allowed to fetch from | `[payments.x402].allowed_hosts` in `app/agent/studio.toml` | ⚠️ Only by editing toml + restart |
43
- | L3 SigningPolicy | which `(chain_id, contract)` + primary type the wallet will sign | `[wallet.signing]` in `app/agent/studio.toml` (additive over SDK strictDefault) | ⚠️ Only by editing toml + restart |
36
+ | --- | --- | --- | --- |
37
+ | L2 - HTTP host | which servers the x402 buyer is allowed to fetch from | `[payments.x402].allowed_hosts` in `app/agent/studio.toml` | ⚠️ Only by editing toml + restart |
38
+ | L3 - SigningPolicy | which `(chain_id, contract)` + primary type the wallet will sign | `[wallet.signing]` in `app/agent/studio.toml` (additive over SDK strictDefault) | ⚠️ Only by editing toml + restart |
44
39
 
45
- **Both layers must permit a request** for it to succeed. Adding only one half won't work see Section A.
40
+ **Both layers must permit a request** for it to succeed. Adding only one half won't work - see Section A.
46
41
 
47
42
  EIP-191 SIWE (the `pieverse_usage` MCP tool / `bag llm activate`) uses a **separate** hardcoded allowlist `{"llm.pieverse.io"}` and is not configurable.
48
43
 
49
44
  ## Quick triage decision tree
50
45
 
51
46
  | User said... | Section |
52
- |---|---|
53
- | "buy X service via x402" (X is not Pieverse) | A new x402 service |
54
- | "sign for custom commerce contract / order / quote" | B custom primary type |
55
- | `PolicyViolation` / `X402PolicyError` at runtime | C diagnosing the rejection |
56
- | "agent needs to approve unlimited USDC" / Permit / Permit2 | D refuse the request |
57
- | "expand the 600s validity window" | E validity overrides |
47
+ | --- | --- |
48
+ | "buy X service via x402" (X is not Pieverse) | A - new x402 service |
49
+ | "sign for custom commerce contract / order / quote" | B - custom primary type |
50
+ | `PolicyViolation` / `X402PolicyError` at runtime | C - diagnosing the rejection |
51
+ | "agent needs to approve unlimited USDC" / Permit / Permit2 | D - refuse the request |
52
+ | "expand the 600s validity window" | E - validity overrides |
58
53
 
59
54
  ## A. Integrate a new x402 service
60
55
 
61
56
  The user wants the agent to pay e.g. `api.example.com` via x402.
62
57
 
63
- **Pre-flight checks (must be true in v0.0.1 refuse and explain if not):**
58
+ **Pre-flight checks (must be true in the current release; refuse and explain if not):**
64
59
 
65
- 1. The service accepts payment on **BSC chain 56 or 97**. v0.0.1 wallets are BSC-only; a service on Base/Ethereum/Polygon won't work until v0.2 multi-chain support lands.
60
+ 1. The service accepts payment on **BSC chain 56 or 97**. Current wallets are BSC-only; services on Base, Ethereum, or Polygon are unsupported.
66
61
  2. The service uses **EIP-3009 `TransferWithAuthorization`** (or `ReceiveWithAuthorization`). If it uses Permit2 or a custom primary type → goes to Section B.
67
- 3. The token contract address on BSC is known and the user can confirm it. Don't guess from a token symbol look up the deployed address.
62
+ 3. The token contract address on BSC is known and the user can confirm it. Don't guess from a token symbol - look up the deployed address.
68
63
 
69
- If any of (1)(3) fail, **stop and tell the user**. v0.0.1 cannot integrate cross-chain services or non-EIP-3009 payment rails. Don't try to work around it; the SigningPolicy will refuse and the failure will be confusing.
64
+ If any of (1)-(3) fail, **stop and tell the user**. The current release cannot integrate cross-chain services or non-EIP-3009 payment rails. Do not work around it; the SigningPolicy will refuse the request.
70
65
 
71
- **Steps when (1)(3) all pass:**
66
+ **Steps when (1)-(3) all pass:**
72
67
 
73
68
  ```bash
74
- # 1. Edit app/agent/studio.toml both gates. `bag config` resolves the app/agent/
69
+ # 1. Edit app/agent/studio.toml - both gates. `bag config` resolves the app/agent/
75
70
  # sub-project automatically from the workspace root
76
71
  # (there is NO --side flag); pass --project-root app/agent to be explicit.
77
72
  bag config set payments.x402.allowed_hosts '["llm.pieverse.io", "api.example.com"]'
@@ -98,6 +93,7 @@ bag wallet policy show
98
93
  ```
99
94
 
100
95
  **Hard rules**:
96
+
101
97
  - Do not add a contract to `extra_domains` without verifying its address on a block explorer. The SigningPolicy treats `(chain_id, contract)` as a unit; the wrong address = signing into a phishing contract.
102
98
  - Do not silently widen `daily_cap_usd` or `max_per_request_usd` to make the new service "fit". The caps are budget guardrails; surface the proposed values to the user before editing.
103
99
 
@@ -114,9 +110,10 @@ extra_domains = [
114
110
  extra_primary_types = ["MyOrder", "BondQuote"]
115
111
  ```
116
112
 
117
- **Both must be added** adding a primary type without the matching domain is useless (the contract still gets rejected) and adding the domain without the type still rejects the signature (primary_type allowlist).
113
+ **Both must be added** - adding a primary type without the matching domain is useless (the contract still gets rejected) and adding the domain without the type still rejects the signature (primary_type allowlist).
118
114
 
119
115
  **Hard rules**:
116
+
120
117
  - The SDK denylist (`Permit`, `PermitSingle`, `PermitBatch`) **always wins** over `extra_primary_types`. Listing them does not enable them.
121
118
  - Custom primary types bypass studio's known semantic checks. Be extra careful that the typed data structure matches what the contract expects; an attacker controlling the contract or the LLM input can construct unfavorable messages.
122
119
 
@@ -130,7 +127,7 @@ PolicyViolation: unknown (chain_id, verifyingContract): (56, 0xAbc...)
130
127
  → Section A or B: add to [wallet.signing].extra_domains, then restart
131
128
 
132
129
  PolicyViolation: primary type 'Permit' is denylisted
133
- → Section D: refuse do not work around
130
+ → Section D: refuse - do not work around
134
131
 
135
132
  PolicyViolation: primary type 'MyOrder' not in allowlist
136
133
  → Section B: add to extra_primary_types
@@ -138,14 +135,14 @@ PolicyViolation: primary type 'MyOrder' not in allowlist
138
135
  PolicyViolation: validity window 7200s exceeds max 600
139
136
  → Section E: max_validity_window_seconds in [wallet.signing]
140
137
 
141
- X402HostNotAllowedError: x402 buyer refusing 'api.example.com' not in allowed_hosts
142
- → L2 HTTP gate (exact hosts only wildcard entries are not supported)
138
+ X402HostNotAllowedError: x402 buyer refusing 'api.example.com' - not in allowed_hosts
139
+ → L2 HTTP gate (exact hosts only - wildcard entries are not supported)
143
140
  → bag config set payments.x402.allowed_hosts '[..., "api.example.com"]'
144
141
  → (L3 may also need updating per Section A)
145
142
 
146
143
  X402BudgetExhaustedError: x402 402 demands $1.50 > max_usd=$1.00
147
144
  → Budget cap; user must explicitly raise via studio.toml.
148
- → DON'T silently widen tell the user.
145
+ → DON'T silently widen - tell the user.
149
146
  ```
150
147
 
151
148
  Confirm the current state before editing:
@@ -161,13 +158,14 @@ If the user (or, more dangerously, the LLM) asks the agent to sign `Permit`, `Pe
161
158
 
162
159
  **Stop. Refuse. Explain why.**
163
160
 
164
- These primary types grant unbounded ERC-20 spend authority to a third party. The denylist exists exactly to prevent LLMs being talked into signing one. Even if the user insists, the SDK will refuse with `PolicyViolation` and the message is correct do not bypass via `_DANGEROUS_signTypedDataNoPolicy`.
161
+ These primary types grant unbounded ERC-20 spend authority to a third party. The denylist exists exactly to prevent LLMs being talked into signing one. Even if the user insists, the SDK will refuse with `PolicyViolation` and the message is correct - do not bypass via `_DANGEROUS_signTypedDataNoPolicy`.
165
162
 
166
163
  Acceptable alternatives:
167
- - For paying a known service: use EIP-3009 `TransferWithAuthorization` (Section A — bounded amount, single-use, time-windowed)
168
- - For session-scoped recurring payments: opt-in to `Permit2 PermitTransferFrom` (Section B — single-use, witness-bound; not Permit / PermitSingle / PermitBatch)
169
164
 
170
- If the user is integrating something that genuinely requires Permit, this is a v0.2+ decision and should go in an ADR do not make the change ad-hoc.
165
+ - For paying a known service: use EIP-3009 `TransferWithAuthorization` (Section A - bounded amount, single-use, time-windowed)
166
+ - For session-scoped recurring payments: opt-in to `Permit2 PermitTransferFrom` (Section B - single-use, witness-bound; not Permit / PermitSingle / PermitBatch)
167
+
168
+ If the user is integrating something that genuinely requires Permit, this is a v0.2+ decision and should go in an ADR - do not make the change ad-hoc.
171
169
 
172
170
  ## E. Widening the validity window
173
171
 
@@ -185,10 +183,10 @@ Use sparingly. A signed authorization that lives 30 minutes can be replayed by a
185
183
  ## F. Common refusal patterns (when user asks for something unsafe)
186
184
 
187
185
  | User request | Why refuse |
188
- |---|---|
186
+ | --- | --- |
189
187
  | "Just turn off the signing policy" | The SigningPolicy L3 is the last-mile defense. Disabling it makes the wallet a blind-sign oracle. Use `extra_domains` instead. |
190
188
  | "Use `_DANGEROUS_signTypedDataNoPolicy`" | Logs WARN with caller filename. Acceptable only in tests or one-shot CLI debugging. Never in LLM-tool / agent runtime code. |
191
- | "Sign on Ethereum mainnet" | v0.0.1 is BSC-only. Tell the user this is v0.2 backlog. |
189
+ | "Sign on Ethereum mainnet" | The current release is BSC-only. |
192
190
  | "Permit USDC to a swap router" | Denylisted unconditionally (Section D). |
193
191
  | "Read the keystore and sign yourself, bypassing the wallet provider" | The SDK provider IS the security boundary; bypassing it discards every defense layer. Refuse. |
194
192
 
@@ -202,7 +200,7 @@ bag config show
202
200
  bag wallet policy show
203
201
  bag wallet policy show --json # for diff against an expected baseline
204
202
 
205
- # 3. Restart whatever process holds the wallet `bag dev` (the local A2A
203
+ # 3. Restart whatever process holds the wallet - `bag dev` (the local A2A
206
204
  # agent) or the AgentCore runtime. SigningPolicy is read once at
207
205
  # wallet construction; in-process changes won't take effect until restart.
208
206
 
@@ -213,18 +211,17 @@ bag wallet policy show --json # for diff against an expected baseline
213
211
  ## H. Read-only references (no signing, no funding required)
214
212
 
215
213
  When deeper protocol details are needed:
216
- - the SigningPolicy decision (`docs/design/decisions.md`) — full defense-in-depth rationale, 6-layer model
217
- - `docs/guides/user-guide.md` §6.1 same decision tree in user-doc form
218
- - `bag wallet policy show --json` machine-readable current state
219
- - SDK source `@bnbagent/sdk` (signing policy module) `SigningPolicy.strictDefault()` + `.extend()` semantics
214
+
215
+ - the SigningPolicy decision (`docs/design/decisions.md`) - full defense-in-depth rationale, 6-layer model
216
+ - `docs/guides/user-guide.md` §6.1 - same decision tree in user-doc form
217
+ - `bag wallet policy show --json` - machine-readable current state
218
+ - SDK source `@bnbagent/sdk` (signing policy module) - `SigningPolicy.strictDefault()` + `.extend()` semantics
220
219
 
221
220
  ## Hard rules (security boundary)
222
221
 
223
222
  - Never bypass the policy with `_DANGEROUS_*` calls in agent code. They exist for tests and incident response.
224
223
  - Never instruct the user to widen caps / allowlists "to make it work" without explaining the security tradeoff.
225
- - Persist the wallet password only in the generated, gitignored, owner-only
226
- `.studio/.env.local` for local use or a managed secret channel for deploys;
227
- never put it in argv, application code, logs, or chat.
224
+ - Persist the wallet password only in the generated, gitignored, owner-only `.studio/.env.local` for local use or a managed secret channel for deploys; never put it in argv, application code, logs, or chat.
228
225
  - Never persist signed payloads outside the keystore.
229
226
  - Always run `bag wallet policy show` after editing `[wallet.signing]` to confirm the change took effect.
230
- - Always restart the process SigningPolicy is captured at wallet construction.
227
+ - Always restart the process - SigningPolicy is captured at wallet construction.