@bnbagent/studio-cli 0.0.6-alpha.1

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.
Files changed (55) hide show
  1. package/DISCLAIMER.md +48 -0
  2. package/LICENSE +201 -0
  3. package/dist/_agentcoreName-DZDWEYD3.js +7 -0
  4. package/dist/_twak-5XQMOFUC.js +25 -0
  5. package/dist/bag.js +19358 -0
  6. package/dist/chunk-7RAKL4AS.js +172 -0
  7. package/dist/chunk-M3ODFCA7.js +1053 -0
  8. package/dist/chunk-U7IDQ3K5.js +14 -0
  9. package/dist/deployCli-N6TPN6XA.js +40 -0
  10. package/package.json +64 -0
  11. package/recipes/agent/code/{{PKG}}/signing.ts.tmpl +287 -0
  12. package/recipes/agent/recipe.toml +35 -0
  13. package/recipes/providers/pieverse-llm/recipe.toml +16 -0
  14. package/recipes/providers/pieverse-llm/skills/funding-pieverse-llm.md +203 -0
  15. package/recipes/runtimes/agentcore/code/{{PKG}}/.dockerignore.tmpl +8 -0
  16. package/recipes/runtimes/agentcore/code/{{PKG}}/Dockerfile.tmpl +50 -0
  17. package/recipes/runtimes/agentcore/code/{{PKG}}/agentCard.ts.tmpl +135 -0
  18. package/recipes/runtimes/agentcore/code/{{PKG}}/dualMain.ts.tmpl +402 -0
  19. package/recipes/runtimes/agentcore/code/{{PKG}}/executor.ts.tmpl +147 -0
  20. package/recipes/runtimes/agentcore/code/{{PKG}}/main.ts.tmpl +344 -0
  21. package/recipes/runtimes/agentcore/code/{{PKG}}/mcpMain.ts.tmpl +677 -0
  22. package/recipes/runtimes/agentcore/code/{{PKG}}/model.ts.tmpl +117 -0
  23. package/recipes/runtimes/agentcore/code/{{PKG}}/sellerCore.ts.tmpl +503 -0
  24. package/recipes/runtimes/agentcore/code/{{PKG}}/tools.ts.tmpl +157 -0
  25. package/recipes/runtimes/agentcore/recipe.toml +97 -0
  26. package/recipes/runtimes/azure-foundry/code/{{PKG}}/.dockerignore.tmpl +8 -0
  27. package/recipes/runtimes/azure-foundry/code/{{PKG}}/Dockerfile.tmpl +47 -0
  28. package/recipes/runtimes/azure-foundry/code/{{PKG}}/agentCard.ts.tmpl +131 -0
  29. package/recipes/runtimes/azure-foundry/code/{{PKG}}/executor.ts.tmpl +504 -0
  30. package/recipes/runtimes/azure-foundry/code/{{PKG}}/foundryMain.ts.tmpl +300 -0
  31. package/recipes/runtimes/azure-foundry/code/{{PKG}}/main.ts.tmpl +196 -0
  32. package/recipes/runtimes/azure-foundry/code/{{PKG}}/mcpMain.ts.tmpl +562 -0
  33. package/recipes/runtimes/azure-foundry/code/{{PKG}}/model.ts.tmpl +117 -0
  34. package/recipes/runtimes/azure-foundry/code/{{PKG}}/tools.ts.tmpl +157 -0
  35. package/recipes/runtimes/azure-foundry/recipe.toml +88 -0
  36. package/recipes/tools-chain/code/{{PKG}}/chainTools.ts.tmpl +166 -0
  37. package/recipes/tools-chain/recipe.toml +11 -0
  38. package/recipes/wallet/recipe.toml +20 -0
  39. package/recipes/x402-buyer/code/{{PKG}}/x402Buyer.ts.tmpl +175 -0
  40. package/recipes/x402-buyer/recipe.toml +15 -0
  41. package/skills/bnbagent-studio.md +107 -0
  42. package/skills/references/bnbagent-studio-adding-to-project.md +241 -0
  43. package/skills/references/bnbagent-studio-buying-from-bazaar.md +169 -0
  44. package/skills/references/bnbagent-studio-buying-via-8183.md +222 -0
  45. package/skills/references/bnbagent-studio-extending-signing.md +227 -0
  46. package/skills/references/bnbagent-studio-operating.md +211 -0
  47. package/skills/references/bnbagent-studio-scaffolding-agent.md +536 -0
  48. package/skills/references/bnbagent-studio-selling-via-8183.md +271 -0
  49. package/skills/references/bnbagent-studio-selling-via-b402.md +194 -0
  50. package/skills/references/bnbagent-studio-use-aws-agentcore.md +208 -0
  51. package/skills/references/bnbagent-studio-use-azure-foundry.md +164 -0
  52. package/skills/references/bnbagent-studio-use-bnb-trial.md +92 -0
  53. package/skills/references/bnbagent-studio-using-altana-wallet.md +68 -0
  54. package/skills/references/bnbagent-studio-using-twak-wallet.md +260 -0
  55. package/skills/references/bnbagent-studio-wiring-llm-tools.md +338 -0
@@ -0,0 +1,260 @@
1
+ ---
2
+ name: bnbagent-studio-using-twak-wallet
3
+ description: When the user's project has [wallet].kind = "twak" (a fully-supported wallet kind, opt in with `--wallet-kind twak`) — creating the Trust Wallet Agent Kit wallet, anchoring its address, funding it, SIWE-binding for Pieverse, deploying it as a container, and working around its known limitations.
4
+ ---
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.
7
+
8
+ # bnbagent-studio-using-twak-wallet
9
+
10
+ Procedure for setting up and operating the **twak** wallet kind (Trust Wallet
11
+ Agent Kit CLI) in a bnbagent-studio project. twak is a **fully-supported**
12
+ wallet kind — opt in at scaffold with `bag init <name> --wallet-kind twak`
13
+ (`evm-local`, a local keystore, is the default). The wallet is a **self-custody,
14
+ AES-256-GCM-encrypted mnemonic** the user controls (not a hosted service),
15
+ living by default in a **project-dedicated** home `.studio/twak`
16
+ (`[wallet].twak_home`), isolated from your main `~/.twak`. The default kind is
17
+ `evm-local` (local keystore); re-scaffold with `--wallet-kind twak` to use twak.
18
+
19
+ ## 1. Install the CLI
20
+
21
+ Needs Node ≥ 20:
22
+
23
+ ```bash
24
+ npm install -g @trustwallet/cli@0.20.0
25
+ twak --version
26
+ ```
27
+
28
+ studio requires **>= 0.20.0** (the SDK forwards `--paymaster-url` on sponsored
29
+ bsc-testnet writes — the flag first shipped in v0.20.0; older CLIs reject it
30
+ with "unknown option"); `bag doctor` and `bag deploy prepare` verify the floor.
31
+
32
+ ## 2. Create the wallet — one time, in YOUR terminal
33
+
34
+ studio can't create it for you (the twak CLI takes the password on argv, upstream
35
+ S-8, and studio never puts secrets on argv). Do these steps yourself.
36
+
37
+ **Every twak command is prefixed with the dedicated home.** Without `HOME=$DH`,
38
+ twak uses your real `~/.twak` (your MAIN wallet) and macOS pops a login-keychain
39
+ password prompt. Set it once:
40
+
41
+ ```bash
42
+ DH=<workspace>/.studio/twak # e.g. ~/proj/.studio/twak
43
+ ```
44
+
45
+ **1. Get Trust Wallet NaaS API credentials** (one time; account-level, NOT
46
+ wallet-specific). Make an app at https://portal.trustwallet.com/dashboard/apps
47
+ → copy its Access ID + HMAC secret. (`twak wallet create` fails with "No API
48
+ credentials found" without them.)
49
+
50
+ **2. Run the setup wizard** — writes the credentials into the dedicated home:
51
+ ```bash
52
+ HOME="$DH" twak setup
53
+ ```
54
+ - **Step 1 (API credentials):** paste the Access ID + HMAC secret.
55
+ WalletConnect Project ID → leave blank, ENTER.
56
+ - **Step 2 ("which harnesses to wire up"): SELECT NONE — press ENTER** on the
57
+ empty list (do NOT press SPACE or `a`). 🔒 This would register twak's
58
+ signing MCP into Claude Code / Cursor / etc., handing wallet+signing power
59
+ to your AI assistant (and any prompt-injection reaching it) — studio forbids
60
+ that: signing is fixed `signing.ts` code, the LLM only receives read-only
61
+ chain tools, and the deployed agent never calls twak via MCP.
62
+ - **Step 3 (Wallet "Pick one"): choose `3) Skip for now`** (you create it in
63
+ the next step). NOT `2) Use WalletConnect with my existing wallet` (binds
64
+ your main/real wallet).
65
+
66
+ **3. Create the wallet** (password UPPER + lower + digit, e.g. `Mypasswd01`;
67
+ `mypasswd01` is rejected). **RECOMMENDED — let studio drive it with the
68
+ password OFF argv** (it resolves the project home from studio.toml, so no
69
+ `HOME=` juggling):
70
+ ```bash
71
+ bag wallet twak-init # interactive hidden prompt
72
+ printf %s "$PW" | bag wallet twak-init --password-stdin # CI / scripts
73
+ bag wallet twak-init --password-file pw.txt # file must be chmod 600
74
+ ```
75
+ It wraps `twak wallet create --no-keychain` (password reaches twak via env +
76
+ piped stdin only), tightens `wallet.json` to mode 600, and adopts the
77
+ address into studio.toml in one go — so steps 5's `bag wallet new` is
78
+ already done.
79
+
80
+ Manual alternative (password lands on argv → `ps` / shell history;
81
+ acceptable only for a throwaway hot wallet):
82
+ ```bash
83
+ HOME="$DH" twak wallet create --password '<StrongPw>' --no-keychain
84
+ ```
85
+ `--no-keychain` keeps the password OUT of the OS keychain — it lives only in
86
+ `TWAK_WALLET_PASSWORD` (step 4), so creation triggers **no macOS keychain
87
+ prompt**. Expect: "Agent wallet created successfully / Wallet registered with backend /
88
+ Generated addresses for 25 chains". (twak then prints "Restart your harness… /
89
+ Try a sample query…" — that's for MCP users; ignore it, studio doesn't use
90
+ twak's MCP.)
91
+
92
+ > **Already have a wallet here?** If twak says `Wallet already exists. Back up
93
+ > … then delete it`, the wallet is already created — do **NOT** follow the
94
+ > literal "delete it". `wallet.json` is the ONLY copy of your AES-256-GCM
95
+ > encrypted mnemonic; deleting it without the mnemonic backed up loses the funds
96
+ > **forever**. Confirm it's yours (`HOME="$DH" twak wallet addresses`), skip
97
+ > create, and go straight to step 5 — `bag wallet new` just ADOPTS the existing
98
+ > address (idempotent, never destructive). Only recreate if you've safely backed
99
+ > up the mnemonic, and then `mv` `wallet.json` to a `.bak` rather than deleting.
100
+
101
+ > **CI / scripts:** use `bag wallet twak-init --password-stdin` /
102
+ > `--password-file` above — it is the supported non-interactive path and
103
+ > works on headless runners (no keychain involved). Avoid the older
104
+ > `TWAK_NONINTERACTIVE=1 TWAK_SETUP_WALLET=create … twak setup` route: it
105
+ > has no `--no-keychain` equivalent, stores the password in the OS
106
+ > keychain, and aborts with `STORAGE_ERROR` on headless / Docker runners.
107
+
108
+ **4. Put the unlock password in `.env.local`** — **YOU edit the file** (never
109
+ through the chat, never `bag env set <literal>` — the password must not reach
110
+ the assistant or argv). Same value as Step 3:
111
+ ```
112
+ # .studio/.env.local
113
+ TWAK_WALLET_PASSWORD=<StrongPw>
114
+ ```
115
+ studio AND the deployed runtime unlock via this env — the keychain copy is
116
+ local-only and never deploys, so this line is mandatory or deploy can't sign.
117
+
118
+ **5. Anchor + activate** — back in a NORMAL shell (**no `HOME=` prefix**; studio
119
+ resolves the home from `[wallet].twak_home` itself, and `bag wallet new`
120
+ ADOPTS the address — it does not create a second wallet):
121
+ ```bash
122
+ cd <workspace>/app/agent
123
+ bag wallet new # writes the NEW address into studio.toml [wallet].address — confirm it's the new wallet, not your main one
124
+ bag llm activate # zero-deposit Pieverse key
125
+ bag doctor # all PASS (zero balance is a WARN, fine)
126
+ ```
127
+
128
+ ### macOS keychain — bypassed by default
129
+
130
+ With `--no-keychain` (step 3) the wallet password lives ONLY in
131
+ `TWAK_WALLET_PASSWORD` (step 4) — twak never reads or writes the OS keychain, so
132
+ both creation and signing trigger **no macOS password prompt**. studio and the
133
+ deployed runtime unlock via that env, so nothing is lost by skipping the keychain.
134
+
135
+ > **Safety net (you normally never see it):** for the rare case you create a wallet
136
+ > WITHOUT `--no-keychain`, `bag init` (and `bag wallet new`) also auto-creates an
137
+ > isolated, **empty-password** keychain under `$DH/Library/Keychains` —
138
+ > secret-free, scoped to `$DH` (your real login keychain untouched), never
139
+ > deployed. With `--no-keychain` twak doesn't touch any keychain at all.
140
+
141
+ > ⚠️ **If you omitted `--no-keychain` and a macOS prompt LOOPS** (or a bare `twak
142
+ > setup` prompted against your **main** login keychain and rejects every password):
143
+ > **Do NOT click "Reset Default Keychain"** — it erases your Wi-Fi passwords, SSH
144
+ > passphrases, and saved app secrets. Quit it with `pkill -9 -f twak`, then
145
+ > recreate the wallet **disk-only**:
146
+ > ```bash
147
+ > HOME="$DH" twak wallet create --password '<StrongPw>' --no-keychain
148
+ > ```
149
+ > and rely on `TWAK_WALLET_PASSWORD` (step 4) to unlock — same end state, no
150
+ > keychain involved.
151
+
152
+ ### Other wallet placements
153
+
154
+ `bag init` always writes a project-dedicated `[wallet].twak_home`; the flow above
155
+ is the default (a brand-new dedicated wallet). Alternatives:
156
+ - **Reuse an existing wallet** across agents → `bag init --twak-home <path>`
157
+ (that wallet's HOME-style dir, containing `.twak/wallet.json`). Same flow:
158
+ create with `--no-keychain`, unlock via `TWAK_WALLET_PASSWORD`.
159
+ - **Your main `~/.twak`** (DISCOURAGED — real funds / bound identities) → opt-in
160
+ only via `bag init --twak-home ~`, or "yes" to the warned prompt (default "no")
161
+ when a machine wallet is detected. Recorded as `[wallet].twak_home = <$HOME>`.
162
+
163
+ Each wallet is its own address → its own ERC-8004 identity, Pieverse SIWE
164
+ binding, and secret bundle; `bag doctor` / `bag deploy` resolve the right one via
165
+ `[wallet].twak_home`.
166
+
167
+ ## 3. Fund it — and keep it a HOT wallet
168
+
169
+ Two assets, two different rules:
170
+
171
+ - **U (payment token)** — the principal for x402 topups (LLM credit) and what
172
+ buyers pay you. x402 payments are **GASLESS** (EIP-3009, the facilitator
173
+ settles), so topping up burns no BNB. A twak wallet is also a supported
174
+ b402 **seller** payout wallet (`bag init --wallet-kind twak --rails b402`);
175
+ receiving needs no signature or gas either.
176
+ - **BNB (gas)** — **testnet: none needed; mainnet: a little for ERC-8183.**
177
+ Testnet: the SDK forwards MegaFuel's testnet paymaster (`--paymaster-url`,
178
+ twak >= 0.20.0), so x402 topups (already gasless) plus **all** 8004/8183
179
+ writes are sponsored — a little tBNB (~0.007) is only a fallback in case
180
+ sponsorship declines a tx. Mainnet: x402 stays gasless and `bag 8004
181
+ register` is gas-sponsored by twak internally (Trust gateway — studio
182
+ passes no paymaster flag), but **`8183 settle` / `fund` self-pay gas**, so
183
+ keep ~0.007 BNB on the wallet for them.
184
+
185
+ > ⚠️ **MegaFuel testnet relay reliability (BUG-029).** The bsctestnet relay
186
+ > has been observed accepting a sponsored write, returning a tx hash, and
187
+ > then never broadcasting it — the hash is unverifiable on every public
188
+ > RPC and the wallet nonce never moves (reproduced 2026-07-24 and
189
+ > 2026-07-28 with raw `twak erc8183 create-job --paymaster-url …`). Do NOT
190
+ > treat raw `twak erc8183` sponsored bsctestnet writes as a stable PASS
191
+ > path for tests/CI. Drive the write through studio (`bag erc8004 …`,
192
+ > `bag erc8183 …`) or the SDK's `TWAKProvider` instead: those classify the
193
+ > failure (`RelaySubmissionUnverifiedError` = relay swallowed it, never
194
+ > persist the hash as pending; `TransactionPendingError` = the tx IS
195
+ > visible, wait) instead of a bare receipt timeout. Self-pay escape
196
+ > hatches: `--no-paymaster` on studio 8004 writes, or
197
+ > `BNBAGENT_USE_PAYMASTER=0` for any studio/SDK call.
198
+
199
+ **Hot-wallet rule**: fund only a few days of spend. The Agent wallet is an
200
+ operational hot wallet, not a treasury — the on-chain balance is the one
201
+ spending limit nothing can bypass. Studio's daily caps
202
+ (`[budget].max_per_day_usd`) are in-process guardrails: real across CLI runs
203
+ (persisted to `.studio/spend-ledger.json`), best-effort in the deployed
204
+ runtime (in-memory, resets on cold start).
205
+
206
+ Testnet faucet: https://www.bnbchain.org/en/testnet-faucet (tBNB, fallback only).
207
+ Mainnet: U via PancakeSwap (BNB not needed — gas is sponsored).
208
+
209
+ ## 4. SIWE binding (Pieverse) — ALWAYS bind before paying
210
+
211
+ Pieverse attributes x402 topups to the **SIWE-bound payer address** (the paid
212
+ call carries no session header on the twak path). `bag llm activate` performs
213
+ the SIWE login (an EIP-191 `sign_message`, which twak supports) before any
214
+ payment, so the normal flow is safe. If you ever top up through a custom
215
+ path: bind first, pay second — an unbound payment cannot be attributed.
216
+
217
+ ## 5. Local dev (no Docker) vs deploy (Container image)
218
+
219
+ **Local dev needs no Docker.** `bag dev` runs the agent **in-process** by
220
+ default (the TS entrypoint, no Docker) — the keystore/twak materialize hooks are
221
+ no-ops locally, so in-process exercises the same code path as the deployed
222
+ container minus the image. Use `bag dev --container` only if you want the
223
+ AgentCore dev container for full image parity (that mode runs via `agentcore
224
+ dev` and needs Docker / Podman / Finch); it is **not** required to develop or
225
+ test the twak agent locally.
226
+
227
+ **Deploy ships a Container image.** The managed AgentCore image can't host the
228
+ twak CLI toolchain, so a twak Agent deploys as a **custom container** (Node ≥ 20
229
+ + the twak CLI). `bag init` already configured everything: `agentcore.json`
230
+ registers a `Container` runtime and `app/agent/Dockerfile` builds the image
231
+ (linux/arm64 — an x86 machine needs docker buildx for cross-build).
232
+
233
+ - Local Docker is **required** for `bag deploy --provider aws`: the pinned
234
+ `bnbagent-deploy` (to which Studio delegates all cloud execution
235
+ to) builds the image locally (linux/arm64) and pushes it to ECR — there is
236
+ no remote-build fallback, so the Docker daemon must be running.
237
+ - Wallet material reaches the runtime ONLY via AWS Secrets Manager
238
+ (`TWAK_WALLET_JSON` / `TWAK_CREDENTIALS_JSON` / `TWAK_WALLET_PASSWORD`),
239
+ never inside the image. `bag deploy prepare` verifies all of this.
240
+
241
+ ## 6. Known limitations (upstream twak CLI v0.20.0)
242
+
243
+ | Limitation | Upstream ref | What you see |
244
+ |---|---|---|
245
+ | ~~Seller `submit` unavailable~~ | ~~REQ-1~~ RESOLVED in v0.19.0 | `submit --opt-params` works — verified on-chain. |
246
+ | ~~Seller `quote` signing broken~~ | ~~S-11 regression in v0.19.0~~ RESOLVED in v0.19.1 | v0.19.0 hex-decoded `0x…` messages and signed the bytes, so provider_sig never verified (testnet also rejected `sign-message --chain bsctestnet`). v0.19.1 signs the literal text (EIP-191): `sign_quote` works on both wallet kinds. |
247
+ | ~~Testnet intent writes self-pay gas~~ | ~~REQ-2~~ RESOLVED in v0.20.0 | twak accepts `--paymaster-url`; the SDK forwards MegaFuel's testnet endpoint on every sponsored write, so testnet 8004/8183 writes are gasless too (the relay itself is flaky — see the BUG-029 warning in §3). Mainnet stays twak-internal (no flag passed). The CLI floor is now **0.20.0** — `bag doctor` / `bag deploy prepare` reject older. |
248
+ | No generic EIP-712 signing | P0 (won't fix) | `[wallet.signing]` is ignored; payments go through the delegated payer's own prechecks + `--max-payment`. Endpoints needing an `Authorization` header *and* x402 are unavailable (e.g. `bag llm key new --initial-usd > 0` — use `--initial-usd 0` + topup + allocate instead, same end state). |
249
+ | No wallet import | S-6 | Switching wallet kinds changes your address → re-run `bag 8004 register` (new on-chain identity). |
250
+ | Programmatic wallet creation forces password onto argv | S-8 | Bridged by `bag wallet twak-init` (password via stdin / 0600 file / hidden prompt — never argv); the manual twak commands remain a fallback. |
251
+ | CLI has no daily/monthly caps | — | Studio's policy layer (`[budget].max_per_day_usd`, host allowlist, per-request caps) is the spend authority for both wallet kinds. |
252
+
253
+ ## 7. Quick health checks
254
+
255
+ ```bash
256
+ bag doctor # [wallet] twak CLI / wallet / address-anchor checks
257
+ bag wallet show # describe(): address, key_location, capabilities
258
+ bag wallet balance # BNB + U via RPC (works on testnet too)
259
+ bag deploy prepare # container/Dockerfile/secret checks before deploy
260
+ ```
@@ -0,0 +1,338 @@
1
+ ---
2
+ name: bnbagent-studio-wiring-llm-tools
3
+ description: When the user wants their agent's LLM to call read-only chain queries (wallet balance, ERC-8004 agent info, ERC-8183 job status, etc.) — exposes the 15 functions in `@bnbagent/studio-runtime/tools` as LLM tools via AI SDK `tool()` wrappers, or any other TS agent framework.
4
+ ---
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.
7
+
8
+ # bnbagent-studio-wiring-llm-tools
9
+
10
+ Wire `bnbagent-studio`'s 15 chain readonly functions into the user's agent so
11
+ the LLM can autonomously query wallet, balance, ERC-8004 identity, ERC-8183
12
+ jobs, etc. Studio ships the pure functions plus two emitted wrapper files: the
13
+ runtime recipe's curated default (`app/agent/src/tools.ts`, `LLM_READ_TOOLS`)
14
+ and the full-inventory `tools-chain` recipe
15
+ (`tools-chain/code/{{PKG}}/chainTools.ts.tmpl`, emitted as
16
+ `app/agent/src/chainTools.ts`); for a non-AI-SDK framework you (Claude Code)
17
+ write a thin wrapping file in the Agent sub-project.
18
+
19
+ In v1 the workspace contains one sub-project, `app/agent/` — the single
20
+ selected-faces seller runtime. LLM tools always live in
21
+ **`app/agent/src/tools.ts`**. The `{{PKG}}` recipe variable resolves to the
22
+ agent's `src/` dir, so the emit target is `app/agent/src/tools.ts` — its
23
+ meaning is "source dir of the agent sub-project", not "package inside a
24
+ single-root project".
25
+
26
+ ## Audience
27
+
28
+ Claude Code (or another agent) editing the user's workspace. The user has run
29
+ `bag init` and wants their Agent sub-project to expose read-only chain queries
30
+ to its LLM (`app/agent/src/tools.ts`). These are READ-ONLY — the Agent's
31
+ signing always stays in `app/agent/src/signing.ts` (fixed code), never an LLM
32
+ tool.
33
+
34
+ ## When to use this skill
35
+
36
+ - The user says "let my agent query its balance" / "agent should know about its
37
+ on-chain jobs" / "give the LLM access to chain state"
38
+ - The user wants to wire chain tools into a **non-AI-SDK** stack (LangChain.js,
39
+ a bare OpenAI/Anthropic SDK tool loop, custom)
40
+ - The user wants to **customize** which chain queries their LLM sees
41
+ - The user uses `bag init` but wants to extend / re-emit the tool list
42
+
43
+ ## When NOT to use this skill
44
+
45
+ - The user wants the Agent to **sign transactions / pay** — in the single seller
46
+ model all signing (quote-sign, submit, settle) is FIXED code
47
+ in `app/agent/src/signing.ts` (called by A2A's `SellerAgentExecutor` or MCP's
48
+ `src/mcpMain.ts` tools), **never** an
49
+ LLM-callable tool. The LLM only produces work text after a job is verified
50
+ funded; fixed code prices, clamps, signs, and submits. There is no "wire a
51
+ signing tool into the LLM" path in v1.
52
+ - The user is doing dev-time debugging via Claude Code — that's the `bag` CLI
53
+ read commands (`bag wallet`, `bag erc8183 status/list`, …), not LLM tools.
54
+
55
+ ---
56
+
57
+ ## The 15 functions
58
+
59
+ All in `@bnbagent/studio-runtime/tools`. Each returns a plain object (or
60
+ string); the wire-format keys stay snake_case (the tool contract shared with
61
+ LLMs and MCP clients).
62
+
63
+ ### Wallet & chain basics — always safe
64
+
65
+ | Function | Reads | Dependency |
66
+ |---|---|---|
67
+ | `walletInfo()` | active wallet address + source + keystore dir | none |
68
+ | `walletAddress()` | active wallet address (alias of walletInfo) | none |
69
+ | `walletList()` | all configured keystore addresses | dev concern |
70
+ | `balanceNative(address?, network?)` | BNB / tBNB balance | none |
71
+ | `balanceU(address?, network?)` | U token balance | `[u_token]` |
72
+ | `networkInfo(network?)` | chain id, RPC host, contract addresses | none |
73
+ | `txStatus(txHash, network?)` | tx receipt + revert reason | none |
74
+
75
+ ### LLM provider — Pieverse-specific
76
+
77
+ | Function | Reads | Dependency |
78
+ |---|---|---|
79
+ | `pieverseUsage(days=7)` | LLM spend on Pieverse | `[llm.provider=pieverse-llm]` |
80
+
81
+ Note: `pieverseUsage` does a SIWE EIP-191 personal_sign (no on-chain effect,
82
+ domain-locked). Other functions are pure RPC reads.
83
+
84
+ ### ERC-8004 identity
85
+
86
+ | Function | Reads | Dependency |
87
+ |---|---|---|
88
+ | `agentInfo(agentId, network?)` | on-chain ERC-8004 record by ID | `[erc8004]` |
89
+ | `agentByAddress(address, network?)` | look up agent by owner address | `[erc8004]` |
90
+
91
+ ### ERC-8183 jobs
92
+
93
+ | Function | Reads | Dependency |
94
+ |---|---|---|
95
+ | `jobStatus(jobId, network?)` | job state, client, provider, budget | `[erc8183]` |
96
+ | `jobList(limit=10, mine=false, provider?, network?)` | recent jobs | `[erc8183]` |
97
+ | `jobCount(network?)` | network-wide inflight job count | `[erc8183]` |
98
+
99
+ ### Advanced / footguns
100
+
101
+ | Function | Reads | Why footgun |
102
+ |---|---|---|
103
+ | `blockInfo(block?, network?)` | block summary | usually noise for LLM |
104
+ | `contractCallView(address, functionSignature, args?, outputTypes?, network?)` | arbitrary `eth_call` | accepts **any** ABI — LLM can be prompt-injected into calling attacker contracts |
105
+
106
+ ---
107
+
108
+ ## Step 1 — Confirm the user has run `bag init`
109
+
110
+ ```bash
111
+ # from workspace root:
112
+ ls app/agent/studio.toml && (ls app/agent/src/main.ts 2>/dev/null || ls app/agent/src/mcpMain.ts)
113
+ ```
114
+
115
+ If `app/agent/src/tools.ts` already exists, the user has the AI SDK form
116
+ already. Skip to Step 4 if they want to customize.
117
+
118
+ ---
119
+
120
+ ## Step 2 — Identify the stack
121
+
122
+ Look at `app/agent/src/main.ts` or `app/agent/src/mcpMain.ts` imports /
123
+ `app/agent/package.json`:
124
+
125
+ | Sign in code | Stack |
126
+ |---|---|
127
+ | `import { tool, generateText } from "ai"` | **AI SDK** (use stock recipe) |
128
+ | `from "langchain"` / `from "@langchain/core"` | **LangChain.js** |
129
+ | `openai.chat.completions.create({ tools: ... })` | **bare OpenAI SDK loop** |
130
+ | `anthropic.messages.create({ tools: ... })` | **bare Anthropic SDK loop** |
131
+
132
+ If AI SDK: emit the stock recipe and stop.
133
+
134
+ ```bash
135
+ bag recipe code tools-chain > app/agent/src/chainTools.ts # full inventory + CHAIN_READ_TOOLS
136
+ ```
137
+
138
+ Then in the protocol entrypoint (`app/agent/src/main.ts` for A2A,
139
+ `app/agent/src/mcpMain.ts` for MCP), pass the tool set into the generate call:
140
+
141
+ ```ts
142
+ import { LLM_READ_TOOLS } from "./tools.js";
143
+ // inside runWork:
144
+ const { text } = await generateText({ model, tools: LLM_READ_TOOLS, prompt });
145
+ ```
146
+
147
+ For non-AI-SDK stacks, continue.
148
+
149
+ ---
150
+
151
+ ## Step 3 — Write a framework-specific wrapper
152
+
153
+ Studio doesn't ship adapters for non-AI-SDK stacks (commitment: "agent code
154
+ the user owns"). You write a wrapper file in the user's project. Pattern:
155
+ import the pure functions, wrap each with the framework's tool primitive.
156
+
157
+ ### LangChain.js
158
+
159
+ ```ts
160
+ // app/agent/src/tools.ts
161
+ import { tool } from "@langchain/core/tools";
162
+ import { z } from "zod";
163
+ import * as cr from "@bnbagent/studio-runtime/tools";
164
+
165
+ export const LLM_READ_TOOLS = [
166
+ tool(async () => cr.walletInfo(), {
167
+ name: "wallet_info",
168
+ description: "Describe the agent's active wallet.",
169
+ schema: z.object({}),
170
+ }),
171
+ tool(async ({ address, network }) => cr.balanceNative(address ?? null, network),
172
+ {
173
+ name: "balance_native",
174
+ description: "Native BNB balance of an address (defaults to the agent's wallet).",
175
+ schema: z.object({ address: z.string().optional(), network: z.string().optional() }),
176
+ }),
177
+ // balanceU (requires [u_token]), networkInfo, txStatus,
178
+ // pieverseUsage (requires [llm.provider=pieverse-llm]),
179
+ // agentInfo / agentByAddress (require [erc8004]),
180
+ // jobStatus / jobList (require [erc8183]) — same pattern.
181
+ // ⚠️ contractCallView accepts any ABI — keep it out unless deliberate.
182
+ ];
183
+ ```
184
+
185
+ Wire into the agent (e.g. `createReactAgent({ llm, tools: LLM_READ_TOOLS })`).
186
+
187
+ ### Bare OpenAI / Anthropic tool loop
188
+
189
+ For a hand-rolled tool loop, declare each function in the provider's tool JSON
190
+ format and dispatch on the tool name:
191
+
192
+ ```ts
193
+ // app/agent/src/tools.ts
194
+ import * as cr from "@bnbagent/studio-runtime/tools";
195
+
196
+ export const CHAIN_READ_FUNCTIONS: Record<string, (args: any) => Promise<unknown>> = {
197
+ wallet_info: async () => cr.walletInfo(),
198
+ balance_native: async (a) => cr.balanceNative(a.address ?? null, a.network),
199
+ balance_u: async (a) => cr.balanceU(a.address ?? null, a.network), // requires [u_token]
200
+ network_info: async (a) => cr.networkInfo(a.network),
201
+ tx_status: async (a) => cr.txStatus(a.tx_hash, a.network),
202
+ // pieverse_usage, // requires [llm.provider=pieverse-llm]
203
+ // agent_info, agent_by_address, // require [erc8004]
204
+ // job_status, job_list, // require [erc8183]
205
+ // contract_call_view, block_info, wallet_list, wallet_address,
206
+ };
207
+ ```
208
+
209
+ ### Generic
210
+
211
+ For any framework that accepts a typed function + description, the pattern is
212
+ identical — wrap each `cr.*` function in the framework's tool primitive and
213
+ assemble a list. The emitted AI SDK files (`tools.ts` / `chainTools.ts`)
214
+ already carry per-tool descriptions and zod input schemas you can copy from.
215
+
216
+ ---
217
+
218
+ ## Step 4 — Customize what the LLM sees
219
+
220
+ The recipe gives a sensible default; the user owns the file. Common edits:
221
+
222
+ **Remove tools** the agent doesn't need (smaller LLM context = better focus):
223
+
224
+ ```ts
225
+ export const LLM_READ_TOOLS: ToolSet = {
226
+ balance_u: CHAIN_READ_TOOLS.balance_u, // only thing this agent really needs
227
+ tx_status: CHAIN_READ_TOOLS.tx_status,
228
+ };
229
+ ```
230
+
231
+ **Uncomment Pieverse usage** if the user's `[llm].provider = "pieverse-llm"`:
232
+
233
+ ```ts
234
+ pieverse_usage: ..., // requires [llm.provider=pieverse-llm]
235
+ ```
236
+
237
+ **Uncomment 8004 / 8183 reads** if the user added those sections to
238
+ `studio.toml` after `bag init` (e.g., ran `bag erc8004 register` later).
239
+
240
+ **Never uncomment** `contract_call_view` without thinking — it accepts any ABI
241
+ signature and an LLM jailbreak / prompt injection can drain via reads from
242
+ malicious contracts (or hammer expensive RPC). Keep commented unless the
243
+ agent has a specific debug / introspection job and the user has read the
244
+ tool description.
245
+
246
+ ---
247
+
248
+ ## Step 5 — Write operations live in fixed code, NOT LLM tools
249
+
250
+ Read tools (this skill) are safe-ish — worst case the LLM gives wrong info.
251
+ **Write operations** (quote-sign, submit, settle) are the whole point of the
252
+ single seller model's signing boundary: they live as FIXED code in
253
+ `app/agent/src/signing.ts`, are dispatched by A2A's `SellerCore` (in
254
+ `app/agent/src/sellerCore.ts`, which `SellerAgentExecutor` inherits) or MCP's
255
+ server tools (`negotiate`/`notify_funded`; `settle` is the manual `bag erc8183 settle`),
256
+ and are **never** put in the LLM's `tools` set. The quote price is rule-based
257
+ (fixed code reads the list `price`, clamps it to `[min,max]`, then signs — the
258
+ LLM never touches the price); the LLM only PRODUCES the work text in `notify_funded` delivery —
259
+ money never flows through a tool call.
260
+
261
+ The one automatic signing path outside `signing.ts` is the budget-gated
262
+ model-wrapper LLM-credit auto-renew hook (in the emitted
263
+ `app/agent/src/model.ts`'s `buildModel()` factory, backed by
264
+ `@bnbagent/studio-runtime/pieverse` `PieverseCreditEnsurer`) — also automatic,
265
+ also **not** an LLM tool.
266
+
267
+ The x402 buyer kernel (`@bnbagent/studio-runtime/x402`, the payment signer) is
268
+ **not** an LLM tool either — in v1 it is reachable only as the Agent's
269
+ automatic model-wrapper LLM-credit auto-renew (above), driven by fixed code,
270
+ never the LLM. Do not wire it into the Agent's `tools` set. The SDK's
271
+ `SigningPolicy` is the second-layer gate on every signature regardless.
272
+
273
+ ---
274
+
275
+ ## Common questions
276
+
277
+ **Q: Why isn't `app/agent/src/tools.ts` auto-synced with `app/agent/studio.toml` changes?**
278
+
279
+ A: The recipe is emitted once at `bag init` time; the file is the user's. To
280
+ refresh after configuring new features (e.g., enabling `[erc8183]` later):
281
+
282
+ ```bash
283
+ bag recipe code tools-chain > app/agent/src/chainTools.ts.new
284
+ diff app/agent/src/chainTools.ts app/agent/src/chainTools.ts.new
285
+ # manually merge — preserves any user customizations
286
+ ```
287
+
288
+ **Q: Does this work in AgentCore deployment?**
289
+
290
+ A: Yes. The functions only need `@bnbagent/studio-runtime` (already a
291
+ dependency of the Agent sub-project via `app/agent/package.json`). No
292
+ subprocess, no MCP transport — pure in-process calls. The deploy artifact
293
+ ships the built `tools.ts` as part of the Agent that serves its selected
294
+ A2A/MCP faces on AgentCore.
295
+
296
+ **Q: Is this the same as `bag init --protocols MCP`?**
297
+
298
+ A: No. `bag init --protocols MCP` selects an **external seller face**
299
+ (streamable-HTTP `/mcp` for buyers). This skill wires read-only chain queries
300
+ into the Agent's own LLM as in-process tools. v0.0.1 doesn't ship
301
+ MCP-for-agent (the agent runtime consuming a subprocess MCP server as its LLM
302
+ tools). MCP here is instead an *external seller face* (`bag init --protocols
303
+ MCP` or `--protocols A2A,MCP`) — see `docs/design/decisions.md`. For
304
+ now: in-process is simpler, faster, and matches commitment "agent code the
305
+ user owns".
306
+
307
+ **Q: How do I know if my `app/agent/src/tools.ts` is up to date?**
308
+
309
+ A: Re-emit with `bag recipe code tools-chain > app/agent/src/chainTools.ts.new`
310
+ and diff against your current file. If studio added new tools in a newer
311
+ version, they'll appear in the emit; you decide whether to adopt.
312
+
313
+ **Q: Can I reuse a Pieverse API key I created with a DIFFERENT wallet (BYOK)?**
314
+
315
+ A: Yes, for inference — with one caveat. The LLM-credit auto-renew hook
316
+ (`PieverseCreditEnsurer`) authenticates to Pieverse with the **agent's signing
317
+ wallet** and can only inspect/allocate keys **that wallet owns**. If you set
318
+ `[llm.pieverse].key_hash` to a key created by another wallet (the owner is your
319
+ day-to-day wallet, not the agent's throwaway signer), the hook can't see it: it
320
+ detects the owner mismatch, prints one warning, **disables itself for that
321
+ session, and lets inference run on the key's existing Bearer credit**. It does
322
+ not crash the agent and does not repeat the check.
323
+
324
+ Recommended BYOK setup — do NOT hand the owner wallet's private key to the
325
+ agent (that would violate the "keys stay in the user's environment" boundary):
326
+
327
+ 1. Put the key in the agent env: `PIEVERSE_LLM_API_KEY=sk-pv-…` in
328
+ `.studio/.env.local`, plus `[llm.pieverse].key_hash = "0x…"` and `network`
329
+ in `studio.toml`.
330
+ 2. Turn off auto-renew so the hook doesn't try to allocate a key it can't own:
331
+ `bag llm auto-renew llm off`.
332
+ 3. Top the key up yourself in the Pieverse portal (or from the owner wallet)
333
+ when it runs low — the agent will 402 upstream if the Bearer credit is
334
+ exhausted.
335
+
336
+ If you instead want the agent to auto-allocate/topup, activate a key the
337
+ **agent's own** signing wallet owns with `bag llm activate` (zero-deposit is
338
+ fine) and keep auto-renew on.