This page covers advanced plugin behavior, environment variables, and stream reliability controls.
- Start OpenCode inside this repo (or make the plugin global so it globs in everywhere).
- Every tooling session creates memory artifacts in SQLite.
- Prompt-time memory injection appends volatile recall output to the latest user message by default, preserving the stable system/history prefix for provider prompt caches.
- Use
codemem statsandcodemem recentto confirm ingestion. - Browse the viewer at the printed URL.
OpenCode prompt-time pack construction and prompt-pack ledger transitions use the
long-lived local viewer first. Retryable connection, timeout, endpoint-version,
server, or malformed-response failures fall back to the compatible CLI path.
Validated request errors are terminal only after a compatible profile handshake;
before compatibility is established, a structured request error may indicate a
foreign or older process and uses the CLI fallback. Policy and authorization errors
remain terminal. A viewer_contract_unsupported response is likewise terminal after
a compatible profile handshake and may fall back before one. The HTTP timeout uses
CODEMEM_INJECT_HTTP_MAX_TIME_S (default: 2 seconds).
Pack and ledger requests include their resolved default or explicit database,
identity/config, compression, and embedding targets. The viewer also rejects a cached store
identity that no longer matches current database/config resolution. A mismatch
uses the local CLI fallback exactly once instead of reading or retrying another
local profile. A payload-free profile handshake runs before each POST and returns
protocol_version plus min_supported_protocol_version; clients accept
overlapping ranges and interpret an older profile without the minimum as a
single-version range. Fetch redirects are disabled so prompt-derived request
bodies are not replayed to another endpoint.
A 30-run synthetic-fixture benchmark measured the OpenCode plugin path only; it does not measure Claude or Codex latency. The privacy-safe report contains no prompt, memory content, IDs, or paths.
| Mode | Median / p95 | Prompt children |
|---|---|---|
| Direct CLI | 857.459 / 1001.124 ms | — |
| Healthy Viewer | 9.478 / 10.772 ms | pack=0, ledger=0, other=0, failed=0 |
| Classified Viewer-unavailable fallback | 832.101 / 881.455 ms | pack=30, ledger=30, other=0, failed=0 |
CodeMem's Claude integration is hook-first and distributed through a Claude plugin marketplace source in this repo (.claude-plugin/marketplace.json).
In Claude Code, add the marketplace and install the plugin:
/plugin marketplace add kunickiaj/codemem
/plugin install codemem
The plugin starts MCP with the TS CLI:
codemem mcp
Claude's Node/ESM wrapper normalizes each native hook once, then sends the exact normalized envelope to the local server's canonical POST /api/raw-events endpoint. Healthy HTTP ingestion starts no codemem or npx child. On a retryable failure, the wrapper sends the same serialized envelope to:
codemem enqueue-raw-eventnpx -y codemem@<plugin version> enqueue-raw-event
The wrapper never remaps the native payload during fallback, so event identity is identical across HTTP and direct enqueue. Named POST /api/claude-hooks remains a compatibility alias/caller for older packaged and plugin-free CLI paths.
Transcript fallback scans backward through at most the final 16 MiB using a bounded reusable chunk buffer and stops at the latest qualifying assistant record. When that tail starts immediately after a newline, the first complete record is retained; when it starts in the middle of a record, the partial first record is discarded. JSONL records may use LF or CRLF, and UTF-8 characters remain valid across chunk boundaries.
Claude preserves its existing best-effort failure posture: if Viewer HTTP and both command fallbacks fail, the wrapper logs the failure and exits non-zero. It does not maintain a file spool; Codex's separately documented normalized-envelope spool is intentionally adapter-specific.
You can update an existing marketplace install with:
/plugin marketplace update codemem-marketplace
Ingest one Claude hook payload through the installed wrapper:
printf '%s\n' '{"hook_event_name":"SessionStart","session_id":"sess-1"}' | node plugins/claude/scripts/ingest-hook.mjsPrompt-time retrieval runs through the packaged dependency-free Node hook. It validates the
Viewer protocol, database, and runtime identity before sending identity-gated POST /api/pack.
Claude prompt retrieval and event ingestion accept only explicit loopback Viewer hosts
(localhost, 127.0.0.0/8, or IPv6 loopback); non-loopback hosts are never fetched.
By default, SessionEnd requests a best-effort boundary flush after enqueue rather than waiting for sweeper timing. Set CODEMEM_CLAUDE_HOOK_FLUSH=0 to force enqueue-only behavior, and set CODEMEM_CLAUDE_HOOK_FLUSH_ON_STOP=1 to include Stop boundary flush. Direct Viewer transport keeps the boundary request, durable HTTP retry, and command fallbacks inside one Claude Code host budget (1.5 seconds by default, configurable with CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS), preserves command-fallback time after preprocessing and across both HTTP attempts, and reserves a 50 ms exit margin. The fallback reserve is normally 10% of the host budget, clamped between 500 ms and 5 seconds, but never exceeds half of the post-margin budget. Stop uses one 125-second internal budget under a 130-second packaged hook timeout, leaving startup and shutdown headroom. Override the boundary budget with CODEMEM_CLAUDE_HOOK_BOUNDARY_TIMEOUT_MS; SessionEnd still clamps its request to the live remaining host budget.
The packaged template currently registers these hook events in plugins/claude/hooks/hooks.json:
SessionStartUserPromptSubmitPostToolUsePostToolUseFailureStopSessionEnd
UserPromptSubmit runs scripts/user-prompt-hook.mjs, which:
- sends the hook payload into capture ingest (
ingest-hook.mjs) in the background, and - performs a payload-free compatible-profile check, retrieves an identity-gated Viewer pack, returns host-compatible
hookSpecificOutput.additionalContext, then records delivery best-effort with a 500 ms cap.
Healthy prompt-time Claude injection starts no codemem or npx prompt child. Retryable
transport, version/profile, and local database/runtime identity mismatches start one compatibility chain:
codemem claude-hook-inject, then the plugin-version-pinned npx equivalent if needed. Valid
request failures after a compatible handshake, policy, authorization, and compatible-profile contract
failures do not fall back. Pre-handshake structured request failures use the compatibility chain. Non-loopback
Viewer hosts and redirects are rejected. Ledger failure never retries inline or changes already-written
hook output.
For Claude hooks, project resolution precedence is:
CODEMEM_PROJECT(if set)- repo/cwd-derived project name (
resolve_project(cwd)) - payload
projectfallback (only when cwd is unavailable)
PreToolUse is intentionally deferred in the default template. Current memory extraction uses PostToolUse / PostToolUseFailure (tool_result) as the shipped Claude tool signal.
Codex support is early beta — functional and dogfooded end-to-end, but not yet promoted to a stable support tier. The Codex plugin uses the same shared raw-event pipeline as Claude and OpenCode. It is packaged under plugins/codex/ with .codex-plugin/plugin.json, bundled .mcp.json, and hook scripts under plugins/codex/scripts/.
Codex's Node/ESM wrapper adds a timestamp and nonce when the host omitted a timestamp, normalizes exactly once, and sends the exact envelope to POST /api/raw-events. Healthy HTTP ingestion starts no codemem or npx child. After a retryable HTTP failure, it durably spools the normalized envelope before starting this fallback chain:
codemem enqueue-raw-event, then the pinnednpxequivalent.- A successful fallback removes the envelope from
~/.codemem/codex-raw-event-spool; if both fail, it remains there for a later HTTP drain. This is separate from the legacy native-hook spool.
The same serialized envelope—and therefore the same event ID—is used by every transport. Named POST /api/codex-hooks remains a compatibility alias/caller for older packaged and plugin-free CLI paths.
printf '%s\n' '{"hook_event_name":"SessionStart","session_id":"codex-1"}' | node plugins/codex/scripts/ingest-hook.mjsUserPromptSubmit runs scripts/user-prompt-hook.mjs, which:
- sends the hook payload into capture ingest (
ingest-hook.mjs) in the background, and - performs a payload-free compatible-profile check, retrieves an identity-gated Viewer pack, and returns
framed
hookSpecificOutput.additionalContext; delivery recording is best-effort and capped at 500 ms.
The packaged Codex hook is a dependency-free direct Viewer client. Healthy prompt retrieval starts no
codemem or npx child. Retryable Viewer transport, version/profile, and local database/runtime
identity mismatches and pre-handshake structured request failures use one local compatibility chain;
validated request failures after compatibility is established, policy, authorization, and
compatible-profile contract failures fail closed. Prompt and event HTTP reject non-loopback Viewer hosts.
The injected pack is framed as codemem reference data, not instructions. The hook has a total 4.5-second
prompt-output budget within Codex's 5-second host timeout, and always emits {"continue": true} so a
hook failure does not block a session.
printf '%s\n' '{"hook_event_name":"UserPromptSubmit","session_id":"codex-1","prompt":"what did we change","cwd":"/tmp/demo"}' | codemem codex-hook-injectcodemem codex-hook-inject is retained for compatibility and plugin-free setup. It now uses the same
profile-validated, identity-gated Viewer HTTP retrieval before falling back to its local database pack.
Like the packaged hook, it rejects non-loopback prompt retrieval and fails closed on policy,
authorization, and compatible-profile contract errors; local packing is limited to classified
compatibility failures. The packaged hook remains the zero-child healthy path.
For Codex hooks, project resolution precedence matches the Claude hook path:
CODEMEM_PROJECT(if set)- repo/cwd-derived project name
- payload
projectfallback (only when cwd is unavailable)
Stop events map the inline last_assistant_message when present, and fall back to the last assistant message in transcript_path so final responses are captured even when the inline field is omitted. This fallback uses the same backward, bounded 16 MiB JSONL scan and record-boundary rules as Claude.
The packaged Codex template registers SessionStart, UserPromptSubmit, PostToolUse, and Stop in plugins/codex/hooks/hooks.json. Codex support is early beta; see docs/plans/2026-05-28-codex-first-class-integration.md for the rollout plan and validation gates.
Install through Codex's own plugin marketplace — there is no codemem setup step:
codex plugin marketplace add https://github.com/kunickiaj/codemem.git
codex plugin add codemem@codemem
# refresh the marketplace snapshot later:
codex plugin marketplace upgrade
# remove:
codex plugin remove codemem@codememThe plugin bundles .mcp.json (npx -y codemem mcp), hooks/hooks.json, and a dependency-free generated normalizer. Ingest wrappers use Viewer HTTP without child processes when healthy; codemem and pinned npx are fallback-only. Generated files come from the TypeScript normalizers in packages/core/src/ via node scripts/build-adapter-normalizers.mjs and are protected by a byte-drift test. Validated targets: Codex CLI 0.135+ and current Desktop builds.
API-key / non-subscription Codex Desktop greys out plugin installation. For that case, configure Codex directly — no marketplace, no plugin:
npx -y codemem setup --codex-only # or, with a global install: codemem setup --codex-onlyWhat it does (idempotent; honors CODEX_HOME; backs up existing files; --force to refresh):
- MCP: appends
[mcp_servers.codemem](command = "npx",args = ["-y", "codemem", "mcp"]) to<CODEX_HOME>/config.tomlif not already present. The file is never reparsed or reformatted — only appended — so comments and unrelated servers (including secrets) are preserved. - Hooks: merges
SessionStart,UserPromptSubmit(ingest + inject),PostToolUse, andStopinto<CODEX_HOME>/hooks.json, preserving any unrelated user hooks. Hook commands resolve to a directcodemem codex-hook-*call whencodememis onPATH, otherwisenpx -y codemem codex-hook-*. Prompt injection validates the loopback Viewer profile and retrieves withPOST /api/packfirst, using the local database only for classified compatibility fallback.
Hooks loaded from the user config layer require a one-time trust approval in Codex (you'll be prompted on first run; MCP recall needs no trust). Codex setup also runs automatically in a plain codemem setup when a Codex home (~/.codex or $CODEX_HOME) is detected.
- No memories and no raw events captured. Confirm the
codememthe hooks resolve actually has the Codex commands:codemem codex-hook-ingest </dev/nullshould print a structured{"error":"read_error",...}, notunknown command. The Codex commands are first published in codemem 0.35.0; the0.34.0release on npm predates them, so an older global install (or thenpx -y codemem@<plugin version>fallback while the plugin manifest still pins a pre-0.35 version) silently fails and spools. Inspect normalized wrapper envelopes at~/.codemem/codex-raw-event-spool/, legacy native-hook payloads at~/.codemem/codex-hook-spool/, and the plugin log at~/.codemem/plugin.log. database lockedin the plugin log / payloads spooling. The direct-queue fallback lost the writer lock (the viewer or maintenance worker held it). Keep the viewer running and current so canonicalPOST /api/raw-eventsavoids cross-process lock contention.POST /api/raw-eventsreturns 404. The running viewer predates normalized edge ingress; restart or upgrade it. Older plugin packages may continue using the named compatibility route.- Normalized spool backlog drains automatically at one envelope per successful ingest. The wrapper never reads or removes files from the legacy native-hook spool.
- A model rejects injected context (for example "the conversation must end with a user message"): disable prompt-time injection with
CODEMEM_INJECT_CONTEXT=0. Capture/ingest keeps working and recall is still available through the MCP tools.
After restarting OpenCode or the viewer, run this quick check when behavior looks off:
- Confirm plugin + viewer are talking to the same DB path.
- Check backend stats and recent writes (
codemem stats,codemem recent). - Verify runner mode and source (
CODEMEM_RUNNER,CODEMEM_RUNNER_FROM) match your install strategy. - Confirm injection controls are what you expect (
CODEMEM_INJECT_CONTEXT,CODEMEM_INJECT_LIMIT,CODEMEM_INJECT_TOKEN_BUDGET). - If stream mode is enabled, check backlog health (
codemem db raw-events-status).
If needed, restart viewer + plugin flow:
codemem serve restartIf you override the viewer bind, keep the plugin and viewer aligned on the same target:
set -lx CODEMEM_VIEWER_HOST 127.0.0.1
set -lx CODEMEM_VIEWER_PORT 38892The plugin now passes that explicit host/port through when it auto-starts, health-checks, stops, or restarts the viewer. Its liveness monitor requires a successful GET /api/health JSON response identifying service: "codemem-viewer"; ready: false still means the viewer process is live. For compatibility, only a 404 from the health route triggers one bounded probe of the legacy raw-event status endpoint. Raw-event ingest availability keeps its separate preflight behavior, now bounded by a 5-second timeout so a hung viewer socket cannot stall event delivery. Do not run multiple viewers against the same DB/runtime folder unless they intentionally share the same bind target; otherwise viewer.pid ownership becomes ambiguous.
If compatibility toasts appear after restart, follow the runner-specific guidance in Compatibility guidance behavior below.
mem-status- show viewer URL, log path, stats, and recent entries.mem-stats- show just the stats block.mem-recent- show recent items (defaults to 5).
These are plugin tools callable by the agent/runtime. They are not user-facing slash commands in the OpenCode chat input.
The MCP server exposes memory retrieval and write tools such as memory_search,
memory_pack, memory_recent, memory_remember, and memory_forget.
memory_distill_candidates mines recurring lessons into reviewable context
candidates. It is read-only and does not modify documentation files. By
default an observer-model worthiness pass drops routine-activity clusters
(release/CI status, review passes with no findings, context lookups) before
the candidates are returned; pass judge: false to skip it. When no observer
model is configured the tool returns unjudged output with judged: false and
a judge_error in the metadata.
Example agent requests:
- "Find recurring project lessons worth adding to AGENTS.md."
- "Run distill for all projects and show top candidates."
- "Distill without judging so I can see the raw recurrence ranking."
- OpenAI:
gpt-5.1-codex-mini - Anthropic:
claude-4.5-haiku(mapped to Anthropic direct API aliasclaude-haiku-4-5when usingapi_http)
Provider/model selection can be overridden with CODEMEM_OBSERVER_PROVIDER and
CODEMEM_OBSERVER_MODEL. Custom providers are loaded from OpenCode config.
Observer execution supports API, Claude, and Codex runtime paths.
- Runtime values:
api_http,claude_sidecar,codex_sidecar. claude_sidecarruns observer calls via local Claude runtime auth (noANTHROPIC_API_KEYrequired).claude_sidecarusesclaude_command(orCODEMEM_CLAUDE_COMMAND) as argv prefix for launching Claude CLI. Default:["claude"].codex_sidecarruns observer calls via the localcodexCLI (codex exec), so Codex / ChatGPT Pro users get memory extraction with no API key — auth is delegated to the Codex CLI (~/.codex). It usescodex_command(orCODEMEM_CODEX_COMMAND) as the argv prefix. Default:["codex"]. The spawned process runs with--ephemeral --ignore-user-config -s read-onlyand codemem's own hooks suppressed, so it never recurses into capture.- codemem auto-selects
codex_sidecaronly when noobserver_runtimeis set, no API key is available from any provider, the OpenCode OAuth cache has no usable credentials, thecodexCLI is resolvable, and~/.codex/auth.jsonexists. Otherwise setobserver_runtime = "codex_sidecar"(orCODEMEM_OBSERVER_RUNTIME=codex_sidecar) explicitly. - Default models:
api_http:gpt-5.1-codex-miniunlessobserver_modelis set.claude_sidecar:claude-4.5-haikuunlessobserver_modelis set.codex_sidecar:gpt-5.1-codex-miniunlessobserver_modelis set; the selected model is passed tocodex execvia-m(tier routing).- Anthropic direct API calls accept Anthropic model IDs/aliases; use
claude-haiku-4-5-20251001if you need a pinned snapshot instead of the moving alias. - If
observer_modelis unsupported in Claude CLI, codemem retries once without--model. The same fallback applies tocodex_sidecar: an unavailable tier model is retried once without-m. - Supported auth sources:
auto,env,file,command,none. - Supported: API keys and gateway tokens codemem can read directly.
- Custom provider path does not implicitly fall back to OpenCode/IAP env tokens; use provider key,
CODEMEM_OBSERVER_API_KEY,file, orcommand. - For codemem-native custom providers, set
observer_base_url(orCODEMEM_OBSERVER_BASE_URL) to avoid relying on OpenCode provider config.
For command-refreshed gateway auth, configure a command token source plus templated headers:
{
"observer_provider": "your-gateway-provider",
"observer_base_url": "https://gateway.example/v1",
"observer_runtime": "api_http",
"observer_auth_source": "command",
"observer_auth_command": ["iap-auth", "--audience", "example"],
"observer_auth_timeout_ms": 1500,
"observer_auth_cache_ttl_s": 300,
"observer_headers": {
"Authorization": "Bearer ${auth.token}"
}
}observer_auth_command is direct argv execution (no shell interpolation).
- Config key type: JSON string array (
["cmd", "arg1", "arg2"]). - Env var
CODEMEM_OBSERVER_AUTH_COMMANDmust also be a JSON string array (for example'["iap-auth","--audience","example"]'), not a space-separated command string.
Header template variables:
${auth.token}${auth.type}${auth.source}
Command/file token cache behavior:
- Successful token resolutions are cached for
observer_auth_cache_ttl_s. - Failed token resolutions are not cached.
Stream contract:
- Preflight availability:
GET /api/raw-events/status - Event streaming:
POST /api/raw-events - Non-2xx and network failures are treated as stream failures.
- Raw events are delivered through the viewer ingest API.
- Raw-event batches accepted by the viewer are retried by the sweeper flush workers.
- If the direct CLI fallback reports an explicit SQLite busy/locked result or command timeout, the plugin retries it once with the same event ID. Other failures are reported and dropped rather than requeued or spooled, and logs retain only a bounded failure category rather than raw command output.
GET /api/raw-events/status also includes transcript_diagnostics, a per-Viewer-process, per-router-instance counter block scoped explicitly to legacy_compatibility_routes. It counts Claude and Codex compatibility-route transcript reads by the fixed outcomes ok, not_provided, path_rejected, unreadable, no_complete_record, and no_assistant_record. These counters are not persisted, do not include paths or transcript content, and do not describe the normal generated-adapter path through POST /api/raw-events. A skipped legacy Stop response keeps skip_reason: "transcript_unavailable" and may include one of the non-ok outcomes as skip_detail; other mapping skips remain skip_reason: "unsupported_hook".
Suggested settings:
export CODEMEM_RAW_EVENTS_AUTO_FLUSH=1
export CODEMEM_RAW_EVENTS_DEBOUNCE_MS=60000
export CODEMEM_RAW_EVENTS_SWEEPER=1
export CODEMEM_RAW_EVENTS_SWEEPER_IDLE_MS=120000
export CODEMEM_RAW_EVENTS_SWEEPER_LIMIT=25
export CODEMEM_RAW_EVENTS_STUCK_BATCH_MS=300000
# optional retention
# export CODEMEM_RAW_EVENTS_RETENTION_MS=$((7*24*60*60*1000))To monitor backlog:
codemem db raw-events-statusIf raw-events-status shows batches=error:N (legacy label) or queue=... failed:N for a stream, retry:
codemem db raw-events-retry <session_stream_id>The plugin uses OpenCode event hooks and flushes on explicit lifecycle boundaries:
tool.execute.after: queue tool event; contributes to force-flush thresholds.session.idle: immediate flush attempt.session.created: flush previous session buffer before switching context./newprompt boundary: flush before session reset.session.error: immediate flush attempt.
Force-flush thresholds (immediate flush):
>=50tool events, or>=15prompts, or>=10minutes session duration.
Failure semantics:
- Stream POST failures are backoff-gated in plugin runtime (
CODEMEM_RAW_EVENTS_BACKOFF_MS). - Availability checks are rate-limited (
CODEMEM_RAW_EVENTS_STATUS_CHECK_MS). - Accepted raw-event batches are retried by viewer/store queue workers (
codemem db raw-events-retry).
When ingesting plugin payloads, CodeMem stores a normalized project label instead of a full path.
- Path-like labels are reduced to the basename (for example,
/Users/adam/workspace/codemem->codemem). - Windows-style paths are normalized with Windows path rules on every OS runtime.
C:\Users\adam\workspace\codemem->codememD:/dev/client-demo->client-demo\\server\share\team\project-x->project-x
CODEMEM_PROJECTstill has highest precedence and is normalized the same way.
If you run multiple adapters for the same project (for example OpenCode + Claude), set a shared CODEMEM_PROJECT value in both runtimes to guarantee unified project grouping in memory retrieval.
| Env var | Description |
|---|---|
CODEMEM_RUNNER |
Override auto-detected runner: codemem (global), npx, node (repo/dev), or custom binary name. |
CODEMEM_RUNNER_FROM |
Runner source override: npm package spec for npx (for example codemem@0.20.0-alpha.7), or repo/CLI entry path for node. |
CODEMEM_VIEWER |
Set to 0, false, or off to disable the viewer entirely. |
CODEMEM_VIEWER_HOST, CODEMEM_VIEWER_PORT |
Explicit host/port the plugin-managed viewer should start, probe, stop, and restart. Prompt retrieval accepts loopback hosts only. |
CODEMEM_VIEWER_AUTO |
Set to 0/false/off to disable auto-start (default on). |
CODEMEM_VIEWER_AUTO_STOP |
Set to 0/false/off to keep the viewer running after OpenCode exits (default on). |
CODEMEM_PLUGIN_LOG |
Path for the plugin log file (set 1/true/yes for ~/.codemem/plugin.log; Claude hook failures are logged to this path by default). |
CODEMEM_PLUGIN_LOG_PATH |
Explicit log file path for Claude hook script logging (overrides CODEMEM_PLUGIN_LOG for that script). |
CODEMEM_CLAUDE_HOOK_HTTP_CONNECT_TIMEOUT_S |
Claude hook HTTP enqueue connect timeout in seconds (default 1). |
CODEMEM_CLAUDE_HOOK_HTTP_MAX_TIME_S |
Claude hook HTTP enqueue total timeout in seconds (default 2). |
CODEMEM_CODEX_HOOK_HTTP_TIMEOUT_MS |
Codex hook HTTP enqueue timeout in milliseconds (default 1000). |
CODEMEM_CODEX_HOOK_LOCK_DIR |
Codex hook fallback lock path (default ~/.codemem/codex-hook-ingest.lock). |
CODEMEM_CODEX_HOOK_LOCK_TTL_S |
Seconds before a Codex hook fallback lock is treated as stale (default 120). |
CODEMEM_CODEX_HOOK_SPOOL_DIR |
Legacy native Codex hook fallback spool directory (default ~/.codemem/codex-hook-spool); the normalized wrapper does not read or drain it. |
CODEMEM_CODEX_RAW_EVENT_SPOOL_DIR |
Normalized Codex raw-event envelope spool directory (default ~/.codemem/codex-raw-event-spool). |
CODEMEM_CODEX_LOCAL_PACK_ONLY |
Internal coordination flag set by the packaged Codex wrapper when it invokes the CLI compatibility fallback; skips duplicate Viewer retrieval. Not intended for manual use. |
CODEMEM_INJECT_HTTP_MAX_TIME_S |
Viewer request timeout for OpenCode and Claude prompt retrieval, the per-request cap for packaged Codex, and the total profile-plus-pack HTTP budget for plugin-free Codex (default and maximum 2 seconds for plugin-free Codex). Claude and Codex ledger completion has a separate fixed 500 ms cap; packaged Codex also enforces a total 4.5-second output budget. |
CODEMEM_INJECT_MAX_CHARS |
Max chars returned as Claude/Codex additionalContext (default 16000). |
CODEMEM_PLUGIN_CMD_TIMEOUT |
Milliseconds before a plugin CLI call is aborted (default 20000). |
CODEMEM_MIN_VERSION |
Minimum required CLI version for plugin compatibility warnings (default 0.9.20). |
CODEMEM_BACKEND_UPDATE_POLICY |
Compatibility and release-notification policy: notify (default), auto, or off. |
CODEMEM_INSTALL_KIND |
Internal/advanced release-guidance detection override (npm-global, npx, docker, repo-dev, pinned, or unknown). This does not enable installation. |
CODEMEM_CODEX_ENDPOINT |
Override Codex OAuth endpoint. |
CODEMEM_PLUGIN_DEBUG |
Set to 1, true, or yes to log plugin lifecycle events. |
CODEMEM_PLUGIN_IGNORE |
Skip all plugin behavior for this process. |
CODEMEM_INJECT_CONTEXT |
Set to 0 to disable memory pack injection (default on). |
CODEMEM_INJECT_SURFACE |
OpenCode injection surface: message by default; set system for the legacy system-prompt transform. |
CODEMEM_INJECT_LIMIT |
Max memory items in injected pack (default 8). |
CODEMEM_INJECT_TOKEN_BUDGET |
Approx token budget for injected pack (default 800). |
CODEMEM_USE_OPENCODE_RUN |
Use opencode run for observer generation (default off). |
CODEMEM_OPENCODE_MODEL |
Model for opencode run (default gpt-5.1-codex-mini). |
CODEMEM_OPENCODE_AGENT |
Agent for opencode run (optional). |
CODEMEM_OBSERVER_PROVIDER |
Force openai, anthropic, or a custom provider key (optional). |
CODEMEM_OBSERVER_MODEL |
Override observer model (default gpt-5.1-codex-mini or claude-4.5-haiku). |
CODEMEM_OBSERVER_API_KEY |
API key for observer model (optional). |
CODEMEM_CLAUDE_COMMAND |
JSON argv array for Claude CLI invocation used by claude_sidecar (default ["claude"]). |
CODEMEM_OBSERVER_RUNTIME |
Observer runtime mode (api_http or claude_sidecar). |
CODEMEM_OBSERVER_AUTH_SOURCE |
Observer auth source (auto, env, file, command, none). |
CODEMEM_OBSERVER_AUTH_FILE |
Path to token file used when auth source is file. |
CODEMEM_OBSERVER_AUTH_COMMAND |
Command argv as a JSON string array used when auth source is command. |
CODEMEM_OBSERVER_AUTH_TIMEOUT_MS |
Command auth timeout in milliseconds (default 1500). |
CODEMEM_OBSERVER_AUTH_CACHE_TTL_S |
Cache TTL for command/file auth resolution in seconds (default 300). |
CODEMEM_OBSERVER_HEADERS |
JSON object of templated observer headers, e.g. {"Authorization":"Bearer ${auth.token}"}. |
CODEMEM_OBSERVER_MAX_CHARS |
Max observer prompt characters (default 12000). |
CODEMEM_RAW_EVENTS_BACKOFF_MS |
Backoff window after stream failure before retrying stream POSTs (default 10000). |
CODEMEM_RAW_EVENTS_STATUS_CHECK_MS |
Minimum interval between stream availability preflight checks (default 30000). |
CODEMEM_RAW_EVENTS_HARD_MAX |
Hard upper bound for in-memory plugin queue under sustained failure pressure (default 2000). |
CODEMEM_RAW_EVENTS_AUTO_FLUSH |
Set to 1 to enable viewer-side debounced flush of streamed raw events (default off). |
CODEMEM_RAW_EVENTS_DEBOUNCE_MS |
Debounce delay before auto-flush per session (default 60000). |
CODEMEM_RAW_EVENTS_SWEEPER |
Set to 1 to enable periodic sweeper flush for idle sessions (default on). |
CODEMEM_RAW_EVENTS_SWEEPER_INTERVAL_MS |
Sweeper tick interval (default 30000). |
CODEMEM_RAW_EVENTS_SWEEPER_INTERVAL_S |
Config/env interval in seconds used by Settings UI (default 30; overridden by CODEMEM_RAW_EVENTS_SWEEPER_INTERVAL_MS when set). |
CODEMEM_RAW_EVENTS_SWEEPER_IDLE_MS |
Consider session idle if no events since this many ms (default 120000). |
CODEMEM_RAW_EVENTS_SWEEPER_LIMIT |
Max idle sessions to flush per sweeper tick (default 25). |
CODEMEM_RAW_EVENTS_STUCK_BATCH_MS |
Mark flush batches older than this many ms as error (default 300000). |
CODEMEM_RAW_EVENTS_RETENTION_MS |
If >0, delete raw events older than this many ms (default 0, keep forever). |
CODEMEM_CLAUDE_HOOK_FLUSH |
Set to 0 to disable immediate SessionEnd boundary flush (default on for SessionEnd; Stop still requires CODEMEM_CLAUDE_HOOK_FLUSH_ON_STOP=1). |
CODEMEM_CLAUDE_HOOK_FLUSH_ON_STOP |
Set to 1 to flush on Claude Stop hooks in addition to SessionEnd (default off). |
CODEMEM_CLAUDE_HOOK_BOUNDARY_TIMEOUT_MS |
Override the direct Viewer request wait for SessionEnd, clamped inside CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS. For opt-in Stop flushing, this sets the whole boundary budget; the first request reserves fallback time within it (default total: 125000 ms). |
When the plugin detects CLI/runtime version mismatch, it shows guidance based on runner mode:
CODEMEM_RUNNER=codemem: runnpm install -g codemem, then restart OpenCodeCODEMEM_RUNNER=npx: updateCODEMEM_RUNNER_FROMto a newer package/version (or reinstall plugin), then restart OpenCodeCODEMEM_RUNNER=node: pull latest repo changes and runpnpm build, then restart OpenCode- custom/unknown runner: update the underlying
codemembinary or package source, then restart OpenCode
Update policy:
CODEMEM_BACKEND_UPDATE_POLICY=notify(default): show warning toast with suggested actionCODEMEM_BACKEND_UPDATE_POLICY=auto: try a best-effort auto-update for eligible compatibility-floor mismatches and fresh stable releases observed for at least 24 hours, then warn if still outdated- skipped for
nodedev-mode runners - skipped when
CODEMEM_RUNNER_FROMis pinned to a fixed package/version - skipped for Docker, unknown, stale, prerelease, or downgrade states
- skipped for
CODEMEM_BACKEND_UPDATE_POLICY=off: no compatibility toast (logging still records mismatch)
After its startup delay, the plugin also runs codemem update check --json through the same
argv-based CLI runner. notify and auto show a best-effort toast at most once per latest stable
release in the current OpenCode process; off skips this release check. Under explicit auto, an
eligible result invokes the fail-closed codemem update install command and verifies the active CLI
version before a plugin-owned Viewer is restarted. Current, unavailable, malformed, ineligible, and
timed-out results are ignored or shown as guidance without delaying plugin startup.
The installer uses a process-owned lock under ~/.codemem so simultaneous OpenCode sessions cannot
run competing global npm installations. A live lock causes later attempts to fail closed; a lock whose
recorded process no longer exists is reclaimed.
Docker images set CODEMEM_INSTALL_KIND=docker so release guidance cannot mistake the bundled
global npm package for a host npm installation. Docker deployments never self-update; rebuild and
restart the image with the desired CODEMEM_VERSION instead.
Compatibility checks do not block plugin startup.
