Skip to main content

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}