codemem serveruns the viewer in the foreground.codemem serve startruns it in the background.codemem serve restartrestarts the background viewer.codemem serve --backgroundstill works as a deprecated alias forcodemem serve start.
- The viewer and its JSON APIs are designed for localhost-only use.
- codemem currently relies on loopback-origin checks and local-process assumptions, not a real login/session auth layer.
- Binding the viewer to
0.0.0.0, putting it behind a reverse proxy, or exposing it through a tunnel can make local APIs reachable in ways the current trust model was not built for. - Treat the viewer as a local tool. If you must expose it beyond loopback, add your own auth and network restrictions first.
- This warning applies to the viewer HTTP service, not the separate sync/coordinator listeners documented elsewhere.
- The viewer UI is built from
packages/ui/and served bypackages/viewer-server/. - Rebuild UI assets after frontend changes:
pnpm --filter @codemem/ui build. - Restart the viewer after updates:
codemem serve restart.
- Open via the Settings button in the header.
- Shows effective values (configured or default) to avoid blank/ambiguous fields.
- Persists only changed settings on save (unchanged effective defaults are not rewritten to config).
- Uses task-oriented sections:
Connection,Processing, andDevice Sync. - Includes a
Show advanced controlstoggle for technical tuning fields (JSON headers, cache/timeout, tier-routing tuning, network overrides, and pack limits). - Connection/auth settings map to
claude_command,observer_runtime,observer_provider,observer_model,observer_base_url,observer_auth_source,observer_auth_file,observer_auth_command,observer_auth_timeout_ms,observer_auth_cache_ttl_s, andobserver_headers. - Processing settings include
raw_events_sweeper_interval_splus tiered observer routing controls forobserver_tier_routing_enabled,observer_simple_model,observer_simple_temperature,observer_rich_model,observer_rich_temperature,observer_rich_reasoning_effort,observer_rich_reasoning_summary, andobserver_rich_max_output_tokens. - When tiered routing is enabled, the Processing tab becomes the primary place for model selection; the Connection tab's base
observer_modelacts as a fallback rather than a competing primary control. - When you have not made an explicit routing choice, codemem may enable tiered routing automatically for capability-safe paths such as OpenAI/Anthropic over
api_httpand Claude subscription usage overclaude_sidecar. - Explicit config still wins. If you set routing or transport values yourself, codemem honors them instead of replacing them with built-in defaults.
- For OpenAI
api_httppaths, codemem now treats Responses as the default transport instead of chat-completions-style behavior. - If a selected tier path cannot honor the requested settings, codemem records the requested versus actual provider/model/runtime details and surfaces a visible fallback reason.
- Sync settings can also be updated here (
sync_enabled,sync_host,sync_port,sync_interval_s,sync_mdns). - Environment variables still override file values.
- Config resolution supports JSON and JSONC with this precedence:
- explicit
CODEMEM_CONFIG - workspace-scoped config derived from
CODEMEM_RUNTIME_ROOTorCODEMEM_WORKSPACE_ID - legacy global config (
~/.config/codemem/config.jsonor~/.config/codemem/config.jsonc)
- explicit
- Runtime choices are
api_httpandclaude_sidecar. claude_sidecarruns observer calls through the local Claude runtime (subscription/session auth) and does not requireANTHROPIC_API_KEY.claude_commandcontrols howclaude_sidecarinvokes Claude CLI (default["claude"]).- Wrapper example:
"claude_command": ["wrapper", "claude", "--"]
- Wrapper example:
- Default model selection:
api_http:gpt-5.1-codex-miniunlessobserver_modelis set.claude_sidecar:claude-4.5-haikuunlessobserver_modelis set.- Tier routing may pick different simple/rich models automatically when the current runtime/provider path is marked capability-safe.
- Anthropic direct API calls use Anthropic's direct model IDs. codemem translates the common shorthand
claude-4.5-haikutoclaude-haiku-4-5; if you want a fixed snapshot, set a versioned model likeclaude-haiku-4-5-20251001directly. - If a configured
observer_modelis unsupported by Claude CLI, codemem retries once with Claude's default model. - Supported auth sources:
auto,env,file,command,none. observer_auth_commandis argv and must be a JSON string array, not a space-separated string.- Config file form:
"observer_auth_command": ["iap-auth", "--audience", "example"] - Env var form (
CODEMEM_OBSERVER_AUTH_COMMAND):'["iap-auth","--audience","example"]'
- Config file form:
- Header templates can use
${auth.token},${auth.type}, and${auth.source}. - Settings are grouped into
Connection,Processing, andDevice Syncsections with shell-agnostic labels. - Queue settings include
raw_events_sweeper_interval_s(seconds), which controls background pending-event drain cadence. - Tiered routing settings live in the Processing tab. The basic view exposes the tier-routing toggle plus simple/rich model choices, while advanced controls reveal the extra rich-tier tuning knobs.
- To avoid overlapping primary controls, the Connection tab reframes
observer_modelas a fallback whenever tiered routing is enabled. - Rich-tier OpenAI transport tuning remains visible in Processing, but OpenAI API paths are Responses-first by default.
Example command-token gateway config:
{
"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}",
"X-Auth-Source": "${auth.source}"
}
}Header template variables:
${auth.token}${auth.type}${auth.source}
Command/file token caching notes:
- Successful
file/commandtoken resolutions are cached forobserver_auth_cache_ttl_s. - Failed
file/commandresolutions are not cached (codemem clears stale cache and retries on the next call).
- A session is created per ingest payload.
- Observations and summaries persist when the observer emits meaningful content.
- Low-signal observations are filtered before writing.
- The plugin can inject a memory pack into the system prompt.
- Controls:
CODEMEM_INJECT_CONTEXT=0disables injection.CODEMEM_INJECT_LIMITcaps memory items (default 8).CODEMEM_INJECT_TOKEN_BUDGETcaps pack size (default 800).
- Reuse savings estimate discovery work versus pack read size.
- Embeddings are stored via sqlite-vec + fastembed.
- Embeddings are written automatically for new memories.
- Backfill existing memories with:
codemem embed --dry-runthencodemem embed. - If sqlite-vec fails to load, semantic recall is skipped and keyword search remains.
codemem sync enablegenerates keys and writes config.codemem sync startstarts the viewer-backed sync runtime.codemem sync statusshows device info and peer health.
- In the viewer, open the Sync panel and scan/copy the QR payload (recommended).
- Or run
codemem sync pairand copy the payload. - On the other device, run
codemem sync pair --accept '<payload>'.
Optional (recommended for coworker sync): set a per-peer project filter at accept time:
codemem sync pair --accept '<payload>' --include shared-repo-1,shared-repo-2codemem sync pair --accept '<payload>' --exclude private-repo
- In the Sync panel, use
Assigned actorto map a peer to your local actor when that machine should count as part of your identity. - Peers assigned to your local actor stay on the same-person continuity path, including private sync.
- If a machine is replaced or re-paired, use
Claim old device as mineto reconnect older synced history to your local actor.
- The Sync panel now has an
Actorssection for creating and renaming non-local actors. - The same section can merge a duplicate actor into another actor; this immediately moves assigned peers, while already-stamped historical memories keep their current provenance until a later follow-on flow changes them.
- Assign each paired peer below to
Unassigned actor, your local actor, or a named actor. - Assigning a peer changes how older synced memories from that peer are attributed.
- Assigning a peer to a non-local actor keeps that peer's history shared; assigning it to your local actor keeps it personal/private.
- Non-local actors receive memories from projects allowed by their include/exclude filters by default.
- Use
Only meon a memory when it should stay local and not sync to non-local actors. - The Sync panel also shows a teammate review card with per-peer counts for memories that will share by default versus memories marked
Only me, plus a one-click jump intoMy memoriesin the Feed for review.
codemem sync oncesyncs all peers once.codemem sync once --peer <name-or-device-id>syncs one peer.
- codemem does not ship a
sync installhelper in the TS CLI. - Use an OS service manager to run
codemem serve start --foregroundat login/boot. - Example service templates live in
docs/autostart/launchd/anddocs/autostart/systemd/.
codemem sync doctordiagnoses sync configuration issues (keys, config, peer reachability).codemem sync bootstrap <peer-device-id>bootstraps sync state from a peer's snapshot.codemem sync attemptsshows recent sync attempt history per peer.
codemem sync statusshows sync config and peer health.codemem sync start|stop|restartare deprecated — usecodemem serve start|stop|restartinstead. The viewer process manages the sync runtime; there is no separate sync-only daemon.
- Use coordinator-backed discovery when peers are reachable but their addresses change frequently or mDNS does not work across network boundaries such as VPNs.
- Set
sync_coordinator_urlandsync_coordinator_groupto enable it. - The Settings UI exposes coordinator URL, group, timeout, and presence TTL fields under the Sync tab.
- The coordinator is self-hosted/operator-run and only helps peers discover fresh addresses; direct peer-to-peer sync remains the data path.
- See docs/coordinator-discovery.md for setup, config, and current limitations.
- Do not expose the viewer itself just because the coordinator or sync protocol needs cross-network reachability; those are separate surfaces.
sync_key_store=keychain(orCODEMEM_SYNC_KEY_STORE=keychain) stores the private key in Secret Service (Linux) or Keychain (macOS).- Falls back to file-based storage if the platform tooling is unavailable.
- On macOS, the Keychain storage uses the
securityCLI and may expose the key in process arguments; usesync_key_store=fileif that is a concern.
- If sessions are missing, confirm the viewer and plugin share the same DB path.
- Check
~/.codemem/plugin.logfor plugin errors. - Sync errors:
codemem sync statusshows the last error per peer.
Symptom: API errors with SqliteError: no such module: vec0, or the viewer logs sqlite-vec failed to load; retrying viewer startup with embeddings disabled at startup.
memory_vectors is a sqlite-vec virtual table backed by the vec0 extension module. The module is shipped as a per-platform npm sub-package (sqlite-vec-darwin-arm64, sqlite-vec-linux-arm64, sqlite-vec-linux-x64, sqlite-vec-windows-x64, sqlite-vec-darwin-x64) and selected automatically by npm's optionalDependencies resolution. It usually just works, but a few install layouts can leave the right binary missing.
Diagnose first:
# Confirm the architecture and the codemem install path
uname -m
which codemem
ls (npm root -g)/codemem/node_modules/ | grep -i sqlite-vecYou should see both sqlite-vec/ (the wrapper) and sqlite-vec-<platform>/ (the prebuilt binary). If the platform-specific package is missing, that's the bug.
Fixes, in order of preference:
-
Reinstall codemem with optional deps explicitly included. npm sometimes drops
optionalDependenciesfor global installs:npm install -g --include=optional codemem@latest
-
Force-install the platform package alongside. If reinstalling didn't help (sometimes happens with global installs across major Node upgrades), install the matching platform sub-package separately and link it into codemem's tree:
# 64-bit Pi OS / generic Linux ARM64 npm install -g sqlite-vec-linux-arm64 ln -sfn (npm root -g)/sqlite-vec-linux-arm64 \ (npm root -g)/codemem/node_modules/sqlite-vec-linux-arm64 # then restart the viewer
Substitute the right platform:
sqlite-vec-linux-armfor 32-bit Pi OS (uname -mreportsarmv7l),sqlite-vec-linux-x64for x86_64 Linux. -
Run with embeddings disabled. Codemem degrades gracefully: keyword search via FTS5 keeps working, the viewer keeps loading, and the only feature you lose is semantic recall via vector similarity:
set -Ux CODEMEM_EMBEDDING_DISABLED 1 # then restart the viewer
Reverse with
set -e CODEMEM_EMBEDDING_DISABLED.
The viewer's startup retries automatically with embeddings disabled if the initial load fails (sqlite-vec failed to load; retrying viewer startup with embeddings disabled in the banner). If you see API errors with no such module: vec0 AFTER that retry message, please file an issue — getSemanticIndexDiagnostics and other vec-touching code paths should be self-healing on a connection without vec0.
Symptom: worker bootstrap fails with HTTP 401 / bootstrap_grant_invalid.
The wire error is intentionally generic. Check the seed peer's server logs for the specific reason, then work through these:
- Is the coordinator reachable from the seed peer? The seed must call the coordinator's admin API to verify the grant. If the coordinator is down or unreachable, the grant cannot be verified and bootstrap will fail. Check network connectivity and
sync_coordinator_urlconfig on the seed. - Is the grant expired or revoked? List active grants with
codemem coordinator list-bootstrap-grants <group>and confirm the grant is still valid. - Does the grant's worker device match the bootstrapping device? The
worker_device_idon the grant must match the device ID of the worker attempting bootstrap. A mismatch (e.g., using a grant issued for a different worker) will be rejected.
- New memories default to the shared path for projects allowed by sync filters.
- Owned feed items expose a visibility control so you can explicitly switch a memory between
Only meandShare with peers. - Choosing
Only mekeeps the memory local and restores personal workspace scope; choosingShare with peerskeeps it eligible for allowed-project sync and shared workspace scope. - The feed supports
All,Mine, andTheirsscopes without splitting memories into separate databases. - For non-local peers, project and per-peer sync filters define the default eligible sync set, and
Only meacts as a per-memory override.
- The
Actorssection gives actor creation/rename one home, while peer cards keep assignment close to the peer being changed. Assigned actorreplaces the olderBelongs to melanguage in the peer cards.- Feed cards you own include a visibility control so shared/private intent can be changed without editing raw metadata.
Redact sensitive detailslives above Recent sync attempts so it is easier to find before you inspect peer addresses and attempt history.- Recent sync attempts intentionally show only the latest few rows in the viewer; use CLI diagnostics for deeper history if needed.