use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct Preset {
pub id: String,
pub title: String,
pub direction: String,
pub capability: String,
pub summary: String,
pub task: String,
pub invariants: Vec<String>,
pub context_recipe: String,
pub verify: String,
}
struct Seed {
id: &'static str,
title: &'static str,
direction: &'static str,
capability: &'static str,
summary: &'static str,
task: &'static str,
invariants: &'static [&'static str],
context_recipe: &'static str,
verify: &'static str,
}
const VERIFY_DEFAULT: &str =
"cargo build && cargo test; no clippy regressions; public API unchanged unless intended.";
const SEEDS: &[Seed] = &[
Seed {
id: "symbol-context-selection",
title: "Symbol-level context selection",
direction: "context",
capability: "memory",
summary: "Select relevant functions/signatures for a task, not whole files.",
task: "In src/evolve/context_selector.rs and src/evolve/map.rs, add symbol-level \
selection: given a task target, pick only the relevant functions/impls/signatures \
(via the AST/structure analyzer) instead of whole files, and assemble those as the \
context. Add an endpoint /api/context/select/symbols and a 'specialized' tier. \
Measure the token reduction vs file-level selection.",
invariants: &[
"Cited evidence stays line-accurate to the original source.",
"Selection is deterministic for the same target + graph revision.",
"No symbol is included without its enclosing type/trait context.",
],
context_recipe: "map + task-scoped signatures",
verify: "New unit tests for symbol extraction; token count strictly lower than file-level for the same task.",
},
Seed {
id: "dedup-clutter-strip",
title: "Dedup + clutter-strip before tokenizing",
direction: "context",
capability: "memory",
summary: "Remove duplicate content and strip comments/imports/inline-tests before the tokenizer.",
task: "Add a context-reduction pass that runs before token counting and before content is \
sent: reuse src/evolve/fn_dedup.rs to drop duplicated function bodies, strip comments \
(src/evolve/context_reduce.rs), use-imports, and inline #[cfg(test)] blocks. Apply it \
to map expansion and evidence assembly. Report tokens saved.",
invariants: &[
"Stripping never changes the meaning of retained code.",
"Line numbers in emitted evidence stay self-consistent with the stripped text.",
"Deduplication keeps at least one canonical copy and links the rest.",
],
context_recipe: "compact (comment-stripped) + dedup",
verify: "Golden tests: stripped output parses; dedup count matches fn_dedup; measured token drop.",
},
Seed {
id: "split-giant-files",
title: "Split the 3 giant files",
direction: "refactor",
capability: "tool_dispatch",
summary: "Break tool_dispatch.rs / cli/mod.rs / interactive.rs into cohesive modules.",
task: "Refactor src/agent/tool_dispatch.rs (~4000 lines), src/cli/mod.rs (~4400), and \
src/agent/interactive.rs (~3500) into submodules along responsibility seams \
(e.g. tool_dispatch: result_summary, error_kind, command_analysis, confirmation, \
execution). Move one cohesive group at a time; keep impl blocks split across files. \
Preserve the public API via re-exports.",
invariants: &[
"Zero behavior change — pure refactor.",
"The full test suite is green after every moved group.",
"Public API (paths, signatures) is preserved via re-exports.",
],
context_recipe: "full (target file) + dependents' signatures",
verify: "cargo build && cargo test green at each step; git diff shows moves, not rewrites.",
},
Seed {
id: "add-tool",
title: "Add a new tool",
direction: "capability",
capability: "tool_dispatch",
summary: "Register a new tool in the ToolRegistry with safety + tests.",
task: "Add a new tool to src/tools/ and register it in the ToolRegistry. Wire it through the \
safety gate, add its schema, and cover it with unit + integration tests. Replace \
<TOOL> with the concrete tool to build.",
invariants: &[
"Every tool call passes the safety check before execution.",
"The tool declares whether it is parallel-safe.",
"A denied call never mutates state.",
],
context_recipe: "map + tools module signatures",
verify: VERIFY_DEFAULT,
},
Seed {
id: "add-context-tier",
title: "Add a context tier / recipe",
direction: "context",
capability: "memory",
summary: "Add a new named context recipe for a common interaction.",
task: "Add a new context recipe to the tier system (src/evolve/context.rs + map.rs) that \
auto-composes the right content for a named interaction (e.g. 'fix-bug', 'extend', \
'review'), including the logical-layer invariants of the touched capability.",
invariants: &[
"Token size is reported honestly (measured, not guessed).",
"The recipe is reproducible for the same inputs.",
],
context_recipe: "logical capability + selection",
verify: VERIFY_DEFAULT,
},
Seed {
id: "add-loop-type",
title: "Add a loop type",
direction: "automation",
capability: "task_loop",
summary: "Add a first-class loop type (review / watch / cron) to the loop registry.",
task: "Add a new loop type as a first-class object with type, trigger, context recipe, state, \
and history, integrated with the AgentState machine and the evolution loop.",
invariants: &[
"Every iteration runs budget and cancellation checks before work.",
"State advances only through the defined state machine.",
],
context_recipe: "logical (task_loop capability) + loop modules",
verify: VERIFY_DEFAULT,
},
Seed {
id: "gate-context-trust",
title: "Deepen the context trust gate",
direction: "safety",
capability: "safety",
summary: "Assistant sends are gated through evolve::context_trust (shipped 2026-07-26: high-severity findings in non-trusted evidence block with 422 context_trust_blocked). Next: role-enclosure verification and perplexity/entropy anomaly detection.",
task: "Extend the evidence trust gate in src/evolve/assistant.rs (gate_evidence_trust) with role-enclosure \
verification (content must not reframe itself as system/role messages mid-evidence) and a \
perplexity/entropy anomaly check for machine-generated payloads, keeping the invariant below.",
invariants: &[
"High-severity findings in non-trusted evidence block the send before any model call.",
"Trusted first-party code is reported, never blocked.",
],
context_recipe: "custom (safety + evolve::context_trust + assistant)",
verify: "cargo test --lib trust_gate; blocked send returns 422 context_trust_blocked.",
},
Seed {
id: "add-perspective",
title: "Add a comprehension perspective",
direction: "comprehension",
capability: "interface",
summary: "Add a new graph lens / view for understanding the system.",
task: "Add a new perspective (lens) to the graph UI that recolors/regroups nodes by a new \
dimension (e.g. churn, coverage, complexity, coupling), with a legend and backing data.",
invariants: &[
"Rendering never blocks the task loop.",
"The lens degrades gracefully when a dimension is absent on a node.",
],
context_recipe: "map + web assets signatures",
verify: "Served assets updated; lens data present on nodes; UI smoke test green.",
},
];
pub fn presets() -> Vec<Preset> {
SEEDS
.iter()
.map(|s| Preset {
id: s.id.to_string(),
title: s.title.to_string(),
direction: s.direction.to_string(),
capability: s.capability.to_string(),
summary: s.summary.to_string(),
task: normalize_ws(s.task),
invariants: s.invariants.iter().map(|i| i.to_string()).collect(),
context_recipe: s.context_recipe.to_string(),
verify: s.verify.to_string(),
})
.collect()
}
pub fn preset(id: &str) -> Option<Preset> {
presets().into_iter().find(|p| p.id == id)
}
pub fn render_prompt(p: &Preset) -> String {
let invariants = p
.invariants
.iter()
.map(|i| format!("- {i}"))
.collect::<Vec<_>>()
.join("\n");
format!(
"{task}\n\nInvariants you MUST preserve (refuse the change if any would break):\n{invariants}\n\nContext recipe: {recipe}\nVerify: {verify}",
task = p.task,
recipe = p.context_recipe,
verify = p.verify,
)
}
fn normalize_ws(s: &str) -> String {
s.split_whitespace().collect::<Vec<_>>().join(" ")
}
#[cfg(test)]
#[path = "../../tests/unit/evolve/presets_test.rs"]
mod presets_test;