Skip to content

Worked example · agentic commerce · mesh-llm

Paid inference between strangers: two books, one payment.

On mesh-llm, a node can pay another node it has never met to run a model, over Lightning, with no one in the middle. This page shows how evidence and payment fit together in that exchange. Every claim below says what it rests on, and links it where the source is public.

Merged upstreamThe payments.v1 plugin and the payer's payment.lifecycle.v1 events (#2035, 25 Sep 2026). Not yet in a tagged release.
Proposed upstreamThe provider's matching events, in the same shape (issue #2017, open).
Released, oursThe evidence plugin that seals each node's half (capsule-emit-mesh v0.1.0).
Not yet publishedSwapping halves at completion, the Evidence tab, and recording the payment events. These are on a public branch not yet released, on our unpublished fork, or still in design; the claims table says which.

The problem

One ledger cannot say why a payment is missing.

A provider serves a request and the payment never shows up in its wallet. From the provider's own records, three different stories look the same from its own records: an expired, unpaid invoice.

What happenedWhat the payer's half showsWhat the provider's half would show
Never paidTerms accepted and an invoice received, then no settlement from its wallet.The invoice lapsed, or a debt was recorded.
Paid lateIts wallet reported the payment, sealed after the invoice's expiry.The invoice lapsed, then a late receipt arrived.
Noticed lateIts wallet reported the payment in time.Its own wallet saw the payment only after its deadline check.

Only the two halves together, joined on the payment_hash both wallets already share, separate the three. Today the payer's events are merged upstream; the provider's are proposed in #2017. The times come from each side's sealed record, and recording the payment events into those records is still in design.

The architecture

Each node keeps its own book. Nothing sits in the middle.

The requester pays and the provider serves. Each runs mesh-llm with two plugins: payments.v1, which holds the wallet and does the paying or invoicing, and the evidence plugin, which seals that node's own half of the exchange where the host serves it. Each side's half commits to digests of the exact request and response, and never to the text itself.

Paid inference on mesh-llm: two nodes, two books, an optional witness Left, the requester node; right, the provider node. Each has the mesh-llm host, the payments.v1 plugin with a wallet, the evidence plugin, and its own book. Between them: the request and token stream over mesh QUIC, invoices and Lightning payments, and each side's half exchanged at completion (not yet published). The payer's payments plugin emits payment.lifecycle.v1 to its evidence plugin (merged, #2035); the provider's matching stream is proposed in #2017. Both books can register checkpoints with a witness, off by default. merged upstream, or released proposed, or not yet published REQUESTER NODE · PAYS mesh-llm host exchange event · request + response digests payments.v1 + wallet merged upstream · #2035 evidence plugin seals this node's half · v0.1.0 digests only, never the text its own book sealed records · local checkpoints stays here: prompt, answer, preimage payment.lifecycle.v1 payer side · merged PROVIDER NODE · SERVES mesh-llm host runs the model · exchange event payments.v1 + wallet merged upstream · #2035 evidence plugin seals this node's half · v0.1.0 digests only, never the text its own book sealed records · local checkpoints stays here: prompt, answer, secrets provider side proposed · #2017 MESH QUIC request tokens stream back LIGHTNING input, then output invoice two payments each side's half swapped at completion CLOSED when both match not yet published a witness (optional) registers checkpoints, never content off unless you set its URL · v0.1.0 checkpoint checkpoint Paid inference on mesh-llm: two nodes, two books, an optional witness Top, the requester node; below it, the provider node. Each has the mesh-llm host, the payments.v1 plugin with a wallet, the evidence plugin, and its own book. Between them: the request and token stream over mesh QUIC, invoices and Lightning payments, and each side's half exchanged at completion (not yet published). The payer's payment.lifecycle.v1 stream is merged (#2035); the provider's is proposed (#2017). Both books can register checkpoints with a witness, off by default. merged / released proposed / unpublished REQUESTER NODE · PAYS mesh-llm host exchange event · digests payments.v1 + wallet emits payment.lifecycle.v1 payer side · merged #2035 evidence plugin · v0.1.0 seals this node's half digests only, never the text its own book sealed records · local checkpoints stays here: prompt, answer, preimage ① request ↓ · tokens ↑ mesh QUIC ② invoices ↑ · payments ↓ Lightning · input, then output ③ each side's half swapped at completion CLOSED when both match not yet published PROVIDER NODE · SERVES mesh-llm host runs the model · exchange event payments.v1 + wallet provider-side lifecycle proposed · #2017 evidence plugin · v0.1.0 seals this node's half digests only, never the text its own book sealed records · local checkpoints stays here: prompt, answer, secrets a witness (optional) registers checkpoints only off unless you set its URL checkpoint
Solid lines are merged in mesh-llm or released in the evidence plugin. Dashed lines are proposed upstream or not yet published. The witness is a separate party that only ever sees checkpoints, and you choose whether to use one.

1 · Serve

The requester sends the request with the provider's advertised prices. The provider prefills, then sends an input invoice with the terms frozen. It may decode ahead, but it pauses delivery at 512 tokens until its own wallet sees the payment.

2 · Pay

The payer pays the input invoice under its own spending cap. Output streams, and the provider invoices the output it actually sent. The payer settles that under the original authorization. Each moment appears on the payer's payment.lifecycle.v1 stream.

3 · Seal and close

At the end of the stream, each evidence plugin seals its node's half. On our working branch the two halves are swapped, and the exchange reads CLOSED when both sides recorded the same request and response digests. Checkpoints cover the new records, and a witness registers them if you turned one on.

The lifecycle

Six phases, and who asserts each one.

Every event carries a source, so a reader can see who is making the assertion. A signature on an event never upgrades it: a provider's claim stays a provider's claim.

PhaseWhat it recordsWho asserts itStatus
terms_acceptedThe payer accepted the frozen terms; the amount is its approved cap.payer_assertedmerged · #2035
input_invoice_issuedThe provider's input invoice, as the payer received it (not independently verified issuance).provider_assertedmerged · #2035
input_settlement_observedThe payer's wallet reported the input payment succeeded.wallet_reportedmerged · #2035
output_invoice_issuedThe provider's invoice for the output it sent, as the payer received it.provider_assertedmerged · #2035
output_settlement_observedThe payer's wallet reported the output payment succeeded.wallet_reportedmerged · #2035
final_accountedWhat the payer actually paid, fees included.payer_assertedmerged · #2035

The provider's half, proposed in #2017, uses the same event shape plus role: provider. It covers the invoice as actually issued (provider_asserted) and its own wallet seeing the payment arrive (wallet_reported). It also records when delivery paused and resumed at the token gate (host_asserted), a lapsed invoice, the output delivered, and a debt recorded or forgiven. A forgiveness is an operator action, so it goes on the record. proposed

What each party can show

Checkable by each side, without trusting the other's wallet.

The requester can show

  • What it agreed to: a digest over the eight public fields of the terms, and nothing private.
  • Whether and what its own wallet reported paying, keyed by payment_hash.
  • Its sealed half of the exchange: digests of the exact request and response, and the token counts.

The provider can show

  • Its sealed half of the exchange, including what it served and on which model file.
  • With #2017, the invoices it actually issued, what its own wallet received, and when delivery was paused for payment.
  • Which debts it recorded, and which an operator forgave.

Nobody takes on trust

  • That the other side's record is the same: the halves match by digest, or they don't.
  • That a record wasn't rewritten later: checkpoints commit to it, and a witness holds a copy of the checkpoint.
  • Which side a claim came from: every event names its source.

What no one can show from this, yet

  • That the inference was correct, or that the prefill was honest. Upstream states that prices and token counts are the provider's claims, and that neither is checked.
  • That a paid wallet belongs to any particular person or organisation.
  • That every event was delivered. The stream is best-effort by design (an eight-event queue and a one-second timeout, and settlement never waits for it), so a missing event means incomplete evidence, not a failed payment.

What stays local

Prompt and response text, the invoice string, the payment preimage, wallet transaction IDs, and the private recovery ID never leave the node in these events or records. What travels is digests, amounts and payment_hash. Upstream notes that payment hashes are linkable metadata, so treat them that way.

For builders

Run it on two nodes

  1. Build mesh-llm from main on both machines. payments.v1 merged on 25 Sep 2026 and is not in a tagged release yet (the latest release, v0.76.2, is from 14 Sep 2026).
  2. Set up a wallet on each node as the upstream payments spec describes. Paid mode moves real money over Lightning. A paid provider must run a single-node text model.
  3. Install the evidence plugin on both:
    mesh-llm plugins install action-state-group/capsule-emit-mesh@0.1.0
    Each node now seals its own half of every exchange and checkpoints locally. Nothing leaves the machine unless you set a witness URL.

Not released yet: the provider-side events (#2017, proposed), swapping halves and the CLOSED state (on a public branch, not yet released), and the Evidence tab (our fork, not published). Recording the payment events into the book is also not released; it is in design.

For enterprises

Why this matters for agent payments

When your agents buy and sell work from parties you don't know, a dispute is settled by records, and one side's ledger is not enough to settle it. Here each party seals its own view at the moment of the exchange, and the two views join on an identifier both wallets already share, so "never paid", "paid late" and "noticed late" become checkable facts rather than accusations. No platform sits in the middle holding everyone's data: each party keeps its own book and shows only what a dispute needs.

When a dispute needs a second signature from someone who is neither party, that is what Countersign is for.

Claims table

Every claim on this page, and what it rests on.

Upstream links point at the mesh-llm pull request, issue or merge commit. Rows marked “not yet released” link a commit on a public branch that is not in a release yet. Rows marked “not yet public” cite a commit that hasn't been published, and the row says so.

#ClaimStatusRests on
1The mesh-llm host tells out-of-process plugins about each OpenAI exchange, including on the node that routed the request.merged#1437 · 6929c702887343af1b73296d7bd7f4aaa2db642f
#1668 · 85b142df02fbb4c2555becd589ad7324296a8114
2That event carries digests of the exact request and response, plus serving provenance, so a half commits to digests and not text.merged#1841 · 6ffb2b711f081ca03bde7dc5bc9f8facec03da51
#1946 · 3060f3762aa92841be048113660eba07f2eab251
3The payments engine runs as the in-process payments.v1 plugin. It can be turned off, and with no engine installed the node runs free-only.merged#2035 · d06600ea0433a3271d0b51686ddb195f77a2336f
4The payer emits payment.lifecycle.v1: six phases, each with a source of payer_asserted, provider_asserted or wallet_reported.mergedpaid_events.rs @ d06600ea0433a3271d0b51686ddb195f77a2336f
5The terms digest covers eight public fields; the private recovery ID and the local peer are excluded.mergedpaid_events.rs @ d06600ea0433a3271d0b51686ddb195f77a2336f (terms_digest)
6Events carry no invoice string, preimage, wallet transaction ID, prompt or response text, and payment hashes are linkable metadata. Delivery is best-effort: an eight-event queue, a one-second timeout, and settlement never waits for it.mergeddocs/specs/lightning-payments.md @ d06600ea0433a3271d0b51686ddb195f77a2336f
7Two payments, input then output. Delivery pauses at 512 tokens until the provider's wallet sees the input payment.mergedlifetimes.rs @ d06600ea0433a3271d0b51686ddb195f77a2336f (PRE_PAYMENT_OUTPUT_TOKENS)
8An unpaid input invoice with nothing delivered lapses and does not block the peer. Delivered output left unpaid blocks the peer until it is paid or an operator forgives it.mergedreceivables.rs @ d06600ea0433a3271d0b51686ddb195f77a2336f
9Prices and token counts are the provider's claims. Correct inference and honest prefill are not checked.merged (stated)docs/specs/lightning-payments.md @ d06600ea0433a3271d0b51686ddb195f77a2336f (Payment flow)
10payments.v1 is not in a tagged release: the latest is v0.76.2 (14 Sep 2026), and #2035 merged on 25 Sep 2026.factmesh-llm releases · #2035
11The provider's matching events use the same shape plus role: provider, including host_asserted delivery pause and resume, lapse, and debt recorded or forgiven. They join on payment_hash.proposedissue #2017 (open)
12The evidence plugin installs with one command and seals each node's own half at the serving boundary. Local checkpoints are on by default, and the witness is off unless you set its URL.released · ourscapsule-emit-mesh v0.1.0 · 55a3656b6b7eb9a296cc4f3e3110d894d2b35a7e
13The halves are swapped at completion, and the exchange reads CLOSED when both sides' digests match.public branch · not yet releasedcapsule-emit-mesh 08c63607d62cef434e6f1b33144a17177b94755b (on a public branch, not in a release)
14The Evidence tab in mesh-llm shows each exchange's two halves and its CLOSED state.our fork · not yet publicmesh-llm fork d30ee1f3a8959d09309059f0fc0edc7a21dbd6cd (unpublished)
15The evidence plugin will read payment.lifecycle.v1 and record each payment moment with its source. The three missing-payment stories are read from those records.designedDESIGN-paid-inference-evidence.md @ v0.1.0

More worked examples, with reports you can open and check: Demos →