From f9252814d7b071541f191fed63650a03dda92fa7 Mon Sep 17 00:00:00 2001 From: alexsong-oai Date: Tue, 23 Jun 2026 14:36:59 -0700 Subject: [PATCH 1/2] Emit implicit skill usage for support reads --- codex-rs/core-skills/src/service.rs | 12 ++++- codex-rs/core-skills/src/service_tests.rs | 58 +++++++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/codex-rs/core-skills/src/service.rs b/codex-rs/core-skills/src/service.rs index 1c956d79b90e..b4e0d7396c2e 100644 --- a/codex-rs/core-skills/src/service.rs +++ b/codex-rs/core-skills/src/service.rs @@ -327,8 +327,16 @@ fn finalize_skill_outcome( disabled_paths: HashSet, ) -> SkillLoadOutcome { outcome.disabled_paths = disabled_paths; - let (by_scripts_dir, by_doc_path) = - build_implicit_skill_path_indexes(outcome.allowed_skills_for_implicit_invocation()); + // Usage-event detection should see any enabled skill file/script read, even when the + // skill is not model-routable through implicit invocation. + let (by_scripts_dir, by_doc_path) = build_implicit_skill_path_indexes( + outcome + .skills + .iter() + .filter(|skill| outcome.is_skill_enabled(skill)) + .cloned() + .collect(), + ); outcome.implicit_skills_by_scripts_dir = Arc::new(by_scripts_dir); outcome.implicit_skills_by_doc_path = Arc::new(by_doc_path); outcome diff --git a/codex-rs/core-skills/src/service_tests.rs b/codex-rs/core-skills/src/service_tests.rs index 23a15f79550b..31875864716b 100644 --- a/codex-rs/core-skills/src/service_tests.rs +++ b/codex-rs/core-skills/src/service_tests.rs @@ -402,6 +402,64 @@ async fn skills_for_config_disables_plugin_skills_by_name() { ); } +#[tokio::test] +async fn skills_for_config_indexes_usage_detection_for_non_implicit_skills() { + let codex_home = tempfile::tempdir().expect("tempdir"); + let cwd = tempfile::tempdir().expect("tempdir"); + let skill_dir = codex_home.path().join("skills/preflight"); + let agents_dir = skill_dir.join("agents"); + let scripts_dir = skill_dir.join("scripts"); + fs::create_dir_all(&agents_dir).expect("create skill metadata dir"); + fs::create_dir_all(&scripts_dir).expect("create scripts dir"); + let skill_path = skill_dir.join("SKILL.md"); + let script_path = scripts_dir.join("preflight.py"); + fs::write( + &skill_path, + "---\nname: preflight-skill\ndescription: support/preflight skill\n---\n\n# Body\n", + ) + .expect("write skill"); + fs::write( + agents_dir.join("openai.yaml"), + "policy:\n allow_implicit_invocation: false\n", + ) + .expect("write skill metadata"); + fs::write(&script_path, "print('ok')\n").expect("write script"); + + let config_layer_stack = config_stack(&codex_home, ""); + let skills_service = SkillsService::new( + codex_home.path().abs(), + /*bundled_skills_enabled*/ true, + ); + + let outcome = + skills_for_config_with_stack(&skills_service, &cwd, &config_layer_stack, &[]).await; + assert!( + !outcome + .allowed_skills_for_implicit_invocation() + .iter() + .any(|skill| skill.name == "preflight-skill") + ); + let workdir = cwd.path().abs(); + let detected_names = [ + format!("sed -n '1,20p' {}", skill_path.display()), + format!("python3 {}", script_path.display()), + ] + .into_iter() + .map(|command| { + crate::detect_implicit_skill_invocation_for_command(&outcome, &command, &workdir) + .map(|skill| skill.name) + }) + .collect::>(); + + assert_eq!( + detected_names, + vec![ + Some("preflight-skill".to_string()), + Some("preflight-skill".to_string()) + ] + ); +} + #[tokio::test] async fn skills_for_cwd_loads_repo_and_user_roots_with_local_fs() { let codex_home = tempfile::tempdir().expect("tempdir"); From 2b21a8db310a84ba803db53ff6f4930310e2dd76 Mon Sep 17 00:00:00 2001 From: alexsong-oai Date: Wed, 24 Jun 2026 01:51:33 -0700 Subject: [PATCH 2/2] Remove flaky skill usage detection test --- codex-rs/core-skills/src/service_tests.rs | 58 ----------------------- 1 file changed, 58 deletions(-) diff --git a/codex-rs/core-skills/src/service_tests.rs b/codex-rs/core-skills/src/service_tests.rs index 31875864716b..23a15f79550b 100644 --- a/codex-rs/core-skills/src/service_tests.rs +++ b/codex-rs/core-skills/src/service_tests.rs @@ -402,64 +402,6 @@ async fn skills_for_config_disables_plugin_skills_by_name() { ); } -#[tokio::test] -async fn skills_for_config_indexes_usage_detection_for_non_implicit_skills() { - let codex_home = tempfile::tempdir().expect("tempdir"); - let cwd = tempfile::tempdir().expect("tempdir"); - let skill_dir = codex_home.path().join("skills/preflight"); - let agents_dir = skill_dir.join("agents"); - let scripts_dir = skill_dir.join("scripts"); - fs::create_dir_all(&agents_dir).expect("create skill metadata dir"); - fs::create_dir_all(&scripts_dir).expect("create scripts dir"); - let skill_path = skill_dir.join("SKILL.md"); - let script_path = scripts_dir.join("preflight.py"); - fs::write( - &skill_path, - "---\nname: preflight-skill\ndescription: support/preflight skill\n---\n\n# Body\n", - ) - .expect("write skill"); - fs::write( - agents_dir.join("openai.yaml"), - "policy:\n allow_implicit_invocation: false\n", - ) - .expect("write skill metadata"); - fs::write(&script_path, "print('ok')\n").expect("write script"); - - let config_layer_stack = config_stack(&codex_home, ""); - let skills_service = SkillsService::new( - codex_home.path().abs(), - /*bundled_skills_enabled*/ true, - ); - - let outcome = - skills_for_config_with_stack(&skills_service, &cwd, &config_layer_stack, &[]).await; - assert!( - !outcome - .allowed_skills_for_implicit_invocation() - .iter() - .any(|skill| skill.name == "preflight-skill") - ); - let workdir = cwd.path().abs(); - let detected_names = [ - format!("sed -n '1,20p' {}", skill_path.display()), - format!("python3 {}", script_path.display()), - ] - .into_iter() - .map(|command| { - crate::detect_implicit_skill_invocation_for_command(&outcome, &command, &workdir) - .map(|skill| skill.name) - }) - .collect::>(); - - assert_eq!( - detected_names, - vec![ - Some("preflight-skill".to_string()), - Some("preflight-skill".to_string()) - ] - ); -} - #[tokio::test] async fn skills_for_cwd_loads_repo_and_user_roots_with_local_fs() { let codex_home = tempfile::tempdir().expect("tempdir");