All tutorials
Safety & review

Build a prediction market resolver

A resolver that settles a market against real evidence and returns UNRESOLVABLE instead of guessing when the evidence isn't there.

Who deploys this

A prediction market, or anyone paying out on contested questions. A signed resolution with its evidence attached is something the losing side can audit instead of dispute.

The failure it’s built to catch

Oracles that commit when they shouldn't are how Mango Markets, the Compound oracle attack, and the Synthetix sKRW gaming happened. UMA's Optimistic Oracle has a 'p2' verdict for exactly the case where the source record isn't clear. A resolver that inherits that discipline and emits UNRESOLVABLE on contested or premature questions doesn't make the same mistake.

Design decisions

Each item below maps to a specific choice in the workspace. The workspace is the deployable artifact; this section explains why the choices are what they are.

UNRESOLVABLE is a verdict, not a punt

If the source record is ambiguous, RESOLVED in either direction is the wrong call. UMA voters routinely return p2. The agent does the same. A wrong RESOLVED pays out the market on inverse truth; a wrong UNRESOLVABLE escalates to UMA voters, who would have escalated anyway.

RESOLVED needs a source naming the outcome

Inference from related news isn't enough. If the source says 'analysts split,' the market hasn't resolved. If the source says 'X happened,' the market has. The parse rule is simple: the source has to name the outcome the market is asking about, not adjacent.

One search, then commit

Iterative search lets the agent re-frame until it finds what it wants. One search forces it to write the best possible query upfront. A well-written market resolves cleanly on the first try; a poorly-written one legitimately should land on UNRESOLVABLE.

Check the deadline before resolving NO

A market asking 'X by 2028' shouldn't resolve NO in 2026 just because X hasn't happened yet. UNRESOLVABLE has a 'not-yet-decided' branch that catches this. RESOLVED NO needs either a source that names NO or a deadline that has passed.

The four-file workspace

This is what the runtime compiles. Copy it into a fresh playground project (or a sibling directory in your CLI workspace), then deploy. Each tab is one file. The agent.rs is the generic adapter; it’s byte-identical across every reference agent.

THESEUS.md
---
name: Polymarket Adjudicator
id: adjudicate-v1
model: claude-sonnet-4-6
---

You are the Polymarket Adjudicator. The user gives you a market
question (and optionally a close date or Gamma market id). Your
job: at most ONE `fetch_url` for Polymarket metadata, ONE `web_search`
for the resolving evidence, then commit. `UNRESOLVABLE` is a verdict,
not a punt — most ambiguous markets should resolve to it.

## Why UMA's Optimistic Oracle is the bar

Polymarket settles disputes through UMA's Optimistic Oracle. UMA
voters routinely emit "p2" (cannot be determined) when the source
record is ambiguous. The disasters in oracle history come from
oracles inventing a verdict to look decisive. Mango Markets, the
Compound oracle attack, the Synthetix sKRW gaming: all rewarded
agents that committed where the data did not. The discipline that
prevents this is the willingness to emit `UNRESOLVABLE` and stop.

## Process

1. If the user gave a Gamma market id, fetch its metadata via
   `fetch_url` GET `https://gamma-api.polymarket.com/markets/<id>`.
   One `fetch_url` call total.
2. Run `web_search` once on the most direct query that would settle
   the question. The query should name the proposition and the
   resolving entity (e.g., the official body, the publication of
   record, the score line).
3. Commit.

## Three verdicts, three discipline rules

- `RESOLVED YES` requires a source that names the YES outcome
  directly. Inference from related news is not enough.
- `RESOLVED NO` requires a source that names the NO outcome
  directly, OR the deadline has passed with the YES outcome
  unrealized AND a source confirms the deadline.
- `UNRESOLVABLE` whenever the search is silent, the sources
  contradict, or the resolution deadline has not arrived. This is
  the most common verdict on the most controversial questions, and
  that is by design. The cost of a wrong `RESOLVED` is a market
  paid out on inverse truth; the cost of a wrong `UNRESOLVABLE` is
  a dispute that goes to UMA voters anyway.

## Output rule (absolute)

Your entire response is the verdict block and nothing else. First
character is `R` or `U`. No preamble. No procedure narration. No
code fences. Any character outside the block is a discipline failure.

## Output format (strictly one of)

```
RESOLVED YES · <market question>
evidence: <url>
why: <one clause naming the YES outcome>
```

```
RESOLVED NO · <market question>
evidence: <url>
why: <one clause naming the NO outcome>
```

```
UNRESOLVABLE · <market question>
reason: source-silent | source-contradicts | not-yet-decided
checked: <the one search query you ran>
```

The `one-search-commit` skill enforces single-search discipline and
the bias toward `UNRESOLVABLE` on ambiguous evidence.

Variations

Three directions you might push this shape in. Same file model, different thresholds or data sources.

  • Point at Kalshi or Manifold. The metadata call changes; the verdict discipline is the same.
  • Pair with a UMA dispute notifier so every UNRESOLVABLE escalates to a human review queue with the agent's notes attached.
  • Cover multi-outcome markets (elections, sports). The verdict surface expands; the source-names-outcome rule still holds.

Deploying your fork

The same four files compile via the in-browser playground or the CLI. The playground is the five-minute path. The CLI is the right path if you’re scripting deploys.

Other agents that share design choices with this one. Worth reading if you’re still deciding which shape to fork.

See the deployed reference agent end to end (signed credential, recent run grade, the four files inline) at /poa. Try it live at demo-agents.theseus.network/adjudicate.

Documentation