██████╗ ██████╗ ██████╗ ██╗███████╗
██╔════╝██╔═══██╗██╔══██╗██║██╔════╝
██║ ██║ ██║██║ ██║██║█████╗
██║ ██║ ██║██║ ██║██║██╔══╝
╚██████╗╚██████╔╝██████╔╝██║███████╗
╚═════╝ ╚═════╝ ╚═════╝ ╚═╝╚══════╝
v0.2.0 · Your local AI coding agent
Think it. Type it. Ship it.
A local, agentic coding CLI for LM Studio, built with Ink (React for
terminals). It has automatic context compaction so the server never fails when the
context window fills up, plus a proper multi-panel UI: fixed bottom input bar, scrollable
history, markdown rendering, a thinking spinner, and shell-style command history.
The first version of this tool used blessed, an older imperative terminal-UI library.
It hit real, hard-to-fix bugs: multi-line streamed output collapsing to one line, no way
to scroll finalized output, and up/down history navigation that silently never worked
because blessed's Textbox widget has an explicitly unfinished
// TODO: Handle directional keys in its own source.
Ink (used by Gemini CLI, Claude Code, and Codex's CLI) solves all of this natively:
<Static>renders permanent scrollback efficiently — finalized messages never re-renderuseInputis a well-supported, documented hook with working arrow-key detection- Flexbox layout via
<Box>makes pinning an input bar to the bottom trivial - Everything is normal React state — no manual line-buffer mutation
LM Studio's context window (set in the server settings) is fixed. If you keep sending the full conversation history and it exceeds that limit, the server rejects the request or truncates unpredictably — which looks like "it just stops working."
This tool solves that client-side, the way hosted AI products do: it tracks real token
usage (via LM Studio's own /tokenize endpoint) and, before the context overflows,
summarizes older turns into a compact note and drops the originals, keeping recent turns
verbatim. You'll never hit a hard context wall.
npm install
npm run buildStart LM Studio with a reasonably large context:
# LM Studio runs on port 1234 by default
# Just start LM Studio and load a modelTool calling requires a model/template that supports OpenAI-style function calling (e.g. Qwen2.5-Coder, Hermes-3, recent Llama instruct with function-calling templates). If your model doesn't support it, tool calls just won't be emitted — you can still chat.
Run the CLI:
npm start -- --session myprojector after a global link:
npm link
codie- Bottom input bar: bordered box, always focused, with a status line below showing cwd (left) and live token usage color-coded by how close you are to the context limit (green/yellow/red).
- Mode-aware input colors: the input outline reflects the active mode — agent (green), chat (blue), plan (yellow).
- Markdown rendering: headers, bold, lists, and syntax-aware code blocks render with real ANSI styling once a response finishes streaming.
- Thinking spinner: animates from the moment you hit enter until the first token arrives, then switches to a live raw-text preview of the streaming response.
- Command history: press ↑/↓ to cycle through previous messages, exactly like a shell.
- Quick mode switch: press Ctrl+↑ or Ctrl+↓ to cycle agent → chat → plan.
- Colorized diffs: file edits show a proper +/- diff, green/red, instead of raw patch text.
| Mode | Tool Access |
|---|---|
agent |
All tools |
chat |
Read-only tools (read_file, list_dir, search_files, read_file_outline, get_file_content, get_file_size, get_file_lines) |
plan |
Read-only tools only. Conversation is automatically saved to planning.md in the codebase root for coding implementation planning. |
| Command | Effect |
|---|---|
/usage |
Show current token usage vs. budget |
/compact |
Force compaction now |
/memory |
Show the current session memory file (info.md) |
/save |
Save session to disk |
/save-planning |
Save current planning conversation to planning.md |
/sessions |
List saved sessions |
/clear |
Wipe current history (keeps system prompt) |
/mode |
Show active mode |
/mode <agent|chat|plan> |
Change active mode |
/exit |
Save and quit |
Sessions auto-save after every turn to ~/.codie/sessions/<name>.json, so a crash
or Ctrl+C doesn't lose your work — resume with --session <name>.
codie --keep-recent 8 --max-tokens 3072--keep-recent: how many raw messages stay verbatim before older ones get summarized.--max-tokens: reserved headroom for each response; also subtracted from the compaction budget so a big response never gets cut off by a full context.
src/
llamaClient.ts — OpenAI-compatible client for LM Studio (/v1/chat/completions,
/tokenize, /props), streaming + tool call parsing
contextManager.ts — token budget tracking + auto-summarization/compaction
tools.ts — read_file, read_file_outline, write_file, edit_file, list_dir, search_files,
run_shell_command implementations + JSON schemas
session.ts — save/resume conversations to disk
markdown.ts — markdown → ANSI rendering, hardened against terminal-size
detection edge cases
uiTypes.ts — shared log-entry types
App.tsx — root Ink component: layout, state, imperative handle for the
async cli.tsx driver to push updates into React state
LogLine.tsx — renders one finalized entry (user/assistant/info/error/tool/diff)
InputBar.tsx — bordered TextInput + shell-style history navigation
StatusBar.tsx — cwd + token usage display
ThinkingIndicator.tsx — spinner shown while waiting for the first token
StreamingPreview.tsx — live raw-text view of the in-progress response
cli.tsx — entrypoint: wires everything together, runs the agent loop
(request → tool calls → tool results → repeat)
- Tool-call support depends entirely on your model + its chat template exposing
OpenAI-style
tool_calls. Not all GGUF models do. - Summarization uses the same local model, so aggressive compaction costs an extra generation each time it triggers — deliberate trade-off (your own compute, no external calls).
- No sandboxing beyond "stay inside the working directory" for file tools;
run_shell_commandexecutes real shell commands — review what the agent proposes before trusting it in sensitive directories.