plans/2026-05-07-claude-mem-server-apache-bullmq-team-auth.md
Status: implementation plan
Date: 2026-05-07
Primary command: claude-mem server
Target runtime: deployable Docker container plus local compatibility path
Target license: Apache-2.0 for embeddable/core code
Build Claude-Mem Server inside this repo as the canonical next runtime. Keep the current worker as a compatibility shim while moving shared server logic into typed server/core/storage modules.
Use:
RouteHandler.setupRoutes(app).Do not build hosted Magic Recall cloud, billing, SSO/SAML/SCIM, enterprise RBAC UI, or cross-customer managed sync in this pass.
/Users/alexnewman/Downloads/claude-mem-handoff-docs/apache-2-plan.md/Users/alexnewman/Downloads/claude-mem-handoff-docs/claude-mem-server-plan.mdpackage.jsonsrc/npx-cli/index.tssrc/npx-cli/commands/runtime.tssrc/services/server/Server.tssrc/services/worker-service.tssrc/services/worker/http/middleware.tssrc/services/worker/http/routes/SessionRoutes.tssrc/services/worker/http/routes/SearchRoutes.tssrc/services/worker/http/routes/DataRoutes.tssrc/services/worker/http/routes/MemoryRoutes.tssrc/services/sqlite/PendingMessageStore.tssrc/services/queue/SessionQueueProcessor.tssrc/services/worker/SessionManager.tssrc/services/sqlite/schema.sqlsrc/services/sqlite/migrations/runner.tssrc/servers/mcp-server.tsdocker/claude-mem/Dockerfiledocker/claude-mem/README.mdplans/2026-05-06-observation-queue-engine-deep-dive.mdplans/2026-05-06-redis-dependency-strategy.mdsetupRoutes(app: express.Application): void, then register through Server.registerRoutes(handler).zod schemas with validateBody(schema) from src/services/worker/http/middleware/validateBody.ts.tools array in src/servers/mcp-server.ts, with plain JSON Schema inputSchema and handlers that call server/core logic.new Queue(name, { connection }), then enqueue jobs with queue.add(name, data, options). BullMQ stores jobs in Redis and workers can pick them up later.jobId or deduplication id for observation dedupe. Custom job IDs are unique per queue and duplicate adds are ignored while the previous job still exists.app.all("/api/auth/*splat", toNodeHandler(auth)) before express.json() on Express 5. Do not place global express.json() before the Better Auth handler.teams: { enabled: true } and custom project/memory permissions.claude-mem-server package.express.json() if using Better Auth.CLAUDE_MEM_QUEUE_ENGINE=bullmq is explicitly configured.What to implement:
LICENSE with official Apache License 2.0 text.package.json and nested manifests intended for public/core distribution to "license": "Apache-2.0".NOTICE.docs/license.md and docs/ip-boundary.md using the handoff language from apache-2-plan.md.src/server, src/core, src/storage, src/sdk, and src/adapters files as they are created.Documentation references:
/Users/alexnewman/Downloads/claude-mem-handoff-docs/apache-2-plan.md.Verification:
rg -n "AGPL|GNU Affero|Affero|GPL|copyleft|license" .rg -n "Claude-Mem™|trademark|official Anthropic|endorsed by Anthropic" .bun test tests/infrastructure/version-consistency.test.tsAnti-pattern guards:
Claude-Mem.What to implement:
src/npx-cli/commands/server.ts.src/npx-cli/index.ts to route:
claude-mem server startclaude-mem server stopclaude-mem server restartclaude-mem server statusclaude-mem server doctorclaude-mem server logsclaude-mem server migrateclaude-mem server exportclaude-mem server importclaude-mem server api-key create|list|revokestart|stop|restart|status as worker compatibility aliases.claude-mem worker start|stop|restart|status aliases that call the same command implementation as server.src/services/worker-service.ts's internal command switch to accept the same server subcommands where installed plugin scripts invoke the worker bundle directly.Documentation references:
src/npx-cli/commands/runtime.ts.src/npx-cli/index.ts.plugin/scripts/worker-service.cjs.src/services/worker-service.ts.Verification:
bun test tests/install-non-tty.test.ts tests/infrastructure/worker-json-status.test.tsserver and worker namespaces.node dist/npx-cli/index.js --helpnode dist/npx-cli/index.js server statusAnti-pattern guards:
npx claude-mem install.What to implement:
src/server/create-server.ts as the new composition root.Server shell from src/services/server/Server.ts toward src/server/http-server.ts, but keep compatibility exports during migration.cors to production dependencies or removing the runtime import. Current code imports cors but only @types/cors is declared.allowedHeaders to include Authorization before API-key routes ship.Documentation references:
src/services/server/Server.ts.src/services/worker/http/middleware.ts.express.json(), Express 5 catch-all route uses *splat.Verification:
bun test tests/server/server.test.ts tests/worker/middleware/cors-restriction.test.tsnpm run typecheck:rootAnti-pattern guards:
express.json() before Better Auth.127.0.0.1 without a migration and explicit config.What to implement:
src/core/schemas/:
agent-event.tsmemory-item.tscontext-pack.tsproject.tssession.tsteam.tsauth.tssrc/storage/sqlite/ repositories for new server-owned tables:
projectsserver_sessionsagent_eventsmemory_itemsmemory_sourcesteamsteam_membersapi_keys or Better Auth tablesaudit_logsdk_sessions, observations, session_summaries, user_prompts, and pending_messages readable during migration.observations and new memory_items.Documentation references:
/Users/alexnewman/Downloads/claude-mem-handoff-docs/claude-mem-server-plan.md.src/services/sqlite/* and migration style from src/services/sqlite/migrations/runner.ts.Verification:
tests/services/sqlite/migration-runner.test.ts.bun test tests/services/sqlite/ tests/sqlite/Anti-pattern guards:
observations search while adding memory_items.What to implement:
src/server/queue/ObservationQueueEngine.ts with an interface shaped around current behavior:export interface ObservationQueueEngine {
enqueue(sessionDbId: number, contentSessionId: string, message: PendingMessage): Promise<EnqueueResult>;
createIterator(sessionDbId: number, signal: AbortSignal, onIdleTimeout?: () => void): AsyncIterableIterator<PendingMessageWithId>;
clearPendingForSession(sessionDbId: number): Promise<number>;
resetProcessingToPending(sessionDbId: number): Promise<number>;
getPendingCount(sessionDbId: number): Promise<number>;
getTotalQueueDepth(): Promise<number>;
close(): Promise<void>;
}
SqliteObservationQueueEngine by wrapping PendingMessageStore and SessionQueueProcessor.SessionManager to depend on the interface instead of directly constructing PendingMessageStore.worker_pid consistently;pending|processing with stale processed|failed references;storeObservationsAndMarkComplete() dead-code writes.Documentation references:
src/services/sqlite/PendingMessageStore.ts.src/services/queue/SessionQueueProcessor.ts.SessionManager.Verification:
bun test tests/services/sqlite/PendingMessageStore.test.ts tests/services/queue/SessionQueueProcessor.test.tsAnti-pattern guards:
_persistentId and _originalTimestamp semantics.What to implement:
bullmqioredis if BullMQ usage requires direct connection management beyond BullMQ exports.CLAUDE_MEM_QUEUE_ENGINE=sqlite|bullmqCLAUDE_MEM_REDIS_URLCLAUDE_MEM_REDIS_HOSTCLAUDE_MEM_REDIS_PORTCLAUDE_MEM_REDIS_MODE=external|managed|dockerCLAUDE_MEM_QUEUE_REDIS_PREFIXBullMqObservationQueueEngine.1, to preserve per-session FIFO without BullMQ Pro groups.obs_${sha256(contentSessionId + "\0" + toolUseId)}sum_${sha256(contentSessionId + "\0" + createdAtEpoch + "\0" + messageKind)}/api/health and server status only when BullMQ is enabled.Documentation references:
Queue.add(...) stores jobs in Redis and workers can process later.plans/2026-05-06-redis-dependency-strategy.md.Verification:
CLAUDE_MEM_REDIS_URL.tool_use_id suppressed;Anti-pattern guards:
: in custom job IDs.What to implement:
better-auth@better-auth/api-keysrc/server/auth/auth.ts with:
src/server/middleware/auth.ts:
Authorization: Bearer <key>;authContext containing userId, organizationId, teamId, scopes, and key id;CLAUDE_MEM_AUTH_MODE=local-dev.claude-mem server api-key create --team <team> --scope memories:read,memories:writeclaude-mem server api-key listclaude-mem server api-key revoke <id>Documentation references:
hasPermission.Verification:
bun test tests/server/ tests/worker/middleware/Anti-pattern guards:
What to implement:
src/server/routes/v1/*:
GET /healthzGET /v1/infoGET /v1/projectsPOST /v1/projectsGET /v1/projects/:idPOST /v1/sessions/startPOST /v1/sessions/:id/endGET /v1/sessions/:idPOST /v1/eventsPOST /v1/events/batchGET /v1/events/:idPOST /v1/memoriesGET /v1/memories/:idPATCH /v1/memories/:idPOST /v1/memories/:id/supersedePOST /v1/forgetPOST /v1/searchPOST /v1/contextGET /v1/auditPOST /v1/exportPOST /v1/importPOST /v1/reindex/api/* routes for current hooks, MCP, and viewer.zod-to-json-schema, or add a focused OpenAPI helper only if needed.Documentation references:
claude-mem-server-plan.md.Verification:
tests/server/v1/./api/sessions/init, /api/sessions/observations, /api/search, /api/context/inject still work.Anti-pattern guards:
/api/* compatibility routes in this phase.What to implement:
src/adapters/claude-code/mapper.ts to map existing hook payloads to AgentEvent.src/adapters/generic-rest/examples.ts with Codex/OpenCode/OpenClaw/custom examples.SessionRoutes ingestion to call the same event-ingestion service used by POST /v1/events.contentSessionIdtool_nametool_inputtool_responsecwdagentIdagentTypeplatformSourcetool_use_id / toolUseIdDocumentation references:
src/services/worker/http/routes/SessionRoutes.ts.src/shared/platform-source.ts.Verification:
Anti-pattern guards:
What to implement:
src/server/mcp/tools.ts, resources.ts, prompts.ts, and register.ts.src/servers/mcp-server.ts as a thin stdio entrypoint.memory_addmemory_searchmemory_contextmemory_forgetmemory_list_recentmemory_record_decisionDocumentation references:
src/servers/mcp-server.ts.tests/servers/mcp-tool-schemas.test.ts.Verification:
scripts/build-hooks.js still prevents Bun-only worker code from bloating the MCP bundle.Anti-pattern guards:
What to implement:
docker/server/Dockerfile or update docker/claude-mem/Dockerfile for server mode.docker-compose.yml with services:
claude-mem-servervalkeychroma if Chroma remains enabled in server profileCLAUDE_MEM_HOST=0.0.0.0 inside containerCLAUDE_MEM_QUEUE_ENGINE=bullmqCLAUDE_MEM_REDIS_URL=redis://valkey:6379/data/claude-memGET /healthz.Documentation references:
docker/claude-mem/Dockerfile.docker/claude-mem/README.md and entrypoint.sh.plans/2026-05-06-redis-dependency-strategy.md.Verification:
docker compose up --buildcurl http://127.0.0.1:<port>/healthzcurl -H "Authorization: Bearer <key>" http://127.0.0.1:<port>/v1/infoAnti-pattern guards:
What to implement:
docs/server.mddocs/api.mddocs/adapters.mddocs/security.mddocs/docker.mddocs/migration-worker-to-server.mdDocumentation references:
docs/public/*.mdx.Verification:
rg -n "worker service|Worker Service|worker-first" README.md docsAnti-pattern guards:
Run:
npm run typecheck:root
bun test tests/server/ tests/services/queue/ tests/services/sqlite/ tests/servers/
bun test tests/integration/worker-api-endpoints.test.ts
npm run build
docker compose up --build
Manual acceptance checklist:
npx claude-mem install still works.claude-mem server start|status|stop works.claude-mem worker start|status|stop aliases work.The order intentionally moves the middleware and queue boundaries before Better Auth and REST V1. Those two boundaries are the highest-risk coupling points in the current codebase.