__ __ ____ ___ ____ _____
| \/ |/ ___/ _ \| _ \| ____|
| |\/| | | | | | | | | | _|
| | | | |__| |_| | |_| | |___
|_| |_|\____\___/|____/|_____|
Streams tokens over your shell, edits your files, runs your commands — no Electron, no runtime, one native binary.
mcode is a small, self-contained terminal coding agent. Point it at a model — a cloud one through OpenRouter, or a local one through Ollama — and talk to it in a REPL. It can read and edit files in your project, run shell commands, search the filesystem, and fetch URLs, all gated behind your confirmation for anything destructive. Everything is a single native C++ binary with no language runtime, no bundled Node/Python, and no telemetry.
It's built to feel like a proper CLI tool: raw-mode line editing, in-place history recall, an inline file picker, and live Markdown rendering as the model streams its answer — not a REPL bolted onto a chat loop.
__ __ ____ ___ ____ _____
| \/ |/ ___/ _ \| _ \| ____|
| |\/| | | | | | | | | | _|
| | | | |__| |_| | |_| | |___
|_| |_|\____\___/|____/|_____|
A simplest terminal coding agent built using C++
> /provider
✓ Provider set: ollama
✓ Model set: qwen3:8b
> hey?
Hello! How can I assist you today?
>
-
Interactive REPL shell — raw-terminal line editor (POSIX
termios) with Up/Down prompt history recall, in-progress-draft preservation, and bracketed-paste support so multi-line pastes don't submit early. -
Inline
@file picker — press@mid-prompt to pop a modal directory/file browser and splice the picked path straight into the line, instead of typing it out. -
Ghost autocomplete — an unambiguous prefix of a known command (
/prov→/provider) is shown dimmed inline and expands on Enter. -
Multi-provider model gateway — swap between:
- OpenRouter — cloud gateway routing to many hosted models, picked from a live-fetched, price-sorted model list.
- Ollama — local models served from
http://localhost:11434, no API key required. - Interactive pickers for both provider (
/provider) and model (/model), plus a direct/model <name>form.
-
Streaming responses with a live Markdown-to-ANSI renderer — headings, bold, inline code, and fenced code blocks render correctly as tokens arrive, chunk boundaries and all.
-
Braille spinner with rotating status words (Thinking, Pondering, Marinating, Scheming…) while waiting on the first byte of a response.
-
Agentic tool-calling loop — the model can chain up to 8 rounds of tool calls before answering, with each call's arguments streamed and merged before execution.
-
9 built-in tools, all exposed to the model as JSON-Schema function defs:
Tool What it does read_fileRead a file's contents from disk create_fileCreate a new file with given contents create_directoryCreate a directory edit_fileFind/replace inside a file, with a colored git diff --no-indexpreview printed before writingdelete_fileDelete a file — asks for y/n confirmation first delete_directoryDelete a directory recursively — asks for y/n confirmation first command_executorRun a shell command and return stdout/stderr/exit code — asks for y/n confirmation first search_fileRecursive glob-pattern filename search web_searchFetch a URL over HTTP(S) and return the (truncated) body -
Conversation persistence — every turn is written to disk and reloaded automatically on the next launch, so a crash or plain
exitnever loses history. -
Zero-config first run —
~/.config/mcode/config.jsonis created automatically on first launch if missing.
See Roadmap.
| Layer | Choice |
|---|---|
| Language | C++20 (-fcoroutines enabled on GCC) |
| Build system | CMake ≥ 3.15 |
| HTTP client | cpr (libcurl wrapper) — streaming request bodies for token-by-token output |
| JSON | nlohmann/json |
| Terminal I/O | Raw POSIX termios/ioctl — no ncurses, no external TUI library |
| Model gateways | OpenRouter (cloud, multi-model) · Ollama (local) |
| Diffing | Shells out to the system git diff --no-index for edit previews |
flowchart TD
main["main.cpp<br/>REPL loop"] --> Commander
main --> Conversation
main --> Storage
main --> Config
main --> ProviderManager
main --> ToolManager
Commander -->|"/provider, /model,<br/>history, clear, save,<br/>@ file picker"| ProviderManager
Commander --> Conversation
ProviderManager --> OpenRouter
ProviderManager --> Ollama
OpenRouter -->|"streams via cpr"| MarkdownStream
OpenRouter --> Spinner
OpenRouter -->|"tool-call loop"| ToolManager
Ollama -->|"tool-call loop"| ToolManager
ToolManager --> Tools["ReadFile · CreateFile · CreateDirectory<br/>EditFile · DeleteFile · DeleteDirectory<br/>CommandExecutor · SearchFile · WebSearch"]
Conversation --> Storage
Storage -->|"./conversation.txt"| Disk[(Disk)]
Config -->|"~/.config/mcode/config.json"| Disk
Each piece has one job and doesn't reach into the others' internals:
Provideris an interface (providers.h) —OpenRouterandOllamaare interchangeable implementations, swapped at runtime byProviderManagerwithout touchingCommanderormain.Toolis likewise an interface (tool.h) — adding a new tool is a new subclass registered intool_initializer.cpp; no provider code changes.Commanderowns all terminal rendering (raw mode, pickers, ghost text) somain.cppstays a plain loop.
curl -fsSL https://raw.githubusercontent.com/MohakGupta2004/mcode/master/install.sh | bashThis installs missing build dependencies (cmake, a C++20 compiler, nlohmann-json, cpr — via Homebrew on macOS, or apt/dnf/pacman/zypper on Linux, building cpr from source if your distro doesn't package it), builds mcode, and drops the mcode binary into /usr/local/bin (falls back to ~/.local/bin if that's not writable and there's no sudo).
Review install.sh before piping it into bash — that's true of any curl-install script, this one included.
Then just run:
mcodePrerequisites: CMake ≥ 3.15, a C++20 compiler, nlohmann-json, cpr.
# macOS
brew install cmake nlohmann-json cpr
git clone https://github.com/MohakGupta2004/mcode.git
cd mcode
cmake -S . -B build
cmake --build build -jThis produces build/mcode. Run it with ./build/mcode.
On first run mcode creates ~/.config/mcode/config.json — see Configuration before you try to use OpenRouter.
Config lives at ~/.config/mcode/config.json, created automatically on first launch:
{
"API_KEY": {
"openrouter": ""
}
}To use OpenRouter, drop your key into the openrouter field:
{
"API_KEY": {
"openrouter": "sk-or-..."
}
}To use Ollama, no key is needed — just have ollama serve running locally on the default port (11434) and switch to it with /provider.
| Command | Effect |
|---|---|
| (plain text) | Send a message to the current model |
@ (while typing) |
Open the file/directory picker and insert the picked path |
↑ / ↓ |
Recall previous prompts from this session |
/provider |
Open an interactive picker to switch between openrouter and ollama |
/model |
Open an interactive picker for the active provider's models |
/model <name> |
Set the model directly, no picker |
history |
Print the full conversation so far |
clear |
Clear in-memory conversation history |
save |
Force-persist the conversation to disk |
exit / Ctrl-D |
Quit |
Known gaps and unfinished corners, roughly in priority order:
-
web_searchis a raw URL fetch, not a search engine — it fetches a given URL's body; it doesn't query anything. A real search API integration is still open. - No automated tests or CI.
- No packaging — no Homebrew formula, no prebuilt releases; build-from-source only.
- No license file — pick and add one before treating this as distributable.
- Windows is unsupported — terminal handling is POSIX-only (
termios,unistd.h,sys/ioctl.h). - System prompt is hardcoded in the OpenRouter provider, not user-configurable.
- No non-interactive mode — no way to pipe a single prompt in and get one answer out for scripting; the REPL assumes an interactive TTY.
- Ollama support is newer/less exercised than OpenRouter — expect rough edges.
This is a solo learning/build project in active development — expect breaking changes. Issues and PRs against the repo are welcome.