Skip to main content

Registry

Struct Registry 

Source
pub struct Registry { /* private fields */ }
Expand description

An open set of harnesses. Build it with the ones you want — the built-ins (Bob/Claude/Codex) and/or your own:

use harness::Registry;
let reg = Registry::new()
    .register(harness::Bob::new());
    // .register(MyCustomHarness::new())   // your own impl Harness
assert!(reg.by_id("bob").is_some());

Implementations§

Source§

impl Registry

Source

pub fn new() -> Self

An empty registry.

Examples found in repository?
examples/custom_harness.rs (line 176)
174fn main() -> Result<(), String> {
175    // Register your harness alongside (or instead of) the built-ins — no fork.
176    let reg = Registry::new().register(EchoHarness);
177    let h = reg.by_id(ECHO_ID).expect("registered");
178    println!("harness: {} — {}", h.info().display_name, h.info().description);
179
180    let (tx, rx) = sync_channel::<RunEvent>(64);
181    let on_event: RunCallback = Arc::new(move |ev| {
182        let _ = tx.send(ev);
183    });
184    let _handle = h.run(
185        RunRequest {
186            run_id: "demo".into(),
187            prompt: "hello".into(),
188            cwd: None,
189            mode: RunMode::Ask,
190            tuning: RunTuning::default(),
191        },
192        on_event,
193    )
194    .map_err(|e| e.to_string())?;
195
196    // One normalized stream — same as for any built-in harness.
197    for ev in rx {
198        match ev {
199            RunEvent::Session { model, .. } => println!("[session] model={model:?}"),
200            RunEvent::Text { delta, .. } => println!("[answer] {delta}"),
201            RunEvent::Exited { exit_code, .. } => {
202                println!("[exited] {exit_code:?}");
203                break;
204            }
205            other => println!("{other:?}"),
206        }
207    }
208    Ok(())
209}
Source

pub fn register(self, harness: impl Harness + 'static) -> Self

Add a harness. Chainable. Registration order is preserved (it’s the UI display order; the first registered is the conventional default).

Examples found in repository?
examples/custom_harness.rs (line 176)
174fn main() -> Result<(), String> {
175    // Register your harness alongside (or instead of) the built-ins — no fork.
176    let reg = Registry::new().register(EchoHarness);
177    let h = reg.by_id(ECHO_ID).expect("registered");
178    println!("harness: {} — {}", h.info().display_name, h.info().description);
179
180    let (tx, rx) = sync_channel::<RunEvent>(64);
181    let on_event: RunCallback = Arc::new(move |ev| {
182        let _ = tx.send(ev);
183    });
184    let _handle = h.run(
185        RunRequest {
186            run_id: "demo".into(),
187            prompt: "hello".into(),
188            cwd: None,
189            mode: RunMode::Ask,
190            tuning: RunTuning::default(),
191        },
192        on_event,
193    )
194    .map_err(|e| e.to_string())?;
195
196    // One normalized stream — same as for any built-in harness.
197    for ev in rx {
198        match ev {
199            RunEvent::Session { model, .. } => println!("[session] model={model:?}"),
200            RunEvent::Text { delta, .. } => println!("[answer] {delta}"),
201            RunEvent::Exited { exit_code, .. } => {
202                println!("[exited] {exit_code:?}");
203                break;
204            }
205            other => println!("{other:?}"),
206        }
207    }
208    Ok(())
209}
Source

pub fn by_id(&self, id: &str) -> Option<&dyn Harness>

Resolve a harness by its HarnessInfo::id.

Examples found in repository?
examples/custom_harness.rs (line 177)
174fn main() -> Result<(), String> {
175    // Register your harness alongside (or instead of) the built-ins — no fork.
176    let reg = Registry::new().register(EchoHarness);
177    let h = reg.by_id(ECHO_ID).expect("registered");
178    println!("harness: {} — {}", h.info().display_name, h.info().description);
179
180    let (tx, rx) = sync_channel::<RunEvent>(64);
181    let on_event: RunCallback = Arc::new(move |ev| {
182        let _ = tx.send(ev);
183    });
184    let _handle = h.run(
185        RunRequest {
186            run_id: "demo".into(),
187            prompt: "hello".into(),
188            cwd: None,
189            mode: RunMode::Ask,
190            tuning: RunTuning::default(),
191        },
192        on_event,
193    )
194    .map_err(|e| e.to_string())?;
195
196    // One normalized stream — same as for any built-in harness.
197    for ev in rx {
198        match ev {
199            RunEvent::Session { model, .. } => println!("[session] model={model:?}"),
200            RunEvent::Text { delta, .. } => println!("[answer] {delta}"),
201            RunEvent::Exited { exit_code, .. } => {
202                println!("[exited] {exit_code:?}");
203                break;
204            }
205            other => println!("{other:?}"),
206        }
207    }
208    Ok(())
209}
More examples
Hide additional examples
examples/verify_enrichment.rs (line 22)
16fn main() -> Result<(), String> {
17    let id = std::env::args().nth(1).unwrap_or_else(|| "claude".to_owned());
18    let prompt = std::env::args().nth(2).unwrap_or_else(|| default_prompt(&id));
19
20    let reg = default_registry();
21    let h = reg
22        .by_id(&id)
23        .ok_or_else(|| format!("unknown/disabled harness: {id}"))?;
24
25    // Cheapest viable settings (per the "don't burn tokens" rule).
26    let tuning = match id.as_str() {
27        "claude" => RunTuning { model: Some("haiku".to_owned()), ..RunTuning::default() },
28        "codex" => RunTuning { effort: Some(ReasoningEffort::Low), ..RunTuning::default() },
29        _ => RunTuning::default(),
30    };
31
32    let (tx, rx) = sync_channel::<RunEvent>(256);
33    let on_event: RunCallback = Arc::new(move |ev| {
34        let _ = tx.send(ev);
35    });
36
37    eprintln!("── running {id} ──");
38    let _handle = h.run(
39        RunRequest {
40            run_id: "verify".into(),
41            prompt,
42            cwd: Some(std::env::current_dir().map_err(|e| e.to_string())?),
43            mode: RunMode::Ask,
44            tuning,
45        },
46        on_event,
47    )
48    .map_err(|e| e.to_string())?;
49
50    let (mut session, mut tool_input, mut tool_output, mut usage) = (false, false, false, false);
51    for ev in rx {
52        print_event(&ev);
53        match &ev {
54            RunEvent::Session { session_id, model, .. } => {
55                session = session_id.is_some() || model.is_some();
56            }
57            RunEvent::ToolStart { input, .. } => tool_input |= input.is_some(),
58            RunEvent::ToolEnd { output, .. } => tool_output |= output.is_some(),
59            RunEvent::Usage { input_tokens, output_tokens, total_tokens, .. } => {
60                usage = input_tokens.is_some() || output_tokens.is_some() || total_tokens.is_some();
61            }
62            RunEvent::Exited { .. } => break,
63            _ => {}
64        }
65    }
66    eprintln!(
67        "\n── enrichment seen from real {id}: session={session} tool_input={tool_input} tool_output={tool_output} usage={usage}"
68    );
69    Ok(())
70}
Source

pub fn catalog(&self) -> Vec<HarnessInfo>

Metadata for every registered harness, in registration order.

Source

pub fn ids(&self) -> Vec<String>

The ids of every registered harness, in registration order.

Trait Implementations§

Source§

impl Default for Registry

Source§

fn default() -> Registry

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.