codex - 💡(How to fix) Fix Codex Rules: per-session cache for additionalContext (Claude Code InstructionsLoaded parity)

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Root Cause

  • gitignore-semantics matching via ignore lib (Claude Code parity)
  • Brace expansion in paths: frontmatter ({ts,tsx})
  • @-mention extraction (priority candidate)
  • Conversational keyword extraction (top-level dir mentions — necessary because Codex hooks fire BEFORE tool decisions, so we can't be purely reactive like Claude Code)
  • Session-scoped JSON cache with mtime invalidation
  • Atomic writes, 30-day TTL pruning, cache failure is non-fatal

Fix Action

Fix / Workaround

We built a userland workaround: per-session cache file at ~/.codex/cache/<plugin>/<session_id>.json, mtime-based invalidation, gitignore-semantics matching via the ignore library.

  • #16430 (plugin-local hooks not firing in 0.128.0) — currently blocks distributing this as a plugin; registering globally as workaround. Confirmed reproducible in 0.128.0 release.
  • #19385 (PreToolUse additionalContext not supported) — would enable fully reactive loading like Claude Code's path_glob_match.
  • #20766 (TUI: collapse hook context) — UI-side mitigation but doesn't reduce the token cost.
RAW_BUFFERClick to expand / collapse

Problem

A common Codex hook pattern: UserPromptSubmit reads project rules (e.g. .claude/rules/*.md with paths: frontmatter — same convention Claude Code uses), matches them against paths mentioned in the user's prompt, and emits matched rule bodies as hookSpecificOutput.additionalContext.

Problem: Codex re-injects the same rule bodies on every prompt.

If a user works on apps/design/ for 20 turns, the same 5 rules (~10 KB of additionalContext) get re-injected 20 times. That's ~200 KB of redundant context for a small project — bigger projects easily exceed 1 MB per session.

How Claude Code solves this natively

Claude Code's InstructionsLoaded event (with load_reason: nested_traversal | path_glob_match | session_start | compact | include) fires only when:

  1. A rule file is discovered for the first time in the session
  2. The model touches a path that triggers a previously-unseen rule
  3. Cache is invalidated (compaction)

A rule loaded on turn 1 stays in context. The hook on turn 2 sees the same paths but emits nothing new — the rule is already there.

Source: src/utils/attachments.ts:1755-1769 (memoryFilesToAttachments, where path_glob_match fires) and src/utils/claudemd.ts:1395 (uses the ignore library for gitignore-semantics path matching).

Empirical impact (our setup)

We built a userland workaround: per-session cache file at ~/.codex/cache/<plugin>/<session_id>.json, mtime-based invalidation, gitignore-semantics matching via the ignore library.

TurnActionadditionalContext size
1 (cold)edit apps/design/foo.tsx10,225 chars (full rule bodies)
2 (warm)edit apps/design/bar.tsx356 chars (status only: "already in context")
3 (touch + edit)touch .claude/rules/x.md && edit apps/design/baz.tsx~2 KB (re-injects only the changed rule)

~96.5% context reduction on the warm path. A 20-turn session in the same domain saves ~200 KB.

Proposed approaches (4 — pick what fits the team's roadmap)

  1. Native event (heaviest): add InstructionsLoaded-equivalent that hooks can subscribe to with built-in path-glob matching against frontmatter. Fully reactive (fires on tool path access). Mirrors Claude Code 1:1.

  2. Helper library (medium): publish a Codex helper that hooks call to compute "what's new since last turn" given session_id

    • candidate set. No core changes; pattern becomes documented.
  3. Cookbook docs (lightest): publish the pattern as official guidance in docs/hooks/ — "hooks that inject state should key cache by session_id and dedupe against prior turns."

  4. Marketplace plugin (zero core changes): ship our reference implementation as an official curated plugin. Users install once via codex plugin marketplace add; works for any project with a rule directory.

Reference implementation (open to contribute)

~530 lines of Node, MIT-able. Behaviors covered:

  • gitignore-semantics matching via ignore lib (Claude Code parity)
  • Brace expansion in paths: frontmatter ({ts,tsx})
  • @-mention extraction (priority candidate)
  • Conversational keyword extraction (top-level dir mentions — necessary because Codex hooks fire BEFORE tool decisions, so we can't be purely reactive like Claude Code)
  • Session-scoped JSON cache with mtime invalidation
  • Atomic writes, 30-day TTL pruning, cache failure is non-fatal

Happy to extract a clean version under whichever path the maintainers prefer (1/2/3/4).

Adjacent issues

  • #16430 (plugin-local hooks not firing in 0.128.0) — currently blocks distributing this as a plugin; registering globally as workaround. Confirmed reproducible in 0.128.0 release.
  • #19385 (PreToolUse additionalContext not supported) — would enable fully reactive loading like Claude Code's path_glob_match.
  • #20766 (TUI: collapse hook context) — UI-side mitigation but doesn't reduce the token cost.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

codex - 💡(How to fix) Fix Codex Rules: per-session cache for additionalContext (Claude Code InstructionsLoaded parity)