src/services/worker/README.md
The Worker Service is an Express HTTP server that handles all claude-mem operations. It runs on port 37777 (configurable via CLAUDE_MEM_WORKER_PORT) and is managed by PM2.
Hook (plugin/scripts/*-hook.js)
→ HTTP Request to Worker (localhost:37777)
→ Route Handler (http/routes/*.ts)
→ MCP Server Tool (for search) OR Service Layer (for session/data)
→ Database (SQLite3 + Chroma vector DB)
src/services/worker/
├── README.md # This file
├── WorkerService.ts # Slim orchestrator (~150 lines)
├── http/ # HTTP layer
│ ├── middleware.ts # Shared middleware (logging, CORS, etc.)
│ └── routes/ # Route handlers organized by feature area
│ ├── SessionRoutes.ts # Session lifecycle (init, observations, summarize, complete)
│ ├── DataRoutes.ts # Data retrieval (get observations, summaries, prompts, stats)
│ ├── SearchRoutes.ts # Search/MCP proxy (all search endpoints)
│ ├── SettingsRoutes.ts # Settings, MCP toggle, branch switching
│ └── ViewerRoutes.ts # Health check, viewer UI, SSE stream
└── services/ # Business logic services (existing, NO CHANGES in Phase 1)
├── DatabaseManager.ts # SQLite connection management
├── SessionManager.ts # Session state tracking
├── SDKAgent.ts # Claude Agent SDK for observations/summaries
├── SSEBroadcaster.ts # Server-Sent Events for real-time updates
├── PaginationHelper.ts # Query pagination utilities
├── SettingsManager.ts # User settings CRUD
└── BranchManager.ts # Git branch operations
GET /health - Health check endpointGET / - Serve viewer UI (React app)GET /stream - SSE stream for real-time updatesSession lifecycle operations (use service layer directly):
POST /sessions/init - Initialize new sessionPOST /sessions/:sessionId/observations - Add tool usage observationsPOST /sessions/:sessionId/summarize - Trigger session summaryGET /sessions/:sessionId/status - Get session statusDELETE /sessions/:sessionId - Delete sessionPOST /sessions/:sessionId/complete - Mark session completePOST /sessions/claude-id/:claudeId/observations - Add observations by claude_idPOST /sessions/claude-id/:claudeId/summarize - Summarize by claude_idPOST /sessions/claude-id/:claudeId/complete - Complete by claude_idData retrieval operations (use service layer directly):
GET /observations - List observations (paginated)GET /summaries - List session summaries (paginated)GET /prompts - List user prompts (paginated)GET /observations/:id - Get observation by IDGET /sessions/:sessionId - Get session by IDGET /prompts/:id - Get prompt by IDGET /stats - Get database statisticsGET /projects - List all projectsGET /processing - Get processing statusPOST /processing - Set processing statusAll search operations (proxy to MCP server):
GET /search - Unified search (observations + sessions + prompts)GET /timeline - Unified timeline contextGET /decisions - Decision-type observationsGET /changes - Change-related observationsGET /how-it-works - How-it-works explanationsGET /search/observations - Search observationsGET /search/sessions - Search sessionsGET /search/prompts - Search promptsGET /search/by-concept - Find by concept tagGET /search/by-file - Find by file pathGET /search/by-type - Find by observation typeGET /search/recent-context - Get recent contextGET /search/context-timeline - Get context timelineGET /context/preview - Preview contextGET /context/inject - Inject contextGET /search/timeline-by-query - Timeline by search queryGET /search/help - Search helpSettings and configuration (use service layer directly):
GET /settings - Get user settingsPOST /settings - Update user settingsGET /mcp/status - Get MCP server statusPOST /mcp/toggle - Toggle MCP server on/offGET /branch/status - Get git branch infoPOST /branch/switch - Switch git branchPOST /branch/update - Pull branch updatesPhase 1 is a pure code reorganization with ZERO functional changes:
MCP vs Direct DB Split (inherited, not changed in Phase 1):
Phase 2 will unify the architecture:
This separation allows the worker to be deployed anywhere (as a CLI tool, cloud service, etc.) without carrying database dependencies.
setupRoutes() methodExample:
// In DataRoutes.ts
private async handleGetFoo(req: Request, res: Response): Promise<void> {
try {
const result = await this.dbManager.getFoo();
res.json(result);
} catch (error) {
logger.failure('WORKER', 'Get foo failed', {}, error as Error);
res.status(500).json({ error: (error as Error).message });
}
}
// Register in setupRoutes()
app.get('/foo', this.handleGetFoo.bind(this));
.bind(this) to preserve context