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 /// Manage Mermaid plugin bundles
185 Plugin {
186 #[command(subcommand)]
187 command: PluginCommand,
188 },
189 /// Manage Mermaid's Linux background service
190 Daemon {
191 #[command(subcommand)]
192 command: DaemonCommand,
193 },
194 /// Create a remote pairing token
195 Pair {
196 /// Human label for the remote client
197 #[arg(long)]
198 label: Option<String>,
199 },
200 /// Internal self-QA commands. Hidden from normal help output.
201 #[command(hide = true)]
202 Qa {
203 #[command(subcommand)]
204 command: QaCommand,
205 },
206 /// Add an MCP server (e.g., mermaid add context7)
207 Add {
208 /// MCP server name (e.g., context7, github, filesystem)
209 name: String,
210 },
211 /// Remove a configured MCP server
212 Remove {
213 /// MCP server name to remove
214 name: String,
215 },
216 /// List configured MCP servers
217 Mcp,
218 /// Create a pull/merge request from the current branch via the host CLI
219 /// (`gh` for GitHub, `glab` for GitLab)
220 Pr {
221 #[command(subcommand)]
222 command: PrCommand,
223 },
224 /// Configure Ollama Cloud API key (interactive prompt). Run this
225 /// from your shell before starting mermaid — it reads stdin and
226 /// doesn't work from inside the TUI.
227 CloudSetup,
228 /// Run a single prompt non-interactively
229 Run {
230 /// The prompt to execute
231 prompt: String,
232
233 /// Output format (text, json, markdown)
234 #[arg(short, long, value_enum, default_value_t = OutputFormat::Text)]
235 format: OutputFormat,
236
237 /// Maximum tokens to generate
238 #[arg(long)]
239 max_tokens: Option<usize>,
240
241 /// Don't execute agent actions (dry run)
242 #[arg(long)]
243 no_execute: bool,
244 },
245}
246
247#[derive(Subcommand, Debug)]
248pub enum PluginCommand {
249 /// Install a plugin from a local path
250 Install {
251 /// Path containing plugin.toml
252 path: PathBuf,
253 },
254 /// List installed plugins
255 List,
256 /// Enable an installed plugin
257 Enable {
258 /// Plugin id or name
259 id: String,
260 },
261 /// Disable an installed plugin
262 Disable {
263 /// Plugin id or name
264 id: String,
265 },
266 /// Validate a plugin manifest without installing
267 Audit {
268 /// Path containing plugin.toml
269 path: PathBuf,
270 },
271}
272
273/// Which Git hosting provider's CLI to drive.
274#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
275pub enum GitHost {
276 /// GitHub, via the `gh` CLI.
277 Github,
278 /// GitLab, via the `glab` CLI.
279 Gitlab,
280}
281
282#[derive(Subcommand, Debug)]
283pub enum PrCommand {
284 /// Create a PR/MR from the current branch. Wraps `gh pr create` /
285 /// `glab mr create`, reusing their existing authentication.
286 Create {
287 /// PR/MR title. Omitted → filled from the branch's commits.
288 #[arg(short, long)]
289 title: Option<String>,
290 /// PR/MR body text.
291 #[arg(short, long)]
292 body: Option<String>,
293 /// Read the body from a file (e.g. a saved review summary).
294 #[arg(long, value_name = "FILE", conflicts_with = "body")]
295 summary: Option<PathBuf>,
296 /// Base branch to merge into (defaults to the host's default branch).
297 #[arg(long)]
298 base: Option<String>,
299 /// Open as a draft.
300 #[arg(long)]
301 draft: bool,
302 /// Open the creation page in a browser instead of creating directly.
303 #[arg(long)]
304 web: bool,
305 /// Force a provider instead of auto-detecting from the `origin` remote.
306 #[arg(long, value_enum)]
307 provider: Option<GitHost>,
308 },
309}
310
311#[derive(Subcommand, Debug)]
312pub enum DaemonCommand {
313 /// Install the systemd user service for this user
314 Install {
315 /// Start and enable the service after writing the unit
316 #[arg(long)]
317 start: bool,
318 /// Overwrite an existing Mermaid service unit
319 #[arg(long)]
320 force: bool,
321 },
322 /// Remove the systemd user service for this user
323 Uninstall,
324 /// Start the background user service
325 Start,
326 /// Stop the background user service
327 Stop,
328 /// Restart the background user service
329 Restart,
330 /// Show background service status
331 Status,
332 /// Show background service logs
333 Logs {
334 /// Follow log output
335 #[arg(short, long)]
336 follow: bool,
337 /// Number of log lines to show before following/exiting
338 #[arg(short = 'n', long, default_value_t = 100)]
339 lines: usize,
340 },
341 /// Print the generated service unit without installing it
342 PrintUnit,
343}
344
345#[derive(Subcommand, Debug)]
346pub enum QaCommand {
347 /// Deterministically exercise context compaction without a real model.
348 CompactSmoke {
349 /// Number of synthetic user/assistant turns to seed
350 #[arg(long, default_value_t = 6)]
351 turns: usize,
352 /// Output format
353 #[arg(short, long, value_enum, default_value_t = OutputFormat::Json)]
354 format: OutputFormat,
355 },
356}
357
358#[derive(Debug, Clone, Copy, ValueEnum)]
359pub enum OutputFormat {
360 /// Plain text output
361 Text,
362 /// JSON structured output
363 Json,
364 /// Markdown formatted output
365 Markdown,
366}