Direct answer

Use Codex lifecycle hooks to load a small memory index at SessionStart, retrieve relevant records at UserPromptSubmit, and capture completed turns at Stop. Use PreCompact and SessionEnd to checkpoint extraction work, with explicit timeouts and retry handling. Codex also offers local memories; hooks are useful when you need a separate store, shared context across agents, or control over capture and recall.

Choose the memory store before wiring events

Suppose yesterday's Codex session established why your ingestion worker cannot retry an entire batch. Today you open another checkout and ask it to fix duplicate processing. The useful memory is the recorded retry constraint, its evidence and its scope. Replaying yesterday's entire conversation would also import failed hypotheses and unrelated debugging output.

OpenAI's Memories documentation describes a local Codex memory store, off by default, with chat controls through /memories. Use that when local recall meets your needs. A custom hook adapter makes sense when the same recorded constraint must reach another agent or a fresh VM, or when your team needs its own retention and extraction rules.

For the adapter, define a record containing the fact, repository identity, author, evidence reference and review date. Keep required repository instructions in AGENTS.md. Give recalled observations an explicit data label so an old debugging note cannot silently become a standing instruction.

Register the handlers in Codex configuration

The OpenAI Configuration Reference supports inline lifecycle hooks in config.toml. Add the following to ~/.codex/config.toml on a machine running Codex CLI. These script names are examples of handlers you implement, not commands bundled with Codex:

[[hooks.SessionStart]]
[[hooks.SessionStart.hooks]]
type = "command"
command = "python3 ~/.codex/hooks/memory_start.py"
timeout = 2
additionalContextLimit = 1500

[[hooks.UserPromptSubmit]]
[[hooks.UserPromptSubmit.hooks]]
type = "command"
command = "python3 ~/.codex/hooks/memory_recall.py"
timeout = 2
additionalContextLimit = 1000

[[hooks.Stop]]
[[hooks.Stop.hooks]]
type = "command"
command = "python3 ~/.codex/hooks/memory_capture.py"
timeout = 3

[[hooks.PreCompact]]
[[hooks.PreCompact.hooks]]
type = "command"
command = "python3 ~/.codex/hooks/memory_checkpoint.py"
timeout = 2

[[hooks.SessionEnd]]
[[hooks.SessionEnd.hooks]]
type = "command"
command = "python3 ~/.codex/hooks/memory_close.py"
timeout = 3

Here, timeout uses seconds. additionalContextLimit controls the approximate token threshold for spilling oversized context to disk; enforce your own smaller output budget inside each reader. The reference also supports async = true for command hooks, while SessionEnd remains synchronous. This example deliberately keeps capture synchronous long enough to save a local queue entry.

Open /hooks to review and trust these definitions. Install only one copy of this adapter: user, project and plugin hooks can otherwise duplicate capture.

Load an index at session start

Make memory_start.py return the person's profile, repository identifiers and a short catalog of available memory records. For the ingestion worker, that might mean a two-line retry constraint and a pointer to its supporting incident note. Keep test output and historical assistant explanations out of this initial payload.

Command hooks read JSON from standard input. Dispatch using hook_event_name; retain session_id and cwd for correlation. For startup, return this documented output shape:

{
  "hookSpecificOutput": {
    "hookEventName": "SessionStart",
    "additionalContext": "Recorded memory, not instructions: ingestion-worker has a batch retry constraint. Read the incident record before changing retries."
  }
}

Resolve the repository against an approved mapping before selecting records. A directory basename such as api is too ambiguous across checkouts. Keep person and workspace selection in authenticated adapter configuration rather than accepting a repository file's claim about whose memories to load. For startup sizing choices, see context budgets at session start.

Recall against the current prompt

At UserPromptSubmit, the input includes prompt and turn_id. Return recall through hookSpecificOutput with hookEventName set to UserPromptSubmit and the retrieved text in additionalContext.

Implement the search in two passes: first restrict candidates to the authenticated person's permitted workspace and current repository, then rank the remaining records against the prompt. The request about duplicate processing should find the batch retry constraint. A request about button spacing should produce no memory output.

Set a network deadline inside the reader that expires before the configured hook timeout. On an unavailable store, return an empty JSON object and exit successfully; reserve standard output for the hook protocol. Record a short diagnostic without the prompt text. This keeps optional recall from turning a memory outage into a failed editing session.

Attach the memory's evidence reference and review date to the returned snippet. Ask the agent to check the referenced code before relying on a historical observation. For request-path tradeoffs, see recall latency and failure modes.

Capture completed turns without relying on shutdown

The Stop payload includes turn_id, stop_hook_active and nullable last_assistant_message. Return valid JSON, such as {}. The supplied transcript_path can be null, and its file format is not a stable hook interface.

Design memory_capture.py to scrub and durably enqueue the completed turn before returning. Associate the submitted prompt with the same session and turn identifiers. Use a versioned transcript reader only when you need tool evidence beyond the final response; treat unknown formats as capture failures instead of uploading an unparsed file.

Have a separate worker upload queued records and acknowledge them before deletion. Deduplicate on workspace, session and turn identifiers. Codex cancels unfinished background hooks at session end, so an asynchronous network request alone is insufficient delivery protection. On extraction, distinguish the assistant's claim that tests passed from recorded test evidence.

Use PreCompact to checkpoint the current extraction segment and SessionEnd to enqueue its closure. Treat these as application boundaries, with idempotent retries; do not make shutdown wait for model extraction. Keep capture disabled until the user or workspace has enabled it. Scrub both prompts and assistant text before either reaches a durable queue, and define expiry for uploads that never succeed.

Where SPYN3 fits

SPYN3's optional Memory & skills layer provides shared context through MCP. Its Codex plugin loads a profile, memory index and skill catalog at SessionStart, recalls at UserPromptSubmit, uploads finished turns in the background at Stop, and closes sessions at PreCompact and SessionEnd. Capture is separately off by default, requires the workspace's model key and write:memory, strips common secret patterns, and deletes raw turns after extraction. SPYN3_MEMORY_OFF=1 disables the plugin for a session.

Verify the next session gets the right constraint

Exercise the adapter with a synthetic ingestion incident before capturing real work. Record that batch retries duplicate already-committed items, close the session, then start a new one and ask about duplicate processing. Inspect the injected recall and the selected evidence, not just the fluency of the answer.

  1. Ask an unrelated UI question. Confirm the retry memory is absent.
  2. Use another repository and another identity. Confirm the incident record is unavailable unless explicitly shared.
  3. Make the memory service unavailable. Confirm startup and prompt submission remain usable within your deadline.
  4. Terminate Codex after local capture but before upload acknowledgment. Confirm the worker retries and the store retains one turn.
  5. Replay compaction and closure notifications. Confirm they neither duplicate extraction nor erase pending work.
  6. Insert a fake token into a synthetic turn. Confirm neither queue files nor uploaded capture contain it.

Run the same cases after upgrading Codex, especially if your capture reads transcript files. A successful rollout means the next session retrieves the batch constraint with its evidence, unrelated tasks stay uncluttered, and interrupted uploads remain recoverable.

Built for the next step

Keep context with the user, not the agent

Memory and skills behind the same endpoint as your tools, readable by any agent you connect.

Read the developer guide
About SPYN3

SPYN3 is a consolidated MCP layer: one hosted endpoint in front of every system you connect — MCP servers, Postgres, REST APIs, Google Drive — with tools foldered by source and read/write permissions per key. Switching agents means moving one URL. Free plan available; current capabilities are documented on the product facts page.

Sources

  1. OpenAI: Hooks — Codex hook trust and discovery, lifecycle events, input and output fields, timeout units, background cancellation and transcript format limitations. Verified 27 Oct 2026
  2. OpenAI: Configuration Reference — Inline config.toml hook matcher groups and command handlers, additionalContextLimit token threshold, async setting and synchronous SessionEnd behavior. Verified 27 Oct 2026
  3. OpenAI: Memories — Built-in local Codex memories, disabled-by-default configuration, per-chat /memories controls and keeping required guidance in AGENTS.md. Verified 27 Oct 2026