2 Commits
Author SHA1 Message Date
Omar SobhandClaude Opus 5 2eb0880fc0 fix(skills): reconcile team-template skill names so role bindings actually bind
ci / gates (push) Successful in 5s
ci / rust (push) Failing after 10s
ci / frontend (push) Failing after 19s
ci / e2e (push) Skipped
ci / publish (push) Skipped
Every skill reference in every team template was failing to resolve. The
TOMLs used snake_case slugs (`write_rust`, `index_selection`) while the
authored skills under `skills/**/*.md` declare kebab-case names
(`write-rust-current-edition`, `postgres-index-selection`), so
`get_by_name` missed on all of them: 128 skipped bindings across 51
distinct names, and no mission agent received any of its template's
skills.

The mirror-image half was equally invisible: ten authored skills —
including `int-xx-marker-protocol`, whose own `when_to_use` says "pin on
every coding role" — were referenced by no role at all, so nothing could
ever load them.

- Rename the 14 references that have authored skills behind them, and
  dedupe the two that now collapse onto the commit-protocol skill.
- Attach all ten orphaned skills to the roles their `when_to_use` names.
  All 23 authored skills now reach at least one role.
- Aggregate the loader's per-name logging into one line per template.
  The old per-name spam is why this went unnoticed; a bound/unresolved
  count is noticeable. References with no authored skill are kept and
  listed — they record intent for skills not yet written.
- Two regression tests: no authored skill may be orphaned, and every
  authored skill must be referenced by its exact name.

Also clears the two standing clippy warnings: group
`mint_team_from_template`'s eight positional args into `TeamMint`, and
make `provider_alias_for` branch on `is_exact_provider_match` so the
helper is live code and the two can't disagree about what counts as an
exact family match.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-07-31 19:47:18 -07:00
Omar SobhandClaude Opus 5 95bd65540c docs(missions): record why template role prose is not deletable
Plan §12 proposed deleting the ~1,250 lines of `system_prompt` prose across
the 23 team templates as instruction-shaped injection. Tracing the two
prompt paths shows that would be strictly harmful:

- Missions never see it. `topology_exec::build_prompt` synthesizes its own
  one-line system text from the role slot, so the prose costs zero mission
  tokens and deleting it saves zero.
- Chat depends on it. `mission_orchestrator` copies it into
  `agents.system_prompt`, which is the base prompt
  `cm_runtime::brain::compose_system` augments for a claw's chat turns.
  Deleting it leaves every mission-minted claw with no identity in chat.

The prose is also mostly information (domain standards, wire discipline)
rather than instructions restating general competence, which is the kind
ablation keeps. Comment left at the one injection site so this isn't
re-derived.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-07-31 19:20:43 -07:00
14 changed files with 222 additions and 77 deletions
+37 -10
View File
@@ -186,13 +186,15 @@ pub async fn on_launch(
mission.title, purpose, template.template.name mission.title, purpose, template.template.name
); );
let team_id = mint_team_from_template( let team_id = mint_team_from_template(
TeamMint {
pool, pool,
workspace_id, workspace_id,
user_id, user_id,
provisioner.as_ref(), provisioner: provisioner.as_ref(),
&template, template: &template,
&team_name, team_name: &team_name,
"claude-sonnet-5", default_model: "claude-sonnet-5",
},
&mut provisioned_claws, &mut provisioned_claws,
) )
.await?; .await?;
@@ -298,16 +300,33 @@ pub async fn on_launch(
Ok(Some(team_id)) Ok(Some(team_id))
} }
async fn mint_team_from_template( /// The read-only inputs for minting a team. Grouped into a struct so the
pool: &PgPool, /// signature stays readable as the orchestrator accumulates context — the
/// growing positional list was also easy to mis-order at the call site,
/// since `team_name` and `default_model` are both `&str`.
struct TeamMint<'a> {
pool: &'a PgPool,
workspace_id: WorkspaceId, workspace_id: WorkspaceId,
user_id: cm_domain::UserId, user_id: cm_domain::UserId,
provisioner: Option<&RuntimeProvisioner>, provisioner: Option<&'a RuntimeProvisioner>,
template: &TeamTemplateDetail, template: &'a TeamTemplateDetail,
team_name: &str, team_name: &'a str,
default_model: &str, default_model: &'a str,
}
async fn mint_team_from_template(
mint: TeamMint<'_>,
provisioned_claws: &mut Vec<cm_domain::AgentId>, provisioned_claws: &mut Vec<cm_domain::AgentId>,
) -> Result<Uuid, String> { ) -> Result<Uuid, String> {
let TeamMint {
pool,
workspace_id,
user_id,
provisioner,
template,
team_name,
default_model,
} = mint;
// Build the topology graph from role slots so the team's `graph` // Build the topology graph from role slots so the team's `graph`
// NOT NULL column is satisfied + downstream topology executors // NOT NULL column is satisfied + downstream topology executors
// have a valid shape to iterate over. // have a valid shape to iterate over.
@@ -364,6 +383,14 @@ async fn mint_team_from_template(
workspace_id, workspace_id,
name: format!("{} · {}", team_name, role.slot), name: format!("{} · {}", team_name, role.slot),
job_title: role.slot.clone(), job_title: role.slot.clone(),
// This is the ONLY consumer of the templates' `system_prompt` prose,
// and it feeds the *chat* path, not missions: it lands in
// `agents.system_prompt`, which `cm_runtime::brain::compose_system`
// uses as the base prompt for a claw's chat turns. A mission turn
// never sees it — `topology_exec::build_prompt` synthesizes its own
// one-line system text from the role slot alone. So deleting the
// template prose to save mission tokens would save exactly zero and
// would leave every mission-minted claw with no identity in chat.
system_prompt: role.system_prompt.clone(), system_prompt: role.system_prompt.clone(),
avatar: String::new(), avatar: String::new(),
accent: default_accent_for(&role.slot).to_string(), accent: default_accent_for(&role.slot).to_string(),
+15 -8
View File
@@ -29,14 +29,15 @@ pub fn claw_alias(claw_id: Uuid) -> String {
pub fn provider_alias_for(model: &str) -> &'static str { pub fn provider_alias_for(model: &str) -> &'static str {
let m = model.trim().to_ascii_lowercase(); let m = model.trim().to_ascii_lowercase();
// Prefix families first (covers claude-sonnet-5, claude-opus-4-8, // Prefix families first (covers claude-sonnet-5, claude-opus-4-8,
// claude-haiku-4-5-*, etc.) then explicit aliases. // claude-haiku-4-5-*, etc.) then explicit aliases. `is_exact_provider_match`
// decides what "its own family" means, so the two can't drift apart.
if is_exact_provider_match(&m) {
if m.starts_with("claude") { if m.starts_with("claude") {
return "anthropic.default"; return "anthropic.default";
} }
if m.starts_with("gemini") { if m.starts_with("gemini") {
return "gemini.default"; return "gemini.default";
} }
if m.starts_with("llama") || m.starts_with("groq") {
return "groq.default"; return "groq.default";
} }
match m.as_str() { match m.as_str() {
@@ -69,12 +70,13 @@ pub fn provider_alias_for(model: &str) -> &'static str {
} }
} }
/// Whether `provider_alias_for` resolved this model to its own family, or /// Whether `provider_alias_for` resolves this model to its own family, or
/// substituted a different one. /// substitutes a different one.
/// ///
/// Callers that surface a model choice to a user can use this to say so rather /// `provider_alias_for` branches on this, so it is the single definition of
/// than letting the substitution be discovered on an invoice. Kept alongside /// "its own family". Also public for callers that surface a model choice to a
/// `provider_alias_for` so the two can't disagree about what counts as a match. /// user, so a substitution can be said out loud rather than discovered on an
/// invoice.
pub fn is_exact_provider_match(model: &str) -> bool { pub fn is_exact_provider_match(model: &str) -> bool {
let m = model.trim().to_ascii_lowercase(); let m = model.trim().to_ascii_lowercase();
m.starts_with("claude") m.starts_with("claude")
@@ -350,7 +352,12 @@ mod tests {
"{m} resolves to anthropic.default by substitution, not by family" "{m} resolves to anthropic.default by substitution, not by family"
); );
} }
for m in ["claude-sonnet-5", "gemini-2.5-flash", "groq-llama", "llama3"] { for m in [
"claude-sonnet-5",
"gemini-2.5-flash",
"groq-llama",
"llama3",
] {
assert!( assert!(
super::is_exact_provider_match(m), super::is_exact_provider_match(m),
"{m} should resolve to its own family" "{m} should resolve to its own family"
+117 -6
View File
@@ -167,6 +167,13 @@ async fn load_one(pool: &PgPool, path: &std::path::Path) -> Result<String, Strin
{ {
eprintln!("team_template_loader: clear_template_role_skills({key}) failed: {e}"); eprintln!("team_template_loader: clear_template_role_skills({key}) failed: {e}");
} }
// Unresolved names are aggregated into one line per template rather than
// logged individually: the per-name spam (128 lines at last count) scrolled
// past unread for long enough that every template's skill bindings were
// silently empty, because the TOMLs used snake_case slugs while the authored
// skills in `skills/**/*.md` use kebab-case names. A count is noticeable.
let mut unresolved: Vec<String> = Vec::new();
let mut bound = 0usize;
for role in &file.roles { for role in &file.roles {
for (idx, skill_name) in role.skills.iter().enumerate() { for (idx, skill_name) in role.skills.iter().enumerate() {
match cm_db::repo::skills_catalog::get_by_name(pool, None, skill_name).await { match cm_db::repo::skills_catalog::get_by_name(pool, None, skill_name).await {
@@ -188,20 +195,124 @@ async fn load_one(pool: &PgPool, path: &std::path::Path) -> Result<String, Strin
"team_template_loader: attach skill {skill_name} → {key}.{}: {e}", "team_template_loader: attach skill {skill_name} → {key}.{}: {e}",
role.slot role.slot
); );
} else {
bound += 1;
} }
} }
Ok(None) => { Ok(None) => unresolved.push(format!("{}.{skill_name}", role.slot)),
eprintln!(
"team_template_loader: skill '{skill_name}' referenced by {key}.{} not found — skipped",
role.slot
);
}
Err(e) => { Err(e) => {
eprintln!("team_template_loader: lookup skill '{skill_name}' failed: {e}"); eprintln!("team_template_loader: lookup skill '{skill_name}' failed: {e}");
} }
} }
} }
} }
if unresolved.is_empty() {
eprintln!("team_template_loader: {key} — {bound} role skills bound");
} else {
eprintln!(
"team_template_loader: {key} — {bound} role skills bound, {} unresolved (no such skill authored under skills/): {}",
unresolved.len(),
unresolved.join(", "),
);
}
Ok(key) Ok(key)
} }
#[cfg(test)]
mod tests {
use std::collections::HashSet;
use std::path::{Path, PathBuf};
fn repo_root() -> PathBuf {
// crates/cm-api → repo root
Path::new(env!("CARGO_MANIFEST_DIR"))
.ancestors()
.nth(2)
.expect("repo root above crates/cm-api")
.to_path_buf()
}
fn authored_skill_names(dir: &Path, out: &mut HashSet<String>) {
let Ok(entries) = std::fs::read_dir(dir) else {
return;
};
for e in entries.flatten() {
let p = e.path();
if p.is_dir() {
authored_skill_names(&p, out);
} else if p.extension().is_some_and(|x| x == "md") {
let body = std::fs::read_to_string(&p).unwrap_or_default();
if let Some(name) = body
.lines()
.find_map(|l| l.strip_prefix("name:").map(str::trim))
{
out.insert(name.to_string());
}
}
}
}
fn referenced_skill_names() -> HashSet<String> {
let mut refs = HashSet::new();
let dir = repo_root().join("templates/teams");
for e in std::fs::read_dir(&dir)
.expect("templates/teams readable")
.flatten()
{
let body = std::fs::read_to_string(e.path()).unwrap_or_default();
let parsed: toml::Value = match body.parse() {
Ok(v) => v,
Err(e) => panic!("{:?} is not valid TOML: {e}", e),
};
if let Some(roles) = parsed.get("roles").and_then(|r| r.as_array()) {
for role in roles {
if let Some(skills) = role.get("skills").and_then(|s| s.as_array()) {
refs.extend(skills.iter().filter_map(|s| s.as_str()).map(str::to_string));
}
}
}
}
refs
}
/// Every skill authored under `skills/**/*.md` must be reachable by at
/// least one team role.
///
/// This is the half of the naming drift that was invisible: the TOMLs used
/// snake_case slugs (`write_rust`) while the authored skills use kebab-case
/// names (`write-rust-current-edition`), so `get_by_name` missed on every
/// lookup — no role got any skill, and ten authored skills were reachable
/// by nobody. Both halves are silent at runtime; only a test catches them.
#[test]
fn every_authored_skill_is_referenced_by_some_role() {
let mut authored = HashSet::new();
authored_skill_names(&repo_root().join("skills"), &mut authored);
assert!(
!authored.is_empty(),
"no authored skills found — check the skills/ path"
);
let referenced = referenced_skill_names();
let orphans: Vec<_> = authored.difference(&referenced).cloned().collect();
assert!(
orphans.is_empty(),
"authored skills no team role references (they can never reach an agent): {orphans:?}"
);
}
/// A referenced name that matches no authored skill binds to nothing. Some
/// are deliberately aspirational, so this asserts the *resolvable* ones
/// stay resolvable rather than demanding every name exist.
#[test]
fn referenced_skills_that_exist_use_the_authored_spelling() {
let mut authored = HashSet::new();
authored_skill_names(&repo_root().join("skills"), &mut authored);
let referenced = referenced_skill_names();
let resolvable = referenced.intersection(&authored).count();
assert_eq!(
resolvable,
authored.len(),
"every authored skill should be referenced by its exact name",
);
}
}
+5 -5
View File
@@ -10,7 +10,7 @@ version = 1
[[roles]] [[roles]]
slot = "api_designer" slot = "api_designer"
order_idx = 0 order_idx = 0
skills = ["decompose_int_items", "openapi_schema", "small_focused_commits"] skills = ["decompose-int-items", "openapi_schema", "small-focused-commits", "api-pagination-day-1"]
system_prompt = """ system_prompt = """
You are the API DESIGNER of a Backend team. You are the API DESIGNER of a Backend team.
@@ -31,7 +31,7 @@ brain_seed = """
[[roles]] [[roles]]
slot = "db_engineer" slot = "db_engineer"
order_idx = 1 order_idx = 1
skills = ["postgres_migrations", "index_selection", "explain_analyze", "write_rust", "workspace_repo_edit"] skills = ["postgres-migrations-forward-only", "postgres-index-selection", "explain_analyze", "write-rust-current-edition", "workspace-repo-commit-protocol"]
system_prompt = """ system_prompt = """
You are the DB ENGINEER of a Backend team. You are the DB ENGINEER of a Backend team.
@@ -55,7 +55,7 @@ brain_seed = """
[[roles]] [[roles]]
slot = "coder" slot = "coder"
order_idx = 2 order_idx = 2
skills = ["write_rust", "cargo_build", "cargo_test", "workspace_repo_edit", "git_commit_protocol"] skills = ["write-rust-current-edition", "cargo_build", "cargo-test-driven-development", "workspace-repo-commit-protocol", "int-xx-marker-protocol", "rust-error-handling", "rust-async-tokio-idioms"]
system_prompt = """ system_prompt = """
You are the CODER of a Backend team. You are the CODER of a Backend team.
@@ -68,7 +68,7 @@ brain_seed = ""
[[roles]] [[roles]]
slot = "tester" slot = "tester"
order_idx = 3 order_idx = 3
skills = ["cargo_test", "integration_tests_pg", "coverage_report"] skills = ["cargo-test-driven-development", "integration_tests_pg", "coverage_report", "tdd-red-green-refactor"]
system_prompt = """ system_prompt = """
You are the TESTER of a Backend team. You are the TESTER of a Backend team.
@@ -81,7 +81,7 @@ brain_seed = ""
[[roles]] [[roles]]
slot = "committer" slot = "committer"
order_idx = 4 order_idx = 4
skills = ["git_commit_protocol", "small_focused_commits"] skills = ["workspace-repo-commit-protocol", "small-focused-commits"]
system_prompt = """ system_prompt = """
You are the COMMITTER. Same protocol as rust_sdlc: only run when tests You are the COMMITTER. Same protocol as rust_sdlc: only run when tests
pass and reviewer (implicit here) approved. Emit COMPLETED: INT-<NN>. pass and reviewer (implicit here) approved. Emit COMPLETED: INT-<NN>.
+4 -4
View File
@@ -10,7 +10,7 @@ version = 1
[[roles]] [[roles]]
slot = "designer" slot = "designer"
order_idx = 0 order_idx = 0
skills = ["decompose_int_items", "design_system_check", "a11y_checklist"] skills = ["decompose-int-items", "design_system_check", "a11y_checklist"]
system_prompt = """ system_prompt = """
You are the DESIGNER of a Frontend team. You are the DESIGNER of a Frontend team.
@@ -34,7 +34,7 @@ brain_seed = """
[[roles]] [[roles]]
slot = "coder" slot = "coder"
order_idx = 1 order_idx = 1
skills = ["write_typescript_react", "tailwind_idioms", "workspace_repo_edit", "git_commit_protocol"] skills = ["write_typescript_react", "tailwind-v4-idioms", "workspace-repo-commit-protocol", "int-xx-marker-protocol", "component-4-state-model", "react-19-server-components"]
system_prompt = """ system_prompt = """
You are the CODER of a Frontend team. You are the CODER of a Frontend team.
@@ -53,7 +53,7 @@ brain_seed = """
[[roles]] [[roles]]
slot = "tester" slot = "tester"
order_idx = 2 order_idx = 2
skills = ["playwright_e2e", "vitest_unit", "a11y_axe"] skills = ["playwright_e2e", "vitest_unit", "a11y_axe", "tdd-red-green-refactor"]
system_prompt = """ system_prompt = """
You are the TESTER of a Frontend team. You are the TESTER of a Frontend team.
@@ -65,7 +65,7 @@ brain_seed = ""
[[roles]] [[roles]]
slot = "committer" slot = "committer"
order_idx = 3 order_idx = 3
skills = ["git_commit_protocol", "small_focused_commits"] skills = ["workspace-repo-commit-protocol", "small-focused-commits"]
system_prompt = """ system_prompt = """
You are the COMMITTER. Only run on green tests + a11y pass. Emit You are the COMMITTER. Only run on green tests + a11y pass. Emit
COMPLETED: INT-<NN>. COMPLETED: INT-<NN>.
+4 -4
View File
@@ -10,7 +10,7 @@ version = 1
[[roles]] [[roles]]
slot = "arch_analyst" slot = "arch_analyst"
order_idx = 0 order_idx = 0
skills = ["decompose_int_items", "gpu_arch_reference", "roofline_model"] skills = ["decompose-int-items", "gpu-coalescing-and-occupancy", "roofline-model"]
system_prompt = """ system_prompt = """
You are the ARCHITECTURE ANALYST of a GPU team. You are the ARCHITECTURE ANALYST of a GPU team.
@@ -32,7 +32,7 @@ brain_seed = """
[[roles]] [[roles]]
slot = "kernel_author" slot = "kernel_author"
order_idx = 1 order_idx = 1
skills = ["write_cuda", "write_metal", "write_rocm", "write_rust_ffi", "workspace_repo_edit", "git_commit_protocol"] skills = ["write_cuda", "write_metal", "write_rocm", "write_rust_ffi", "workspace-repo-commit-protocol"]
system_prompt = """ system_prompt = """
You are the KERNEL AUTHOR of a GPU team. You are the KERNEL AUTHOR of a GPU team.
@@ -65,7 +65,7 @@ brain_seed = ""
[[roles]] [[roles]]
slot = "coder" slot = "coder"
order_idx = 3 order_idx = 3
skills = ["write_rust", "cargo_build", "cargo_test", "workspace_repo_edit"] skills = ["write-rust-current-edition", "cargo_build", "cargo-test-driven-development", "workspace-repo-commit-protocol", "int-xx-marker-protocol"]
system_prompt = """ system_prompt = """
You are the RUST-SIDE CODER. Integrate the kernel + FFI into the Rust You are the RUST-SIDE CODER. Integrate the kernel + FFI into the Rust
library, add safe wrappers, and expose ergonomic APIs. Own the library, add safe wrappers, and expose ergonomic APIs. Own the
@@ -76,7 +76,7 @@ brain_seed = ""
[[roles]] [[roles]]
slot = "committer" slot = "committer"
order_idx = 4 order_idx = 4
skills = ["git_commit_protocol", "small_focused_commits"] skills = ["workspace-repo-commit-protocol", "small-focused-commits"]
system_prompt = """ system_prompt = """
You are the COMMITTER. Only run when the kernel meets the roofline You are the COMMITTER. Only run when the kernel meets the roofline
target OR a specific reason to defer is documented. target OR a specific reason to defer is documented.
+4 -4
View File
@@ -10,7 +10,7 @@ version = 1
[[roles]] [[roles]]
slot = "designer" slot = "designer"
order_idx = 0 order_idx = 0
skills = ["decompose_int_items", "ios_hig_check", "material_you_check"] skills = ["decompose-int-items", "ios_hig_check", "material_you_check"]
system_prompt = """ system_prompt = """
You are the DESIGNER of a Mobile team. You are the DESIGNER of a Mobile team.
@@ -28,7 +28,7 @@ brain_seed = """
[[roles]] [[roles]]
slot = "coder" slot = "coder"
order_idx = 1 order_idx = 1
skills = ["write_typescript_react_native", "expo_managed_workflow", "workspace_repo_edit", "git_commit_protocol"] skills = ["write_typescript_react_native", "expo-managed-vs-bare", "workspace-repo-commit-protocol", "int-xx-marker-protocol", "component-4-state-model", "rn-flashlist-perf"]
system_prompt = """ system_prompt = """
You are the CODER of a Mobile team. You are the CODER of a Mobile team.
@@ -46,7 +46,7 @@ brain_seed = """
[[roles]] [[roles]]
slot = "tester" slot = "tester"
order_idx = 2 order_idx = 2
skills = ["detox_e2e", "jest_unit", "ios_simulator_check", "android_emulator_check"] skills = ["detox_e2e", "jest_unit", "ios_simulator_check", "android_emulator_check", "tdd-red-green-refactor"]
system_prompt = """ system_prompt = """
You are the TESTER of a Mobile team. You are the TESTER of a Mobile team.
@@ -59,7 +59,7 @@ brain_seed = ""
[[roles]] [[roles]]
slot = "committer" slot = "committer"
order_idx = 3 order_idx = 3
skills = ["git_commit_protocol", "small_focused_commits"] skills = ["workspace-repo-commit-protocol", "small-focused-commits"]
system_prompt = """ system_prompt = """
You are the COMMITTER. Only run on green tests both platforms. You are the COMMITTER. Only run on green tests both platforms.
Emit COMPLETED: INT-<NN>. Emit COMPLETED: INT-<NN>.
+5 -5
View File
@@ -10,7 +10,7 @@ version = 1
[[roles]] [[roles]]
slot = "planner" slot = "planner"
order_idx = 0 order_idx = 0
skills = ["read_roadmap", "decompose_int_items", "estimate_effort", "small_focused_commits"] skills = ["read_roadmap", "decompose-int-items", "estimate_effort", "small-focused-commits"]
system_prompt = """ system_prompt = """
You are the PLANNER of a Rust SDLC team. You are the PLANNER of a Rust SDLC team.
@@ -43,7 +43,7 @@ brain_seed = """
[[roles]] [[roles]]
slot = "coder" slot = "coder"
order_idx = 1 order_idx = 1
skills = ["write_rust", "cargo_build", "cargo_test", "workspace_repo_edit", "small_focused_commits", "git_commit_protocol"] skills = ["write-rust-current-edition", "cargo_build", "cargo-test-driven-development", "workspace-repo-commit-protocol", "small-focused-commits", "int-xx-marker-protocol", "rust-error-handling", "rust-async-tokio-idioms", "react-19-server-components"]
system_prompt = """ system_prompt = """
You are the CODER of a Rust SDLC team. You are the CODER of a Rust SDLC team.
@@ -78,7 +78,7 @@ brain_seed = """
[[roles]] [[roles]]
slot = "tester" slot = "tester"
order_idx = 2 order_idx = 2
skills = ["cargo_test", "cargo_nextest", "coverage_report", "criterion_bench"] skills = ["cargo-test-driven-development", "cargo_nextest", "coverage_report", "criterion_bench", "tdd-red-green-refactor"]
system_prompt = """ system_prompt = """
You are the TESTER of a Rust SDLC team. You are the TESTER of a Rust SDLC team.
@@ -96,7 +96,7 @@ brain_seed = ""
[[roles]] [[roles]]
slot = "reviewer" slot = "reviewer"
order_idx = 3 order_idx = 3
skills = ["code_review_checklist", "read_diff", "small_focused_commits"] skills = ["code-review-checklist", "read_diff", "small-focused-commits", "cargo-audit-workflow", "secret-scanning-gitleaks"]
system_prompt = """ system_prompt = """
You are the REVIEWER of a Rust SDLC team. You are the REVIEWER of a Rust SDLC team.
@@ -115,7 +115,7 @@ brain_seed = ""
[[roles]] [[roles]]
slot = "committer" slot = "committer"
order_idx = 4 order_idx = 4
skills = ["git_commit_protocol", "workspace_repo_edit", "small_focused_commits"] skills = ["workspace-repo-commit-protocol", "small-focused-commits"]
system_prompt = """ system_prompt = """
You are the COMMITTER of a Rust SDLC team. You are the COMMITTER of a Rust SDLC team.
+3 -3
View File
@@ -10,7 +10,7 @@ version = 1
[[roles]] [[roles]]
slot = "scene_designer" slot = "scene_designer"
order_idx = 0 order_idx = 0
skills = ["decompose_int_items", "scene_graph_planning"] skills = ["decompose-int-items", "scene_graph_planning"]
system_prompt = """ system_prompt = """
You are the SCENE DESIGNER of a three.js team. You are the SCENE DESIGNER of a three.js team.
@@ -28,7 +28,7 @@ brain_seed = """
[[roles]] [[roles]]
slot = "coder" slot = "coder"
order_idx = 1 order_idx = 1
skills = ["write_typescript", "threejs_idioms", "workspace_repo_edit", "git_commit_protocol"] skills = ["write_typescript", "threejs-perf-and-teardown", "workspace-repo-commit-protocol", "int-xx-marker-protocol"]
system_prompt = """ system_prompt = """
You are the CODER of a three.js team. You are the CODER of a three.js team.
@@ -69,7 +69,7 @@ brain_seed = ""
[[roles]] [[roles]]
slot = "committer" slot = "committer"
order_idx = 4 order_idx = 4
skills = ["git_commit_protocol", "small_focused_commits"] skills = ["workspace-repo-commit-protocol", "small-focused-commits"]
system_prompt = """ system_prompt = """
You are the COMMITTER. Only run when perf targets met. Emit You are the COMMITTER. Only run when perf targets met. Emit
COMPLETED: INT-<NN>. COMPLETED: INT-<NN>.