FairWhistle

agent & API docs
Landing here as an agent? Start with /llms.txt โ€” a plain-text index of everything on this page, sized for a model's context window.

What FairWhistle is

FairWhistle is a match-integrity surveillance agent. It watches odds microstructure across four books (1X2 + totals 2.5) for patterns consistent with match fixing or informed money, using three transparent, causal detectors โ€” abnormal repricing velocity, cross-market coordination, and stale-then-snap board freezes (see the rule cards on the live dashboard for exact thresholds). Every detection is published as a timestamped, SHA-256-fingerprinted, Ed25519-signed alert โ€” evidence-grade, not a black box.

It runs against two sources: a replay fixture โ€” a committed, seeded, deterministic synthetic tape with 3 openly-labeled planted anomalies, replayed on a 10-minute loop, always available โ€” and live โ€” the real FIFA World Cup Final via TxLINE mainnet consensus odds (free tier, ~60s batch delay). FairWhistle prices no trades and makes no execution claims; it answers one question: is there a reason to distrust the current price on this market? Frame it as a trading agent's risk desk โ€” check it before you trade, not as a strategy in itself.

Read endpoints (raw HTTP)

All are public, CORS-open, no auth. Base URL: https://fairwhistle.vercel.app

EndpointWhat
GET /api/alertsAttested replay-fixture alerts: hashed, Ed25519-signed, current cycle.
GET /api/live-state?sinceTs=Live TxLINE surveillance state: odds points, feed events, live alerts. Returns 503 with an honest note if the deployment has no TXLINE_API_TOKEN configured โ€” expected, not a bug.
GET /api/metaAgent identity (Ed25519 pubkey), fixture id, detector rule parameters.
POST /api/verifyServer-side signature verification. Body: {instance, signature, publicKey}. Also GET /api/verify?id=<alertId> for a replay-cycle alert looked up by id.
GET /api/feedtext/event-stream SSE push of alerts as they're detected. Long-lived; not wrapped as an MCP tool (a poor fit for request/response) โ€” use /api/alerts for a snapshot, or subscribe directly for the live stream.
curl "https://fairwhistle.vercel.app/api/alerts"
curl "https://fairwhistle.vercel.app/api/live-state"
curl "https://fairwhistle.vercel.app/api/meta"
curl -X POST "https://fairwhistle.vercel.app/api/verify" \
  -H 'content-type: application/json' \
  -d '{"instance": {...}, "signature": "...", "publicKey": "..."}'
curl -N "https://fairwhistle.vercel.app/api/feed"

MCP tools

FairWhistle ships a thin stdio MCP server (mcp/server.mjs in the repo, using the official @modelcontextprotocol/sdk) that wraps the read endpoints above โ€” no detection or attestation logic of its own, just fetch + a light, honest reshape:

ToolWrapsWhat
list_active_alerts({ source, severity?, includeEvidence? })/api/alerts or /api/live-stateFull current alert set for a sweep.
get_market_status({ source })/api/state or /api/live-stateReplay cycle/minute/score, or live feed/kickoff/game state.
check_market_integrity({ market, source })same as above, filteredThe pre-trade check: clean or flagged for one outcome.
verify_alert_signature({ source, alertId?, instance?, signature? })/api/verifyConfirms an alert's Ed25519 signature.
check_market_integrity({ market: "a", source: "replay" })
->
{
  "verdict": "flagged",
  "matchingAlertCount": 1,
  "alerts": [{ "core": { "rule": "velocity",
    "narrative": "Cirrus Sports repriced 1X2 ยท Away far faster than baseline volatility explains..." } }]
}

source is replay (default, a labeled synthetic fixture) or live (the real TxLINE feed, ~60s upstream delay, may be unconfigured on a given deployment โ€” an honest available: false there, not a bug). Every tool description states these caveats in-band; none oversell "real-time" or guaranteed accuracy.

Installing the MCP server / Claude Code plugin

git clone https://github.com/chaintail/fairwhistle
cd fairwhistle
pnpm install                # pulls in @modelcontextprotocol/sdk + zod
node mcp/server.mjs         # stdio MCP server; talks to fairwhistle.vercel.app

The repo is also a Claude Code plugin: .claude-plugin/plugin.json + .mcp.json wire the fairwhistle MCP server to node ${CLAUDE_PLUGIN_ROOT}/mcp/server.mjs, and skills/fairwhistle-integrity/SKILL.md documents tool usage, when to reach for it as a pre-trade check, honest caveats, and a described (prose-only, not implemented) pattern for polling live surveillance during a trade window.

Codex works with the same stdio server via its mcp_servers config (~/.codex/config.toml):

[mcp_servers.fairwhistle]
command = "node"
args = ["/absolute/path/to/fairwhistle/mcp/server.mjs"]

[mcp_servers.fairwhistle.env]
FAIRWHISTLE_BASE_URL = "https://fairwhistle.vercel.app"

Links

Repo: github.com/chaintail/fairwhistle
Live dashboard: fairwhistle.vercel.app
Live surveillance view: /live.html
Agent index: /llms.txt
Skill: skills/fairwhistle-integrity/SKILL.md