kimandClaude f347c150a4 v0.6.0: sub-agent orchestration, plan mode, memory, and the Claude-Code feature gap
Closes the gap to Claude Code across four upgrade rounds (all verified
green: typecheck, 388 tests, build 313 KB).

Sub-agent orchestration:
- Resumable sub-agents (send_message) + MaxIterations "continue" path
- Configurable multi-depth sub-agent nesting
- Parallel fan-out for pure agent/agent__* batches, each writable delegation
  in its own throwaway git worktree (no file collisions)
- Named specialist fleet: explore, code-reviewer, planner, debugger,
  test-writer (read-only types skip worktree isolation)
- Named teammates: agent tool `name` arg + list_teammates + send_message
  by name (synchronous, addressable handle — not true async background)

Plan mode:
- True in-turn pause/resume on approval (no synthetic proceed turn)
- exit_plan_mode tool + side-by-side diff rendering (/diff)

Persistent memory:
- Typed file-per-fact memory under config dir, index folded into the
  system prompt (bounded), memory + memory_write tools, /memory command

Toolset + UI:
- multi_edit, notebook_edit, web_search/web_fetch, workflow orchestration
  primitive (agent/parallel/pipeline/phase/log + worktree isolation +
  best-effort structured output with recursive schema validation)
- Structured task system (task_create/list/get/update with dependency
  graph + ownership) replacing flat todo_write
- Cron/scheduled tasks (cron_create/list/delete, schedule_wakeup) with
  durable persistence and idle-gated ticking
- Interactive worktree session (enter_worktree/exit_worktree) with a
  live-cwd UI switch that survives /model changes
- AskUserQuestion tool + QuestionPrompt UI
- Permission rule granularity + user/project settings merge
- Color diffs, sub-agent activity panel, /undo, dashboard refinements

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-16 11:35:05 +09:00
2026-07-06 12:41:15 +09:00
2026-07-06 12:41:15 +09:00

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>.

locode can also install Claude Code plugins directly — the parts that map onto locode's own architecture, anyway (see below for what doesn't):

locode plugin add ./path/to/plugin       # a local plugin directory
locode plugin add https://github.com/someone/some-plugin.git   # cloned via git
locode plugin list
locode plugin remove <name>

Hooks (see below) are hand-edited JSON rather than added via a CLI subcommand:

locode hooks path    # print the user-level hooks.json path to edit
locode hooks list     # see every configured hook (plugin + user + project), merged

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.

  • Ctrl+O: print the full text of the last /compact (or auto-compact) summary. The collapsed notice you see right after compacting only shows a one-line hint — press Ctrl+O any time afterward to print the whole thing.

  • Ctrl+B: while a bash command is running, detaches it into the background and returns control to you immediately — the turn continues with a bash_output-checkable job id instead of waiting for the command to finish. A notice appears in the transcript once the backgrounded command actually completes. Only bash supports this today. The model can kill a still-running backgrounded job with bash_kill; any jobs still running when locode itself exits are killed too, so they don't outlive the process as orphans.

  • 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_status, bash_output, todo_write run automatically. write_file, edit_file, bash, bash_kill, and git_commit show a diff/preview in a bordered box and ask you to pick Yes / Yes-always-this-session / No with the arrow keys before running.

  • Permission modes: default (ask before every mutating tool), plan (research only — every mutating tool is blocked outright, no prompt; the model is expected to describe what it would do in its final answer instead), auto-edit (file edits auto-approved, bash/git_commit still ask), auto-accept (everything auto-approved — use with care). Cycle with Shift+Tab or set directly with /perm <mode>.

  • Task checklists: for multi-step work the model can call todo_write to show a live checklist (☐/◐/☑) in the transcript instead of silently working through a list you can't see progress on.

  • Project instructions: a CLAUDE.md (or AGENTS.md) file in the project root is automatically read at session start and folded into the system prompt — put repo-specific conventions there and every session picks them up without being told.

  • Images: read_file returns image files (png, jpg, jpeg, gif, webp, bmp — up to 5MB) as actual image content instead of trying to decode them as text, so vision-capable models can see them when the model itself calls the tool. To attach a file or image to your own message directly, use /import <path> [caption].

  • @ file mentions: type @ in the chat input to open a fuzzy file picker (searches the whole project, skipping node_modules/.git/dist) — keep typing to filter, ↑/↓ to navigate, Tab (or Enter) to insert the highlighted path. Any @path left in your message when you hit Enter for real is resolved against disk and attached to that message (text inlined, images attached as image content) — a stray @ that isn't an actual file (e.g. an email address) is left as plain text.

  • Git: git_status covers read-only inspection (status, diff, log, show, branches) and runs automatically. git_commit covers add, commit, create_branch, checkout, and push — 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 agent tool lets the model delegate a self-contained task to a fresh, isolated tool loop (same tools, minus agent itself — 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 add or a project's .mcp.json (stdio and remote/streamable-HTTP transports), and adds their tools to every session, namespaced as mcp__<server>__<tool>. Every MCP tool is treated as mutating (confirmation required on every call) regardless of what it reports — the MCP readOnlyHint annotation is advisory and could be wrong (or set by a malicious server specifically to skip confirmation), so locode never trusts it. One misconfigured server doesn't block the others — check /mcp for per-server connection status.

  • Claude Code plugins: locode plugin add <path-or-git-url> installs a Claude Code-compatible plugin — locode reads its .claude-plugin/plugin.json, then loads it all directly: MCP servers (its .mcp.json or manifest mcpServers, merged in like any other MCP server), slash commands (commands/*.md — frontmatter description/argument-hint, body is a template expanded with $ARGUMENTS/$1..$9 and submitted as your message), agents (agents/*.md — the body becomes a sub-agent's system prompt, exposed as a callable tool named agent__<plugin>__<agent>; a tools: frontmatter list restricts what it can use, with Claude Code's built-in tool names — Read, Grep, Edit, etc. — automatically mapped to locode's equivalents), hooks (hooks/hooks.json, see below), and skills (skills/*/SKILL.md, see below). Check /plugins for what's loaded.

  • Skills: named instructions the model loads on demand rather than a hook or a sub-agent — every installed skill (skills/<name>/SKILL.md) is exposed through one shared skill tool, whose own description lists every skill's name and "use this when..." blurb so the model knows when to call it. You can also invoke one directly with /<skill-name> [request], which skips the model's own judgment and submits the skill's instructions (plus your request, if any) as the turn. Check /skills for what's installed.

  • Hooks: shell commands that fire on session lifecycle events — SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, PermissionRequest, SubagentStart, SubagentStop, CwdChanged, FileChanged, ConfigChange, Stop, SessionEnd. Configured the same way MCP servers are — plugin-bundled (hooks/hooks.json), user-level (locode hooks path, hand-edited), and project-level (.locode/hooks.json) all merge together, every hook from every source runs. A hook receives a JSON payload on stdin (session_id, cwd, hook_event_name, plus event-specific fields like prompt or tool_name/tool_input); exit 0 allows (stdout becomes injected context for SessionStart/UserPromptSubmit), exit 2 blocks (stderr is the reason shown), anything else is a non-blocking warning. PreToolUse, UserPromptSubmit, and PermissionRequest can block; the rest are fire-and-forget. PreToolUse fires before permission modes apply, so a hook's block can't be bypassed by auto-accept. command and http hook types are supported (prompt is declared in the config format but not yet executed); command hooks can opt into structured JSON output via outputSchema: "json". SessionEnd fires on every exit path (including Ctrl+C and external SIGTERM/SIGHUP). Check /hooks for what's configured.

  • 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|auto or the in-session /mode command.

  • Context tracking & compaction: the status bar shows ctx NN% — context window usage, from real usage.prompt_tokens when the backend reports it (requested via stream_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)
/perm [mode]      cycle or set permission mode (default | plan | auto-edit | auto-accept)
/status           show current model, backend, tool-call mode, and cwd
/dashboard        show session stats: token I/O, elapsed/model time, turns, tool calls
/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
/plugins          show installed Claude Code-compatible plugins (commands, agents, skills, MCP servers)
/hooks            show configured hooks per lifecycle event
/skills           show installed skills; /<skill-name> [request] invokes one directly
/compact          summarize the conversation now to free up context
/export [file]    save the conversation as markdown — opens an editable filename prompt (default: locode-export-<timestamp>.md)
/import <path> [caption]   attach a local file or image to your next message
/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, LOCODE_AUTO_COMPACT_THRESHOLD, LOCODE_REQUEST_TIMEOUT_MS) > 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 50)
locode config set autoCompactThreshold 0.85  # fraction of context window at which auto-compact triggers
locode config set requestTimeoutMs 300000  # per-request timeout in ms (default 180000); raise this if
                                            # your backend queues requests behind a concurrency limit
                                            # (e.g. Ollama's OLLAMA_NUM_PARALLEL) under multi-session load
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 bash tool has only had light testing; behavior may differ from Unix shells for complex quoting.
  • git_commit covers add/commit/create_branch/checkout/push/reset/stash/merge/rebase/delete_branch. Use bash for anything beyond that.
  • MCP tool results support text, image, audio, and resource content blocks. Images are returned in the same shape as read_file so vision-capable models can see them; audio and binary resources are summarized. Remote (HTTP) MCP servers support static headers (e.g. a bearer token) but not OAuth flows.
  • Compaction (/compact or automatic) 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 auto-compact threshold defaults to 85% and is configurable via locode config set autoCompactThreshold or LOCODE_AUTO_COMPACT_THRESHOLD.
  • Plugin support (locode plugin add) now covers every part of a plugin: MCP servers, slash commands, agents, hooks, and skills. A plugin's allowed-tools restriction on a command isn't enforced (the expanded prompt just runs as a normal turn with the full toolset). Duplicate MCP server names across sources are now detected and surfaced in /mcp — project-level wins over user-level wins over plugin-level. Duplicate slash-command and skill names are also surfaced in /plugins and /skills.
  • Skills are exposed as one shared skill tool rather than one tool per skill — if two plugins install a skill with the same name, the first plugin in load order wins and the collision is shown in /skills. Skills can bundle sibling references/*.md files that are included when the skill is invoked.
  • Hooks cover the most useful subset of Claude Code's lifecycle events: SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, PermissionRequest, SubagentStart, SubagentStop, CwdChanged, FileChanged, ConfigChange, Stop, SessionEnd. CwdChanged is declared in the config format but not yet fired anywhere — a cwd never changes mid-session in locode today, so configuring it is a no-op for now. command hooks and http hooks are supported; prompt hooks are declared in the config format but not yet executed. Command hooks can opt into structured JSON output via outputSchema: "json". PreToolUse, UserPromptSubmit, and PermissionRequest can block; the rest are fire-and-forget. SessionEnd fires on every exit path (including Ctrl+C and external SIGTERM/SIGHUP), so it doesn't always have a real session id to report. All hooks for an event run in parallel with no defined ordering, and every configured hook always runs — there's no way to disable one without editing the file it came from.
S
Description
No description provided
Readme
1.1 MiB
Languages
TypeScript 100%