Assert an agent’s output

Assert the answer before it goes anywhere. An agent was told: “Summarise this source in JSON with a summary, one quotation from it, and the source_url.” A second call checks it: the JSON validates against the schema the caller wrote, the quotation appears verbatim in the source as the caller supplied it, a URL is present and under the allowed domain, and none of the usual hedges appear. Every check is a deterministic function of the inputs, so the same output gets the same verdict every time, and the answer is a signed Assay record that names which check failed and where. The second answer below fabricates its quotation; the record says so.

3calls answered
2receipts re-hashed
2records verified
$0.01list price for a stranger
338ms end to end
partial · 2 records verified

Run 2026-10-11 05:26 UTC against api.s2ar.dev 0.1.1 · 3 calls · 338 ms · list price $0.01 for a stranger (these ran on the operator's key and cost nothing) · every number on this page re-derived by tools/walkthrough.py before it was written

1. The quote: HTTP 402

The price, the rails, the determinism and the witnesses of this route, and where the worked example lives. The quote costs nothing.

curl -s -X POST 'https://api.s2ar.dev/v1/assert' \
  -H 'X-Assay-Quote: 1' \
  -H 'content-type: application/json' \
  -d '{"text": "{\"summary\": \"ripgrep parses the --glob flag in defs.rs; later globs override earlier ones.\", \"quote\": \"Overrides are applied in order of appearance on the command line\", \"source_url\": \"https://github.com/BurntSushi/ripgrep\"}", "checks": [{"check": "json_valid"}]}'

→ HTTP 402 · 123 ms

price_usd0.005
rails["x402", "credits"]
determinismreplayable
witnesses["checks"]
expected_latency_ms300
free.per_day_keyless10
how_to_payPay per call with USDC on Base over x402 (no key: sign the 402's accepts[0], resend with PAYMENT-SIGNATURE); or buy a $5 pack by card and send Authorization:…
docshttps://s2ar.dev/examples/assert-an-agents-output.html
the answer, as JSON
{
  "price_usd": 0.005,
  "rails": [
    "x402",
    "credits"
  ],
  "determinism": "replayable",
  "witnesses": [
    "checks"
  ],
  "expected_latency_ms": 300,
  "free.per_day_keyless": 10,
  "how_to_pay": "Pay per call with USDC on Base over x402 (no key: sign the 402's accepts[0], resend with PAYMENT-SIGNATURE); or buy a $5 pack by card and send Authorization:…",
  "docs": "https://s2ar.dev/examples/assert-an-agents-output.html"
}

2. An answer that holds

Four checks, four passes: the JSON validates, the quotation is in the source word for word, the URL is under github.com, no hedge.

curl -s -X POST 'https://api.s2ar.dev/v1/assert' \
  -H "Authorization: Bearer $S2AR_KEY" \
  -H 'content-type: application/json' \
  -d '{"text": "{\"summary\": \"ripgrep parses the --glob flag in defs.rs; later globs override earlier ones.\", \"quote\": \"Overrides are applied in order of appearance on the command line\", \"source_url\": \"https://github.com/BurntSushi/ripgrep\"}", "source": "The glob flag is parsed in crates/core/flags/defs.rs. Each flag is a type implementing the Flag trait, with a short name, a long name and a documentation string. Overrides are applied in order of appearance on the command line, so a later --glob can undo an earlier one.", "checks": [{"check": "json_schema", "schema": {"type": "object", "required": ["summary", "quote", "source_url"], "properties": {"summary": {"type": "string", "maxLength": 200}, "quote": {"type": "string"}, "source_url": {"type": "string"}}}}, {"check": "quotes_in_source"}, {"check": "urls_allowed", "domains": ["github.com"]}, {"check": "banned_terms", "terms": ["I cannot", "as an AI", "I'm not sure"]}]}'

PARTIAL → HTTP 200 · 101 ms · list price $0.005 · receipt sha256:709c64a987b51f19…

verdictpartial
passed3
checks4
score0.75
results.0.checkjson_schema
results.0.oktrue
results.1.checkquotes_in_source
results.1.okfalse
results.1.evidence{"quotes": 2, "missing": ["ripgrep parses the --glob flag in defs.rs; later globs override earlier ones."]}
record.kindassertion
record.issuerassay
record.replayabletrue
record_sha25611dcc16c0d1402c0…
x-assay-record11dcc16c0d1402c0…
the answer, as JSON
{
  "verdict": "partial",
  "passed": 3,
  "checks": 4,
  "score": 0.75,
  "results.0.check": "json_schema",
  "results.0.ok": true,
  "results.1.check": "quotes_in_source",
  "results.1.ok": false,
  "results.1.evidence": {
    "quotes": 2,
    "missing": [
      "ripgrep parses the --glob flag in defs.rs; later globs override earlier ones."
    ]
  },
  "record.kind": "assertion",
  "record.issuer": "assay",
  "record.replayable": true,
  "record_sha256": "11dcc16c0d1402c086d05906d73d637092e42d8d0e837589685b72530b8c10ba",
  "x-assay-record": "11dcc16c0d1402c086d05906d73d637092e42d8d0e837589685b72530b8c10ba"
}

Assay badge for record 11dcc16c0d1402c0

re-derived by the generator
✓receipt sha256:709c64a987b51f19… re-derived: sha256 over the canonical answer, header and body agree
✓record 11dcc16c0d1402c0… fetched back from /v1/verify: sealed, signed, and signed by assay-1 (the key at /.well-known/assay.json)

3. An answer that fabricates its quotation

The schema still validates; the quotation is not in the source and a hedge slipped in: two of four checks fail, and the evidence names the missing quote and the hedge’s offset. The call is delivered, charged and recorded: the evidence is the answer.

curl -s -X POST 'https://api.s2ar.dev/v1/assert' \
  -H "Authorization: Bearer $S2AR_KEY" \
  -H 'content-type: application/json' \
  -d '{"text": "{\"summary\": \"ripgrep parses globs in defs.rs; I cannot be sure which wins.\", \"quote\": \"the last glob always wins and earlier ones are discarded\", \"source_url\": \"https://github.com/BurntSushi/ripgrep\"}", "source": "The glob flag is parsed in crates/core/flags/defs.rs. Each flag is a type implementing the Flag trait, with a short name, a long name and a documentation string. Overrides are applied in order of appearance on the command line, so a later --glob can undo an earlier one.", "checks": [{"check": "json_schema", "schema": {"type": "object", "required": ["summary", "quote", "source_url"]}}, {"check": "quotes_in_source"}, {"check": "urls_allowed", "domains": ["github.com"]}, {"check": "banned_terms", "terms": ["I cannot", "as an AI", "I'm not sure"]}]}'

PARTIAL → HTTP 200 · 114 ms · list price $0.005 · receipt sha256:8c0538ce649f06f2…

verdictpartial
passed2
checks4
results.1.checkquotes_in_source
results.1.okfalse
results.1.evidence.missing["ripgrep parses globs in defs.rs; I cannot be sure which wins.", "the last glob always wins and earlier ones are discarded"]
results.3.checkbanned_terms
results.3.okfalse
results.3.evidence.found[{"term": "I cannot", "offset": 46}]
record.outcomepartial
record_sha2562178d867d06fe537…
the answer, as JSON
{
  "verdict": "partial",
  "passed": 2,
  "checks": 4,
  "results.1.check": "quotes_in_source",
  "results.1.ok": false,
  "results.1.evidence.missing": [
    "ripgrep parses globs in defs.rs; I cannot be sure which wins.",
    "the last glob always wins and earlier ones are discarded"
  ],
  "results.3.check": "banned_terms",
  "results.3.ok": false,
  "results.3.evidence.found": [
    {
      "term": "I cannot",
      "offset": 46
    }
  ],
  "record.outcome": "partial",
  "record_sha256": "2178d867d06fe537131608c173220ef92bb7c6e7831d293cb1960fab2b10dc45"
}

Assay badge for record 2178d867d06fe537

re-derived by the generator
✓receipt sha256:8c0538ce649f06f2… re-derived: sha256 over the canonical answer, header and body agree
✓record 2178d867d06fe537… fetched back from /v1/verify: sealed, signed, and signed by assay-1 (the key at /.well-known/assay.json)

The record carries the checks, each result and the sha256 of the text and the source, never the text: anyone holding the output can re-run the checks, and anyone at all can check the seal and the signature, free, at /v1/verify/<record_sha256>. Read the verdict for what it is: quotes_in_source proves the output is consistent with the source as given (its hash is in the record), not that the source is true or complete; a reader who cares compares source_sha256 with the document they trust. An agent calls the same route as GET /v1/assert?text=&checks=, or the assert_output tool over MCP; GET /v1/assert/checks lists the check kinds and the named rubrics.

What this cannot buy

From the signed proceedings (/.well-known/proceedings.json), verbatim:

Failed calls are never charged. Nothing about a caller is kept. The rules: the charter.