ito_core/harness/claude_code.rs
1use super::streaming_cli::run_streaming_cli;
2use super::types::{Harness, HarnessName, HarnessRunConfig, HarnessRunResult};
3use miette::Result;
4
5/// Runs the `claude` CLI in non-interactive print mode (`claude -p`).
6/// Selected via `ito ralph --harness claude`; requires the Claude Code CLI on PATH.
7#[derive(Debug, Default)]
8pub struct ClaudeCodeHarness;
9
10impl Harness for ClaudeCodeHarness {
11 /// Identify the harness as the Claude harness.
12 ///
13 /// # Returns
14 ///
15 /// `HarnessName::CLAUDE`
16 ///
17 /// # Examples
18 ///
19 /// ```
20 /// use ito_core::harness::{ClaudeCodeHarness, Harness, HarnessName};
21 ///
22 /// let h = ClaudeCodeHarness::default();
23 /// assert_eq!(h.name(), HarnessName::CLAUDE);
24 /// ```
25 fn name(&self) -> HarnessName {
26 HarnessName::CLAUDE
27 }
28
29 /// Run the Claude CLI using the provided configuration and stream its output.
30 ///
31 /// # Returns
32 ///
33 /// A `HarnessRunResult` describing the outcome of the run.
34 ///
35 /// # Examples
36 ///
37 /// ```ignore
38 /// use ito_core::harness::{ClaudeCodeHarness, HarnessRunConfig};
39 ///
40 /// let mut harness = ClaudeCodeHarness::default();
41 /// let config = HarnessRunConfig {
42 /// prompt: "Translate to French: Hello".to_string(),
43 /// ..Default::default()
44 /// };
45 /// let result = harness.run(&config).unwrap();
46 /// ```
47 fn run(&mut self, config: &HarnessRunConfig) -> Result<HarnessRunResult> {
48 let mut args = Vec::new();
49 if let Some(model) = config.model.as_deref() {
50 args.push("--model".to_string());
51 args.push(model.to_string());
52 }
53 if config.allow_all {
54 args.push("--dangerously-skip-permissions".to_string());
55 }
56 args.push("-p".to_string());
57 args.push(config.prompt.clone());
58
59 run_streaming_cli("claude", &args, config)
60 }
61
62 /// Stops the harness. This implementation is a no-op because `run` is synchronous.
63 ///
64 /// # Examples
65 ///
66 /// ```
67 /// use ito_core::harness::{ClaudeCodeHarness, Harness};
68 ///
69 /// let mut h = ClaudeCodeHarness::default();
70 /// // Calling stop has no effect for this harness.
71 /// h.stop();
72 /// ```
73 fn stop(&mut self) {
74 // No-op: `run` is synchronous.
75 }
76
77 /// Indicates whether this harness produces streaming output.
78 ///
79 /// Returns `true` if the harness produces streaming output, `false` otherwise.
80 /// For this harness, the method always returns `true`.
81 ///
82 /// # Examples
83 ///
84 /// ```
85 /// use ito_core::harness::{ClaudeCodeHarness, Harness};
86 ///
87 /// let h = ClaudeCodeHarness::default();
88 /// assert!(h.streams_output());
89 /// ```
90 fn streams_output(&self) -> bool {
91 true
92 }
93}