Skip to main content

ito_core/harness/
codex.rs

1use super::streaming_cli::run_streaming_cli;
2use super::types::{Harness, HarnessName, HarnessRunConfig, HarnessRunResult};
3use miette::Result;
4
5/// Runs the `codex` CLI in non-interactive exec mode (`codex exec`).
6/// Selected via `ito ralph --harness codex`; requires the Codex CLI on PATH.
7#[derive(Debug, Default)]
8pub struct CodexHarness;
9
10impl Harness for CodexHarness {
11    /// Identify this harness implementation as the Codex harness.
12    ///
13    /// # Examples
14    ///
15    /// ```
16    /// use ito_core::harness::{CodexHarness, Harness, HarnessName};
17    ///
18    /// let h = CodexHarness::default();
19    /// assert_eq!(h.name(), HarnessName::CODEX);
20    /// ```
21    fn name(&self) -> HarnessName {
22        HarnessName::CODEX
23    }
24
25    /// Execute the `codex` CLI with arguments derived from `config` and stream its output.
26    ///
27    /// The constructed command begins with `"exec"`, includes `--model <model>` if `config.model` is set,
28    /// appends `--yolo` when `config.allow_all` is true, and appends `config.prompt` as the final argument.
29    ///
30    /// # Returns
31    ///
32    /// The resulting `HarnessRunResult` on success.
33    ///
34    /// # Examples
35    ///
36    ///
37    fn run(&mut self, config: &HarnessRunConfig) -> Result<HarnessRunResult> {
38        let mut args = vec!["exec".to_string()];
39        if let Some(model) = config.model.as_deref() {
40            args.push("--model".to_string());
41            args.push(model.to_string());
42        }
43        if config.allow_all {
44            args.push("--yolo".to_string());
45        }
46        args.push(config.prompt.clone());
47
48        run_streaming_cli("codex", &args, config)
49    }
50
51    /// Performs no action; provided to satisfy the `Harness` trait.
52    ///
53    /// This method is intentionally empty because `run` executes synchronously and there is nothing to stop.
54    ///
55    /// # Examples
56    ///
57    /// ```
58    /// use ito_core::harness::{CodexHarness, Harness};
59    ///
60    /// let mut h = CodexHarness::default();
61    /// h.stop();
62    /// ```
63    fn stop(&mut self) {
64        // No-op: `run` is synchronous.
65    }
66
67    /// Indicates whether this harness emits output incrementally (streaming) during a run.
68    ///
69    /// # Returns
70    ///
71    /// `true` if the harness streams output as it runs, `false` otherwise.
72    ///
73    /// # Examples
74    ///
75    /// ```
76    /// use ito_core::harness::{CodexHarness, Harness};
77    ///
78    /// let h = CodexHarness::default();
79    /// assert!(h.streams_output());
80    /// ```
81    fn streams_output(&self) -> bool {
82        true
83    }
84}