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
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.
--- 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.
Related tutorials
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.