Skip to content

Commit ced4234

Browse files
simonovic86claude
andauthored
Plan next steps for production demo (#27)
* feat(runtime): implement x402/USDC wallet payment hostcall Add wallet_pay hostcall enabling agents to pay for services from their budget. This completes the self-provisioning story: agents can now observe prices (HTTP), decide to pay (wallet_pay), and survive crashes mid-payment (effect lifecycle). Runtime: - wallet_pay ABI: amount, recipient, memo → signed payment receipt - Manifest-driven validation: allowed_recipients, max_payment_microcents - Budget deduction with Ed25519-signed receipt generation - Event log recording for deterministic replay (CM-4) SDK: - igor.WalletPay(amount, recipient, memo) wrapper with auto-retry - MockBackend.WalletPay + PaymentHandler for native testing Demo (agents/x402buyer): - Encounters HTTP 402 paywall, parses payment terms - Effect lifecycle: Record → checkpoint → Begin → Pay → Confirm - Crash recovery: unresolved payments reconciled, no duplicates - Mock paywall server (agents/x402buyer/cmd/paywall) - End-to-end demo script (scripts/demo-x402.sh) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(dev): add agent go.mod, move paywall server to cmd/ - Add go.mod for x402buyer agent (same pattern as other agents) - Move paywall server from agents/x402buyer/cmd/ to cmd/paywall/ so it's part of the main module (not the agent's TinyGo module) - Update Makefile build path - Fix errcheck lint warning Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(runtime): add wallet_pay replay support, fix budget deduction ordering - Register wallet_pay in both registerReplayHostModule and registerChainReplayHostModule so agents using x402 capability can pass replay verification (CM-4) - Move receipt buffer capacity check before budget deduction in payment.go to prevent double-charge when caller retries with a larger buffer after receiving -5 (payErrBufferTooSmall) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 0a64d58 commit ced4234

18 files changed

Lines changed: 1159 additions & 18 deletions

File tree

CLAUDE.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ make agent # Build example WASM agent → agents/research/example/a
1919
make agent-heartbeat # Build heartbeat WASM agent → agents/heartbeat/agent.wasm
2020
make agent-pricewatcher # Build price watcher WASM agent → agents/pricewatcher/agent.wasm
2121
make agent-sentinel # Build treasury sentinel WASM agent → agents/sentinel/agent.wasm
22+
make agent-x402buyer # Build x402 buyer WASM agent → agents/x402buyer/agent.wasm
2223
make test # Run tests: go test -v ./...
2324
make lint # golangci-lint (5m timeout)
2425
make vet # go vet
@@ -29,6 +30,7 @@ make demo # Build + run bridge reconciliation demo
2930
make demo-portable # Build + run portable agent demo (run → stop → copy → resume → verify)
3031
make demo-pricewatcher # Build + run price watcher demo (fetch prices → stop → resume → verify)
3132
make demo-sentinel # Build + run treasury sentinel demo (effect lifecycle → crash → reconcile)
33+
make demo-x402 # Build + run x402 payment demo (pay for premium data → crash → reconcile)
3234
make clean # Remove bin/, checkpoints/, agent.wasm
3335
```
3436

@@ -66,7 +68,7 @@ Atomic writes via temp file → fsync → rename. Every checkpoint is also archi
6668
- `cmd/igord/` — CLI entry point, subcommand dispatch (`run`, `resume`, `verify`, `inspect`), tick loop
6769
- `internal/agent/` — Agent lifecycle: load WASM, init, tick, checkpoint, resume, budget deduction
6870
- `internal/runtime/` — wazero sandbox: 64MB memory limit, WASI with fs/net disabled
69-
- `internal/hostcall/``igor` host module: clock, rand, log, wallet hostcall implementations
71+
- `internal/hostcall/``igor` host module: clock, rand, log, wallet, http, x402 payment hostcall implementations
7072
- `internal/inspector/` — Checkpoint inspection and lineage chain verification (`chain.go`: `VerifyChain`)
7173
- `internal/storage/``CheckpointProvider` interface + filesystem impl + checkpoint history archival
7274
- `internal/eventlog/` — Per-tick observation event log for deterministic replay
@@ -81,11 +83,12 @@ Atomic writes via temp file → fsync → rename. Every checkpoint is also archi
8183
- `pkg/manifest/` — Capability manifest parsing and validation
8284
- `pkg/protocol/` — Message types: `AgentPackage`, `AgentTransfer`, `AgentStarted`
8385
- `pkg/receipt/` — Payment receipt data structure, Ed25519 signing, binary serialization
84-
- `sdk/igor/` — Agent SDK: hostcall wrappers (ClockNow, RandBytes, Log, WalletBalance), lifecycle plumbing (Agent interface), Encoder/Decoder with Raw/FixedBytes/ReadInto for checkpoint serialization, EffectLog for intent tracking across checkpoint/resume
86+
- `sdk/igor/` — Agent SDK: hostcall wrappers (ClockNow, RandBytes, Log, WalletBalance, WalletPay, HTTPRequest), lifecycle plumbing (Agent interface), Encoder/Decoder with Raw/FixedBytes/ReadInto for checkpoint serialization, EffectLog for intent tracking across checkpoint/resume
8587
- `sdk/igor/effects.go` — Effect lifecycle primitives: EffectLog, IntentState (Recorded→InFlight→Confirmed/Unresolved→Compensated), the resume rule (InFlight→Unresolved on Unmarshal)
8688
- `agents/heartbeat/` — Demo agent: logs heartbeat with tick count and age, milestones every 10 ticks
8789
- `agents/pricewatcher/` — Demo agent: fetches BTC/ETH prices from CoinGecko, tracks high/low/latest across checkpoint/resume
8890
- `agents/sentinel/` — Treasury sentinel: monitors simulated treasury balance, triggers refills with effect-safe intent tracking, demonstrates crash recovery and reconciliation
91+
- `agents/x402buyer/` — x402 payment demo: encounters HTTP 402 paywall, pays from budget via wallet_pay hostcall, receives premium data, crash-safe payment reconciliation
8992
- `agents/research/example/` — Original demo agent (Survivor) from research phases
9093
- `agents/research/reconciliation/` — Bridge reconciliation demo agent (research phase)
9194
- `scripts/demo-portable.sh` — End-to-end portable agent demo

Makefile

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.PHONY: help bootstrap build build-lab clean test lint vet fmt fmt-check tidy agent agent-heartbeat agent-reconciliation agent-pricewatcher agent-sentinel run-agent demo demo-portable demo-pricewatcher demo-sentinel gh-check gh-metadata gh-release
1+
.PHONY: help bootstrap build build-lab clean test lint vet fmt fmt-check tidy agent agent-heartbeat agent-reconciliation agent-pricewatcher agent-sentinel agent-x402buyer run-agent demo demo-portable demo-pricewatcher demo-sentinel demo-x402 gh-check gh-metadata gh-release
22

33
.DEFAULT_GOAL := help
44

@@ -10,6 +10,7 @@ HEARTBEAT_AGENT_DIR := agents/heartbeat
1010
RECONCILIATION_AGENT_DIR := agents/research/reconciliation
1111
PRICEWATCHER_AGENT_DIR := agents/pricewatcher
1212
SENTINEL_AGENT_DIR := agents/sentinel
13+
X402BUYER_AGENT_DIR := agents/x402buyer
1314

1415
# Go commands
1516
GOCMD := go
@@ -58,6 +59,7 @@ clean: ## Remove build artifacts
5859
rm -f agents/research/reconciliation/agent.wasm
5960
rm -f agents/pricewatcher/agent.wasm
6061
rm -f agents/sentinel/agent.wasm
62+
rm -f agents/x402buyer/agent.wasm
6163
@echo "Clean complete"
6264

6365
test: ## Run tests (with race detector)
@@ -136,6 +138,13 @@ agent-sentinel: ## Build treasury sentinel demo agent WASM
136138
cd $(SENTINEL_AGENT_DIR) && $(MAKE) build
137139
@echo "Agent built: $(SENTINEL_AGENT_DIR)/agent.wasm"
138140

141+
agent-x402buyer: ## Build x402 buyer demo agent WASM
142+
@echo "Building x402buyer agent..."
143+
@which tinygo > /dev/null || \
144+
(echo "tinygo not found. See docs/governance/DEVELOPMENT.md for installation" && exit 1)
145+
cd $(X402BUYER_AGENT_DIR) && $(MAKE) build
146+
@echo "Agent built: $(X402BUYER_AGENT_DIR)/agent.wasm"
147+
139148
demo: build agent-reconciliation ## Build and run reconciliation demo
140149
@echo "Building demo runner..."
141150
@mkdir -p $(BINARY_DIR)
@@ -158,6 +167,14 @@ demo-sentinel: build agent-sentinel ## Run the treasury sentinel demo (effect li
158167
@chmod +x scripts/demo-sentinel.sh
159168
@./scripts/demo-sentinel.sh
160169

170+
demo-x402: build agent-x402buyer ## Run the x402 payment demo (pay for premium data, crash recovery)
171+
@echo "Building paywall server..."
172+
@mkdir -p $(BINARY_DIR)
173+
$(GOBUILD) -o $(BINARY_DIR)/paywall ./cmd/paywall
174+
@echo "Running x402 Payment Demo..."
175+
@chmod +x scripts/demo-x402.sh
176+
@./scripts/demo-x402.sh
177+
161178
check: fmt-check vet lint test ## Run all checks (formatting, vet, lint, tests)
162179
@echo "All checks passed"
163180

agents/x402buyer/Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.PHONY: build clean
2+
3+
build:
4+
tinygo build -target=wasi -no-debug -o agent.wasm .
5+
6+
clean:
7+
rm -f agent.wasm
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"capabilities": {
3+
"clock": { "version": 1 },
4+
"rand": { "version": 1 },
5+
"log": { "version": 1 },
6+
"http": {
7+
"version": 1,
8+
"options": {
9+
"allowed_hosts": ["localhost"],
10+
"timeout_ms": 5000,
11+
"max_response_bytes": 8192
12+
}
13+
},
14+
"x402": {
15+
"version": 1,
16+
"options": {
17+
"allowed_recipients": ["paywall-provider"],
18+
"max_payment_microcents": 1000000
19+
}
20+
}
21+
},
22+
"resource_limits": {
23+
"max_memory_bytes": 67108864
24+
}
25+
}

agents/x402buyer/go.mod

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module github.com/simonovic86/igor/agents/x402buyer
2+
3+
go 1.24
4+
5+
require github.com/simonovic86/igor/sdk/igor v0.0.0
6+
7+
replace github.com/simonovic86/igor/sdk/igor => ../../sdk/igor

0 commit comments

Comments
 (0)