Skip to content

Commit f444dfa

Browse files
trilltinoclaude
andcommitted
refactor: collapse TxODDS demo to single buyer/seller/verifier, polish live narrative
Simplify the reference kit to its minimal viable loop so it forks cleanly: - Remove echo-agent, user_proxy (dead/unused), and the seller-base persona wrapper; the buyer now launches one seller-agent directly instead of five personas multiplexed through a shared registration. - Remove the sharp-movement/risk-policy seller services, the research-market watcher/detector/grading pipeline, and their UI wiring - all downstream of the persona collapse and unused without it. - Modularize buyer-agent's src/ into award/, settlement/, verify/, reputation/, and feed/ submodules instead of a flat file list. - Rewrite the seller's delivery LLM prompt for a colorful two-sentence take instead of a clinical one-liner; the live feed's story headline now shows that narrative directly instead of a stats-table paragraph, and drops the redundant progress-stage tracker in favor of the prose recap. - Fix seller-agent's manifest missing the x402 procurement options (PROCURE_RAIL, PROCURE_X402_URL, SELLER_KEYPAIR_B58) that its own code and the round launcher already depended on. Verified live end-to-end on devnet: WANT -> BID -> AWARD -> ESCROW_REQUIRED -> DEPOSITED -> DELIVERED -> VERIFIED -> ARBITER_RELEASED, real TxLINE data, real LLM read, real settlement tx. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1 parent b200d29 commit f444dfa

105 files changed

Lines changed: 2279 additions & 3840 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/settings.local.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
"allow": [
44
"Bash(powershell -Command ' *)",
55
"Bash(grep -r \"///\" --include=\"*.rs\")",
6-
"Bash(cargo check *)"
6+
"Bash(cargo check *)",
7+
"Bash(node -e ' *)",
8+
"Bash(node --input-type=module --check)",
9+
"Bash(npm run *)"
710
]
811
}
912
}

.env.example

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,19 @@ SOLANA_RPC_URL=https://api.devnet.solana.com
2424

2525
# ── LLM brain (the agent's reasoning + delivery) ──────────────────────────────
2626

27-
# This kit's LLM is Venice AI — OpenAI-compatible, with free credits. Create a key at
28-
# https://venice.ai/settings/api; new accounts get $50 free with redeem code IMPERIAL50 (bottom of that
29-
# page). Recommended: set both of these.
27+
# Recommended: Groq — OpenAI-compatible, genuinely free (a renewing per-day/per-minute rate limit,
28+
# not a one-time credit grant that runs out). Create a key at https://console.groq.com/keys, no card
29+
# needed. Set both of these:
30+
# LLM_PROVIDER=groq
31+
GROQ_API_KEY=
32+
33+
# Alternative: Venice AI — OpenAI-compatible, free SIGNUP CREDITS (a one-time pool that can run out,
34+
# unlike Groq's renewing limit). Create a key at https://venice.ai/settings/api; new accounts get $50
35+
# free with redeem code IMPERIAL50 (bottom of that page).
3036
# LLM_PROVIDER=venice
3137
VENICE_API_KEY=
3238

33-
# Alternatives (no code change) — set LLM_PROVIDER + the matching key:
39+
# Other alternatives (no code change) — set LLM_PROVIDER + the matching key:
3440
# LLM_PROVIDER=openai → OPENAI_API_KEY=...
3541
# LLM_PROVIDER=anthropic → ANTHROPIC_API_KEY=...
3642
OPENAI_API_KEY=

API.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,8 @@ app.get('/api/premium-data', async (req, res) => {
367367
| `SELLER_WALLET` | agent-runtime | Seller's receive-only public key. |
368368
| `SELLER_KEYPAIR_B58` | payment-runtime | Seller's spend key (for x402 procurement). |
369369
| `ARBITER_KEYPAIR_B58` | payment-runtime | Arbiter authority for escrow release/refund. |
370-
| `LLM_PROVIDER` | agent-runtime | `venice`, `openai`, or `anthropic`. |
370+
| `LLM_PROVIDER` | agent-runtime | `groq`, `venice`, `openai`, or `anthropic`. Groq recommended — free, renewing rate limit. |
371+
| `GROQ_API_KEY` | agent-runtime | Groq API key. |
371372
| `VENICE_API_KEY` | agent-runtime | Venice API key. |
372373
| `OPENAI_API_KEY` | agent-runtime | OpenAI API key. |
373374
| `ANTHROPIC_API_KEY` | agent-runtime | Anthropic API key. |

CLAUDE.md

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ The repository implements a devnet agent-commerce reference system. Agents coord
99
Primary lifecycle:
1010

1111
```text
12-
WANT -> BID -> AWARD -> ESCROW_REQUIRED -> DEPOSITED -> DELIVERED -> VERIFIED -> RELEASED
12+
WANT -> BID -> AWARD -> ESCROW_REQUIRED -> DEPOSITED -> DELIVERED -> VERIFIED -> RELEASED | ARBITER_RELEASED
1313
```
1414

1515
The Rust surface is limited to `examples/txodds/escrow`, which contains the escrow and arbiter programs. Most repository code is TypeScript.
@@ -22,8 +22,8 @@ The Rust surface is limited to `examples/txodds/escrow`, which contains the escr
2222
| `packages/harness-runtime/` | Seller execution adapter SDK for `node-llm`, `claude-code`, and arbitrary CLI harnesses. |
2323
| `packages/payment-runtime/` | Rail interface/router, working devnet Solana Pay and escrow rails, scaffold rails, and proof receipts. |
2424
| `packages/solana-agent-tools/` | Read-only Solana context tools and optional Solana Agent Kit adapter. |
25-
| `examples/txodds/` | TxODDS proxy, web UI, service implementation, feed server, research watcher, and escrow workspace. |
26-
| `coral-agents/` | Buyer, seller, verifier, and echo agent containers. |
25+
| `examples/txodds/` | TxODDS proxy, web UI, service implementation, feed server, and escrow workspace. |
26+
| `coral-agents/` | Buyer, seller, and verifier agent containers. |
2727
| `scripts/` | Setup, wallet provisioning, and example runner scripts. |
2828

2929
## Common Commands
@@ -57,8 +57,7 @@ Key files:
5757
| `examples/txodds/agent/txline.ts` | TxLINE client. |
5858
| `examples/txodds/agent/edge.ts` | Verified odds to fair-line analysis. |
5959
| `examples/txodds/agent/service.ts` | `deliverService()` for paid delivery. |
60-
| `examples/txodds/server/proxy.ts` | Proxy, settlement endpoints, run persistence, grading. |
61-
| `examples/txodds/research/watcher.ts` | Odds-move event queue. |
60+
| `examples/txodds/server/proxy.ts` | Proxy, settlement endpoints, run persistence. |
6261
| `examples/txodds/escrow/` | Escrow and arbiter Anchor programs. |
6362

6463
`npm run dev` starts the proxy on `:8801` and the static UI on `:3020`.
@@ -101,8 +100,8 @@ Common variables:
101100
| `ARBITER_KEYPAIR_B58` | Arbiter release/refund keypair. |
102101
| `WALLET` / `SELLER_WALLET` | Seller payout addresses. |
103102
| `SOLANA_RPC_URL` | Defaults to devnet if unset. |
104-
| `LLM_PROVIDER` | `venice`, `openai`, or `anthropic`. |
105-
| `VENICE_API_KEY` / `OPENAI_API_KEY` / `ANTHROPIC_API_KEY` | Provider keys. |
103+
| `LLM_PROVIDER` | `groq`, `venice`, `openai`, or `anthropic`. Groq is the recommended free default — see `LLM.md`. |
104+
| `GROQ_API_KEY` / `VENICE_API_KEY` / `OPENAI_API_KEY` / `ANTHROPIC_API_KEY` | Provider keys. |
106105
| `TXLINE_API_KEY` | TxLINE token for TxODDS examples. |
107106

108107
Never commit `.env`, private keys, provider keys, seed phrases, or generated wallet secrets.

CORAL.md

Lines changed: 67 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ CoralOS provides multi-agent coordination. Solana payment signing and settlement
88
|---|---|---|
99
| Runtime | `packages/agent-runtime/src/coral/` | MCP client, tool discovery, agent entrypoint, context helpers. |
1010
| Protocol | `packages/agent-runtime/src/market/protocol.ts` | Market message formatters/parsers. Coral transports these as strings. |
11-
| Agents | `coral-agents/` | Buyer, seller, verifier, echo, and user-proxy implementations. |
11+
| Agents | `coral-agents/` | Buyer, seller, and verifier implementations. |
1212
| Orchestration | `docker-compose.yml`, `examples/txodds/coral/round.ts` | Start CoralOS and create sessions from agent graphs. |
1313
| UI/feed | `examples/txodds/feed` | Read extended session state and expose browser-safe APIs. |
1414

@@ -48,27 +48,28 @@ await startCoralAgent({ agentName: 'my-agent' }, async (ctx) => {
4848
| `buyer-agent` | Creates market thread, sends `WANT`, collects bids, awards, deposits, verifies, and releases. |
4949
| `seller-agent` | Bids on supported services, verifies funded escrow, runs a harness adapter, and delivers payloads. |
5050
| `verifier-agent` | Checks delivery hash/structure and replies `VERIFIED pass` or `fail`. |
51-
| `echo-agent` | Minimal connectivity test agent. |
52-
| `user_proxy` | Idle session participant driven by the puppet API. |
5351

54-
### Seller Personas
52+
### Adding Another Seller
5553

56-
Seller personas reuse the `seller-agent` Docker image with different manifest values:
54+
The TxODDS round (`examples/txodds/coral/round.ts`) runs a single `seller-agent`. To add a second,
55+
competing seller, reuse the `seller-agent` Docker image with a new manifest under its own
56+
`coral-agents/` directory, overriding just the market identity and pricing:
5757

5858
```toml
59-
# coral-agents/seller-worldcup/coral-agent.toml
59+
# coral-agents/seller-fast/coral-agent.toml
6060
[agent]
61-
name = "seller-worldcup"
61+
name = "seller-fast"
6262
image = "seller-agent"
6363

6464
[agent.env]
65-
AGENT_NAME = "seller-worldcup"
66-
PERSONA = "worldcup-specialist"
65+
AGENT_NAME = "seller-fast"
66+
PERSONA = "a fast generalist"
6767
FLOOR_SOL = "0.0001"
6868
SERVICES = "txline"
6969
```
7070

71-
No new code needed — just a new `coral-agent.toml` directory under `coral-agents/`.
71+
No new code needed — just a new `coral-agent.toml` directory under `coral-agents/`, and adding it to
72+
`round.ts`'s agent list so the buyer's `MARKET_SELLERS` includes it.
7273

7374
### Agent Discovery
7475

@@ -81,6 +82,25 @@ localAgents = ["/agents/*"]
8182

8283
Every directory under `coral-agents/` with a `coral-agent.toml` is auto-registered. Nothing needs to be hand-listed.
8384

85+
### Agent Runtimes
86+
87+
Every `coral-agent.toml` can declare `[runtimes.docker]`, `[runtimes.executable]`, or both — CoralOS
88+
either launches the agent as a container (via the mounted Docker socket) or execs it directly as its
89+
own child process. `examples/txodds/coral/round.ts`'s `agent()` helper picks per agent:
90+
91+
- **`runtime: 'docker'`**`buyer-agent` and `seller-agent`. These hold real devnet signing
92+
keys, so container process isolation is worth the overhead.
93+
- **`runtime: 'executable'`**`verifier-agent`. It holds no key, so there's no isolation to trade
94+
away, and coral-server just execs `node dist/index.js` directly — no image, no `docker build`.
95+
96+
The stock `ghcr.io/coral-protocol/coral-server` image has no Node.js (it's `ubuntu:noble` + a minimal
97+
JRE), so `runtime: 'executable'` needs `docker/coral-server.Dockerfile`'s Node layer to actually work
98+
`docker-compose.yml`'s `coral` service builds from that Dockerfile, not the bare upstream image.
99+
100+
This is deliberately not applied to `buyer-agent`/`seller-agent` — moving wallet-holding agents off
101+
Docker was considered and set aside; see the "Not adopted" note below for the same reasoning applied
102+
to Coral Cloud.
103+
84104
## Session Creation
85105

86106
```ts
@@ -89,7 +109,7 @@ const session = await createSession({
89109
agentGraphRequest: {
90110
agents: [
91111
{ name: 'buyer-agent', ... },
92-
{ name: 'seller-worldcup', ... },
112+
{ name: 'seller-agent', ... },
93113
{ name: 'verifier-agent', ... },
94114
],
95115
},
@@ -98,7 +118,8 @@ const session = await createSession({
98118
})
99119
```
100120

101-
CoralOS starts one container per graph agent and injects `CORAL_CONNECTION_URL`.
121+
CoralOS starts each graph agent per its declared runtime (a container, or a direct child process —
122+
see "Agent Runtimes" above) and injects `CORAL_CONNECTION_URL` either way.
102123

103124
## Market Flow
104125

@@ -130,12 +151,12 @@ import { formatWant, formatBid, parseMarketMessage } from '@pay/agent-runtime'
130151
const want = formatWant({ round: 1, service: 'txline', arg: 'FIFA World Cup', budgetSol: 0.001 })
131152
// => "WANT round=1 service=txline arg=FIFA World Cup budget=0.001"
132153

133-
const bid = formatBid({ round: 1, priceSol: 0.0002, by: 'seller-worldcup' })
134-
// => "BID round=1 price=0.0002 by=seller-worldcup"
154+
const bid = formatBid({ round: 1, priceSol: 0.0002, by: 'seller-agent' })
155+
// => "BID round=1 price=0.0002 by=seller-agent"
135156

136157
// Parse incoming messages
137-
const parsed = parseMarketMessage('BID round=1 price=0.0002 by=seller-worldcup')
138-
// => { verb: 'BID', round: 1, priceSol: 0.0002, by: 'seller-worldcup' }
158+
const parsed = parseMarketMessage('BID round=1 price=0.0002 by=seller-agent')
159+
// => { verb: 'BID', round: 1, priceSol: 0.0002, by: 'seller-agent' }
139160
```
140161

141162
## Extended State and Feed
@@ -175,18 +196,47 @@ npm run dev # Probes automatically before launch
175196

176197
Set `CORAL_CONSOLE=0` to skip the probe. Set `CORAL_CONSOLE_REQUIRED=1` to make failures fatal.
177198

199+
## Not Adopted: Coral Cloud LLM Proxy
200+
201+
CoralOS agents can route every model call through **Coral Cloud** (`llm.coralcloud.ai`), a hosted
202+
OpenAI-compatible proxy, by declaring `[[llm.proxies]]` in `coral-agent.toml` and setting a
203+
`CORAL_API_KEY`. This repo doesn't use it — LLM calls go straight to Groq/Anthropic/OpenAI/Venice
204+
(`packages/agent-runtime/src/llm/complete.ts`). That's a deliberate choice, not an oversight: Coral
205+
Cloud trades this kit's bring-your-own-key flexibility (in particular Groq's free renewing-rate-limit
206+
path, which the whole kit is built around — see `README.md`) for a dependency on a separate hosted
207+
account. Worth knowing it exists if you're forking this for a context where a Coral Cloud account is
208+
already a given.
209+
178210
## Running
179211

180212
```sh
181213
# Single-agent (no CoralOS needed)
182214
npm run dev
183215

184-
# Multi-agent CoralOS round
216+
# One-command multi-agent CoralOS round (brings up coral-server + creates a round automatically)
217+
npm run dev:agentic
218+
219+
# ...or the manual steps dev:agentic wraps, useful if one of them is stuck and you want to isolate which:
185220
docker compose up -d coral
186221
bash build-agents.sh
187222
npm run demo:coral
188223
```
189224

225+
### Cleaning Up Agent Containers
226+
227+
Buyer/seller agent containers are **not** docker-compose services — CoralOS launches them dynamically
228+
per round (one per seller persona, with per-round env), through the Docker socket mounted into the
229+
`coral` container, so a static compose `services:` entry can't represent them. `docker compose down`
230+
only stops `coral-server` itself.
231+
232+
```sh
233+
npm run agents:stop # force-removes every buyer-agent/seller-agent container, any time
234+
```
235+
236+
Every new round already does this automatically before it starts (`round.ts`'s `stopPreviousRound()`),
237+
and `npm run dev:agentic`'s Ctrl+C shutdown handler does it too — the only case you'd run this by hand
238+
is wanting a clean slate without immediately starting a new round.
239+
190240
## Claude Code Plugin: `coral-skills`
191241

192242
`.claude/settings.json` pre-registers and enables the official

LLM.md

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
11
# LLM Provider Configuration
22

3-
`packages/agent-runtime/src/llm/complete.ts` exposes one SDK-free `complete()` function over `fetch`. Supports Venice, OpenAI, and Anthropic.
3+
`packages/agent-runtime/src/llm/complete.ts` exposes one SDK-free `complete()` function over `fetch`. Supports Venice, OpenAI, Anthropic, and Groq.
4+
5+
## Which Provider to Use
6+
7+
**Groq is the recommended default for this kit.** It's genuinely free — not a one-time credit grant like Venice's signup bonus, but a renewing per-day/per-minute rate limit, so it doesn't run dry the way Venice credits do. Get a key at [console.groq.com/keys](https://console.groq.com/keys), no card required.
8+
9+
Venice, OpenAI, and Anthropic remain fully supported for anyone with existing keys or who wants a different model — nothing about them changed.
410

511
## Environment Variables
612

713
| Variable | Description |
814
|---|---|
9-
| `LLM_PROVIDER` | `venice`, `openai`, or `anthropic`. Set explicitly when more than one key exists. |
10-
| `VENICE_API_KEY` | Venice API key. |
15+
| `LLM_PROVIDER` | `groq`, `venice`, `openai`, or `anthropic`. Set explicitly when more than one key exists. |
16+
| `GROQ_API_KEY` | Groq API key — free, renewing rate limit. |
17+
| `VENICE_API_KEY` | Venice API key — free signup credits, one-time (can run out). |
1118
| `OPENAI_API_KEY` | OpenAI API key. |
1219
| `ANTHROPIC_API_KEY` | Anthropic API key. |
1320
| `LLM_MODEL` | Optional model override. |
1421
| `TRACE` | Set to `1` to log provider/model selection and raw replies. |
1522

1623
```ini
1724
# .env (gitignored)
18-
LLM_PROVIDER=venice
19-
VENICE_API_KEY=...
25+
LLM_PROVIDER=groq
26+
GROQ_API_KEY=...
2027
```
2128

2229
## Provider Selection
@@ -26,25 +33,29 @@ VENICE_API_KEY=...
2633
1. `LLM_PROVIDER` set explicitly → use it.
2734
2. `OPENAI_API_KEY` exists → OpenAI.
2835
3. `VENICE_API_KEY` exists → Venice.
29-
4. Fallback → Anthropic (fails if no key).
36+
4. `GROQ_API_KEY` exists → Groq.
37+
5. Fallback → Anthropic (fails if no key).
38+
39+
Auto-detection is a convenience for having exactly one key set; if you have both `VENICE_API_KEY` and `GROQ_API_KEY` in `.env` (e.g. switching over after Venice ran out), set `LLM_PROVIDER=groq` explicitly rather than relying on priority order.
3040

3141
## Default Models
3242

3343
| Provider | Default Model |
3444
|---|---|
45+
| Groq | `llama-3.3-70b-versatile` |
3546
| Venice | `llama-3.3-70b` |
3647
| OpenAI | `gpt-4o-mini` |
3748
| Anthropic | `claude-haiku-4-5-20251001` |
3849

3950
Override with `LLM_MODEL`:
4051

4152
```ini
42-
LLM_PROVIDER=venice
43-
VENICE_API_KEY=...
44-
LLM_MODEL=kimi-k2-7-code
53+
LLM_PROVIDER=groq
54+
GROQ_API_KEY=...
55+
LLM_MODEL=llama-3.3-70b-versatile
4556
```
4657

47-
Venice Kimi models: the runtime raises `maxTokens` requests below `1024` to `1024` (Kimi may consume budget on reasoning before emitting content).
58+
Venice Kimi models: the runtime raises `maxTokens` requests below `1024` to `1024` (Kimi may consume budget on reasoning before emitting content). Groq has no equivalent quirk.
4859

4960
## Usage
5061

@@ -71,10 +82,10 @@ Every decision follows **propose → enforce**: the model proposes, deterministi
7182

7283
### Bid Review (Optional)
7384

74-
Set `BID_REVIEW_ENABLED=1` on a seller persona to add a second, independently-prompted loop that can veto a proposed bid. The reviewer has no visibility into the first loop's reasoning.
85+
Set `BID_REVIEW_ENABLED=1` on the seller to add a second, independently-prompted loop that can veto a proposed bid. The reviewer has no visibility into the first loop's reasoning.
7586

7687
```toml
77-
# coral-agents/seller-worldcup/coral-agent.toml
88+
# coral-agents/seller-agent/coral-agent.toml
7889
[agent.env]
7990
BID_REVIEW_ENABLED = "1"
8091
```
@@ -95,7 +106,7 @@ Every LLM-backed decision emits an `LlmUse` record into the run ledger:
95106
```ts
96107
{
97108
round: 1,
98-
agent: 'seller-worldcup',
109+
agent: 'seller-agent',
99110
purpose: 'bid-decision',
100111
status: 'ok',
101112
provider: 'venice',
@@ -110,9 +121,20 @@ Every LLM-backed decision emits an `LlmUse` record into the run ledger:
110121

111122
When a provider key is absent, invalid, rate-limited, or exhausted, callers either surface the error or use a deterministic fallback. TxODDS UI labels deterministic reads separately from LLM reads.
112123

124+
## Groq Free Tier
125+
126+
No credit card, no expiring credit pool — a renewing rate limit instead. Limits vary by model; roughly, at time of writing:
127+
128+
| Model | Requests/day | Tokens/minute |
129+
|---|---|---|
130+
| `llama-3.3-70b-versatile` (default) | 14,400 | 6,000 |
131+
| `groq/compound` | 250 | 70,000 |
132+
133+
Check [console.groq.com](https://console.groq.com) for current limits per model — Groq adjusts these. If you're hitting the per-minute token cap in a tight bid/verify loop, either switch to a lighter-limit model via `LLM_MODEL`, or fall back to another configured provider for that run.
134+
113135
## Adding a Provider
114136

115-
All wiring is in `packages/agent-runtime/src/llm/complete.ts`:
137+
All wiring is in `packages/agent-runtime/src/llm/complete.ts`. `completeGroq()` there is a real, working example of the pattern below — copy it.
116138

117139
1. Add the provider to `LlmProvider`.
118140
2. Add a default model.

PAY.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,11 @@ if (violations.length > 0) throw new PolicyError(violations)
160160
| `rate-limit` | Deposits closer than `POLICY_MIN_INTERVAL_MS`. |
161161
| `verifier-gate` | Release without `VERIFIED pass` when verifier is required. |
162162

163+
The x402 upstream-procurement leg (`packages/payment-runtime/src/procure.ts`) is gated separately by
164+
an `AllowancePolicy` (`packages/payment-runtime/src/policy/spend-policy.ts`): per-call and per-day
165+
caps, allowed providers/services/currencies, and expiry. This is distinct from the escrow-round policy
166+
above — it governs what the seller is allowed to *spend upstream*, not what the buyer deposits.
167+
163168
## Configuration
164169

165170
| Variable | Rail | Notes |

0 commit comments

Comments
 (0)