{"slug": "show-hn-router-picks-cursor-claude-codex-and-effort-per-task-then-launches-it", "title": "Show HN: Router picks Cursor/Claude/Codex and effort per task, then launches it", "summary": "A developer released router, a pre-release command-line tool that selects an AI coding agent, model, and reasoning effort for a task and launches it inside a Herdr pane, supporting Cursor, Claude Code, Codex, and OpenCode. The tool applies deterministic eligibility rules first — enabled models, quota, and a 40% reserve floor on shared accounts — then calls the TypeSafe API to rank remaining options and choose an effort level, with no fallback if TypeSafe is unavailable. Router requires Node.js 20 or newer, a TypeSafe API key, at least one logged-in agent CLI, and Herdr, and keeps configuration, usage snapshots, decisions, and session history local unless an explicitly configured integration needs them.", "body_md": "Local-first, quota-aware routing for AI coding agents in Herdr.\n\n`router` is a command-line tool that picks an AI coding agent, model, and reasoning effort\nfor a task, then starts that agent for you in a Herdr pane.\n\n```\nrouter run \"implement the approved plan in docs/plans/billing.md\"\n```\n\nIt filters your subscriptions with fixed rules (enabled models, quota, the 40% reserve on shared accounts), asks TypeSafe to rank what is left and choose an effort, starts the chosen agent (Cursor, Claude Code, Codex, or OpenCode), and hands it the task.\n\n**Pre-release:** the project is under active development. Review the security and privacy\nnotes below before using real credentials or shared accounts.\n\n- **Quota-aware:** routes around depleted or reserved subscription capacity.\n- **Policy-first:** deterministic eligibility rules run before semantic ranking.\n- **Local-first:** configuration, usage snapshots, decisions, and session history stay on\nyour machine unless an explicitly configured integration needs them.\n- **Agent-agnostic:** supports Cursor, Claude Code, Codex, and OpenCode through one command.\n\n- **Node.js 20 or newer** (`nvm use` reads`.nvmrc` ).\n- **A TypeSafe API key.** Routing always calls TypeSafe; there is no fallback. Each run sends\nthe task text to TypeSafe. Recognizable credentials are rejected locally before the call;\ndo not place other sensitive narrative data in routing tasks.\n- **At least one agent CLI you are logged in to:**`agent` (Cursor),`claude` (Claude Code),`codex` , or`opencode` . The router uses those logins; no provider API keys are needed.\n- **Herdr** , to launch agents.`router run` without`--dry-run` only launches from inside a\nHerdr pane (`HERDR_ENV=1` ).\n\n```\ngit clone https://github.com/nidhi-singh02/agent-router.git\ncd model-router\nnpm install\nnpm run build\nnpm link -w @model-router/router\n```\n\nOr add an alias to `~/.zshrc`:\n\n```\nalias router=\"node $HOME/Code/model-router/packages/router/dist/cli.js\"\n```\n\nAfter `git pull`, run `npm run build` again.\n\nThe config lives in `.model-router/` inside the repo (gitignored). Point the router at it\nfrom `~/.zshrc`, then `source ~/.zshrc`:\n\n```\nexport MODEL_ROUTER_HOME=\"$HOME/Code/model-router/.model-router\"\nmkdir -p .model-router\ncp config.example.json .model-router/config.json\n```\n\nWithout `MODEL_ROUTER_HOME`, the router uses `~/Library/Application Support/model-router`\non macOS (`~/.config/model-router` elsewhere).\n\n```\nsecurity add-generic-password -a \"$USER\" -s model-router-typesafe -w\n```\n\nThe command prompts for the key, so it never lands in shell history. The config refers to\nit with `\"typesafe\": { \"apiKeyRef\": \"keychain:model-router-typesafe\" }`. Every pane and agent\nthen finds the key without exporting anything, and it stays out of agents' environments. To\nreplace the key, add `-U`. If macOS asks to allow `security` access the first time, choose\n\"Always Allow\". `TYPESAFE_API_KEY` in the environment still works as a fallback.\n\nThere is no `router accounts add` command. Edit the `accounts` array in\n`.model-router/config.json` (hidden folder; for example `code .model-router/config.json`) with\none entry per agent login:\n\n```\n{\n  \"id\": \"acct_personal_claude\",\n  \"label\": \"personal claude\",\n  \"provider\": \"anthropic\",\n  \"agent\": \"claude-code\",\n  \"ownership\": \"personal\",\n  \"collectorPreference\": [\"local-session\"],\n  \"enabledModels\": [\"anthropic:claude-sonnet\", \"anthropic:claude-opus\"],\n  \"enabled\": true\n}\n```\n\n| Field | Values | \n|---|---|\n| `agent` | `cursor` ,`claude-code` ,`codex` ,`opencode` | \n| `provider` | Matches the models: `cursor` ,`anthropic` ,`openai` | \n| `ownership` | `personal` , or`shared` for a subscription other people also use (see below) | \n| `reserveFloor` | Optional, 0 to 1. Shared accounts default to `0.40` and cannot go lower | \n| `collectorPreference` | Where usage comes from: `local-session` ,`official-cli` ,`official-api` ,`browser-dashboard` | \n| `enabledModels` | Model IDs from the table below | \n| `enabled` | `true` or`false` | \n| `credentialRef` | Optional `env:NAME` or`keychain:NAME` . Never put secret values in the file | \n\nRun `router accounts` to check that the file parses. `docs/configuration.md` has the full\nschema.\n\nThe skill lets an agent route the next phase of your work (see\n[Phases](#phases-planning-then-implementation)). Link the repo copy so updates arrive with\n`git pull`:\n\n```\nln -s \"$PWD/skills/model-router\" ~/.claude/skills/model-router\nln -s \"$PWD/skills/model-router\" ~/.codex/skills/model-router\nln -s \"$PWD/skills/model-router\" ~/.cursor/skills/model-router\n```\n\nThe links follow whatever branch is checked out in this repo.\n\nDefined in `packages/router/config/models.json`. Add an ID to an account's `enabledModels` to\nuse it.\n\n| Model ID | Agent | Starts as | Efforts | Quota pool | \n|---|---|---|---|---|\n| `cursor:grok-4.6` | Cursor | `agent --model cursor-grok-4.6-<effort>` | low, medium, high | spend | \n| `cursor:grok-4.5` | Cursor | `agent --model cursor-grok-4.5-high` | high | spend | \n| `cursor:composer-2.5` | Cursor | `agent --model composer-2.5` | none | auto | \n| `anthropic:claude-sonnet` | Claude Code | `claude --model sonnet --effort <effort>` | low, medium, high |  | \n| `anthropic:claude-opus` | Claude Code | `claude --model opus --effort <effort>` | low, medium, high |  | \n| `openai:gpt-6-astra` | Codex | `codex --model gpt-6-astra -c model_reasoning_effort=\"<effort>\"` | low, medium, high, ultra |  | \n| `openai:gpt-5.6-sol` | Codex | `codex --model gpt-5.6-sol …` | low, medium, high, ultra |  | \n| `openai:gpt-5.6-terra` | Codex | `codex --model gpt-5.6-terra …` | low, medium, high, ultra |  | \n| `openai:gpt-5.6-luna` | Codex | `codex --model gpt-5.6-luna …` | low, medium, high |  | \n| `openai:gpt-5.5` | Codex | `codex --model gpt-5.5 …` | low, medium, high |  | \n| `openai:opencode` | OpenCode | `opencode --model openai` | low, medium, high |  | \n\nTypeSafe picks the effort from the model's list. `ultra` is only offered when your task text\ncontains the word \"ultra\". Capability, cost, and latency numbers in `models.json` are\nestimates you can adjust.\n\n```\nrouter run \"<task>\" --dry-run    # see which agent, model, and effort would be used\nrouter run \"<task>\"              # start that agent in a new Herdr pane and send the task\nrouter status                    # list accounts; add --usage to show quota\nrouter session                   # the latest launch; router session --list for more\n```\n\n`--dry-run` prints the decision card and the command it would start, without opening a pane\nor sending anything. A real run splits a new pane next to the current one, starts the agent,\nwaits for it to finish starting up, sends the task, and confirms the agent began working. You\ncan run the router any number of times, in the same tab or different ones; each launch gets\nits own agent name such as `router-codex-3c356c`.\n\n```\nSelected: cursor / composer-2.5 / none\nPhase: implementation\nWhy: TypeSafe selected acct_personal_cursor:cursor:composer-2.5 for implementation in phase implementation\nReserve policy: personal account\nCache decision: no previous session\nUsage source: estimated local-session\nQuota: auto 70% left (spend 45% left)\nFreshness: refreshed at 2026-09-17T12:00:00.000Z\n```\n\nThe router routes **one phase per task** (planning, implementation, debugging, review,\nresearch, and so on). It does not answer your question itself; the launched agent does.\n\n| Code | Meaning | \n|---|---|\n| 0 | Route selected (and launched, unless `--dry-run` ) | \n| 1 | Launch failed; the reason is printed and recorded in the session | \n| 2 | No route: no eligible model, TypeSafe unavailable, or session not found | \n| 3 | Low confidence on a consequential task; choose one of the two routes | \n\nUsage checks on `router run` are **local-session by default**: the router reads status-line\ncache files (milliseconds) and persists non-unknown snapshots to SQLite. Official CLI/API\nand browser collectors stay behind `--usage` (slower, and some live commands may consume\nquota). Personal accounts stay eligible when quota is missing, stale, or at 0%. Shared\naccounts still need *known* usage above the reserve.\n\n`router status` without `--usage` still lists accounts only. `router status --usage` runs\nthe full collector chain.\n\nQuota on the card is informational. For a personal account, a model at 0% remaining is\nstill eligible. Shared accounts still exclude `quota-exhausted` and `unknown-usage`.\n\nThe Cursor, Claude Code, and Codex CLIs do not report plan usage on the command line. The\nrouter reads quota from cache files that **your own status line scripts** write; the router\ndoes not install those scripts. Enable it with `\"local-session\"` in the account's\n`collectorPreference`. Cache data older than 15 minutes counts as unknown, and a cache only\nrefreshes while a session of that tool is open and redrawing its status line.\n\n**Cursor:** `~/.cursor/statusline-quota-cache.json`\n\n```\n{ \"pct\": 45, \"auto_left\": 70, \"at\": 1700000000 }\n```\n\n`pct` is the percent of included spend left (Grok models), `auto_left` the percent of the Auto\npool left (Composer), and `at` the Unix time in seconds.\n\n**Claude Code:** `~/.claude/statusline-quota-cache.json`, written from the `rate_limits`\nClaude Code passes to its status line:\n\n```\n{\n  \"at\": 1700000000,\n  \"five_hour\": { \"used_percentage\": 20, \"resets_at\": 1700013600 },\n  \"seven_day\": { \"used_percentage\": 10, \"resets_at\": 1700604800 }\n}\n```\n\nEither window may be missing, and a window whose reset time has passed counts as fully available.\n\n**Codex:** `~/.codex/statusline-quota-cache.json`\n\n```\n{ \"weekly_left\": 40, \"at\": 1700000000 }\n```\n\n`weekly_left` is the percent of weekly quota remaining (0–100), and `at` is Unix time in\nseconds. The router does not write this file.\n\n**OpenCode:** harness-only; quota belongs to the underlying provider.\n\n- **Personal:** stays eligible even if quota is missing, stale, or at 0%. The card may still\nshow remaining quota when a cache exists.\n- **Shared:** needs known usage (a fresh local-session cache, or`--usage` ) and keeps 40% of\nits quota in reserve. It is excluded when the coordinator reports someone else using it.\nWithout a coordinator (the usual local setup), it routes on its quota alone.\n\nEach `router run` records a session in `.model-router/state.sqlite`. A launched agent's task\nends with `Router session: <id>` and instructions for when its phase is done. With the skill\ninstalled, the flow is:\n\nThe router repairs the state directory to `0700` and SQLite-related files to `0600` whenever\nit opens the database. Treat the task and handoff history as sensitive local data.\n\n1. `router run \"plan feature X\"` starts, for example, Grok for planning.\n2. The agent writes the plan to a file and asks you whether to route the next phase.\n3. When you agree, it runs `router session <id>` and`router run --session <id> \"implement the plan in docs/plans/x.md\" --dry-run` , shows you\nthe card, and launches without`--dry-run` after you confirm.\n4. The new session records the previous one. The card shows\n`Previous session: <id> (planning -> implementation)` , and the new agent gets the previous\nphase and task.\n\nThe next agent starts in a new pane without the earlier conversation, so the task must point to the file. You can run the same commands yourself:\n\n```\nrouter session <id>\nrouter run --session <id> \"implement the plan in docs/plans/x.md\"\nrouter run \"<task>\" [--dry-run] [--usage] [--session <id>] [--json]\nrouter status [--usage]\nrouter session [id] [--list] [--limit <n>] [--json]\nrouter accounts\nrouter usage refresh [--source local-session|official-cli|browser] [--dry-run]\n```\n\n`--json` prints machine-readable output for plugins, including `sessionId`, `agentName`, and\n`paneId`. `router usage refresh` defaults to local-session file reads; `--dry-run` prints\nfacts and does not persist. Without `--dry-run` it writes snapshots to SQLite.\n\nAgent Router also ships as a Herdr plugin, so routing, status, sessions, and usage refresh are reachable from Herdr actions and keybindings instead of a shell prompt:\n\n```\nherdr plugin install nidhi-singh02/agent-router\nherdr plugin action list --plugin nidhi-singh02.agent-router\n```\n\nThe manifest is `herdr-plugin.toml` at the repository root; the scripts it runs live in\n`herdr-plugin/`. See [` herdr-plugin/README.md`](https://github.com/nidhi-singh02/agent-router/blob/main/herdr-plugin/README.md) for the action list,\nkeybinding examples, and local development with `herdr plugin link`.\n\n| Message | What to do | \n|---|---|\n| `TypeSafe could not select a route (typesafe-unavailable). No TypeSafe API key found …` | Store the key (setup step 4) | \n| `No eligible route. Exclusions: [...]` | Read each `reason` below | \n| `quota-exhausted` | That model's quota pool is at 0%; if unexpected, refresh the status-line cache or pass `--usage` | \n| `shared-activity-constrained` | Shared account without known usage (missing/stale cache, or coordinator busy) | \n| `below-reserve` | Shared account would drop below its 40% reserve | \n| `stale-usage` ,`unknown-usage` | Usage data too old or missing; open a session of that tool to refresh its cache | \n| `model-not-enabled` ,`account-disabled` | Check `enabledModels` and`enabled` in the config | \n| `HERDR_ENV=1 is required to launch a pane` | Run from a Herdr pane, or add `--dry-run` | \n| `herdr agent start failed: <code>: <message>` | Herdr's own error; the router closes the pane it created | \n| `handoff not received by agent <name> in pane <id> …` | The agent is open but never started the task; paste the task there or run again | \n| `agent is blocked; not resending the handoff` | The agent is waiting on a question or approval in its pane | \n| `Session not found: <id>` | Check the id with `router session --list` | \n| `zsh: command not found: router` | Setup step 2, then open a new shell | \n\n```\nnpm run verify   # typecheck, lint, format check, tests, build\nnpm test         # tests only\n```\n\nDo not deploy the Cloudflare coordinator (`packages/coordinator`) or write into an external\nHermes checkout (`packages/hermes-heartbeat`) without explicit approval. See `docs/` for\nconfiguration, operations, privacy, and provider support.\n\n- Never commit `.model-router/` ,`.env` , API keys, bearer tokens, cookies, or provider cache\nfiles. The repository ignores the local state directories and environment files by default.\n- Store the TypeSafe key in the macOS Keychain as shown above. Environment variables are a supported fallback, but are easier to expose accidentally through child processes or logs.\n- Task text is sent to TypeSafe for classification and ranking. Do not route secrets, credentials, private client data, or other sensitive text.\n- `router run` starts local agent processes with the permissions of your current user. Review\nthe selected route and task before launching it.\n- The optional coordinator and heartbeat packages are not required for ordinary personal accounts. Treat them as pre-release components and review their deployment configuration before exposing them to a network.\n\nSee [Privacy](https://github.com/nidhi-singh02/agent-router/blob/main/docs/privacy.md), [Operations](https://github.com/nidhi-singh02/agent-router/blob/main/docs/operations.md), and\n[Configuration](https://github.com/nidhi-singh02/agent-router/blob/main/docs/configuration.md) for the detailed data flow and deployment guidance.\n\nIssues and focused pull requests are welcome. Before opening a pull request, run:\n\n```\nnpm run verify\n```\n\nPlease do not include credentials, private account data, local quota caches, generated state, or provider dashboard exports in issues, tests, or commits.\n\nAgent Router is available under the [MIT License](https://github.com/nidhi-singh02/agent-router/blob/main/LICENSE).", "url": "https://wpnews.pro/news/show-hn-router-picks-cursor-claude-codex-and-effort-per-task-then-launches-it", "canonical_source": "https://github.com/nidhi-singh02/agent-router", "published_at": "2026-09-17 18:13:55+00:00", "updated_at": "2026-09-17 18:25:50.300551+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "ai-products"], "entities": ["router", "Herdr", "TypeSafe", "Cursor", "Claude Code", "Codex", "OpenCode", "Node.js"], "alternates": {"html": "https://wpnews.pro/news/show-hn-router-picks-cursor-claude-codex-and-effort-per-task-then-launches-it", "markdown": "https://wpnews.pro/news/show-hn-router-picks-cursor-claude-codex-and-effort-per-task-then-launches-it.md", "text": "https://wpnews.pro/news/show-hn-router-picks-cursor-claude-codex-and-effort-per-task-then-launches-it.txt", "jsonld": "https://wpnews.pro/news/show-hn-router-picks-cursor-claude-codex-and-effort-per-task-then-launches-it.jsonld"}}