ralph_workflow/cli/
args.rs

1//! CLI argument definitions.
2//!
3//! Contains the `Args` struct with clap configuration for command-line parsing.
4
5use clap::Parser;
6
7/// Verbosity level shorthand flags (--quiet, --full).
8#[derive(Parser, Debug, Default)]
9pub struct VerbosityShorthand {
10    /// Shorthand for --verbosity=0 (minimal output)
11    #[arg(
12        short,
13        long,
14        conflicts_with = "verbosity",
15        help = "Quiet mode (same as -v0)"
16    )]
17    pub quiet: bool,
18
19    /// Shorthand for --verbosity=3 (no truncation)
20    #[arg(
21        long,
22        short,
23        conflicts_with = "verbosity",
24        help = "Full output mode, no truncation (same as -v3)"
25    )]
26    pub full: bool,
27}
28
29/// Debug verbosity flag.
30#[derive(Parser, Debug, Default)]
31pub struct DebugVerbosity {
32    /// Shorthand for --verbosity=4 (maximum verbosity with raw JSON)
33    #[arg(
34        long,
35        conflicts_with = "verbosity",
36        help = "Debug mode (same as -v4)",
37        hide = true
38    )]
39    pub debug: bool,
40}
41
42/// Quick preset mode flags.
43#[derive(Parser, Debug, Default)]
44pub struct QuickPresets {
45    /// Quick mode: 1 developer iteration, 1 review pass (fast turnaround)
46    #[arg(
47        long,
48        short = 'Q',
49        help = "Quick mode: 1 dev iteration + 1 review (for rapid prototyping)"
50    )]
51    pub quick: bool,
52
53    /// Rapid mode: 2 developer iterations, 1 review pass (between quick and standard)
54    #[arg(
55        long,
56        short = 'U',
57        help = "Rapid mode: 2 dev iterations + 1 review (fast but more thorough than quick)"
58    )]
59    pub rapid: bool,
60
61    /// Long mode: 15 developer iterations, 10 review passes (for thorough development)
62    #[arg(
63        long,
64        short = 'L',
65        help = "Long mode: 15 dev iterations + 10 reviews (for thorough development)"
66    )]
67    pub long: bool,
68}
69
70/// Standard preset mode flags.
71#[derive(Parser, Debug, Default)]
72pub struct StandardPresets {
73    /// Standard mode: 5 developer iterations, 2 review passes (default workflow)
74    #[arg(
75        long,
76        short = 'S',
77        help = "Standard mode: 5 dev iterations + 2 reviews (default workflow)"
78    )]
79    pub standard: bool,
80
81    /// Thorough mode: 10 developer iterations, 5 review passes (balanced but more than default)
82    #[arg(
83        long,
84        short = 'T',
85        help = "Thorough mode: 10 dev iterations + 5 reviews (balanced but thorough)"
86    )]
87    pub thorough: bool,
88}
89
90/// Unified config initialization flags.
91#[derive(Parser, Debug, Default)]
92pub struct UnifiedInitFlags {
93    /// Initialize unified config file and exit (alias for --init-global)
94    #[arg(
95        long,
96        conflicts_with_all = ["init_global", "init_legacy", "init_prompt"],
97        help = "Create ~/.config/ralph-workflow.toml with default settings (recommended)",
98        hide = true
99    )]
100    pub init: bool,
101
102    /// Initialize unified config file and exit
103    #[arg(
104        long,
105        conflicts_with_all = ["init", "init_legacy", "init_prompt"],
106        help = "Create ~/.config/ralph-workflow.toml with default settings (recommended)",
107        hide = true
108    )]
109    pub init_global: bool,
110}
111
112/// Legacy initialization flag.
113#[derive(Parser, Debug, Default)]
114pub struct LegacyInitFlag {
115    /// Initialize legacy per-repo agents.toml and exit
116    #[arg(
117        long,
118        conflicts_with_all = ["init", "init_global", "init_prompt"],
119        help = "(Legacy) Create .agent/agents.toml with default settings (not recommended)",
120        hide = true
121    )]
122    pub init_legacy: bool,
123}
124
125/// Agent listing flags.
126#[derive(Parser, Debug, Default)]
127pub struct AgentListFlags {
128    /// List all configured agents and exit
129    #[arg(
130        long,
131        help = "Show all agents from registry and config file",
132        hide = true
133    )]
134    pub list_agents: bool,
135
136    /// List only agents found in PATH and exit
137    #[arg(
138        long,
139        help = "Show only agents that are installed and available",
140        hide = true
141    )]
142    pub list_available_agents: bool,
143}
144
145/// Provider listing flag.
146#[derive(Parser, Debug, Default)]
147pub struct ProviderListFlag {
148    /// List `OpenCode` provider types and their configuration
149    #[arg(
150        long,
151        help = "Show OpenCode provider types with model prefixes and auth commands",
152        hide = true
153    )]
154    pub list_providers: bool,
155}
156
157/// Template listing flag.
158#[derive(Parser, Debug, Default)]
159pub struct TemplateListFlag {
160    /// List available PROMPT.md templates and exit
161    #[arg(
162        long,
163        help = "Show all available PROMPT.md templates with descriptions"
164    )]
165    pub list_templates: bool,
166}
167
168/// Template management subcommands.
169#[derive(Parser, Debug, Default)]
170pub struct TemplateCommands {
171    /// Initialize user templates directory
172    #[arg(
173        long = "init-templates",
174        help = "Create ~/.config/ralph/templates/ with default templates",
175        default_missing_value = "false",
176        num_args = 0..=1,
177        require_equals = true
178    )]
179    pub init_templates: Option<bool>,
180
181    /// Force overwrite existing templates when initializing
182    #[arg(
183        long,
184        requires = "init_templates",
185        help = "Overwrite existing templates during init"
186    )]
187    pub force: bool,
188
189    /// Validate all templates for syntax errors
190    #[arg(long, help = "Validate all templates for syntax errors")]
191    pub validate: bool,
192
193    /// Show template content and metadata
194    #[arg(long, value_name = "NAME", help = "Show template content and metadata")]
195    pub show: Option<String>,
196
197    /// List all prompt templates with their variables
198    #[arg(long, help = "List all prompt templates with their variables")]
199    pub list: bool,
200
201    /// Extract variables from a template
202    #[arg(long, value_name = "NAME", help = "Extract variables from a template")]
203    pub variables: Option<String>,
204
205    /// Test render a template with provided variables
206    #[arg(
207        long,
208        value_name = "NAME",
209        help = "Test render a template with provided variables"
210    )]
211    pub render: Option<String>,
212}
213
214impl TemplateCommands {
215    /// Check if --init-templates flag was provided.
216    pub const fn init_templates_enabled(&self) -> bool {
217        self.init_templates.is_some()
218    }
219}
220
221/// Commit message plumbing flags.
222#[derive(Parser, Debug, Default)]
223pub struct CommitPlumbingFlags {
224    /// Generate commit message only (writes to .agent/commit-message.txt)
225    #[arg(
226        long,
227        help = "Run only the commit message generation phase, then exit",
228        hide = true
229    )]
230    pub generate_commit_msg: bool,
231
232    /// Apply commit using existing .agent/commit-message.txt
233    #[arg(
234        long,
235        help = "Stage all changes and commit using .agent/commit-message.txt",
236        hide = true
237    )]
238    pub apply_commit: bool,
239}
240
241/// Commit display plumbing flags.
242#[derive(Parser, Debug, Default)]
243pub struct CommitDisplayFlags {
244    /// Show the generated commit message and exit
245    #[arg(long, help = "Read and display .agent/commit-message.txt", hide = true)]
246    pub show_commit_msg: bool,
247
248    /// Reset the starting commit reference to current HEAD
249    #[arg(
250        long,
251        help = "Reset .agent/start_commit to current HEAD (for incremental diff generation)",
252        hide = true
253    )]
254    pub reset_start_commit: bool,
255}
256
257/// Recovery command flags.
258#[derive(Parser, Debug, Default)]
259pub struct RecoveryFlags {
260    /// Resume from last checkpoint after an interruption
261    #[arg(
262        long,
263        help = "Resume from last checkpoint (if one exists from a previous interrupted run)",
264        hide = true
265    )]
266    pub resume: bool,
267
268    /// Validate setup without running agents (dry run)
269    #[arg(
270        long,
271        help = "Validate configuration and PROMPT.md without running agents",
272        hide = true
273    )]
274    pub dry_run: bool,
275
276    /// Output comprehensive diagnostic information
277    #[arg(
278        long,
279        short = 'd',
280        help = "Show system info, agent status, and config for troubleshooting"
281    )]
282    pub diagnose: bool,
283}
284
285/// Rebase control flags.
286#[derive(Parser, Debug, Default)]
287pub struct RebaseFlags {
288    /// Skip automatic rebase before/after pipeline
289    #[arg(
290        long,
291        help = "Skip automatic rebase to main branch before and after pipeline"
292    )]
293    pub skip_rebase: bool,
294
295    /// Only perform rebase and exit
296    #[arg(
297        long,
298        help = "Only rebase to main branch, then exit (no pipeline execution)"
299    )]
300    pub rebase_only: bool,
301}
302
303/// Ralph: PROMPT-driven agent orchestrator for git repos
304#[derive(Parser, Debug)]
305#[command(name = "ralph")]
306#[command(about = "PROMPT-driven multi-agent orchestrator for git repos")]
307#[command(
308    long_about = "Ralph orchestrates AI coding agents to implement changes based on PROMPT.md.\n\n\
309    It runs a developer agent for code implementation, then a reviewer agent for\n\
310    quality assurance, automatically staging and committing the final result."
311)]
312#[command(version)]
313#[command(
314    after_help = "╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\
315\n\
316NEW TO RALPH?\n\
317    Just want to get started? Run:\n\
318        ralph --init-prompt feature-spec    # Create a prompt template\n\
319        ralph \"fix: my bug\"                # Run with AI agents\n\
320\n\
321╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\
322\n\
323PRESET MODES (pick how thorough AI should be):\n\
324    -Q  Quick:      1 dev + 1 review     (typos, small fixes)\n\
325    -U  Rapid:      2 dev + 1 review     (minor changes)\n\
326    -S  Standard:   5 dev + 2 reviews    (default for most tasks)\n\
327    -T  Thorough:  10 dev + 5 reviews    (complex features)\n\
328    -L  Long:      15 dev + 10 reviews   (most thorough)\n\
329\n\
330╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\
331\n\
332COMMON SHORTHANDS:\n\
333    -D N, -R N       Set dev iterations and review cycles\n\
334    -a AGENT         Pick developer agent (claude, opencode, etc.)\n\
335    -r AGENT         Pick reviewer agent\n\
336    -v N / -q / -f   Set verbosity (quiet/normal/full)\n\
337    -d               Diagnose/show system info\n\
338    -i               Interactive mode (prompt if PROMPT.md missing)\n\
339    -c PATH          Use specific config file\n\
340\n\
341╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\
342\n\
343QUICK EXAMPLES:\n\
344    ralph \"fix: typo\"                Run with default settings\n\
345    ralph -Q \"fix: small bug\"        Quick mode for tiny fixes\n\
346    ralph -U \"feat: add button\"      Rapid mode for minor features\n\
347    ralph -a claude \"fix: bug\"       Use specific agent\n\
348    ralph --list-templates            See all prompt templates\n\
349╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
350)]
351// CLI arguments naturally use many boolean flags. These represent independent
352// user choices, not a state machine, so bools are the appropriate type.
353pub struct Args {
354    /// Verbosity shorthand flags (--quiet, --full)
355    #[command(flatten)]
356    pub verbosity_shorthand: VerbosityShorthand,
357
358    /// Debug verbosity flag
359    #[command(flatten)]
360    pub debug_verbosity: DebugVerbosity,
361
362    /// Quick preset mode flags
363    #[command(flatten)]
364    pub quick_presets: QuickPresets,
365
366    /// Standard preset mode flags
367    #[command(flatten)]
368    pub standard_presets: StandardPresets,
369
370    /// Unified config initialization flags
371    #[command(flatten)]
372    pub unified_init: UnifiedInitFlags,
373
374    /// Legacy initialization flag
375    #[command(flatten)]
376    pub legacy_init: LegacyInitFlag,
377
378    /// Agent listing flags
379    #[command(flatten)]
380    pub agent_list: AgentListFlags,
381
382    /// Provider listing flag
383    #[command(flatten)]
384    pub provider_list: ProviderListFlag,
385
386    /// Template listing flag
387    #[command(flatten)]
388    pub template_list: TemplateListFlag,
389
390    /// Template management commands
391    #[command(flatten)]
392    pub template_commands: TemplateCommands,
393
394    /// Commit message plumbing flags
395    #[command(flatten)]
396    pub commit_plumbing: CommitPlumbingFlags,
397
398    /// Commit display plumbing flags
399    #[command(flatten)]
400    pub commit_display: CommitDisplayFlags,
401
402    /// Recovery command flags
403    #[command(flatten)]
404    pub recovery: RecoveryFlags,
405
406    /// Rebase control flags
407    #[command(flatten)]
408    pub rebase_flags: RebaseFlags,
409
410    /// Commit message for the final commit
411    #[arg(
412        default_value = "chore: apply PROMPT loop + review/fix/review",
413        help = "Commit message for the final commit"
414    )]
415    pub commit_msg: String,
416
417    /// Number of developer iterations (default: 5)
418    #[arg(
419        long = "developer-iters",
420        short = 'D',
421        env = "RALPH_DEVELOPER_ITERS",
422        value_name = "N",
423        help = "Number of developer agent iterations",
424        aliases = ["developer-iteration", "dev-iter", "d-iters"]
425    )]
426    pub developer_iters: Option<u32>,
427
428    /// Number of review-fix cycles (N=0 skips review, N=1 is one review-fix cycle, etc.)
429    #[arg(
430        long = "reviewer-reviews",
431        short = 'R',
432        env = "RALPH_REVIEWER_REVIEWS",
433        value_name = "N",
434        help = "Number of review-fix cycles (0=skip review, 1=one cycle, default: 2)",
435        aliases = ["reviewer-count", "reviewer-review"]
436    )]
437    pub reviewer_reviews: Option<u32>,
438
439    /// Preset for common agent combinations
440    #[arg(
441        long,
442        env = "RALPH_PRESET",
443        value_name = "NAME",
444        help = "Use a preset agent combination (default, opencode)",
445        hide = true
446    )]
447    pub preset: Option<super::presets::Preset>,
448
449    /// Developer/driver agent to use (from `agent_chain.developer`)
450    #[arg(
451        long,
452        short = 'a',
453        env = "RALPH_DEVELOPER_AGENT",
454        aliases = ["driver-agent", "dev-agent", "developer"],
455        value_name = "AGENT",
456        help = "Developer agent for code implementation (default: first in agent_chain.developer)"
457    )]
458    pub developer_agent: Option<String>,
459
460    /// Reviewer agent to use (from `agent_chain.reviewer`)
461    #[arg(
462        long,
463        short = 'r',
464        env = "RALPH_REVIEWER_AGENT",
465        aliases = ["rev-agent", "reviewer"],
466        value_name = "AGENT",
467        help = "Reviewer agent for code review (default: first in agent_chain.reviewer)"
468    )]
469    pub reviewer_agent: Option<String>,
470
471    /// Developer model/provider override (e.g., "-m opencode/glm-4.7-free")
472    #[arg(
473        long,
474        env = "RALPH_DEVELOPER_MODEL",
475        value_name = "MODEL_FLAG",
476        help = "Model flag for developer agent (e.g., '-m opencode/glm-4.7-free')",
477        hide = true
478    )]
479    pub developer_model: Option<String>,
480
481    /// Reviewer model/provider override (e.g., "-m opencode/claude-sonnet-4")
482    #[arg(
483        long,
484        env = "RALPH_REVIEWER_MODEL",
485        value_name = "MODEL_FLAG",
486        help = "Model flag for reviewer agent (e.g., '-m opencode/claude-sonnet-4')",
487        hide = true
488    )]
489    pub reviewer_model: Option<String>,
490
491    /// Developer provider override (e.g., "opencode", "zai", "anthropic", "openai")
492    /// Use this to switch providers at runtime without changing agent config.
493    /// Combined with the agent's model to form the full model flag.
494    /// Provider types: 'opencode' (Zen gateway), 'zai'/'zhipuai' (Z.AI direct), 'anthropic'/'openai' (direct API)
495    #[arg(
496        long,
497        env = "RALPH_DEVELOPER_PROVIDER",
498        value_name = "PROVIDER",
499        help = "Provider for developer agent: 'opencode' (Zen), 'zai'/'zhipuai' (Z.AI direct), 'anthropic'/'openai' (direct API)",
500        hide = true
501    )]
502    pub developer_provider: Option<String>,
503
504    /// Reviewer provider override (e.g., "opencode", "zai", "anthropic", "openai")
505    /// Use this to switch providers at runtime without changing agent config.
506    /// Combined with the agent's model to form the full model flag.
507    /// Provider types: 'opencode' (Zen gateway), 'zai'/'zhipuai' (Z.AI direct), 'anthropic'/'openai' (direct API)
508    #[arg(
509        long,
510        env = "RALPH_REVIEWER_PROVIDER",
511        value_name = "PROVIDER",
512        help = "Provider for reviewer agent: 'opencode' (Zen), 'zai'/'zhipuai' (Z.AI direct), 'anthropic'/'openai' (direct API)",
513        hide = true
514    )]
515    pub reviewer_provider: Option<String>,
516
517    /// JSON parser for the reviewer agent (overrides agent config)
518    /// Useful for testing different parsers with problematic agents
519    #[arg(
520        long,
521        env = "RALPH_REVIEWER_JSON_PARSER",
522        value_name = "PARSER",
523        help = "JSON parser for reviewer (claude, codex, gemini, opencode, generic); overrides agent config",
524        hide = true
525    )]
526    pub reviewer_json_parser: Option<String>,
527
528    /// Verbosity level (0=quiet, 1=normal, 2=verbose, 3=full, 4=debug)
529    #[arg(
530        short,
531        long,
532        value_name = "LEVEL",
533        value_parser = clap::value_parser!(u8).range(0..=4),
534        help = "Output verbosity (0=quiet, 1=normal, 2=verbose [default], 3=full, 4=debug); overrides RALPH_VERBOSITY"
535    )]
536    pub verbosity: Option<u8>,
537
538    /// Disable isolation mode (allow NOTES.md and ISSUES.md to persist)
539    #[arg(
540        long,
541        help = "Disable isolation mode: keep NOTES.md and ISSUES.md between runs",
542        hide = true
543    )]
544    pub no_isolation: bool,
545
546    /// Review depth level (standard, comprehensive, security, incremental)
547    #[arg(
548        long,
549        value_name = "LEVEL",
550        help = "Review depth: standard (balanced), comprehensive (thorough), security (OWASP-focused), incremental (changed files only)",
551        hide = true
552    )]
553    pub review_depth: Option<String>,
554
555    /// Path to configuration file (default: ~/.config/ralph-workflow.toml)
556    #[arg(
557        long,
558        short = 'c',
559        value_name = "PATH",
560        help = "Path to configuration file (default: ~/.config/ralph-workflow.toml)",
561        hide = true
562    )]
563    pub config: Option<std::path::PathBuf>,
564
565    /// Initialize PROMPT.md from template and exit
566    #[arg(
567        long,
568        value_name = "TEMPLATE",
569        help = "Create PROMPT.md from a template (use --list-templates to see options)"
570    )]
571    pub init_prompt: Option<String>,
572
573    /// Interactive mode: prompt to create PROMPT.md from template when missing
574    #[arg(
575        long,
576        short = 'i',
577        help = "Interactive mode: prompt to create PROMPT.md from template when missing"
578    )]
579    pub interactive: bool,
580
581    /// Git user name override (highest priority in identity resolution chain)
582    #[arg(
583        long,
584        env = "RALPH_GIT_USER_NAME",
585        value_name = "NAME",
586        help = "Git user name for commits (overrides config, env, and git config)"
587    )]
588    pub git_user_name: Option<String>,
589
590    /// Git user email override (highest priority in identity resolution chain)
591    #[arg(
592        long,
593        env = "RALPH_GIT_USER_EMAIL",
594        value_name = "EMAIL",
595        help = "Git user email for commits (overrides config, env, and git config)"
596    )]
597    pub git_user_email: Option<String>,
598
599    /// Show streaming quality metrics at the end of agent output
600    #[arg(
601        long,
602        help = "Display streaming quality metrics (delta stats, repairs, violations) after agent completion"
603    )]
604    pub show_streaming_metrics: bool,
605}