mirocode 0.14.3 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +113 -120
  2. package/README.zh.md +113 -120
  3. package/dist/cli.js +288 -434
  4. package/package.json +11 -18
package/README.md CHANGED
@@ -5,8 +5,8 @@
5
5
  <h1 align="center">Miro</h1>
6
6
 
7
7
  <p align="center">
8
- A terminal client for ACP-compatible coding agents.<br>
9
- Interactive TUI and one-shot print mode, built with Bun, React, and Ink.
8
+ A terminal coding agent with its own tool loop.<br>
9
+ Interactive TUI and one-shot print mode, built with Bun.
10
10
  </p>
11
11
 
12
12
  <p align="center">
@@ -17,12 +17,12 @@
17
17
 
18
18
  ---
19
19
 
20
- **miro-cli** includes a built-in agent that calls Chat Completions, OpenAI Responses, or Anthropic Messages directly with its own tool loop. Use `--acp <provider-id>` only when you want to start an [Agent Client Protocol](https://agentclientprotocol.com/) provider as a child process over stdio JSON-RPC.
20
+ **miro-cli** calls Chat Completions, OpenAI Responses, or Anthropic Messages directly and runs its own agent and tool loop in-process.
21
21
 
22
22
  ## Requirements
23
23
 
24
24
  - [Bun](https://bun.sh/) **>= 1.4.3**, or Node **>= 22.7** for the npm package
25
- - An API endpoint for Miro's built-in agent; an ACP binary on `PATH` is needed only for `--acp` (see [ACP providers](#acp-providers))
25
+ - A compatible LLM API endpoint
26
26
 
27
27
  ## Install and run
28
28
 
@@ -67,7 +67,6 @@ echo "Summarize this input" | miro -p
67
67
  miro -p --output-format json "Fix the tests"
68
68
  miro --model hy3
69
69
  miro --effort high
70
- miro --acp claude
71
70
  miro --continue
72
71
  miro --resume <session-id>
73
72
  ./dist/miro -c <session-id>
@@ -82,73 +81,91 @@ bun start -- -p "Analyze this project"
82
81
 
83
82
  ### Options
84
83
 
85
- | Flag | Description |
86
- |------|-------------|
87
- | `-p`, `--print` | Run one non-interactive request and exit |
88
- | `--output-format <text\|json>` | Print-mode output (requires `--print`) |
89
- | `--acp <provider-id>` | Start this available ACP provider by id; otherwise use Miro's built-in agent |
90
- | `--model <model>` | Model by value or display name (interactive and print modes) |
91
- | `--effort <level>` | Effort by value or display name (interactive and print modes; not saved) |
92
- | `-c`, `--continue [id]` | Resume a session; omit `id` to use the latest for this project |
93
- | `--resume <id>` | Resume the given session id |
94
- | `--permission-mode <m>` | miro permission mode: `auto` (default) or `manual` |
95
- | `--mode <mode>` | Interaction mode: `default` or `plan` |
96
- | `-h`, `--help` | Print help |
97
-
98
- `--output-format` is only valid with `-p` / `--print`; `--acp`, `--model`, and `--effort` also work when starting the interactive TUI and apply only to this run. `--acp` accepts only an available ACP provider id; the removed `--provider` flag reports a migration error. A bare prompt without `--print` is an error. `-c` without an id continues the latest session for the selected mode (and ACP id); `--resume` always requires an id.
84
+ | Flag | Description |
85
+ | ------------------------------ | ---------------------------------------------------------------------------- |
86
+ | `-p`, `--print` | Run one non-interactive request and exit |
87
+ | `--output-format <text\|json>` | Print-mode output (requires `--print`) |
88
+ | `--model <model>` | Model by value or display name (interactive and print modes) |
89
+ | `--effort <level>` | Effort by value or display name (interactive and print modes; not saved) |
90
+ | `-c`, `--continue [id]` | Resume a session; omit `id` to use the latest for this project |
91
+ | `--resume <id>` | Resume the given session id |
92
+ | `--permission-mode <m>` | miro permission mode: `auto` (default) or `manual` |
93
+ | `--mode <mode>` | Interaction mode: `default` or `plan` |
94
+ | `-h`, `--help` | Print help |
95
+
96
+ `--output-format` is only valid with `-p` / `--print`; `--model` and `--effort` also work when starting the interactive TUI and apply only to this run. A bare prompt without `--print` is an error. `-c` without an id continues the latest session for the current project; `--resume` always requires an id.
97
+
98
+ ## ACP clients
99
+
100
+ Miro can serve [Agent Client Protocol v1](https://agentclientprotocol.com/protocol/v1/session-setup) over stdio. Configure the same `~/.miro/models.json` or `~/.miro/settings.json` used by the standalone CLI, then connect with tico:
101
+
102
+ ```bash
103
+ tico --agent "miro acp"
104
+ # From a checkout (use absolute paths when tico runs in another directory):
105
+ tico --agent "bun /absolute/path/to/miro/src/main.ts acp"
106
+ ```
107
+
108
+ To use `tico --acp miro`, add this entry to `~/.tico/acp.json`:
109
+
110
+ ```json
111
+ {
112
+ "miro": { "command": "miro", "args": ["acp"] }
113
+ }
114
+ ```
115
+
116
+ `miro acp` accepts `--model`, `--effort`, `--permission-mode auto|manual`, and `--mode default|plan`. The client supplies the working directory and manages prompts and session restoration. ACP supports streaming replies and reasoning, tool progress, manual permission requests, embedded file context, model/configuration changes, cancellation, and saved session listing/loading/resuming. Miro uses its own tools and MCP configuration and also accepts stdio or HTTP MCP servers supplied by the client. Protocol messages use stdout; diagnostics use stderr.
99
117
 
100
118
  ## Commands
101
119
 
102
120
  Type these in the interactive composer:
103
121
 
104
- | Command | Description |
105
- |---------|-------------|
106
- | `/init [extra]` | Analyze the codebase and create or improve `AGENTS.md` |
107
- | `/model [model]` | Select or switch model |
108
- | `/effort [level]` | Set the current model's effort level |
109
- | `/config [id] [val]` | View or change ACP session config options |
110
- | `/thinking [mode]` | Set thinking display to `compact` (default), `full`, or `hidden`; no mode opens a picker |
111
- | `/permissions [mode]` | miro permission mode: `auto` (default) or `manual`; no mode opens a picker |
112
- | `/plan [on\|off\|status]` | Enter, leave, or inspect Plan Mode (miro only) |
113
- | `/statusline [reset]` | Configure status-line items, order, and colors |
114
- | `/review [text]` | Review code changes; with no argument opens a picker (uncommitted, branch, commit, or custom instructions) |
115
- | `/goal [text]` | Work toward an objective across as many turns as it takes until the model reports it done or blocked; while a response is running, a new objective safely interrupts it and takes over. No text shows the current goal; `replace`, `status`, `pause`, `resume`, and `cancel` manage it (miro only). |
116
- | `/simplify [text]` | Simplify code while preserving behavior; accepts paths or free-form instructions |
117
- | `/commit [text]` | Create one commit from the current changes; optional text guides the message |
118
- | `/commit-push-pr` | Create one commit, push the branch to `origin`, and open a pull request with the CLI for that host (`gh`, `glab`, or `tea`) |
119
- | `/resume [id]` | Resume a saved session; no id opens the picker |
120
- | `/continue [id]` | Alias for `/resume` |
121
- | `/new` | New session without clearing the terminal |
122
- | `/sessions` | List saved sessions for the current project |
123
- | `/clear` | New ACP session and clear the terminal display and visible transcript |
124
- | `/compact [text]` | Summarize earlier context while keeping recent history; optional text guides the summary |
125
- | `/export [file]` | Export the conversation (clipboard or `.txt` file) |
126
- | `/help` | Show help |
127
- | `/exit` | Exit (`exit`, `/quit`, `quit`) and print the session usage summary |
128
- | `!<command>` | Run a local shell command; output is attached to the next prompt |
129
-
130
- Provider-specific slash commands advertised by ACP are forwarded as-is.
122
+ | Command | Description |
123
+ | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
124
+ | `/init [extra]` | Analyze the codebase and create or improve `AGENTS.md` |
125
+ | `/model [model]` | Select or switch model |
126
+ | `/effort [level]` | Set the current model's effort level |
127
+ | `/config [id] [val]` | View or change model, runtime, and prompt-language options |
128
+ | `/thinking [mode]` | Set thinking display to `compact` (default), `full`, or `hidden`; no mode opens a picker |
129
+ | `/permissions [mode]` | miro permission mode: `auto` (default) or `manual`; no mode opens a picker |
130
+ | `/plan [on\|off\|status]` | Enter, leave, or inspect Plan Mode (miro only) |
131
+ | `/statusline [reset]` | Configure status-line items, order, and colors |
132
+ | `/review [text]` | Review code changes; with no argument opens a picker (uncommitted, branch, commit, or custom instructions) |
133
+ | `/goal [text]` | Work toward an objective across as many turns as it takes until the model reports it done or blocked; while a response is running, a new objective safely interrupts it and takes over. No text shows the current goal; `replace`, `status`, `pause`, `resume`, and `cancel` manage it (miro only). |
134
+ | `/simplify [text]` | Simplify code while preserving behavior; accepts paths or free-form instructions |
135
+ | `/commit [text]` | Create one commit from the current changes; optional text guides the message |
136
+ | `/commit-push-pr` | Create one commit, push the branch to `origin`, and open a pull request with the CLI for that host (`gh`, `glab`, or `tea`) |
137
+ | `/resume [id]` | Resume a saved session; no id opens the picker |
138
+ | `/continue [id]` | Alias for `/resume` |
139
+ | `/new` | New session without clearing the terminal |
140
+ | `/sessions` | List saved sessions for the current project |
141
+ | `/clear` | New session and clear the terminal display and visible transcript |
142
+ | `/compact [text]` | Summarize earlier context while keeping recent history; optional text guides the summary |
143
+ | `/export [file]` | Export the conversation (clipboard or `.txt` file) |
144
+ | `/help` | Show help |
145
+ | `/exit` | Exit (`exit`, `/quit`, `quit`) and print the session usage summary |
146
+ | `!<command>` | Run a local shell command; output is attached to the next prompt |
131
147
 
132
148
  `/commit-push-pr` reads the `origin` remote and picks the matching CLI: `gh` on GitHub, `glab` on GitLab, `tea` on Gitea or Forgejo. When that CLI is missing, unauthenticated, or the host has none at all (Bitbucket, an unrecognised self-hosted instance), it still commits and pushes, then reports the URL for opening the pull request by hand instead of inventing one. A repository with no `origin` remote stops after the local commit.
133
149
 
134
- While a turn is running, Enter steers the built-in Miro agent and Tab queues a prompt for the next turn. Steering waits for the current model response and tools to finish, then continues the same task; pending steering stays visible until it enters the model history. Normal, Plan, and Goal conversations support steering. ACP, isolated workflows such as `/review` and `/commit`, and standalone compaction fall back to FIFO queuing. Unapplied steering after interruption, failure, or session recovery pauses sending: open Ctrl+Q and press `r` to resume, or edit/delete the messages. Slash commands keep their existing dispatch rules. `!command` is refused while busy.
150
+ While a turn is running, Enter steers the built-in Miro agent and Tab queues a prompt for the next turn. Steering waits for the current model response and tools to finish, then continues the same task; pending steering stays visible until it enters the model history. Normal, Plan, and Goal conversations support steering. Isolated workflows such as `/review` and `/commit`, and standalone compaction fall back to FIFO queuing. Unapplied steering after interruption, failure, or session recovery pauses sending: open Ctrl+Q and press `r` to resume, or edit/delete the messages. Slash commands keep their existing dispatch rules. `!command` is refused while busy.
135
151
 
136
152
  ## Shortcuts
137
153
 
138
- | Key | Action |
139
- |-----|--------|
140
- | Enter | Send the prompt; steer the current task while supported |
141
- | Tab | Queue a prompt while running; completion takes priority |
142
- | Shift+Enter | Insert a newline (Miro enables Kitty and xterm extended-key reporting; unsupported terminals still cannot distinguish it from Enter) |
143
- | `?` | Shortcut cheatsheet (empty composer) |
144
- | ↑ / ↓ | Input history or completion |
145
- | Ctrl+M | Select or switch model (needs a terminal that supports the kitty keyboard protocol, otherwise the key is the same as Enter) |
146
- | Shift+Tab | Cycle interaction mode (`Default` / `Plan`) |
147
- | Ctrl+O | Open the full-screen Review window: live and retained thinking, shell output, and tool details |
148
- | Ctrl+Q | Review pending steering and edit, reorder, or remove queued messages; `r` resumes paused sending |
149
- | Ctrl+L | Clear the terminal display (not the ACP session) |
150
- | Ctrl+C | Clear the input draft; on an empty input, cancel the turn and press again within 2 seconds to exit. Any normal exit — this one, `/exit`, or a bare `exit`/`quit` — prints a one-line session usage summary, e.g. `Stat ↑12.4k ↓2.1k R84.3k W6.2k CH81.9% $0.018`: ↑/↓ are the session totals of input and output tokens, `R`/`W` the cache read and write tokens (the segment is added once the session has a cache reading; the direction with no reading is shown as 0), `CH` the cache hit rate (read / (uncached input + read + write)), and the trailing amount the session cost (three decimals below one unit, four below a tenth of a cent — miro adds main-loop requests and compaction summaries, ACP uses the agent's cumulative `usage_update` cost). The line is omitted entirely when the provider never reported usage or cost |
151
- | Esc | Close shortcut help, or interrupt a running turn |
154
+ | Key | Action |
155
+ | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
156
+ | Enter | Send the prompt; steer the current task while supported |
157
+ | Tab | Queue a prompt while running; completion takes priority |
158
+ | Shift+Enter | Insert a newline (Miro enables Kitty and xterm extended-key reporting; unsupported terminals still cannot distinguish it from Enter) |
159
+ | `?` | Shortcut cheatsheet (empty composer) |
160
+ | ↑ / ↓ | Input history or completion |
161
+ | Ctrl+M | Select or switch model (needs a terminal that supports the kitty keyboard protocol, otherwise the key is the same as Enter) |
162
+ | Shift+Tab | Cycle interaction mode (`Default` / `Plan`) |
163
+ | Ctrl+O | Open the full-screen Review window: live and retained thinking, shell output, and tool details |
164
+ | Ctrl+Q | Review pending steering and edit, reorder, or remove queued messages; `r` resumes paused sending |
165
+ | Ctrl+L | Clear the terminal display (not the session) |
166
+ | Ctrl+Z | Suspend miro to the background (macOS/Linux); `fg` resumes it and redraws the screen |
167
+ | Ctrl+C | Clear the input draft; on an empty input, cancel the turn and press again within 2 seconds to exit. Any normal exit — this one, `/exit`, or a bare `exit`/`quit` — prints a one-line session usage summary, e.g. `Stat ↑12.4k ↓2.1k R84.3k W6.2k CH81.9% $0.018`: ↑/↓ are the session totals of input and output tokens, `R`/`W` the cache read and write tokens (the segment is added once the session has a cache reading; the direction with no reading is shown as 0), `CH` the cache hit rate (read / (uncached input + read + write)), and the trailing amount the session cost (three decimals below one unit, four below a tenth of a cent — miro adds main-loop requests and compaction summaries). The line is omitted entirely when no usage or cost has been reported |
168
+ | Esc | Close shortcut help, or interrupt a running turn |
152
169
 
153
170
  `@` completes file paths (`git ls-files`, with a filesystem fallback). Multiline pastes stay a single submission: they are collapsed while editing and restored to their original text in the transcript after submission.
154
171
 
@@ -156,37 +173,17 @@ While a turn is running, Enter steers the built-in Miro agent and Tab queues a p
156
173
 
157
174
  Agent replies are rendered as Markdown in the terminal: headings, lists, tables, fenced code blocks, and inline code are styled, and `$...$` / `$$...$$` math is rendered with Unicode glyphs. Unterminated math delimiters in a stream are passed through verbatim until the turn ends, and unsupported LaTeX is left as plain text. This is display-only — your message text is never altered.
158
175
 
159
- Thinking uses three disclosure levels. While a block is streaming, miro extracts a leading `**bold title**` when available and keeps the activity line stable. That live line also carries the timing and, once the provider has reported usage, the token counts, e.g. `Thinking… (12s · ↑5 ↓2.9k)`: input and output from the provider's latest reading — each miro LLM call, or the ACP `PromptResponse` usage at the end of a turn. Providers that never report usage leave the hint out. Finalized blocks follow the persisted `thinkingDisplay` setting: `compact` keeps a title-and-duration summary, `full` also prints the Markdown body, and `hidden` leaves it out of the visible transcript. `/thinking` opens the picker; `/thinking compact|full|hidden` applies a mode directly. Ctrl+O opens a full-screen review browser for the live thinking block, the live shell output, and everything retained in the transcript: the list selects an item with ↑/↓ and opens its detail with Enter, and Left/Right inside a detail moves to the previous or next item of that list.
176
+ Thinking uses three disclosure levels. The default `compact` mode shows a leading `**bold title**`, when available, only in the live activity area; finalized thinking adds no `Thought:` rows to terminal history or exports. `full` also previews the live body and prints the title, duration, and Markdown body when a block is finalized. `hidden` suppresses the title and body, leaving only a generic live thinking status. Thinking in `compact` or `hidden` does not split consecutive light-tool groups. Empty planning placeholders leave no thinking history rows. The live line shows elapsed thinking time and an estimated output-token count based on streamed text, e.g. `Thinking… (12s · ↓2.9k)`; without text, it falls back to the model's latest usage reading when available.
160
177
 
161
- Visible thinking blocks retain only metadata; Miro model-context checkpoints also omit raw reasoning and thinking blocks. Raw `agent_thought_chunk` messages are also omitted from ACP traffic logs by default; set `"recordRawThinking": true` in `~/.miro/settings.json` only when those sensitive details are intentionally needed for debugging.
178
+ `/thinking` opens the picker; `/thinking compact|full|hidden` changes the current and subsequent thinking blocks, not blocks already finalized in `full`. Existing `compact` summaries are omitted when history is restored or redrawn. Ctrl+O opens a full-screen review browser for live thinking, live shell output, and retained thinking and tool details, including thinking hidden from terminal history: select with ↑/↓, open with Enter, and use Left/Right inside a detail to switch entries. Thinking details remain available only while retained in the current process. Saved sessions keep thinking metadata, not the raw body; Miro model-context checkpoints likewise omit raw reasoning and thinking blocks.
162
179
 
163
- ## ACP providers
180
+ ## Built-in agent
164
181
 
165
- Miro uses its built-in agent by default. Start an ACP provider explicitly with `miro --acp <id>`; its binary must be on `PATH`. Add or override ACP definitions in `~/.miro/acp.json`, whose top level maps each id to `{ command | bin, args, name, sessionMeta }`:
182
+ Miro calls an LLM API directly, runs its own tool loop (`read_file`, `write_file`, `edit_file`, `terminal`, `grep`, `glob`, `spawn_agent`, `update_tasks`). It supports OpenAI Chat Completions (the default), OpenAI Responses, and Anthropic Messages. It is always available, with no binary to install. Long conversations are compacted automatically; when that happens, both the transcript and the model see a `Context compacted` notice.
166
183
 
167
- ```json
168
- {
169
- "knot": { "command": "knot-cli", "args": ["acp"] },
170
- "my-cursor": { "command": "cursor-agent", "args": ["acp"], "name": "Cursor (work)" }
171
- }
172
- ```
173
-
174
- Miro stores an ACP provider's last `/model` and `/effort` choice as `model` / `effort` in that same entry. The `providers` object in `~/.miro/settings.json` is no longer read.
175
-
176
- | Id | Name | Binary |
177
- |----|------|--------|
178
- | `pi` | Pi | `pi-acp` |
179
- | `cursor` | Cursor | `cursor-agent` |
180
- | `claude` | Claude | `claude-agent-acp` |
181
- | `codex` | Codex | `codex-acp` |
184
+ Commands whose output is a report — `/review`, `/simplify`, `/commit`, `/commit-push-pr`, and `/init` — run in a **separate context**. Their prompt (rubric, pre-read git context, your instructions) and every file the model reads while working stay in a history built for that one run; only a one-line record of the command (added when the run starts) and its final answer are appended to the session. A review that read fifty files therefore stops crowding out the conversation, while the answer still lands in the transcript, so a follow-up like "fix the second finding" still has something to point at. `Esc` cancels the run: the command's record and whatever was already streamed stay in the session, matching what the transcript shows, so a resumed session sees the same history.
182
185
 
183
- ### Built-in agent
184
-
185
- Miro's built-in agent does not start a child process or speak ACP: it calls an LLM API directly, runs its own tool loop (`read_file`, `write_file`, `edit_file`, `terminal`, `grep`, `glob`, `spawn_agent`, `update_tasks`), and emits the same events as ACP clients. It supports OpenAI Chat Completions (the default), OpenAI Responses, and Anthropic Messages. It is always available, with no binary to install. Long conversations are compacted automatically; when that happens, both the transcript and the model see a `Context compacted` notice.
186
-
187
- Commands whose output is a report — `/review`, `/simplify`, `/commit`, `/commit-push-pr`, and `/init` — run in a **separate context**. Their prompt (rubric, pre-read git context, your instructions) and every file the model reads while working stay in a history built for that one run; only a one-line record of the command (added when the run starts) and its final answer are appended to the session. A review that read fifty files therefore stops crowding out the conversation, while the answer still lands in the transcript, so a follow-up like "fix the second finding" still has something to point at. `Esc` cancels the run: the command's record and whatever was already streamed stay in the session, matching what the transcript shows, so a resumed session sees the same history. This is miro-only: an ACP provider keeps its conversation history inside the provider process, where miro can neither isolate nor trim it, so the same commands run as ordinary turns there and stay in the conversation.
188
-
189
- Use `/compact` while idle, or `/compact preserve the migration decisions` to guide the summary. It uses the current model, keeps the visible transcript, and saves the compacted model context for session resume. It works even when automatic compaction is disabled. Press `Esc` to cancel without replacing history; insufficient history is a no-op. Pause an active goal first. Print mode also supports `miro -c <session-id> -p "/compact"`, with progress on stderr. For ACP, the command is forwarded only when the provider advertises support.
186
+ Use `/compact` while idle, or `/compact preserve the migration decisions` to guide the summary. It uses the current model, keeps the visible transcript, and saves the compacted model context for session resume. It works even when automatic compaction is disabled. Press `Esc` to cancel without replacing history; insufficient history is a no-op. Pause an active goal first. Print mode also supports `miro -c <session-id> -p "/compact"`, with progress on stderr.
190
187
 
191
188
  List miro LLM endpoints in `~/.miro/models.json`. `/model` reloads this file, so edits apply without restarting:
192
189
 
@@ -197,10 +194,7 @@ List miro LLM endpoints in `~/.miro/models.json`. `/model` reloads this file, so
197
194
  "baseUrl": "http://localhost:11434/v1",
198
195
  "api": "openai-completions",
199
196
  "apiKey": "ollama",
200
- "models": [
201
- { "id": "llama3.1:8b" },
202
- { "id": "qwen2.5-coder:7b" }
203
- ]
197
+ "models": [{ "id": "llama3.1:8b" }, { "id": "qwen2.5-coder:7b" }]
204
198
  }
205
199
  }
206
200
  }
@@ -229,21 +223,21 @@ If `models.json` is missing or has no usable models, miro falls back to the `mir
229
223
  }
230
224
  ```
231
225
 
232
- | Field | Default | Notes |
233
- |-------|---------|-------|
234
- | `protocol` | `chat-completions` | Fallback when `models.json` is unused: `chat-completions`, `openai-responses`, or `anthropic-messages`. Also configurable with `$MIRO_PROTOCOL`. Catalog models carry their own `api` instead. |
235
- | `baseUrl` | Protocol-specific default | Chat Completions / Responses default to `https://api.openai.com/v1`; Anthropic Messages defaults to `https://api.anthropic.com`. `$MIRO_BASE_URL` overrides it. Catalog `baseUrl` wins for models listed in `models.json`. |
236
- | `apiKey` | `$MIRO_API_KEY`, then protocol-specific key | Uses `$ANTHROPIC_API_KEY` for Anthropic Messages and `$OPENAI_API_KEY` for the two OpenAI protocols. In `models.json`, `apiKey` may also be `$ENV` or `!command`. |
237
- | `models` | `gpt-4o-mini`, `gpt-4o`, `deepseek-chat` | Used only when `~/.miro/models.json` has no usable entries. Strings, or `{ id, name, contextWindow }` entries. |
238
- | `model` / `effort` / `thinking` | first model / `medium` / `true` | Fallback defaults; the top-level `model` / `effort` preference takes precedence when it matches an available option. Same `/model`, `/effort`, and `/config` flows as ACP providers. |
239
- | `maxToolRounds` | unlimited | Maximum tool-loop rounds per turn. There is no default cap because auto compaction already bounds the context; set a number to stop a runaway turn. |
240
- | `temperature` | unset | Sampling temperature passed to the API. |
241
- | `permissionMode` | `auto` | `auto` never asks the user; only Terminal calls with `risk_level: high` or `sandbox: false` receive an isolated model review, while all other tools run directly. `manual` confirms writes and commands. Unknown values and legacy `ask`, `plan`, or `yolo` fall back to `auto`. |
242
- | `sandbox.enabled` | `false` | When `true`, the `terminal` tool runs commands inside the `@anthropic-ai/sandbox-runtime` network sandbox: no network unless `allowedDomains` grants it per call. The tool keeps its name in both modes and only gains the sandbox-only parameters. Filesystem access still uses host permissions. Requires the platform prerequisites of `@anthropic-ai/sandbox-runtime`; it never falls back to an unrestricted shell. |
226
+ | Field | Default | Notes |
227
+ | ------------------------------- | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
228
+ | `protocol` | `chat-completions` | Fallback when `models.json` is unused: `chat-completions`, `openai-responses`, or `anthropic-messages`. Also configurable with `$MIRO_PROTOCOL`. Catalog models carry their own `api` instead. |
229
+ | `baseUrl` | Protocol-specific default | Chat Completions / Responses default to `https://api.openai.com/v1`; Anthropic Messages defaults to `https://api.anthropic.com`. `$MIRO_BASE_URL` overrides it. Catalog `baseUrl` wins for models listed in `models.json`. |
230
+ | `apiKey` | `$MIRO_API_KEY`, then protocol-specific key | Uses `$ANTHROPIC_API_KEY` for Anthropic Messages and `$OPENAI_API_KEY` for the two OpenAI protocols. In `models.json`, `apiKey` may also be `$ENV` or `!command`. |
231
+ | `models` | `gpt-4o-mini`, `gpt-4o`, `deepseek-chat` | Used only when `~/.miro/models.json` has no usable entries. Strings, or `{ id, name, contextWindow }` entries. |
232
+ | `model` / `effort` / `thinking` | first model / `medium` / `true` | Fallback defaults; the top-level `model` / `effort` preference takes precedence when it matches an available option. Change these with `/model`, `/effort`, and `/config`. |
233
+ | `maxToolRounds` | unlimited | Maximum tool-loop rounds per turn. There is no default cap because auto compaction already bounds the context; set a number to stop a runaway turn. |
234
+ | `temperature` | unset | Sampling temperature passed to the API. |
235
+ | `permissionMode` | `auto` | `auto` never asks the user; only Terminal calls with `risk_level: high` or `sandbox: false` receive an isolated model review, while all other tools run directly. `manual` confirms writes and commands. Unknown values and legacy `ask`, `plan`, or `yolo` fall back to `auto`. |
236
+ | `sandbox.enabled` | `false` | When `true`, the `terminal` tool runs commands inside the `@anthropic-ai/sandbox-runtime` network sandbox: no network unless `allowedDomains` grants it per call. The tool keeps its name in both modes and only gains the sandbox-only parameters. Filesystem access still uses host permissions. Requires the platform prerequisites of `@anthropic-ai/sandbox-runtime`; it never falls back to an unrestricted shell. |
243
237
 
244
238
  Use `/config sandbox on` or `/config sandbox off` to update this setting and switch the command tool's sandboxing in the current session.
245
239
 
246
- `/model` and `/effort` choices are remembered per provider. Miro uses top-level `model` / `effort` in `settings.json`, and records the model as `provider/id`; an ACP provider keeps its own entry in `~/.miro/acp.json`. The `model` / `effort` entries inside `miro` are fallback defaults when the top-level preference is absent or unavailable. Miro's `Default` / `Plan` interaction mode is independent from its `Auto` / `Manual` permission mode; `Shift+Tab` cycles the interaction mode.
240
+ `/model` and `/effort` choices are saved as top-level `model` / `effort` in `settings.json`; models are recorded as `provider/id`. The `model` / `effort` entries inside `miro` are fallback defaults when the top-level preference is absent or unavailable. Miro's `Default` / `Plan` interaction mode is independent from its `Auto` / `Manual` permission mode; `Shift+Tab` cycles the interaction mode.
247
241
 
248
242
  ### Codemode (experimental)
249
243
 
@@ -251,7 +245,7 @@ Codemode is off by default and available only to the built-in Miro agent. Use `/
251
245
 
252
246
  The model can compose reads, searches, paging and aggregation in one JavaScript script inside an isolated QuickJS Worker, returning only selected output to its context. Scripts can call `read_file`, `grep`, `glob` and configured MCP bridges. They have no host `process`, `fetch`, file writes, Terminal or subagent access. Each actual MCP call still follows the normal permission policy, including denial in non-interactive Manual mode, and internal calls remain visible in the transcript.
253
247
 
254
- Each script has a 60-second VM limit, a 64 MiB QuickJS heap, at most 64 tool calls and eight concurrent reads, with separate tool-data and output budgets. Scripts must await their calls. Cancellation and timeout wait for host cleanup but cannot undo remote effects; failed scripts are never automatically replayed. See the [tool reference](./docs/tools/codemode.md) for the exact API and limits. This is separate from the Terminal sandbox and does not change ACP providers.
248
+ Each script has a 60-second VM limit, a 64 MiB QuickJS heap, at most 64 tool calls and eight concurrent reads, with separate tool-data and output budgets. Scripts must await their calls. Cancellation and timeout wait for host cleanup but cannot undo remote effects; failed scripts are never automatically replayed. See the [tool reference](./docs/tools/codemode.md) for the exact API and limits. This is separate from the Terminal sandbox.
255
249
 
256
250
  ### MCP
257
251
 
@@ -288,8 +282,6 @@ Sign-in follows the server's `WWW-Authenticate` resource metadata URL. Scopes co
288
282
 
289
283
  **Only configure servers you trust.** Discovery may start local processes even in Manual mode. Actual MCP invocations require Manual approval scoped to the server, tool and complete arguments; non-interactive Manual runs deny them. Auto runs MCP calls without prompts or Terminal safety review. MCP is outside the Terminal sandbox. Cancelling or timing out does not guarantee that remote effects were undone; calls are never automatically replayed. Keep `settings.json` private; tool arguments and results are still session data.
290
284
 
291
- ACP sessions receive the trusted configured servers, but the external agent owns connections, permissions and OAuth. HTTP entries are skipped with a diagnostic unless the agent advertises support. Miro's ACP traffic log redacts MCP connection configuration; the external agent still receives the credentials and may keep its own logs.
292
-
293
285
  ### Skills
294
286
 
295
287
  Miro supports the `SKILL.md` convention (Agent Skills). Skills are discovered at startup from `<cwd>/.miro/skills`, `<cwd>/.agents/skills`, `~/.miro/skills`, and `~/.agents/skills`, in that priority order. Extra directories go in a top-level `skills` array in `~/.miro/settings.json`; `"skills": false` turns the feature off. A directory containing `SKILL.md` is one skill and is not scanned any deeper, while a bare `*.md` file counts only when its frontmatter has a `description`. When two skills share a name, the higher priority root wins (explicit paths take precedence over default roots), and the shadowed file is reported in the client's diagnostics.
@@ -305,13 +297,11 @@ miro -p "/skill:pdf extract the tables from invoice.pdf"
305
297
 
306
298
  `disable-model-invocation: true` keeps a skill out of the model-visible catalog while leaving `/skill:` available for hand-picked use. Skills only add instructions — they never add capabilities: Manual approval and Auto's Terminal review policy remain unchanged.
307
299
 
308
- This is miro-only. ACP providers own their skills, and any command they advertise (for example `skill:<name>`) reaches miro as a normal provider command.
309
-
310
300
  ## Sessions and context
311
301
 
312
302
  Miro saves model-context checkpoints alongside the visible transcript, including compaction summaries and complete tool-call/result pairs. Resume uses the latest valid checkpoint rather than replaying the pre-compaction transcript; sessions without checkpoints fall back to visible messages. Checkpoints contain conversation and tool data, so keep session files private.
313
303
 
314
- Visible transcripts are stored at `~/.miro/sessions/<flattened-cwd>/<acp|miro>/<sessionId>.jsonl` and can be resumed with `/resume`, `--continue`, or `--resume`. Raw ACP traffic is isolated under `<flattened-cwd>/acp/raw/`, so it cannot collide with the resumable transcript for the same session ID. The project directory name is the cwd with every non-alphanumeric character collapsed to `-` (no hash, so it stays readable). Raw thinking chunks are omitted unless `recordRawThinking` is explicitly enabled. Persistence errors are non-fatal; older transcript layouts are not read. A visible session is identified by its runtime **and** its session ID. `/resume`, `/sessions`, and `--continue` show only sessions for the current startup mode; to resume an ACP transcript, restart with that transcript's `--acp <id>`. Empty conversations leave nothing behind: the transcript file (and its runtime directory) is created only when the first user or assistant message is recorded, and zero-message transcripts are not listed by `/resume`, `/sessions`, or `--continue` (raw ACP traffic logs are exempt — they still start as soon as the session opens).
304
+ Visible transcripts are stored at `~/.miro/sessions/<flattened-cwd>/miro/<sessionId>.jsonl` and can be resumed with `/resume`, `--continue`, or `--resume`. Each non-alphanumeric cwd character becomes `-`, with no hash. Persistence errors are non-fatal. Only sessions in this directory are read; other layouts and removed external-agent sessions are ignored, and existing files are left untouched. Empty conversations create no files: storage starts with the first user or assistant message, and zero-message sessions are excluded from the list.
315
305
 
316
306
  `~/.miro/AGENTS.md` and `./AGENTS.md` are loaded at startup (blank or unreadable files skipped; identical text deduplicated) and sent with the **first ordinary prompt**. Resumed sessions skip AGENTS.md reinjection. A failed first request restores injection so you can retry.
317
307
 
@@ -319,16 +309,16 @@ Composer history is independent of the transcript, at `~/.miro/history.jsonl`.
319
309
 
320
310
  ## Configuration
321
311
 
322
- Model, effort, prompt-language, and status-line preferences live in `~/.miro/settings.json`; ACP provider definitions and their own `model` / `effort` preferences live in `~/.miro/acp.json`. A legacy top-level `provider` value in `settings.json` is ignored, as is its `providers` object. Miro LLM endpoints and models are imported only from `~/.miro/models.json`. `/config` changes both the live ACP options advertised as `configOptions` and miro's own `language` option.
312
+ Model, effort, prompt-language, and status-line preferences live in `~/.miro/settings.json`. Configure LLM services and the model catalog in `~/.miro/models.json`; an absent catalog falls back to `settings.miro`. `/config` changes model and runtime options and the local prompt language.
323
313
 
324
314
  ### Permission mode
325
315
 
326
316
  Miro offers `Auto` and `Manual`, with `Auto` as the default. `/permissions` selects a mode directly or opens a picker; this setting is independent from Plan Mode.
327
317
 
328
- | Mode | Behavior |
329
- |------|----------|
330
- | `auto` | Default. Never opens a user approval prompt. Non-Terminal tools run directly; Terminal is auto-reviewed only for `risk_level: high` or `sandbox: false` |
331
- | `manual` | Writes, edits, deletes, moves, and commands need approval; read, search, and task updates run directly |
318
+ | Mode | Behavior |
319
+ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
320
+ | `auto` | Default. Never opens a user approval prompt. Non-Terminal tools run directly; Terminal is auto-reviewed only for `risk_level: high` or `sandbox: false` |
321
+ | `manual` | Writes, edits, deletes, moves, and commands need approval; read, search, and task updates run directly |
332
322
 
333
323
  `Auto` does not parse Terminal command text, so `rm`, `curl`, redirection, interpreters, and heredocs have no special lexical rules; `low` and `medium` run directly. For `high` or `sandbox: false`, it projects user intent, earlier tool calls, and the proposed action (including the model's optional `risk_reason`, treated as an untrusted self-report) to an isolated classifier with no tools, never tool results. Only an explicit approval runs the command. A block, error, or uncertain result is returned directly to the next model round without asking the user. The verdict shows on the tool row, and a block spells out the reviewer's reason there.
334
324
 
@@ -348,7 +338,7 @@ Plan Mode separates investigation and design from implementation. Enter it with
348
338
 
349
339
  In either interactive mode, the agent can ask up to four structured questions with single-select or multi-select answers, optional Markdown previews, custom text, and notes. In Plan Mode it then submits the canonical file for review. Approving freezes that exact text, returns to Default Mode, and starts a fresh implementation turn from the frozen snapshot. Requesting changes keeps Plan Mode active; rejecting exits without implementation. Plan state is persisted with the session. Plan Mode cannot start while a goal is actively running. Non-interactive runs and subagents never expose the question UI.
350
340
 
351
- `miro -p --mode plan "Design this change"` is intentionally non-interactive: it prints a plan and exits without asking questions, opening approval UI, or implementing the result. ACP providers keep their own mode behavior.
341
+ `miro -p --mode plan "Design this change"` is intentionally non-interactive: it prints a plan and exits without asking questions, opening approval UI, or implementing the result.
352
342
 
353
343
  ### Spinner verbs
354
344
 
@@ -356,7 +346,10 @@ The waiting-verb animation on the status line is customizable via `spinnerVerbs`
356
346
 
357
347
  ```json
358
348
  {
359
- "spinnerVerbs": { "mode": "append", "verbs": ["thinking", "planning", "searching"] }
349
+ "spinnerVerbs": {
350
+ "mode": "append",
351
+ "verbs": ["thinking", "planning", "searching"]
352
+ }
360
353
  }
361
354
  ```
362
355
 
@@ -364,17 +357,17 @@ The waiting-verb animation on the status line is customizable via `spinnerVerbs`
364
357
 
365
358
  ### Prompt language
366
359
 
367
- `/config language English` (or `en`, `en-us`), `/config language Chinese` (or `zh`, `zh-cn`, `中文`) or `/config language Cantonese` (or `yue`, `zh-hk`, `zh-yue`, `粤语`, `粵語`) sets the language of miro's own built-in workflow prompts (`/init`, `/review`, `/simplify`, `/commit`, and `/commit-push-pr`) and saves it as `language` in `~/.miro/settings.json`. English is the default, and unknown values fall back to it. The ACP session config and your own messages are untouched; the prompt text itself lives under `src/commands/prompts/<language>/`, so adding a language means adding a directory there.
360
+ `/config language English` (or `en`, `en-us`), `/config language Chinese` (or `zh`, `zh-cn`, `中文`) or `/config language Cantonese` (or `yue`, `zh-hk`, `zh-yue`, `粤语`, `粵語`) sets the language of miro's own built-in workflow prompts (`/init`, `/review`, `/simplify`, `/commit`, and `/commit-push-pr`) and saves it as `language` in `~/.miro/settings.json`. English is the default, and unknown values fall back to it. Your own messages are untouched.
368
361
 
369
362
  ### Status line
370
363
 
371
- `/statusline` picks items, order, and colors interactively. `/statusline reset` restores the defaults. Confirming writes `statusLine` and `statusLineUseColors` together.
364
+ `/statusline` picks items, order, and colors interactively. It uses a monochrome palette by default; colors can be enabled. `/statusline reset` restores the defaults. Confirming writes `statusLine` and `statusLineUseColors` together.
372
365
 
373
366
  Default items: `["model-with-reasoning", "current-dir"]`. An empty array hides the status line. Unknown ids are ignored (one-time warning); items without data are skipped.
374
367
 
375
- While a goal exists, the right end of the same line shows `◎ /goal active (4s)`: the goal's status plus how long it has actually been running (paused time and time after it stopped are not counted, matching the budget). It is not a configurable item — it appears and disappears with the goal — and the ACP provider, which has no goal mode, never shows it. An empty status line hides it along with the rest of the bar.
368
+ While a goal exists, the right end of the same line shows `◎ /goal active (4s)`: the goal's status plus how long it has actually been running (paused time and time after it stopped are not counted, matching the budget). It is not a configurable item — it appears and disappears with the goal. An empty status line hides it along with the rest of the bar.
376
369
 
377
- Available ids include `model`, `model-with-reasoning`, `reasoning`, `mode`, `permission-mode`, `current-dir`, `project-name`, `hostname`, `git-branch`, `run-state`, `provider`, `session-id`, `session-title`, `miro-version`, `context-used`, `context-remaining`, `context-window-size`, `task-progress`, `goal`, `used-tokens`, `input-tokens`, `output-tokens`, `thought-tokens`, and `session-cost`. Context, token, cost, and session-title items need the provider to report them. `used-tokens`, `input-tokens`, `output-tokens`, `thought-tokens`, and `session-cost` are session totals — miro adds each main-loop LLM request and compaction summary (subagent runs are not counted), ACP uses the agent's cumulative `PromptResponse` snapshot (and its cumulative `usage_update` cost) — so they can exceed the latest-reading hint on the activity line. `permission-mode` shows `AUTO` or `MANUAL` for the miro provider, and stays hidden when no miro permission mode is available. `goal` shows the active goal's status and progress, and stays hidden without a goal — the ACP provider has no goal mode, so it is always hidden there. These ids also accept short aliases: `model-name` (`model`), `permissions` (`permission-mode`), `project` / `project-root` (`project-name`), `status` (`run-state`), `thread-id` / `thread-title` (`session-id`), `version` (`miro-version`), `context-usage` (`context-used`), `goal-status` (`goal`).
370
+ Available ids include `model`, `model-with-reasoning`, `reasoning`, `mode`, `permission-mode`, `current-dir`, `project-name`, `hostname`, `git-branch`, `run-state`, `session-id`, `session-title`, `miro-version`, `context-used`, `context-remaining`, `context-window-size`, `task-progress`, `goal`, `used-tokens`, `input-tokens`, `output-tokens`, `thought-tokens`, and `session-cost`. Context, token, cost, and session-title items need the agent or model to report them. `used-tokens`, `input-tokens`, `output-tokens`, `thought-tokens`, and `session-cost` are session totals — miro adds each main-loop LLM request and compaction summary (subagent runs are not counted) — so they can exceed the latest-reading hint on the activity line. `permission-mode` shows `AUTO` or `MANUAL` for the agent, and stays hidden when no miro permission mode is available. `goal` shows the active goal's status and progress, and stays hidden without a goal. These ids also accept short aliases: `model-name` (`model`), `permissions` (`permission-mode`), `project` / `project-root` (`project-name`), `status` (`run-state`), `thread-id` / `thread-title` (`session-id`), `version` (`miro-version`), `context-usage` (`context-used`), `goal-status` (`goal`).
378
371
 
379
372
  ## License
380
373