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    /// Smart initialization: creates setup based on current state
94    ///
95    /// This is the RECOMMENDED way to get started with Ralph.
96    ///
97    /// Behavior:
98    ///   --init              (no value)   → Smart mode: infers what you need
99    ///   --init bug-fix      (with value) → Create PROMPT.md from specific Work Guide
100    ///
101    /// Smart mode (no value):
102    ///   - No config? Creates config at ~/.config/ralph-workflow.toml
103    ///   - Config exists, no PROMPT.md? Creates or prompts for PROMPT.md
104    ///   - Both exist? Shows helpful status message and exits
105    ///
106    /// Work Guides (for PROMPT.md):
107    ///   quick, bug-fix, feature-spec, refactor, test, docs, cli-tool, web-api,
108    ///   performance-optimization, security-audit, api-integration, database-migration,
109    ///   dependency-update, data-pipeline, ui-component, code-review, debug-triage,
110    ///   release, tech-debt, onboarding
111    ///
112    /// Note: These are Work Guides for YOUR work descriptions, NOT Agent Prompts.
113    /// See --help for details on the difference.
114    #[arg(
115        long,
116        conflicts_with_all = ["init_global", "init_config", "init_legacy", "init_prompt"],
117        help = "Smart init: create config or PROMPT.md (infers from current state)",
118        value_name = "TEMPLATE",
119        num_args = 0..=1,
120        default_missing_value = "",
121        // Cannot use possible_values here due to Option<String> type with optional value
122        // Completion is handled via --generate-completion
123    )]
124    pub init: Option<String>,
125
126    /// Force overwrite existing PROMPT.md when using --init or --init-prompt
127    #[arg(
128        long = "force-overwrite",
129        visible_alias = "overwrite",
130        help = "Overwrite existing PROMPT.md without prompting (use with --init or --init-prompt)",
131        hide = true
132    )]
133    pub force_init: bool,
134
135    /// Initialize unified config file and exit (explicit alias for config creation)
136    #[arg(
137        long,
138        conflicts_with_all = ["init", "init_global", "init_legacy", "init_prompt"],
139        help = "Create ~/.config/ralph-workflow.toml with default settings (recommended)",
140        hide = true
141    )]
142    pub init_config: bool,
143
144    /// Initialize unified config file and exit
145    #[arg(
146        long,
147        conflicts_with_all = ["init", "init_config", "init_legacy", "init_prompt"],
148        help = "Create ~/.config/ralph-workflow.toml with default settings (recommended)",
149        hide = true
150    )]
151    pub init_global: bool,
152}
153
154/// Legacy initialization flag.
155#[derive(Parser, Debug, Default)]
156pub struct LegacyInitFlag {
157    /// Initialize legacy per-repo agents.toml and exit
158    #[arg(
159        long,
160        conflicts_with_all = ["init", "init_global", "init_prompt"],
161        help = "(Legacy) Create .agent/agents.toml with default settings (not recommended)",
162        hide = true
163    )]
164    pub init_legacy: bool,
165}
166
167/// Agent listing flags.
168#[derive(Parser, Debug, Default)]
169pub struct AgentListFlags {
170    /// List all configured agents and exit
171    #[arg(
172        long,
173        help = "Show all agents from registry and config file",
174        hide = true
175    )]
176    pub list_agents: bool,
177
178    /// List only agents found in PATH and exit
179    #[arg(
180        long,
181        help = "Show only agents that are installed and available",
182        hide = true
183    )]
184    pub list_available_agents: bool,
185}
186
187/// Provider listing flag.
188#[derive(Parser, Debug, Default)]
189pub struct ProviderListFlag {
190    /// List `OpenCode` provider types and their configuration
191    #[arg(
192        long,
193        help = "Show OpenCode provider types with model prefixes and auth commands",
194        hide = true
195    )]
196    pub list_providers: bool,
197}
198
199/// Shell completion generation flag.
200#[derive(Parser, Debug, Default)]
201pub struct CompletionFlag {
202    /// Generate shell completion script
203    #[arg(
204        long,
205        value_name = "SHELL",
206        value_enum,
207        help = "Generate shell completion script (bash, zsh, fish, elvish, powershell)",
208        hide = true
209    )]
210    pub generate_completion: Option<Shell>,
211}
212
213/// Supported shell types for completion generation.
214#[derive(Debug, Clone, Copy, PartialEq, Eq, clap::ValueEnum)]
215pub enum Shell {
216    /// Bash shell
217    Bash,
218    /// Zsh shell
219    Zsh,
220    /// Fish shell
221    Fish,
222    /// Elvish shell
223    Elvish,
224    /// `pwsh` (`PowerShell`) shell
225    Pwsh,
226}
227
228/// Work Guide listing flag.
229#[derive(Parser, Debug, Default)]
230pub struct WorkGuideListFlag {
231    /// List available PROMPT.md Work Guides and exit
232    #[arg(
233        long = "list-work-guides",
234        visible_alias = "list-templates",
235        help = "Show all available Work Guides for PROMPT.md"
236    )]
237    pub list_work_guides: bool,
238}
239
240/// Template management subcommands.
241#[derive(Parser, Debug, Default)]
242pub struct TemplateCommands {
243    /// Initialize user templates directory with Agent Prompts (backend AI prompts)
244    #[arg(
245        long = "init-system-prompts",
246        alias = "init-templates",
247        help = "Create ~/.config/ralph/templates/ with default Agent Prompts (backend AI behavior configuration, NOT Work Guides for PROMPT.md)",
248        default_missing_value = "false",
249        num_args = 0..=1,
250        require_equals = true,
251        hide = true
252    )]
253    pub init_templates: Option<bool>,
254
255    /// Force overwrite existing templates when initializing
256    #[arg(
257        long,
258        requires = "init_templates",
259        help = "Overwrite existing system prompt templates during init (use with caution)",
260        hide = true
261    )]
262    pub force: bool,
263
264    /// Validate all templates for syntax errors
265    #[arg(
266        long,
267        help = "Validate all Agent Prompt templates for syntax errors",
268        hide = true
269    )]
270    pub validate: bool,
271
272    /// Show template content and metadata
273    #[arg(
274        long,
275        value_name = "NAME",
276        help = "Show Agent Prompt template content and metadata",
277        hide = true
278    )]
279    pub show: Option<String>,
280
281    /// List all prompt templates with their variables
282    #[arg(
283        long,
284        help = "List all Agent Prompt templates with their variables",
285        hide = true
286    )]
287    pub list: bool,
288
289    /// List all templates including deprecated ones
290    #[arg(
291        long,
292        help = "List all Agent Prompt templates including deprecated ones"
293    )]
294    pub list_all: bool,
295
296    /// Extract variables from a template
297    #[arg(
298        long,
299        value_name = "NAME",
300        help = "Extract variables from an Agent Prompt template",
301        hide = true
302    )]
303    pub variables: Option<String>,
304
305    /// Test render a template with provided variables
306    #[arg(
307        long,
308        value_name = "NAME",
309        help = "Test render a system prompt template with provided variables",
310        hide = true
311    )]
312    pub render: Option<String>,
313}
314
315impl TemplateCommands {
316    /// Check if --init-system-prompts or --init-templates flag was provided.
317    pub const fn init_templates_enabled(&self) -> bool {
318        self.init_templates.is_some()
319    }
320}
321
322/// Commit message plumbing flags.
323#[derive(Parser, Debug, Default)]
324pub struct CommitPlumbingFlags {
325    /// Generate commit message only (writes to .agent/commit-message.txt)
326    #[arg(
327        long,
328        help = "Run only the commit message generation phase, then exit",
329        hide = true
330    )]
331    pub generate_commit_msg: bool,
332
333    /// Apply commit using existing .agent/commit-message.txt
334    #[arg(
335        long,
336        help = "Stage all changes and commit using .agent/commit-message.txt",
337        hide = true
338    )]
339    pub apply_commit: bool,
340}
341
342/// Commit display plumbing flags.
343///
344/// This groups flags for displaying commit-related information.
345#[derive(Parser, Debug, Default)]
346pub struct CommitDisplayFlags {
347    /// Show the generated commit message and exit
348    #[arg(long, help = "Read and display .agent/commit-message.txt", hide = true)]
349    pub show_commit_msg: bool,
350
351    /// Reset the starting commit reference to merge-base with main branch
352    #[arg(
353        long,
354        help = "Reset .agent/start_commit to merge-base with main branch (for incremental diff generation)",
355        hide = true
356    )]
357    pub reset_start_commit: bool,
358
359    /// Show the current baseline state and exit
360    /// Handler: `cli/handlers/baseline.rs::handle_show_baseline()`
361    #[arg(long, help = "Show current review baseline and start commit state")]
362    pub show_baseline: bool,
363}
364
365/// Recovery command flags.
366#[derive(Parser, Debug, Default)]
367pub struct RecoveryFlags {
368    /// Resume from last checkpoint after an interruption
369    #[arg(
370        long,
371        help = "Resume from last checkpoint (if one exists from a previous interrupted run)",
372        hide = true
373    )]
374    pub resume: bool,
375
376    /// Validate setup without running agents (dry run)
377    #[arg(
378        long,
379        help = "Validate configuration and PROMPT.md without running agents",
380        hide = true
381    )]
382    pub dry_run: bool,
383
384    /// Output comprehensive diagnostic information
385    #[arg(
386        long,
387        short = 'd',
388        help = "Show system info, agent status, and config for troubleshooting"
389    )]
390    pub diagnose: bool,
391
392    /// Show extended help with more details
393    #[arg(
394        long = "extended-help",
395        visible_alias = "man",
396        help = "Show extended help with shell completion, all presets, and troubleshooting"
397    )]
398    pub extended_help: bool,
399}
400
401/// Rebase control flags.
402#[derive(Parser, Debug, Default)]
403pub struct RebaseFlags {
404    /// Enable automatic rebase before/after pipeline
405    ///
406    /// When enabled, ralph will automatically rebase to the main branch before
407    /// starting development and after the review phase. Default is disabled to
408    /// keep operations fast and avoid conflicts.
409    #[arg(
410        long,
411        help = "Enable automatic rebase to main branch before and after pipeline"
412    )]
413    pub with_rebase: bool,
414
415    /// Only perform rebase and exit
416    #[arg(
417        long,
418        help = "Only rebase to main branch, then exit (no pipeline execution)",
419        hide = true
420    )]
421    pub rebase_only: bool,
422
423    /// Skip automatic rebase before/after pipeline (deprecated: use default behavior or --with-rebase)
424    #[arg(
425        long,
426        help = "Skip automatic rebase to main branch before and after pipeline",
427        hide = true
428    )]
429    #[deprecated(
430        since = "0.4.2",
431        note = "Rebase is now disabled by default; use --with-rebase to enable"
432    )]
433    pub skip_rebase: bool,
434}
435
436/// Ralph: PROMPT-driven agent orchestrator for git repos
437#[derive(Parser, Debug)]
438#[command(name = "ralph")]
439#[command(about = "PROMPT-driven multi-agent orchestrator for git repos")]
440#[command(
441    long_about = "Ralph orchestrates AI coding agents to implement changes based on PROMPT.md.\n\n\
442    It runs a developer agent for code implementation, then a reviewer agent for\n\
443    quality assurance, automatically staging and committing the final result."
444)]
445#[command(version)]
446#[command(after_help = "GETTING STARTED:\n\
447    ralph --init                 Smart init (infers what you need)\n\
448    ralph --init <work-guide>    Create PROMPT.md from a Work Guide\n\
449    ralph \"fix: my bug\"         Run the orchestrator\n\
450\n\
451More help: ralph --extended-help  (shell completion, all presets, troubleshooting)")]
452// CLI arguments naturally use many boolean flags. These represent independent
453// user choices, not a state machine, so bools are the appropriate type.
454pub struct Args {
455    /// Verbosity shorthand flags (--quiet, --full)
456    #[command(flatten)]
457    pub verbosity_shorthand: VerbosityShorthand,
458
459    /// Debug verbosity flag
460    #[command(flatten)]
461    pub debug_verbosity: DebugVerbosity,
462
463    /// Quick preset mode flags
464    #[command(flatten)]
465    pub quick_presets: QuickPresets,
466
467    /// Standard preset mode flags
468    #[command(flatten)]
469    pub standard_presets: StandardPresets,
470
471    /// Unified config initialization flags
472    #[command(flatten)]
473    pub unified_init: UnifiedInitFlags,
474
475    /// Legacy initialization flag
476    #[command(flatten)]
477    pub legacy_init: LegacyInitFlag,
478
479    /// Agent listing flags
480    #[command(flatten)]
481    pub agent_list: AgentListFlags,
482
483    /// Provider listing flag
484    #[command(flatten)]
485    pub provider_list: ProviderListFlag,
486
487    /// Shell completion generation flag
488    #[command(flatten)]
489    pub completion: CompletionFlag,
490
491    /// Work Guide listing flag
492    #[command(flatten)]
493    pub work_guide_list: WorkGuideListFlag,
494
495    /// Template management commands
496    #[command(flatten)]
497    pub template_commands: TemplateCommands,
498
499    /// Commit message plumbing flags
500    #[command(flatten)]
501    pub commit_plumbing: CommitPlumbingFlags,
502
503    /// Commit display plumbing flags
504    #[command(flatten)]
505    pub commit_display: CommitDisplayFlags,
506
507    /// Recovery command flags
508    #[command(flatten)]
509    pub recovery: RecoveryFlags,
510
511    /// Rebase control flags
512    #[command(flatten)]
513    pub rebase_flags: RebaseFlags,
514
515    /// Commit message for the final commit
516    #[arg(
517        default_value = "chore: apply PROMPT loop + review/fix/review",
518        help = "Commit message for the final commit"
519    )]
520    pub commit_msg: String,
521
522    /// Number of developer iterations (default: 5)
523    #[arg(
524        long = "developer-iters",
525        short = 'D',
526        env = "RALPH_DEVELOPER_ITERS",
527        value_name = "N",
528        help = "Number of developer agent iterations",
529        aliases = ["developer-iteration", "dev-iter", "d-iters"]
530    )]
531    pub developer_iters: Option<u32>,
532
533    /// Number of review-fix cycles (N=0 skips review, N=1 is one review-fix cycle, etc.)
534    #[arg(
535        long = "reviewer-reviews",
536        short = 'R',
537        env = "RALPH_REVIEWER_REVIEWS",
538        value_name = "N",
539        help = "Number of review-fix cycles (0=skip review, 1=one cycle, default: 2)",
540        aliases = ["reviewer-count", "reviewer-review"]
541    )]
542    pub reviewer_reviews: Option<u32>,
543
544    /// Preset for common agent combinations
545    #[arg(
546        long,
547        env = "RALPH_PRESET",
548        value_name = "NAME",
549        help = "Use a preset agent combination (default, opencode)",
550        hide = true
551    )]
552    pub preset: Option<super::presets::Preset>,
553
554    /// Developer/driver agent to use (from `agent_chain.developer`)
555    #[arg(
556        long,
557        short = 'a',
558        env = "RALPH_DEVELOPER_AGENT",
559        aliases = ["driver-agent", "dev-agent", "developer"],
560        value_name = "AGENT",
561        help = "Developer agent for code implementation (default: first in agent_chain.developer)"
562    )]
563    pub developer_agent: Option<String>,
564
565    /// Reviewer agent to use (from `agent_chain.reviewer`)
566    #[arg(
567        long,
568        short = 'r',
569        env = "RALPH_REVIEWER_AGENT",
570        aliases = ["rev-agent", "reviewer"],
571        value_name = "AGENT",
572        help = "Reviewer agent for code review (default: first in agent_chain.reviewer)"
573    )]
574    pub reviewer_agent: Option<String>,
575
576    /// Developer model/provider override (e.g., "-m opencode/glm-4.7-free")
577    #[arg(
578        long,
579        env = "RALPH_DEVELOPER_MODEL",
580        value_name = "MODEL_FLAG",
581        help = "Model flag for developer agent (e.g., '-m opencode/glm-4.7-free')",
582        hide = true
583    )]
584    pub developer_model: Option<String>,
585
586    /// Reviewer model/provider override (e.g., "-m opencode/claude-sonnet-4")
587    #[arg(
588        long,
589        env = "RALPH_REVIEWER_MODEL",
590        value_name = "MODEL_FLAG",
591        help = "Model flag for reviewer agent (e.g., '-m opencode/claude-sonnet-4')",
592        hide = true
593    )]
594    pub reviewer_model: Option<String>,
595
596    /// Developer provider override (e.g., "opencode", "zai", "anthropic", "openai")
597    /// Use this to switch providers at runtime without changing agent config.
598    /// Combined with the agent's model to form the full model flag.
599    /// Provider types: 'opencode' (Zen gateway), 'zai'/'zhipuai' (Z.AI direct), 'anthropic'/'openai' (direct API)
600    #[arg(
601        long,
602        env = "RALPH_DEVELOPER_PROVIDER",
603        value_name = "PROVIDER",
604        help = "Provider for developer agent: 'opencode' (Zen), 'zai'/'zhipuai' (Z.AI direct), 'anthropic'/'openai' (direct API)",
605        hide = true
606    )]
607    pub developer_provider: Option<String>,
608
609    /// Reviewer provider override (e.g., "opencode", "zai", "anthropic", "openai")
610    /// Use this to switch providers at runtime without changing agent config.
611    /// Combined with the agent's model to form the full model flag.
612    /// Provider types: 'opencode' (Zen gateway), 'zai'/'zhipuai' (Z.AI direct), 'anthropic'/'openai' (direct API)
613    #[arg(
614        long,
615        env = "RALPH_REVIEWER_PROVIDER",
616        value_name = "PROVIDER",
617        help = "Provider for reviewer agent: 'opencode' (Zen), 'zai'/'zhipuai' (Z.AI direct), 'anthropic'/'openai' (direct API)",
618        hide = true
619    )]
620    pub reviewer_provider: Option<String>,
621
622    /// JSON parser for the reviewer agent (overrides agent config)
623    /// Useful for testing different parsers with problematic agents
624    #[arg(
625        long,
626        env = "RALPH_REVIEWER_JSON_PARSER",
627        value_name = "PARSER",
628        help = "JSON parser for reviewer (claude, codex, gemini, opencode, generic); overrides agent config",
629        hide = true
630    )]
631    pub reviewer_json_parser: Option<String>,
632
633    /// Verbosity level (0=quiet, 1=normal, 2=verbose, 3=full, 4=debug)
634    #[arg(
635        short,
636        long,
637        value_name = "LEVEL",
638        value_parser = clap::value_parser!(u8).range(0..=4),
639        help = "Output verbosity (0=quiet, 1=normal, 2=verbose [default], 3=full, 4=debug); overrides RALPH_VERBOSITY"
640    )]
641    pub verbosity: Option<u8>,
642
643    /// Disable isolation mode (allow NOTES.md and ISSUES.md to persist)
644    #[arg(
645        long,
646        help = "Disable isolation mode: keep NOTES.md and ISSUES.md between runs",
647        hide = true
648    )]
649    pub no_isolation: bool,
650
651    /// Review depth level (standard, comprehensive, security, incremental)
652    #[arg(
653        long,
654        value_name = "LEVEL",
655        help = "Review depth: standard (balanced), comprehensive (thorough), security (OWASP-focused), incremental (changed files only)",
656        hide = true
657    )]
658    pub review_depth: Option<String>,
659
660    /// Path to configuration file (default: ~/.config/ralph-workflow.toml)
661    #[arg(
662        long,
663        short = 'c',
664        value_name = "PATH",
665        help = "Path to configuration file (default: ~/.config/ralph-workflow.toml)",
666        hide = true
667    )]
668    pub config: Option<std::path::PathBuf>,
669
670    /// Initialize PROMPT.md from a Work Guide and exit
671    ///
672    /// This is a legacy alias for `--init <template>`. Consider using `--init` instead.
673    ///
674    /// Work Guides describe YOUR work to the AI (e.g., bug-fix, feature-spec).
675    /// These are different from Agent Prompts which configure AI behavior.
676    ///
677    /// Available Work Guides:
678    /// quick, bug-fix, feature-spec, refactor, test, docs, cli-tool, web-api,
679    /// performance-optimization, security-audit, api-integration, database-migration,
680    /// dependency-update, data-pipeline, ui-component, code-review, debug-triage,
681    /// release, tech-debt, onboarding
682    #[arg(
683        long,
684        value_name = "TEMPLATE",
685        help = "Create PROMPT.md from a Work Guide (use --list-work-guides to see options)",
686        hide = true
687    )]
688    pub init_prompt: Option<String>,
689
690    /// Interactive mode: prompt to create PROMPT.md from template when missing
691    #[arg(
692        long,
693        short = 'i',
694        help = "Interactive mode: prompt to create PROMPT.md from template when missing",
695        hide = true
696    )]
697    pub interactive: bool,
698
699    /// Git user name override (highest priority in identity resolution chain)
700    #[arg(
701        long,
702        env = "RALPH_GIT_USER_NAME",
703        value_name = "NAME",
704        help = "Git user name for commits (overrides config, env, and git config)",
705        hide = true
706    )]
707    pub git_user_name: Option<String>,
708
709    /// Git user email override (highest priority in identity resolution chain)
710    #[arg(
711        long,
712        env = "RALPH_GIT_USER_EMAIL",
713        value_name = "EMAIL",
714        help = "Git user email for commits (overrides config, env, and git config)",
715        hide = true
716    )]
717    pub git_user_email: Option<String>,
718
719    /// Show streaming quality metrics at the end of agent output
720    #[arg(
721        long,
722        help = "Display streaming quality metrics (delta stats, repairs, violations) after agent completion",
723        hide = true
724    )]
725    pub show_streaming_metrics: bool,
726}