remove superseded design notes
CLAUDE.md already told readers these were "older design notes" and to treat the code as
the source of truth. Keeping them is worse than that warning: they are detailed enough to
be believed, and every one of them describes an app that has since changed.
- OFFICERDEV_BACKEND.md, OFFICERDEV_FRONTEND.md — architecture snapshots from February;
CLAUDE.md and the code cover this now.
- SETUP_ANALYSIS.md — an analysis of problems in setup.sh, superseded by `bun setup`.
- event-handler-instances.md — the result of a one-off scan ("found 167 instances"),
regenerable with a grep in less time than reading it.
- HOOKS.md — a bare list of hook file paths, likewise.
- docs/per-user-api-keys.md — an architecture analysis for per-user API keys, which
contradicts the single-user hard invariant in CLAUDE.md.
Kept deliberately, though all are old: SECURITY_AUDIT.md and SECURITY_FIXES.md (a
findings record and its remediation log — not the kind of thing to bin on a hunch),
PHONE_APP.md (a native app is being built), MARKETING_WEBSITE.md and
docs/DOCKERIZATION_PLAN.md (plans that may not have been carried out yet), and
docs/jobs-unification.md.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,92 +0,0 @@
|
||||
# Per-User API Keys — Architecture Analysis
|
||||
|
||||
## Current State
|
||||
|
||||
- Single shared `auth.json` at `~/.pi/agent/auth.json` (server-side)
|
||||
- Pi CLI supports `--api-key` flag — we already use this in `pi-bridge.ts` via `resolveApiKeyForModel()`
|
||||
- User settings have unused fields: `ai.enabledModels`, `ai.enabledProviders`, `ai.disabledProviders`
|
||||
- 13 providers supported: anthropic, openai, google, groq, mistral, xai, openrouter, minimax, huggingface, azure-openai-responses, opencode, zai, cerebras
|
||||
|
||||
## Architecture
|
||||
|
||||
### Layer 1: Key Resolution
|
||||
|
||||
**Precedence:** User key > System key > fail
|
||||
|
||||
- Store user keys in `user_settings.ai.apiKeys` (JSONB column, no new DB table needed)
|
||||
- Format: `{ "ai": { "apiKeys": { "openai": "sk-...", "anthropic": "sk-ant-..." } } }`
|
||||
- `resolveApiKeyForModel()` in `pi-bridge.ts` checks user keys first, falls back to system `auth.json`
|
||||
- Key passed to Pi via `--api-key` CLI flag (already implemented for system keys)
|
||||
- Keys never touch the container filesystem — all resolution is server-side
|
||||
|
||||
### Layer 2: Model Visibility
|
||||
|
||||
- System access policy defines base available providers/models
|
||||
- User's own provider keys unlock additional providers
|
||||
- Existing `enabledProviders`/`enabledModels` settings fields drive filtering
|
||||
- Model listing becomes a union: system models + user's provider models
|
||||
|
||||
## Key Design Decisions
|
||||
|
||||
1. **No new DB table** — use existing `user_settings` JSONB column
|
||||
2. **No per-user auth.json files** — all key resolution server-side via `--api-key` flag
|
||||
3. **Eventually remove PI_CONFIG_DIR mount** — auth.json in container no longer needed for keys (still needed for local providers/models.json)
|
||||
4. **Model listing = union** of system + user models
|
||||
|
||||
## What This Enables
|
||||
|
||||
- Admin deploys with their keys → all users can chat
|
||||
- User adds their own key → gets access to that provider
|
||||
- User's key takes priority (user pays for their own usage)
|
||||
- No credential leakage (keys in DB, passed as CLI args, never on container filesystem)
|
||||
|
||||
## Files to Change
|
||||
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `src/servers/api/pi/pi-bridge.ts` | Update `resolveApiKeyForModel()` to check user settings first |
|
||||
| `src/servers/api/settings/settings.ts` | API endpoint for saving/deleting user API keys (encrypted at rest ideally) |
|
||||
| `src/workspaces/state/src/useSettings.ts` | Add `ai.apiKeys` to `UserSettings` type |
|
||||
| `src/servers/api/pi/list-models.ts` | Union system + user provider models |
|
||||
| `src/workspaces/officerdev/src/hooks/usePiModels.ts` | Filter models based on user's available providers |
|
||||
| `src/apps/officer-web/Screens/Dashboard/Settings/ProfileSettings/AIModels.tsx` | UI for managing per-user API keys |
|
||||
| `src/servers/api/server-settings/pi-mono.ts` | Distinguish admin vs user key management |
|
||||
|
||||
## Deep-Dive: Pi CLI & Auth
|
||||
|
||||
### CLI Flags
|
||||
- `--provider` — force provider
|
||||
- `--model` — force model (format: `provider/model-name`)
|
||||
- `--api-key` — force API key (takes precedence over auth.json and env vars)
|
||||
- `--system-prompt` — system prompt
|
||||
|
||||
### Supported Environment Variables
|
||||
`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, `GROQ_API_KEY`, `MISTRAL_API_KEY`, `XAI_API_KEY`, `OPENROUTER_API_KEY`, etc.
|
||||
|
||||
### auth.json Format
|
||||
```json
|
||||
{
|
||||
"provider_id": {
|
||||
"type": "api_key",
|
||||
"key": "sk-..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Key Resolution Precedence (inside Pi)
|
||||
`--api-key` flag > auth.json entry > environment variable > built-in providers
|
||||
|
||||
### Pi Spawn Flow (pi-bridge.ts)
|
||||
1. Determine model from user settings or default
|
||||
2. `resolveApiKeyForModel(model)` extracts provider from `provider/model-name`
|
||||
3. Looks up key in auth.json (currently system-level only)
|
||||
4. Passes `--api-key <key>` when spawning Pi process
|
||||
5. Container never sees raw credentials
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
1. **Add key storage** — extend `UserSettings` type, add API endpoint for CRUD
|
||||
2. **Update key resolution** — `resolveApiKeyForModel(model, userId?)` checks user DB first
|
||||
3. **Update model listing** — merge system models with user-unlocked provider models
|
||||
4. **Build settings UI** — API key input per provider in AI settings page
|
||||
5. **Remove PI_CONFIG_DIR mount** (later) — once models.json is also handled server-side
|
||||
Reference in New Issue
Block a user