The open-source, offline alternative to Claude Code, Cursor, and GitHub Copilot.
A private AI pair programmer that runs on your machine with Ollama — no API keys, no cloud.
Private by default. Free forever. Works offline.
🔒 100% local — your code never leaves your machine · 💸 Free — no API keys, no per-token billing · ⚡ Offline — runs on your own GPU
ollama pull qwen2.5-coder:14b # any coding model works
curl -fsSL https://raw.githubusercontent.com/maruakshay/miii-cli/main/install.sh | sh
miiiWindows: irm https://raw.githubusercontent.com/maruakshay/miii-cli/main/install.ps1 | iex · any platform: npm i -g miii-agent · needs Node ≥ 18 and Ollama.
> refactor the auth module to use async/await
> @src/server.ts add rate limiting to all POST routes
> why are my tests failing in utils/parser.ts
miii reads your files, writes the code, runs your tests, and fixes what breaks — planning before it acts, and verifying after. Entirely on your own GPU.
| Cloud agents | miii | |
|---|---|---|
| Your code | Sent to a third party | Never leaves your machine |
| Cost | Per-token billing | Free — runs on your hardware |
| Setup | API keys, accounts | npm i -g miii-agent |
| Offline | No | Yes |
| Latency | Network + queue | Your GPU only |
- 🧠 Works with small models — miii repairs the malformed tool calls a 7B model emits instead of burning a turn on each one, and sizes its own prompt to your context window so the room goes to your code.
- 🧪
miii doctor— not every local model can drive an agent. Grades your installed models on real engineering tasks. - 🖼️ Paste images —
Ctrl+Va screenshot to ask why a UI looks broken. Needs a vision model (llava,llama3.2-vision, …). - 💧 Lossless output spill — a 50K-line test log is never truncated. The full text goes to disk and the model pages through it.
- 📋 Plan mode —
shift+tab(or/plan) makes the session read-only. miii researches your code, proposes a plan, and touches nothing until you approve it. The block is enforced by the harness, not asked for in the prompt: with no write tools and only reporting commands, a model that triessed -iorcat > fileanyway gets refused. - 🔒 Permission-gated tools — you approve what the agent touches, and see the exact rule before you save it. A saved wildcard never stretches across a command boundary, so approving
npm testcan't quietly authorizenpm test && rm -rf ~. - ⌨️ Your own slash commands — drop
review.mdin.miii/commands/and/reviewis a command, in the palette, checked into the repo with everything else. - 📄
MIII.md— drop one in your repo to teach miii your conventions and commands. Same idea asCLAUDE.md, read every turn.
Picking a model: 8GB VRAM → qwen2.5-coder:7b · 16–24GB → qwen2.5-coder:14b (sweet spot) · 48GB+ → qwen2.5-coder:32b.
Built-in tools
| Tool | Function |
|---|---|
read_file |
Read any file in your workspace |
write_file |
Create new files |
edit_file |
Precise string-level edits, whitespace-tolerant |
glob |
Pattern-match files across the project |
grep |
Regex search across files |
run_bash |
Execute shell commands |
write_todos |
Track multi-step work as a live checklist |
File tools (read_file, write_file, edit_file) reject ../ traversal and absolute paths outside the workspace. run_bash is not path-confined — its only boundary is the permission prompt, so review commands before approving.
How "always" approvals are scoped
Answering "always" saves both the exact command and a generalized glob (npm run build → npm run *), and the prompt shows you the widest rule before you choose.
Two things are never widened: destructive programs (rm, dd, sudo, git reset, …) and compound commands, whose first token says nothing about what the rest of the line does. A saved glob also refuses to match any command containing an unquoted ; && || | > or $(…), so an approval can't be stretched past the command you actually read.
Saved rules live in .miii/permissions.json in the project — that is what "always" writes to. Approval subjects are usually project-relative (src/index.ts means a different file in every repo), so a rule that followed you everywhere would be granting far more than you agreed to. Rules in ~/.miii/permissions.json apply in every project; put the ones you really do mean globally there by hand. /permissions lists both and says which file each came from.
Gitignore .miii/permissions.json — it is a record of what you approved. .miii/commands/ is meant to be committed.
Permission modes — shift+tab
shift+tab cycles the mode; the input frame changes colour with it.
| Mode | What it does |
|---|---|
| normal | asks before writing files or running commands |
| plan mode | read-only — research and a plan, approved before anything happens |
| auto-accept edits | writes files without asking; commands still prompt, since a command can reach outside the workspace |
| bypass permissions | runs everything without asking (red frame — for a sandbox or a throwaway tree) |
In plan mode the write tools are not offered at all and run_bash runs only commands that report — ls, cat, grep, find, git status/log/diff, one at a time, no pipes or &&. A compound command is refused however harmless its first word, because ls tells you nothing about what comes after the &&. When the research is done miii calls exit_plan_mode with the plan and you get three choices: start work, start work and stop asking about the edits, or send it back for another pass.
Custom slash commands
A Markdown file is a command. .miii/commands/review.md becomes /review:
---
description: review the staged diff
---
Review the staged diff for bugs and unhandled errors. Focus on $ARGUMENTS.$ARGUMENTS is everything typed after the command; $1…$9 are its individual words. A command that references neither gets the arguments appended, so nothing you type is silently dropped.
.miii/commands/ is project scope — check it in, and the whole team gets it. ~/.miii/commands/ is yours in every project. A project command shadows a personal one of the same name, and neither can shadow a built-in.
Keyboard shortcuts and commands
| Key | Action |
|---|---|
Enter |
Send prompt |
/ |
Open the command palette |
Shift+Tab |
Cycle permission mode — normal → plan → auto-accept → bypass |
@filename |
Attach file to context |
Ctrl+V |
Paste clipboard image (needs a vision model) |
Ctrl+T |
Toggle the model's thinking |
Ctrl+O / left click |
Toggle full tool output |
| Mouse wheel | Scroll the transcript |
PgUp / PgDn |
Scroll the transcript a page at a time |
Shift+↑ / Shift+↓ |
Scroll the transcript a row at a time |
Ctrl+A / Ctrl+E |
Jump to start / end of line |
Esc |
Stop generation or tool run |
Ctrl+Y |
Copy the last reply to the clipboard |
Ctrl+S |
Hand the mouse back to the terminal, so a drag selects text |
Ctrl+C |
Quit |
| Command | Action |
|---|---|
/plan |
Toggle plan mode — research read-only, then approve the plan |
/permissions |
List saved approval rules and which file each lives in |
/models |
Switch model, provider (tab) and effort (←→) |
/provider |
Pick a configured provider |
/new |
Save this session and start fresh |
/sessions |
List and resume a saved session |
/copy |
Copy to the clipboard — last (default), code, tool or all |
/compact |
Summarize the conversation to free context — /compact <focus> to steer it |
/clear |
Reset conversation |
/exit |
Quit |
Configuration, other backends, and updates
Settings live in ~/.miii/config.json, created on first run:
{
"model": "qwen2.5-coder:14b",
"effort": "medium",
"providers": {
"ollama": { "type": "ollama", "baseUrl": "http://localhost:11434" }
}
}effort (low | medium | high) controls temperature and the output token cap. numCtxCap (default 16384) bounds the context window miii asks for, so a model advertising a 131k window can't make Ollama size a KV cache that eats your RAM — it only ever lowers, never raises. A top-level ollamaHost still works and is folded into the ollama provider on load.
miii talks to any OpenAI-compatible local server too — llama.cpp, LM Studio, vLLM:
{
"model": "qwen2.5-coder-14b",
"provider": "llamacpp",
"providers": {
"llamacpp": { "type": "openai", "baseUrl": "http://localhost:8080" }
}
}Switch at launch with miii --provider llamacpp. Any openai-type provider on localhost counts as local — no key, no cloud.
Updates: miii checks npm on launch and pulls a newer release in the background, applied on next start. miii update to do it now, miii --version to check. Opt out with "autoUpdate": false.
Install failing on permissions? Your global npm prefix isn't writable:
npm config set prefix "$HOME/.npm-global"
export PATH="$HOME/.npm-global/bin:$PATH" # add to ~/.bashrc or ~/.zshrcHow output spill works
When a tool result exceeds the inline budget (~10K bytes), the full output is written to ~/.miii/output/<id>.txt. Only a head + tail preview is inlined, with a pointer:
[This command output was long (412900 bytes), so I'm showing the start and
end. The full text is saved at ~/.miii/output/9f3a1c.txt — read it with
read_file offset/limit to see the middle.]
The model pages through the middle with ranged read_file reads. Spill files are garbage-collected after 24 hours.
Development
src/
├── agent/ # The core reasoning loop, and tool-call repair
├── tools/ # read/write/edit/bash/grep/glob/todos + output spill
├── prompt/ # System prompt and MIII.md project context
├── permissions/ # Approval rules, modes, and how they're scoped
├── commands/ # User-defined slash commands (.miii/commands/*.md)
├── llm/ # Ollama and OpenAI-compatible backends
├── session/ # Saved conversations
├── ui/ # Ink terminal UI and input handling
└── config.ts # Settings and provider resolution
git clone https://github.com/maruakshay/miii-cli.git && cd miii-cli
npm install && npm run devnpm run build # production build
npm run typecheck # type-check src + eval
npm test # unit tests
npm run eval # regression gate (powers `miii doctor`)To run your working tree as the global miii: npm run build && npm link (restore with npm i -g miii-agent).
Does miii work without internet? Yes. Once you've pulled a model with Ollama, miii runs fully offline — no network calls, no account, no cloud.
Is my code sent anywhere? No. Every file read, edit, and inference happens on your machine — privacy is the default, not a setting.
How is miii different from Claude Code, Cursor, or GitHub Copilot? Those are cloud services — metered, account-gated, and they ship your code to a third-party server. miii is open-source, free, and runs entirely on your hardware, with the same terminal-agent workflow.
How is it different from Continue.dev? Continue.dev is an IDE extension. miii is a standalone terminal agent — no editor required.
Which local LLM is best for coding? qwen2.5-coder at the largest size your VRAM allows. Run miii doctor to grade what you have installed.
Do I need a GPU? No, but it helps. Smaller models run on CPU; a GPU makes larger ones fast enough for real work.
MVP. The core agent loop is stable; actively refining tool execution, streaming, and the permission model. PRs welcome.
MIT © maruakshay
Built for engineers who'd rather own their tools than rent them.
