@mrrlin-dev/external-agents 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 mrrlin-dev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,237 @@
1
+ # @mrrlin-dev/external-agents
2
+
3
+ **One MCP server for every LLM you talk to.**
4
+
5
+ `external-agents` is a small, opinionated MCP server + CLI that lets your primary coding agent (Claude Code, Codex, Cursor) route work to a pool of secondary LLMs — Gemini, DeepSeek, Grok, OpenRouter, local Ollama, and any CLI-agentic reviewer (cursor-agent, opencode) — through one clean surface, with per-provider auth, cooldowns, round-robin, escalation, and a local statistics dashboard.
6
+
7
+ > **Part of [mrrlin.com](https://mrrlin.com)** — the AI orchestration platform for developers. `external-agents` is the open-source layer we use internally to power multi-model consensus and cost-efficient atomic execution. Ships MIT so anyone can adopt it standalone.
8
+
9
+ ---
10
+
11
+ ## Why this exists
12
+
13
+ If you use more than one LLM in your workflow (and by now most people do), you've probably done at least one of these:
14
+
15
+ - Hand-rolled a shell script that alternates DeepSeek and Gemini for cheap tasks.
16
+ - Copy-pasted the same "review this diff" prompt into three CLIs to compare answers.
17
+ - Written a wrapper to detect a 429 and retry on a different provider.
18
+ - Kept a mental note of which providers are quota-exhausted today.
19
+
20
+ `external-agents` collapses all of that into **one tool with one config**:
21
+
22
+ - **Unified dispatch.** `dispatch(agent_id, prompt)` with default transport `generate_new` picks the next healthy provider by round-robin; N parallel `pick_agents` + `dispatch` calls (consumer-composed) fans out to N providers in parallel with cross-model diversity guaranteed.
23
+ - **State that heals itself.** Quota exhaustion is detected from live responses and rate-limit headers, cooldown lasts until the *provider's* reset time (not a made-up default), and healthy calls automatically clear stale cooldowns.
24
+ - **Auth surfaces you actually have.** Subscription CLI (Codex, Claude), env-var API keys via [`aider`](https://aider.chat) → direct-to-provider through LiteLLM (Gemini, DeepSeek, Grok, OpenRouter, and 100+ more), direct CLI (cursor-agent, opencode, ollama) — pick your credential path per entry, no forced OAuth, no gateway proxy.
25
+ - **Statistics that answer your questions.** How many dispatches went to Gemini this week? What did they cost? Which provider is failing the most? All in a local dashboard, no cloud required.
26
+
27
+ ---
28
+
29
+ ## Install
30
+
31
+ ```bash
32
+ npm install -g @mrrlin-dev/external-agents
33
+ external-agents --version
34
+ ```
35
+
36
+ Requires Node ≥ 20. Works on macOS and Linux. Windows via WSL.
37
+
38
+ ---
39
+
40
+ ## Two-minute quickstart
41
+
42
+ ```bash
43
+ # 1. See what's available (starts with zero-config defaults)
44
+ external-agents status
45
+
46
+ # 2. Wire an API-key provider (e.g. DeepSeek — sets DEEPSEEK_API_KEY for aider)
47
+ external-agents auth deepseek
48
+
49
+ # 3. Dispatch something (auto-pick + run)
50
+ id=$(external-agents pick -n 1)
51
+ external-agents dispatch "$id" "Summarize this in one line: <paste any text>"
52
+
53
+ # 4. See what just happened
54
+ external-agents stats
55
+ ```
56
+
57
+ Open the local dashboard with `external-agents ui` and you'll get a page like:
58
+
59
+ ![external-agents dashboard](docs/screenshot.png)
60
+
61
+ ---
62
+
63
+ ## Wire into your MCP client
64
+
65
+ Once installed, add one block to your MCP client config.
66
+
67
+ **Claude Code** (`~/.claude.json`):
68
+ ```json
69
+ {
70
+ "mcpServers": {
71
+ "external-agents": {
72
+ "command": "external-agents",
73
+ "args": ["mcp", "serve"]
74
+ }
75
+ }
76
+ }
77
+ ```
78
+
79
+ **Codex Code** (`~/.codex/config.toml`):
80
+ ```toml
81
+ [mcp_servers.external-agents]
82
+ command = "external-agents"
83
+ args = ["mcp", "serve"]
84
+ ```
85
+
86
+ **Cursor** — Settings → MCP → Add server → same command.
87
+
88
+ Your primary agent now has these low-level tools (build your own exec/review flows on top):
89
+
90
+ | Tool | What it does |
91
+ | --- | --- |
92
+ | `pick_agents` | Pick N distinct healthy candidates (round-robin, cooldown-aware). Optional `min_distinct_providers` for diverse fan-out. |
93
+ | `dispatch` | Run a specific agent with a prompt. `escalate_to_pro: true` retries on the same provider's strong tier. |
94
+ | `probe_agent` | Health-check one provider (cheap prompt). |
95
+ | `list_agents` | Registry with live state. |
96
+ | `get_state` | Full state file — for building your own dashboard. |
97
+ | `get_stats` | Aggregated dispatch metrics from local JSONL. |
98
+ | `set_credential` | Store a provider credential via the entry's auth surface. |
99
+
100
+ **Composition example** — build "review by a panel of 3 diverse providers" client-side:
101
+ ```
102
+ ids = pick_agents({ n: 3, min_distinct_providers: 3, exclude_ids: [primary] })
103
+ outs = Promise.all(ids.map(id => dispatch({ agent_id: id, prompt })))
104
+ ```
105
+ The package is deliberately unopinionated about *what* you compose. Mrrlin uses these primitives for its own `/consensus` gate and atomic-executor loop; your workflow probably has its own vocabulary — that's the whole point.
106
+
107
+ ---
108
+
109
+ ## Supported providers (v0.1.0)
110
+
111
+ ### Free tier — no card required to get started
112
+
113
+ Most of the pool runs on generous free tiers. **20 agents across 8 providers, 17 of which cost $0** when the request is on the provider's free plan (all get their own quota bucket, so round-robin dramatically extends what you can do without paying).
114
+
115
+ | Provider | Models | Free tier |
116
+ | --- | --- | --- |
117
+ | **Google Gemini** (via AI Studio) | 3.5-flash-lite, 3.1-flash-lite, 3.6-flash, 3.5-flash, 3-flash-preview, 3/3.1-pro-preview | ✅ generous per-model quotas |
118
+ | **Groq** ⚡ | llama-3.3-70b-versatile, deepseek-r1-distill-llama-70b | ✅ 30 rpm — fastest inference on the market (~500-800 tok/s) |
119
+ | **OpenRouter** 🌐 | 50+ models tagged `:free` (deepseek-r1, qwen-coder-32b, llama-3.3-70b, ...) | ✅ 20 rpd free without card |
120
+ | **Cerebras** ⚡⚡ | llama3.3-70b, qwen-3-coder-480b | ✅ 30 rpm — ~2000 tok/s (fastest on the planet) |
121
+ | **Z.ai** (GLM) | glm-4.7-flash | ✅ free API tier |
122
+ | **Ollama Cloud** | gpt-oss:20b-cloud, gpt-oss:120b-cloud | ✅ free with Ollama account |
123
+
124
+ ### Paid tier / per-token
125
+
126
+ | Provider | Models | Notes |
127
+ | --- | --- | --- |
128
+ | **DeepSeek** (direct API) | deepseek-chat (Flash), deepseek-reasoner | Very cheap per-token; not on free tier but often <$1/day for atomic-task workloads |
129
+ | **Codex** (subscription) | gpt-5.2-codex (primary orchestrator) | Uses your Codex Code subscription; not an API key |
130
+
131
+ ### Direct-CLI agentic (repo-aware reviewers)
132
+
133
+ - cursor-agent, opencode, Ollama (local, no quota)
134
+
135
+ Missing a provider? Adding one is a ~15-line YAML addition — see [docs/adding-a-provider.md](docs/adding-a-provider.md). aider (our downstream) supports 100+ providers via LiteLLM.
136
+
137
+ ---
138
+
139
+ ## Config reference
140
+
141
+ Registry file at `~/.config/external-agents/agents.yaml`:
142
+
143
+ ```yaml
144
+ runtime:
145
+ primary_agent: codex # ignored when there's no orchestrator concept
146
+ review_diversity:
147
+ min_distinct_providers: 3
148
+ max_rounds_default: 3
149
+
150
+ telemetry_sink: # optional: pipe events to your own endpoint
151
+ url: https://your-backend.example/telemetry
152
+ headers:
153
+ Authorization: "Bearer {ENV_TOKEN}"
154
+ batch_size: 50
155
+
156
+ agents:
157
+ aider-gemini-flash:
158
+ provider: google
159
+ model: gemini-3-flash-preview
160
+ tier: weak
161
+ auth: "env:GEMINI_API_KEY"
162
+ transports:
163
+ generate_new:
164
+ url: "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions"
165
+ env: GEMINI_API_KEY
166
+ model: gemini-3-flash-preview
167
+ edit_exists: "aider --model gemini/gemini-3-flash-preview"
168
+ # ... more entries
169
+ ```
170
+
171
+ Full schema documented in [docs/registry-schema.md](docs/registry-schema.md).
172
+
173
+ ---
174
+
175
+ ## Local UI
176
+
177
+ Run `external-agents ui` and a page opens on `http://127.0.0.1:port`. Loopback only — never exposed to the network. Shows:
178
+
179
+ **💰 "Unlock more free voices" banner at the top** — as long as you have any free-tier provider that hasn't been wired up yet (no env var set), the UI shows a golden banner urging you to sign up. One row per provider with: what it gives you ("Groq: ~500-800 tok/s — fastest on the market"), the exact env var name to set, and a green "Get free key ↗" link to the signup page. **Signup is usually 60 seconds and doesn't ask for a card.** Once you add the key and restart your MCP client, that provider drops from the banner and joins the pool.
180
+
181
+
182
+ - Every registry entry with a live status badge
183
+ - **Per-row Usage link** — for each provider that publishes one (Gemini / DeepSeek / OpenAI / Z.ai / Ollama Cloud / ...), a small `↗ usage` link opens the provider's own dashboard so you never have to guess where your billing lives
184
+ - Install / auth / verify buttons per state
185
+ - **"Missing your model?" panel** — a two-input form (model name + optional docs URL) at the bottom of the table. Submit records your suggestion locally (JSONL). If you're running inside mrrlin, the same submit is intercepted and filed as an actionable task in your inbox
186
+ - Statistics tab: dispatches, costs, success rate, per-agent timing
187
+ - Config editor with schema validation
188
+
189
+ Everything the UI does is also available in the CLI — the UI is a convenience, not a requirement.
190
+
191
+ ---
192
+
193
+ ## FAQ
194
+
195
+ **Do you send my API keys anywhere?**
196
+ No. API-key credentials live in env vars only (read by aider at spawn time). Subscription tokens live where the subscription CLI keeps them (`codex login`, `claude login`, ...). `external-agents` never persists or transmits your credentials.
197
+
198
+ **Do you phone home?**
199
+ Not by default. Telemetry writes to a local JSONL file. If you configure `telemetry_sink` in your registry, events go to *your* endpoint — no default sink.
200
+
201
+ **Is Mrrlin required?**
202
+ No. `external-agents` is standalone. Mrrlin uses it internally, but the package works for anyone building a multi-model workflow.
203
+
204
+ **Can I use this with just a subscription (no API keys)?**
205
+ Yes — Codex subscription with `--model` overrides gives you access to cheaper models on the same plan. Same story with Claude when v0.2 lands. Zero API-key setup for those cases.
206
+
207
+ **How do you avoid rate-limit surprises?**
208
+ Every real call updates state from response headers and error signals. Cooldown honors the provider's own reset time (parsed from `x-ratelimit-reset-*`, `Retry-After`, and error bodies). If Google says "resets in 42h", we wait 42h — not a 1h default.
209
+
210
+ **Why `aider` for API-key providers?**
211
+ [aider](https://aider.chat) is a mature (4-year) agentic CLI that talks to 100+ providers directly through [LiteLLM](https://litellm.ai) — no gateway proxy. Every provider is just an env var (`GEMINI_API_KEY`, `DEEPSEEK_API_KEY`, `ANTHROPIC_API_KEY`, ...) and a `--model {provider}/{id}` flag. We layer state / round-robin / cooldown on top instead of writing our own provider client for every LLM ourselves.
212
+
213
+ ---
214
+
215
+ ## Contributing
216
+
217
+ Contributions welcome. See [CONTRIBUTING.md](CONTRIBUTING.md).
218
+
219
+ We use MIT + DCO (sign-off in commits), no CLA. Bug reports and provider additions are especially appreciated.
220
+
221
+ ---
222
+
223
+ ## License
224
+
225
+ MIT. See [LICENSE](LICENSE).
226
+
227
+ ---
228
+
229
+ ## About Mrrlin
230
+
231
+ `external-agents` is one piece of [**Mrrlin**](https://mrrlin.com) — an AI orchestration platform for solo developers and small teams. Mrrlin uses this package internally to power its multi-model consensus gate and cost-efficient atomic executor, and layers on top of it a Director agent that decides what work to route where.
232
+
233
+ If you like `external-agents`, you'll probably like the rest of Mrrlin.
234
+
235
+ ---
236
+
237
+
package/agents.yaml ADDED
@@ -0,0 +1,357 @@
1
+ # External-agents registry v1 (see ADR 0021 in mrrlin repo).
2
+ #
3
+ # ONE entry per (provider, model). An entry may declare BOTH transports —
4
+ # named after WHAT they do reliably (action-oriented):
5
+ # transports.generate_new — native fetch → OpenAI-compat /chat/completions.
6
+ # Dispatcher writes the response content to workdir/generated.md. Ideal
7
+ # for "produce the contents of this file from spec". Preferred by default.
8
+ # transports.edit_exists — spawns aider (or another agentic CLI). Used when
9
+ # the caller explicitly requests transport="edit_exists" (iterative edits,
10
+ # multi-file, tool use — aider's core strength).
11
+ # When both are present, `runAny` picks `generate_new` unless overridden.
12
+ #
13
+ # Auth surfaces (2, merged from previous 3):
14
+ # env:VAR — external-agents reads the value from process.env.VAR
15
+ # cli:tool — the named CLI owns its own credential store (subscription
16
+ # token, cookie, OAuth session; whatever `<tool> login` writes)
17
+ #
18
+ # Tags are opaque strings. UI styles `free` as a green $0 badge.
19
+ # Env overrides live under `env:` (values may be "@file:~/path" refs).
20
+ schema_version: 1
21
+ agents:
22
+
23
+ # ============ Google Gemini (AI Studio) ============
24
+ - id: gemini-3.5-flash-lite
25
+ provider: google
26
+ model: gemini-3.5-flash-lite
27
+ quota_scope: per_model
28
+ tier: weak
29
+ tags: [quick, cheap, free]
30
+ auth: "env:GEMINI_API_KEY"
31
+ preference_order: 5
32
+ usage_url: "https://aistudio.google.com/usage"
33
+ transports:
34
+ generate_new:
35
+ url: "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions"
36
+ env: GEMINI_API_KEY
37
+ model: gemini-3.5-flash-lite
38
+ edit_exists: "aider --model gemini/gemini-3.5-flash-lite"
39
+
40
+ - id: gemini-3.1-flash-lite
41
+ provider: google
42
+ model: gemini-3.1-flash-lite
43
+ quota_scope: per_model
44
+ tier: weak
45
+ tags: [quick, cheap, free]
46
+ auth: "env:GEMINI_API_KEY"
47
+ preference_order: 5
48
+ usage_url: "https://aistudio.google.com/usage"
49
+ transports:
50
+ generate_new:
51
+ url: "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions"
52
+ env: GEMINI_API_KEY
53
+ model: gemini-3.1-flash-lite
54
+ edit_exists: "aider --model gemini/gemini-3.1-flash-lite"
55
+
56
+ - id: gemini-3.6-flash
57
+ provider: google
58
+ model: gemini-3.6-flash
59
+ quota_scope: per_model
60
+ tier: weak
61
+ tags: [quick, free]
62
+ auth: "env:GEMINI_API_KEY"
63
+ preference_order: 10
64
+ usage_url: "https://aistudio.google.com/usage"
65
+ transports:
66
+ generate_new:
67
+ url: "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions"
68
+ env: GEMINI_API_KEY
69
+ model: gemini-3.6-flash
70
+ edit_exists: "aider --model gemini/gemini-3.6-flash"
71
+
72
+ - id: gemini-3.5-flash
73
+ provider: google
74
+ model: gemini-3.5-flash
75
+ quota_scope: per_model
76
+ tier: weak
77
+ tags: [quick, free]
78
+ auth: "env:GEMINI_API_KEY"
79
+ preference_order: 10
80
+ usage_url: "https://aistudio.google.com/usage"
81
+ transports:
82
+ generate_new:
83
+ url: "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions"
84
+ env: GEMINI_API_KEY
85
+ model: gemini-3.5-flash
86
+ edit_exists: "aider --model gemini/gemini-3.5-flash"
87
+
88
+ - id: gemini-3-flash-preview
89
+ provider: google
90
+ model: gemini-3-flash-preview
91
+ quota_scope: per_model
92
+ tier: weak
93
+ tags: [quick, free]
94
+ auth: "env:GEMINI_API_KEY"
95
+ preference_order: 10
96
+ usage_url: "https://aistudio.google.com/usage"
97
+ transports:
98
+ generate_new:
99
+ url: "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions"
100
+ env: GEMINI_API_KEY
101
+ model: gemini-3-flash-preview
102
+ edit_exists: "aider --model gemini/gemini-3-flash-preview"
103
+
104
+ - id: gemini-3-pro-preview
105
+ provider: google
106
+ model: gemini-3-pro-preview
107
+ quota_scope: per_model
108
+ tier: strong
109
+ tags: [quick, free]
110
+ auth: "env:GEMINI_API_KEY"
111
+ usage_url: "https://aistudio.google.com/usage"
112
+ transports:
113
+ generate_new:
114
+ url: "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions"
115
+ env: GEMINI_API_KEY
116
+ model: gemini-3-pro-preview
117
+ edit_exists: "aider --model gemini/gemini-3-pro-preview"
118
+
119
+ - id: gemini-3.1-pro-preview
120
+ provider: google
121
+ model: gemini-3.1-pro-preview
122
+ quota_scope: per_model
123
+ tier: strong
124
+ tags: [quick, free]
125
+ auth: "env:GEMINI_API_KEY"
126
+ usage_url: "https://aistudio.google.com/usage"
127
+ transports:
128
+ generate_new:
129
+ url: "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions"
130
+ env: GEMINI_API_KEY
131
+ model: gemini-3.1-pro-preview
132
+ edit_exists: "aider --model gemini/gemini-3.1-pro-preview"
133
+
134
+ # ============ DeepSeek ============
135
+ - id: deepseek-chat
136
+ provider: deepseek
137
+ model: deepseek-chat
138
+ quota_scope: shared
139
+ tier: weak
140
+ tags: [quick]
141
+ auth: "env:DEEPSEEK_API_KEY"
142
+ preference_order: 10
143
+ usage_url: "https://platform.deepseek.com/usage"
144
+ transports:
145
+ generate_new:
146
+ url: "https://api.deepseek.com/v1/chat/completions"
147
+ env: DEEPSEEK_API_KEY
148
+ model: deepseek-chat
149
+ edit_exists: "aider --model deepseek/deepseek-chat"
150
+
151
+ - id: deepseek-reasoner
152
+ provider: deepseek
153
+ model: deepseek-reasoner
154
+ quota_scope: shared
155
+ tier: strong
156
+ tags: [quick, reasoning]
157
+ auth: "env:DEEPSEEK_API_KEY"
158
+ usage_url: "https://platform.deepseek.com/usage"
159
+ transports:
160
+ generate_new:
161
+ url: "https://api.deepseek.com/v1/chat/completions"
162
+ env: DEEPSEEK_API_KEY
163
+ model: deepseek-reasoner
164
+ edit_exists: "aider --model deepseek/deepseek-reasoner"
165
+
166
+ # ============ Z.ai (GLM) — OpenAI-compat with per-entry env override ============
167
+ - id: glm-4.7-flash
168
+ provider: zai
169
+ model: glm-4.7-flash
170
+ quota_scope: shared
171
+ tier: weak
172
+ tags: [quick, free]
173
+ auth: "env:ZAI_API_KEY (or ~/.claude/state/zai.key)"
174
+ preference_order: 15
175
+ usage_url: "https://z.ai/manage-apikey/apikey-list"
176
+ transports:
177
+ generate_new:
178
+ url: "https://api.z.ai/api/paas/v4/chat/completions"
179
+ env: OPENAI_API_KEY # per-entry override below routes the AIza… key here
180
+ model: glm-4.7-flash
181
+ edit_exists: "aider --model openai/glm-4.7-flash --openai-api-base https://api.z.ai/api/paas/v4"
182
+ env:
183
+ OPENAI_API_KEY: "@file:~/.claude/state/zai.key"
184
+
185
+ # ============ Groq — free tier, ~500-800 tok/s ============
186
+ - id: groq-llama-3.3-70b
187
+ provider: groq
188
+ model: llama-3.3-70b-versatile
189
+ quota_scope: shared
190
+ tier: weak
191
+ tags: [quick, fast, free]
192
+ auth: "env:GROQ_API_KEY"
193
+ preference_order: 8
194
+ usage_url: "https://console.groq.com/settings/usage"
195
+ transports:
196
+ generate_new:
197
+ url: "https://api.groq.com/openai/v1/chat/completions"
198
+ env: GROQ_API_KEY
199
+ model: llama-3.3-70b-versatile
200
+ edit_exists: "aider --model groq/llama-3.3-70b-versatile"
201
+
202
+ - id: groq-deepseek-r1-distill
203
+ provider: groq
204
+ model: deepseek-r1-distill-llama-70b
205
+ quota_scope: shared
206
+ tier: strong
207
+ tags: [quick, reasoning, free]
208
+ auth: "env:GROQ_API_KEY"
209
+ usage_url: "https://console.groq.com/settings/usage"
210
+ transports:
211
+ generate_new:
212
+ url: "https://api.groq.com/openai/v1/chat/completions"
213
+ env: GROQ_API_KEY
214
+ model: deepseek-r1-distill-llama-70b
215
+ edit_exists: "aider --model groq/deepseek-r1-distill-llama-70b"
216
+
217
+ # ============ OpenRouter — 50+ free models with :free tag ============
218
+ - id: openrouter-deepseek-r1-free
219
+ provider: openrouter
220
+ model: deepseek/deepseek-r1-distill-llama-70b:free
221
+ quota_scope: shared
222
+ tier: strong
223
+ tags: [quick, reasoning, free]
224
+ auth: "env:OPENROUTER_API_KEY"
225
+ usage_url: "https://openrouter.ai/settings/credits"
226
+ transports:
227
+ generate_new:
228
+ url: "https://openrouter.ai/api/v1/chat/completions"
229
+ env: OPENROUTER_API_KEY
230
+ model: deepseek/deepseek-r1-distill-llama-70b:free
231
+ edit_exists: "aider --model openrouter/deepseek/deepseek-r1-distill-llama-70b:free"
232
+
233
+ - id: openrouter-qwen-coder-32b-free
234
+ provider: openrouter
235
+ model: qwen/qwen-2.5-coder-32b-instruct:free
236
+ quota_scope: shared
237
+ tier: weak
238
+ tags: [quick, coding, free]
239
+ auth: "env:OPENROUTER_API_KEY"
240
+ preference_order: 15
241
+ usage_url: "https://openrouter.ai/settings/credits"
242
+ transports:
243
+ generate_new:
244
+ url: "https://openrouter.ai/api/v1/chat/completions"
245
+ env: OPENROUTER_API_KEY
246
+ model: qwen/qwen-2.5-coder-32b-instruct:free
247
+ edit_exists: "aider --model openrouter/qwen/qwen-2.5-coder-32b-instruct:free"
248
+
249
+ - id: openrouter-llama-3.3-70b-free
250
+ provider: openrouter
251
+ model: meta-llama/llama-3.3-70b-instruct:free
252
+ quota_scope: shared
253
+ tier: weak
254
+ tags: [quick, free]
255
+ auth: "env:OPENROUTER_API_KEY"
256
+ preference_order: 15
257
+ usage_url: "https://openrouter.ai/settings/credits"
258
+ transports:
259
+ generate_new:
260
+ url: "https://openrouter.ai/api/v1/chat/completions"
261
+ env: OPENROUTER_API_KEY
262
+ model: meta-llama/llama-3.3-70b-instruct:free
263
+ edit_exists: "aider --model openrouter/meta-llama/llama-3.3-70b-instruct:free"
264
+
265
+ # ============ Cerebras — ~2000 tok/s, 30 rpm free ============
266
+ - id: cerebras-llama-3.3-70b
267
+ provider: cerebras
268
+ model: llama3.3-70b
269
+ quota_scope: shared
270
+ tier: weak
271
+ tags: [quick, fast, free]
272
+ auth: "env:CEREBRAS_API_KEY"
273
+ preference_order: 7
274
+ usage_url: "https://cloud.cerebras.ai/platform/keys"
275
+ transports:
276
+ generate_new:
277
+ url: "https://api.cerebras.ai/v1/chat/completions"
278
+ env: CEREBRAS_API_KEY
279
+ model: llama3.3-70b
280
+ edit_exists: "aider --model cerebras/llama3.3-70b"
281
+
282
+ - id: cerebras-qwen-3-coder-480b
283
+ provider: cerebras
284
+ model: qwen-3-coder-480b
285
+ quota_scope: shared
286
+ tier: strong
287
+ tags: [coding, free]
288
+ auth: "env:CEREBRAS_API_KEY"
289
+ usage_url: "https://cloud.cerebras.ai/platform/keys"
290
+ transports:
291
+ generate_new:
292
+ url: "https://api.cerebras.ai/v1/chat/completions"
293
+ env: CEREBRAS_API_KEY
294
+ model: qwen-3-coder-480b
295
+ edit_exists: "aider --model cerebras/qwen-3-coder-480b"
296
+
297
+ # ============ Ollama Cloud (via localhost daemon → cloud proxy) ============
298
+ - id: ollama-gpt-oss-20b
299
+ provider: ollama-cloud
300
+ model: gpt-oss:20b-cloud
301
+ quota_scope: shared
302
+ tier: weak
303
+ tags: [quick, free]
304
+ auth: "cli:ollama"
305
+ preference_order: 20
306
+ usage_url: "https://ollama.com/settings/keys"
307
+ transports:
308
+ generate_new:
309
+ url: "http://localhost:11434/v1/chat/completions"
310
+ env: OLLAMA_UNUSED_KEY # Ollama daemon needs no key; env var is dummy
311
+ model: gpt-oss:20b-cloud
312
+ edit_exists: "aider --model ollama/gpt-oss:20b-cloud"
313
+
314
+ - id: ollama-gpt-oss-120b
315
+ provider: ollama-cloud
316
+ model: gpt-oss:120b-cloud
317
+ quota_scope: shared
318
+ tier: strong
319
+ tags: [quick, free]
320
+ auth: "cli:ollama"
321
+ usage_url: "https://ollama.com/settings/keys"
322
+ transports:
323
+ generate_new:
324
+ url: "http://localhost:11434/v1/chat/completions"
325
+ env: OLLAMA_UNUSED_KEY
326
+ model: gpt-oss:120b-cloud
327
+ edit_exists: "aider --model ollama/gpt-oss:120b-cloud"
328
+
329
+ # ============ Direct-CLI agentic reviewers (no OpenAI-compat, cli-only) ============
330
+ - id: cursor-agent
331
+ provider: cursor
332
+ model: default
333
+ tier: strong
334
+ tags: [agentic]
335
+ auth: "cli:cursor-agent"
336
+ transports:
337
+ edit_exists: "cursor-agent -p --output-format text"
338
+
339
+ - id: opencode
340
+ provider: sst
341
+ model: default
342
+ tier: weak
343
+ tags: [agentic]
344
+ auth: "cli:opencode"
345
+ transports:
346
+ edit_exists: "opencode -p"
347
+
348
+ # ============ Primary orchestrator (subscription CLI) ============
349
+ - id: codex
350
+ provider: openai
351
+ model: gpt-5.2-codex
352
+ tier: strong
353
+ tags: []
354
+ auth: "cli:codex"
355
+ usage_url: "https://platform.openai.com/usage"
356
+ transports:
357
+ edit_exists: "codex exec"