@bnbagent/studio-cli 0.0.6-alpha.6 → 0.0.6-alpha.8

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,291 +1,206 @@
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, so you must provision the Cognito OAuth2
164
- authorizer first.
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
168
- bag deploy provision-cognito # emit the Cognito CDK app; run `cdk deploy`, wire discoveryUrl/clientId
169
120
  bag deploy --provider aws # ship the agent to AgentCore (selected protocol)
170
121
  bag deploy verify --provider aws # delegated status + reconcile ERC-8004 identity
171
122
  ```
172
123
 
173
- ERC-8004 identity is registered with the **AgentCore endpoint**: A2A uses
174
- `AgentEndpoint.a2a(baseUrl, "0.3.0")` (normalizing to
175
- `/.well-known/agent-card.json`), while MCP records the `/mcp` endpoint plus access
176
- metadata. Buyers reach the agent directly. `bag deploy verify --provider aws`
177
- 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.
178
125
 
179
126
  **Hard rules**:
127
+
180
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.
181
- - To serve external buyers, configure the Cognito authorizer (`provision-cognito` `cdk deploy --outputs-file` `provision-cognito --wire`); `bag deploy prepare` warns (W9) if unset but does NOT block. With no authorizer the runtime is IAM/SigV4 owner-only (never anonymous) buyers without AWS creds just can't reach it.
182
- - Price bounds (`min_price`/`max_price`) live with the Agent it clamps + signs the quote.
183
-
184
- ## Stage 5 How a SUBMITTED job happens
185
-
186
- There is **no background poll loop** in v1. Delivery is triggered by
187
- `notify_funded`; the execution model depends on the selected protocol:
188
-
189
- 1. **A2A buyer push (the prompt path):** buyer negotiates over A2A (`negotiate`
190
- skill) buyer anchors the signed quote on-chain (`createJob` `register`
191
- `setBudget` → `fund`, provider = the agent address) → buyer pushes a
192
- `notify_funded` A2A message for the `job_id` the executor synchronously
193
- re-verifies (`verifySignedJob`) and **acks `accepted`** at once, then in a
194
- **background task** does the LLM work and SIGNS + submits the deliverable
195
- on-chain → job → SUBMITTED. The buyer **polls the chain** for the result (it
196
- does not wait on the ack), then approves or disputes within `dispute_window`
197
- (24h on testnet). While any background delivery is in flight the runtime
198
- reports `/ping` `HEALTHY_BUSY` (AgentCore's long-running async pattern), so the
199
- scale-to-zero runtime stays warm until the work lands — bounded by the session
200
- max-lifetime (≤8h).
201
- 2. **A2A in-process sweep (the fallback):** on every accepted `notify_funded`, the
202
- executor opportunistically sweeps (in the background)
203
- `ERC8183JobOps.getPendingJobs()` for other FUNDED jobs assigned to this
204
- provider and delivers them too. This catches jobs whose buyer funded on-chain
205
- but never pushed `notify_funded`. The sweep is **deduped** (a job already being
206
- delivered — by the notification or a concurrent sweep — is skipped via an
207
- in-flight set, so notify + sweep never double-deliver the same job),
208
- **idempotent** (`verifySignedJob` returns non-OK for an already-SUBMITTED
209
- job, so there is no state file), and **best-effort** (one bad job never aborts
210
- the sweep, and a sweep failure never affects the ack).
211
- 3. **MCP synchronous delivery:** buyer negotiates through the `negotiate` MCP
212
- tool, funds on-chain, then calls `notify_funded`; the tool verifies, runs the
213
- work, and signs + submits before returning, with progress heartbeats. There is
214
- no background ack/sweep path in MCP.
215
-
216
- Because the sweep runs only when *someone* invokes `notify_funded` (and only while
217
- the runtime is warm), a totally idle, scaled-to-zero agent will not deliver during
218
- the cold window until the next notify. A periodic Lambda poller is the v2
219
- robustness path that closes it. The full line protocol is in
220
- `docs/design/erc8183-buyer-push.md`.
221
-
222
- 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):
223
143
 
224
144
  ```bash
225
145
  bag erc8183 submit <job_id> "<deliverable text>" [--metadata-json '{...}']
226
146
  ```
227
147
 
228
- Use only if the Agent produced a deliverable out-of-band and you need to attach it
229
- manually.
148
+ Use only if the Agent produced a deliverable out-of-band and you need to attach it manually.
230
149
 
231
- ## Stage 6 Defending against disputes
150
+ ## Stage 6 - Defending against disputes
232
151
 
233
152
  Buyer can `settle --action dispute` within `dispute_window`. Seller responses:
234
153
 
235
154
  | Symptom | Diagnosis | Action |
236
- |---|---|---|
155
+ | --- | --- | --- |
237
156
  | Buyer disputed within 24h | Their right; goes to quorum vote | Provide evidence via the off-chain governance flow; don't argue on-chain |
238
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` |
239
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 |
240
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 |
241
160
 
242
161
  **Hard rules**:
162
+
243
163
  - Never tamper with quorum vote signals (no fake validators / no spam-disputes).
244
- - 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.
245
165
  - Keep the agent's logs (it prints redacted audit events to stdout → CloudWatch).
246
166
 
247
- ## Stage 7 Settle + withdraw funds
167
+ ## Stage 7 - Buyer settlement and seller payout
248
168
 
249
- `settle` is the **seller's manual step** there is no in-runtime auto-settle in
250
- 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:
251
170
 
252
171
  ```bash
253
- bag erc8183 settle <job_id> # default --action approve
172
+ bag erc8183 settle <job_id> # buyer wallet; default --action approve
254
173
  bag erc8183 status <job_id> # confirm COMPLETED
255
174
  # Funds auto-transfer on COMPLETED in the current contract; no manual withdraw needed.
256
175
  ```
257
176
 
258
- Older contracts may have required a manual `withdraw` confirm against the
259
- deployed commerce contract's behavior.
177
+ Older contracts may have required a manual `withdraw` - confirm against the deployed commerce contract's behavior.
260
178
 
261
179
  ## How a buyer reads the deliverable
262
180
 
263
- The agent serves **no** job-query endpoint. The buyer reads the deliverable back
264
- from the on-chain submission (the `submit` tx carries the deterministic
265
- `deliverable_url`) / the IPFS object. This is by design — the chain is the shared
266
- 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.
267
182
 
268
183
  ## Common errors + remediation
269
184
 
270
185
  | Error | Cause | Fix |
271
- |---|---|---|
272
- | 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 |
273
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 |
274
- | `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 |
275
190
  | `PieverseAccountBalanceExhaustedError` mid-job | Agent's LLM credit ran out | Let it surface; run `bag llm topup`; consider `bag budget enable` |
276
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` |
277
192
 
278
193
  ## Hard rules (security boundary)
279
194
 
280
195
  - Don't store buyer-supplied data outside the request lifecycle (privacy + storage cost).
281
- - The Agent signs only for **its own** quote / submit / settle actions; it never signs for the buyer.
282
- - 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).
283
- - 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.
284
- - 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.
285
200
 
286
201
  ## Reference
287
202
 
288
203
  - `docs/design/single-seller-agent.md` (the A2A deploy model and history)
289
204
  - `docs/design/erc8183-buyer-push.md` (the negotiate → fund → notify_funded line protocol)
290
- - `docs/design/architecture.md` §2.5 (the single seller runtime as-built)
291
- - 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