From 4b06ff1b394db6addd4c5bebf6b78ae4e58f9a29 Mon Sep 17 00:00:00 2001 From: Dylan Hurd Date: Sat, 17 Jan 2026 00:52:57 -0800 Subject: [PATCH] chore(skills) Update skills guidance --- codex-rs/core/src/project_doc.rs | 7 +++---- codex-rs/core/src/skills/render.rs | 25 ++++++++++++------------- codex-rs/core/tests/suite/client.rs | 2 +- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/codex-rs/core/src/project_doc.rs b/codex-rs/core/src/project_doc.rs index c763755af5..b7ab1217ef 100644 --- a/codex-rs/core/src/project_doc.rs +++ b/codex-rs/core/src/project_doc.rs @@ -237,6 +237,7 @@ mod tests { use super::*; use crate::config::ConfigBuilder; use crate::skills::load_skills; + use crate::skills::render::HOW_TO_USE_SKILLS; use std::fs; use std::path::PathBuf; use tempfile::TempDir; @@ -516,9 +517,8 @@ mod tests { ) .unwrap_or_else(|_| cfg.codex_home.join("skills/pdf-processing/SKILL.md")); let expected_path_str = expected_path.to_string_lossy().replace('\\', "/"); - let usage_rules = "- Discovery: The list above is the skills available in this session (name + description + file path). Skill bodies live on disk at the listed paths.\n- Trigger rules: If the user names a skill (with `$SkillName` or plain text) OR the task clearly matches a skill's description shown above, you must use that skill for that turn. Multiple mentions mean use them all. Do not carry skills across turns unless re-mentioned.\n- Missing/blocked: If a named skill isn't in the list or the path can't be read, say so briefly and continue with the best fallback.\n- How to use a skill (progressive disclosure):\n 1) After deciding to use a skill, open its `SKILL.md`. Read only enough to follow the workflow.\n 2) If `SKILL.md` points to extra folders such as `references/`, load only the specific files needed for the request; don't bulk-load everything.\n 3) If `scripts/` exist, prefer running or patching them instead of retyping large code blocks.\n 4) If `assets/` or templates exist, reuse them instead of recreating from scratch.\n- Coordination and sequencing:\n - If multiple skills apply, choose the minimal set that covers the request and state the order you'll use them.\n - Announce which skill(s) you're using and why (one short line). If you skip an obvious skill, say why.\n- Context hygiene:\n - Keep context small: summarize long sections instead of pasting them; only load extra files when needed.\n - Avoid deep reference-chasing: prefer opening only files directly linked from `SKILL.md` unless you're blocked.\n - When variants exist (frameworks, providers, domains), pick only the relevant reference file(s) and note that choice.\n- Safety and fallback: If a skill can't be applied cleanly (missing files, unclear instructions), state the issue, pick the next-best approach, and continue."; let expected = format!( - "base doc\n\n## Skills\nA skill is a set of local instructions to follow that is stored in a `SKILL.md` file. Below is the list of skills that can be used. Each entry includes a name, description, and file path so you can open the source for full instructions when using a specific skill.\n### Available skills\n- pdf-processing: extract from pdfs (file: {expected_path_str})\n### How to use skills\n{usage_rules}" + "base doc\n\n# Skills\nA skill is a set of local instructions to follow that is stored in a `SKILL.md` file. Below is the list of skills that can be used. Each entry includes a name, description, and file path so you can open the source for full instructions when using a specific skill.\n## Available skills\n- pdf-processing: extract from pdfs (file: {expected_path_str})\n{HOW_TO_USE_SKILLS}" ); assert_eq!(res, expected); } @@ -540,9 +540,8 @@ mod tests { dunce::canonicalize(cfg.codex_home.join("skills/linting/SKILL.md").as_path()) .unwrap_or_else(|_| cfg.codex_home.join("skills/linting/SKILL.md")); let expected_path_str = expected_path.to_string_lossy().replace('\\', "/"); - let usage_rules = "- Discovery: The list above is the skills available in this session (name + description + file path). Skill bodies live on disk at the listed paths.\n- Trigger rules: If the user names a skill (with `$SkillName` or plain text) OR the task clearly matches a skill's description shown above, you must use that skill for that turn. Multiple mentions mean use them all. Do not carry skills across turns unless re-mentioned.\n- Missing/blocked: If a named skill isn't in the list or the path can't be read, say so briefly and continue with the best fallback.\n- How to use a skill (progressive disclosure):\n 1) After deciding to use a skill, open its `SKILL.md`. Read only enough to follow the workflow.\n 2) If `SKILL.md` points to extra folders such as `references/`, load only the specific files needed for the request; don't bulk-load everything.\n 3) If `scripts/` exist, prefer running or patching them instead of retyping large code blocks.\n 4) If `assets/` or templates exist, reuse them instead of recreating from scratch.\n- Coordination and sequencing:\n - If multiple skills apply, choose the minimal set that covers the request and state the order you'll use them.\n - Announce which skill(s) you're using and why (one short line). If you skip an obvious skill, say why.\n- Context hygiene:\n - Keep context small: summarize long sections instead of pasting them; only load extra files when needed.\n - Avoid deep reference-chasing: prefer opening only files directly linked from `SKILL.md` unless you're blocked.\n - When variants exist (frameworks, providers, domains), pick only the relevant reference file(s) and note that choice.\n- Safety and fallback: If a skill can't be applied cleanly (missing files, unclear instructions), state the issue, pick the next-best approach, and continue."; let expected = format!( - "## Skills\nA skill is a set of local instructions to follow that is stored in a `SKILL.md` file. Below is the list of skills that can be used. Each entry includes a name, description, and file path so you can open the source for full instructions when using a specific skill.\n### Available skills\n- linting: run clippy (file: {expected_path_str})\n### How to use skills\n{usage_rules}" + "# Skills\nA skill is a set of local instructions to follow that is stored in a `SKILL.md` file. Below is the list of skills that can be used. Each entry includes a name, description, and file path so you can open the source for full instructions when using a specific skill.\n## Available skills\n- linting: run clippy (file: {expected_path_str})\n{HOW_TO_USE_SKILLS}" ); assert_eq!(res, expected); } diff --git a/codex-rs/core/src/skills/render.rs b/codex-rs/core/src/skills/render.rs index f998a51042..684cb98790 100644 --- a/codex-rs/core/src/skills/render.rs +++ b/codex-rs/core/src/skills/render.rs @@ -6,9 +6,9 @@ pub fn render_skills_section(skills: &[SkillMetadata]) -> Option { } let mut lines: Vec = Vec::new(); - lines.push("## Skills".to_string()); + lines.push("# Skills".to_string()); lines.push("A skill is a set of local instructions to follow that is stored in a `SKILL.md` file. Below is the list of skills that can be used. Each entry includes a name, description, and file path so you can open the source for full instructions when using a specific skill.".to_string()); - lines.push("### Available skills".to_string()); + lines.push("## Available skills".to_string()); for skill in skills { let path_str = skill.path.to_string_lossy().replace('\\', "/"); @@ -17,24 +17,23 @@ pub fn render_skills_section(skills: &[SkillMetadata]) -> Option { lines.push(format!("- {name}: {description} (file: {path_str})")); } - lines.push("### How to use skills".to_string()); + lines.push("".to_string()); lines.push( - r###"- Discovery: The list above is the skills available in this session (name + description + file path). Skill bodies live on disk at the listed paths. -- Trigger rules: If the user names a skill (with `$SkillName` or plain text) OR the task clearly matches a skill's description shown above, you must use that skill for that turn. Multiple mentions mean use them all. Do not carry skills across turns unless re-mentioned. -- Missing/blocked: If a named skill isn't in the list or the path can't be read, say so briefly and continue with the best fallback. + r###"## How to use skills +- Discovery: The list above is the skills available in this session (name + description + file path). Skill bodies live on disk at the listed paths. +- Trigger rules: + - If the user names a skill (with `$SkillName` or plain text) OR the task clearly matches a skill's description shown above, you should do your best to use that skill for that turn. + - If the user references multiple skills, you should use them all. + - Do not carry skills across turns unless re-mentioned. +- Missing/blocked on skill discovery: If a named skill isn't in the list or the path can't be read, pick a reasonable fallback and continue. - How to use a skill (progressive disclosure): 1) After deciding to use a skill, open its `SKILL.md`. Read only enough to follow the workflow. 2) If `SKILL.md` points to extra folders such as `references/`, load only the specific files needed for the request; don't bulk-load everything. 3) If `scripts/` exist, prefer running or patching them instead of retyping large code blocks. 4) If `assets/` or templates exist, reuse them instead of recreating from scratch. - Coordination and sequencing: - - If multiple skills apply, choose the minimal set that covers the request and state the order you'll use them. - - Announce which skill(s) you're using and why (one short line). If you skip an obvious skill, say why. -- Context hygiene: - - Keep context small: summarize long sections instead of pasting them; only load extra files when needed. - - Avoid deep reference-chasing: prefer opening only files directly linked from `SKILL.md` unless you're blocked. - - When variants exist (frameworks, providers, domains), pick only the relevant reference file(s) and note that choice. -- Safety and fallback: If a skill can't be applied cleanly (missing files, unclear instructions), state the issue, pick the next-best approach, and continue."### + - If multiple skills apply to the current task, choose the minimal set that can complete the request. +- Safety and fallback: If a skill can't be applied cleanly (missing files, unclear instructions), pick the next-best approach, and continue."### .to_string(), ); diff --git a/codex-rs/core/tests/suite/client.rs b/codex-rs/core/tests/suite/client.rs index 6f659e1b64..bb01d5542e 100644 --- a/codex-rs/core/tests/suite/client.rs +++ b/codex-rs/core/tests/suite/client.rs @@ -734,7 +734,7 @@ async fn skills_append_to_instructions() { .as_str() .expect("instructions text"); assert!( - instructions_text.contains("## Skills"), + instructions_text.contains("# Skills"), "expected skills section present" ); assert!(