mythos-skill 0.1.1

Explicit-state recurrent synthesis: deterministic packet compiler for AI agent runs. Takes subagent output (evidence.jsonl, verifier findings, raw artifacts) and compiles a schema-validated, hash-provenanced next-pass packet that Prime can reason over without consuming raw subagent prose.
Documentation
use crate::schema::DecisionLogRecord;
use serde::{Deserialize, Serialize};
use std::fs::OpenOptions;
use std::io::{self, Write};
use std::path::Path;

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct JournalEvent<T> {
    pub run_id: String,
    pub pass_id: String,
    pub event_kind: String,
    pub payload: T,
}

pub fn append_event_jsonl<T>(path: &Path, event: &JournalEvent<T>) -> io::Result<()>
where
    T: Serialize,
{
    let mut file = OpenOptions::new().create(true).append(true).open(path)?;
    serde_json::to_writer(&mut file, event).map_err(io::Error::other)?;
    file.write_all(b"\n")?;
    Ok(())
}

pub fn append_decision_log(path: &Path, record: &DecisionLogRecord) -> io::Result<()> {
    let mut file = OpenOptions::new().create(true).append(true).open(path)?;
    serde_json::to_writer(&mut file, record).map_err(io::Error::other)?;
    file.write_all(b"\n")?;
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::{JournalEvent, append_decision_log, append_event_jsonl};
    use crate::schema::DecisionLogRecord;
    use serde_json::Value;
    use std::fs;

    #[test]
    fn appends_jsonl_events() {
        let path = std::env::temp_dir().join("mythos-compiler-journal.jsonl");
        let _ = fs::remove_file(&path);
        let event = JournalEvent {
            run_id: "run-1".to_string(),
            pass_id: "pass-1".to_string(),
            event_kind: "packet-built".to_string(),
            payload: serde_json::json!({"ok": true}),
        };

        append_event_jsonl(&path, &event).expect("append event");

        let written = fs::read_to_string(&path).expect("read journal");
        let first_line = written.lines().next().expect("line");
        let parsed: Value = serde_json::from_str(first_line).expect("valid json");
        assert_eq!(parsed["event_kind"], "packet-built");

        let _ = fs::remove_file(&path);
    }

    #[test]
    fn appends_raw_decision_log_records() {
        let path = std::env::temp_dir().join("mythos-compiler-decisions.jsonl");
        let _ = fs::remove_file(&path);

        let record = DecisionLogRecord {
            id: "decision-1".to_string(),
            run_id: "run-1".to_string(),
            pass_id: "pass-1".to_string(),
            decision_kind: "promote".to_string(),
            summary: "promote directive".to_string(),
            source_ids: vec!["src-1".to_string()],
            selected_action_ids: vec!["act-1".to_string()],
            created_at: "2026-04-21T00:00:00Z".to_string(),
            promotion: None,
        };

        append_decision_log(&path, &record).expect("append decision log");

        let written = fs::read_to_string(&path).expect("read decisions");
        let first_line = written.lines().next().expect("line");
        let parsed: Value = serde_json::from_str(first_line).expect("valid json");
        assert_eq!(parsed["id"], "decision-1");
        assert!(parsed.get("payload").is_none());

        let _ = fs::remove_file(&path);
    }
}