From b5dc5f4a281943259d3ce9606a6d269dc309585e Mon Sep 17 00:00:00 2001 From: elkaix Date: Thu, 13 Aug 2026 18:16:39 -0400 Subject: [PATCH 1/3] feat: pin a separate implementation model for write jobs Maestro pinned one Codex model shared by read-only debates and write dispatches. Add an optional implementation model in ~/.codex/maestro-impl-model so write jobs can run on a different model, inheriting the debate model when unpinned so existing installs are unchanged. --pin gains a fourth tab field, publish_pin extends its rollback transaction to the third file, and companion_turn selects the model in the same mode branch that already selects the effort. The session-start and on-demand pickers now ask for the implementation model and carry the curated menu. Verified: tests/model-selector.sh (10 passed), tests/preflight.sh, tests/bounded-calls.sh (22 passed), plus a standalone pin-contract check confirmed red before the change. --- ARCHITECTURE.md | 12 +-- hooks/codex-model-select.sh | 127 +++++++++++++++++++++++++----- hooks/lib-companion.sh | 40 ++++++---- hooks/orchestrator-inject.mjs | 16 ++-- hooks/session-start.mjs | 31 ++++++-- tests/bounded-calls.sh | 35 +++++++- tests/fixtures/fake-companion.mjs | 15 +++- tests/model-selector.sh | 105 +++++++++++++++++++++++- 8 files changed, 323 insertions(+), 58 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index f16e665..19ddc8e 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -93,7 +93,7 @@ machine-readable", not for parallelism. | Component | Trigger | Responsibility | Depends on | |---|---|---|---| -| `session-start.mjs` | `SessionStart` | Reads the Codex model/effort pin; emits the setup question (when armed via `~/.maestro/ask-on-start`); appends a validated `MAESTRO_SESSION_ID` export to `$CLAUDE_ENV_FILE` for session attribution | `~/.codex/config.toml`, `~/.codex/maestro-impl-effort` | +| `session-start.mjs` | `SessionStart` | Reads the Codex model/effort pin; emits the setup question (when armed via `~/.maestro/ask-on-start`); appends a validated `MAESTRO_SESSION_ID` export to `$CLAUDE_ENV_FILE` for session attribution | `~/.codex/config.toml`, `~/.codex/maestro-impl-effort`, `~/.codex/maestro-impl-model` | | `orchestrator-inject.mjs` | `UserPromptSubmit` | Resets the direct-edit authorization flag on new tasks; sets it only on an explicit "edit it yourself"-class imperative; emits the orchestrator/implementer directive only when the prompt carries a code/design signal; intercepts "codex model" setup phrasing | `maestro-policy.mjs`, `~/.maestro/direct-edit/` | | `orchestrator-gate.mjs` | `PreToolUse` (`Edit\|Write\|MultiEdit`) | Blocks the orchestrator's direct source edits; allows non-code allowlisted files, anchored scratch/Desktop paths, any path carrying a `.claude` or `.codex` segment (harness exemption — segment-based, not root-anchored), and only a session-scoped, owner-private, exact-content direct-edit flag; refuses overrides inside subagents; fails closed on unreadable payloads | `maestro-policy.mjs`, `~/.maestro/direct-edit/` | | `maestro-policy.mjs` | (shared module) | Single source of truth for file classification (non-code extensions/basenames), session-id validation, and direct-edit directive parsing with negation/quote guards | none | @@ -128,7 +128,7 @@ Layering is strict and directional: `lib-process.sh` → `lib-companion.sh` → | Component | Role | |---|---| -| `codex-model-select.sh` | Transactionally pins Codex model + debate effort (in `~/.codex/config.toml`) and implementation effort (in `~/.codex/maestro-impl-effort`); serialized by its own lock; `--show`, `--pin`, `--ask-on-start on\|off` | +| `codex-model-select.sh` | Transactionally pins Codex model + debate effort (in `~/.codex/config.toml`) and implementation effort/model (in `~/.codex/maestro-impl-effort` and `~/.codex/maestro-impl-model`); serialized by its own lock; `--show`, `--pin`, `--ask-on-start on\|off` | | `codex-mcp-check.sh` | Reports which MCP servers background Codex jobs inherit from `~/.codex/config.toml`, env keys masked | ### 2.6 Installer / uninstaller (package entry points) @@ -203,7 +203,7 @@ kill without a recovery daemon. | Session-start preference | `~/.maestro/ask-on-start` | Empty marker file; armed by default on first install, managed by `codex-model-select.sh --ask-on-start on\|off` and removed by uninstall | `install.mjs`, `codex-model-select.sh` | `session-start.mjs`, `uninstall.mjs` | | Installer ownership manifest | `~/.maestro/install-manifest.json` | `{ "version": 1, "files": { "": "" } }`, `0600` | `install.mjs` | `install.mjs`, `uninstall.mjs` | | Session identity | `$CLAUDE_ENV_FILE` | `export MAESTRO_SESSION_ID=` appended at session start | `session-start.mjs` | All lease/provenance code via `write_lock_session_id` | -| Codex pin | `~/.codex/config.toml` (top-level `model`, `model_reasoning_effort`), `~/.codex/maestro-impl-effort` | TOML preamble / single line | `codex-model-select.sh` | `companion_pin`, `session-start.mjs` | +| Codex pin | `~/.codex/config.toml` (top-level `model`, `model_reasoning_effort`), `~/.codex/maestro-impl-effort`, `~/.codex/maestro-impl-model` | TOML preamble / single line | `codex-model-select.sh` | `companion_pin`, `session-start.mjs` | | Hook registrations | `~/.claude/settings.json` | `hooks.` blocks with exact `# maestro-managed: