feat(config): models.yaml lane map + per-project native roles — 0.6.0 #2

Merged
ksamaschke merged 2 commits from feat/models-yaml-lane-map into main 2026-07-31 09:44:14 +00:00
Owner

Two commits, each standing on its own:

  1. feat(configure-codex-roles): per-project native role layer via --project — pre-existing local work: status/apply/remove --project <repo> manage the project .codex role layer, project leaves overriding only the roles they name. Verified by its own 19 tests.
  2. feat(config): models.yaml lane map, shared schema, + bin/isc — 0.6.0 — model selection moves from dotted model.<lane>.<tier> keys to models.yaml, the schema shared verbatim with the Claude Code and Cursor variants.

Reviewer defaults are inverted relative to the Claude Code variant on purpose: this harness implements on GPT, so an independent review belongs on a Claude lane. A native role profile is static config Codex itself runs, so it must stay Codex-runnable — adversarial_reviewer inherits implementer_high, and both isc doctor and the installer refuse to write an Anthropic id into one; cross-family review reaches Claude through engine.claude.review.

Legacy - model.role.<name> lines still resolve, one step weaker than the yaml in the same scope. The other legacy families are documented in a migration table and named by isc doctor rather than silently ignored.

isc sync records a digest of the resolved role map, so doctor detects profiles rendered from a different lane map instead of merely checking that files exist. One effective Codex home (CODEX_HOME) is used by resolution, init and the installer alike, and the installer's parser matches bin/isc byte for byte.

51 checks in tests/isc-smoke.sh plus 23 Python tests (needs python3 ≥ 3.11 for tomllib, or the codex CLI).

Two commits, each standing on its own: 1. `feat(configure-codex-roles): per-project native role layer via --project` — pre-existing local work: `status`/`apply`/`remove --project <repo>` manage the project `.codex` role layer, project leaves overriding only the roles they name. Verified by its own 19 tests. 2. `feat(config): models.yaml lane map, shared schema, + bin/isc — 0.6.0` — model selection moves from dotted `model.<lane>.<tier>` keys to `models.yaml`, the schema shared verbatim with the Claude Code and Cursor variants. Reviewer defaults are inverted relative to the Claude Code variant on purpose: this harness implements on GPT, so an independent review belongs on a Claude lane. A native role profile is static config Codex itself runs, so it must stay Codex-runnable — `adversarial_reviewer` inherits `implementer_high`, and both `isc doctor` and the installer refuse to write an Anthropic id into one; cross-family review reaches Claude through `engine.claude.review`. Legacy `- model.role.<name>` lines still resolve, one step weaker than the yaml in the same scope. The other legacy families are documented in a migration table and named by `isc doctor` rather than silently ignored. `isc sync` records a digest of the resolved role map, so `doctor` detects profiles rendered from a different lane map instead of merely checking that files exist. One effective Codex home (`CODEX_HOME`) is used by resolution, init and the installer alike, and the installer's parser matches `bin/isc` byte for byte. 51 checks in `tests/isc-smoke.sh` plus 23 Python tests (needs python3 ≥ 3.11 for `tomllib`, or the codex CLI).
configure_roles.py gains project scope: `status`/`apply`/`remove --project
<repo>` manage `<repo>/.codex/config.toml` and `<repo>/.codex/agents/*.toml`,
the layer Codex loads for a trusted project, instead of the user-level roles in
$CODEX_HOME.

Project leaves override only the roles they name; every unspecified role
inherits its global or bundled model. Unknown roles, duplicate leaves and
invalid model identifiers abort before any config or profile write, and the
existing safety properties are unchanged: unrelated configuration preserved,
config.toml.bak beside any existing config, exact legacy profiles adopted,
colliding unowned profiles refused, repeated application a no-op.

Skill and README document project mode and its reporting rule: report the
project .codex path rather than implying the global Codex home changed.

tests/test_configure_codex_roles.py: 19 tests (5 new for project scope).
Model selection moves from dotted `model.<lane>.<tier>` keys in
implementation-skills.md to models.yaml — the schema shared verbatim with the
Claude Code and Cursor variants, so a lane means the same thing wherever the
toolchain runs.

Nine portable lanes, engine.<pi|claude>.<fast|ordinary|strong|review|fallback>,
role.<name> for native Codex profiles, and harness.codex.<key> overrides.
Resolution per key, first hit wins: <repo>/.codex/models.yaml >
<repo>/models.yaml > $CODEX_HOME/models.yaml > built-in default, with an
explicit prompt model still winning over all of them.

Reviewer defaults are inverted relative to the Claude Code variant on purpose:
this harness implements on GPT, so an independent review belongs on a Claude
lane (reviewer_default: opus, reviewer_security: claude-fable-5). A native role
profile is static config Codex itself runs, so it must stay Codex-runnable:
adversarial_reviewer inherits implementer_high, and both `isc doctor` and the
installer refuse to write an Anthropic id into one. Cross-family review reaches
Claude through engine.claude.review instead. The old warning against the
floating `opus` alias no longer applies — it resolves to Opus 5 — while
claude-fable-5 stays pinned for the strong Claude lane because Fable sits
above Opus.

Legacy `- model.role.<name>` lines are still read, one step weaker than the
yaml in the same scope. The other legacy families (model.pi.*, model.codex-*,
model.claude-cli.*) are no longer read; a migration table documents the
renames and `isc doctor` names any file that still sets them.

bin/isc: init, show with provenance, doctor, models, sync. sync runs the role
installer and records a digest of the resolved role map, so doctor detects
profiles rendered from a different lane map instead of merely checking that
files exist. One effective Codex home (CODEX_HOME, default ~/.codex) is used by
resolution, init and the installer alike. doctor fails on structural errors,
unknown keys, ids the CLI refuses, ids whose vendor cannot be recognised, and
on either routing invariant, each waivable explicitly.

The installer's parser matches bin/isc byte for byte — quoting, tabbed
comments, CRLF, ASCII-only trimming, last-wins duplicates — and harness
shadowing collapses per source before merging, so `isc show` and `isc sync`
cannot disagree about which model a role runs.

Contract: implement-issues/references/model-config.md.
Executable: tests/isc-smoke.sh (51 checks), tests/test_configure_codex_roles.py
(23 tests; needs python3 >= 3.11 for tomllib, or the codex CLI).
ksamaschke deleted branch feat/models-yaml-lane-map 2026-07-31 09:44:14 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ksamaschke/implementation-skills-codex!2
No description provided.