Headless Mitii CLI over @mitii/sdk -> @mitii/v8 (with @mitii/host for indexing, checkpoints, memory, and skills).
npm install -g @mitii/cli
# or
npx @mitii/cli --helpRequires Node.js 20+ (Discord/Slack bridges need Node 22+ for built-in WebSocket). Native dependency: better-sqlite3 (optional LanceDB for vectors). License: AGPL-3.0-or-later.
Published from this monorepo on v* release tags. For local development:
pnpm --filter @mitii/cli build
node apps/cli/bin/mitii.js --helpLegacy npm @mitii/cli@2.7.x is a different binary stack - prefer versions published from this tree.
mitii --help # or: mitii -h
mitii setup # pick provider + write .mitii/config.json
export ANTHROPIC_API_KEY=... # or GEMINI_ / OPENAI_ / MITII_API_KEY
mitii session # dotted MITII banner + interactive loopSmoke without a live model:
mitii ask "What is recursion?" --echo
# Deterministic prep / SARIF only (no LLM):
mitii review --preview
mitii review --from main --to HEAD --format sarif --output review.sarif
# LLM findings (read-only ask + review skill):
mitii ask "Review the working-tree changes" --mode ask --skill code-review-and-quality --echoCheck what is configured (never prints secrets):
mitii setup --show
mitii -v # or: mitii --version / mitii versionmitii ask "What is recursion?" --echo
mitii run --auto "run tests and fix failures" --echo
mitii index
mitii status --json
mitii session
mitii export-session "Summarize this repo" --out session.json --echo| Command | Behavior |
|---|---|
setup |
Interactive (or flag-driven) model/provider setup |
ask <prompt> |
SDK ask with streaming, cancel, clarify/approve |
commit-message |
Draft commit message (auto-attaches git-commit-message) |
pr-summary |
Draft PR body (auto-attaches git-pr-summary) |
changelog |
Draft Keep a Changelog entry (auto-attaches release-changelog) |
run --auto "<task>" |
Unattended CI run (agent + apply autonomy; no prompts) |
session |
Interactive prompt loop with MITII banner |
index |
Full workspace index + publish repository state |
review |
Deterministic review prep / SARIF (--preview, --from/--to, --commit, --format, --output). For LLM findings use mitii ask … --skill code-review-and-quality (recipe/skill) or the VS Code Review button for working-tree changes |
status |
Show latest persisted repository state |
export-session |
Run ask and write secret-free JSON export |
connect |
Bridge Mitii into Telegram, Discord, or Slack |
schedule |
CRUD / trigger / history for automation schedules |
serve |
Long-lived automation daemon (+ optional webhook ingress) |
events |
Ingest / list automation events (GitHub webhooks, etc.) |
version / help |
Version and usage (-v / --version, -h / --help) |
These gather git status/diff/log and force-attach the matching bundled skill:
mitii commit-message
mitii pr-summary
mitii changelog
# equivalent:
mitii ask --recipe commit-messageOptional note after the command becomes a user hint on the prompt.
Shareable RecipeSpec documents (schemaVersion: 1) under .mitii/recipes/<id>.json.
They compile to prompt / mode / skills / autonomy only — never widen ToolGrant.
mitii recipe run after-commit --param task="write tests and open a PR"
mitii recipe run commit-message --preview # compile only
mitii recipe run .mitii/recipes/smoke.json --param word=hi --echoBuilt-in writing recipe ids (commit-message, pr-summary, changelog) also work as recipe run targets.
mitii connect runs a long-lived bridge from a chat channel into Mitii agent turns
(same SDK path as mitii ask / mitii session). The process stays in the foreground
until you stop it.
mitii connect # list installed adapters
mitii connect <channel> --help # channel-specific options
mitii connect --stop # stop all running connectors for this cwd
mitii connect <channel> --stop # stop one channelNo - not as a connect adapter. Connectors are chat surfaces (Telegram, Discord, Slack).
GitHub is different:
| Need | Use |
|---|---|
| Chat with Mitii from phone / Discord / Slack | mitii connect telegram|discord|slack |
PRs, issues, gh / git in a repo |
Run Mitii in the repo (--cwd) with --mode agent; install gh on that machine if you want PR tooling |
| Bot that replies on PR / issue comments | Not a connect channel - use agent mode + gh, or a future issue-bot adapter |
| Channel | Command | Transport |
|---|---|---|
| Telegram | mitii connect telegram |
Bot API long-poll |
| Discord | mitii connect discord |
Bot gateway (WebSocket) |
| Slack | mitii connect slack |
Socket Mode (WebSocket) |
-
Configure a real model (not echo), unless you are smoke-testing with
--echo:mitii setup --provider anthropic --yes # or ollama / gemini / ... export ANTHROPIC_API_KEY=... # matching provider key
-
Prefer indexing the workspace once (ask/connect will auto-index if needed):
mitii index --cwd /path/to/repo
-
Run
connectwith that workspace as--cwdso tools and project rules apply to the right tree.
| Flag | Meaning |
|---|---|
--cwd <path> |
Workspace root (default: current directory) |
--mode ask|plan|agent |
Same modes as CLI (ask default - safest for chat) |
--echo |
Force Echo LLM (local smoke, no API key) |
--approve |
Auto-approve mutation/plan gates (default for connectors) |
--deny |
Do not auto-approve; suspended turns stop instead |
--allowed-user-id <id> |
Allowlist platform user id (repeatable). Recommended |
--stop |
Stop a running connector for this channel/cwd |
-h, --help |
Channel help |
| Command | Effect |
|---|---|
/help |
Short connector help + mode/cwd |
/new |
Clear this thread's Mitii conversation carry |
/whereami |
Print channel / user ids, cwd, mode |
Ordinary text becomes one Mitii turn; the reply is posted back to the same chat/thread.
History is kept per thread under .mitii/connectors/<channel>/.
- Open Telegram and chat with @BotFather.
- Send
/newbot, follow the prompts, copy the bot token (123456:ABC...). - Optional:
/setprivacy-> Disable if the bot should see all group messages (DMs work either way).
export TELEGRAM_BOT_TOKEN='123456:ABC...'cd /path/to/repo
mitii connect telegram --token "$TELEGRAM_BOT_TOKEN"
# or omit --token when TELEGRAM_BOT_TOKEN is set
mitii connect telegram \
--mode ask \
--allowed-user-id 123456789Telegram-only flags: --token / -t, --bot-username / -u.
- Start once, send
/whereamiin chat, noteuserId=.... - Restart with
--allowed-user-id <that id>.
Ctrl-C
# or
mitii connect telegram --stop- Open the Discord Developer Portal -> New Application.
- Open Bot -> Add Bot -> Reset Token -> copy the bot token.
- Under Privileged Gateway Intents, enable Message Content Intent (required to read message text).
- Open OAuth2 -> URL Generator:
- Scopes:
bot - Bot permissions: at least Send Messages, Read Message History, View Channels
- Scopes:
- Open the generated URL, invite the bot to your server.
export DISCORD_BOT_TOKEN='your-bot-token'cd /path/to/repo
mitii connect discord --token "$DISCORD_BOT_TOKEN"
mitii connect discord \
--mode ask \
--allowed-user-id 987654321012345678Discord-only flags: --token / -t (or DISCORD_BOT_TOKEN).
Behavior:
- DMs - every message is handled (subject to allowlist).
- Guild channels - the bot only replies when @mentioned.
- Enable Discord Developer Mode (Settings -> Advanced -> Developer Mode).
- Right-click your avatar -> Copy User ID, or send
/whereamito the bot. - Restart with
--allowed-user-id <id>.
Ctrl-C
# or
mitii connect discord --stopSlack uses Socket Mode (no public webhook URL).
- Open api.slack.com/apps -> Create New App -> From scratch.
- Socket Mode -> enable -> create an App-Level Token with scope
connections:write-> copyxapp-.... - OAuth & Permissions -> Bot Token Scopes, add at least:
chat:writechannels:historygroups:historyim:historympim:historyapp_mentions:read(optional, useful in channels)
- Event Subscriptions -> enable -> subscribe the bot to:
message.immessage.channels(and/ormessage.groupsas needed)
- Install App to your workspace -> copy the Bot User OAuth Token
xoxb-.... - Invite the bot to the channel:
/invite @YourBot.
export SLACK_BOT_TOKEN='xoxb-...'
export SLACK_APP_TOKEN='xapp-...'cd /path/to/repo
mitii connect slack \
--bot-token "$SLACK_BOT_TOKEN" \
--app-token "$SLACK_APP_TOKEN"
mitii connect slack \
--mode ask \
--allowed-user-id U012ABCDEFSlack-only flags: --bot-token, --app-token (or the env vars above).
- Start once and send
/whereamiin a DM or channel with the bot. - Note
userId=U...and restart with--allowed-user-id U....
Ctrl-C
# or
mitii connect slack --stopUnder the workspace:
.mitii/connectors/telegram/<botUsername>.json
.mitii/connectors/telegram/<botUsername>.threads.json
.mitii/connectors/discord/default.json
.mitii/connectors/discord/default.threads.json
.mitii/connectors/slack/default.json
.mitii/connectors/slack/default.threads.json
Safe to delete *.threads.json to reset history. Tokens are not written to these files.
- The channel delivers an inbound message.
- Allowlist / slash commands are handled locally.
- Mitii runs
createCliClient+driveRun(same engine asmitii ask). result.answeris posted back (chunked if long).- Conversation carry is saved for the next message in that thread.
- Prefer
--mode askunless you intentionally want edits. - Always set
--allowed-user-idfor personal bots. - Use
--cwdpointing only at the repo you intend to expose. --approveis on by default for connectors (no TTY for y/n). Use--denyif you want suspensions to stop instead of mutating.- Keep bot / app tokens in the environment - never commit them.
| Symptom | What to try |
|---|---|
| Missing token errors | Set the channel env var or pass the matching --token / --bot-token / --app-token |
already running pid=... |
mitii connect <channel> --stop then start again |
| Echo / stub answers | Configure provider + API key; drop --echo |
| Unauthorized... | Your user id is not on --allowed-user-id |
| Telegram ignores group messages | BotFather -> /setprivacy -> Disable, or @mention the bot |
| Discord ignores guild messages | Enable Message Content Intent; @mention the bot |
| Slack not receiving events | Socket Mode on; app installed; bot invited; event subscriptions saved |
requires Node.js with global WebSocket |
Use Node 22+ (Discord/Slack bridges use the built-in WebSocket) |
| No repo context / weak tools | mitii index --cwd ... then restart connect with that --cwd |
| Mode | Behavior |
|---|---|
ask |
Q&A / explain (default) |
plan |
Read-only plan; no file edits |
agent |
Edit + verify with approvals |
Set with --mode <mode> or defaultMode in config.
| Option | Meaning |
|---|---|
-h, --help |
Show usage |
-v, --version |
Print package version |
--cwd <path> |
Workspace root (default: process.cwd()) |
--json |
Machine-readable JSON on stdout |
--stream-json |
NDJSON: one { type: "event", event } line per RunEvent, then { type: "result", result } |
--echo |
Force EchoLlmPort even when API keys are set |
--clarify <text> |
Non-interactive clarification resume |
--approve / --deny |
Non-interactive approval resume |
--out <file> |
Session export path (export-session) |
--mode <mode> |
ask | plan | agent |
--origin <o> |
user | automation | api (unattended policy) |
--autonomy <a> |
readonly | propose | apply | apply_and_pr |
--agent <id|path> |
Load .mitii/agents/<id>.md or a markdown path |
--prompt-file <path> |
Prompt from file (- = stdin) |
--loop-policy-json <json> |
Lab: one-off threshold overrides for this run |
--no-loop-policy |
Ignore config loopPolicy for this run |
Unknown options error out (they are not silently ignored).
SIGINT cancels the active run via run.cancel().
By default the CLI uses window-band standards from the model context window
(compact < 50k, standard < 100k, wide >= 100k). Permanent ship values live in
@mitii/v8 -> policy/loopPolicyBands.ts.
Optional lab overrides (same merge as VS Code Developer -> Custom loop policy):
{
"provider": "ollama",
"model": "qwen3-coder:30b",
"loopPolicy": {
"enabled": true,
"thresholds": {
"maxReadOnlyToolTurnsBeforeMutationNudge": 14,
"maxRejectedMutationRecoveries": 5
}
}
}# One-off override (merged on top of config when enabled)
mitii ask "Fix types" --mode agent \
--loop-policy-json '{"maxRejectedMutationRecoveries":5}'
# Force shipped bands only for this run
mitii ask "Fix types" --mode agent --no-loop-policyLeave loopPolicy unset (or "enabled": false) for deploy / normal use.
| Option | Meaning |
|---|---|
--show |
Print current config (no secrets) |
--provider <id> |
ollama, anthropic, gemini, openai, deepseek, ... |
--model <id> |
Model id |
--base-url <url> |
OpenAI-compatible base URL |
--global |
Write ~/.mitii/config.json instead of project .mitii/ |
--test |
Probe the provider after writing |
--yes / -y |
Non-interactive (requires --provider) |
# Local Ollama
mitii setup --provider ollama --yes
# Claude, then set the key in the shell
mitii setup --provider anthropic --model claude-sonnet-4-5 --yes
export ANTHROPIC_API_KEY=sk-ant-...
# Custom OpenAI-compatible gateway
mitii setup --provider openai-compatible --base-url http://localhost:1234/v1 --model local-model --yes --testKeys go in the environment. Provider and model go in .mitii/config.json or ~/.mitii/config.json (prefer mitii setup).
# Anthropic (Claude)
export ANTHROPIC_API_KEY=sk-ant-...
mitii ask "What is recursion?"{ "provider": "anthropic", "model": "claude-sonnet-4-5" }# Gemini
export GEMINI_API_KEY=...
# DeepSeek (OpenAI-compatible)
export MITII_API_KEY=...
# OpenAI
export OPENAI_API_KEY=sk-...{ "provider": "gemini", "model": "gemini-2.5-flash" }{
"provider": "openai-compatible",
"providerPreset": "deepseek",
"model": "deepseek-chat",
"baseUrl": "https://api.deepseek.com/v1"
}{
"provider": "openai-compatible",
"baseUrl": "http://localhost:11434/v1",
"model": "qwen3-coder:30b"
}Overrides: MITII_PROVIDER, MITII_MODEL, MITII_BASE_URL, MITII_API_KEY.
Local Ollama / LM Studio do not need a key. Anthropic and Gemini do.
Optional. When configured, the CLI injects a SearchPort so Decision Policy can grant web_search (and content-aware fetch_url) for live-web asks. Prefer free self-hosted SearXNG; Brave / Tavily are paid fallbacks.
Option A — project or global config (wins over env):
# Project (cwd)
mkdir -p .mitii
cat > .mitii/config.json <<'EOF'
{
"provider": "echo",
"searxngBaseUrl": "http://192.168.0.91:8888"
}
EOF
# Or merge into an existing config (keep your provider/model fields):
# "searxngBaseUrl": "http://127.0.0.1:8080"Global alternative: ~/.mitii/config.json with the same searxngBaseUrl field. Project config is tried first.
Option B — environment (used when config has no searxngBaseUrl):
export SEARXNG_BASE_URL=http://192.168.0.91:8888
# or
export MITII_SEARXNG_URL=http://192.168.0.91:8888Optional paid providers (same search-kit chain as VS Code):
export BRAVE_API_KEY=... # or MITII_SEARCH_API_KEY
export TAVILY_API_KEY=...
# optional order:
export MITII_SEARCH_PROVIDERS=searxng,brave,tavilyDefault order when unset: SearXNG (if URL) → Brave (if key) → Tavily (if key).
-
Base URL only — no
/searchpath. Mitii appends/search?format=json. -
Enable JSON in SearXNG settings (
formatsmust includejson). Smoke test:curl -sS 'http://192.168.0.91:8888/search?q=test&format=json' | head
-
LAN / localhost hosts are allowed for the configured SearXNG base URL.
mitii ask "Search the web for Next.js 15 error boundaries"Explicit phrases like “search the web for …” grant web_search when a provider is configured. Security asks such as “check vulnerabilities online …” also grant it. Without any provider, Mitii continues from model knowledge and omits SearchPort.
Cursor Cloud Agents are a separate agent API, not an LLM endpoint. Point openai-compatible at any /v1/chat/completions proxy if you need a custom gateway.
mitii session prints a dotted MITII banner, then workspace / provider / mode, and the mitii> prompt. If you are still on the echo stub, it points you at mitii setup.
| Symptom | What to try |
|---|---|
| Echo / stub answers only | mitii setup, then export the matching API key |
unknown option |
Typos fail loudly - run mitii --help |
| Index falls back to snapshot | Optional native deps / embeddings; ask still works with host snapshot |
| No repository state | mitii index, or let ask / connect auto-index |
| Wrong model | mitii setup --show, then mitii setup again |
| Connect / Telegram issues | See Connect -> Troubleshooting above |
Daemon and board UIs are not part of this CLI yet (Phase 1+). Channel bridges are
Telegram, Discord, and Slack via mitii connect. GitHub work uses the repo +
tools/gh, not a connect adapter (see Connect above).
Phase 0 CI automation works today: --origin / --autonomy / --agent /
mitii run --auto, plus optional .mitii/safety.json (tighten-only) and
MITII_SANDBOX=1 (OS process sandbox, fail-closed). See
docs/SAFETY_PHASES.md.
--prompt-file plus the example workflows under
docs/examples/workflows/mitii-*.yml. See
docs/automation/README.md.
pnpm --filter @mitii/cli typecheck
pnpm --filter @mitii/cli test
pnpm --filter @mitii/cli build
node apps/cli/bin/mitii.js ask "ping" --echo --json
node apps/cli/bin/mitii.js setup --show- Repo: Mitii-dev/Mitii
- SDK:
@mitii/sdk - Host kit:
@mitii/host