@morphllm/morphrouter
v0.1.12
Published
Morph-powered Claude Code subscription router that switches Haiku, Sonnet, and Opus per user turn.
Readme
@morphllm/morphrouter
Morph-powered model routing for Claude Code.
You stay signed into Claude Code with your normal Claude account. This wrapper
runs the real Claude Code TUI, classifies each prompt with Morph
(difficulty / ambiguity / domain), and switches the live session between
haiku, sonnet, and opus by injecting /model. It can also inject
/effort low|medium|high|xhigh|max. The default matrix routes difficulty to
model (easy -> haiku, medium -> sonnet, hard -> opus) and ambiguity to
effort (low -> low, medium -> medium, high -> high).
No Anthropic API key, OpenRouter key, or per-user provider key is required for this mode.
Install
npm install -g @morphllm/morphrouter
# or run without installing:
npx @morphllm/morphrouter chatRequires Node.js >= 20 and an installed, logged-in Claude Code.
Quick start
export MORPH_API_KEY=... # your Morph key
morphrouter init # write a starter config
morphrouter chat "fix the parser bug"Running morphrouter with no subcommand is the same as morphrouter chat.
chat (alias enterprise-chat) launches the native Claude Code TUI. When you
submit a normal prompt it: clears the draft line, calls Morph, sends
/model <selected-model> if the model changed, auto-confirms Claude Code's
switch prompt, sends /effort <selected-effort> if needed, waits for it to
settle, then resends your prompt.
The Morph status bar is part of normal chat startup. When Claude Code does not
already have a custom statusLine, morphrouter wires the bar automatically.
Slash commands (/status, /model opus, /exit, …) pass through unchanged.
Works with all Claude Code flags
Any flag you pass is forwarded straight to the underlying claude process, so
subagents, MCP, sessions, and permission modes all work as normal:
# boolean flags can be passed directly:
morphrouter chat --dangerously-skip-permissions
# expose the local routed session through Claude Code Remote Control:
morphrouter chat -- --remote-control
# use `--` before value-flags so they aren't read as prompt text:
morphrouter chat "refactor auth" -- --add-dir ../shared --resume
morphrouter chat -- --mcp-config ./mcp.json --permission-mode planNotes:
- The router owns
--model, so a--modelyou pass is ignored. - Subagents and remote control work because this drives the real TUI — the
wrapper only touches the top-level input line and
/modelswitching. - In the SDK fallback (
chat-sdk),--dangerously-skip-permissionsand--add-dirare translated to SDK options; other flags are TUI-only.
Config
The subscription route is just the Claude Code model alias. Thinking effort is configured beside it:
{
"routing": {
"defaultRoute": "sonnet",
"defaultEffort": "medium",
"matrix": [
{ "difficulty": "easy", "ambiguity": "low", "domain": "*", "route": "haiku", "effort": "low" },
{ "difficulty": "easy", "ambiguity": "high", "domain": "*", "route": "haiku", "effort": "high" },
{ "difficulty": "hard", "ambiguity": "low", "domain": "*", "route": "opus", "effort": "low" },
{ "difficulty": "hard", "ambiguity": "high", "domain": "*", "route": "opus", "effort": "high" }
]
}
}Stop switching on long context (KV cache)
Switching models mid-conversation busts the upstream KV/prefix cache. Set a token ceiling past which the router pins the current model instead of re-routing:
{ "routing": { "contextLock": { "enabled": true, "maxTokens": 60000 } } }In the gateway this counts the full request (system + tools + messages); in native chat it counts the rendered output the router can observe, so it is approximate and errs toward locking a little early.
Tuning for native /model switching lives under claudeCodeSubscription
(switchIdleMs, switchConfirmTimeoutMs, autoConfirmModelSwitch,
autoConfirmEffortSwitch, …). See
config.example.json in the repo for the full set.
Debug trace:
MORPH_NATIVE_TRACE=/tmp/morph-native-trace.jsonl morphrouter chatCommands
morphrouter # same as morphrouter chat
morphrouter chat # route each turn in native Claude Code via /model
morphrouter enterprise-chat # alias for chat
morphrouter chat-sdk # Claude Agent SDK wrapper (non-TTY fallback)
morphrouter plan-chat "..." # route once at startup, then hand off to claude
morphrouter statusline # print latest Morph decision for statusLine
morphrouter doctor # diagnose the setup
morphrouter config # open the config file in your editor (alias: edit-config)Develop
npm ci
npm testThis package is published by the landing repo's morphcli-publish-mcp.yml
workflow.
License
MIT
