Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.claude-mem.ai/llms.txt

Use this file to discover all available pages before exploring further.

Historical Migration DocumentationThis document describes the PM2 to Bun migration that occurred in v7.1.0 (December 2025). If you’re installing claude-mem for the first time, this migration has already been completed and you can use the current Bun-based system documented in the main guides.This documentation is preserved for users upgrading from versions older than v7.1.0.

PM2 to Bun Migration: Complete Technical Documentation

Version: 7.1.0 Date: December 2025 Migration Type: Process Management (PM2 → Bun) + Database Driver (better-sqlite3 → bun:sqlite)

Executive Summary

Claude-mem version 7.1.0 introduces two major architectural migrations:
  1. Process Management: PM2 → Custom Bun-based ProcessManager
  2. Database Driver: better-sqlite3 npm package → bun:sqlite runtime module
Both migrations are automatic and transparent to end users. The first time a hook fires after updating to 7.1.0+, the system performs a one-time cleanup of legacy PM2 processes and transitions to the new architecture.

Key Benefits

  • Simplified Dependencies: Removes PM2 and better-sqlite3 npm packages
  • Improved Cross-Platform Support: Better Windows compatibility
  • Faster Installation: No native module compilation required
  • Built-in Runtime: Leverages Bun’s built-in process management and SQLite
  • Reduced Complexity: Custom ProcessManager is simpler than PM2 integration

Migration Impact

  • Data Preservation: User data, settings, and database remain unchanged
  • Automatic Cleanup: Old PM2 processes automatically terminated (all platforms)
  • No User Action Required: Migration happens automatically on first hook trigger
  • Backward Compatible: SQLite database format unchanged (only driver changed)

Architecture Comparison

Old System (PM2-based)

Component: PM2 (Process Manager 2)
  • Package: pm2 npm dependency
  • Process Name: claude-mem-worker
  • Management: External PM2 daemon manages lifecycle
  • Discovery: pm2 list, pm2 describe commands
  • Auto-restart: PM2 automatically restarts on crash
  • Logs: ~/.pm2/logs/claude-mem-worker-*.log
  • PID File: ~/.pm2/pids/claude-mem-worker.pid
Lifecycle Commands:
pm2 start <script>           # Start worker
pm2 stop claude-mem-worker   # Stop worker
pm2 restart claude-mem-worker # Restart worker
pm2 delete claude-mem-worker  # Remove from PM2
pm2 logs claude-mem-worker    # View logs
Pain Points:
  • Additional npm dependency required
  • PM2 daemon must be running
  • Potential conflicts with other PM2 processes
  • Windows compatibility issues
  • Complex configuration for simple use case
Component: better-sqlite3
  • Package: better-sqlite3 npm package (native module)
  • Installation: Requires native compilation (node-gyp)
  • Windows: Requires Visual Studio build tools + Python
  • Import: import Database from 'better-sqlite3'
Installation Requirements:
  • Node.js development headers
  • C++ compiler (gcc/clang on Mac/Linux, MSVC on Windows)
  • Python (for node-gyp)
  • Windows: Visual Studio Build Tools

New System (Bun-based)

Component: Custom ProcessManager (src/services/process/ProcessManager.ts)
  • Package: Built-in Bun APIs (no external dependency)
  • Process Spawn: Bun.spawn() with detached mode
  • Management: Direct process control via PID file
  • Discovery: PID file + process existence check + HTTP health check
  • Auto-restart: Hook-triggered restart on failure detection
  • Logs: ~/.claude-mem/logs/worker-YYYY-MM-DD.log
  • PID File: ~/.claude-mem/.worker.pid
  • Port File: ~/.claude-mem/.worker.port (new)
Lifecycle Commands:
npm run worker:start    # Start worker
npm run worker:stop     # Stop worker
npm run worker:restart  # Restart worker
npm run worker:status   # Check status
npm run worker:logs     # View logs
Core Mechanisms:
  1. PID File Management:
    • File: ~/.claude-mem/.worker.pid
    • Content: Process ID (e.g., “35557”)
    • Validation: Process existence via kill(pid, 0) signal
  2. Port File Management:
    • File: ~/.claude-mem/.worker.port
    • Content: Two lines (port number, PID)
    • Purpose: Track port binding and validate PID match
  3. Health Checking:
    • Layer 1: PID file exists?
    • Layer 2: Process alive? (kill(pid, 0))
    • Layer 3: HTTP health check (GET /health)
    • All three must pass for “healthy” status
Advantages:
  • No external dependencies
  • Simpler codebase (direct control)
  • Better error handling and validation
  • Platform-agnostic (Bun handles platform differences)
Component: bun:sqlite
  • Package: Built into Bun runtime (no npm package)
  • Installation: None required (comes with Bun ≥1.0)
  • Platform: Works anywhere Bun works
  • Import: import { Database } from 'bun:sqlite'
  • API: Similar to better-sqlite3 (synchronous)
Installation Requirements:
  • Bun ≥1.0 (automatically installed if missing)
  • No native compilation required
  • No platform-specific build tools needed
Compatibility:
  • SQLite database format: Unchanged
  • Database file: ~/.claude-mem/claude-mem.db (same location)
  • Query syntax: Identical (both use SQLite SQL)

Migration Mechanics

One-Time PM2 Cleanup

The migration system uses a marker-based approach to perform PM2 cleanup exactly once. Implementation: src/shared/worker-utils.ts:73-86
// Clean up legacy PM2 (one-time migration)
const pm2MigratedMarker = join(DATA_DIR, '.pm2-migrated');

if (!existsSync(pm2MigratedMarker)) {
  try {
    spawnSync('pm2', ['delete', 'claude-mem-worker'], { stdio: 'ignore' });
    // Mark migration as complete
    writeFileSync(pm2MigratedMarker, new Date().toISOString(), 'utf-8');
    logger.debug('SYSTEM', 'PM2 cleanup completed and marked');
  } catch {
    // PM2 not installed or process doesn't exist - still mark as migrated
    writeFileSync(pm2MigratedMarker, new Date().toISOString(), 'utf-8');
  }
}

Migration Trigger Points

1

Hook Execution

SessionStart, UserPromptSubmit, or PostToolUse hooks execute using new 7.1.0 code
2

Worker Status Check

ensureWorkerRunning() checks if ~/.claude-mem/.worker.pid exists (it doesn’t for first run after update)
3

Start Worker Decision

Worker not running → Call startWorker()
4

Migration Check

Check if ~/.claude-mem/.pm2-migrated exists
5

PM2 Cleanup

Execute pm2 delete claude-mem-worker (errors ignored), create marker file
6

New Worker Start

Spawn new Bun-managed worker process with PID and port files

Marker File

Location: ~/.claude-mem/.pm2-migrated Content: ISO 8601 timestamp
2025-12-13T00:18:39.673Z
Purpose:
  • One-time migration flag
  • Prevents repeated PM2 cleanup on every start
  • Persists across restarts and reboots
Lifecycle:
  • Created: First hook trigger after update to 7.1.0+ (all platforms)
  • Updated: Never
  • Deleted: Never (user could manually delete to force re-migration)

User Experience Timeline

First Session After Update

This is the critical migration moment. The process takes approximately 2-5 seconds.
Step-by-Step Execution:
  1. Hook fires (SessionStart most common)
  2. Worker status check: No PID file → worker not running
  3. Migration check: No marker file → run PM2 cleanup
  4. PM2 cleanup: pm2 delete claude-mem-worker (old worker terminated)
  5. Marker creation: ~/.claude-mem/.pm2-migrated with timestamp
  6. New worker start: Bun process spawned, PID/port files created
  7. Verification: Process check + HTTP health check
  8. Hook completes: Claude Code session starts normally
User Observable Behavior:
  • Slight delay on first startup (PM2 cleanup + new worker spawn)
  • No error messages (cleanup failures silently handled)
  • Worker appears running via npm run worker:status
  • Old PM2 worker no longer in pm2 list

Subsequent Sessions

After migration completes, every hook trigger follows the fast path:
  1. PID file exists? YES
  2. Process alive? YES
  3. HTTP health check? SUCCESS
  4. Result: Worker already running, done (~50ms)
No migration logic runs on subsequent sessions.

Platform-Specific Behavior

Platform Comparison

FeaturemacOSLinuxWindows
PM2 CleanupAttemptedAttemptedAttempted
Marker FileCreatedCreatedCreated
Process SignalsPOSIX (native)POSIX (native)Bun abstraction
Bun SupportFullFullFull
PID FileYesYesYes
Port FileYesYesYes
Health CheckHTTPHTTPHTTP
Migration Delay~2-5s first time~2-5s first time~2-5s first time

Platform Notes

  • POSIX signal handling works natively
  • Bun fully supported
  • No platform-specific workarounds needed

Observable Changes

Command Changes

Old (PM2)New (Bun)Notes
pm2 listnpm run worker:statusShows worker status
pm2 start <script>npm run worker:startStart worker
pm2 stop claude-mem-workernpm run worker:stopStop worker
pm2 restart claude-mem-workernpm run worker:restartRestart worker
pm2 delete claude-mem-workernpm run worker:stopRemove worker
pm2 logs claude-mem-workernpm run worker:logsView logs
pm2 describe claude-mem-workernpm run worker:statusDetailed status
pm2 monitNo equivalentPM2-specific monitoring

File Location Changes

Logs:
Old: ~/.pm2/logs/claude-mem-worker-out.log
     ~/.pm2/logs/claude-mem-worker-error.log

New: ~/.claude-mem/logs/worker-YYYY-MM-DD.log
PID Files:
Old: ~/.pm2/pids/claude-mem-worker.pid

New: ~/.claude-mem/.worker.pid
Process State:
Old: PM2 daemon memory (pm2 save)

New: ~/.claude-mem/.worker.pid
     ~/.claude-mem/.worker.port
     ~/.claude-mem/.pm2-migrated (all platforms)
Database (unchanged):
Same: ~/.claude-mem/claude-mem.db

User-Visible Changes

Before Update:
$ pm2 list
┌────┬────────────────────┬─────────┬─────────┬──────────┐
 id name status restart uptime
├────┼────────────────────┼─────────┼─────────┼──────────┤
 0 claude-mem-worker online 0 2d 5h
└────┴────────────────────┴─────────┴─────────┴──────────┘
After Update:
$ pm2 list
# Empty - worker no longer managed by PM2

$ npm run worker:status
Worker is running
PID: 35557
Port: 37777
Uptime: 2h 15m

Orphaned Files

After migration, these PM2 files may remain (safe to delete):
~/.pm2/                    # Entire PM2 directory
~/.pm2/logs/               # Old logs
~/.pm2/pids/               # Old PID files
~/.pm2/pm2.log             # PM2 daemon log
~/.pm2/dump.pm2            # PM2 process dump
Cleanup (optional):
# Remove PM2 entirely (if not used for other processes)
pm2 kill
rm -rf ~/.pm2

# Or just remove claude-mem logs
rm -f ~/.pm2/logs/claude-mem-worker-*.log
rm -f ~/.pm2/pids/claude-mem-worker.pid

File System State

State Directory Structure

Before Migration (PM2 system):
~/.claude-mem/
├── claude-mem.db          # Database (unchanged)
├── chroma/                # Vector embeddings (unchanged)
├── logs/                  # Application logs (unchanged)
└── settings.json          # User settings (unchanged)

~/.pm2/
├── logs/
│   ├── claude-mem-worker-out.log
│   └── claude-mem-worker-error.log
├── pids/
│   └── claude-mem-worker.pid
└── pm2.log
After Migration (Bun system):
~/.claude-mem/
├── claude-mem.db          # Database (same file)
├── chroma/                # Vector embeddings (unchanged)
├── logs/
│   └── worker-2025-12-13.log  # New log format
├── settings.json          # User settings (unchanged)
├── .worker.pid            # NEW: Process ID
├── .worker.port           # NEW: Port + PID
└── .pm2-migrated          # NEW: Migration marker (all platforms)

~/.pm2/                    # Orphaned (safe to delete)
├── logs/                  # Old logs (no longer written)
├── pids/                  # Old PID (no longer updated)
└── pm2.log                # PM2 daemon log (not used)

Edge Cases and Troubleshooting

Scenario 1: Migration Fails (PM2 Still Running)

This is rare but can happen if PM2 has watch mode enabled or the process is manually restarted.
Symptoms:
  • pm2 list still shows claude-mem-worker
  • Port conflict errors in logs
  • Worker fails to start
Resolution:
# Manual cleanup
pm2 delete claude-mem-worker
pm2 save  # Persist the deletion

# Force re-migration (optional)
rm ~/.claude-mem/.pm2-migrated

# Restart worker
npm run worker:restart

Scenario 2: Stale PID File (Process Dead)

Symptoms:
  • npm run worker:status shows “not running”
  • .worker.pid file exists
  • Process ID doesn’t exist
Automatic Recovery: Next hook trigger detects dead process and starts a fresh worker. Manual Resolution:
rm ~/.claude-mem/.worker.pid
rm ~/.claude-mem/.worker.port
npm run worker:start

Scenario 3: Port Already in Use

Error: EADDRINUSE: address already in use Resolution:
# Check what's using the port
lsof -i :37777

# Kill the process
kill -9 <PID>

# Restart worker
npm run worker:restart

Common Error Messages

ErrorCauseResolution
EADDRINUSEPort already in uselsof -i :37777 then kill conflicting process
No such processStale PID fileAutomatic cleanup on next hook trigger
pm2: command not foundPM2 not installedNone needed (error is caught and ignored)
Invalid port XPort validation failedUpdate CLAUDE_MEM_WORKER_PORT in settings

Developer Notes

Testing the Migration

# 1. Install old version (with PM2)
git checkout <pre-7.1.0-tag>
npm install && npm run build && npm run sync-marketplace

# 2. Start PM2 worker
pm2 start plugin/scripts/worker-cli.js --name claude-mem-worker

# 3. Update to new version
git checkout main
npm install && npm run build && npm run sync-marketplace

# 4. Trigger hook
node plugin/scripts/session-start-hook.js

# 5. Verify migration
pm2 list  # Should NOT show claude-mem-worker
cat ~/.claude-mem/.pm2-migrated  # Should exist
npm run worker:status  # Should show Bun worker running

Architecture Decisions

Why Custom ProcessManager Instead of PM2?
  1. Simplicity: Direct control, no external daemon
  2. Dependencies: Remove npm dependency
  3. Cross-platform: Bun handles platform differences
  4. Bundle Size: Reduce plugin package size
  5. Control: Fine-grained error handling and validation
Why One-Time Marker Instead of Always Running PM2 Delete?
  1. Performance: Avoid unnecessary process spawning
  2. Idempotency: Migration runs exactly once
  3. Debugging: Timestamp shows when migration occurred
  4. Simplicity: Clear migration state
Why Run PM2 Cleanup on All Platforms?
  1. Quality Migration: Clean up orphaned processes
  2. Consistency: Same behavior across all platforms
  3. Safety: Error handling already in place (try/catch)
  4. No Downside: If PM2 not installed, error is caught and ignored

Summary

The migration from PM2 to Bun-based ProcessManager is a one-time, automatic, transparent transition that:
  1. Removes external dependencies (PM2, better-sqlite3)
  2. Simplifies architecture (direct process control)
  3. Improves cross-platform support (especially Windows)
  4. Preserves user data (database, settings, logs unchanged)
  5. Requires no user action (automatic on first hook trigger)
Key Migration Moment: First hook trigger after update to 7.1.0+ Duration: ~2-5 seconds (one-time delay) Impact: Seamless transition, user-invisible Rollback: Not needed (migration is forward-only, safe) For most users, the migration will be completely transparent - they’ll see no errors, no data loss, and experience improved reliability and simpler troubleshooting going forward.