@menteeai/menteeswe
v0.14.0
Published
MenteE SWE — a model-agnostic autonomous software-engineering agent CLI. Bring your own intelligence: Kimi, GLM/Z.ai, and more.
Maintainers
Readme
MenteE SWE
An autonomous SWE agent in your terminal. It investigates your repository, plans, makes minimal edits, runs your tests, debugs failures, and reports back with evidence — never claiming success without proof.
Bring your own intelligence: MenteE is model-agnostic. Claude, GPT, Gemini, DeepSeek, Qwen, Kimi, GLM and more plug in as replaceable providers. The product is the harness: tools, verification loop, context management, and orchestration.
Install
npm install -g @menteeai/menteesweQuick start
# one-time configuration (pick a provider, paste API key)
mentee config
# run a task in your project
cd your-project
mentee "fix the failing auth tests"Or try without installing: npx @menteeai/menteeswe "your task".
Providers
Fifteen, all interchangeable at runtime. Pick one with -p, /provider, or
mentee config, and override the model with -m <id>.
| Provider | -p | Default model | Env var |
|---|---|---|---|
| Kimi (Moonshot) | kimi | kimi-k2.7-code | MENTEE_KIMI_API_KEY |
| GLM (Zhipu CN) | glm | glm-4.6 | MENTEE_GLM_API_KEY |
| Z.ai (GLM international) | zai | glm-4.6 | MENTEE_ZAI_API_KEY |
| Z.ai Coding Plan | zai-coding | glm-4.6 | MENTEE_ZAI_API_KEY |
| OpenAI | openai | gpt-5.4 | MENTEE_OPENAI_API_KEY |
| Anthropic | anthropic | claude-sonnet-4-5 | MENTEE_ANTHROPIC_API_KEY |
| Google Gemini | gemini | gemini-2.5-pro | MENTEE_GEMINI_API_KEY |
| DeepSeek | deepseek | deepseek-chat | MENTEE_DEEPSEEK_API_KEY |
| Qwen (international) | qwen | qwen3-coder-plus | MENTEE_DASHSCOPE_API_KEY |
| Qwen (China) | qwen-cn | qwen3-coder-plus | MENTEE_DASHSCOPE_CN_API_KEY |
| OpenRouter | openrouter | anthropic/claude-sonnet-4.5 | MENTEE_OPENROUTER_API_KEY |
| NVIDIA NIM | nvidia | nvidia/llama-3.1-nemotron-70b-instruct | MENTEE_NVIDIA_API_KEY |
| OpenCode Inference | opencode | kimi-k2.6 | MENTEE_OPENCODE_API_KEY |
| IFM | ifm | IFM/K2-Horizon-375B-A23B | MENTEE_IFM_API_KEY |
| Mock (offline) | mock | — | no key needed |
mentee -p anthropic "add a health check endpoint"
mentee -p gemini -m gemini-2.5-flash "explain this stack trace"Two notes that save time:
- Qwen keys are region-locked. An international key sent to the Beijing host
fails with an opaque 404. Use
qwenfordashscope-intlkeys andqwen-cnfor Beijing keys. - Anthropic is a real integration, not a URL swap. Its Messages API puts the
system prompt outside the message list, has no
toolrole, and usesinput_schema, so it is implemented natively — including streaming, so token output stays live in the TUI. - OpenCode Inference is one gateway, several API families. This provider
speaks the Chat Completions family (
kimi,glm,minimax,deepseek,grok); GPT ids on that gateway are served by the Responses API and Claude/Qwen by the Messages API, which this provider does not speak — use the direct provider for those. A Console service-account key is required: the*-freeids are gated to the OpenCode client itself and return 403 from outside it.
Any OpenAI-compatible endpoint can also be reached through openrouter, which
carries 100+ models behind one key. MenteE identifies itself with the full
OpenRouter attribution header set, including X-OpenRouter-Categories: cli-agent,
which is what unlocks the models OpenRouter restricts to agentic harnesses.
Switching provider resets the model to that provider's default — the old id meant nothing on the new host.
Delegation
The agent can hand one focused question to a read-only subagent with its own fresh context, and get back a short cited answer instead of a transcript:
> find everywhere auth is enforced
subagent: find everywhere auth is enforced answered 3 req 5 reads 11s
FINDINGS
- the admin router wraps it in try/catch (src/routes/admin.ts:14)
- nothing else calls it; only the test does (tests/admin.test.ts:9)
UNRESOLVED
- a dynamic dispatch could hide a caller (would need a runtime trace)It pays off because your context is the scarce resource: reading four files to answer one question costs 15k tokens you will still need later, while the report costs about 400 and your context is unchanged.
The subagent gets ten read-only tools, its own 8-request ceiling, and cannot spawn
another subagent. Fan-out is capped at 8 per task and an identical question is
refused rather than paid for twice. Its tokens are billed to your total, and a
report that cites path:line is a claim the agent verifies before acting on it.
Use it for breadth — "where does X happen", "what would break if I change this". Not for a file you already know the path of.
Inside the chat
The interactive CLI stays open between tasks. The prompt is a text area, not a line, so a task can be as long as the task actually is:
- Paste anything. A stack trace, a diff, three bullet points — every line arrives at the model as you pasted it.
- Enter sends. Ctrl+J starts a new line. Most terminals cannot tell you Shift+Enter from Enter, so Ctrl+J (a distinct byte) is the one that always works. Shift+Enter and Alt+Enter are accepted where the terminal reports them.
- A pasted block that ends in a newline is sent, the way a shell runs a command you pasted with a trailing newline.
- Arrows, Ctrl+A/E (line ends), Ctrl+U/K (kill to line end), Ctrl+W (delete word) and Backspace all work across line breaks. ↑/↓ move the caret once your text spans more than one row, and scroll the transcript until then.
- The prompt grows to six rows and then scrolls with the caret, so a long paste cannot crowd out the conversation.
Slash commands:
/provider <name> switch provider (kimi, glm, zai, zai-coding, openai,
anthropic, gemini, deepseek, qwen, qwen-cn, openrouter,
nvidia, opencode, ifm, mock)
/model <id> set the model for the current provider
/key <api-key> add the API key for the current provider (saved to ~/.mentee/config.json)
/last [n] re-print the output of recent tool calls that were summarised
/status show provider, model, key, workspace
/history show command history
/skills list available skills; /skill <name> injects one
/plan <task> investigate read-only, approve the plan, then execute
/turtle [on|off] Turtule mode: debug out loud so you learn the moves
/undo restore the last edit checkpoint
/fork <name> branch the session; /branches lists, /switch <name> changes
/exit quitWhile a task runs, one status line stays live at the bottom showing the phase,
the tool in flight, token spend, an estimated dollar cost, and elapsed time. Type
the next task while it runs and it is queued rather than dropped. Every tool call
prints one line (+ [tests] npm test 42 passing 1.2s); failures open
automatically with the relevant output, and large successful output is summarised
with a /last affordance.
Routing and fallback
Serve exploration batches from a cheap model and edit turns from a strong one, and degrade gracefully when a provider hits its daily quota:
{
"routing": {
"exploration": { "provider": "glm", "model": "glm-4.6" },
"implementation": { "provider": "anthropic", "model": "claude-sonnet-4-5" },
"review": { "provider": "deepseek" }
},
"fallbackModels": [
{ "provider": "glm", "model": "glm-4.6" },
{ "provider": "openrouter" }
]
}The serving provider is picked by the last committed tool batch. On a period
quota or sustained rate limit the task degrades through fallbackModels, tries
each once, and sticks to the first that answers.
MCP tools
Model Context Protocol servers join the toolset when configured:
{
"mcpServers": {
"filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "."] },
"remote": { "url": "http://localhost:8080/mcp" }
}
}Read from ~/.mentee/config.json (global) or .mcp.json / .mentee/mcp.json
(project). Tools appear as mcp__<server>__<tool> and always need approval.
A server that fails to start warns and is skipped — it never blocks startup.
Plan mode
mentee --plan or /plan <task>: the model investigates read-only, writes a
structured plan (GOAL / FILES / APPROACH / VERIFY / RISKS), and nothing changes
until you approve. Sessions can branch mid-task with /fork <name> and switch
back with /switch main.
Edits print as ~ edit src/x.ts +12 -3 with up to 6 removed and 6 added
lines, then say how many were withheld. A diff larger than the peek is truncated
rather than allowed to bury the conversation.
Turtule mode — debugging out loud
Want to learn how the debugging works rather than just get the fix? Turn it on:
🐢 Want to learn debugging? Turn on Turtule mode with /turtle — MenteE debugs out loud instead of just solving./turtle opens a dropdown; /turtle on skips it. mentee --turtle starts a
session with it already on. The turtle is a nod to the rubber duck, which is
worth a paragraph because it is the cheapest debugging technique that exists:
explaining a problem line by line to something that cannot help you finds the
bug faster than looking harder, because the explanation forces every assumption
into words.
In this mode MenteE debugs as if to a reader rather than producing a fix:
- one sentence before each tool call — what it suspects, and what the call proves or disproves
- hypotheses named and cited (
src/auth.ts:42), dropped explicitly when the evidence contradicts them - the debugging move named, not just the result: reproduce first, narrow the scope, check the last change, read the error bottom-up
- what each result means for the hypothesis, in plain words
- one Socratic question per phase where it helps — and never a blocking one, because there is no back-and-forth inside a run and a question the agent waits on is a stalled run
- a "What we learned" recap at the end: root cause, the clue that gave it away, the habit to reuse
Verification, minimal edits and the phase machine are untouched. Only the commentary changes.
What a task costs
Token spend scales with iterations, not with the size of the change. A one-line edit that takes 5 model requests costs roughly 5x a one-iteration task even though the diff is a single line. The reasons a small change still needs several requests: locating the string, reading the file, patching, the enforced verification run, and the final synthesis.
Two numbers come out of a run and they mean different things, which is worth stating because conflating them hides a real overflow:
- cumulative input — every request summed. The same prefix is charged on every turn, which is exactly what the prompt-cache breakpoint below avoids. This is a cost figure.
- peak request — the largest single request. This is the context size, and the one a model context limit is about.
--status and the context warning report both, labelled.
The system prompt is a fixed ~1.7k tokens sent on every request, so on a
five-iteration run it is most of the input bill for a small change. MenteE sends
a cache_control breakpoint on every request to every provider, so that prefix
is billed once instead of five times. There is nothing to configure: an endpoint
that does not understand the field rejects the request, so MenteE retries once
without it and remembers not to send it to that provider again.
MENTEE_PROMPT_CACHE=off # the only setting: never send cache_controlFull-screen mode
--ink opens the alternate-screen chat view instead of the default linear one:
mentee --ink| Key | Action |
|---|---|
| ↑ / ↓ | scroll one row |
| PgUp / PgDn | scroll a page |
| Ctrl+U / Ctrl+D | scroll half a page |
| Esc | jump back to the latest |
| Alt+E | expand or collapse the last tool call or diff |
| Alt+T | show or hide the model's thinking |
| Alt+M / Ctrl+P / Ctrl+K | model / provider / API key |
Scrolling is measured in rows, so a single press moves a single line no matter
how tall the entry above it is. When you scroll back, the view stays where you
left it and a ↓ N new marker appears instead of the conversation jumping; press
Esc to snap back to the latest.
Safety model
- safe — read-only commands (
git status,npm test,ls) run automatically - restricted — installs, git history changes → interactive approval (
y/a/n), or auto-approve with--yes - dangerous —
rm -rf,sudo, force pushes → always blocked
All file edits are constrained to the current workspace. Sessions log to ~/.mentee/logs/.
Not claiming more than happened
The failure this guards against is a confident summary of partial work, which is the one output the user cannot check.
- Evidence is typed. A finding is
observed(a tool printed it) orinferred(it follows from something else), and only the loop — never the agent's own account — may mark oneverified. An agent claiming a check confirmed something renders asCLAIMED, not as proof. The ledger is replayed after a compaction, so a verified finding cannot come back as a guess. - A finish is held against the evidence. For a task whose profile expects changes, a change must exist and a check must have passed before the run is allowed to report done. Checking the checklist alone is not enough: deleting the open steps and explaining them in prose satisfies it, which is how a task that was never implemented gets reported complete with three steps removed from the list the user is watching.
- Blocked is allowed, twice. A task that genuinely cannot be finished — no test suite, a credential that is not there — is challenged twice and then permitted to say so, recorded as incomplete. A harness that will not let the agent report a blockage teaches it to fake completion instead.
- Tool effects are checked. A tool that reports success is audited against
the filesystem and the live checklist; a claim that is positively contradicted
is downgraded to
EFFECT_NOT_VERIFIEDrather than passed on. - Truncated results name their resume point.
readon a large file returns a contiguous window plusstart_linefor the rest, rather than a head and a tail with an unexplained gap in the middle.
CLI
mentee [task...] run a task (simple linear chat in a terminal)
mentee config provider/key setup wizard
mentee -p anthropic "task" choose provider
mentee -m claude-sonnet-4-5 "task" override model
mentee --turtle "task" debug out loud instead of just solving
mentee --yes --no-tui "task" headless mode for scripts/CI
mentee --ink "task" legacy Ink TUI (default: simple chat)Development
npm install
npm run dev # run from source
npm test # unit + integration tests (mock provider, no API keys needed)
npm run typecheck # tsc --noEmit
npm run build # bundle to dist/
npm run eval # eval suite against fixture repos (mock provider)Copy .env.example to .env if you would rather supply provider keys from the
environment. .env is gitignored; the app also reads them from
~/.mentee/config.json, which mentee config writes for you.
Releasing
Two branches:
main— development. Merging here runs CI only.production— releases. Merging here publishes to npm.
main ──────▶ production ──▶ npmOne-time setup: add an npm automation token as the repository secret
NPM_TOKEN (Settings → Secrets and variables → Actions). Do not put it in a
file — a token committed to a repo is a leaked token, and Actions secrets are
the mechanism for exactly this.
To ship a release:
npm version patch # or minor / major; this is the version npm gets
git commit -am "0.3.3"
git push origin main
# open a PR from main -> production and merge itMerging to production runs .github/workflows/publish.yml, which typechecks,
builds and publishes.
On provenance: it is deliberately off. --provenance requires npm to build a
publicly verifiable attestation, and npm refuses bundles from a private source
repository outright:
Unsupported GitHub Actions source repository visibility: "private".
Only public source repositories are supported when publishing with provenance.So the workflow grants no id-token: write and passes --provenance=false. That
permission alone is enough to make npm attach provenance with no flag on the
command line, which is why removing just the flag would not have helped. If this
repository is ever made public, put id-token: write back and drop the flag.
CI typechecks and builds on every push. The test suite is a separate job behind
workflow_dispatch, because it renders real terminal frames and is unreliable on
a loaded runner; run it deliberately when you want it.
Architecture
src/
cli.tsx entry point: flag parsing, terminal setup, mode selection
agent/ the harness: loop, prompts, persistence, delegation
subagent.ts the read-only subagent behind the `delegate` tool
evidence.ts the evidence ledger, the phase machine, and the completion gate
turtle.ts Turtule mode: the rubber-duck instructions and its launch hint
accounting.ts where the tokens went, split by who wrote them
models/ provider layer: OpenAI-compatible factories, plus a native
Anthropic Messages API client for the one provider that is
not OpenAI-shaped
tools/ 46 tools (+ delegate), sandboxed paths, risk classification
base.ts ToolResult: command, exitCode, error, and a resumable range
postcheck.ts audits a tool's claimed effect against what is observable
investigation.ts the agent's own reasoning state, wired to the loop
modes/ chat.ts (default), headless.ts (CI), and the --ink TUI
tui/
layout.ts the frame contract: column budget, exact-width rows
measure.ts entry model, heights, bottom-anchored scroller
md.ts markdown to exact-width rows
chat.ts linear-mode rendering (status, panels, entries)
eventmap.ts bus events to entries, shared by all three renderers
status.ts the rewritable live status line
App.tsx full-screen chat viewThe rendering rule everything else follows: a frame is exactly rows - 1 lines
tall and every line is exactly cols display columns wide. Ink has no clipping
path — a frame that reaches the terminal height triggers a full-screen clear and
repaint, and one that exceeds it makes the terminal scroll and desyncs the
cursor, which is how text ends up drawn over other text. layout.ts is the
single place that arithmetic lives, and tests/ui/frame.test.ts renders the real
app at six terminal sizes and asserts the frame never breaks.
See ../MAIN_GOAL.md for the full product plan: phases, verification loop, subagents, context engineering, and routing roadmap.
