Why
The evaluator script (scripts/agent_guidance_eval.py) has grown into the shared infrastructure for three distinct jobs — guidance evaluation, calibration, and document slop review — while remaining a single ~1,500-line script. This shape has produced concrete problems, each observed during the 2026-08-14/15 hardening work:
- Internal-import coupling. The slop reviewer (
scripts/doc_slop_review.py) imports the evaluator's private functions (invoke_codex, parse_trace, retry helpers) because there is no shared module boundary. Any evaluator refactor can silently break the reviewer.
- Path-based invocation. Skills and hooks must reference the scripts by checkout path, which is host-layout-dependent and cannot survive relocation.
- Interpreter incantations. The scripts require Python 3.11+, but
uv run --no-project python resolves to a uv-managed 3.8 on some hosts. Today this is patched with repeated --python 3.14.6 pins in two hook entries and the Makefile, plus a runtime version guard (calibration PR).
- Mixed responsibilities in one file. Target discovery, the pass cache, failure-evidence persistence, per-case majority aggregation, trigger accounting, Codex subprocess management, and two CLI entry points live together, so every change risks the acceptance gate that guards everything else.
Proposal
Extract a proper uv project at tools/agent-guidance/ with a src/agent_guidance/ package and a single console script:
agent-guidance eval --staged --trials 3 --jobs 2 --timeout 600
agent-guidance validate --staged
agent-guidance slop-review <file|--diff|->
agent-guidance calibrate --all
Internal layout: codex_runner.py (the one definition of Codex subprocess management: model/effort arguments, ephemeral CODEX_HOME, transient retry, trace parsing — the gateway and auth themselves stay in ~/.codex/config.toml, not in this package), evaluator/ (discovery, cache, evidence, aggregation policies), slop/ (regex tier, rubric loading, judge flow), and cli.py.
Design constraints carried over from the hardening work:
- Acceptance policy stays in the hook lines.
--trials 3 --jobs 2 --timeout 600 and the per-case majority behavior remain explicit in .pre-commit-config.yaml and the Makefile, because those files are the predeclared machine-policy source. The package must not bury policy in defaults.
requires-python >= 3.11 in the package replaces the scattered interpreter pins and the runtime guard.
uv tool install puts agent-guidance on PATH, so skills reference a stable command name instead of a checkout path.
Migration plan
- Extract the package with the existing 90+ unit tests migrated; keep
scripts/agent_guidance_eval.py and scripts/doc_slop_review.py as thin compatibility shims that delegate to the package.
- Switch the hook entries and Makefile to the console script (separate PR — these lines are policy-owned).
- Update the slop-review skill's command reference to the installed command; remove the shims once nothing invokes them.
Each step keeps the acceptance gate green: the gate itself runs on this code, so no step may change evaluation semantics (the pass cache will invalidate once from the runner-hash change; that is expected and harmless).
Open questions
- Package/command naming (
agent-guidance vs something shorter).
- Whether calibration deserves a first-class subcommand or stays a documented invocation.
- Shim retention period.
- Conclusions from the ongoing design consultation (Herdr tab
cli-design-consult) should be folded in before implementation starts.
Why
The evaluator script (
scripts/agent_guidance_eval.py) has grown into the shared infrastructure for three distinct jobs — guidance evaluation, calibration, and document slop review — while remaining a single ~1,500-line script. This shape has produced concrete problems, each observed during the 2026-08-14/15 hardening work:scripts/doc_slop_review.py) imports the evaluator's private functions (invoke_codex,parse_trace, retry helpers) because there is no shared module boundary. Any evaluator refactor can silently break the reviewer.uv run --no-project pythonresolves to a uv-managed 3.8 on some hosts. Today this is patched with repeated--python 3.14.6pins in two hook entries and the Makefile, plus a runtime version guard (calibration PR).Proposal
Extract a proper uv project at
tools/agent-guidance/with asrc/agent_guidance/package and a single console script:Internal layout:
codex_runner.py(the one definition of Codex subprocess management: model/effort arguments, ephemeralCODEX_HOME, transient retry, trace parsing — the gateway and auth themselves stay in~/.codex/config.toml, not in this package),evaluator/(discovery, cache, evidence, aggregation policies),slop/(regex tier, rubric loading, judge flow), andcli.py.Design constraints carried over from the hardening work:
--trials 3 --jobs 2 --timeout 600and the per-case majority behavior remain explicit in.pre-commit-config.yamland the Makefile, because those files are the predeclared machine-policy source. The package must not bury policy in defaults.requires-python >= 3.11in the package replaces the scattered interpreter pins and the runtime guard.uv tool installputsagent-guidanceonPATH, so skills reference a stable command name instead of a checkout path.Migration plan
scripts/agent_guidance_eval.pyandscripts/doc_slop_review.pyas thin compatibility shims that delegate to the package.Each step keeps the acceptance gate green: the gate itself runs on this code, so no step may change evaluation semantics (the pass cache will invalidate once from the runner-hash change; that is expected and harmless).
Open questions
agent-guidancevs something shorter).cli-design-consult) should be folded in before implementation starts.