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:
2026-07-30 08:31:14 +00:00
co-authored by Claude Opus 5
parent 71c32b8044
commit 3da97ffe2e
6 changed files with 0 additions and 3553 deletions
-92
View File
@@ -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