Problem
After PR #1017 is merged, a powermem server instance uses a single global .env file (~/.powermem/.env) for LLM configuration. All connected programming tools (Claude Code, Cursor, Codex, OpenCode, etc.) share the same provider, model, and API key.
Users often work with multiple tools simultaneously and want each tool to use a different LLM backend — for example, Claude Code via Anthropic, Cursor via OpenAI, and Codex via DeepSeek — while still sharing a single powermem server for memory storage.
Proposed Solution
Allow a powermem server instance to serve multiple clients, each with its own LLM configuration.
Registration Flow
Client Server
│ │
│ POST /api/v1/instances │
│ { │
│ "client": "claude-code", │
│ "provider": "anthropic", │
│ "model": "claude-sonnet-4-6",│
│ "api_key": "sk-...", │
│ "base_url": "" │
│ } │
│──────────────────────────────>│
│ │ ─ generates instance_id
│ {"instance_id": "pmem-abc123"}│
│<──────────────────────────────│
│ │
│ (client saves instance_id │
│ to its plugin data dir) │
│ │
│ POST /api/v1/memories/search│
│ X-PowerMem-Instance: pmem-abc123 │
│ {"query": "..."} │
│──────────────────────────────>│ ─ looks up LLM config by instance_id
│ │ ─ uses anthropic/claude-sonnet-4-6
│ search results │
│<──────────────────────────────│
- Client calls
POST /api/v1/instances with its LLM config (provider + model + api_key + base_url).
- Server persists the config and returns an
instance_id.
- Client stores the
instance_id in its local data directory (e.g., ~/.powermem/instance.id for the Claude Code plugin).
- All subsequent requests include
X-PowerMem-Instance header. Server uses the corresponding LLM config.
- Requests without the header fall back to the global
.env config (backward compatible).
Instance ID storage per tool
| Tool |
Instance ID location |
| Claude Code plugin |
~/.powermem/instance.id |
| Cursor extension |
Extension settings / .cursor/mcp.json |
| Codex |
~/.codex/powermem-instance.id |
| OpenCode |
~/.config/opencode/powermem-instance.id |
| Generic MCP client |
Client-specific config file |
Persistence (open for design)
Option A — SQLite:
CREATE TABLE instances (
instance_id TEXT PRIMARY KEY,
client TEXT NOT NULL DEFAULT '',
provider TEXT NOT NULL,
model TEXT NOT NULL,
api_key TEXT NOT NULL,
base_url TEXT DEFAULT '',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Pros: structured, queryable, no file-locking issues.
Option B — YAML (~/.powermem/instances.yaml):
instances:
pmem-abc123:
client: claude-code
provider: anthropic
model: claude-sonnet-4-6
api_key: sk-ant-...
pmem-def456:
client: cursor
provider: openai
model: gpt-4o
api_key: sk-...
Pros: human-editable, easy to inspect/backup.
Option C — Both: check YAML first, fall back to SQLite. YAML for manual management, SQLite for API-registered instances.
Management API (open for design)
| Method |
Endpoint |
Description |
POST |
/api/v1/instances |
Register a new instance |
GET |
/api/v1/instances |
List all instances (api_key masked) |
GET |
/api/v1/instances/{id} |
Get instance details |
PUT |
/api/v1/instances/{id} |
Update instance config |
DELETE |
/api/v1/instances/{id} |
Remove an instance |
Registration endpoint (open for design)
Option A — Dedicated endpoint:
POST /api/v1/instances
{
"client": "claude-code",
"provider": "anthropic",
"model": "claude-sonnet-4-6",
"api_key": "sk-ant-...",
"base_url": ""
}
Option B — Reuse init.sh flow: The existing plugin init script already creates .env. After PR #1017, it could also call POST /api/v1/instances to register and receive an instance_id, which it stores to ~/.powermem/instance.id.
Option C — First-request implicit registration: Client sends LLM config on the first request via headers, server auto-creates an instance and returns the instance_id in the response.
Security considerations
api_key should be stored encrypted or with restricted file permissions (0600).
instance_id is not a secret — it only maps to the config; the actual auth key is the api_key stored server-side.
- List/show endpoints must mask
api_key (e.g., sk-a…b12x).
Scope
- In scope: LLM configuration per client instance (provider, model, api_key, base_url).
- Out of scope (for now): Per-instance embedder config, per-instance vector store config, multi-tenancy/isolation of memory data.
Impact
src/server/main.py — parse X-PowerMem-Instance header, inject into request context
src/powermem/config_loader.py — load LLM config per instance
apps/claude-code-plugin/scripts/init.sh — register instance on init, persist instance_id
- Storage layer — new table or config file for instance configs
.env behavior — unchanged, serves as the default/fallback
Problem
After PR #1017 is merged, a powermem server instance uses a single global
.envfile (~/.powermem/.env) for LLM configuration. All connected programming tools (Claude Code, Cursor, Codex, OpenCode, etc.) share the same provider, model, and API key.Users often work with multiple tools simultaneously and want each tool to use a different LLM backend — for example, Claude Code via Anthropic, Cursor via OpenAI, and Codex via DeepSeek — while still sharing a single powermem server for memory storage.
Proposed Solution
Allow a powermem server instance to serve multiple clients, each with its own LLM configuration.
Registration Flow
POST /api/v1/instanceswith its LLM config (provider + model + api_key + base_url).instance_id.instance_idin its local data directory (e.g.,~/.powermem/instance.idfor the Claude Code plugin).X-PowerMem-Instanceheader. Server uses the corresponding LLM config..envconfig (backward compatible).Instance ID storage per tool
~/.powermem/instance.id.cursor/mcp.json~/.codex/powermem-instance.id~/.config/opencode/powermem-instance.idPersistence (open for design)
Option A — SQLite:
Pros: structured, queryable, no file-locking issues.
Option B — YAML (
~/.powermem/instances.yaml):Pros: human-editable, easy to inspect/backup.
Option C — Both: check YAML first, fall back to SQLite. YAML for manual management, SQLite for API-registered instances.
Management API (open for design)
POST/api/v1/instancesGET/api/v1/instancesGET/api/v1/instances/{id}PUT/api/v1/instances/{id}DELETE/api/v1/instances/{id}Registration endpoint (open for design)
Option A — Dedicated endpoint:
Option B — Reuse init.sh flow: The existing plugin init script already creates
.env. After PR #1017, it could also callPOST /api/v1/instancesto register and receive aninstance_id, which it stores to~/.powermem/instance.id.Option C — First-request implicit registration: Client sends LLM config on the first request via headers, server auto-creates an instance and returns the
instance_idin the response.Security considerations
api_keyshould be stored encrypted or with restricted file permissions (0600).instance_idis not a secret — it only maps to the config; the actual auth key is theapi_keystored server-side.api_key(e.g.,sk-a…b12x).Scope
Impact
src/server/main.py— parseX-PowerMem-Instanceheader, inject into request contextsrc/powermem/config_loader.py— load LLM config per instanceapps/claude-code-plugin/scripts/init.sh— register instance on init, persist instance_id.envbehavior — unchanged, serves as the default/fallback