Outcome-verified agent commerce
Agents can transact.
Every outcome should be provable.
Garnet is a buyer agent. It hires a specialist agent within your budget, checks the delivered work against an independent source, and only then pays, recovers the money, or stops and asks a human.
- Task
- Analyse tx 0xe29f23…48f320
- Budget
- $1.50 · $0.65 paid
- Escrow
- SIMULATED
- Agent
- Scripted planner
- Select
- Reserve
- Deliver
- Verify
- Settle
#1 Seller A · Quickscan quote $0.40DEMO FAULT ON
rejected · refunded- PASStxHash
- PASSchainId
- PASSfrom
- PASSto
- FAILblockNumber
- PASSstatus
- PASSvalueWei
blockNumber: expected 47997912 · got 47997913 — source rpc:sepolia.base.org
#2 Seller B · Deepledger quote $0.65
verified · paid once- PASStxHash
- PASSchainId
- PASSfrom
- PASSto
- PASSblockNumber
- PASSstatus
- PASSvalueWei
Seller A delivered a wrong block number (demo fault injection). Garnet's verifier caught it against the chain, refunded the reservation, hired Seller B under the same budget, verified and paid once. Run it yourself →
The problem
A payment receipt is not proof of work.
Agents can already pay each other. What they can't do is know whether they got what they paid for. A confirmed transfer proves money moved. It says nothing about whether the analysis was right.
If a buyer agent trusts the seller's output, it pays for wrong answers. If it retries a payment after a timeout, it can pay twice. Garnet is built to prevent both.
- Naive buyer agent
- pays on delivery
- Garnet
- pays on verified delivery
How it works
Select. Verify. Settle or recover.
- 01
Select
The buyer agent reads the quotes and your budget, picks a seller and explains why. Code then checks the choice: no unknown sellers, no repeat of a failed seller, nothing over budget.
- 02
Verify
The acceptance criteria are fixed before work starts. When the seller delivers, Garnet fetches the transaction and receipt from Base Sepolia itself and compares every field. Each check gets PASS, FAIL or INCONCLUSIVE.
- 03
Settle / Recover
PASS releases the reserved funds, exactly once. FAIL produces an evidence packet, refunds the reservation and hires the next seller under the same budget. If the check is inconclusive, funds are held and a human is asked.
Proof & safety
Guardrails in code, not in the prompt.
The model can pick a seller. It can't approve a payment, raise the budget or overrule the verifier. Those rules run as ordinary code with tests behind them.
Budget guardrail
Payments plus open reservations can never exceed the original budget. All amounts are exact integers; there is no floating-point money.
Independent receipts
The verifier makes its own RPC calls and never reads the seller's data source. If the RPC fails, the result is INCONCLUSIVE, never PASS.
Evidence packets
Each rejection is saved as a hashed record: the frozen contract, the delivery hash, the failed checks, their source and timestamps.
Exactly-once settlement
Every money movement carries an idempotency key. The database allows one release per job. If an acknowledgement is lost, Garnet looks the payment up by key instead of sending it again.
Restart-safe
Jobs, attempts, ledger entries and events are written to SQLite. If the process restarts, the job continues from the last saved step.
Honest modes
Escrow is simulated, and every receipt is labeled SIMULATED. Fault injection is labeled as a demo. When no model key is set, the scripted planner is labeled as scripted.
For developers
Four parts, connected through small interfaces.
The agent plans. Providers do the work. The verifier checks it. The payment adapter moves money. Neatlogs records each step as a span, so any run can be traced from decision to settlement.
Read the source →src/lib/ agent/ planner (Claude Opus 5.5) · engine providers/ seller-a · seller-b verification/ viem RPC verifier · evidence payments/ SIMULATED escrow ledger jobs/ frozen contract · state machine telemetry/ Neatlogs spans garnet.job WORKFLOW ├─ select_provider AGENT ├─ budget_and_policy_guard GUARDRAIL ├─ reserve · seller_execute TOOL ├─ verify GUARDRAIL ├─ create_dispute · refund TOOL ├─ fallback → … → release AGENT/TOOL └─ finalize CHAIN