From f1b5f2021098dc712899b3ff862bcd8756f92330 Mon Sep 17 00:00:00 2001 From: Hauke Schnau Date: Tue, 13 Jan 2026 10:18:07 +0100 Subject: [PATCH] codex: unify skills option and tests --- modules/programs/codex.nix | 33 +++++++++---------- tests/modules/programs/codex/default.nix | 2 +- tests/modules/programs/codex/skill-file.md | 8 +++++ .../programs/codex/skills-conflict.nix | 13 -------- tests/modules/programs/codex/skills-dir.nix | 5 +-- .../modules/programs/codex/skills-inline.nix | 30 ++++++++++------- .../codex/skills-path-not-directory.nix | 10 ++++++ 7 files changed, 57 insertions(+), 44 deletions(-) create mode 100644 tests/modules/programs/codex/skill-file.md delete mode 100644 tests/modules/programs/codex/skills-conflict.nix create mode 100644 tests/modules/programs/codex/skills-path-not-directory.nix diff --git a/modules/programs/codex.nix b/modules/programs/codex.nix index dfb26abb..d931dcc5 100644 --- a/modules/programs/codex.nix +++ b/modules/programs/codex.nix @@ -64,14 +64,23 @@ in }; skills = lib.mkOption { - type = lib.types.attrsOf (lib.types.either lib.types.lines lib.types.path); + type = lib.types.either (lib.types.attrsOf (lib.types.either lib.types.lines lib.types.path)) lib.types.path; default = { }; description = '' Custom skills for Codex. - The attribute name becomes the skill directory name, and the value is either: + + This option can either be: + - An attribute set defining skills + - A path to a directory containing multiple skill folders + + If an attribute set is used, the attribute name becomes the skill directory name, + and the value is either: - Inline content as a string (creates {file}`skills//SKILL.md`) - A path to a file (creates {file}`skills//SKILL.md`) - A path to a directory (creates {file}`skills//` with all files) + + If a path is used, it is expected to contain one folder per skill name, each + containing a {file}`SKILL.md`. The directory is symlinked to {file}`skills/`. ''; example = lib.literalExpression '' { @@ -98,16 +107,6 @@ in } ''; }; - - skillsDir = lib.mkOption { - type = lib.types.nullOr lib.types.path; - default = null; - description = '' - Path to a directory containing skill folders for Codex. - Skill folders from this directory will be symlinked to {file}`skills/`. - ''; - example = lib.literalExpression "./skills"; - }; }; config = @@ -120,8 +119,8 @@ in mkIf cfg.enable { assertions = [ { - assertion = !(cfg.skills != { } && cfg.skillsDir != null); - message = "Cannot specify both `programs.codex.skills` and `programs.codex.skillsDir`"; + assertion = !lib.isPath cfg.skills || lib.pathIsDirectory cfg.skills; + message = "`programs.codex.skills` must be a directory when set to a path"; } ]; @@ -134,8 +133,8 @@ in "${configDir}/AGENTS.md" = lib.mkIf (cfg.custom-instructions != "") { text = cfg.custom-instructions; }; - "${configDir}/skills" = lib.mkIf (cfg.skillsDir != null) { - source = cfg.skillsDir; + "${configDir}/skills" = lib.mkIf (lib.isPath cfg.skills) { + source = cfg.skills; recursive = true; }; } @@ -150,7 +149,7 @@ in lib.nameValuePair "${configDir}/skills/${name}/SKILL.md" ( if lib.isPath content then { source = content; } else { text = content; } ) - ) cfg.skills); + ) (if builtins.isAttrs cfg.skills then cfg.skills else { })); sessionVariables = mkIf useXdgDirectories { CODEX_HOME = "${config.xdg.configHome}/codex"; }; diff --git a/tests/modules/programs/codex/default.nix b/tests/modules/programs/codex/default.nix index 46529834..23eb27b1 100644 --- a/tests/modules/programs/codex/default.nix +++ b/tests/modules/programs/codex/default.nix @@ -8,5 +8,5 @@ codex-empty-custom-instructions = ./empty-custom-instructions.nix; codex-skills-inline = ./skills-inline.nix; codex-skills-dir = ./skills-dir.nix; - codex-skills-conflict = ./skills-conflict.nix; + codex-skills-path-not-directory = ./skills-path-not-directory.nix; } diff --git a/tests/modules/programs/codex/skill-file.md b/tests/modules/programs/codex/skill-file.md new file mode 100644 index 00000000..ffb1c7ca --- /dev/null +++ b/tests/modules/programs/codex/skill-file.md @@ -0,0 +1,8 @@ +--- +name: file-skill +description: File skill for tests. +--- + +# File Skill + +Test fixture content. diff --git a/tests/modules/programs/codex/skills-conflict.nix b/tests/modules/programs/codex/skills-conflict.nix deleted file mode 100644 index 608e096c..00000000 --- a/tests/modules/programs/codex/skills-conflict.nix +++ /dev/null @@ -1,13 +0,0 @@ -{ - programs.codex = { - enable = true; - skills = { - inline-skill = "Test"; - }; - skillsDir = ./skills-dir; - }; - - test.asserts.assertions.expected = [ - "Cannot specify both `programs.codex.skills` and `programs.codex.skillsDir`" - ]; -} diff --git a/tests/modules/programs/codex/skills-dir.nix b/tests/modules/programs/codex/skills-dir.nix index b348f0fe..f3fbd20b 100644 --- a/tests/modules/programs/codex/skills-dir.nix +++ b/tests/modules/programs/codex/skills-dir.nix @@ -1,11 +1,12 @@ { programs.codex = { enable = true; - skillsDir = ./skills-dir; + skills = ./skills-dir; }; nmt.script = '' assertFileExists home-files/.codex/skills/skill-one/SKILL.md - assertFileRegex home-files/.codex/skills/skill-one/SKILL.md "Skill One" + assertFileContent home-files/.codex/skills/skill-one/SKILL.md \ + ${./skills-dir/skill-one/SKILL.md} ''; } diff --git a/tests/modules/programs/codex/skills-inline.nix b/tests/modules/programs/codex/skills-inline.nix index 340cecad..e10c4b60 100644 --- a/tests/modules/programs/codex/skills-inline.nix +++ b/tests/modules/programs/codex/skills-inline.nix @@ -1,22 +1,30 @@ +let + inlineSkill = '' + --- + name: inline-skill + description: Inline skill for tests. + --- + + # Inline Skill + + Test fixture content. + ''; +in { programs.codex = { enable = true; skills = { - inline-skill = '' - --- - name: inline-skill - description: Inline skill for tests. - --- - - # Inline Skill - - Test fixture content. - ''; + inline-skill = inlineSkill; + file-skill = ./skill-file.md; }; }; nmt.script = '' assertFileExists home-files/.codex/skills/inline-skill/SKILL.md - assertFileRegex home-files/.codex/skills/inline-skill/SKILL.md "Inline Skill" + assertFileContent home-files/.codex/skills/inline-skill/SKILL.md \ + ${builtins.toFile "expected-inline-skill.md" inlineSkill} + assertFileExists home-files/.codex/skills/file-skill/SKILL.md + assertFileContent home-files/.codex/skills/file-skill/SKILL.md \ + ${./skill-file.md} ''; } diff --git a/tests/modules/programs/codex/skills-path-not-directory.nix b/tests/modules/programs/codex/skills-path-not-directory.nix new file mode 100644 index 00000000..92a086f4 --- /dev/null +++ b/tests/modules/programs/codex/skills-path-not-directory.nix @@ -0,0 +1,10 @@ +{ + programs.codex = { + enable = true; + skills = ./skill-file.md; + }; + + test.asserts.assertions.expected = [ + "`programs.codex.skills` must be a directory when set to a path" + ]; +}