use std::path::Path;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Stack {
pub name: &'static str,
pub marker: &'static str,
pub test: &'static str,
pub format: &'static str,
}
pub const KNOWN: [Stack; 4] = [
Stack {
name: "rust",
marker: "Cargo.toml",
test: "cargo test",
format: "cargo fmt",
},
Stack {
name: "node",
marker: "package.json",
test: "npm test",
format: "npm run format",
},
Stack {
name: "python",
marker: "pyproject.toml",
test: "pytest",
format: "ruff format .",
},
Stack {
name: "go",
marker: "go.mod",
test: "go test ./...",
format: "gofmt -w .",
},
];
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Seed {
pub source: String,
pub fact: String,
}
pub fn known(name: &str) -> Option<Stack> {
KNOWN.into_iter().find(|s| s.name == name)
}
pub fn stacks(repo: &Path) -> Vec<Stack> {
KNOWN
.into_iter()
.filter(|s| repo.join(s.marker).exists())
.collect()
}
pub fn preferred_harness(
candidates: &[String],
installed_on_host: &dyn Fn(&str) -> bool,
) -> Option<String> {
candidates
.iter()
.find(|c| installed_on_host(c))
.or_else(|| candidates.first())
.cloned()
}
pub fn seeds(repo: &Path) -> Vec<Seed> {
let mut out = Vec::new();
if let Ok(readme) = std::fs::read_to_string(repo.join("README.md")) {
if let Some(line) = readme
.lines()
.map(|l| l.trim().trim_start_matches('>').trim())
.find(|l| {
!l.is_empty()
&& !l.starts_with('#')
&& !l.starts_with("[!")
&& !l.starts_with("![")
&& !l.starts_with("---")
})
{
out.push(Seed {
source: "README.md".into(),
fact: line.to_string(),
});
}
}
for s in stacks(repo) {
out.push(Seed {
source: s.marker.into(),
fact: format!(
"stack: {} (test `{}`, format `{}`)",
s.name, s.test, s.format
),
});
}
for rules in ["AGENTS.md", "CLAUDE.md"] {
if let Ok(body) = std::fs::read_to_string(repo.join(rules)) {
if !body.trim().is_empty() {
out.push(Seed {
source: rules.into(),
fact: format!("existing conventions ({} lines)", body.lines().count()),
});
}
}
}
out
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;
fn repo(files: &[(&str, &str)]) -> (tempfile::TempDir, PathBuf) {
let dir = tempfile::tempdir().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
for (name, body) in files {
let p = root.join(name);
std::fs::create_dir_all(p.parent().unwrap()).unwrap();
std::fs::write(p, body).unwrap();
}
(dir, root)
}
#[test]
fn a_manifest_identifies_the_stack() {
let (_d, r) = repo(&[("Cargo.toml", "[package]")]);
let found = stacks(&r);
assert_eq!(found.len(), 1);
assert_eq!(found[0].name, "rust");
}
#[test]
fn a_polyglot_repo_reports_every_stack() {
let (_d, r) = repo(&[("Cargo.toml", ""), ("package.json", "{}")]);
let names: Vec<_> = stacks(&r).into_iter().map(|s| s.name).collect();
assert_eq!(names, ["rust", "node"]);
}
#[test]
fn no_marker_means_no_stack_rather_than_a_guess() {
let (_d, r) = repo(&[("README.md", "hello")]);
assert!(stacks(&r).is_empty());
}
#[test]
fn every_known_stack_supplies_commands() {
for s in KNOWN {
assert!(!s.test.is_empty(), "{} has no test command", s.name);
assert!(!s.format.is_empty(), "{} has no format command", s.name);
}
}
fn candidates() -> Vec<String> {
vec!["claude".into(), "opencode".into()]
}
#[test]
fn host_evidence_picks_the_default_harness() {
let pick = preferred_harness(&candidates(), &|h| h == "opencode");
assert_eq!(pick.as_deref(), Some("opencode"));
}
#[test]
fn nothing_installed_still_yields_a_default() {
let pick = preferred_harness(&candidates(), &|_| false);
assert_eq!(pick.as_deref(), Some("claude"));
}
#[test]
fn no_adapters_means_no_preference() {
assert_eq!(preferred_harness(&[], &|_| true), None);
}
#[test]
fn seeds_are_derived_from_what_the_repo_already_says() {
let (_d, r) = repo(&[
("README.md", "# omh\n\noh-my-zsh for agentic coding.\n"),
("Cargo.toml", "[package]\nname = \"omh\""),
]);
let s = seeds(&r);
assert!(
s.iter().any(|x| x.fact.contains("oh-my-zsh")),
"README should seed the project description: {s:?}"
);
assert!(
s.iter().any(|x| x.fact.contains("rust")),
"stack should be seeded: {s:?}"
);
}
#[test]
fn a_blockquote_tagline_is_read_as_prose() {
let (_d, r) = repo(&[("README.md", "# omh\n\n> Launch any coding harness.\n")]);
let s = seeds(&r);
let fact = &s
.iter()
.find(|x| x.source == "README.md")
.expect("README seed")
.fact;
assert_eq!(
fact, "Launch any coding harness.",
"markdown syntax is not the fact"
);
}
#[test]
fn a_badge_line_is_not_mistaken_for_a_description() {
let (_d, r) = repo(&[(
"README.md",
"# p\n\n[](https://ci)\n\nA real description.\n",
)]);
let s = seeds(&r);
let fact = &s
.iter()
.find(|x| x.source == "README.md")
.expect("README seed")
.fact;
assert_eq!(fact, "A real description.");
}
#[test]
fn every_seed_cites_its_source() {
let (_d, r) = repo(&[("README.md", "# p\n\nA thing.\n"), ("go.mod", "module x")]);
for seed in seeds(&r) {
assert!(!seed.source.is_empty(), "unsourced seed: {seed:?}");
}
}
#[test]
fn an_empty_repo_seeds_nothing_rather_than_inventing() {
let (_d, r) = repo(&[]);
assert!(seeds(&r).is_empty());
}
#[test]
fn existing_rules_are_seeded_so_conventions_survive() {
let (_d, r) = repo(&[("AGENTS.md", "# Rules\n\nTDD always.\n")]);
let s = seeds(&r);
assert!(
s.iter().any(|x| x.source.contains("AGENTS.md")),
"got: {s:?}"
);
}
}