BuildIntegrated Examples
Agent Commerce Network
Run a budgeted security-review purchase between buyer and provider organizations with signed receipts at both boundaries.
Where the code lives
examples/agent-commerce-network/. Run it with ./smoke.sh. Set OPENAI_API_KEY or ANTHROPIC_API_KEY to use an external-model agent loop. With neither variable set, the smoke uses its deterministic CI fallback.What it shows
- A buyer agent in Org A (
lattice-platform-security) procures a service from a provider agent in Org B (vanguard-security). - A capability token carries a free quote-read grant and a budgeted job-write grant (
maxInvocations,maxCostPerInvocation,maxTotalCost). - The buyer sidecar (
chio api protect) signs a receipt for each API call. - The provider edge (
chio mcp serve-http) verifies the capability, enforces the policy, and signs its own receipt. - Trust-control tracks budget consumption, revocations, and financial reports (budget usage, exposure ledger, settlement).
- Both boundaries emit signed receipts: the buyer sidecar for each API call, the provider edge for each tool call. The run bundle captures the resulting receipts.
Architecture
Service inventory
smoke.sh picks free ports for its processes. The shape is fixed; the numbers vary per run. Port discovery uses the shared pick_free_port helper that opens a socket on port 0, reads back the OS-assigned port, and prints it. Each call returns a fresh free port:
pick_free_port() {
python3 - <<'PY'
import socket
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.bind(("127.0.0.1", 0))
print(sock.getsockname()[1])
PY
}
# smoke.sh then assigns four ports up front:
TRUST_PORT="$(pick_free_port)"
PROVIDER_PORT="$(pick_free_port)" # provider edge, default 8931
BUYER_API_PORT="$(pick_free_port)"
BUYER_SIDECAR_PORT="$(pick_free_port)" # buyer sidecar (chio api protect), default 9090| Process | Command | Listens on |
|---|---|---|
| trust-control | chio trust serve | 127.0.0.1:$TRUST_PORT |
| provider edge | chio mcp serve-http wrapping provider/review_server.py | 127.0.0.1:$PROVIDER_PORT |
| buyer FastAPI | uvicorn buyer.app:app | 127.0.0.1:$BUYER_API_PORT |
| buyer sidecar | chio api protect over the buyer FastAPI | 127.0.0.1:$BUYER_SIDECAR_PORT |
| orchestrator | python orchestrate.py | no listen; CLI client |
Each long-running process writes logs under artifacts/live/<timestamp>/logs/ and its sqlite state under the matching state/ directory. The cleanup trap kills the background processes on exit.
Run It
# From the chio workspace root
cargo build --bin chio
cd examples/agent-commerce-network
./smoke.sh
# Optional: live agent loop instead of the deterministic fallback
export OPENAI_API_KEY=... # OpenAI Agents SDK path
# or
export ANTHROPIC_API_KEY=... # Anthropic SDK path
./smoke.shOn a successful run the script prints two lines:
agent-commerce-network smoke passed
artifacts: /path/to/examples/agent-commerce-network/artifacts/live/<timestamp>Phase 1: Quote
The orchestrator first asks trust-control for a capability with two grants. Read calls (procurement_quote_read) are free; write calls (procurement_job_write) carry the budget envelope.
The buyer agent posts a quote-request to the provider edge. Both sides are JSON. Quote-request body:
{
"quote_id": "quote_req_lattice_001",
"buyer_id": "lattice-platform-security",
"provider_id": "vanguard-security",
"service_family": "security-review",
"requested_scope": "release-review",
"target": "git://lattice.example/payments-api",
"release_window": "2026-05-01T16:00:00Z"
}Quote-response body:
{
"quote_id": "quote_vanguard_001",
"request_id": "quote_req_lattice_001",
"service_family": "security-review",
"offer_id": "release-review",
"price_minor": 125000,
"currency": "USD",
"approval_required": true,
"estimated_delivery_hours": 48,
"pricing_basis": "bounded release review for one release window"
}cap = trust.issue_capability(
subject_pk="00" * 32,
scope={
"grants": [
{"server_id": "http-sidecar-client",
"tool_name": "procurement_quote_read",
"operations": ["invoke"], "constraints": []},
{"server_id": "http-sidecar-client",
"tool_name": "procurement_job_write",
"operations": ["invoke"], "constraints": [],
"maxInvocations": 3,
"maxCostPerInvocation": _usd(args.budget_minor),
"maxTotalCost": _usd(args.budget_minor)},
],
"resource_grants": [], "prompt_grants": [],
},
ttl=3600,
)The agent then calls POST /procurement/quote-requests on the buyer sidecar, which forwards to the provider edge. The provider responds with a per-call quote and the approval_required flag flips when the quote exceeds 100,000 cents.
{
"quote_id": "quote_vanguard_001",
"request_id": "quote_req_lattice_001",
"service_family": "security-review",
"offer_id": "release-review",
"price_minor": 125000,
"currency": "USD",
"approval_required": true,
"estimated_delivery_hours": 48,
"pricing_basis": "bounded release review for one release window"
}Expected log lines (provider edge):
chio.mcp.serve-http: tools/call request_quote -> allow
chio.mcp.serve-http: receipt receipt_<id> sealed (verdict=allow)Phase 2: Job Creation and Budget Check
The buyer service turns the quote into a job and checks it against the budget envelope client-side, before anything dispatches. If the job budget is below the quoted price it stamps denied_budget; if the quote tripped the approval threshold it stamps pending_approval; otherwise it executes. The grant's maxInvocations / maxCostPerInvocation / maxTotalCost caps are enforced separately by trust-control as the buyer sidecar signs each call.
if budget_minor < quote["price_minor"]:
job["status"] = "denied_budget"
job["denial_reason"] = "requested work exceeds the buyer budget envelope"
elif quote["approval_required"]:
job["status"] = "pending_approval"
else:
self._execute_job(job)Phase 3: Dispatch
The buyer issues an MCP tools/call for execute_review. The capability rides on the request as the X-Chio-Capability header, and the auth bearer rides on Authorization: Bearer ...:
headers: dict[str, str] = {"Authorization": f"Bearer {auth_token}"}
if cap_header:
headers["X-Chio-Capability"] = cap_header
r = http.post(f"{buyer_url}{path}", headers=headers, json=body)The provider edge runs its policy pipeline and forwards into the review tool. The tool returns a fulfillment package:
{
"fulfillment_id": "fulfillment_vanguard_001",
"job_id": "job_lattice_001",
"service_family": "security-review",
"deliverables": [
"executive-summary.md",
"findings.json",
"remediation-checklist.md"
],
"status": "completed_with_findings",
"severity_summary": {"critical": 0, "high": 2, "medium": 5, "low": 7}
}Phase 4: Receipts
Each boundary signs its own receipt. The buyer sidecar ( chio api protect) writes an HTTP receipt for each call it mediates into state/buyer-receipts.sqlite3 (one row per receipt in the http_receipts table). The provider MCP edge signs a receipt for each tools/call it admits. Trust-control ingests receipts into state/trust-receipts.sqlite3 (the chio_tool_receipts table). The run bundle captures all of them: the evidence is the set of independently signed receipts across both orgs, each under its own kernel signature.
Peek at the two stores directly. Route, method, and verdict live inside the receipt blob rather than in dedicated columns:
# Trust-control ingested receipts: one row per admitted call
sqlite3 state/trust-receipts.sqlite3 \
'select receipt_id, tool_server, tool_name, decision_kind from chio_tool_receipts order by seq;'
# Buyer sidecar HTTP receipts: id plus the signed receipt blob
sqlite3 state/buyer-receipts.sqlite3 \
'select id, receipt_json from http_receipts order by rowid;'Bilateral intent binding is a protocol feature, not this example
GovernedTransactionIntent binding, where a buyer and provider receipt each commit to one shared intent hash, is documented under Bilateral Receipts. This runnable example keeps the flow simpler: a capability grant with a budget envelope, a client-side budget check, and independently signed receipts on each side.Phase 5: Reconcile
After dispatch, the buyer kernel calls /v1/budgets/reconcile-spend with the actual cost. Three outcomes:
- Actual < charged: the difference is credited back to the grant.
- Actual = charged: no adjustment.
- Actual > charged: the overrun is recorded against the grant.
Phase 6: Settle
In the example the settlement rail is stubbed and returns a synthetic settlement_id:
{
"settlement_id": "settlement_lattice_vanguard_001",
"job_id": "job_lattice_001",
"quoted_amount_minor": 125000,
"approved_amount_minor": 125000,
"settled_amount_minor": 125000,
"currency": "USD",
"status": "reconciled",
"buyer_position": "accepted",
"provider_position": "accepted"
}See On-chain Settlement and Pricing for how the payment_reference field on the receipt connects to an EVM, Solana, CCIP, or x402 settlement rail.
Inspect Run Files
Each run creates a directory under artifacts/live/<timestamp>/:
cd artifacts/live/<timestamp>
# Capability that drove the run
cat capability.json
# What the agent decided and which tools it called
cat agent-output.json
cat summary.json
# Contracts captured from the agent's tool calls
ls contracts/
cat contracts/quote-response.json
cat contracts/fulfillment-package.json
cat contracts/settlement-reconciliation.json
# Trust-control financial reports
cat financial/budget-usage.json
cat financial/exposure-ledger.json
cat financial/settlement-report.json
# Persistent state per service
ls state/
# trust-receipts.sqlite3 receipts ingested by trust-control
# trust-revocations.sqlite3 revocation table
# trust-authority.sqlite3 authority signing seed + history
# trust-budgets.sqlite3 grant usage records
# buyer-receipts.sqlite3 receipts written by chio api protect
# provider-sessions.sqlite3 provider edge session state
# Per-process logs
ls logs/
# trust.log chio trust serve
# provider-edge.log chio mcp serve-http
# buyer-api.log uvicorn buyer.app
# buyer-sidecar.log chio api protectThe smoke also runs the in-tree verifier: commerce_network.verify.verify_bundle reads the run directory, confirms the required files is present, that each contract parses, and that the agent and summary final_status agree. Its output lands in review-result.json; the smoke aborts if ok is false.
Smoke Assertions
The smoke runs the in-tree verifier as its last step. The post-orchestrator block in smoke.sh aborts the run if a required file is missing or a check fails:
uv run --project "${EXAMPLE_ROOT}" python -c "
import sys; sys.path.insert(0, '${EXAMPLE_ROOT}')
from commerce_network.verify import verify_bundle
import json
r = verify_bundle('${ARTIFACT_ROOT}')
json.dump(r, open('${ARTIFACT_ROOT}/review-result.json', 'w'), indent=2)
assert r['ok'], r['errors']
"
printf 'agent-commerce-network smoke passed\n'
printf 'artifacts: %s\n' "${ARTIFACT_ROOT}"verify_bundle checks that agent-output.json, the three contracts, and summary.json all exist; that the agent's final_status matches summary.json; that each contract under contracts/ parses as JSON; and that no entry in financial/budget-usage.json records a negative totalCostCharged. There is no price-consistency check and no receipt-chain check.
Inspect After
Set the env vars to the run's sqlite paths and walk the state with the standard CLI tooling:
cd artifacts/live/<timestamp>
export TRUST_RECEIPT_DB="$(pwd)/state/trust-receipts.sqlite3"
export BUYER_DB="$(pwd)/state/buyer-receipts.sqlite3"
# Five most recent receipts trust-control ingested
sqlite3 "$TRUST_RECEIPT_DB" \
'select receipt_id, tool_server, tool_name, decision_kind from chio_tool_receipts order by seq desc limit 5;'
# Buyer-side HTTP receipts: id plus the signed receipt blob
sqlite3 "$BUYER_DB" \
'select id, receipt_json from http_receipts order by rowid;'
# Budget consumption, from the trust-control financial report
jq '.' financial/budget-usage.json
# Pricing slice of the quote contract
jq '{price_minor, currency, approval_required}' contracts/quote-response.json
# Settlement reconciliation, bilateral position
jq '{status, buyer_position, provider_position, settled_amount_minor}' \
contracts/settlement-reconciliation.jsonExpected output (with one happy-path run):
# trust-receipts (receipt_id|tool_server|tool_name|decision_kind)
rcpt-...|http-sidecar-client|procurement_quote_read|allow
rcpt-...|provider-security-review|execute_review|allow
# buyer-receipts: each row is (id, receipt_json); route, method, and
# verdict are nested inside receipt_json (verdict at .verdict.verdict)
# pricing slice
{
"price_minor": 125000,
"currency": "USD",
"approval_required": true
}
# settlement bilateral
{
"status": "reconciled",
"buyer_position": "accepted",
"provider_position": "accepted",
"settled_amount_minor": 125000
}Failure Paths
The example has three intentional failure branches. Each writes a run file:
- Budget denial: requested work exceeds the envelope. The buyer service stamps the job as
denied_budget; it does not dispatch work to the provider. - Pending approval: the quote tripped
approval_required. The agent must callapprove_jobwith a reason; the dispatch proceeds only after the approval is recorded on the job. - Dispute: after fulfillment, the agent calls
dispute_job. The settlement record flips toreversal_pending.
Use this example when...
Where to read more
MeteredBillingQuote. Bilateral Receipts covers receipt-pair verification.