Repository navigation
Conversation
Codex sends source "fork" for a forked session, but the plugin's SessionStart matcher stopped at compact, so the hook never ran: the forked session got no bootstrap package and no Session binding. The hook script and the Server already accept fork. Fixes oceanbase#2287.
Fengzdadi
requested review from
Alanxtl,
PsiACE and
zhanghuidinah
as code owners
October 28, 2026 08:00
Contributor
There was a problem hiding this comment.
Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.
An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Which issue or RFC does this PR close?
Fixes #2287.
Found while running real hosts for #2250. This is a behavior fix, so it is separate from the #2250 PRs, which only move code.
Rationale for this change
The Codex plugin registers its
SessionStarthook with the matcherstartup|resume|clear|compact. Codex sendssource: "fork"when a session is forked, so it never runs the plugin's hook for a fork. A forked session then gets no bootstrap package, and the plugin does not write a Session binding for the new session ID. The first prompt still prepares context, because Scope resolution falls back to the workspace binding.The hook script already accepts
fork(_LIFECYCLESinhooks/session_binding.py), and so do the Server's bootstrap lifecycle enum and RFC 1429. The Claude Code plugin's matcher and docs includefork. Only the Codex matcher and the Codex docs leave it out, and they have done so since ba73996 (#1720).What changes are included in this PR?
integrations/codex/plugins/powercontext/hooks/hooks.json: theSessionStartmatcher is nowstartup|resume|clear|compact|fork.docs/en/docs/integrations/codex.mdanddocs/zh/docs/integrations/codex.md: the bootstrap section listsfork. The plugin README does not list lifecycles, so it is unchanged.tests/codex_plugin/test_contract.py: the registeredSessionStartmatcher must select each lifecycle Codex sends (startup,resume,clear,compact,fork), checked withre.fullmatch. The exact-string assertion on the matcher is gone; the test now asserts the matcher's behavior. With the old matcher, theforkcase fails.tests/e2e/test_bootstrap_host_service_chain.py: acodex-recorded-forkcase runs the packaged hook in a subprocess against a live Server with the payload Codex 0.165.0-alpha.1.2 sent for a fork. The session ID, working directory, and transcript path take the test's values;hook_event_name,model,permission_mode, andsourcestay as recorded. The case checks the same chain as the startup cases: the package is injected, the first prompt reports the receipt, and ordinary recall works. The hook script already acceptedfork, so this case also passes without the fix. It guards the script's handling of the real payload; the contract test above is the one that fails on the old matcher. Like the existing cases, it sets an explicit Scope, so it does not cover the Session binding. The binding was checked only on the real host (below).Open question:
restore. The script and the Server acceptrestore, but I found no sign that Codex sends it. In the Codex 0.165.0-alpha.1.2 binary, the strings next to the SessionStart output errors list exactlystartup,resume,clear,compact, andfork. The matcher therefore leaves outrestore. Should the script keep accepting it, or should it go?Are there any user-facing changes?
Yes. With the updated plugin, forking a Codex session (
codex fork,codex exec fork) runs theSessionStarthook. The new session gets a Session binding and, whenPOWERCONTEXT_CODEX_BOOTSTRAP_CONTEXT=true, the bootstrap package. Nothing changes for the other lifecycles.A fork keeps its parent's history, which may already contain the parent's package. The forked session then sees the package twice, bounded by
POWERCONTEXT_CODEX_BOOTSTRAP_MAX_BYTES. The Claude Code plugin already behaves this way forfork, and RFC 1429 listsforkas a bootstrap lifecycle.Codex records a trust hash for each hook. I compared two isolated Codex homes whose plugin
hooks.jsonfiles differ only in this matcher. TheSessionStarthook's hash differed, and the hashes of the other three hooks were the same. Users who already trusted the plugin's hooks will probably be asked to review theSessionStarthook again after updating. I did not test the update path.There are no API or persisted-format changes.
How was this change tested?
uv run pytest tests/codex_plugin/test_contract.py tests/e2e/test_bootstrap_host_service_chain.py: 35 passed.test_codex_session_start_hook_runs_for_every_lifecycle_codex_sends[fork].forkfrom the script's_LIFECYCLESfails onlytest_packaged_host_hooks_complete_the_live_bootstrap_chain[codex-recorded-fork].make check: passed.make unit-test: 6386 passed, 303 skipped.make e2e-test: 1144 passed, 491 skipped.make docs-test: passed (979 pages verified).CODEX_HOME, with the plugin installed from this branch throughcodex plugin marketplace addandcodex plugin add. It ran against a local Server with enforced auth. One Memory taggedbootstrap-contextheld a random marker. The plugin hooks were trusted once through the interactive "Hooks need review" dialog; I did not use--dangerously-bypass-hook-trust.codex exec(startup) and thencodex exec fork <thread>both answered with the marker.source: "fork". The Server loggedset_scope_binding,prepare_bootstrap_context, andrecord_bootstrap_delivery, followed by the prompt'sprepare_context. The forked rollout holds the# PowerContext bootstrap contextdeveloper message, written after the fork started.UserPromptSubmitandStophooks (resolve_scope_binding,prepare_context,capture_content_source,get_stats). It logged no binding write and no bootstrap request.clearandcompactwere not run on the real host.AI usage statement
This PR was prepared with Claude Code (Claude Opus 5.5). It found the gap during the #2250 host runs, made the change and the tests, and ran the real Codex host and the checks. I reviewed the change and the results.