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:- Process Management: PM2 → Custom Bun-based ProcessManager
- Database Driver: better-sqlite3 npm package → bun:sqlite runtime module
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)
Process Management (PM2)
Process Management (PM2)
Component: PM2 (Process Manager 2)Pain Points:
- Package:
pm2npm dependency - Process Name:
claude-mem-worker - Management: External PM2 daemon manages lifecycle
- Discovery:
pm2 list,pm2 describecommands - Auto-restart: PM2 automatically restarts on crash
- Logs:
~/.pm2/logs/claude-mem-worker-*.log - PID File:
~/.pm2/pids/claude-mem-worker.pid
- Additional npm dependency required
- PM2 daemon must be running
- Potential conflicts with other PM2 processes
- Windows compatibility issues
- Complex configuration for simple use case
Database Driver (better-sqlite3)
Database Driver (better-sqlite3)
Component: better-sqlite3
- Package:
better-sqlite3npm package (native module) - Installation: Requires native compilation (node-gyp)
- Windows: Requires Visual Studio build tools + Python
- Import:
import Database from 'better-sqlite3'
- 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)
Process Management (Custom ProcessManager)
Process Management (Custom ProcessManager)
Component: Custom ProcessManager (Core Mechanisms:
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)
-
PID File Management:
- File:
~/.claude-mem/.worker.pid - Content: Process ID (e.g., “35557”)
- Validation: Process existence via
kill(pid, 0)signal
- File:
-
Port File Management:
- File:
~/.claude-mem/.worker.port - Content: Two lines (port number, PID)
- Purpose: Track port binding and validate PID match
- File:
-
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
- No external dependencies
- Simpler codebase (direct control)
- Better error handling and validation
- Platform-agnostic (Bun handles platform differences)
Database Driver (bun:sqlite)
Database Driver (bun:sqlite)
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)
- Bun ≥1.0 (automatically installed if missing)
- No native compilation required
- No platform-specific build tools needed
- 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
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 exists5
PM2 Cleanup
Execute
pm2 delete claude-mem-worker (errors ignored), create marker file6
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
- One-time migration flag
- Prevents repeated PM2 cleanup on every start
- Persists across restarts and reboots
- 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.
- Hook fires (SessionStart most common)
- Worker status check: No PID file → worker not running
- Migration check: No marker file → run PM2 cleanup
- PM2 cleanup:
pm2 delete claude-mem-worker(old worker terminated) - Marker creation:
~/.claude-mem/.pm2-migratedwith timestamp - New worker start: Bun process spawned, PID/port files created
- Verification: Process check + HTTP health check
- Hook completes: Claude Code session starts normally
- 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:- PID file exists? YES
- Process alive? YES
- HTTP health check? SUCCESS
- Result: Worker already running, done (~50ms)
Platform-Specific Behavior
Platform Comparison
| Feature | macOS | Linux | Windows |
|---|---|---|---|
| PM2 Cleanup | Attempted | Attempted | Attempted |
| Marker File | Created | Created | Created |
| Process Signals | POSIX (native) | POSIX (native) | Bun abstraction |
| Bun Support | Full | Full | Full |
| PID File | Yes | Yes | Yes |
| Port File | Yes | Yes | Yes |
| Health Check | HTTP | HTTP | HTTP |
| Migration Delay | ~2-5s first time | ~2-5s first time | ~2-5s first time |
Platform Notes
- macOS
- Linux
- Windows
- POSIX signal handling works natively
- Bun fully supported
- No platform-specific workarounds needed
Observable Changes
Command Changes
| Old (PM2) | New (Bun) | Notes |
|---|---|---|
pm2 list | npm run worker:status | Shows worker status |
pm2 start <script> | npm run worker:start | Start worker |
pm2 stop claude-mem-worker | npm run worker:stop | Stop worker |
pm2 restart claude-mem-worker | npm run worker:restart | Restart worker |
pm2 delete claude-mem-worker | npm run worker:stop | Remove worker |
pm2 logs claude-mem-worker | npm run worker:logs | View logs |
pm2 describe claude-mem-worker | npm run worker:status | Detailed status |
pm2 monit | No equivalent | PM2-specific monitoring |
File Location Changes
Logs:User-Visible Changes
Before Update:Orphaned Files
After migration, these PM2 files may remain (safe to delete):File System State
State Directory Structure
Before Migration (PM2 system):Edge Cases and Troubleshooting
Scenario 1: Migration Fails (PM2 Still Running)
Symptoms:pm2 liststill showsclaude-mem-worker- Port conflict errors in logs
- Worker fails to start
Scenario 2: Stale PID File (Process Dead)
Symptoms:npm run worker:statusshows “not running”.worker.pidfile exists- Process ID doesn’t exist
Scenario 3: Port Already in Use
Error:EADDRINUSE: address already in use
Resolution:
Common Error Messages
| Error | Cause | Resolution |
|---|---|---|
EADDRINUSE | Port already in use | lsof -i :37777 then kill conflicting process |
No such process | Stale PID file | Automatic cleanup on next hook trigger |
pm2: command not found | PM2 not installed | None needed (error is caught and ignored) |
Invalid port X | Port validation failed | Update CLAUDE_MEM_WORKER_PORT in settings |
Developer Notes
Testing the Migration
Architecture Decisions
Why Custom ProcessManager Instead of PM2?- Simplicity: Direct control, no external daemon
- Dependencies: Remove npm dependency
- Cross-platform: Bun handles platform differences
- Bundle Size: Reduce plugin package size
- Control: Fine-grained error handling and validation
- Performance: Avoid unnecessary process spawning
- Idempotency: Migration runs exactly once
- Debugging: Timestamp shows when migration occurred
- Simplicity: Clear migration state
- Quality Migration: Clean up orphaned processes
- Consistency: Same behavior across all platforms
- Safety: Error handling already in place (try/catch)
- 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:- Removes external dependencies (PM2, better-sqlite3)
- Simplifies architecture (direct process control)
- Improves cross-platform support (especially Windows)
- Preserves user data (database, settings, logs unchanged)
- Requires no user action (automatic on first hook trigger)

