Summary
The daemon repeatedly gets OOM-killed while indexing a mid-size repo (~9k files), and after each kill the next scheduled reindex treats the on-disk DB as invalid and reruns a full reindex instead of resuming/incremental, causing a daily OOM crash loop that has persisted for weeks.
Environment
codebase-memory-mcp v0.10.8
- Linux x86_64, 15GB total RAM (
total_ram_mb=15613)
- Repo being indexed: ~9096 files (
pipeline.discover files=9096)
What happened
journalctl -k shows the kernel OOM-killer terminating the codebase-memory process (not --cbm-daemon-internal wrapper, the index worker itself) on 10+ separate days between 2026-07-15 and 2026-08-27, always around the same daily trigger time, with RSS between 5.6GB and 7.1GB:
Aug 27 07:23:31 kernel: Out of memory: Killed process 534979 (codebase-memory) total-vm:15045260kB, anon-rss:7082876kB ...
Aug 26 07:22:37 kernel: Out of memory: Killed process 2007241 (codebase-memory) total-vm:12947920kB, anon-rss:6201692kB ...
Aug 25 07:27:59 kernel: Out of memory: Killed process 3482383 (codebase-memory) total-vm:10850636kB, anon-rss:5667976kB ...
Aug 24 07:25:04 kernel: Out of memory: Killed process 765588 (codebase-memory) total-vm:14661524kB, anon-rss:6118132kB ...
Aug 22 07:21:04 kernel: Out of memory: Killed process 3712834 (codebase-memory) total-vm:13960104kB, anon-rss:5824416kB ...
Aug 21 07:23:59 kernel: Out of memory: Killed process 980081 (codebase-memory) total-vm:15476024kB, anon-rss:6758460kB ...
Aug 20 07:20:57 kernel: Out of memory: Killed process 2410488 (codebase-memory) total-vm:14279952kB, anon-rss:6112296kB ...
Notably the worker's own log reports a much smaller intended budget:
level=info msg=mem.init budget_mb=975 total_ram_mb=15613 source=daemon_worker_cap
level=info msg=parallel.mem.budget total_mb=975 per_worker_mb=121
and the daemon itself:
level=info msg=daemon.start version=0.10.8 memory_budget_bytes=4093071360 physical_job_limit=4 worker_memory_budget_bytes=1023267840
level=info msg=mem.init budget_mb=3903 total_ram_mb=15613 source=ram_fraction
So the process's own accounting caps it at ~975MB/worker (~3.9GB budget total), but actual RSS reaches 5.6–7.1GB — ~1.5-7x over its own stated budget. The budget appears to be advisory/accounting only and isn't enforced (no rlimit/cgroup self-imposed by the process), so it doesn't actually prevent the OOM.
The crash-loop mechanism
After each OOM kill, the in-progress DB write is left as a .stage.<random> file of 0 bytes (confirmed 3 consecutive days: home-ubuntu-hermes-agent.db.stage.2TZ0Qq, ...5QSpI1, ...PIBqTb, one per day, all 0 bytes). The next run then logs:
level=warn msg=pipeline.route path=full reason=invalid_existing_db
level=info msg=pipeline.route path=full
i.e. it treats the corrupted/incomplete DB as unusable and reruns a full reindex of all 9096 files from scratch — reproducing the same memory spike and getting OOM-killed again. This has repeated daily for at least 6 weeks with no self-recovery, because there's no partial/incremental-index fallback and no automatic re-attempt with reduced parallelism/budget after a detected crash.
Suggested fixes
- Enforce the computed memory budget (e.g. via
setrlimit/cgroup self-limit, or backpressure that pauses extraction workers) instead of only accounting it, so the process degrades gracefully instead of triggering the kernel OOM killer.
- On
invalid_existing_db, don't unconditionally do a full reindex — if the failure was itself caused by OOM/crash, retry with a smaller worker count / lower per-file retention before falling back to full.
- Write the DB more atomically / checkpoint incrementally so a crash mid-index doesn't invalidate everything already indexed.
- Expose the memory budget/parallelism as user-configurable via
codebase-memory-mcp config set (currently only auto_index, auto_watch, ui_* are configurable) so operators on memory-constrained hosts can cap it below the automatic ram_fraction default.
Workaround applied
Deleted the stale .stage files to break the loop, and added MemoryHigh/MemoryMax cgroup limits to the parent systemd units that spawn the MCP daemon, so a future runaway is contained to that unit's cgroup instead of triggering the global kernel OOM killer (which was also killing unrelated sibling services on the same host).
Summary
The daemon repeatedly gets OOM-killed while indexing a mid-size repo (~9k files), and after each kill the next scheduled reindex treats the on-disk DB as invalid and reruns a full reindex instead of resuming/incremental, causing a daily OOM crash loop that has persisted for weeks.
Environment
codebase-memory-mcpv0.10.8total_ram_mb=15613)pipeline.discover files=9096)What happened
journalctl -kshows the kernel OOM-killer terminating thecodebase-memoryprocess (not--cbm-daemon-internalwrapper, the index worker itself) on 10+ separate days between 2026-07-15 and 2026-08-27, always around the same daily trigger time, with RSS between 5.6GB and 7.1GB:Notably the worker's own log reports a much smaller intended budget:
and the daemon itself:
So the process's own accounting caps it at ~975MB/worker (~3.9GB budget total), but actual RSS reaches 5.6–7.1GB — ~1.5-7x over its own stated budget. The budget appears to be advisory/accounting only and isn't enforced (no rlimit/cgroup self-imposed by the process), so it doesn't actually prevent the OOM.
The crash-loop mechanism
After each OOM kill, the in-progress DB write is left as a
.stage.<random>file of 0 bytes (confirmed 3 consecutive days:home-ubuntu-hermes-agent.db.stage.2TZ0Qq,...5QSpI1,...PIBqTb, one per day, all 0 bytes). The next run then logs:i.e. it treats the corrupted/incomplete DB as unusable and reruns a full reindex of all 9096 files from scratch — reproducing the same memory spike and getting OOM-killed again. This has repeated daily for at least 6 weeks with no self-recovery, because there's no partial/incremental-index fallback and no automatic re-attempt with reduced parallelism/budget after a detected crash.
Suggested fixes
setrlimit/cgroup self-limit, or backpressure that pauses extraction workers) instead of only accounting it, so the process degrades gracefully instead of triggering the kernel OOM killer.invalid_existing_db, don't unconditionally do a full reindex — if the failure was itself caused by OOM/crash, retry with a smaller worker count / lower per-file retention before falling back to full.codebase-memory-mcp config set(currently onlyauto_index,auto_watch,ui_*are configurable) so operators on memory-constrained hosts can cap it below the automaticram_fractiondefault.Workaround applied
Deleted the stale
.stagefiles to break the loop, and addedMemoryHigh/MemoryMaxcgroup limits to the parent systemd units that spawn the MCP daemon, so a future runaway is contained to that unit's cgroup instead of triggering the global kernel OOM killer (which was also killing unrelated sibling services on the same host).