← back to Cli Printing Press
fix(skills): inherit Codex model from ~/.codex/config.toml instead of hardcoding (#317)
b54882aa7e3b45b529289def54981dd36c91cc7d · 2026-04-26 15:49:55 -0700 · Matt Van Horn
The printing-press skill delegated to Codex with `-m "gpt-5.4"
-c 'model_reasoning_effort="medium"'` flags in two places, and
displayed the model with `codex config get model` — which is not a
real Codex 0.124.0 subcommand. The fallback `|| echo "gpt-5.4"`
fired every time, so the announced model never matched the model
that was actually invoked, and the user's `~/.codex/config.toml`
default was always overridden.
Fix: omit `-m` and `-c` from every `codex exec` call so Codex
inherits its config.toml default. For the display banner, replace
the broken subcommand with a `grep ^model ~/.codex/config.toml`
pipeline.
Adds `internal/cli/codex_model_invariant_test.go` as a regression
guard. Walks every `skills/**/*.md` file and fails on hardcoded
`-m "gpt-..."`, `--model "gpt-..."`, `model_reasoning_effort=`, or
`codex config get model`. Self-tested by simulating a regression
and confirming the test catches it.
When OpenAI ships gpt-5.6, no skill PR is required — every codex
delegation picks up the new model on the next invocation.
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Files touched
A internal/cli/codex_model_invariant_test.goM skills/printing-press/SKILL.mdM skills/printing-press/references/codex-delegation.md
Diff
commit b54882aa7e3b45b529289def54981dd36c91cc7d
Author: Matt Van Horn <mvanhorn@users.noreply.github.com>
Date: Sun Apr 26 15:49:55 2026 -0700
fix(skills): inherit Codex model from ~/.codex/config.toml instead of hardcoding (#317)
The printing-press skill delegated to Codex with `-m "gpt-5.4"
-c 'model_reasoning_effort="medium"'` flags in two places, and
displayed the model with `codex config get model` — which is not a
real Codex 0.124.0 subcommand. The fallback `|| echo "gpt-5.4"`
fired every time, so the announced model never matched the model
that was actually invoked, and the user's `~/.codex/config.toml`
default was always overridden.
Fix: omit `-m` and `-c` from every `codex exec` call so Codex
inherits its config.toml default. For the display banner, replace
the broken subcommand with a `grep ^model ~/.codex/config.toml`
pipeline.
Adds `internal/cli/codex_model_invariant_test.go` as a regression
guard. Walks every `skills/**/*.md` file and fails on hardcoded
`-m "gpt-..."`, `--model "gpt-..."`, `model_reasoning_effort=`, or
`codex config get model`. Self-tested by simulating a regression
and confirming the test catches it.
When OpenAI ships gpt-5.6, no skill PR is required — every codex
delegation picks up the new model on the next invocation.
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
---
internal/cli/codex_model_invariant_test.go | 137 +++++++++++++++++++++
skills/printing-press/SKILL.md | 4 +-
.../printing-press/references/codex-delegation.md | 6 +-
3 files changed, 142 insertions(+), 5 deletions(-)
diff --git a/internal/cli/codex_model_invariant_test.go b/internal/cli/codex_model_invariant_test.go
new file mode 100644
index 00000000..c734e6cc
--- /dev/null
+++ b/internal/cli/codex_model_invariant_test.go
@@ -0,0 +1,137 @@
+package cli_test
+
+import (
+ "io/fs"
+ "os"
+ "path/filepath"
+ "regexp"
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+// TestSkillsInheritCodexModelFromConfig is the regression guard for the
+// 2026-04-26 codex-model auto-default fix.
+//
+// Codex CLI delegations in printing-press skill files must inherit the
+// user's ~/.codex/config.toml default model and reasoning effort.
+// Pinning -m "gpt-...", --model "gpt-...", model_reasoning_effort=...,
+// or invoking the non-existent `codex config get model` subcommand
+// causes every codex run to drift from the user's actual configured
+// model and freezes the skill at whatever literal string is hardcoded.
+//
+// The test walks every markdown file under skills/ and fails on any of
+// those patterns. Vendored content under */vendor/* is excluded.
+func TestSkillsInheritCodexModelFromConfig(t *testing.T) {
+ skillsRoot := "../../skills"
+ info, err := os.Stat(skillsRoot)
+ require.NoError(t, err, "skills/ directory must exist")
+ require.True(t, info.IsDir(), "skills/ must be a directory")
+
+ // Forbidden patterns. Any match in a skill markdown file is a
+ // violation.
+ forbidden := []struct {
+ pattern *regexp.Regexp
+ reason string
+ }{
+ {
+ regexp.MustCompile(`-m\s+"gpt-`),
+ `hardcoded -m "gpt-..." (use codex's config.toml default instead)`,
+ },
+ {
+ regexp.MustCompile(`--model\s+"gpt-`),
+ `hardcoded --model "gpt-..." (use codex's config.toml default instead)`,
+ },
+ {
+ regexp.MustCompile(`model_reasoning_effort\s*=\s*`),
+ `hardcoded model_reasoning_effort= (inherits from config.toml)`,
+ },
+ {
+ regexp.MustCompile(`codex\s+config\s+get\s+model`),
+ "calls non-existent `codex config get model` subcommand " +
+ "(grep ~/.codex/config.toml directly instead)",
+ },
+ }
+
+ // Files allowed to mention forbidden patterns. The test file itself
+ // quotes the patterns; release notes and changelogs may reference
+ // the historical hardcoded values.
+ allowlist := map[string]bool{
+ filepath.Clean("../../internal/cli/codex_model_invariant_test.go"): true,
+ }
+
+ var violations []string
+
+ walkErr := filepath.WalkDir(skillsRoot, func(path string, d fs.DirEntry, err error) error {
+ if err != nil {
+ return err
+ }
+ if d.IsDir() {
+ // Skip vendored content.
+ if strings.Contains(path, "/vendor/") || strings.HasSuffix(path, "/vendor") {
+ return filepath.SkipDir
+ }
+ return nil
+ }
+ if !strings.HasSuffix(path, ".md") {
+ return nil
+ }
+ if allowlist[filepath.Clean(path)] {
+ return nil
+ }
+
+ data, readErr := os.ReadFile(path)
+ if readErr != nil {
+ return readErr
+ }
+
+ for lineNum, line := range strings.Split(string(data), "\n") {
+ for _, f := range forbidden {
+ if f.pattern.MatchString(line) {
+ rel := strings.TrimPrefix(path, "../../")
+ violations = append(violations,
+ " "+rel+":"+itoa(lineNum+1)+": "+f.reason+
+ "\n > "+strings.TrimSpace(line))
+ }
+ }
+ }
+ return nil
+ })
+ require.NoError(t, walkErr)
+
+ if len(violations) > 0 {
+ t.Fatalf("Skill files must inherit Codex model from "+
+ "~/.codex/config.toml. Found pinned models or invalid "+
+ "config calls:\n%s\n\n"+
+ "Fix: remove `-m \"gpt-...\"` and "+
+ "`-c 'model_reasoning_effort=...'` from `codex exec` calls. "+
+ "For display, replace `codex config get model` with a "+
+ "`grep ^model ~/.codex/config.toml` pattern.",
+ strings.Join(violations, "\n"))
+ }
+}
+
+// itoa is a small wrapper to avoid pulling strconv into this file's
+// import list when the tests already use require/strings/regexp.
+func itoa(n int) string {
+ if n == 0 {
+ return "0"
+ }
+ neg := n < 0
+ if neg {
+ n = -n
+ }
+ var buf [20]byte
+ i := len(buf)
+ for n > 0 {
+ i--
+ buf[i] = byte('0' + n%10)
+ n /= 10
+ }
+ if neg {
+ i--
+ buf[i] = '-'
+ }
+ return string(buf[i:])
+}
diff --git a/skills/printing-press/SKILL.md b/skills/printing-press/SKILL.md
index eceedc32..df5ce270 100644
--- a/skills/printing-press/SKILL.md
+++ b/skills/printing-press/SKILL.md
@@ -294,7 +294,9 @@ fi
# Health check: verify codex binary exists
if [ "$CODEX_MODE" = "true" ]; then
if command -v codex >/dev/null 2>&1; then
- CODEX_MODEL=$(codex config get model 2>/dev/null || echo "gpt-5.4")
+ # Model and reasoning effort inherit from ~/.codex/config.toml. Do not pin -m / -c here.
+ CODEX_MODEL=$(grep -E '^model[[:space:]]*=' ~/.codex/config.toml 2>/dev/null | head -1 | sed -E 's/^model[[:space:]]*=[[:space:]]*"?([^"]+)"?.*$/\1/')
+ [ -z "$CODEX_MODEL" ] && CODEX_MODEL="codex default"
echo "Codex mode enabled (model: $CODEX_MODEL). Code-writing tasks will be delegated to Codex."
else
echo "Codex CLI not found - running in standard mode."
diff --git a/skills/printing-press/references/codex-delegation.md b/skills/printing-press/references/codex-delegation.md
index 72ed3bd4..764e761b 100644
--- a/skills/printing-press/references/codex-delegation.md
+++ b/skills/printing-press/references/codex-delegation.md
@@ -26,10 +26,9 @@ When `CODEX_MODE` is true, delegate code-writing tasks to Codex CLI. Claude stil
d. **Delegate** — Pipe to Codex:
```bash
+ # Model and reasoning effort inherit from ~/.codex/config.toml. Do not pin -m / -c here.
cd "$PRESS_LIBRARY/<api>-pp-cli" && echo "$CODEX_PROMPT" | codex exec \
--yolo \
- -c 'model_reasoning_effort="medium"' \
- -m "gpt-5.4" \
-
```
@@ -212,10 +211,9 @@ When `CODEX_MODE` is true, delegate each bug fix to Codex. The shipcheck tools t
```
```bash
+ # Model and reasoning effort inherit from ~/.codex/config.toml. Do not pin -m / -c here.
cd "$PRESS_LIBRARY/<api>-pp-cli" && echo "$CODEX_PROMPT" | codex exec \
--yolo \
- -c 'model_reasoning_effort="medium"' \
- -m "gpt-5.4" \
-
```
← a5c59b33 refactor(cli): table-drive fullrun comparison metrics (#316)
·
back to Cli Printing Press
·
refactor(cli): table-drive dogfood verdict rules (#318) faac0d39 →