Skip to content

feat: enable per-project Codex memories - #79

Merged
tortmayr merged 2 commits into
mainfrom
codex-memory
Sep 18, 2026
Merged

tortmayr merged 2 commits into
mainfrom
codex-memory

Conversation

@tortmayr

Copy link
Copy Markdown
Contributor

What it does

Turns on Codex memories ([features] memories = true in the settings template) so sandboxed sessions stop relearning the project from scratch. Background consolidation uses plan quota; opt out per run with --no-memory or permanently with a config patch.

The existing memory system assumed Claude's model (self-contained files in one mounted directory). Codex splits memory between the mount and its config store, which drives the new spec-schema controls (available to all tool extensions, including installed third-party ones):

  • sandbox.memoryScope: session keys the memory mount by config-store key, so concurrent stores never share a memory database
  • sandbox.noMemoryArgs natively disables memory use and generation for --no-memory and --ephemeral runs. Claude declares it too (--settings '{"autoMemoryEnabled": false}'), so those flags now stop generation instead of only omitting the mount
  • sandbox.statePaths pins config-relative runtime state across config-source overlays and keeps it out of host config passthrough. Codex pins its memory files, their index database, and its thread databases; the thread databases are rebuildable rollout projections, pinned to avoid re-deriving them on every overlaid run
  • cleanup treats session-scoped memory and its config store as one unit (--keep memory / --keep history) and tolerates tools whose extension has been removed
  • tools add/update report the new grants (agent memory, no-memory args, preserved state paths) in the capability summary and update diff

Memory scope is only resolved for tools that declare a memory dir, so memory-less tools don't grow a meaningless field in their golden surface.

Fixes #78

How to test

make build && make test && make lint

  • Verified locally: build, tests, lint, and license-header checks pass

All probes run inside enclave --tool codex shell sessions; no host paths needed. Planted markers stand in for real memory generation, which the model triggers at its own discretion.

  1. Persistence: in a shell session, echo probe > ~/.codex/memories/PROBE.md, exit. Start a new shell session: the probe is still there.
  2. Mount-backed, not store-backed: restart with --no-memory: the probe is gone, because it lives in the omitted memory mount rather than the config store. A regular restart shows it again; remove it afterwards.
  3. Overlay survival: with a config patch active (~/.config/enclave/patches/codex/config.toml), in a shell session touch ~/.codex/state_999.sqlite ~/.codex/memories_999.sqlite, exit, restart: both markers survive the store overlay. On main the overlay deletes them.
  4. Ephemeral: in an --ephemeral shell session write a probe into ~/.codex/memories/, exit, start a regular session: the probe is gone, discarded with the session store.
  5. Cleanup coupling: enclave cleanup --tool codex --dry-run --keep memory retains the config store together with memory; --keep history retains both as well; a plain cleanup --dry-run lists both for removal.
  6. Disable argv: a --no-memory Codex session reports memories disabled via /memories. The injected argv (-c features.memories=false, Claude's --settings '{"autoMemoryEnabled": false}') is pinned by unit tests.

The same seams are covered by automated tests (memory_mount_test.go, overlay_test.go, cleanup_test.go, host_config_passthrough_test.go); the probes are the end-to-end variant of those assertions.

Follow-ups

  • The overlay stages preserved paths by copying through $TMPDIR and walks into directories it already staged wholesale. With statePaths now pinning large trees (memories/ can hold a git repository), staging via rename on the same filesystem and skipping staged directories would cut startup cost on overlaid runs. Worth a ticket; not done here to keep overlay.go out of this PR.

Breaking changes

  • This PR introduces breaking changes and has been coordinated with maintainers.

Review checklist

Codex sessions start from a fresh container, so without memories every
session relearns the project from scratch. Turn them on in the settings
template and give the spec schema the controls this needs:

- sandbox.memoryScope: session couples the memory mount to the
  config-store key, so concurrent stores never share a memory database
- sandbox.noMemoryArgs natively disables memory use and generation for
  --no-memory and --ephemeral runs; Claude declares it too, so those
  flags now stop generation instead of only omitting the mount
- sandbox.statePaths pins config-relative runtime state across
  config-source overlays and keeps it out of host config passthrough;
  Codex pins its memory files, their index database, and its thread
  databases (rebuildable rollout projections, pinned to avoid
  re-deriving them on every overlaid run)
- cleanup treats session-scoped memory and its config store as one
  unit for --keep memory/--keep history and tolerates removed tools
- tools add/update report the new grants in the capability summary
  and update diff

@EclipseSourceAI EclipseSourceAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Note

Autonomous AI review.

This review was done by an AI agent and therefore may contain mistakes. Feel free to ignore any comment you disagree with. A thumbs-down reaction on a comment marks it as rejected for follow-up reviews. Noting why in a reply helps, since replies are read too.

Resolving all AI comments does not lead to an automatic approval. A maintainer still needs to review and sign off on the overall architecture and design.

To get an updated review after pushing changes, a maintainer may re-request a review from this account.

Running in Eclipse Enclave, submitted via review-guard-mcp

Enables Codex memories (features.memories = true in the settings template) and generalizes enclave's memory model to fit a tool that splits memory between the bind mount and its config store. Three new spec-schema fields carry that: sandbox.memoryScope: session keys the memory mount by config-store key (reusing the existing sessionGeneratedKey, same as the skills mount), sandbox.noMemoryArgs gives --no-memory/--ephemeral a native disable argv (Claude declares one too, so those flags now stop generation instead of only dropping the mount), and sandbox.statePaths pins config-relative runtime state, routed into the existing HostConfigPassthroughDeniedPaths so both the overlay preserve list and passthrough denial pick it up for free. Cleanup learns to treat session memory and its config store as one unit and to tolerate tools whose extension is gone.

The integration looks clean: existing seams get reused rather than duplicated, compactProfileArgs moves to load-time normalization where it also covers the new argv, and the docs (stores.md, extension docs, cli-reference) are updated properly. Tests are thorough, including the overlay running against the real preserve-path policy. Build, vet, and the touched package tests pass locally.

Points worth a maintainer's attention:

  • Turning memories = true on by default consumes plan quota for every existing Codex user on upgrade. A product call, not a code issue.
  • Cleanup's abort-vs-warn split on an unloadable spec is fine for the single-tool path but hard-fails the whole --ephemeral --all sweep.
  • statePaths pins thread-writer-locks/, which is the one entry where preserving state across an overlay could carry a stale lock forward.
  • The permanent-opt-out documentation omits enclave's own no_memory config option.

Remaining inline comments are small validation and documentation nits.

Comment thread internal/config/profile.go
Comment thread internal/app/cleanup.go Outdated
Comment thread extensions/tools/codex/spec.yaml
Comment thread extensions/tools/codex/spec.yaml
Comment thread extensions/tools/codex/templates/config.toml
Comment thread extensions/tools/codex/README.md Outdated
Review feedback on #79:

- one broken third-party spec no longer aborts an --ephemeral --all
  sweep for every other tool and project: the sweep warns and falls
  back to the default scope per tool, and under --keep memory skips
  the broken tool's stores, since the scope decides what would be kept
- reject memory_scope declared without memory_dir, matching how the
  session branch and skills_dir treat their dependent fields
- codex spec: note that statePaths are config-relative unlike the
  home-relative memoryDir, and that codex reconciles stale writer
  locks itself, so pinning the lock directory is safe
- codex README: list the no_memory config option as an opt-out

@EclipseSourceAI EclipseSourceAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Note

Autonomous AI review.

This review was done by an AI agent and therefore may contain mistakes. Feel free to ignore any comment you disagree with. A thumbs-down reaction on a comment marks it as rejected for follow-up reviews. Noting why in a reply helps, since replies are read too.

Resolving all AI comments does not lead to an automatic approval. A maintainer still needs to review and sign off on the overall architecture and design.

To get an updated review after pushing changes, a maintainer may re-request a review from this account.

Running in Eclipse Enclave, submitted via review-guard-mcp

Follow-up review. The new commit (a76a6d7) addresses all four inline points from my earlier review: memory_scope: project without memory_dir is now rejected, the ephemeral sweep no longer aborts entirely on one unloadable spec (falls back per tool, skipping only under --keep memory), the codex spec comment now explains the config-relative base and why pinning the lock dir is safe, and the README lists no_memory as an opt-out. Tests were updated to match (cleanup_test.go, spec_loader_test.go) and pass locally, along with go build ./....

The default-on features.memories = true in config.toml (quota impact for existing users) is unchanged, but that was flagged as a product/maintainer sign-off question, not a code defect, so nothing to add there.

No new findings in the delta since my last review.

These previous comments can be resolved as they are now handled:

I can't resolve them myself as I would need write permission on this repository.

@xai
xai self-requested a review September 18, 2026 10:59

@xai xai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Code looks good and the feature works fine!

@tortmayr
tortmayr merged commit da0dd7b into main Sep 18, 2026
9 checks passed
@tortmayr
tortmayr deleted the codex-memory branch September 18, 2026 12:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support Codex memories and generalize the agent-memory system

3 participants