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}