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 /// Update Mermaid to the latest release
100 Update {
101 /// Only report whether an update is available; don't install it
102 #[arg(long)]
103 check: bool,
104 /// Reinstall even if already on the latest version
105 #[arg(long)]
106 force: bool,
107 },
108 /// Check status of dependencies and backends
109 Status,
110 /// Check first-run readiness and explain what Mermaid can do now
111 Doctor {
112 /// Output format (text, json, markdown)
113 #[arg(short, long, value_enum, default_value_t = OutputFormat::Text)]
114 format: OutputFormat,
115 },
116 /// Run fast deterministic Mermaid self-tests
117 SelfTest {
118 /// Output format (text, json, markdown)
119 #[arg(short, long, value_enum, default_value_t = OutputFormat::Text)]
120 format: OutputFormat,
121 /// Keep the temporary self-test workspace after the run
122 #[arg(long)]
123 keep_workspace: bool,
124 },
125 /// List durable runtime tasks
126 Tasks {
127 /// Maximum number of tasks to show
128 #[arg(short, long, default_value_t = 20)]
129 limit: usize,
130 },
131 /// Show one durable runtime task and its timeline
132 Task {
133 /// Task id
134 id: String,
135 },
136 /// List Mermaid-managed background processes
137 Processes {
138 /// Maximum number of processes to show
139 #[arg(short, long, default_value_t = 20)]
140 limit: usize,
141 },
142 /// Print a managed process log
143 Logs {
144 /// Process id from `mermaid processes`
145 id: String,
146 },
147 /// Stop a managed process
148 Stop {
149 /// Process id from `mermaid processes`
150 id: String,
151 },
152 /// Restart a managed process
153 Restart {
154 /// Process id from `mermaid processes`
155 id: String,
156 },
157 /// Open a URL, file, or managed process URL
158 Open {
159 /// URL, path, or process id
160 target: String,
161 },
162 /// Show listening TCP ports
163 Ports,
164 /// List pending approvals
165 Approvals,
166 /// Approve a pending approval record
167 Approve {
168 /// Approval id
169 id: String,
170 },
171 /// Deny a pending approval record
172 Deny {
173 /// Approval id
174 id: String,
175 },
176 /// List recent persisted tool runs
177 ToolRuns {
178 /// Maximum number of tool runs to show
179 #[arg(short, long, default_value_t = 20)]
180 limit: usize,
181 },
182 /// List checkpoints
183 Checkpoints {
184 /// Maximum number of checkpoints to show
185 #[arg(short, long, default_value_t = 20)]
186 limit: usize,
187 },
188 /// Restore a checkpoint by id
189 Restore {
190 /// Checkpoint id
191 id: String,
192 },
193 /// Manage Mermaid plugin bundles
194 Plugin {
195 #[command(subcommand)]
196 command: PluginCommand,
197 },
198 /// Manage Mermaid's Linux background service
199 Daemon {
200 #[command(subcommand)]
201 command: DaemonCommand,
202 },
203 /// Create a remote pairing token
204 Pair {
205 /// Human label for the remote client
206 #[arg(long)]
207 label: Option<String>,
208 },
209 /// Internal self-QA commands. Hidden from normal help output.
210 #[command(hide = true)]
211 Qa {
212 #[command(subcommand)]
213 command: QaCommand,
214 },
215 /// Add an MCP server (e.g., mermaid add context7)
216 Add {
217 /// MCP server name (e.g., context7, github, filesystem)
218 name: String,
219 },
220 /// Remove a configured MCP server
221 Remove {
222 /// MCP server name to remove
223 name: String,
224 },
225 /// List configured MCP servers
226 Mcp,
227 /// Create a pull/merge request from the current branch via the host CLI
228 /// (`gh` for GitHub, `glab` for GitLab)
229 Pr {
230 #[command(subcommand)]
231 command: PrCommand,
232 },
233 /// Configure Ollama Cloud API key (interactive prompt). Run this
234 /// from your shell before starting mermaid — it reads stdin and
235 /// doesn't work from inside the TUI.
236 CloudSetup,
237 /// Run a single prompt non-interactively
238 Run {
239 /// The prompt to execute
240 prompt: String,
241
242 /// Output format (text, json, markdown)
243 #[arg(short, long, value_enum, default_value_t = OutputFormat::Text)]
244 format: OutputFormat,
245
246 /// Maximum tokens to generate
247 #[arg(long)]
248 max_tokens: Option<usize>,
249
250 /// Don't execute agent actions (dry run)
251 #[arg(long)]
252 no_execute: bool,
253 },
254}
255
256#[derive(Subcommand, Debug)]
257pub enum PluginCommand {
258 /// Install a plugin from a local path
259 Install {
260 /// Path containing plugin.toml
261 path: PathBuf,
262 },
263 /// List installed plugins
264 List,
265 /// Enable an installed plugin
266 Enable {
267 /// Plugin id or name
268 id: String,
269 },
270 /// Disable an installed plugin
271 Disable {
272 /// Plugin id or name
273 id: String,
274 },
275 /// Validate a plugin manifest without installing
276 Audit {
277 /// Path containing plugin.toml
278 path: PathBuf,
279 },
280}
281
282/// Which Git hosting provider's CLI to drive.
283#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
284pub enum GitHost {
285 /// GitHub, via the `gh` CLI.
286 Github,
287 /// GitLab, via the `glab` CLI.
288 Gitlab,
289}
290
291#[derive(Subcommand, Debug)]
292pub enum PrCommand {
293 /// Create a PR/MR from the current branch. Wraps `gh pr create` /
294 /// `glab mr create`, reusing their existing authentication.
295 Create {
296 /// PR/MR title. Omitted → filled from the branch's commits.
297 #[arg(short, long)]
298 title: Option<String>,
299 /// PR/MR body text.
300 #[arg(short, long)]
301 body: Option<String>,
302 /// Read the body from a file (e.g. a saved review summary).
303 #[arg(long, value_name = "FILE", conflicts_with = "body")]
304 summary: Option<PathBuf>,
305 /// Base branch to merge into (defaults to the host's default branch).
306 #[arg(long)]
307 base: Option<String>,
308 /// Open as a draft.
309 #[arg(long)]
310 draft: bool,
311 /// Open the creation page in a browser instead of creating directly.
312 #[arg(long)]
313 web: bool,
314 /// Force a provider instead of auto-detecting from the `origin` remote.
315 #[arg(long, value_enum)]
316 provider: Option<GitHost>,
317 },
318}
319
320#[derive(Subcommand, Debug)]
321pub enum DaemonCommand {
322 /// Install the systemd user service for this user
323 Install {
324 /// Start and enable the service after writing the unit
325 #[arg(long)]
326 start: bool,
327 /// Overwrite an existing Mermaid service unit
328 #[arg(long)]
329 force: bool,
330 },
331 /// Remove the systemd user service for this user
332 Uninstall,
333 /// Start the background user service
334 Start,
335 /// Stop the background user service
336 Stop,
337 /// Restart the background user service
338 Restart,
339 /// Show background service status
340 Status,
341 /// Show background service logs
342 Logs {
343 /// Follow log output
344 #[arg(short, long)]
345 follow: bool,
346 /// Number of log lines to show before following/exiting
347 #[arg(short = 'n', long, default_value_t = 100)]
348 lines: usize,
349 },
350 /// Print the generated service unit without installing it
351 PrintUnit,
352}
353
354#[derive(Subcommand, Debug)]
355pub enum QaCommand {
356 /// Deterministically exercise context compaction without a real model.
357 CompactSmoke {
358 /// Number of synthetic user/assistant turns to seed
359 #[arg(long, default_value_t = 6)]
360 turns: usize,
361 /// Output format
362 #[arg(short, long, value_enum, default_value_t = OutputFormat::Json)]
363 format: OutputFormat,
364 },
365}
366
367#[derive(Debug, Clone, Copy, ValueEnum)]
368pub enum OutputFormat {
369 /// Plain text output
370 Text,
371 /// JSON structured output
372 Json,
373 /// Markdown formatted output
374 Markdown,
375}