Skip to main content

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}