LearnNewsExamplesServices
Frontmatter
id13622
titleAdd Codex Stop-hook parity for no-hold reminders
stateClosed
labels
enhancementaitestingarchitecturemodel-experience
assigneesneo-gpt
createdAtJun 20, 2026, 2:59 PM
updatedAtJun 20, 2026, 3:57 PM
githubUrlhttps://github.com/neomjs/neo/issues/13622
authorneo-gpt
commentsCount0
parentIssue13618
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtJun 20, 2026, 3:57 PM

Add Codex Stop-hook parity for no-hold reminders

Closed v13.1.0/archive-v13-1-0-chunk-4 enhancementaitestingarchitecturemodel-experience
neo-gpt
neo-gpt commented on Jun 20, 2026, 2:59 PM

Context

On 2026-06-20, @tobiu asked whether Codex Stop-hook parity should affect Discussion #13621 or become a related ticket. The boundary is clear: #13621 owns the no-hold taxonomy and canonical Stop-hook reminder content; this ticket owns only the Codex Desktop harness adapter parity needed to consume that content.

Release classification: boardless post-v13 harness hardening. This is useful Agent OS stability work, but it is not a release-blocking gate.

Live duplicate sweep: checked the latest 20 open issues at 2026-06-20T12:58:17Z; no equivalent Codex Stop-hook parity ticket exists. Adjacent prior art found: #12633 (Claude-family Stop-hook enforcement), #10063 (Claude auto-memory safety-net, not build-ready), and #13480 (Codex wake submit reliability, separate final-submit boundary). A2A in-flight sweep: latest 30 inbox messages showed the #13621 re-poll, not a competing [lane-claim] / [lane-intent] on this Codex parity slice.

The Problem

The Claude family now has a concrete Stop-hook lane-state enforcement surface, but the Codex harness only has a UserPromptSubmit context hook wired today. Codex docs now document turn-scope Stop hooks, so the old fallback assumption that Codex can only receive prompt-submit context is stale enough to require a parity probe.

The risk is two-sided:

  • If we do nothing, Codex remains the weak harness for the no-hold boundary: Claude can dry-run or enforce at turn-end, while GPT relies on self-policing or prompt-start reminders.
  • If we blindly port the Claude hook, we may assume the wrong stdin/stdout contract. Claude uses structured {"decision":"block","reason":"..."}. Codex must be verified before any enforcement claim.

Ungraduated Discussion Exception

This ticket intentionally cites open Discussion #13621 before its final graduation. The substantive rationale is operator-directed and scope-narrow: the ticket does not graduate #13621, does not decide the reminder wording, and does not encode the taxonomy. It creates the Codex harness adapter lane so the eventual #13621 content has parity across families.

Downstream amendment note: once #13621 graduates, this ticket's content-source row and reminder-string AC may need a small refresh to cite the final approved anchor. The transport ACs remain valid either way.

Divergence Matrix

Option When this would be right Evidence / falsifier
A. New Codex parity ticket under #13618 The issue is harness transport parity, not reminder semantics Current .codex/hooks.json only wires UserPromptSubmit; official Codex docs list Stop; #13621 is converging content only
B. Fold into #13621 The open question were what the reminder should say for Codex specifically Rejected: that would mix content semantics with per-harness adapter mechanics and delay quorum over a non-content concern
C. Fold into #12633 The Claude Stop-hook ticket already owned all harnesses Rejected: #12633 explicitly scopes Claude-family Stop hook and named a Codex fallback, not a verified Codex Stop implementation
D. Use Goal mode / UserPromptSubmit only Codex Stop cannot block, inject, or expose enough turn-end state Kept as fallback: first prove Codex Stop; if it cannot enforce, classify/log at Stop and enrich the next prompt/wake instead

Architectural Reality

  • .codex/hooks.json:3-15 currently registers only UserPromptSubmit, invoking .codex/hooks/codex-context.mjs.
  • .codex/hooks/codex-context.mjs:31-55 records Codex turn presence; .codex/hooks/codex-context.mjs:104-120 emits .codex/CODEX.md as turn context.
  • .claude/hooks/laneStateStopHook.mjs:3-38 documents the Claude Stop-hook enforcement shape; .claude/hooks/laneStateStopHook.mjs:96-120 contains the pure decision mapping; .claude/hooks/laneStateStopHook.mjs:193-230 resolves the runtime Stop payload.
  • test/playwright/unit/hooks/laneStateStopHook.spec.mjs:11-17 defines the current falsification layers; test/playwright/unit/hooks/laneStateStopHook.spec.mjs:149-180 proves dry-run and enforcing output for Claude.
  • Codex Goal mode is not an enforcement substitute: it repeats a persistent objective and completion criteria, while Stop-hook parity is a turn-boundary detector/enforcer.

Pre-Flight (structural fast-path): potential authoring of .codex/hooks/codex-lane-state-stop.mjs matches the sibling hook-module pattern of .codex/hooks/codex-context.mjs in .codex/hooks/; sibling-file-lift applies; no novel directory choice. If implementation instead introduces a shared cross-harness lifecycle module outside the existing ai/scripts/lifecycle/ primitives, rerun structural pre-flight for that new location.

The Fix

  1. Add a Codex Stop-hook probe in dry-run mode to capture the real Codex Stop stdin payload and verify event timing.
  2. Verify Codex output semantics empirically: whether stdout JSON, exit status, or another contract can block/inject a continuation. Do not assume Claude's decision:block contract.
  3. If Codex can block/inject, add a .codex Stop hook that reuses the existing lane-state parser/validator primitives and the canonical #13621 reminder content.
  4. Keep dry-run/log-only as the default. Enforcement must be operator-activated via environment/config after false-positive review.
  5. If Codex cannot block/inject, do not fake enforcement. Ship a classify/log path and route the reminder into the next UserPromptSubmit / Goal-mode wake path as a best-effort fallback.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback Docs / Evidence
Codex Stop hook payload Official Codex hooks docs + live probe fixture Extract final assistant text or a transcript pointer suitable for lane-state parsing If payload lacks final text, classify unsupported and avoid enforcement claims Captured fixture in unit tests and PR body
Codex Stop decision output Official Codex hooks docs + live probe Use only a verified block/inject contract If no block path exists, log/classify and enrich next prompt Spawned-hook tests plus live dry-run evidence
.codex/hooks.json Existing project-local Codex hook config Add Stop alongside current UserPromptSubmit, preserving the current context hook Leave UserPromptSubmit untouched if Stop is probe-only Diff + hook inspection
Reminder content Discussion #13621 after approval/graduation Reuse the single canonical no-hold reminder; no Codex-specific wording fork Temporary placeholder can cite #13621 anchor but must be refreshed before enforcement Discussion anchor in PR body
Enforcement activation #12633 dry-run-to-enforce safety pattern Default dry-run/log-only; operator-owned enforcement flip No enforcement if false-positive rate or hook contract is unsafe Unit tests + audit log evidence

Decision Record impact

None expected. This is aligned with #13618 and the existing Agent OS hook/enforcement direction. No ADR amendment should be needed unless the Codex probe exposes a cross-harness hook contract that should become a shared design record.

Decision Record: Not needed for this ticket; #13621 remains the content discussion.

Acceptance Criteria

  • Codex Stop hook fires in a trusted project-local configuration and captures a representative payload fixture without blocking normal turns.
  • The implementation proves or falsifies Codex block/inject semantics. The PR must explicitly state whether Claude's decision:block shape is supported, unsupported, or replaced by a Codex-specific contract.
  • If block/inject is supported, .codex/hooks.json wires a Codex Stop hook in dry-run mode by default.
  • The hook reuses existing lane-state parser/validator primitives where compatible and does not fork the no-hold taxonomy.
  • The hook reminder content is sourced from #13621's approved/graduated anchor before enforcement can be enabled.
  • Hook failures fail open: malformed Codex payloads, unreadable transcript pointers, log write failures, or validator errors must never trap a turn.
  • Unit coverage mirrors the Claude hook layers: pure decision, input resolution, and spawned hook behavior against a representative Codex Stop payload.
  • If Codex cannot block/inject, the PR ships only classification/logging and next-prompt enrichment; it must not claim enforcement parity.

Out of Scope

  • Changing #13621 content, quorum, or graduation criteria.
  • Changing the Claude hook except for comparison tests or shared parser reuse.
  • Auto-persisting memories; that belongs to #10063 after its session-id and curation-premise rescope.
  • Codex wake submit reliability; #13480 remains the route for direct-message / heartbeat final-submit evidence.
  • Using Goal mode as a validator or enforcement layer.

Avoided Traps

  • Do not create a second canonical reminder string for Codex. Transport parity consumes the content contract; it does not fork it.
  • Do not infer Codex hook decision semantics from Claude. The first deliverable is a falsifying payload/output probe.
  • Do not turn OQ4 observability into an automated metric gate. #13621 converged it as team-facing observability, not enforcement.
  • Do not modify ignored local .codex/config.toml; keep project behavior in tracked .codex/hooks.json and documented activation env/config.

Related

Parent: #13618

Related: #13621, #12633, #10063, #13480

Origin Session ID: 2513f864-fce4-4a47-8d4b-afe8a5532e91

Handoff Retrieval Hints: Codex Stop-hook parity, Codex hooks Stop payload, no-hold reminder transport, laneStateStopHook parity, Goal mode fallback, UserPromptSubmit enrichment.