1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use std::{num::NonZeroUsize, path::PathBuf, time::Duration};
use clap::{Parser, Subcommand, ValueEnum};
use rho_providers::{credentials::CredentialStoreBackend, reasoning::ReasoningLevel};
use crate::app::automation_protocol::parse_duration;
fn parse_credential_store_backend(value: &str) -> Result<CredentialStoreBackend, String> {
CredentialStoreBackend::parse(value).map_err(|error| error.to_string())
}
/// Output contract used by a non-interactive `rho run` invocation.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, ValueEnum)]
pub enum OutputFormat {
/// Print only the authoritative final assistant answer.
#[default]
Text,
/// Stream independently versioned JSON Lines events.
Jsonl,
}
#[derive(Parser, Debug)]
#[command(name = "rho")]
pub struct Cli {
#[arg(long)]
pub provider: Option<String>,
#[arg(long)]
pub model: Option<String>,
#[arg(long)]
pub config: Option<PathBuf>,
#[arg(long, value_parser = ["api-key", "codex", "anthropic-api-key", "google-api-key", "github-copilot", "xai-api-key", "xai-oauth", "moonshot-api-key", "poolside-api-key", "openrouter-api-key", "openrouter-oauth", "kimi-oauth"])]
pub auth: Option<String>,
/// Do not send rho's system prompt, including AGENTS.md and skill context.
#[arg(long)]
pub no_system_prompt: bool,
/// Do not expose any tools to the model.
#[arg(long)]
pub no_tools: bool,
/// Do not expose the delegated-agent tools (agent/agents) to the model.
#[arg(long, global = true)]
pub no_subagents: bool,
/// Select the agent definition used for this session or automation run.
#[arg(long, global = true, value_name = "ID")]
pub agent: Option<String>,
/// Override reasoning level: off, minimal, low, medium, high, xhigh, or max.
#[arg(long)]
pub reasoning: Option<ReasoningLevel>,
/// Resume an existing session by UUID or UUID prefix. Omit the ID to choose from a picker.
#[arg(short = 'R', long, value_name = "ID", num_args = 0..=1)]
pub resume: Option<Option<String>>,
#[command(subcommand)]
pub command: Option<Command>,
}
#[derive(Subcommand, Debug)]
pub enum Command {
/// Run one non-interactive automation prompt and print the final answer.
Run {
/// Read additional prompt text from stdin.
#[arg(long)]
stdin: bool,
/// Stream progress to stdout and write a structured status/result
/// file (JSON) that is updated during the run and finalized on exit.
#[arg(long, value_name = "PATH")]
output_file: Option<PathBuf>,
/// Select plain final-answer output or a JSON Lines event stream.
#[arg(long, value_enum, default_value_t)]
output: OutputFormat,
/// Override the model-step budget for this run.
#[arg(long, value_name = "N")]
max_steps: Option<NonZeroUsize>,
/// Cancel the run after this wall-clock duration.
#[arg(long, value_name = "DURATION", value_parser = parse_duration)]
timeout: Option<Duration>,
/// Prompt text to send to the agent.
#[arg(value_name = "PROMPT", num_args = 0..)]
prompt: Vec<String>,
},
/// Watch a delegated agent run in a read-only TUI.
Attach {
/// Delegated run ID shown when the agent was started.
#[arg(value_name = "ID")]
id: String,
},
/// Log in to a provider from a browser or device-code flow.
Login {
/// Provider to authenticate, for example openai-codex or github-copilot.
#[arg(value_name = "PROVIDER")]
provider: String,
/// Use device-code login instead of opening a local browser callback.
#[arg(long)]
device_auth: bool,
},
/// Configure or probe provider credential storage.
CredentialStore {
#[command(subcommand)]
command: CredentialStoreCommand,
},
/// Update rho using the detected installation method.
Update,
}
#[derive(Subcommand, Debug)]
pub enum CredentialStoreCommand {
/// Test a credential backend by writing and deleting a temporary secret.
Probe {
/// Backend to test: os or file (`auto` is accepted as an alias for os).
#[arg(
value_name = "BACKEND",
default_value = "os",
value_parser = parse_credential_store_backend
)]
backend: CredentialStoreBackend,
},
/// Show the configured credential backend (unset, os, or file).
Status,
/// Save the credential backend used by future rho processes.
Set {
/// Backend to use: os or file (`auto` is accepted as an alias for os).
#[arg(value_name = "BACKEND", value_parser = parse_credential_store_backend)]
backend: CredentialStoreBackend,
},
}
#[cfg(test)]
#[path = "cli_tests.rs"]
mod tests;