memoryrouter-codex
v1.6.1
Published
Automatic, project-scoped MemoryRouter memory for OpenAI Codex
Maintainers
Readme
MemoryRouter for OpenAI Codex
Native Codex integration for durable MemoryRouter memory. It uses Codex's current MCP, lifecycle hooks, and AGENTS.md surfaces rather than pretending that model-selected MCP calls alone are automatic memory.
Release status:
[email protected]is the published npm release. Its automatic capture is message-only: one user request plus the final assistant response, with no tool payloads.
What this integration does
| Layer | Behavior |
| --- | --- |
| UserPromptSubmit hook | Searches MemoryRouter before every prompt and injects bounded, project-scoped context as developer context. |
| Stop hook | Captures only the user request and final assistant response after each completed turn. Tool names, inputs, and results are excluded. |
| SubagentStop hook | Captures the stable final outcome of completed subagents without parsing their unstable transcript files. |
| PreCompact / compact SessionStart | Checkpoints only the current user request and final assistant response when present, then recalls context before Codex continues after compaction. |
| SessionEnd | Best-effort message-only final checkpoint within Codex's three-second SessionEnd budget. |
| Remote MCP | OAuth-based explicit search/store through https://mcp.memoryrouter.ai/mcp. |
| Local MCP fallback | API-key-authenticated stdio tools with strict project filtering, handles, local suppression, status, and full-vault clear confirmation. |
| AGENTS.md | Tells Codex when to recall/store and how MemoryRouter coexists with native Memories. |
MemoryRouter is the cross-machine, cross-tool, team-shareable, and auditable layer. Codex's native Memories remain useful as an automated local personal recall layer.
Requirements and supported surfaces
- Node.js 18 or newer.
- Codex 0.145.0 or newer for the complete lifecycle-hook integration. Version 0.146.0 was tested directly.
- Local Codex CLI, ChatGPT desktop app's local Codex host, and Codex IDE extension share
config.tomlMCP configuration. - User/project hooks require the Codex host to support and trust command hooks. Use
/hooksto review them. - Project
.codexconfig is loaded only for trusted projects. - ChatGPT web does not read a laptop's
~/.codex/config.tomlor local hooks. Use MemoryRouter's hosted plugin/connector surface there. - Codex cloud environments do not automatically inherit host-local user config or secrets. A project-scope install can travel with a repository, but the environment still needs Node, project trust, package/network availability for the stdio fallback, and
MEMORYROUTER_API_KEYfor hooks.
There is no dependency on the obsolete experimental_use_rmcp_client setting in current Codex. That flag was required by old Codex releases; it is absent from the current 0.146 configuration reference and is not written by this installer.
Install
Recommended: remote OAuth MCP plus automatic hooks
Obtain a MemoryRouter memory key from your account. Pass it on stdin so it does not appear in shell history:
printf '%s' "$MEMORYROUTER_API_KEY" | \
npx -y [email protected] init --scope user --auth oauth --api-key-stdin
codex mcp login memoryrouter
memoryrouter-codex doctor --scope userThen start Codex and inspect:
/mcp verbose
/hooksThe API key is written to ~/.memoryrouter/codex/config.json with mode 0600; the directory is 0700. It is never written to config.toml, hooks.json, AGENTS.md, or a repository.
If you prefer not to persist the key, omit --api-key-stdin and ensure MEMORYROUTER_API_KEY is in the environment of the Codex host. Without either source, remote OAuth MCP tools can work after login, but automatic hooks intentionally become no-op/fail-open.
Project scope
cd /path/to/repository
printf '%s' "$MEMORYROUTER_API_KEY" | \
npx -y [email protected] init --scope project --auth oauth --api-key-stdin
codex mcp login memoryrouterThis writes managed blocks/files under the repository's AGENTS.md and .codex/. The runtime contains no secret. Review which files your team wants to commit. Every machine or cloud environment must supply its own authentication.
Secure API-key fallback when OAuth is blocked
printf '%s' "$MEMORYROUTER_API_KEY" | \
npx -y [email protected] init --scope user --auth api-key --api-key-stdinThis uses a local stdio MCP server and the MemoryRouter API. It does not put the memory key in Codex config. The fallback tools are:
memory_searchmemory_date_searchmemory_inspectmemory_storememory_statusmemory_forget
For project scope, the stdio command is package-version-pinned through npx; secrets still come from the environment or private home config.
Exact configuration written
The remote mode adds a versioned managed block equivalent to:
[mcp_servers.memoryrouter]
url = "https://mcp.memoryrouter.ai/mcp"
auth = "oauth"
enabled = true
required = false
startup_timeout_sec = 20
tool_timeout_sec = 45
default_tools_approval_mode = "writes"
scopes = ["memories:read", "memories:write"]
[mcp_servers.memoryrouter.tools.store_memory]
approval_mode = "prompt"oauth_resource is intentionally omitted: MemoryRouter's RFC 9728 metadata already supplies the exact resource. Codex 0.146 was observed duplicating the resource authorization parameter when the same value was also pinned in config.
The installer preserves unrelated TOML byte-for-byte outside its managed block. If an unmanaged [mcp_servers.memoryrouter] table already exists, it refuses to create invalid duplicate TOML. --force creates a timestamped backup, removes only that table and its nested MemoryRouter tool tables, and installs the managed block.
Hooks are merged into hooks.json; foreign hooks remain. Re-running init upgrades/replaces only MemoryRouter-owned handlers. uninstall removes only owned handlers and managed blocks.
Project identity and scoping
The runtime computes:
proj_<first 20 hex chars of SHA-256(canonical project identity)>Identity preference:
- Canonical
origingit URL, with credentials removed and.gitnormalized. - Git common directory (so local worktrees share a project).
- Absolute path fallback.
Only the opaque handle is stored remotely. Local paths are not sent as identity metadata. A canonical remote makes identity stable across worktrees and machines.
Automatic memories use an envelope containing project handle, stable memory handle, kind, and capture time. Retrieval requests extra semantic candidates and then strictly filters to the current project handle before context injection. Legacy/unscoped vault records remain available through explicit remote MCP search but are not automatically injected in project mode.
Set retrievalScope to "vault" in the private config only if you intentionally want unscoped automatic recall.
Historical import (agent-driven)
Prior Codex conversations on this machine can be imported with a strict division of labor: the server owns the extraction prompt (versioned, fetched at import time), Codex itself owns discovery/parsing of its own session files, and this package owns transport. The agent never uploads; this CLI never parses history.
memoryrouter-codex import --instructions # print the server's extraction prompt
memoryrouter-codex import --instructions --run # or run it headless via codex exec
memoryrouter-codex import --file extract.jsonl # validate, preview, quote, approve, upload
memoryrouter-codex import --file extract.jsonl --yes # non-interactive approval
memoryrouter-codex import --dismiss # permanently silence the import nudgeGuarantees: the extract is validated locally (four fields per record, codex: prefixed ids, epoch-ms timestamps); the CLI shows record count, date range, estimated tokens, and the server price quote and requires explicit approval before any write; the import id is content-derived and every batch carries an Idempotency-Key, so re-running after any interruption replays committed batches for free and resumes. Duplicates are never re-billed. The API key never appears in the prompt or the extract file. When a vault is new, injected context includes a one-line import suggestion until an import completes or you --dismiss.
ChatGPT archive imports remain a separate flow (the memoryrouter ChatGPT CLI). Remote MCP OAuth connection by itself never imports history.
Handles, deduplication, retries, and forgetting
- Handles (
mrh_...) are content-derived from project, kind, and normalized content. - Explicit local
memory_storesearches for the exact handle before writing, so exact repeats deduplicate across machines when the earlier record is searchable. - Automatic turn capture keeps local captured-turn/handle state and does not retry writes. This avoids most duplicates. Because the current ingest API has no server-side idempotency key, a network timeout after server acceptance can still create a duplicate on a later attempt. The integration does not claim otherwise.
- Read/search/status requests retry transient errors with short exponential backoff. Writes and destructive operations are never blindly retried.
memory_forget(handle=...)suppresses that handle from this machine's Codex integration; it explicitly does not claim server deletion because the current API has no per-memory delete endpoint.- Whole-vault deletion is available only when
memory_forgetreceives the exact phraseCLEAR MY ENTIRE MEMORYROUTER VAULT. It is irreversible and should require Codex approval. - Use the MemoryRouter dashboard for server-side audit/management where available.
Reflections and consolidation
MemoryRouter's Reflection Hierarchy consolidates raw memories into higher-tier reflections. This package exposes it in two lanes:
- CLI:
memoryrouter-codex reflect [--tier 1|2] [--batches N|all] [--max-tokens N] [--dry-run]. The loop checks out a batch of unconsolidated memories under a 15 minute server lease, runs Codex itself headlessly (codex exec, you pay your own inference) with server-authored instructions, and commits the resulting reflection entries. It keeps no local state: if anything dies mid-loop, the lease expires server-side and the memories return to the pool, so re-running always resumes from the oldest unconsolidated memory.--dry-runprints the checkout and prompt and deliberately lets the lease expire (this bills one checkout). - Local stdio MCP:
memory_consolidate(checkout, returns memory texts plus the server's reflection instructions) andmemory_commit_reflections(submit entries for the batch, idempotent on replay). The model never sees memory row IDs; it works with bare texts and one opaquecb_batch id.
memory_search accepts optional tiers (subset of [1, 2, 3]: raw, reflections, high-level reflections) and importance (integer 1 to 10 minimum threshold; only reflections carry ratings). memory_date_search retrieves memories from a specific time window (from required ISO 8601, optional to, query, tiers, importance, max_tokens): use it for questions like 'what happened last week' or 'most important things this month or lately', setting importance to 7 or higher with tiers [2, 3] for importance questions, omitting query for a chronological review. memory_status reports the current reflection debt. When the server reports that consolidation is suggested, hook-injected context appends a one-line suggestion on every injection until the debt is consolidated.
Reflection prompts are always server-authored. This package never writes its own consolidation instructions and refuses to reflect if the server response carries none. See https://docs.memoryrouter.ai/reflections for endpoint semantics, lease rules, and billing.
Automatic consolidation (default on): when a hook's retrieval response reports debt above the server's threshold, the hooks spawn the same reflect loop as a detached background process (codex exec headless, your own inference). Rails: max 3 batches per trigger with a debt re-check between batches, a machine-wide lockfile at ~/.memoryrouter/consolidate.lock (stale after 20 minutes), a 30 minute cooldown after each completed run, and silent failure with logs at ~/.memoryrouter/consolidate.log. The threshold always comes from the server response. Opt out with "autoConsolidate": false in ~/.memoryrouter/codex/config.json; the suggestion line, stdio tools, and manual reflect keep working.
Context budget and failure behavior
- Default injected context cap: 12,000 characters, assembled at memory boundaries.
- Hook
additionalContextLimit: approximately 3,500 tokens, so Codex can spill unexpectedly large context safely instead of consuming the whole model window. - Candidate search default: 12 before strict project filtering.
- All hook entrypoints exit zero on missing credentials, malformed input, API errors, and timeouts. Memory never blocks Codex work.
- Hook status is recorded without secrets in
~/.memoryrouter/codex/health.json. Search/store/forget outcomes (metadata only, never memory content or keys) append to a rotating 5 MiB local~/.memoryrouter/codex/audit.jsonl.memory_statusexposes both locations. This is a host-local integration audit, not a server-wide team access log. Session state and any legacy pre-1.1 trace files older than 30 days are pruned at session start. Version 1.1 creates no tool trace files. - Set
MEMORYROUTER_DEBUG=1for hook errors on stderr. Debug is off by default.
Codex native Memories coexistence
This installer does not overwrite native-memory settings. Native Memories are off by default and can be enabled independently:
[features]
memories = true
[memories]
disable_on_external_context = truedisable_on_external_context = true keeps chats that used MCP/web/tool-search context out of Codex's background memory generation, avoiding a second divergent extraction of MemoryRouter-assisted work. This also means those chats will not contribute to native Memories. Leave it false if you intentionally want both systems to learn from the same chat.
Use /memories for per-chat native-memory controls. Keep required team rules in AGENTS.md, not in either memory system.
OAuth findings (tested 2026-07-31)
Live verification with official @openai/codex 0.146.0 established:
codex mcp add --url https://mcp.memoryrouter.ai/mcp memoryrouterwrites the expected streamable HTTP entry.- Codex discovers RFC 9728 protected-resource metadata.
- Codex discovers
https://auth.memoryrouter.aiauthorization metadata. - Dynamic client registration succeeds and issues a
dcr_...client ID. - Codex generates an authorization URL with PKCE S256,
memories:read memories:write, the exact RFC 8707 resource, and a loopback callback. - The browser consent/token step was deliberately not completed by the package test because it is account-specific. Therefore
doctorverifies discovery compatibility but never reports an OAuth session as logged in without user consent. Usecodex mcp login memoryrouterand/mcp verboseto complete/verify it.
The production server supports modern stateless MCP 2026-07-28 and still accepts 2025-11-25, 2025-06-18, and 2025-03-26 for handshake-era clients. Codex 0.146 initializes the compatibility path successfully. Do not infer Codex support from protocol negotiation alone; verify OAuth login, /mcp verbose, and the actual tool inventory.
Doctor
memoryrouter-codex doctor --scope user
memoryrouter-codex doctor --scope project --project-dir /repo
memoryrouter-codex doctor --offlineDoctor checks Codex version, managed config, runtime version, hook count, AGENTS.md, private-key availability/validity, OAuth discovery, native-memory coexistence, project identity portability, and local/cloud surface limitations.
Upgrade and uninstall
Upgrade idempotently by re-running the pinned/new package:
npx -y [email protected] init --scope userUninstall:
npx -y [email protected] uninstall --scope user
# or
npx -y [email protected] uninstall --scope project --project-dir /repoUninstall deliberately retains ~/.memoryrouter/codex/ because another project installation may use the credentials and local suppression state. Delete that private directory manually only when no integration uses it.
Honest limitations
- Hooks are the deterministic automatic path. Remote MCP alone remains model-invoked, not guaranteed every turn.
- The transcript file path supplied to hooks is documented as unstable, so this integration does not parse Codex transcript JSONL. Version 1.1 captures only the stable user prompt and
last_assistant_message. - Tool-call records are intentionally excluded. MemoryRouter does not store tool names, tool IDs, tool inputs, tool results, commands, patches, or other
PostToolUsepayloads from automatic Codex capture. Important outcomes must appear in the final assistant response to be retained. - Some specialized tool paths can opt out of hooks. Codex documents hooks as a useful extension surface, not a complete enforcement boundary.
- SessionEnd can happen after a 30-minute idle period and has a three-second maximum. It is a best-effort checkpoint; normal
Stopcapture is the primary write path. - Project scoping is strict for this package's automatic retrieval/local MCP. The existing hosted remote MCP server has no first-class project argument, so use local tools/hooks when cross-project isolation is required.
- Per-memory server deletion is not available through the current API. Local suppression and explicit full-vault clear are accurately labeled.
- API-level idempotency is not yet available; timeout-after-acceptance duplicates remain possible.
Development
cd integrations/codex
npm test
npm run typecheck
npm run pack:dryNo package, config, fixture, or runtime file contains a production secret.
