use std::time::Duration;
use io_harness::{
run_with, ApproveAll, OpenRouter, Policy, RunOutcome, Store, TaskContract, Verification,
};
const NOTES: &str = "alpha ERROR disk full
beta ok
gamma ERROR timeout
delta ok
epsilon ERROR disk full
zeta ok
";
#[tokio::main]
async fn main() -> io_harness::Result<()> {
let dir = tempfile::tempdir().expect("a workspace");
std::fs::write(dir.path().join("notes.txt"), NOTES).expect("the fixture");
let provider = OpenRouter::from_env()?;
let store = Store::open(dir.path().join("trace.db"))?;
let contract = TaskContract::workspace(
"notes.txt has one record per line. Count how many lines contain the word ERROR \
and write just that number into a file called count.txt in the workspace root. \
Use the shell tool.",
dir.path(),
)
.with_verification(Verification::WorkspaceFileContains {
file: "count.txt".into(),
needle: "3".into(),
})
.with_max_steps(8)
.with_exec_timeout(Duration::from_secs(60));
let policy = Policy::default()
.layer("live")
.allow_read("*")
.allow_write("count.txt")
.deny_write("notes.txt")
.allow_exec("grep*")
.allow_exec("wc*")
.allow_exec("cat*")
.allow_exec("sort*")
.allow_exec("uniq*")
.allow_exec("tr*")
.allow_exec("head*")
.allow_exec("tail*")
.deny_exec("rm*")
.deny_exec("curl*")
.deny_exec("git*");
println!("workspace: {}", dir.path().display());
let result = run_with(&contract, &provider, &store, &policy, &ApproveAll).await?;
println!("outcome: {:?}", result.outcome);
println!("\n--- what the model actually ran ---");
for step in store.steps(result.run_id)? {
if !step.tool_call.is_empty() {
let args: serde_json::Value = serde_json::from_str(&step.tool_call).unwrap_or_default();
match args.get("line").and_then(|v| v.as_str()) {
Some(l) => println!(" step {}: {l}", step.step),
None => println!(" step {}: {}", step.step, step.tool_call),
}
}
println!(" -> {}", step.decision);
}
println!("\n--- policy decisions ---");
for ev in store.events(result.run_id)? {
println!(
" step {} {} {} {:?} (rule {:?}, layer {:?})",
ev.step, ev.kind, ev.act, ev.target, ev.rule, ev.layer
);
}
let produced = std::fs::read_to_string(dir.path().join("count.txt"));
println!("\ncount.txt = {produced:?}");
println!(
"verified: {}",
matches!(result.outcome, RunOutcome::Success { .. })
);
Ok(())
}