@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,167 +1,119 @@
1
1
  ---
2
2
  name: bnbagent-studio-selling-via-8183
3
- description: When the user is acting as an ERC-8183 seller on the single selected-protocol AgentCore runtime implementing the value `notify_funded` produces, tuning the deterministic rule-based quote price (fixed list price, clamp + sign no LLM in the negotiate path), understanding A2A async delivery vs MCP synchronous delivery, handling submitted jobs, defending against buyer disputes, and ensuring LLM credit continuity during long jobs. Owns the seller-side decision tree for the entire job lifecycle.
3
+ description: When the user is acting as an ERC-8183 seller on the single selected-protocol AgentCore runtime - implementing the value `notify_funded` produces, tuning the deterministic rule-based quote price (fixed list price, clamp + sign - no LLM in the negotiate path), understanding A2A async delivery vs MCP synchronous delivery, handling submitted jobs, defending against buyer disputes, and ensuring LLM credit continuity during long jobs. Owns the seller-side decision tree for the entire job lifecycle.
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-selling-via-8183
9
9
 
10
- Procedure for the **single seller flow**: implement the value your Agent
11
- produces, deploy it to AgentCore (where it serves A2A by default or MCP
12
- optionally and signs in-process), and handle the job lifecycle (Agent quotes →
13
- buyer funds → buyer calls `notify_funded` → Agent delivers → buyer reads the
14
- result from the chain → buyer settles or disputes).
10
+ Procedure for the **single seller flow**: implement the value your Agent produces, deploy it to AgentCore (where it serves A2A by default or MCP optionally and signs in-process), and handle the job lifecycle (Agent quotes → buyer funds → buyer calls `notify_funded` → Agent delivers → buyer reads the result from the chain → buyer settles or disputes).
15
11
 
16
- Audience: Claude Code in a working repo with a funded wallet (tBNB + U) and an
17
- Agent that produces some valuable output (text, classification, image — whatever).
12
+ Audience: Claude Code in a working repo with a funded wallet (tBNB + U) and an Agent that produces some valuable output (text, classification, image - whatever).
18
13
 
19
14
  **Different from**:
20
- - `bnbagent-studio-scaffolding-agent.md` (same directory) — creates the project (this playbook runs after)
21
- - `bnbagent-studio-adding-to-project.md` (in this same references/ directory) wires the seller runtime into an existing project (the static setup, not the runtime behavior)
22
- - `bnbagent-studio-operating.md` (same directory) generic ops (dev / doctor / balance); jumps here for seller-specific decisions
15
+
16
+ - `bnbagent-studio-scaffolding-agent.md` (same directory) - creates the project (this playbook runs after)
17
+ - `bnbagent-studio-adding-to-project.md` (in this same references/ directory) - wires the seller runtime into an existing project (the static setup, not the runtime behavior)
18
+ - `bnbagent-studio-operating.md` (same directory) - generic ops (dev / doctor / balance); jumps here for seller-specific decisions
23
19
 
24
20
  This skill owns: **implement the `notify_funded` value → deploy the agent → defend disputes**.
25
21
 
26
22
  ## The single seller runtime (one workspace sub-project)
27
23
 
28
- A v1 seller ships as **one runtime**: a single valuable Agent on AWS Bedrock
29
- AgentCore that **serves its selected protocol directly** (A2A:
30
- `0.0.0.0:9000`; MCP: `0.0.0.0:8000/mcp`), holds the key, and signs in-process.
31
- It exposes two fixed-code commerce operations — `negotiate` and `notify_funded`
32
- — as A2A skills on `SellerAgentExecutor` or tools on the MCP server, behind a
33
- mandatory Cognito OAuth2 authorizer. There is no separate forwarding service.
24
+ A v1 seller ships as **one runtime**: a single valuable Agent on AWS Bedrock AgentCore that **serves its selected protocol directly** (A2A: `0.0.0.0:9000`; MCP: `0.0.0.0:8000/mcp`), holds the key, and signs in-process. It exposes two fixed-code commerce operations - `negotiate` and `notify_funded` - as A2A skills on `SellerAgentExecutor` or tools on the MCP server, behind a mandatory Cognito OAuth2 authorizer. There is no separate forwarding service.
34
25
 
35
26
  | Sub-project | Role |
36
- |---|---|
37
- | `<workspace>/app/agent/` | The value (LLM/memory/tools/KB) AND the **sole signer**, deployed to AgentCore and serving the selected protocol. A2A uses `SellerAgentExecutor` in `<workspace>/app/agent/src/executor.ts`, which reads the inbound A2A message's data part and dispatches on its `"skill"` (`negotiate` / `notify_funded`); MCP uses `src/mcpMain.ts` tools with the same bounded operations. ALL signing is fixed `<workspace>/app/agent/src/signing.ts` code never an LLM tool. Keystore lives at the WORKSPACE root `<workspace>/.studio/wallets/` (outside the AgentCore codeLocation, so no deploy packaging path can bundle it; the Agent is its sole reader via `[wallet].keystore_dir`). At deploy the keystore is injected via AWS Secrets Manager (`WALLET_KEYSTORE_JSON`) and reconstructed at cold start by the entrypoint's `loadRuntimeSecrets()`. Config in `<workspace>/app/agent/studio.toml`. |
27
+ | --- | --- |
28
+ | `<workspace>/app/agent/` | The value (LLM/memory/tools/KB) AND the **sole signer**, deployed to AgentCore and serving the selected protocol. A2A uses `SellerAgentExecutor` in `<workspace>/app/agent/src/executor.ts`, which reads the inbound A2A message's data part and dispatches on its `"skill"` (`negotiate` / `notify_funded`); MCP uses `src/mcpMain.ts` tools with the same bounded operations. ALL signing is fixed `<workspace>/app/agent/src/signing.ts` code - never an LLM tool. Keystore lives at the WORKSPACE root `<workspace>/.studio/wallets/` (outside the AgentCore codeLocation, so no deploy packaging path can bundle it; the Agent is its sole reader via `[wallet].keystore_dir`). At deploy the keystore is injected via AWS Secrets Manager (`WALLET_KEYSTORE_JSON`) and reconstructed at cold start by the entrypoint's `loadRuntimeSecrets()`. Config in `<workspace>/app/agent/studio.toml`. |
38
29
 
39
- > The earlier two-layer model (an invoke-only Agent plus a public keyless EC2
40
- > service relaying via `InvokeAgentRuntime`) is **removed**. Once AgentCore could
41
- > serve the protocol surface on a public HTTPS endpoint, the agent became its own
42
- > public surface and the relay disappeared. See `docs/design/single-seller-agent.md`
43
- > for the A2A decision history.
30
+ > The earlier two-layer model (an invoke-only Agent plus a public keyless EC2 service relaying via `InvokeAgentRuntime`) is **removed**. Once AgentCore could serve the protocol surface on a public HTTPS endpoint, the agent became its own public surface and the relay disappeared. See `docs/design/single-seller-agent.md` for the A2A decision history.
44
31
 
45
32
  ## Preconditions
46
33
 
47
- - `bag doctor` is clean (or only warns on optional checks) run from workspace root
34
+ - `bag doctor` is clean (or only warns on optional checks) - run from workspace root
48
35
  - Wallet has ≥ 0.05 tBNB (gas to submit deliverables) and ≥ 0 U (sellers receive U, don't spend)
49
36
  - The agent sub-project is emitted (`<workspace>/app/agent/src/main.ts` for A2A or `src/mcpMain.ts` for MCP, plus `src/signing.ts`). If not, run `bag init` or read the `bnbagent-studio-adding-to-project.md` reference first.
50
37
  - For LLM-using sellers: `[llm].provider` configured in `app/agent/studio.toml` + (if Pieverse) `bag llm activate` has been run
51
38
 
52
- ## Stage 1 Implement the `notify_funded` value (the `runWork` hook)
39
+ ## Stage 1 - Implement the `notify_funded` value (the `runWork` hook)
53
40
 
54
- The valuable work lives in the `notify_funded` path. When a buyer calls
55
- `notify_funded` for a `job_id`, the runtime first synchronously re-verifies the
56
- job is genuinely FUNDED + ours on-chain (`signing.ts` `verifySignedJob`). In A2A
57
- mode, the executor **acks `accepted`** at once and then runs the LLM work +
58
- `signing.ts` `submitResult` (which SIGNS + broadcasts the deliverable) in a
59
- **background task**. In MCP mode, the tool call verifies, runs the LLM work, and
60
- submits synchronously, reporting progress while it runs. The block to specialise
61
- is the **developer hook** — the work function that produces the deliverable text:
41
+ The valuable work lives in the `notify_funded` path. When a buyer calls `notify_funded` for a `job_id`, the runtime first synchronously re-verifies the job is genuinely FUNDED + ours on-chain (`signing.ts` `verifySignedJob`). In A2A mode, the executor **acks `accepted`** at once and then runs the LLM work + `signing.ts` `submitResult` (which SIGNS + broadcasts the deliverable) in a **background task**. In MCP mode, the tool call verifies, runs the LLM work, and submits synchronously, reporting progress while it runs. The block to specialise is the **developer hook** - the work function that produces the deliverable text:
62
42
 
63
43
  ```ts
64
- async function runWork(prompt: string, opts: { sessionId: string }): Promise<string> {
65
- // DEVELOPER HOOK — replace the generic LLM passthrough with your real work:
44
+ async function runWork(
45
+ prompt: string,
46
+ opts: { sessionId: string },
47
+ ): Promise<string> {
48
+ // DEVELOPER HOOK - replace the generic LLM passthrough with your real work:
66
49
  // call domain tools, hit your APIs, run a pipeline, use the KB.
67
- // Return the deliverable TEXT the executor handles submit + on-chain signing.
50
+ // Return the deliverable TEXT - the executor handles submit + on-chain signing.
68
51
  const { text } = await generateText({ model, tools: LLM_READ_TOOLS, prompt });
69
52
  return text;
70
53
  }
71
54
  ```
72
55
 
73
56
  **Hard rules**:
74
- - The `notify_funded` work must finish before the on-chain `submitDeadline` — keep it bounded (A2A also has to land within the session max-lifetime, ≤8h).
75
- - Don't raise unhandled exceptions through `submitResult`. A permanently-bad job is rejected synchronously. In A2A, once accepted, a background delivery FAILURE leaves the job FUNDED (never reaching SUBMITTED) and is surfaced in CloudWatch — not the A2A reply. Let work errors surface so the job simply doesn't get a deliverable and the buyer can dispute cleanly; don't fake a deliverable.
76
- - All chain WRITES go through `app/agent/src/signing.ts` (fixed code). In the `notify_funded` work the LLM only PRODUCES work text it never signs, and it never sets the price (the quote price is rule-based; see Stage 2).
77
-
78
- ## Stage 2 — Rule-based pricing (fixed list price, clamp + sign — no LLM)
79
-
80
- A `negotiate` skill message hits the executor, which dispatches to the quote path.
81
- The quote path is **deterministic policy no LLM, no tools**:
82
-
83
- 1. Fixed code reads the configured **list price** from `[payments.erc8183].price`
84
- (`signing.ts` `listPrice()`). The LLM is never invoked in the negotiate path and never
85
- proposes or touches the price.
86
- 2. **Fixed code CLAMPS** the list price to `[min_price, max_price]`
87
- (`signing.ts` `clampPrice()`) — a misconfigured or hostile request can never sign
88
- out of bounds. For per-task pricing, compute the price from the request in the
89
- quote path *before* clamping; it stays deterministic code, not an LLM decision.
90
- 3. `signing.ts` `signQuote` does the **EIP-191 sign** with a short TTL (returns the
91
- SDK `NegotiationResult` envelope verbatim — price, currency, negotiation_hash,
92
- provider_sig), which the executor returns directly to the buyer over A2A.
93
- `chain_id` + `verifying_contract` are bound into the signature, so the quote
94
- cannot be replayed on another chain/contract. **Money is never in the LLM.**
57
+
58
+ - The `notify_funded` work must finish before the on-chain `submitDeadline` - keep it bounded (A2A also has to land within the session max-lifetime, ≤8h).
59
+ - Don't raise unhandled exceptions through `submitResult`. A permanently-bad job is rejected synchronously. In A2A, once accepted, a background delivery FAILURE leaves the job FUNDED (never reaching SUBMITTED) and is surfaced in CloudWatch - not the A2A reply. Let work errors surface so the job simply doesn't get a deliverable and the buyer can dispute cleanly; don't fake a deliverable.
60
+ - All chain WRITES go through `app/agent/src/signing.ts` (fixed code). In the `notify_funded` work the LLM only PRODUCES work text - it never signs, and it never sets the price (the quote price is rule-based; see Stage 2).
61
+
62
+ ## Stage 2 - Rule-based pricing (fixed list price, clamp + sign - no LLM)
63
+
64
+ A `negotiate` skill message hits the executor, which dispatches to the quote path. The quote path is **deterministic policy - no LLM, no tools**:
65
+
66
+ 1. Fixed code reads the configured **list price** from `[payments.erc8183].price` (`signing.ts` `listPrice()`). The LLM is never invoked in the negotiate path and never proposes or touches the price.
67
+ 2. **Fixed code CLAMPS** the list price to `[min_price, max_price]` (`signing.ts` `clampPrice()`) - a misconfigured or hostile request can never sign out of bounds. For per-task pricing, compute the price from the request in the quote path _before_ clamping; it stays deterministic code, not an LLM decision.
68
+ 3. `signing.ts` `signQuote` does the **EIP-191 sign** with a short TTL (returns the SDK `NegotiationResult` envelope verbatim - price, currency, negotiation_hash, provider_sig), which the executor returns directly to the buyer over A2A. `chain_id` + `verifying_contract` are bound into the signature, so the quote cannot be replayed on another chain/contract. **Money is never in the LLM.**
95
69
 
96
70
  Tune the clamp in `<workspace>/app/agent/studio.toml`:
97
71
 
98
72
  ```toml
99
73
  # app/agent/studio.toml
100
74
  [payments.erc8183]
101
- currency = "0x..." # $U token prefilled by `bag init` from [network].default; rarely changed
102
- price = "0" # raw wei the asking list price the quote signs
103
- min_price = "0" # raw wei clamp floor
104
- max_price = "0" # raw wei clamp ceiling (set > 0 to enforce)
75
+ currency = "0x..." # $U token - prefilled by `bag init` from [network].default; rarely changed
76
+ price = "0" # raw wei - the asking list price the quote signs
77
+ min_price = "0" # raw wei - clamp floor
78
+ max_price = "0" # raw wei - clamp ceiling (set > 0 to enforce)
105
79
  quote_ttl_seconds = 300
106
80
  default_estimated_completion_seconds = 600
107
81
  ```
108
82
 
109
- An explicit `price = "0"` opts into free jobs when the selected ERC-8183
110
- contract supports zero-price funding. Keep `currency` configured because it
111
- remains part of the signed quote.
83
+ An explicit `price = "0"` opts into free jobs when the selected ERC-8183 contract supports zero-price funding. Keep `currency` configured because it remains part of the signed quote.
112
84
 
113
- Prefer the CLI so the zero-price choice is visible and remains a decimal
114
- string:
85
+ Prefer the CLI so the zero-price choice is visible and remains a decimal string:
115
86
 
116
87
  ```bash
117
88
  bag config set payments.erc8183.price 0
118
- bag env set ERC8183_COMMERCE_ADDRESS <commerce-address>
119
- bag env set ERC8183_ROUTER_ADDRESS <router-address>
120
- bag env set ERC8183_POLICY_ADDRESS <policy-address>
89
+ bag env set ERC8183_COMMERCE_ADDRESS '0x...'
90
+ bag env set ERC8183_ROUTER_ADDRESS '0x...'
91
+ bag env set ERC8183_POLICY_ADDRESS '0x...'
121
92
  bag doctor
122
93
  bag deploy prepare
123
94
  ```
124
95
 
125
- Take all three addresses from the same compatible custom deployment.
126
- Doctor/prepare reject canonical or partial contract selection for FREE and
127
- announce `zero token escrow` only when the complete custom stack is selected.
128
-
129
- ## Stage 3 LLM credit continuity (Pieverse projects only)
130
-
131
- If `[llm].provider = "pieverse-llm"`, the Agent's emitted
132
- `app/agent/src/model.ts` `buildModel()` factory returns an AI SDK model wrapped
133
- with credit-ensure middleware (the stack-neutral credit logic lives in
134
- `@bnbagent/studio-runtime/pieverse` `PieverseCreditEnsurer`; the AI-SDK shell
135
- is the emitted file). Its **automatic, budget-gated auto-renew hook** tops up
136
- the active Pieverse key before an LLM call when the cached balance is below
137
- the floor. It fires **only in `notify_funded` work** (the `negotiate` path
138
- runs no LLM, so it never triggers there). This is the **only automatic signing
139
- path outside `signing.ts`**; it rides on the hardened x402 buyer kernel
140
- (`@bnbagent/studio-runtime/x402`, the payment signer) but is **NOT an LLM
141
- tool** — the Agent (the sole key-holder) does it transparently inside the
142
- model wrapper.
96
+ Take all three addresses from the same compatible custom deployment. Doctor/prepare reject canonical or partial contract selection for FREE and announce `zero token escrow` only when the complete custom stack is selected.
97
+
98
+ ## Stage 3 - LLM credit continuity (Pieverse projects only)
99
+
100
+ If `[llm].provider = "pieverse-llm"`, the Agent's emitted `app/agent/src/model.ts` `buildModel()` factory returns an AI SDK model wrapped with credit-ensure middleware (the stack-neutral credit logic lives in `@bnbagent/studio-runtime/pieverse` `PieverseCreditEnsurer`; the AI-SDK shell is the emitted file). Its **automatic, budget-gated auto-renew hook** tops up the active Pieverse key before an LLM call when the cached balance is below the floor. It fires **only in `notify_funded` work** (the `negotiate` path runs no LLM, so it never triggers there). This is the **only automatic signing path outside `signing.ts`**; it rides on the hardened x402 buyer kernel (`@bnbagent/studio-runtime/x402`, the payment signer) but is **NOT an LLM tool** - the Agent (the sole key-holder) does it transparently inside the model wrapper.
143
101
 
144
102
  | Layer | Mechanism | When it fires |
145
- |---|---|---|
103
+ | --- | --- | --- |
146
104
  | **Per-call auto-renew hook** | The emitted managed-model wrapper checks key balance before each LLM call | Cache miss (60s default) or balance < `min_balance_usd` |
147
105
 
148
- If `[budget].enabled = true` (opt-in), the hook auto-tops-up from the
149
- wallet within the 6-gate budget; otherwise it raises
150
- `PieverseAccountBalanceExhaustedError` and the executor's `notify_funded`
151
- work should:
106
+ If `[budget].enabled = true` (opt-in), the hook auto-tops-up from the wallet within the 6-gate budget; otherwise it raises `PieverseAccountBalanceExhaustedError` and the executor's `notify_funded` work should:
152
107
 
153
108
  1. Let the error surface in the background task so the job stays FUNDED (never reaches SUBMITTED) and the buyer can dispute (don't silently fake a deliverable). The job was already acked `accepted`, so the failure is visible on-chain + in CloudWatch, not in the A2A reply.
154
- 2. **Don't** retry the buyer's deadline keeps ticking
109
+ 2. **Don't** retry - the buyer's deadline keeps ticking
155
110
  3. The owner sees the error in CloudWatch logs + should run `bag llm topup` to refill (or `bag budget enable`)
156
111
 
157
112
  Full Pieverse credit decisions live in `funding-pieverse-llm` (project-scope skill in Pieverse projects).
158
113
 
159
- ## Stage 4 Deploy + register (announce to buyers)
114
+ ## Stage 4 - Deploy + register (announce to buyers)
160
115
 
161
- ERC-8183 / ERC-8004 registration is a **deploy-time** concern: the public
162
- AgentCore endpoint must exist before you register, so register **last**. The
163
- agent endpoint has no anonymous mode; `bag deploy` provisions the Cognito
164
- OAuth2 authorizer as part of the deploy.
116
+ ERC-8183 / ERC-8004 registration is a **deploy-time** concern: the public AgentCore endpoint must exist before you register, so register **last**. The agent endpoint has no anonymous mode; `bag deploy` provisions the Cognito OAuth2 authorizer as part of the deploy.
165
117
 
166
118
  ```bash
167
119
  bag deploy prepare # readiness sweep
@@ -169,122 +121,86 @@ bag deploy --provider aws # ship the agent to AgentCore (selected prot
169
121
  bag deploy verify --provider aws # delegated status + reconcile ERC-8004 identity
170
122
  ```
171
123
 
172
- ERC-8004 identity is registered with the **AgentCore endpoint**: A2A uses
173
- `AgentEndpoint.a2a(baseUrl, "0.3.0")` (normalizing to
174
- `/.well-known/agent-card.json`), while MCP records the `/mcp` endpoint plus access
175
- metadata. Buyers reach the agent directly. `bag deploy verify --provider aws`
176
- asks bnbagent-deploy for live status first, then performs the reconcile.
124
+ ERC-8004 identity is registered with the **AgentCore endpoint**: A2A uses `AgentEndpoint.a2a(baseUrl, "0.3.0")` (normalizing to `/.well-known/agent-card.json`), while MCP records the `/mcp` endpoint plus access metadata. Buyers reach the agent directly. `bag deploy verify --provider aws` asks bnbagent-deploy for live status first, then performs the reconcile.
177
125
 
178
126
  **Hard rules**:
127
+
179
128
  - The endpoint must be **reachable** when registered. For A2A, smoke test the normalized card URL directly, for example `curl <agentcore-invocations-url>/.well-known/agent-card.json` (or `curl <already-registered-card-url>` if the endpoint already includes `/.well-known/agent-card.json`). For MCP, connect an MCP client to the deployed `/mcp` URL. Chain doesn't verify reachability, but buyers will see failures.
180
- - `bag deploy --provider aws` provisions the Cognito user pool + buyer M2M client and prints the token URL, client id, and scope. Hand those to each buyer (the client secret is retrieved read-only from the AWS Console studio never stores it). `bag deploy provision-cognito` is deprecated; its CDK pool is never used by a deploy.
181
- - Price bounds (`min_price`/`max_price`) live with the Agent it clamps + signs the quote.
182
-
183
- ## Stage 5 How a SUBMITTED job happens
184
-
185
- There is **no background poll loop** in v1. Delivery is triggered by
186
- `notify_funded`; the execution model depends on the selected protocol:
187
-
188
- 1. **A2A buyer push (the prompt path):** buyer negotiates over A2A (`negotiate`
189
- skill) buyer anchors the signed quote on-chain (`createJob` `register`
190
- `setBudget` → `fund`, provider = the agent address) → buyer pushes a
191
- `notify_funded` A2A message for the `job_id` the executor synchronously
192
- re-verifies (`verifySignedJob`) and **acks `accepted`** at once, then in a
193
- **background task** does the LLM work and SIGNS + submits the deliverable
194
- on-chain → job → SUBMITTED. The buyer **polls the chain** for the result (it
195
- does not wait on the ack), then approves or disputes within `dispute_window`
196
- (24h on testnet). While any background delivery is in flight the runtime
197
- reports `/ping` `HEALTHY_BUSY` (AgentCore's long-running async pattern), so the
198
- scale-to-zero runtime stays warm until the work lands — bounded by the session
199
- max-lifetime (≤8h).
200
- 2. **A2A in-process sweep (the fallback):** on every accepted `notify_funded`, the
201
- executor opportunistically sweeps (in the background)
202
- `ERC8183JobOps.getPendingJobs()` for other FUNDED jobs assigned to this
203
- provider and delivers them too. This catches jobs whose buyer funded on-chain
204
- but never pushed `notify_funded`. The sweep is **deduped** (a job already being
205
- delivered — by the notification or a concurrent sweep — is skipped via an
206
- in-flight set, so notify + sweep never double-deliver the same job),
207
- **idempotent** (`verifySignedJob` returns non-OK for an already-SUBMITTED
208
- job, so there is no state file), and **best-effort** (one bad job never aborts
209
- the sweep, and a sweep failure never affects the ack).
210
- 3. **MCP synchronous delivery:** buyer negotiates through the `negotiate` MCP
211
- tool, funds on-chain, then calls `notify_funded`; the tool verifies, runs the
212
- work, and signs + submits before returning, with progress heartbeats. There is
213
- no background ack/sweep path in MCP.
214
-
215
- Because the sweep runs only when *someone* invokes `notify_funded` (and only while
216
- the runtime is warm), a totally idle, scaled-to-zero agent will not deliver during
217
- the cold window until the next notify. A periodic Lambda poller is the v2
218
- robustness path that closes it. The full line protocol is in
219
- `docs/design/erc8183-buyer-push.md`.
220
-
221
- Manual override (rare — only the agent holds the key):
129
+ - `bag deploy --provider aws` provisions the Cognito user pool + buyer M2M client and prints the token URL, client id, and scope. Hand those to each buyer (the client secret is retrieved read-only from the AWS Console - studio never stores it). `bag deploy provision-cognito` is deprecated; its CDK pool is never used by a deploy.
130
+ - Price bounds (`min_price`/`max_price`) live with the Agent - it clamps + signs the quote.
131
+
132
+ ## Stage 5 - How a SUBMITTED job happens
133
+
134
+ There is **no background poll loop** in v1. Delivery is triggered by `notify_funded`; the execution model depends on the selected protocol:
135
+
136
+ 1. **A2A buyer push (the prompt path):** buyer negotiates over A2A (`negotiate` skill) → buyer anchors the signed quote on-chain (`createJob` → `register` → `setBudget` → `fund`, provider = the agent address) → buyer pushes a `notify_funded` A2A message for the `job_id` → the executor synchronously re-verifies (`verifySignedJob`) and **acks `accepted`** at once, then in a **background task** does the LLM work and SIGNS + submits the deliverable on-chain → job → SUBMITTED. The buyer **polls the chain** for the result (it does not wait on the ack), then approves or disputes within `dispute_window` (24h on testnet). While any background delivery is in flight the runtime reports `/ping` `HEALTHY_BUSY` (AgentCore's long-running async pattern), so the scale-to-zero runtime stays warm until the work lands - bounded by the session max-lifetime (≤8h).
137
+ 2. **A2A in-process sweep (the fallback):** on every accepted `notify_funded`, the executor opportunistically sweeps (in the background) `ERC8183JobOps.getPendingJobs()` for other FUNDED jobs assigned to this provider and delivers them too. This catches jobs whose buyer funded on-chain but never pushed `notify_funded`. The sweep is **deduped** (a job already being delivered - by the notification or a concurrent sweep - is skipped via an in-flight set, so notify + sweep never double-deliver the same job), **idempotent** (`verifySignedJob` returns non-OK for an already-SUBMITTED job, so there is no state file), and **best-effort** (one bad job never aborts the sweep, and a sweep failure never affects the ack).
138
+ 3. **MCP synchronous delivery:** buyer negotiates through the `negotiate` MCP tool, funds on-chain, then calls `notify_funded`; the tool verifies, runs the work, and signs + submits before returning, with progress heartbeats. There is no background ack/sweep path in MCP.
139
+
140
+ Because the sweep runs only when _someone_ invokes `notify_funded` (and only while the runtime is warm), a totally idle, scaled-to-zero agent will not deliver during the cold window until the next notify. A periodic Lambda poller is the v2 robustness path that closes it. The full line protocol is in `docs/design/erc8183-buyer-push.md`.
141
+
142
+ Manual override (rare - only the agent holds the key):
222
143
 
223
144
  ```bash
224
145
  bag erc8183 submit <job_id> "<deliverable text>" [--metadata-json '{...}']
225
146
  ```
226
147
 
227
- Use only if the Agent produced a deliverable out-of-band and you need to attach it
228
- manually.
148
+ Use only if the Agent produced a deliverable out-of-band and you need to attach it manually.
229
149
 
230
- ## Stage 6 Defending against disputes
150
+ ## Stage 6 - Defending against disputes
231
151
 
232
152
  Buyer can `settle --action dispute` within `dispute_window`. Seller responses:
233
153
 
234
154
  | Symptom | Diagnosis | Action |
235
- |---|---|---|
155
+ | --- | --- | --- |
236
156
  | Buyer disputed within 24h | Their right; goes to quorum vote | Provide evidence via the off-chain governance flow; don't argue on-chain |
237
157
  | `0x17be5b7b` revert when buyer tried to `approve` | Buyer tried to approve before 24h passed | This is buyer's mistake, not yours; they'll need to wait or use `dispute` |
238
158
  | `Submission deadline has passed` when you tried to submit | Buyer set too-short `expiredAt` on the job | You can't submit late; politely tell buyer to re-buy with longer deadline |
239
159
  | Job stuck `FUNDED` for >24h | Nobody pushed `notify_funded` (and the agent stayed idle, so the sweep never ran) or the background `runWork` crashed (the job was acked `accepted` but never reached SUBMITTED) | Inspect CloudWatch logs; push a `notify_funded` to wake the agent, or submit work manually if a deliverable exists but submit failed |
240
160
 
241
161
  **Hard rules**:
162
+
242
163
  - Never tamper with quorum vote signals (no fake validators / no spam-disputes).
243
- - If you produced a defective deliverable, **don't dispute** accept the buyer's reject; chain reputation is real.
164
+ - If you produced a defective deliverable, **don't dispute** - accept the buyer's reject; chain reputation is real.
244
165
  - Keep the agent's logs (it prints redacted audit events to stdout → CloudWatch).
245
166
 
246
- ## Stage 7 Settle + withdraw funds
167
+ ## Stage 7 - Buyer settlement and seller payout
247
168
 
248
- `settle` is the **seller's manual step** there is no in-runtime auto-settle in
249
- v1 (no long-running process to run it). After the dispute window elapses:
169
+ `settle` is the **buyer's** manual step; a quorum voter may also reject or resolve a dispute. There is no in-runtime auto-settle in the current single-runtime seller. After the dispute window elapses, the buyer can approve:
250
170
 
251
171
  ```bash
252
- bag erc8183 settle <job_id> # default --action approve
172
+ bag erc8183 settle <job_id> # buyer wallet; default --action approve
253
173
  bag erc8183 status <job_id> # confirm COMPLETED
254
174
  # Funds auto-transfer on COMPLETED in the current contract; no manual withdraw needed.
255
175
  ```
256
176
 
257
- Older contracts may have required a manual `withdraw` confirm against the
258
- deployed commerce contract's behavior.
177
+ Older contracts may have required a manual `withdraw` - confirm against the deployed commerce contract's behavior.
259
178
 
260
179
  ## How a buyer reads the deliverable
261
180
 
262
- The agent serves **no** job-query endpoint. The buyer reads the deliverable back
263
- from the on-chain submission (the `submit` tx carries the deterministic
264
- `deliverable_url`) / the IPFS object. This is by design — the chain is the shared
265
- source of truth, and the agent stays a thin A2A surface.
181
+ The agent serves **no** job-query endpoint. The buyer reads the deliverable back from the on-chain submission (the `submit` tx carries the deterministic `deliverable_url`) / the IPFS object. This is by design - the chain is the shared source of truth, and the agent stays a thin A2A surface.
266
182
 
267
183
  ## Common errors + remediation
268
184
 
269
185
  | Error | Cause | Fix |
270
- |---|---|---|
271
- | A2A job acked `accepted` but never reaches SUBMITTED | background `runWork` / `submitResult` raised (the failure is NOT in the A2A reply the ack already went out) | Inspect CloudWatch logs; wrap LLM/domain calls; let the error surface so the buyer can dispute, don't fake a deliverable |
186
+ | --- | --- | --- |
187
+ | A2A job acked `accepted` but never reaches SUBMITTED | background `runWork` / `submitResult` raised (the failure is NOT in the A2A reply - the ack already went out) | Inspect CloudWatch logs; wrap LLM/domain calls; let the error surface so the buyer can dispute, don't fake a deliverable |
272
188
  | `notify_funded` reply `{ "status": "rejected", "reason": ... }` | synchronous verify failed (not our signature, tampered terms, underfunded, expired) or malformed `job_id` | Confirm the buyer funded the exact signed quote against this provider; re-quote if terms changed |
273
- | `submit_work reverts gas estimation` | Job already SUBMITTED (idempotency violation) | Check `bag erc8183 status <id>` before retry the sweep already handles this idempotently |
189
+ | `submit_work reverts gas estimation` | Job already SUBMITTED (idempotency violation) | Check `bag erc8183 status <id>` before retry - the sweep already handles this idempotently |
274
190
  | `PieverseAccountBalanceExhaustedError` mid-job | Agent's LLM credit ran out | Let it surface; run `bag llm topup`; consider `bag budget enable` |
275
191
  | Agent unreachable (buyer reports) | AgentCore runtime is down, DNS wrong, or the OAuth2 bearer is missing/expired | `bag deploy status` / `bag deploy logs --provider aws` to inspect; redeploy via `bag deploy --provider aws` |
276
192
 
277
193
  ## Hard rules (security boundary)
278
194
 
279
195
  - Don't store buyer-supplied data outside the request lifecycle (privacy + storage cost).
280
- - The Agent signs only for **its own** quote / submit / settle actions; it never signs for the buyer.
281
- - The key lives ONLY in the agent at the workspace root `.studio/wallets/` (outside every codeLocation, so no packaging path can bundle it) and is injected into the agent via AWS Secrets Manager at deploy never inlined into the code artifact (mainnet refuses the envvars fallback). Never log API keys / PII into stdout (the agent's audit events are redacted before they hit CloudWatch).
282
- - Inbound auth is mandatory Cognito OAuth2 buyers send plain HTTPS + a Bearer (no AWS SigV4). An unauthorized request is rejected 401; there is no anonymous mode.
283
- - LLM model name selection (paid vs free) is a per-project decision load `funding-pieverse-llm` if user is unsure which model to use for paid services.
196
+ - The Agent signs only its own quote and submit actions; the buyer or quorum signs settlement actions.
197
+ - The key lives ONLY in the agent at the workspace root `.studio/wallets/` (outside every codeLocation, so no packaging path can bundle it) and is injected into the agent via AWS Secrets Manager at deploy - never inlined into the code artifact (mainnet refuses the envvars fallback). Never log API keys / PII into stdout (the agent's audit events are redacted before they hit CloudWatch).
198
+ - Inbound auth is mandatory Cognito OAuth2 - buyers send plain HTTPS + a Bearer (no AWS SigV4). An unauthorized request is rejected 401; there is no anonymous mode.
199
+ - LLM model name selection (paid vs free) is a per-project decision - load `funding-pieverse-llm` if user is unsure which model to use for paid services.
284
200
 
285
201
  ## Reference
286
202
 
287
203
  - `docs/design/single-seller-agent.md` (the A2A deploy model and history)
288
204
  - `docs/design/erc8183-buyer-push.md` (the negotiate → fund → notify_funded line protocol)
289
- - `docs/design/architecture.md` §2.5 (the single seller runtime as-built)
290
- - the `bnbagent-studio-wiring-llm-tools.md` reference (in this same references/ directory) wiring read-only chain tools into the Agent's LLM
205
+ - `docs/design/architecture.md` §2.5 (the single seller runtime - as-built)
206
+ - the `bnbagent-studio-wiring-llm-tools.md` reference (in this same references/ directory) - wiring read-only chain tools into the Agent's LLM