trinomen
v0.1.3
Published
Three-agent LLM pipeline in your terminal: a router classifies the prompt, a worker generates, a reviewer audits — all on free Groq + Gemini tiers with local budget tracking
Maintainers
Readme
trinomen
Three agents, zero dollars. A multi-agent LLM pipeline in your terminal — router → worker → reviewer — running entirely on free Groq and Gemini tiers.

Ask a question, get an answer. Ask for code, get code that has been classified, generated, reviewed, and (optionally) typechecked in a loop until it passes — each stage handled by a different model picked for that job.
$ trinomen "write a useDebounce hook in TypeScript"
┌─────────┐ ┌─────────┐ ┌──────────┐
│ router │ ───→ │ worker │ ───→ │ reviewer │
│ gpt-oss │ │ gemini │ │ gpt-oss │
│ 20b │ │ flash │ │ 120b │
└─────────┘ └─────────┘ └──────────┘
classifies generates audits
— review —
verdict: shipWhy
- Right-sized models. A 20B model classifies intent in milliseconds; a strong generalist writes the code; a 120B reasoning model audits it. No single model does a job a cheaper one could.
- Free-tier native. Every request is logged to a local SQLite database, and calls are budgeted against ~95% of each provider's daily free-tier caps. When one provider runs dry, the pipeline falls back to the other automatically.
- Adversarial by design. The worker and reviewer run on different providers, so the reviewer has no incentive to rubber-stamp its own output. Reviews come back as structured JSON: verdict (
ship/fix/reject), severity-tagged issues, and a patch. - Verified, not vibed. With
--loop, generated TypeScript is written to a sandbox and run throughtsc --strict. Typecheck errors and review issues are fed back to the worker until the code converges or hits the iteration cap.
Install
npm i -g trinomen
trinomen initYou need two free API keys (no credit card for either):
Keys are stored in ~/.trinomen/config.json (mode 0600), or read from the GOOGLE_API_KEY / GROQ_API_KEY environment variables, which take precedence.
Use
# anything — the router decides what kind of request it is
trinomen "what is the event loop"
trinomen "write a JWT auth middleware for express"
trinomen "review this: function add(a,b){ return a+b }"
# refinement loop: generate → typecheck → review → repeat until clean
trinomen --loop "write a useLocalStorage hook with cross-tab sync"
# skip the reviewer for quick stuff
trinomen --no-review "one-liner to dedupe an array"
# see which model handled each stage
trinomen -v "explain this reduce call: arr.reduce((a, b) => a + b, 0)"
# check today's token spend per provider/model
trinomen statusHow it works
- Router (
openai/gpt-oss-20bon Groq) classifies the prompt intoquestion/code/review/explain, scores complexity, and decides whether a review pass is worth the tokens. Trivial requests skip review entirely. - Worker (
gemini-2.5-flash) generates the answer with an intent-specific system prompt. Output token budget scales with the routed complexity (512 → 2048 → 4096), so a syntax question never burns a refactor-sized budget. - Reviewer (
openai/gpt-oss-120bon Groq) audits non-trivial code against a strict React/TypeScript rubric. It is prompted to flag only provable failures — concrete failing inputs or attack vectors — and a clean review is a valid result.
Every role has a fallback chain on the other provider, so a rate limit or malformed response degrades gracefully instead of failing the run:
| Role | Primary | Fallback |
| -------- | -------------------------- | ----------------------- |
| router | Groq gpt-oss-20b | gemini-2.5-flash-lite |
| worker | gemini-2.5-flash | Groq llama-3.3-70b |
| reviewer | Groq gpt-oss-120b | gemini-2.5-flash |
The refinement loop (--loop)
For code requests, --loop turns the pipeline into a convergence loop:
worker → extract code → tsc --strict (sandbox) → reviewer
↑ │
└── typecheck errors + review issues ─────────────┘The loop exits when the code typechecks and the reviewer says ship, or after --max-iterations (default 3). The sandbox is a throwaway npm project in ~/.trinomen/sandbox with typescript, react, and strict-mode tsconfig — created once on first use.
Budget tracking
Every call records its token usage to ~/.trinomen/budget.db (SQLite). Before each call, the rolling 24-hour spend is checked against conservative per-model caps; models over budget are skipped in favor of their fallback. trinomen status shows the current spend, trinomen reset clears it.
Is the pipeline actually worth it?
Compiling is a weak success metric — code can typecheck and still be wrong. So test/benchmark.js scores functional correctness: each task pins an exact API, and the compiled output must pass a hidden test suite no model ever sees. Three arms, same worker model, same prompt, same budget:
- One-shot — single generation, no feedback
- tsc-retry — typecheck errors fed back, regenerate (no reviewer; the ablation)
- Full pipeline — typecheck gate + LLM reviewer (
--loop)
Round 1 (2026-06-10, live free tiers):
| Task | One-shot | tsc-retry (no reviewer) | Full pipeline | | --- | --- | --- | --- | | debounce | ❌ tests | ✅ | ✅ | | TypedEventEmitter | ✅ | ✅ | ❌ compile | | paginate | ✅ | ✅ | ✅ | | deepEqual | ❌ compile | ✅ | ⊘ quota | | LRUCache | ✅ | ✅ | ✅ | | total | 3/5 · 6.0k tok | 5/5 · 8.0k tok | 3/4 · 41.9k tok |
The ablation was damning and drove two changes shipped in this repo:
- Compiler feedback is most of the value. tsc-retry fixed every one-shot failure for ~30% more tokens. The reviewer-everywhere pipeline cost 5× more and did worse — so the loop is now gate-first: the reviewer only runs once code compiles, spending its tokens on what tsc can't check instead of arguing with the compiler.
- The pipeline's compile failure was a gate bug the benchmark exposed: pure TS was parsed as
.tsx, where generics are ambiguous with JSX. Fixed.
Round 2, after both fixes (partial — free-tier daily quotas ran out mid-run):
| Task | One-shot | tsc-retry (no reviewer) | Full pipeline | | --- | --- | --- | --- | | debounce | ✅ | ❌ tests | ✅ | | TypedEventEmitter | ❌ compile | ✅ | ✅ | | total | 1/2 · 2.5k tok | 1/2 · 2.4k tok | 2/2 · 14.4k tok |
The debounce row is the reviewer earning its seat: the worker emitted a React hook that compiles cleanly but crashes at runtime ("Invalid hook call"). tsc-retry shipped it; the reviewer caught it and forced a regeneration that passed. Gate-first also cut that pipeline run from 8.8k to 4.1k tokens.
Honest verdict: compiler feedback alone gets you cheap mechanical correctness; the reviewer is a semantic safety net for defects that typecheck — at a real token premium, now paid only on compiling code. Sample sizes are small and free-tier model quality varies run to run; reproduce with node test/benchmark.js and read the tables skeptically.
Commands & flags
| Command | Description |
| --------------------- | ------------------------ |
| trinomen "<prompt>" | Run the pipeline |
| trinomen init | Configure API keys |
| trinomen status | Show last-24h usage |
| trinomen reset | Clear usage history |
| Flag | Description |
| ---------------------- | ------------------------------------------------- |
| --loop | Refinement loop: typecheck + review until clean |
| --max-iterations <n> | Loop iteration cap (default 3) |
| --no-review | Skip the reviewer stage |
| -i, --intent <type> | Bypass the router: question\|code\|review\|explain |
| -v, --verbose | Show which provider/model handled each stage |
Library usage
The agents are importable directly:
import { route, work, review } from 'trinomen';
const { decision } = await route('write a binary search in TS');
const { text } = await work(decision.intent, 'write a binary search in TS');
const { review: verdict } = await review('write a binary search in TS', text);Development
git clone https://github.com/vukkt/trinomen.git
cd trinomen && npm install
npm test # offline unit tests + live router eval (eval skips without keys)
npm run test:unit # offline tests only (what CI runs)
node bin/cli.js "hello"Stack: Node ≥ 20, ESM, Vercel AI SDK v6 with zod-validated structured outputs, better-sqlite3 for budget persistence, commander + ora + chalk for the CLI.
License
MIT © Vuk Topalovic
