Skip to content

fix(codex): preserve hook-driven agent status - #8292

Open
bbingz wants to merge 7 commits into
stablyai:mainfrom
bbingz:bbingz/split-7950-hooks-status
Open

bbingz wants to merge 7 commits into
stablyai:mainfrom
bbingz:bbingz/split-7950-hooks-status

Conversation

@bbingz

@bbingz bbingz commented Jul 11, 2026 •

Copy link
Copy Markdown
Contributor

ELI5

Opening or resuming an idle Codex session should clear stale turn status without reporting new work or a completed turn. This update retains session identity, keeps child events from replacing the parent session, and preserves remote user-hook approvals when Orca's hook moves to the front.

What Changed

  • Treat root SessionStart as an idle metadata boundary. Keep its session ID for the next real status, clear stale status, and preserve idempotent relay clear/reconnect replay.
  • Reject child SessionStart and unknown events as root identity sources; fence relayed SessionStart identity and clear together against a foreign connection.
  • Preserve current subagent lifecycle handling and add the remaining tool/result, interrupt and native permission-title handling.
  • Prepend managed remote hooks and migrate unchanged user hooks' index-addressed trust state, preserving existing hashes and explicit disablement even when no hash exists. Snapshot all source states before clearing changed source/destination keys, including absent approvals; repeated installation is a same-index no-op.

Why

This is the hooks/status replacement extracted from #7950, adapted to the current split implementation. It retains the existing local/app-server trust-rebase mechanism and adds the remaining remote prepend migration. Startup delivery, native chat/session bridging, account configuration and rate-limit work remain outside this PR.

Refs #7950

Visual Proof

N/A — no visual redesign. Status and notification behavior is covered by deterministic listener, relay and renderer-predicate tests; rendered Electron verification was not performed.

Testing

Final focused validation is tied to 248694dc06e3134151bdaf2a28c29305cecf6465, rebased onto main 6108ce617c8696c3d52a97d29911aed630a22e78, using Node 26.8.1 and the current lock-matched dependencies on macOS.

  • Cursor focused Vitest: 16 files, 279 tests passed.
  • Independent identity/trust/remote-install/retirement regressions: 7 files, 45 tests passed; all 10 trust test files, 146 tests passed.
  • Node/Web/CLI typechecks with --composite false; all 33 changed files passed oxlint and oxfmt; diff whitespace check passed.
  • Patched node-pty preflight passed after restoring its direct native build. Three affected native/shell suites then passed 46 tests with 2 Linux-only skips.
  • Complete non-Docker Vitest on ancestor 0105225a7a34e74a7f67b84a9e1714fd2d4e20a8: 8,245 files passed / 12 failed / 61 skipped; 76,615 tests passed / 29 failed / 391 skipped, 686.46 seconds. All 28 baseline failures match the clean 6108ce6 baseline rerun. The sole additional failure expected a synthetic working row from Codex SessionStart; the final retirement test now requires no synthetic row and verifies the first real event revives the pane.
  • The full suite is explicitly not green and was not repeated on the final SHA. The follow-up changes one production trust-move helper and three test files; the final trust suite and regression checks cover that delta, while shared listener/server/relay production is byte-identical to the full-tested ancestor.
  • Physical Windows/WSL/SSH installation, full build and rendered Electron verification were not run.

The existing SessionStart assertions intentionally change from synthetic working status to no visible event, with the next real prompt retaining identity and cleared turn data. The retired-pane table now gives Codex a dedicated no-row/real-event revival assertion; every other provider remains covered. The public API parity assertion adds the new trust-move export; existing exports remain covered. Relay tests were moved to a dedicated file without removing their assertions.

Review

Cursor supplied an explicit adversarial/security PASS for this SHA. Independent review reproduced and verified fixes for child SessionStart, stale-connection identity, ignored-event identity poisoning disabled/no-hash trust migration, and stale destination approval/disablement inheritance. Tests cover adjacent shifts, reverse move ordering, destination collisions and repeated remote/redirected-home installs.

The optional standalone Grok review attempt failed with HTTP 402 and yielded no verdict; it is not counted as a PASS.

Compatibility and Security

New main consumes SessionStart as a clear. The relay's compatibility tombstone remains working plus hookEventName: SessionStart, avoiding a synthetic done that completion observers would count as finished work. Older mains retain their previous working-row behavior; this PR does not claim they gain the new clear behavior.

Only matching unchanged user-hook content has trust state relocated. Missing hashes stay missing; no user approval is synthesized. Managed hooks retain their separate existing grant path. SSH and redirected remote homes use the content mover; native local and WSL runtime installs retain their existing app-server path. No new RPC method or stream opcode is introduced.

Before publication, upstream advanced to 8f78c28248fbfa4d55fb837ab6698ac77d4e35c5. Its changed files do not overlap this PR, package/lock files are unchanged, and a local merge-tree check completed without conflicts. The reviewed branch retains its 6108ce6 base.

AI Disclosure

Cursor implemented and reviewed the rebase; OpenAI Codex independently reviewed the diff and verification evidence and reproduced the regression cases.

@coderabbitai

coderabbitai Bot commented Jul 11, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

We couldn't safely recover the incremental review. No full review was started, and the last reviewed checkpoint was preserved. Retry later, or explicitly request a full review by commenting @coderabbitai full review.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Codex hook support now includes SubagentStart and SubagentStop, prepended remote managed hooks, and trust-entry key migration. SessionStart events are metadata-only, with provider sessions cached across subsequent normalized events and pane statuses cleared idempotently across local and relayed paths. Codex lifecycle, interruption, subagent, and tool-input normalization was expanded. Codex-native Action Required titles are recognized as permission states and used in auto-approval suppression.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely describes the primary change: preserving Codex hook-driven agent status.
Description check ✅ Passed The description is detailed and covers the change, rationale, linked issue, visual proof, testing, AI disclosure, review, compatibility, and scope. It omits explicit Template sections for Notes, Check…

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/relay/agent-hook-server.ts (1)

317-334: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Prevent duplicate Codex SessionStart clears on the relay path. In src/relay/agent-hook-server.ts:317-334, normalizeHookPayload(..., 'codex', ...) deletes the cached status for SessionStart, so a second identical POST can re-enter forwardSessionStartClear after the tombstone is written and broadcast a second clear. Skip this branch when previousStatus.hookEventName === 'SessionStart'.

🧹 Nitpick comments (1)
src/main/agent-hooks/server.ts (1)

1310-1330: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document the delete-side-effect inference used to detect a Codex SessionStart clear.

previousStatus && !this.state.lastStatusByPaneKey.has(paneKey) only works because normalizeHookPayload's Codex branch deletes the cache entry as a side effect of returning null for SessionStart. Nothing here checks hookEventName/hook_event_name directly, so this reads as an accidental correlation rather than an intentional contract, and any future Codex event that also nulls-and-deletes for an unrelated reason would silently route through this same "clear" path (with its listener/telemetry side effects).

A one-line comment stating this dependency (and ideally an explicit hookEventName === 'SessionStart' check in clearStatusForSessionStart itself, mirroring the relay's ingestRemote explicit check) would make the contract self-evident.

Based on coding guidelines: "When code is driven by a design document or non-obvious constraint, add a brief one- or two-line comment explaining why it behaves that way."

Source: Coding guidelines


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: be012b83-a822-4745-a4d4-09e9d1be5457

📥 Commits

Reviewing files that changed from the base of the PR and between 490086a5908097185ceb180915c6fe9ea60fb225 and 600e536106349bb7dc19b1fcf7dc08f8545cf7c1.

📒 Files selected for processing (16)
  • src/main/agent-hooks/server.test.ts
  • src/main/agent-hooks/server.ts
  • src/main/codex/codex-hook-identity.ts
  • src/main/codex/config-toml-trust.ts
  • src/main/codex/hook-service-wsl-runtime.test.ts
  • src/main/codex/hook-service.test.ts
  • src/main/codex/hook-service.ts
  • src/relay/agent-hook-server.test.ts
  • src/relay/agent-hook-server.ts
  • src/renderer/src/components/terminal-pane/codex-auto-approval-notification-suppression.test.ts
  • src/renderer/src/components/terminal-pane/codex-auto-approval-notification-suppression.ts
  • src/renderer/src/lib/agent-status.test.ts
  • src/shared/agent-detection.ts
  • src/shared/agent-hook-listener.test.ts
  • src/shared/agent-hook-listener.ts
  • src/shared/agent-title-status.ts
✅ Files skipped from review due to trivial changes (1)
  • src/main/codex/hook-service-wsl-runtime.test.ts
🚧 Files skipped from review as they are similar to previous changes (10)
  • src/shared/agent-detection.ts
  • src/main/codex/codex-hook-identity.ts
  • src/renderer/src/lib/agent-status.test.ts
  • src/renderer/src/components/terminal-pane/codex-auto-approval-notification-suppression.test.ts
  • src/renderer/src/components/terminal-pane/codex-auto-approval-notification-suppression.ts
  • src/shared/agent-title-status.ts
  • src/main/codex/hook-service.ts
  • src/main/codex/hook-service.test.ts
  • src/shared/agent-hook-listener.ts
  • src/main/codex/config-toml-trust.ts

@bbingz
bbingz force-pushed the bbingz/split-7950-hooks-status branch from 600e536 to 1512f04 Compare July 12, 2026 01:29
@bbingz

bbingz commented Jul 12, 2026 •

Copy link
Copy Markdown
Contributor Author

Addressed the latest CodeRabbit outside-diff finding in 7582f64f3.

The relay now recognizes a prior SessionStart tombstone, restores it after the shared normalizer's synchronous delete, and returns without forwarding a duplicate clear. This is intentionally not just an early return: keeping the tombstone is what preserves reconnect replay. The expanded lifecycle test proves one clear across duplicate events, replay of that clear, and replacement by the next real working status.

Post-rebase verification: 3 focused files / 345 tests, full Node/CLI/Web typecheck, targeted lint/format, max-lines, diff check, and independent PASS / APPROVED review.

@bbingz
bbingz force-pushed the bbingz/split-7950-hooks-status branch from 1512f04 to 7582f64 Compare July 12, 2026 01:46
@bbingz

bbingz commented Jul 12, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto latest origin/main to clear a merge conflict in src/main/codex/hook-service.ts introduced by #8333 (WSL trust path folding).

Conflict resolution kept both import surfaces:

  • normalizeCodexProjectPathForLookup from main
  • moveHookTrustEntriesInContent (+ PR trust-move path) from this branch

Focused vitest: hook-service, hook-service-wsl-runtime, agent-hook-listener, agent-hooks/server, relay agent-hook-server — all green.

@bbingz

bbingz commented Jul 13, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 13, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@bbingz
bbingz force-pushed the bbingz/split-7950-hooks-status branch 2 times, most recently from 150ea6b to 6711002 Compare July 14, 2026 00:38
@bbingz
bbingz force-pushed the bbingz/split-7950-hooks-status branch from c9b518b to 1272bbe Compare July 22, 2026 01:33
@bbingz

bbingz commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto latest origin/main (force-with-lease).

Conflict resolution notes:

  • Kept main's Codex subagent roster / lead-state infrastructure and advanced TOML trust parser
  • Ported PR intent: Codex SessionStart no longer emits a working row (clears stale status, caches provider session for the next real event)
  • Ported remote hook prepend + user trust key migration (moveHookTrustEntriesInContent + collectPrependedRemoteUserTrustMoves) onto main's installRemote path
  • Preserved follow-ups: stale Codex session clear + relayed SessionStart dedupe/tombstone replay

@bbingz

bbingz commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto current main. Hook-driven status preservation + SessionStart tombstone handling restacked against main’s subagent roster work. Ready for re-review.

@bbingz

bbingz commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto current origin/main (0326594d52).

Conflict resolution:

  • kept main's isAskUserQuestionTool PreToolUse→waiting mapping and this PR's SessionStart metadata-only clear (no idle working spinner)
  • completed Codex tool previews / PostToolUse tool_response / subagent tool-row surfaces so the PR's status tests hold on current main

Focused tests: agent-hook-listener + codex hooks/suppression/status 283/283 green (5 skipped). ahead=4 behind=0.

@bbingz
bbingz force-pushed the bbingz/split-7950-hooks-status branch from 1272bbe to cf3af2a Compare July 23, 2026 02:03
@nwparker nwparker added the bug Something isn't working label Jul 27, 2026
@bbingz
bbingz force-pushed the bbingz/split-7950-hooks-status branch 2 times, most recently from 46ba1c8 to d8133f1 Compare July 28, 2026 11:33
@bbingz
bbingz force-pushed the bbingz/split-7950-hooks-status branch from d8133f1 to 083f7bd Compare August 5, 2026 04:55
@bbingz

bbingz commented Aug 12, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto latest main (resolved agent-title-status.ts: kept main’s OpenCode native title status + Codex action-required permission).

Head: f7074e93848f — ready for re-review when convenient.

@bbingz
bbingz force-pushed the bbingz/split-7950-hooks-status branch 2 times, most recently from 248694d to 19f9898 Compare September 14, 2026 16:42
@bbingz

bbingz commented Sep 14, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto current origin/main (e53f1557e1). Fork CI still needs maintainer Approve and run workflows. Focused tests passed locally; no origin push and no merge.

bbingz and others added 7 commits September 20, 2026 19:15
SessionStart is an idle TUI/resume boundary. Clear the pane instead of
publishing working/done, prepend remote hooks with index-addressed trust
moves, and forward a working tombstone so old-main cannot treat this as
completion.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep the working tombstone semantics, but move apply/clear helpers and
SessionStart tests out of the over-budget relay files and supply the
required completion stateHistory field.

Co-authored-by: Cursor <cursoragent@cursor.com>
Child SessionStart, foreign-connection SessionStart, and unrecognized
hooks must not replace the root resume id. Cache writes wait until a
root event is accepted, except the intentional SessionStart metadata
write.

Co-authored-by: Cursor <cursoragent@cursor.com>
The three root identity regressions stay intact. They live under main so
tsconfig.web does not follow AgentHookServer into telemetry defines.

Co-authored-by: Cursor <cursoragent@cursor.com>
A user hook with enabled=false and no trusted_hash must travel with its
index shift. Leaving it behind disables the managed hook and inventing a
hash would synthesize approval.

Co-authored-by: Cursor <cursoragent@cursor.com>
Destination enabled/hash must come only from the source. Vacate both
keys before writes so a missing source cannot reuse a stale dest
approval, and a missing enabled cannot inherit dest disablement.
Adapt the Codex retired-pane case: SessionStart stays idle metadata
and the first real event supplies the visible working row.

Co-authored-by: Cursor <cursoragent@cursor.com>
@bbingz
bbingz force-pushed the bbingz/split-7950-hooks-status branch from 19f9898 to 13ab19a Compare September 20, 2026 11:21

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants