AI-powered research assistant for Polymarket prediction markets.
PolyChrome searches multiple sources (Exa, Perplexity, xAI Grok), cross-checks claims, and estimates fair probabilities to help you make informed decisions.
- 🔍 Multi-source research: Queries Exa, Perplexity Sonar Pro, and xAI Grok for comprehensive coverage
- 📊 Fair probability estimates: Compares market odds against research-based estimates
- 📑 Citation tracking: Every claim links to its source
- ⚡ Multiple modes: Fast, Balanced, or Deep analysis
- 🔒 Secure: API keys stay on your Cloudflare Worker, never in the extension
┌─────────────────────────────────────────────────────────────────┐
│ Chrome Extension (MV3) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │Content Script│───▶│ Background SW │───▶│ Sidebar UI │ │
│ │(DOM Parser) │ │ (API Calls) │ │ (Results) │ │
│ └──────────────┘ └───────┬───────┘ └──────────────────┘ │
└──────────────────────────────┼──────────────────────────────────┘
│ POST /v1/analyze
▼
┌─────────────────────────────────────────────────────────────────┐
│ Cloudflare Worker │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ AI Agent │───▶│ Tools │───▶│ Cache + Rate │ │
│ │ (OpenRouter) │ │ Exa/PPL/Grok │ │ Limiting │ │
│ └──────────────┘ └──────────────┘ └──────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
polychrome/
├── shared/ # Shared Zod schemas + TS types
│ ├── schema.ts # API contract schemas
│ ├── types.ts # Inferred TypeScript types
│ └── index.ts # Re-exports
├── worker/ # Cloudflare Worker (API)
│ ├── src/
│ │ ├── index.ts # Entry point + routing
│ │ ├── agent.ts # AI agent with generateText
│ │ ├── env.ts # Environment bindings
│ │ ├── tools/ # Search tool implementations
│ │ │ ├── exa.ts
│ │ │ ├── perplexity.ts
│ │ │ └── grok.ts
│ │ └── util/ # Caching + rate limiting
│ │ ├── cache.ts
│ │ └── rate-limit.ts
│ ├── test/ # Agent tests + trace runners (Bun)
│ │ ├── agent.unit.test.ts
│ │ ├── agent.run.test.ts
│ │ ├── http-test-agent.ts
│ │ ├── run-agent-trace.ts
│ │ └── traces/ # Local trace outputs (gitignored)
│ ├── wrangler.toml # Worker configuration
│ └── package.json
├── extension/ # Chrome Extension (MV3)
│ ├── src/
│ │ ├── background.ts # Service worker
│ │ ├── content.ts # Page injection
│ │ ├── options.ts # Settings page
│ │ ├── options.html
│ │ ├── polymarket/
│ │ │ └── parse.ts # DOM parser
│ │ └── ui/
│ │ ├── sidebar.ts
│ │ └── sidebar.css
│ ├── manifest.json
│ ├── build.ts # Bun build script
│ └── package.json
├── package.json # Workspace root
├── plan.md # Implementation checklist
└── README.md
- Bun v1.0+
- Wrangler (installed via deps)
- API keys for:
- OpenRouter (for LLM access)
- Exa (web search)
- Perplexity (Sonar Pro API)
- xAI (Grok with live search)
# Clone and install dependencies
git clone https://github.com/your-repo/polychrome.git
cd polychrome
bun install- Configure secrets:
bunx wrangler secret put OPENROUTER_API_KEY --config worker/wrangler.toml
bunx wrangler secret put EXA_API_KEY --config worker/wrangler.toml
bunx wrangler secret put PERPLEXITY_API_KEY --config worker/wrangler.toml
bunx wrangler secret put XAI_API_KEY --config worker/wrangler.toml- Deploy:
bun run deploy:worker
# or: bunx wrangler deploy --config worker/wrangler.toml- Note your Worker URL (e.g.,
https://polychrome-worker.your-subdomain.workers.dev)
bun run build:extension
# or: cd extension && bun run build- Open
chrome://extensions - Enable Developer mode (top right)
- Click Load unpacked
- Select the
extension/distfolder
- Click the PolyChrome icon in Chrome toolbar
- Or right-click → Options
- Enter your Worker URL (from step 2 of deployment)
- Choose your default analysis mode
# Start local dev server (port 8787)
bun run dev:worker
# or: bunx wrangler dev --config worker/wrangler.tomlThe worker includes a comprehensive test suite with structured tracing for debugging and analysis.
# Run all offline agent tests (fast, deterministic, no network calls)
bun run test:worker
# or: cd worker && bun test
# Run tests and write trace JSON files for each test run
POLYCHROME_WRITE_TRACES=1 bun run test:workerTest Coverage:
- Unit tests (
agent.unit.test.ts): Pure functions (JSON parsing, outcome preparation, fallback logic) - Integration tests (
agent.run.test.ts): Full agent runs with mocked AI/tools, covering:- Success path (generateObject works)
- Phase 1 failure (tool calls fail, continues with empty research)
- Phase 2 failure (structured output fails, falls back to manual JSON extraction)
- Complete fallback (manual parse fails, uses fallback analysis)
- Schema validation (ensures all responses match
AnalyzeResponseSchema)
Traces capture every step of an agent run: prompts, tool calls/results, model outputs, errors, and timings.
# Generate a trace from a direct agent run (no HTTP)
bun run trace:worker
# or: cd worker && bun run trace
# Trace files are written to worker/test/traces/agent-trace-*.jsonTrace Structure: Each trace is a JSON array of events with:
ts: ISO timestamptMs: Milliseconds since run starttype: Event type (e.g.,run.start,phase1.step.finish,phase2.generateObject.error)data: Event-specific payload (sanitized, truncated for large strings/objects)
Common Event Types:
run.start/run.complete: Run boundariesphase1.start/phase1.complete/phase1.error: Research gatheringphase1.step.finish: Each tool-calling step (includes tool calls/results)phase2.start/phase2.generateObject.success|error: Structured output generationphase2.manualParse.success|error: Fallback JSON extraction attempts
Test against a running wrangler dev server:
# Terminal 1: Start the worker
cd worker
bunx wrangler dev --remote
# Terminal 2: Run HTTP test (optionally with trace)
cd worker
bun run test:agent
# or with trace: bun run test:agent --traceThe HTTP test validates the full request/response cycle and can optionally write trace JSON files.
- Inspect trace files in
worker/test/traces/to see exactly what happened during a run - Compare traces between runs to identify regressions or changes in behavior
- Debug failures: Trace events include error details, model outputs, and tool results
- Performance analysis:
tMstimestamps show where time is spent
Note: Trace files are gitignored by default (worker/test/traces/*.json). Commit them only if needed for documentation or debugging specific issues.
cd extension
bun run build # Build once
bun run watch # Watch mode (if implemented)After rebuilding, refresh the extension in chrome://extensions.
Request:
{
"url": "https://polymarket.com/event/...",
"question": "Super Bowl Champion 2026",
"outcomes": [
{ "name": "Kansas City Chiefs", "marketProb": 0.12 },
{ "name": "Buffalo Bills", "marketProb": 0.10 }
],
"mode": "balanced"
}Response:
{
"market": {
"asOf": "2025-12-29T12:55:00Z",
"outcomes": [...]
},
"summaryBullets": [
"Key finding 1",
"Key finding 2"
],
"evidence": [
{
"claim": "Chiefs have won 4 of last 5 Super Bowls",
"confidence": 0.9,
"sources": [{ "title": "ESPN", "url": "...", "provider": "exa" }]
}
],
"forecast": {
"fairProbs": [
{ "name": "Kansas City Chiefs", "p": 0.11, "low": 0.08, "high": 0.14 }
],
"methodNotes": "Based on historical performance and current season stats"
},
"deltas": [
{ "name": "Kansas City Chiefs", "market": 0.12, "fair": 0.11, "delta": -0.01 }
]
}Set in wrangler.toml under [vars]:
| Variable | Default | Description |
|---|---|---|
OPENROUTER_MODEL |
google/gemini-2.0-flash-001 |
LLM model slug |
MODE_DEFAULT |
balanced |
Default analysis mode |
MAX_STEPS |
10 |
Max tool-calling iterations |
CACHE_TTL_SECONDS |
120 |
Cache duration |
RATE_LIMIT_PER_MINUTE |
30 |
Requests per IP per minute |
OPENROUTER_API_KEYEXA_API_KEYPERPLEXITY_API_KEYXAI_API_KEY
MIT