polycoder
v0.5.0
Published
Polymath — a cost-optimized, multi-model TUI coding agent. Decomposes work into typed tasks, routes each task to the cheapest capable model via OpenRouter, and logs real usage/cost by date + model.
Maintainers
Readme
Polymath 🪄
A cost-optimized, multi-model AI agent for your terminal, VS Code, and Chrome. Like Claude Code, it breaks a request into typed steps — but it routes each step to the cheapest model that's actually good at it (via OpenRouter, 300+ models), records real token usage and cost by date + model, and recommends the best-value model combo before you run.
| Surface | What it does | Install |
|---|---|---|
| CLI / TUI (poly) | Full coding agent in your terminal | npm i -g polycoder |
| VS Code | Runs the agent in the integrated terminal | vscode-extension/ → VSIX |
| Chrome | Automates work in the browser (read / click / type / extract) | chrome-extension/ → load unpacked |
All three share the same skill-aware routing brain and cost ledger.
┌ Polymath · policy: value ──────────────── 4 calls · 12.1k tok · $0.0031 ┐
└─────────────────────────────────────────────────────────────────────────┘
📋 Plan (5 steps) · planner: google/gemini-2.0-flash-001
▶ Step 1 [plan] → google/gemini-2.0-flash-001 ~$0.0004
▶ Step 2 [search] → mistralai/ministral-3b ~$0.0001
▶ Step 4 [edit] → qwen/qwen3-coder ~$0.0021
✓ Added dark-mode toggle to settings panel
✓ Done · 4 calls · 12.1k tokens · $0.0031Why
Running every task on a frontier model is wasteful. Searching, summarizing, and reading don't need a $15/Mtok model — a $0.05/Mtok one is fine, and a cheap coder-tuned model beats a pricey generalist at edits. Polymath assigns the cheapest model that genuinely covers each task and proves the savings with a per-call cost ledger.
Install
Requires Node.js ≥ 22.5 (the CLI uses the built-in
node:sqlite).
1 · CLI (poly)
From npm:
npm install -g polycoder
poly setup # guided: optionally install a local LLM (Ollama) + connect modelspoly setup asks whether to install a local LLM, or skip the prompt with a flag:
poly setup --local # install Ollama + pull a model (RAM-aware default)
poly setup --local -m qwen2.5-coder:7b # choose the model
poly setup --no-local # cloud only — just connect an OpenRouter key
poly setup --local -y # non-interactive (accept defaults / auto-install)Keep everything current with poly update (the CLI via npm, the Ollama runtime, and
your local models) — add --check to only report what's available:
poly update # update CLI + Ollama + re-pull local models
poly update --check # report-only
poly update --self # just the CLI (also --ollama, --models)From source (no npm publish needed):
git clone https://github.com/psychiatristlee/polycoder.git
cd polycoder
npm install # auto-builds dist/cli.js
npm link # puts `poly` on your PATH
poly login2 · VS Code extension
cd vscode-extension
npm install && npm run build && npm run package # -> polymath-vscode-0.1.0.vsixInstall the .vsix via Extensions → … → Install from VSIX…, then use the Command
Palette → "Polymath:". (It drives the poly CLI, and offers to install it if missing.)
3 · Chrome extension
cd chrome-extension
npm install && npm run buildThen chrome://extensions → enable Developer mode → Load unpacked → pick the
chrome-extension/ folder. Open the side panel, paste your OpenRouter key in Settings,
and give it a goal for the active tab. See chrome-extension/README.md.
First run (CLI)
poly recommend "add a dark-mode toggle to the settings page" # model/cost options first
poly run -w -x "add a dark-mode toggle" # -w allow file writes, -x allow shell commands
poly usage # cost by date + modelCommands
| Command | What it does |
|---|---|
| poly setup | First-run: optionally install a local LLM (Ollama) + connect models. --local / --no-local / -m <model> / -y. |
| poly update | Update the CLI (npm), the Ollama runtime, and local models. --check, --self, --ollama, --models. |
| poly login | Connect/replace your OpenRouter API key (Claude-Code-style onboarding). |
| poly run [goal] | Launch the interactive agent. Shows the recommended routing, then executes. |
| poly recommend <goal> | Pre-run recommendation: cheapest / best-value / best-quality model combos + savings. |
| poly models | Browse the catalog with pricing, tier, tool support. Filters: --tier, --tools, --search. |
| poly usage | Recorded usage & cost grouped by date + model. --today, --since, --sync. |
| poly analyze | Which approach reaches the goal with the fewest tokens — efficiency playbook, best model per task type, objective × achievement, usage per command. |
| poly sync | Push distilled efficiency insights to Firebase (Data Connect SQL / Firestore). Raw logs stay local unless --raw. |
| poly config show\|set\|firestore\|dataconnect\|local | View/change settings. |
After each poly run, rate the result 0–9 (one keypress) — your goal-achievement
rating joins the auto score (completed/planned steps) to power poly analyze.
Outcome-driven loop (verify → escalate → repeat)
poly run doesn't stop at "code written" — it measures the result and keeps going
until the goal is actually met:
command → plan + acceptance criteria → code (cheapest model)
→ VERIFY result against criteria (inspects files, runs tests)
→ if unmet: ESCALATE (higher tier, more tokens, cost cap lifted) → fix → re-verify
→ repeat until all criteria pass (or --max-attempts)The cheapest model gets first crack; only the criteria it fails trigger a pricier model — so you pay for frontier capability exactly when (and only when) it's needed.
poly run -w -x "add an add(a,b) to calc.js and make the tests pass"
poly run --no-verify "..." # single pass, no verify/escalate
poly run --max-attempts 5 "..." # try harder before giving upAfter each run you'll see ✓ goal met · 2 attempts (or ⚠ goal not fully met).
Statistical model optimization (learned starting tier)
Every attempt is recorded with its goal type, starting tier, tokens, and pass/fail.
poly analyze then shows, per goal type, which starting model reaches the goal
with the fewest total tokens — and once there's enough evidence (≥3 verified
sessions), poly run auto-starts at that tier, skipping cheap attempts for goal
types that historically need a stronger model from the start.
The efficiency playbook (learned routing)
Everything is captured locally (SQLite). poly analyze distills it into a playbook
of notably efficient approaches — a (task, model) pair qualifies only with ≥3
successful runs, ≥70% success, and ≥20% fewer tokens than the median of its
competitors. The playbook then boosts routing: proven-efficient models get
preferred under the value objective (reason: proven 54% fewer tokens on edit).
poly sync uploads only the playbook by default — your goals and raw logs never
leave the machine unless you pass --raw.
Local LLMs (Ollama / LM Studio) — $0 routing
ollama serve # or LM Studio's local server
poly config local on # default base: http://localhost:11434/v1
poly config local on --base http://localhost:1234/v1 # LM Studio
poly models -s local/ # local models join the catalog at $0
poly run "..." # cheapest objective → local wins what it canLocal models appear as local/<name>, cost $0, and need no API key — with
local on and no OpenRouter key, Polymath runs fully offline on your machine.
Tokens are still tracked, so the playbook learns when your local model is the
most efficient approach.
Routing objectives
Routing is skill-aware: each task type maps to a skill (coding / reasoning /
retrieval / speed), and every model family has a strength profile for those skills
(Claude → coding & agentic, DeepSeek-R1 / o-series → reasoning, Gemini Flash → cheap
retrieval, …). See src/models/strengths.ts.
cheapest— cheapest model that still covers the task's skill.value— best strength-per-dollar for that task (default). Coding work lands on the cheapest genuinely-good coder; a cheap coder-tuned model beats a pricey generalist foredit.quality— strongest model at the task's skill (e.g. Claude for coding edits).
poly run --objective quality "design a rate limiter"
poly run --max-cost 0.02 "small bug fix" # never pick a model that'd cost > $0.02/callHow it works
- Plan — a cheap model decomposes the request into typed steps
(
plan,search,read,edit,command,review,reason, …). - Route — each task maps to a skill; a model is eligible if it meets the tier
floor or is strong enough at that skill (so cheap coder models qualify for
edits). The router then picks by objective. See
src/router/,src/models/tiers.ts,src/models/strengths.ts. - Execute — a bounded tool-use loop runs the step (read/write files, run commands). Every model call's real usage + cost is logged.
- Ledger — usage is stored in local SQLite (
~/.config/polymath/usage.sqlite) and optionally synced to Firestore.
Data & secrets
- API key:
~/.config/polymath/config.json(chmod 600). Override per-shell withOPENROUTER_API_KEY. - Usage DB:
~/.config/polymath/usage.sqlite(built-innode:sqlite, no native deps). - Optional Firestore sync uses the project's existing
mathology-b8e3dFirebase project; enable withpoly config firestore onand provide credentials viaFIREBASE_SERVICE_ACCOUNT_KEYor ADC.
Develop
npm run dev -- recommend "..." # run from source via tsx
npm run typecheck # tsc --noEmit
npm run build # esbuild -> dist/cli.jsRequires Node ≥ 22.5 (for node:sqlite).
