The 8-iteration-per-turn cap was hardcoded from before this session's feature work and too tight for genuine multi-file tasks, causing "Max tool-call iterations reached" on legitimately multi-step work. Raised the default to 25 and made it configurable via `locode config set maxIterations <n>` / $LOCODE_MAX_ITERATIONS, mirroring the existing contextWindow config pattern. Also bumps the version to 0.2.0 (package.json, --version, and the MCP client's self-reported identity) to reflect the substantial feature additions since 0.1.0. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
locode
An agentic coding CLI, in the spirit of Claude Code, for models running locally via Ollama or LM Studio. It talks to either backend's OpenAI-compatible /v1/chat/completions endpoint, so any model you can serve from either one works here.
Install
npm install
npm run build
npm link # makes the `locode` command available globally
Quick start
Make sure Ollama (ollama serve, default http://localhost:11434) or LM Studio (with a model loaded, default http://localhost:1234) is running, then:
locode --model qwen3-coder:30b
If you omit --model, locode lists the models available from the backend and lets you pick one with the arrow keys (Enter to confirm). Your saved default (via config or $LOCODE_MODEL) is pre-highlighted.
Pass --model explicitly to skip the picker entirely. Or persist your defaults so you don't need flags every time:
locode config set backend ollama
locode config set model qwen3-coder:30b
locode
List models available from the configured backend:
locode models
Every conversation is auto-saved as you go. Resume later:
locode --continue # resume the most recent conversation
locode --resume # pick from a list of saved conversations
locode --resume <id> # resume a specific one
locode sessions list # see saved conversations (id, model, title) without starting the UI
locode sessions rm <id> # delete a saved conversation
locode can also use tools from external MCP servers:
locode mcp add my-server --command npx --arg -y --arg @some/mcp-server # stdio server
locode mcp add my-remote --url https://example.com/mcp # remote (streamable HTTP) server
locode mcp list # see configured servers (user-level + project .mcp.json)
locode mcp remove <name>
Project-level servers can also be checked into a repo via a .mcp.json file in its root:
{
"mcpServers": {
"my-server": { "command": "npx", "args": ["-y", "@some/mcp-server"] }
}
}
locode connects to every configured server on startup; their tools show up alongside the built-in ones, namespaced as mcp__<server>__<tool>.
How it works
locode is a full-screen terminal app built with Ink (the same React-for-CLI framework Claude Code itself is built with) — it needs a real interactive terminal (piped/redirected input isn't supported). It takes over the terminal's alternate screen buffer (like vim/htop) — your prior scrollback is restored when you exit. The input box is always pinned to the last row of the window; the conversation fills the space above it and old messages scroll off the top as new ones arrive. Press Ctrl+C or type /exit to quit.
- Backends:
--backend ollama(default) or--backend lmstudio, or--base-url <url>for anything else that speaks the same API. - Tools:
read_file,list_files,grep,web_search,web_fetch,git_statusrun automatically.write_file,edit_file,bash, andgit_commitshow a diff/preview in a bordered box and ask you to pick Yes / Yes-always-this-session / No with the arrow keys before running. - Git:
git_statuscovers read-only inspection (status,diff,log,show,branches) and runs automatically.git_commitcoversadd,commit,create_branch,checkout, andpush— each shows the actual diff/status/commits it's about to affect before you confirm (e.g. a commit's preview is the staged diff plus the message, a push's preview is the list of commits it would send). - Sub-agents: the
agenttool lets the model delegate a self-contained task to a fresh, isolated tool loop (same tools, minusagentitself — no nested sub-agents) and get back only the final answer, keeping the main conversation's context focused. It shows up as a single⏺ Agent(description)/⎿ Sub-agent finished (...)line — the sub-agent's own intermediate steps aren't displayed. Any mutating tool calls it makes still go through the same permission prompts as the main conversation. - MCP servers: locode connects to any MCP servers configured via
locode mcp addor a project's.mcp.json(stdio and remote/streamable-HTTP transports), and adds their tools to every session, namespaced asmcp__<server>__<tool>. A server's tool is treated as mutating (confirmation required) unless it declares itself read-only via the MCPreadOnlyHintannotation. One misconfigured server doesn't block the others — check/mcpfor per-server connection status. - Tool-calling mode: on connect, locode probes whether the model reliably uses native OpenAI-style function calling. If not, it switches to a prompt-based fallback mode where the model is instructed to emit tool calls as fenced
```tool_call ```JSON blocks, which locode parses itself. The result is cached per backend+model so future sessions skip the probe. Override with--tool-mode native|fallback|autoor the in-session/modecommand. - Context tracking & compaction: the status bar shows
ctx NN%— context window usage, from realusage.prompt_tokenswhen the backend reports it (requested viastream_options.include_usage), or a~-prefixed char-based estimate otherwise. The window size itself is auto-detected (Ollama's/api/show, then LM Studio's/api/v0/models) and cached per backend+model; falls back to a configurable default (locode config set contextWindow <n>, or$LOCODE_CONTEXT_WINDOW) if neither responds. At 85% usage, locode automatically asks the model to summarize the conversation and replaces the history with that summary (a notice tells you when this happens) — or trigger it yourself anytime with/compact.
Note: even models with genuine native tool-calling support occasionally emit a tool call as plain text instead of a real structured call — this is model sampling variance, not a bug. If a turn seems to "describe" a tool call instead of running it, just ask again or try /mode fallback.
Slash commands
/model <name> switch the model used for the current backend
/backend <name> switch backend (ollama | lmstudio), keeps current model
/mode <name> view or force tool-call mode (native | fallback)
/status show current model, backend, tool-call mode, and cwd
/tools list available tools
/permissions list mutating tools allowed for the rest of this session
/sessions list saved conversations you can resume with --resume
/mcp show connected MCP servers and their tool counts
/compact summarize the conversation now to free up context
/clear clear conversation history
/help show this help
/exit, /quit exit
Config
Config precedence: CLI flags > env vars (LOCODE_BACKEND, LOCODE_MODEL, LOCODE_BASE_URL, LOCODE_CONTEXT_WINDOW, LOCODE_MAX_ITERATIONS) > persisted config file > defaults.
locode config set backend ollama
locode config set model qwen3-coder:30b
locode config set contextWindow 32768 # fallback size when auto-detection fails
locode config set maxIterations 40 # max tool calls per turn before locode gives up (default 25)
locode config get
locode config path
Known limitations
- Requires a real interactive terminal (TTY) — you can't pipe input into it or run it from a non-interactive script.
- Native tool-calling reliability varies by model and is non-deterministic even for capable models (see above).
- No sandboxing beyond the confirmation prompts — mutating tools operate on the real filesystem/shell with the permissions of the user running
locode. Only approve commands you understand. - Session resume replays prior user/assistant text so you can see it, but it doesn't re-display prior tool-call/tool-result lines from before the resume (the model still has that history — it's just not re-rendered).
- No in-app scrollback — once a message scrolls off the top of the window it's gone until you resize the terminal taller (the conversation itself is still intact and sent to the model; this only affects what you can visually re-read).
- Windows shell quoting for the
bashtool has only had light testing; behavior may differ from Unix shells for complex quoting. git_commitcovers add/commit/create_branch/checkout/push only — no reset, stash, merge, rebase, or branch deletion. Usebashfor anything beyond that.- MCP tool results only support text content — image/audio/resource content blocks are shown as a placeholder note rather than rendered. Remote (HTTP) MCP servers support static headers (e.g. a bearer token) but not OAuth flows.
- Compaction (
/compactor automatic at 85%) replaces history with a model-generated prose summary — it costs one extra model call and loses tool-call/tool-result detail (the model's own account of what happened survives; the raw record doesn't). The 85% threshold isn't currently configurable.