[object Object]

← 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

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 →