mermaid_cli/cli/args.rs
1use clap::{Parser, Subcommand, ValueEnum};
2use std::path::PathBuf;
3
4use crate::models::ReasoningLevel;
5
6#[derive(Parser, Debug)]
7#[command(name = "mermaid")]
8#[command(version)]
9#[command(about = "An open-source, model-agnostic AI pair programmer", long_about = None)]
10#[command(after_help = TOP_LEVEL_HELP_AFTER)]
11pub struct Cli {
12 /// Model to use (e.g., qwen3-coder:30b, ollama/llama3)
13 #[arg(short, long)]
14 pub model: Option<String>,
15
16 /// Reasoning depth (none, minimal, low, medium, high, max).
17 /// Overrides the persisted default for this session; the slash
18 /// command `/reasoning <level>` and Alt+T can change it at runtime.
19 #[arg(long)]
20 pub reasoning: Option<ReasoningLevel>,
21
22 /// Project directory (defaults to current directory)
23 #[arg(short, long)]
24 pub path: Option<PathBuf>,
25
26 /// Verbose output
27 #[arg(short, long)]
28 pub verbose: bool,
29
30 /// Show session picker to choose a previous conversation
31 #[arg(long, conflicts_with = "continue_session")]
32 pub sessions: bool,
33
34 /// Resume the last conversation instead of starting fresh
35 #[arg(long = "continue", conflicts_with = "sessions")]
36 pub continue_session: bool,
37
38 /// Append every reducer `Msg` to a JSONL file at this path for
39 /// debugging / post-mortem replay. Interactive mode only.
40 #[arg(long, value_name = "FILE")]
41 pub record: Option<PathBuf>,
42
43 /// Replace Mermaid's default system prompt for this invocation
44 #[arg(long, global = true, conflicts_with = "system_prompt_file")]
45 pub system_prompt: Option<String>,
46
47 /// Replace Mermaid's default system prompt with the contents of a file
48 #[arg(
49 long,
50 value_name = "FILE",
51 global = true,
52 conflicts_with = "system_prompt"
53 )]
54 pub system_prompt_file: Option<PathBuf>,
55
56 /// Append extra instructions after Mermaid's system prompt for this invocation
57 #[arg(long, global = true)]
58 pub append_system_prompt: Option<String>,
59
60 /// Append extra instructions from a file after Mermaid's system prompt
61 #[arg(long, value_name = "FILE", global = true)]
62 pub append_system_prompt_file: Option<PathBuf>,
63
64 #[command(subcommand)]
65 pub command: Option<Commands>,
66}
67
68const TOP_LEVEL_HELP_AFTER: &str = "\
69Common first run:
70 mermaid doctor Check model, tools, safety, and project readiness
71 mermaid Start the full-screen terminal coding agent
72 mermaid run \"inspect this repo\" Run one prompt headlessly
73 mermaid self-test Run fast deterministic Mermaid self-tests
74
75Command groups:
76 Everyday: chat, run, doctor, status, list, self-test
77 Model/context: models, model-info, --model, --reasoning, --system-prompt*
78 Safety/recovery: approvals, approve, deny, checkpoints, restore
79 Integrations: add, remove, mcp, cloud-setup, plugin, pr
80 Advanced runtime: daemon, tasks, task, processes, logs, stop, restart, ports, pair";
81
82#[derive(Subcommand, Debug)]
83pub enum Commands {
84 /// Initialize configuration
85 Init,
86 /// List available models
87 List,
88 /// List model/provider capability records
89 Models,
90 /// Show static and cached capability info for a model id
91 ModelInfo {
92 /// Model id, e.g. openai/gpt-5.2
93 model: String,
94 },
95 /// Start a chat session (default)
96 Chat,
97 /// Show version information
98 Version,
99 /// Check status of dependencies and backends
100 Status,
101 /// Check first-run readiness and explain what Mermaid can do now
102 Doctor {
103 /// Output format (text, json, markdown)
104 #[arg(short, long, value_enum, default_value_t = OutputFormat::Text)]
105 format: OutputFormat,
106 },
107 /// Run fast deterministic Mermaid self-tests
108 SelfTest {
109 /// Output format (text, json, markdown)
110 #[arg(short, long, value_enum, default_value_t = OutputFormat::Text)]
111 format: OutputFormat,
112 /// Keep the temporary self-test workspace after the run
113 #[arg(long)]
114 keep_workspace: bool,
115 },
116 /// List durable runtime tasks
117 Tasks {
118 /// Maximum number of tasks to show
119 #[arg(short, long, default_value_t = 20)]
120 limit: usize,
121 },
122 /// Show one durable runtime task and its timeline
123 Task {
124 /// Task id
125 id: String,
126 },
127 /// List Mermaid-managed background processes
128 Processes {
129 /// Maximum number of processes to show
130 #[arg(short, long, default_value_t = 20)]
131 limit: usize,
132 },
133 /// Print a managed process log
134 Logs {
135 /// Process id from `mermaid processes`
136 id: String,
137 },
138 /// Stop a managed process
139 Stop {
140 /// Process id from `mermaid processes`
141 id: String,
142 },
143 /// Restart a managed process
144 Restart {
145 /// Process id from `mermaid processes`
146 id: String,
147 },
148 /// Open a URL, file, or managed process URL
149 Open {
150 /// URL, path, or process id
151 target: String,
152 },
153 /// Show listening TCP ports
154 Ports,
155 /// List pending approvals
156 Approvals,
157 /// Approve a pending approval record
158 Approve {
159 /// Approval id
160 id: String,
161 },
162 /// Deny a pending approval record
163 Deny {
164 /// Approval id
165 id: String,
166 },
167 /// List recent persisted tool runs
168 ToolRuns {
169 /// Maximum number of tool runs to show
170 #[arg(short, long, default_value_t = 20)]
171 limit: usize,
172 },
173 /// List checkpoints
174 Checkpoints {
175 /// Maximum number of checkpoints to show
176 #[arg(short, long, default_value_t = 20)]
177 limit: usize,
178 },
179 /// Restore a checkpoint by id
180 Restore {
181 /// Checkpoint id
182 id: String,
183 },
184 /// List project memory entries
185 Memory {
186 /// Project path, defaults to current directory
187 #[arg(long)]
188 project: Option<PathBuf>,
189 },
190 /// Write a project memory entry
191 Remember {
192 /// Memory key
193 key: String,
194 /// Memory value
195 value: String,
196 /// Project path, defaults to current directory
197 #[arg(long)]
198 project: Option<PathBuf>,
199 },
200 /// Soft-delete a memory entry
201 Forget {
202 /// Memory entry id
203 id: String,
204 },
205 /// Edit an existing memory entry value
206 MemoryEdit {
207 /// Memory entry id
208 id: String,
209 /// New memory value
210 value: String,
211 },
212 /// Manage Mermaid plugin bundles
213 Plugin {
214 #[command(subcommand)]
215 command: PluginCommand,
216 },
217 /// Manage Mermaid's Linux background service
218 Daemon {
219 #[command(subcommand)]
220 command: DaemonCommand,
221 },
222 /// Create a remote pairing token
223 Pair {
224 /// Human label for the remote client
225 #[arg(long)]
226 label: Option<String>,
227 },
228 /// Internal self-QA commands. Hidden from normal help output.
229 #[command(hide = true)]
230 Qa {
231 #[command(subcommand)]
232 command: QaCommand,
233 },
234 /// Add an MCP server (e.g., mermaid add context7)
235 Add {
236 /// MCP server name (e.g., context7, github, filesystem)
237 name: String,
238 },
239 /// Remove a configured MCP server
240 Remove {
241 /// MCP server name to remove
242 name: String,
243 },
244 /// List configured MCP servers
245 Mcp,
246 /// Create a pull/merge request from the current branch via the host CLI
247 /// (`gh` for GitHub, `glab` for GitLab)
248 Pr {
249 #[command(subcommand)]
250 command: PrCommand,
251 },
252 /// Configure Ollama Cloud API key (interactive prompt). Run this
253 /// from your shell before starting mermaid — it reads stdin and
254 /// doesn't work from inside the TUI.
255 CloudSetup,
256 /// Run a single prompt non-interactively
257 Run {
258 /// The prompt to execute
259 prompt: String,
260
261 /// Output format (text, json, markdown)
262 #[arg(short, long, value_enum, default_value_t = OutputFormat::Text)]
263 format: OutputFormat,
264
265 /// Maximum tokens to generate
266 #[arg(long)]
267 max_tokens: Option<usize>,
268
269 /// Don't execute agent actions (dry run)
270 #[arg(long)]
271 no_execute: bool,
272 },
273}
274
275#[derive(Subcommand, Debug)]
276pub enum PluginCommand {
277 /// Install a plugin from a local path
278 Install {
279 /// Path containing plugin.toml
280 path: PathBuf,
281 },
282 /// List installed plugins
283 List,
284 /// Enable an installed plugin
285 Enable {
286 /// Plugin id or name
287 id: String,
288 },
289 /// Disable an installed plugin
290 Disable {
291 /// Plugin id or name
292 id: String,
293 },
294 /// Validate a plugin manifest without installing
295 Audit {
296 /// Path containing plugin.toml
297 path: PathBuf,
298 },
299}
300
301/// Which Git hosting provider's CLI to drive.
302#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
303pub enum GitHost {
304 /// GitHub, via the `gh` CLI.
305 Github,
306 /// GitLab, via the `glab` CLI.
307 Gitlab,
308}
309
310#[derive(Subcommand, Debug)]
311pub enum PrCommand {
312 /// Create a PR/MR from the current branch. Wraps `gh pr create` /
313 /// `glab mr create`, reusing their existing authentication.
314 Create {
315 /// PR/MR title. Omitted → filled from the branch's commits.
316 #[arg(short, long)]
317 title: Option<String>,
318 /// PR/MR body text.
319 #[arg(short, long)]
320 body: Option<String>,
321 /// Read the body from a file (e.g. a saved review summary).
322 #[arg(long, value_name = "FILE", conflicts_with = "body")]
323 summary: Option<PathBuf>,
324 /// Base branch to merge into (defaults to the host's default branch).
325 #[arg(long)]
326 base: Option<String>,
327 /// Open as a draft.
328 #[arg(long)]
329 draft: bool,
330 /// Open the creation page in a browser instead of creating directly.
331 #[arg(long)]
332 web: bool,
333 /// Force a provider instead of auto-detecting from the `origin` remote.
334 #[arg(long, value_enum)]
335 provider: Option<GitHost>,
336 },
337}
338
339#[derive(Subcommand, Debug)]
340pub enum DaemonCommand {
341 /// Install the systemd user service for this user
342 Install {
343 /// Start and enable the service after writing the unit
344 #[arg(long)]
345 start: bool,
346 /// Overwrite an existing Mermaid service unit
347 #[arg(long)]
348 force: bool,
349 },
350 /// Remove the systemd user service for this user
351 Uninstall,
352 /// Start the background user service
353 Start,
354 /// Stop the background user service
355 Stop,
356 /// Restart the background user service
357 Restart,
358 /// Show background service status
359 Status,
360 /// Show background service logs
361 Logs {
362 /// Follow log output
363 #[arg(short, long)]
364 follow: bool,
365 /// Number of log lines to show before following/exiting
366 #[arg(short = 'n', long, default_value_t = 100)]
367 lines: usize,
368 },
369 /// Print the generated service unit without installing it
370 PrintUnit,
371}
372
373#[derive(Subcommand, Debug)]
374pub enum QaCommand {
375 /// Deterministically exercise context compaction without a real model.
376 CompactSmoke {
377 /// Number of synthetic user/assistant turns to seed
378 #[arg(long, default_value_t = 6)]
379 turns: usize,
380 /// Output format
381 #[arg(short, long, value_enum, default_value_t = OutputFormat::Json)]
382 format: OutputFormat,
383 },
384}
385
386#[derive(Debug, Clone, Copy, ValueEnum)]
387pub enum OutputFormat {
388 /// Plain text output
389 Text,
390 /// JSON structured output
391 Json,
392 /// Markdown formatted output
393 Markdown,
394}