Skip to main content

ralph/cli/
args.rs

1//! Top-level Clap argument definitions for `ralph`.
2//!
3//! Responsibilities:
4//! - Define the root `Cli` parser and the top-level command enum.
5//! - Keep top-level command documentation and long-help text together.
6//! - Re-export the small `cli-spec` format args used by the machine/app tooling.
7//!
8//! Not handled here:
9//! - Command execution logic.
10//! - Shared queue/list helper functions.
11//! - Parse-regression tests.
12//!
13//! Invariants/assumptions:
14//! - Subcommands validate their own inputs and config dependencies.
15//! - CLI parsing happens after argument normalization in `main`.
16
17use clap::{Args, Parser, Subcommand, ValueEnum};
18
19use super::{
20    app, cleanup, color::ColorArg, completions, config, context, daemon, doctor, init, machine,
21    migrate, plugin, prd, productivity, prompt, queue, run, runner, scan, task, tutorial, undo,
22    version, watch, webhook,
23};
24
25#[derive(Parser)]
26#[command(name = "ralph")]
27#[command(about = "Ralph")]
28#[command(version)]
29#[command(after_long_help = r#"Runner selection:
30  - CLI flags override project config, which overrides global config, which overrides built-in defaults.
31  - Default runner/model come from config files: project config (.ralph/config.jsonc) > global config (~/.config/ralph/config.jsonc) > built-in.
32  - `task` and `scan` accept --runner/--model/--effort as one-off overrides.
33  - `run one` and `run loop` accept --runner/--model/--effort as one-off overrides; otherwise they use task.agent overrides when present; otherwise config agent defaults.
34
35Config example (.ralph/config.jsonc):
36  {
37    "version": 2,
38    "agent": {
39      "runner": "codex",
40      "model": "gpt-5.4",
41      "codex_bin": "codex",
42      "gemini_bin": "gemini",
43      "claude_bin": "claude"
44    }
45  }
46
47Notes:
48  - Allowed runners: codex, opencode, gemini, claude, cursor, kimi, pi
49  - Allowed models: gpt-5.4, gpt-5.3-codex, gpt-5.3-codex-spark, gpt-5.3, zai-coding-plan/glm-4.7, gemini-3-pro-preview, gemini-3-flash-preview, sonnet, opus, kimi-for-coding (codex supports only gpt-5.4 + gpt-5.3-codex + gpt-5.3-codex-spark + gpt-5.3; opencode/gemini/claude/cursor/kimi/pi accept arbitrary model ids))
50  - On macOS: use `ralph app open` to launch the GUI (requires an installed Ralph.app)
51  - App-launched runs are noninteractive: they stream output, but interactive approvals remain terminal-only.
52
53Examples:
54  ralph app open
55  ralph queue list
56  ralph queue show RQ-0008
57  ralph queue next --with-title
58  ralph scan --runner opencode --model gpt-5.3 --focus "CI gaps"
59  ralph task --runner codex --model gpt-5.4 --effort high "Fix the flaky test"
60  ralph scan --runner gemini --model gemini-3-flash-preview --focus "risk audit"
61  ralph scan --runner claude --model sonnet --focus "risk audit"
62  ralph task --runner claude --model opus "Add tests for X"
63  ralph scan --runner cursor --model claude-opus-4-5-20251101 --focus "risk audit"
64  ralph task --runner cursor --model claude-opus-4-5-20251101 "Add tests for X"
65  ralph scan --runner kimi --focus "risk audit"
66  ralph task --runner kimi --model kimi-for-coding "Add tests for X"
67  ralph run one
68  ralph run loop --max-tasks 1
69  ralph run loop
70
71More help:
72  - Default help shows core commands only.
73  - Run `ralph help-all` to see advanced and experimental commands."#)]
74pub struct Cli {
75    #[command(subcommand)]
76    pub command: Command,
77
78    /// Force operations (e.g., bypass stale queue locks; bypass clean-repo safety checks for commands that enforce them, e.g. `run one`, `run loop`, and `scan`).
79    #[arg(long, global = true)]
80    pub force: bool,
81
82    /// Increase output verbosity (sets log level to info).
83    #[arg(short, long, global = true)]
84    pub verbose: bool,
85
86    /// Color output control.
87    #[arg(long, value_enum, default_value = "auto", global = true)]
88    pub color: ColorArg,
89
90    /// Disable colored output (alias for `--color never`).
91    /// Also respects the NO_COLOR environment variable.
92    #[arg(long, global = true)]
93    pub no_color: bool,
94
95    /// Automatically approve all migrations and fixes without prompting.
96    /// Useful for CI/scripting environments.
97    #[arg(long, global = true, conflicts_with = "no_sanity_checks")]
98    pub auto_fix: bool,
99
100    /// Skip startup sanity checks (migrations and unknown-key prompts).
101    #[arg(long, global = true, conflicts_with = "auto_fix")]
102    pub no_sanity_checks: bool,
103}
104
105#[derive(Subcommand)]
106pub enum Command {
107    Queue(queue::QueueArgs),
108    Config(config::ConfigArgs),
109    Run(Box<run::RunArgs>),
110    Task(Box<task::TaskArgs>),
111    Scan(scan::ScanArgs),
112    Init(init::InitArgs),
113    /// macOS app integration commands.
114    App(app::AppArgs),
115    /// Show core, advanced, and experimental command groups.
116    HelpAll,
117    /// Versioned machine-facing JSON API for the macOS app.
118    #[command(hide = true)]
119    Machine(Box<machine::MachineArgs>),
120    /// Render and print the final compiled prompts used by Ralph (for debugging/auditing).
121    #[command(
122        hide = true,
123        after_long_help = "Examples:\n  ralph prompt worker --phase 1 --repo-prompt plan\n  ralph prompt worker --phase 2 --task-id RQ-0001 --plan-file .ralph/cache/plans/RQ-0001.md\n  ralph prompt scan --focus \"CI gaps\" --repo-prompt off\n  ralph prompt task-builder --request \"Add tests\" --tags rust,tests --scope crates/ralph --repo-prompt tools\n"
124    )]
125    Prompt(prompt::PromptArgs),
126    /// Verify environment readiness and configuration.
127    #[command(
128        hide = true,
129        after_long_help = "Examples:\n  ralph doctor\n  ralph doctor --auto-fix\n  ralph doctor --no-sanity-checks\n  ralph doctor --format json\n  ralph doctor --format json --auto-fix"
130    )]
131    Doctor(doctor::DoctorArgs),
132    /// Manage project context (AGENTS.md) for AI agents.
133    #[command(
134        hide = true,
135        after_long_help = "Examples:\n  ralph context init\n  ralph context init --project-type rust\n  ralph context update --section troubleshooting\n  ralph context validate\n  ralph context update --dry-run"
136    )]
137    Context(context::ContextArgs),
138    /// Manage Ralph daemon (background service).
139    #[command(
140        hide = true,
141        after_long_help = "Examples:\n  ralph daemon start\n  ralph daemon start --empty-poll-ms 5000\n  ralph daemon stop\n  ralph daemon status"
142    )]
143    Daemon(daemon::DaemonArgs),
144    /// Convert PRD (Product Requirements Document) markdown to tasks.
145    #[command(
146        hide = true,
147        after_long_help = "Examples:\n  ralph prd create docs/prd/new-feature.md\n  ralph prd create docs/prd/new-feature.md --multi\n  ralph prd create docs/prd/new-feature.md --dry-run\n  ralph prd create docs/prd/new-feature.md --priority high --tag feature\n  ralph prd create docs/prd/new-feature.md --draft"
148    )]
149    Prd(prd::PrdArgs),
150    /// Generate shell completion scripts.
151    #[command(
152        hide = true,
153        after_long_help = "Examples:\n  ralph completions bash\n  ralph completions bash > ~/.local/share/bash-completion/completions/ralph\n  ralph completions zsh > ~/.zfunc/_ralph\n  ralph completions fish > ~/.config/fish/completions/ralph.fish\n  ralph completions powershell\n\nInstallation locations by shell:\n  Bash:   ~/.local/share/bash-completion/completions/ralph\n  Zsh:    ~/.zfunc/_ralph (and add 'fpath+=~/.zfunc' to ~/.zshrc)\n  Fish:   ~/.config/fish/completions/ralph.fish\n  PowerShell: Add to $PROFILE (see: $PROFILE | Get-Member -Type NoteProperty)"
154    )]
155    Completions(completions::CompletionsArgs),
156    /// Check and apply migrations for config and project files.
157    #[command(
158        hide = true,
159        after_long_help = "Examples:\n  ralph migrate              # Check for pending migrations\n  ralph migrate --check      # Exit with error code if migrations pending (CI)\n  ralph migrate --apply      # Apply all pending migrations\n  ralph migrate --list       # List all migrations and their status\n  ralph migrate status       # Show detailed migration status"
160    )]
161    Migrate(migrate::MigrateArgs),
162    /// Clean up temporary files created by Ralph.
163    #[command(
164        hide = true,
165        after_long_help = "Examples:\n  ralph cleanup              # Clean temp files older than 7 days\n  ralph cleanup --force      # Clean all ralph temp files\n  ralph cleanup --dry-run    # Show what would be deleted without deleting"
166    )]
167    Cleanup(cleanup::CleanupArgs),
168    /// Display version information.
169    #[command(after_long_help = "Examples:\n  ralph version\n  ralph version --verbose")]
170    Version(version::VersionArgs),
171    /// Watch files for changes and auto-detect tasks from TODO/FIXME/HACK/XXX comments.
172    #[command(
173        hide = true,
174        after_long_help = "Examples:\n  ralph watch\n  ralph watch src/\n  ralph watch --patterns \"*.rs,*.toml\"\n  ralph watch --auto-queue\n  ralph watch --notify\n  ralph watch --comments todo,fixme\n  ralph watch --debounce-ms 1000\n  ralph watch --ignore-patterns \"vendor/,target/,node_modules/\""
175    )]
176    Watch(watch::WatchArgs),
177    /// Webhook management commands.
178    #[command(
179        hide = true,
180        after_long_help = "Examples:\n  ralph webhook test\n  ralph webhook test --event task_completed\n  ralph webhook status --format json\n  ralph webhook replay --dry-run --id wf-1700000000-1"
181    )]
182    Webhook(webhook::WebhookArgs),
183
184    /// Productivity analytics (streaks, velocity, milestones).
185    #[command(
186        hide = true,
187        after_long_help = "Examples:\n  ralph productivity summary\n  ralph productivity velocity\n  ralph productivity streak"
188    )]
189    Productivity(productivity::ProductivityArgs),
190
191    /// Plugin management commands.
192    #[command(
193        hide = true,
194        after_long_help = "Examples:\n  ralph plugin init my.plugin\n  ralph plugin init my.plugin --scope global\n  ralph plugin list\n  ralph plugin validate\n  ralph plugin install ./my-plugin --scope project\n  ralph plugin uninstall my.plugin --scope project"
195    )]
196    Plugin(plugin::PluginArgs),
197
198    /// Runner management commands (capabilities, list).
199    #[command(
200        hide = true,
201        after_long_help = "Examples:\n  ralph runner capabilities codex\n  ralph runner capabilities claude --format json\n  ralph runner list\n  ralph runner list --format json"
202    )]
203    Runner(runner::RunnerArgs),
204
205    /// Run interactive tutorial for Ralph onboarding.
206    #[command(
207        hide = true,
208        after_long_help = "Examples:\n  ralph tutorial\n  ralph tutorial --keep-sandbox\n  ralph tutorial --non-interactive"
209    )]
210    Tutorial(tutorial::TutorialArgs),
211
212    /// Restore or preview an earlier continuation checkpoint.
213    #[command(
214        after_long_help = "Continuation workflow:\n  - `ralph undo --list` shows the checkpoints Ralph created before queue-changing operations.\n  - `ralph undo --dry-run` previews the restore path without modifying queue files.\n  - `ralph undo` restores the most recent checkpoint; `--id` restores a specific one.\n  - After restoring, run `ralph queue validate` and then continue normal work.\n\nExamples:\n  ralph undo\n  ralph undo --list\n  ralph undo --dry-run\n  ralph undo --id undo-20260215073000000000\n\nCheckpoints are created automatically before queue mutations such as:\n  - ralph task mutate / task decompose --write\n  - ralph task done/reject/start/ready/schedule\n  - ralph task edit/field/clone/split\n  - ralph task relate/blocks/mark-duplicate\n  - ralph queue archive/prune/sort/import/repair\n  - ralph queue issue publish/publish-many\n  - ralph task batch operations"
215    )]
216    Undo(undo::UndoArgs),
217
218    /// Emit a machine-readable CLI specification (JSON) for tooling and legacy clients.
219    #[command(name = "cli-spec", alias = "__cli-spec", hide = true)]
220    CliSpec(CliSpecArgs),
221}
222
223#[derive(Args, Debug, Clone)]
224pub struct CliSpecArgs {
225    /// Output format.
226    #[arg(long, value_enum, default_value_t = CliSpecFormatArg::Json)]
227    pub format: CliSpecFormatArg,
228}
229
230#[derive(ValueEnum, Debug, Copy, Clone, PartialEq, Eq)]
231pub enum CliSpecFormatArg {
232    Json,
233}