From 64221f9c87fc8d7a84b26bfe63d728f971a431e0 Mon Sep 17 00:00:00 2001 From: Austin Horstman Date: Sun, 21 Jun 2026 16:05:42 -0500 Subject: [PATCH] codex: add lifecycle hooks option Manage CODEX_HOME/hooks.json directly while covering the generated file in the existing TOML test. --- modules/programs/codex.nix | 36 +++++++++++++++++++ tests/modules/programs/codex/hooks.json | 27 ++++++++++++++ .../modules/programs/codex/settings-toml.nix | 28 +++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 tests/modules/programs/codex/hooks.json diff --git a/modules/programs/codex.nix b/modules/programs/codex.nix index dd46a6ecb..872ce9507 100644 --- a/modules/programs/codex.nix +++ b/modules/programs/codex.nix @@ -153,6 +153,39 @@ in ''; }; + hooks = lib.mkOption { + inherit (jsonFormat) type; + default = { }; + description = '' + Lifecycle hook events written to {file}`CODEX_HOME/hooks.json`. + + This option uses the same event structure as + {option}`programs.codex.settings.hooks` and writes it under the + top-level `hooks` key expected by Codex's JSON hooks file. + + Hooks can also be configured inline through + {option}`programs.codex.settings.hooks`; prefer using only one hook + representation per layer. + ''; + example = lib.literalExpression '' + { + PreToolUse = [ + { + matcher = "^Bash$"; + hooks = [ + { + type = "command"; + command = "/usr/local/bin/codex-pre-tool-use"; + timeout = 30; + statusMessage = "Checking Bash command"; + } + ]; + } + ]; + } + ''; + }; + plugins = lib.mkOption { type = with lib.types; listOf (either package path); default = [ ]; @@ -535,6 +568,9 @@ in lib.mkIf (cfg.context != "") { text = cfg.context; }; + "${configDir}/hooks.json" = lib.mkIf (cfg.hooks != { }) { + source = jsonFormat.generate "codex-hooks" { inherit (cfg) hooks; }; + }; } // lib.optionalAttrs (cfg.contextOverride != null) ( lib.listToAttrs [ (mkTextOrPathEntry "${configDir}/AGENTS.override.md" cfg.contextOverride) ] diff --git a/tests/modules/programs/codex/hooks.json b/tests/modules/programs/codex/hooks.json new file mode 100644 index 000000000..827f9334e --- /dev/null +++ b/tests/modules/programs/codex/hooks.json @@ -0,0 +1,27 @@ +{ + "hooks": { + "PreToolUse": [ + { + "hooks": [ + { + "command": "/usr/local/bin/codex-pre-tool-use", + "statusMessage": "Checking Bash command", + "timeout": 30, + "type": "command" + } + ], + "matcher": "^Bash$" + } + ], + "Stop": [ + { + "hooks": [ + { + "command": "/usr/local/bin/codex-stop", + "type": "command" + } + ] + } + ] + } +} diff --git a/tests/modules/programs/codex/settings-toml.nix b/tests/modules/programs/codex/settings-toml.nix index 4183770f6..fcea8c3a2 100644 --- a/tests/modules/programs/codex/settings-toml.nix +++ b/tests/modules/programs/codex/settings-toml.nix @@ -29,6 +29,31 @@ in - Temporarily prefer terse answers - Use exact dates in status notes ''; + hooks = { + PreToolUse = [ + { + matcher = "^Bash$"; + hooks = [ + { + type = "command"; + command = "/usr/local/bin/codex-pre-tool-use"; + timeout = 30; + statusMessage = "Checking Bash command"; + } + ]; + } + ]; + Stop = [ + { + hooks = [ + { + type = "command"; + command = "/usr/local/bin/codex-stop"; + } + ]; + } + ]; + }; }; nmt.script = '' assertFileExists home-files/.codex/config.toml @@ -43,6 +68,9 @@ in - Temporarily prefer terse answers - Use exact dates in status notes ''} + assertFileExists home-files/.codex/hooks.json + assertFileContent home-files/.codex/hooks.json \ + ${./hooks.json} assertFileNotRegex home-path/etc/profile.d/hm-session-vars.sh 'CODEX_HOME' ''; }