Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
273 changes: 158 additions & 115 deletions docs/developer-kit/bnbchain-studio/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,159 +4,202 @@ title: BNB Agent Studio Architecture

# Architecture

BNB Agent Studio wraps the [BNB Agent SDK](../bnbagent-sdk/index.md) with scaffolding, safety controls, and IDE integration. A v1 seller project is **two deployable artifacts** on top of a **six-layer stack**.
BNB Agent Studio wraps the [BNB Agent SDK](../bnbagent-sdk/index.md) with scaffolding,
safety boundaries, and IDE integration. A project is **one deployable runtime** composed
from orthogonal recipes.

## Six-layer stack
## One runtime, one signer

| Layer | What |
|-------|------|
| **L1 β€” user code** | `app/agent/*`, `app/service/*` β€” emitted by recipes, you own and edit |
| **L2 β€” IDE** | Claude Code / Cursor β€” reads skills, calls CLI/MCP, edits your files |
| **L3 β€” surfaces** | `bag` CLI, MCP server, recipes, skills |
| **L4 β€” `bnbagent_studio_core`** | Wallet factory, `Policy`, ERC-8004/8183 workflows, x402, audit log |
| **L5 β€” `bnbagent-sdk`** | Protocol clients (`ERC8004Agent`, `ERC8183Client`, `EVMWalletProvider`) |
| **L6 β€” chain** | BSC testnet/mainnet β€” ERC-8004 registry, [APEX / ERC-8183](https://github.com/bnb-chain/apex-contracts#deployments), x402 |
A single deployed process serves every public face you selected and holds the only key.
There is no separate keyless service tier and no cross-service invoke hop.

```mermaid
graph TB
subgraph L1["L1 Β· User code"]
Agent["app/agent/"]
Service["app/service/"]
end
| Entrypoint | Face | Local surface | Runtimes |
| --- | --- | --- | --- |
| `src/unifiedMain.ts` | A2A (+ X402) | agent card and JSON-RPC on `:9000` | AgentCore, Azure Foundry |
| `src/mcpMain.ts` | MCP | Streamable HTTP at `:8000/mcp` | AgentCore, Azure Foundry (local only) |
| `src/dualMain.ts` | A2A-native with tunneled `/mcp` | `:9000` | AgentCore only |

subgraph L2["L2 Β· IDE"]
IDE["Claude Code / Cursor"]
end
Faces are composable (`--protocols`); one seller core and one wallet serve all of them.

subgraph L3["L3 Β· Studio surfaces"]
CLI["bag CLI"]
MCP["MCP server"]
Skills["Skills"]
Recipes["Recipes"]
```mermaid
graph TB
Buyer["Buyer"]
subgraph RT["One deployed runtime Β· sole key-holder"]
Face["unifiedMain.ts / mcpMain.ts / dualMain.ts"]
Seller["sellerCore.ts Β· runWork()"]
Sign["signing.ts Β· fixed code"]
LLM["LLM + read-only chain tools"]
end
SDKL["@bnbagent/studio-runtime"]
SDK["@bnbagent/sdk"]
Chain["BSC Β· ERC-8004 Β· ERC-8183 Β· B402"]

Buyer -->|"negotiate / notify_funded / x402"| Face
Face --> Seller
Seller --> LLM
Face --> Sign
Sign --> SDKL
Seller --> SDKL
SDKL --> SDK
SDK --> Chain
```

subgraph L4["L4 Β· bnbagent_studio_core"]
Core["config Β· policy Β· workflows"]
end
## The bounded operations

subgraph L5["L5 Β· bnbagent-sdk"]
SDK["ERC8004 Β· ERC8183 Β· wallet"]
end
The ERC-8183 rail exposes exactly two operations β€” deliberately narrow, so neither the
LLM nor a buyer can widen them.

subgraph L6["L6 Β· BSC"]
Chain["8004 + 8183 + x402"]
end
**`negotiate`** β€” a rule-based price clamp against `studio.toml`, then an EIP-191
signature. **No LLM touches money**: pricing is deterministic code.

IDE --> Skills
IDE --> CLI
IDE --> MCP
IDE --> Agent
CLI --> Recipes
CLI --> Core
MCP --> Core
Agent --> Core
Service --> SDK
Core --> SDK
SDK --> Chain
```
**`notify_funded`** β€” verify the funded job on-chain (signed terms, assigned provider,
status, budget, funded state) **before** doing paid work, produce the deliverable, then
submit its reference on-chain. A2A acknowledges first and delivers in the background;
MCP delivers synchronously inside the tool call.

## Two-layer deploy model
The optional x402 rail adds an anonymous HTTP request at `/x402`. A positive price
settles through B402 before work starts; an explicit zero is FREE passthrough and
bypasses the facilitator entirely.

The split exists because AgentCore is invoke-only β€” no public HTTP routes, no background poll loop.
`settle` is **manual** β€” `bag erc8183 settle <jobId>`. Studio never silently
auto-settles a buyer's job.

| Layer | Path | Deploy target | Holds key? | Runs LLM? |
|-------|------|---------------|------------|-----------|
| **A β€” Agent** | `app/agent/` | AWS Bedrock AgentCore | Yes (sole signer) | Yes |
| **B β€” Service** | `app/service/` | EC2 / Fargate | No (keyless) | No |
## Signing boundary

**Dependency is one-way:** Service β†’ Agent. The public Service can only *ask* the Agent to sign; the Agent re-validates on chain before signing.
All signing is fixed entrypoint code in `app/agent/src/signing.ts`, or the runtime's
bounded x402 payment handler. It is **never** an LLM-callable tool, and no general
signing tool is exposed. The LLM's chain tools are read-only.

### Action envelopes
The encrypted keystore lives at the workspace root in `.studio/wallets/` β€” outside the
deploy `codeLocation`, so no packaging path can bundle it into an artifact. It reaches a
deployed runtime only through the selected provider's delegated secret channel.

The Agent is invoked on fixed action envelopes β€” never via LLM tools:
## Layer stack

| Action | Purpose |
|--------|---------|
| `quote` | Sign a price offer for a negotiate request |
| `fulfill` | Execute work and submit deliverable |
| `settle` | Apply policy verdict after dispute window |
| Layer | What |
|-------|------|
| **L1 β€” your code** | `app/agent/src/*` β€” emitted by recipes, you own and edit |
| **L2 β€” IDE** | Claude Code / Cursor β€” reads the skill, drives the CLI, edits your files |
| **L3 β€” Studio surfaces** | `bag` CLI, `bag mcp serve` (15 read-only tools), skills, recipes |
| **L4 β€” `@bnbagent/studio-runtime`** | Seller runtime, wallet loader, signing policy, x402 payment handler, audit log |
| **L5 β€” `@bnbagent/sdk`** | Protocol clients β€” `ERC8004Agent`, `ERC8183Client`, `EVMWalletProvider` |
| **L6 β€” chain** | BSC testnet/mainnet β€” ERC-8004 registry, ERC-8183, B402 |

All signing lives in `app/agent/signing.py` β€” fixed entrypoint code, never an LLM-callable tool.
Cloud lifecycle mutations are delegated to the pinned
[`@bnbagent/deploy-cli`](https://www.npmjs.com/package/@bnbagent/deploy-cli); the
generated project depends on `@bnbagent/studio-runtime`, **not** on the CLI.

## Recipe composition

`bag init` composes your project from orthogonal recipe axes:

```
bag/recipes/
β”œβ”€β”€ frameworks/<X>/ e.g. frameworks/adk/
β”œβ”€β”€ runtimes/<Y>/ e.g. runtimes/agentcore/
└── providers/<Z>/code/<framework>/
e.g. providers/pieverse-llm/code/adk/
`bag init` composes the project from orthogonal recipe axes:

```text
recipes/
β”œβ”€β”€ agent/ signing.ts
β”œβ”€β”€ wallet/ wallet selection (evm-local Β· twak Β· altana)
β”œβ”€β”€ runtimes/agentcore/ AWS Bedrock AgentCore entrypoints + Dockerfile
β”œβ”€β”€ runtimes/azure-foundry/ Azure AI Foundry entrypoints + Dockerfile
β”œβ”€β”€ providers/pieverse-llm/ Pieverse LLM wiring + funding playbook
β”œβ”€β”€ tools-chain/ chainTools.ts β€” read-only chain tools
└── x402-buyer/ x402Buyer.ts β€” optional buyer rail
```

| Axis | v1 default | Emitted into |
|------|------------|--------------|
| Framework | Google ADK | `app/agent/main.py`, `tools.py`, `managed_model.py` |
| Runtime | AgentCore | `app/agent/main.py`, `agentcore/agentcore.json` |
| LLM provider | Pieverse | `app/agent/managed_model.py` |
| Service | `8183-service` | `app/service/service.py` (framework-neutral, keyless) |
| Axis | Default | Emits |
|------|---------|-------|
| Agent | always | `signing.ts` |
| Runtime | `agentcore` | `unifiedMain.ts`, `mcpMain.ts`, `dualMain.ts`*, `executor.ts`, `sellerCore.ts`, `tools.ts`, `model.ts`, `agentCard.ts`, `Dockerfile` |
| LLM provider | `pieverse-llm` | provider wiring in `model.ts` |
| Wallet | `evm-local` | keystore selection and config |
| Chain tools | always | `chainTools.ts` |
| x402 buyer | opt-in | `x402Buyer.ts` |

### Emitted vs library
\* `dualMain.ts` is AgentCore-only. Azure Foundry ships no `dualMain` template, which is
why Foundry deploys **A2A scaffolds only** β€” an MCP entrypoint is rejected before deploy.

**Emitted (user-owned β€” edit freely):**
The A2A entrypoint is byte-identical across both runtimes (pinned by a parity test), so
the same image deploys to either cloud.

- `app/agent/main.py` β€” runtime entrypoint
- `app/agent/managed_model.py` β€” provider Γ— framework glue
- `app/agent/tools.py` β€” read-only chain tools for the LLM
- `app/agent/signing.py` β€” protocol-neutral signing entrypoints
- `app/service/service.py` β€” keyless Layer B

**Library (`bnbagent_studio_core` β€” shipped with `bnbagent-studio`):**

- `studio.toml` schema, audit log protocol
- `SigningPolicy`, `BudgetGate`, `expected_recipient`
- Wallet loader, ERC-8183 workflows, x402 buyer, `chain_readonly` tools
- Pieverse credit ensurer, SIWE retry
### Emitted vs library

## Workspace isolation
**Emitted β€” you own it, edit freely:**

- `sellerCore.ts` β€” the work your agent sells (`runWork`); the file you normally edit
- `signing.ts` β€” fixed quote / verify / submit path
- `tools.ts`, `chainTools.ts` β€” read-only chain tools for the LLM
- `model.ts` β€” LLM provider glue
- `unifiedMain.ts`, `mcpMain.ts`, `dualMain.ts` β€” face entrypoints
- `executor.ts`, `agentCard.ts` β€” shared seller executor and A2A card
- `x402Buyer.ts` β€” optional buyer rail

**Library β€” shipped in `@bnbagent/studio-runtime`:**

- `studio.toml` schema and the audit-log protocol
- signing policy and budget gating
- wallet loader, ERC-8183 workflows, the bounded x402 payment handler

## Workspace layout

```text
weatheragent/
β”œβ”€β”€ package.json Β· pnpm-workspace.yaml workspace markers
β”œβ”€β”€ AGENTS.md safety rules for coding agents
β”œβ”€β”€ agentcore/ deployment descriptor + AWS targets
β”œβ”€β”€ .studio/
β”‚ β”œβ”€β”€ .env.local gitignored secrets, mode 0600
β”‚ └── wallets/ encrypted keystore, outside deployable code
└── app/agent/
β”œβ”€β”€ studio.toml network Β· wallet Β· LLM Β· policy Β· rails Β· faces
└── src/ the emitted TypeScript above
```

`bag init` emits two **independent sub-projects**, each with its own `pyproject.toml`, `studio.toml`, and `.env.local`:
Two boundaries do the security work:

1. **Keystore outside deploy codeLocation** β€” `.studio/wallets/` at workspace root, outside `app/agent/`, so no packaging path bundles it.
2. **Keyless Service boundary** β€” Service sub-project has no `bnbagent-studio` dependency and no `[wallet]` config.
3. **Lean Service image** β€” ~200 MB smaller without studio CLI deps.
4. **No shared mutable config** β€” only `[network].default` and provider address sync across layers.
1. **Keystore outside the deploy `codeLocation`** β€” `.studio/wallets/` sits at the
workspace root, so no packaging path bundles it.
2. **Signing outside the LLM's reach** β€” fixed code only; the model gets read-only tools.

## Commerce flow (seller)

```text
Buyer Runtime (sole signer) BNB Chain
β”‚ negotiate β”‚ β”‚
β”‚ ─────────────────────────────────►│ clamp price, EIP-191 sign β”‚
β”‚ ◄─────────────────────────────────│ signed quote β”‚
β”‚ β”‚ β”‚
β”‚ createJob Β· setBudget Β· fund ────────────────────────────────────►│
β”‚ β”‚ β”‚
β”‚ notify_funded β”‚ β”‚
β”‚ ─────────────────────────────────►│ verify funded job on-chain β”‚
β”‚ β”‚ ──────────────────────────────►│
β”‚ β”‚ run work, store deliverable β”‚
β”‚ β”‚ submit reference ─────────────►│
β”‚ ◄─────────────────────────────────│ deliverable β”‚
β”‚ β”‚ β”‚
β”‚ approve / reject / dispute ──────────────────────────────────────►│
```
Buyer Layer B (Service) Layer A (Agent) BNB Chain
β”‚ POST /apex/negotiate β”‚ β”‚ β”‚
β”‚ ────────────────────────────►│ InvokeAgentRuntime(quote) β”‚ β”‚
β”‚ β”‚ ──────────────────────────►│ sign offer β”‚
β”‚ ◄────────────────────────────│ ◄──────────────────────────│ β”‚
β”‚ (funded job on-chain) β”‚ β”‚ β”‚
β”‚ β”‚ poll funded jobs β”‚ β”‚
β”‚ β”‚ InvokeAgentRuntime(fulfill) β”‚ β”‚
β”‚ β”‚ ──────────────────────────►│ execute + submit β”‚
β”‚ β”‚ β”‚ ──────────────────────►│
β”‚ β”‚ InvokeAgentRuntime(settle) β”‚ β”‚
β”‚ β”‚ ──────────────────────────►│ settle β”‚
β”‚ β”‚ β”‚ ──────────────────────►│
```

Settlement stays with the buyer. Operator-side settle is a manual
`bag erc8183 settle <jobId>`.

## Core design principles

1. **Studio is not intelligent** β€” Claude Code / Cursor is the intelligence layer; studio provides recipes, CLI, MCP, and skills.
2. **Zero wallet abstraction** β€” studio uses `bnbagent-sdk`'s `WalletProvider` ABC via `get_wallet()`; no custom wrappers.
3. **Parallel payment protocols** β€” ERC-8183 and x402 each get independent CLI groups, recipes, and config sections.
4. **Payments are runtime services** β€” `@tool` functions in emitted code are the main battleground; CLI payment commands are operator diagnostics.
1. **Studio is not the intelligence** β€” Claude Code / Cursor is; Studio provides
recipes, the CLI, read-only MCP, and skills.
2. **No wallet abstraction of its own** β€” Studio selects a `WalletProvider` from the
SDK; it wraps nothing.
3. **Money is deterministic** β€” pricing clamps and signing are fixed code, never LLM
tool calls.
4. **Rails and faces are independent choices** β€” ERC-8183 and B402 are rails; A2A, MCP
and X402 are faces. One runtime serves any combination.
5. **The generated project is yours** β€” ordinary TypeScript, no closed-source runtime
and no lock-in.

## Further reading

- [BNB Agent SDK architecture](../bnbagent-sdk/architecture.md) β€” protocol module system
- [GitHub β€” architecture.md](https://github.com/bnb-chain/bnbagent-studio/blob/main/docs/design/architecture.md) β€” full design document
- [GitHub β€” decisions.md](https://github.com/bnb-chain/bnbagent-studio/blob/main/docs/design/decisions.md) β€” decision records
- [Quickstart](quickstart.md) β€” install, scaffold, run, deploy
- [Configuration](configuration.md) β€” `studio.toml` and `.env.local`
- [Deployment](deployment.md) β€” the three deploy targets
- [Security](security.md) β€” keystore posture, signing policy, MCP read-only guarantee
- [BNB Agent SDK architecture](../bnbagent-sdk/architecture.md) β€” the protocol layer underneath

[← BNB Agent Studio overview](index.md)
Loading