fix(codex): re-inject memory after compact and clear (#3880)

In Codex, memory is never re-injected after a context compaction. The
SessionStart hook that runs `hook codex context` matches only
"startup|resume", so after a manual /compact or an auto-compaction the
hook does not fire and the session continues with an empty context. A
long-running Codex session loses all injected memory at its first
compaction and never gets it back.

Codex emits four SessionStart sources, not two — SessionStartSource in
codex-rs/hooks/src/events/session_start.rs is Startup, Resume, Clear,
Compact. clear and compact both hand the model a fresh context, which is
exactly when the injection has to run. The Claude Code config already
matches "startup|clear|compact" for the same reason.

Add the two missing sources to the matcher. The hook command is
unchanged and does not branch on source, so it injects on compact and
clear exactly as it already does on startup and resume.

Closes #3862
This commit is contained in:
kavish-19
2026-09-11 06:31:33 +05:30
committed by GitHub
parent d07bb6cd77
commit 9fac73788b
2 changed files with 15 additions and 1 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
"hooks": {
"SessionStart": [
{
"matcher": "startup|resume",
"matcher": "startup|resume|clear|compact",
"hooks": [
{
"type": "command",
@@ -115,6 +115,20 @@ describe('Plugin Distribution - Codex Marketplace', () => {
expect(Object.keys(codexHooks).sort()).toEqual(['hooks']);
});
it('re-injects Codex memory on every SessionStart source that starts a fresh context', () => {
// Codex emits startup, resume, clear and compact (SessionStartSource in
// codex-rs/hooks/src/events/session_start.rs). clear and compact both hand
// the model an empty context, so the injection hook has to run for them or
// the session continues with no memory.
const codexHooks = readJson('plugin/hooks/codex-hooks.json');
const matchers = codexHooks.hooks.SessionStart.map((entry: any) => entry.matcher);
expect(matchers).toHaveLength(1);
for (const source of ['startup', 'resume', 'clear', 'compact']) {
expect(matchers[0].split('|')).toContain(source);
}
});
it('sets the Codex hook marker on every Codex command', () => {
for (const command of commandHooksFrom('plugin/hooks/codex-hooks.json')) {
expect(command).toContain('CLAUDE_MEM_CODEX_HOOK=1');