v0 source realm
Package jury is a commit-reveal adversarial review protocol for disputes over agent work.
View source
Agent Jury — who checks the agents?
Paying agents is the easy part of an agent economy. The hard part is what happens when an agent's output is disputed: a patch that may be wrong, a research claim that may be fabricated, an oracle reading someone contests. Someone has to adjudicate — and if that someone is a single trusted party, you've just recreated the thing blockchains were supposed to remove.
This realm runs a small commit-reveal jury: a fixed panel of reviewers each lock in a hidden verdict, then reveal it. Because verdicts are committed blind, no juror can copy another's vote, and none can be swayed by watching the tally form.
The two phases
commit: each juror submits commit.Verdict(verdict, salt) ← hash, hides the vote
reveal: each juror submits (verdict, salt) ← must reproduce the hash
close: majority of revealed verdicts decides the outcome
The commitment scheme is shared with the other demos
(p/moul/agents/commit/v0), so a juror computes their commitment off-chain:
1commitment := commit.Verdict(true, "a-random-salt") // "I vote YES", hidden
2
3jury.Commit(cross(cur), caseID, commitment) // during commit phase
4// ...later...
5jury.Reveal(cross(cur), caseID, true, "a-random-salt") // reproduces it, or the reveal is rejected
When the last juror commits, the case auto-advances to reveal; when the last reveals, it closes and records the majority outcome. Dissenting jurors (those who voted against the majority) are marked in the render — minority reports stay visible, which matters when the minority turns out to be right.
Composability
A case's subject is just an opaque string — a receipt sequence from the receipt demo, a claim id from gnomem, a raw artifact hash. The jury doesn't import any of them; it adjudicates references. That's the point of small, single-purpose realms: they snap together without hard dependencies.
1id := jury.OpenCase(cross(cur), "receipt#7", []address{j1, j2, j3})
2// ... commit + reveal ...
3jury.Outcome(id) // "upheld" | "rejected" | "tie"
Browse cases at the realm root; each panel and tally is at :<id>.
1gno test .
What's missing (on purpose)
The mechanism is here; the money is not. A production jury bonds each juror (stake coins to serve) and slashes provably bad verdicts — that's what makes honest review the profitable strategy. It also wants juror selection (random or reputation-weighted, to resist packing) and an appeal path (a larger panel on challenge). All of those compose on top of this commit-reveal core; none of them change it.
The uncomfortable design truth: you can't prove a verdict is correct. You can make it blind, independent, and accountable — and that's what turns "one trusted adjudicator" back into "a protocol."
Part of moul/gno-contracts — moul's versioned gno.land contracts. See the repository for the full catalog, build/test tooling, and usage.
Dependency graph:

⚠️ Disclaimer: provided as-is, without warranty; not security-audited. Full disclaimer: DISCLAIMER.
Package jury is a commit-reveal adversarial review protocol for disputes over agent work.
The hard part of an agent economy is not paying agents — it is deciding what happens when an agent's output is disputed. This realm runs a small jury: a fixed panel of reviewers each *commit* to a hidden verdict, then *reveal* it. Commit-reveal means no juror can copy another's vote or be swayed after seeing the tally; every verdict is locked in blind.
The subject of a case is an opaque string — a receipt sequence, a claim id, an off-chain artifact hash — so this realm composes with the receipt and gnomem demos without depending on them.
Bonding and slashing (a juror stakes coins, loses them for provably bad verdicts) are the natural economic layer on top; this demo shows the mechanism without the money.
1
7
func Commit
crossing ActionCommit locks in a juror's hidden verdict. commitment must equal commit.Verdict(verdict, salt) — computed off-chain. When the last juror commits, the case advances to the reveal phase automatically.
func Count
ActionCount returns the number of cases.
func OpenCase
crossing ActionOpenCase starts a dispute with a fixed panel of jurors. An odd panel size avoids ties; duplicates are rejected.
func Outcome
ActionOutcome returns the recorded outcome, or "" if the case is still open.
func Render
Render shows all cases, or one case's panel + tally at :<id>.
func Reveal
crossing ActionReveal opens a juror's verdict. The (verdict, salt) must reproduce the commitment made earlier, or the reveal is rejected. When the last juror reveals, the case closes and the majority outcome is recorded.
func Get
ActionGet returns a copy of a case (jurors flattened separately via Jury).
3
type Case
structCase is a single dispute under review by a fixed panel.
type Juror
structJuror is one panelist and their (eventually revealed) verdict.
type Phase
identPhase is a case's position in the commit-reveal lifecycle.
5
- chain stdlib
- chain/runtime stdlib
- gno.land/p/moul/agents/commit/v0 package
- gno.land/p/nt/ufmt/v0 package
- strings stdlib