@legioncodeinc/rflectr 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -5
- package/dist/cli.js +4 -1
- package/dist/cli.js.map +1 -0
- package/package.json +4 -1
- package/.markdown-link-check.json +0 -7
- package/AGENTS.md +0 -169
- package/assets/733630021_1421561133353555_3999689754075308337_n.jpg +0 -0
- package/assets/github-home-image.png +0 -0
- package/assets/og-image.jpg +0 -0
- package/assets/og-image.png +0 -0
- package/assets/og-image.psd +0 -0
- package/assets/rflectr-no-bg.png +0 -0
- package/assets/vertex-models.example.json +0 -14
- package/library/README.md +0 -39
- package/library/issues/README.md +0 -46
- package/library/issues/backlog/README.md +0 -26
- package/library/issues/completed/README.md +0 -13
- package/library/issues/in-work/README.md +0 -13
- package/library/knowledge/README.md +0 -34
- package/library/knowledge/private/README.md +0 -40
- package/library/knowledge/private/ai/README.md +0 -8
- package/library/knowledge/private/ai/model-discovery-classification.md +0 -81
- package/library/knowledge/private/ai/translation-layer.md +0 -88
- package/library/knowledge/private/architecture/README.md +0 -10
- package/library/knowledge/private/architecture/launch-flow-claude.md +0 -93
- package/library/knowledge/private/architecture/system-overview.md +0 -108
- package/library/knowledge/private/auth/README.md +0 -9
- package/library/knowledge/private/auth/oauth-device-flows.md +0 -95
- package/library/knowledge/private/data/README.md +0 -8
- package/library/knowledge/private/data/preferences-config.md +0 -87
- package/library/knowledge/private/data/provider-registry.md +0 -126
- package/library/knowledge/private/infrastructure/README.md +0 -7
- package/library/knowledge/private/infrastructure/server-gateway.md +0 -87
- package/library/knowledge/private/integrations/README.md +0 -8
- package/library/knowledge/private/integrations/harnesses.md +0 -87
- package/library/knowledge/private/integrations/local-proxy.md +0 -82
- package/library/knowledge/private/security/README.md +0 -9
- package/library/knowledge/private/security/credential-storage.md +0 -129
- package/library/knowledge/private/standards/documentation-framework.md +0 -154
- package/library/knowledge/public/README.md +0 -49
- package/library/knowledge/public/faqs/README.md +0 -7
- package/library/knowledge/public/faqs/troubleshooting.md +0 -92
- package/library/knowledge/public/guides/README.md +0 -13
- package/library/knowledge/public/guides/ai-agents.md +0 -273
- package/library/knowledge/public/guides/api-server.md +0 -108
- package/library/knowledge/public/guides/claude-desktop.md +0 -382
- package/library/knowledge/public/guides/codex.md +0 -296
- package/library/knowledge/public/guides/gemini-cli.md +0 -105
- package/library/knowledge/public/guides/model-compatibility.md +0 -80
- package/library/knowledge/public/guides/providers.md +0 -90
- package/library/knowledge/public/overview/README.md +0 -7
- package/library/knowledge/public/overview/what-is-rflectr.md +0 -71
- package/library/notes/README.md +0 -21
- package/library/requirements/README.md +0 -51
- package/library/requirements/backlog/README.md +0 -30
- package/library/requirements/completed/README.md +0 -14
- package/library/requirements/completed/prd-001-cli-core-launch-orchestration/prd-001-cli-core-launch-orchestration-index.md +0 -205
- package/library/requirements/completed/prd-001-cli-core-launch-orchestration/qa/.gitkeep +0 -0
- package/library/requirements/completed/prd-002-provider-registry/qa/.gitkeep +0 -0
- package/library/requirements/completed/prd-003-model-discovery-classification/qa/.gitkeep +0 -0
- package/library/requirements/completed/prd-004-translation-layer/qa/.gitkeep +0 -0
- package/library/requirements/completed/prd-005-local-proxy-catalog-routing/qa/.gitkeep +0 -0
- package/library/requirements/completed/prd-007-oauth-device-flows/qa/.gitkeep +0 -0
- package/library/requirements/completed/prd-011-claude-desktop-integration/qa/.gitkeep +0 -0
- package/library/requirements/in-work/README.md +0 -19
- package/library/requirements/reports/README.md +0 -31
- package/scripts/refresh-models-dev-cache.mjs +0 -34
- package/test-proxy.ts +0 -19
- package/test-split.js +0 -1
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
# The Server Gateway
|
|
2
|
-
|
|
3
|
-
> Category: Infrastructure | Version: 1.0 | Date: June 2026 | Status: Active
|
|
4
|
-
|
|
5
|
-
`rflectr server` runs a long-lived HTTP gateway that exposes registry/Zen/Go providers (or Claude on Vertex AI) behind Anthropic- and OpenAI-compatible endpoints. It's the backend for Claude Desktop and any tool that can point at a base URL. Read [`../ai/translation-layer.md`](../ai/translation-layer.md) for the translation it reuses.
|
|
6
|
-
|
|
7
|
-
**Related:**
|
|
8
|
-
- [`../integrations/harnesses.md`](../integrations/harnesses.md)
|
|
9
|
-
- [`../ai/translation-layer.md`](../ai/translation-layer.md)
|
|
10
|
-
- [`../security/credential-storage.md`](../security/credential-storage.md)
|
|
11
|
-
- Source: `src/server/` (`index.ts`, `router.ts`, `models.ts`, `vendor-mask.ts`, `vertex-config.ts`, `auth.ts`, `catalog-filter.ts`, `provider-select.ts`, `prompts.ts`)
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## What it is
|
|
16
|
-
|
|
17
|
-
Where the launch commands are short-lived (start a proxy, run a child, tear down), `server` is a **foreground daemon**. `runServerCommand(options)` (`src/server/index.ts`) runs an interactive wizard (which providers to expose, optional favorites-only catalog, discovery-id masking, local vs network bind) and then `startServer()` (`src/server/router.ts`) listens on port **17645**.
|
|
18
|
-
|
|
19
|
-
It serves the same translation core as the CLI proxies — `handleAnthropicMessages` and `handleOpenAIChatCompletions` both end at `createLanguageModel` + the SDK adapter for openai-format models, or a raw forward for anthropic-format models, with a per-`(model × npm × baseURL)` `LanguageModel` cache.
|
|
20
|
-
|
|
21
|
-
```mermaid
|
|
22
|
-
flowchart TD
|
|
23
|
-
client["Claude Desktop / any tool"] --> ep{"endpoint"}
|
|
24
|
-
ep -->|"POST /anthropic/v1/messages"| anth["handleAnthropicMessages"]
|
|
25
|
-
ep -->|"POST /openai/v1/chat/completions"| oai["handleOpenAIChatCompletions"]
|
|
26
|
-
ep -->|"GET /models, /anthropic/v1/models, /openai/v1/models"| list["catalog (apiKey stripped)"]
|
|
27
|
-
ep -->|"GET /health"| health["{ ok: true }"]
|
|
28
|
-
anth --> fmt{"modelFormat"}
|
|
29
|
-
oai --> fmt
|
|
30
|
-
fmt -->|anthropic| raw["raw forward {baseUrl}/v1/messages"]
|
|
31
|
-
fmt -->|openai| sdk["SDK adapter"]
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
---
|
|
35
|
-
|
|
36
|
-
## Endpoints
|
|
37
|
-
|
|
38
|
-
| Method + path | Purpose |
|
|
39
|
-
|---|---|
|
|
40
|
-
| `GET /health` | `{ ok: true }` |
|
|
41
|
-
| `GET /models` | Raw catalog, `apiKey` stripped |
|
|
42
|
-
| `GET /anthropic/v1/models` | Anthropic-format list (optionally masked) |
|
|
43
|
-
| `GET /openai/v1/models` | OpenAI-format list |
|
|
44
|
-
| `POST /anthropic/v1/messages` | Anthropic Messages relay |
|
|
45
|
-
| `POST /openai/v1/chat/completions` | OpenAI Chat Completions relay |
|
|
46
|
-
|
|
47
|
-
Base URLs for clients:
|
|
48
|
-
|
|
49
|
-
- Anthropic: `ANTHROPIC_BASE_URL=http://127.0.0.1:17645/anthropic`
|
|
50
|
-
- OpenAI: `OPENAI_BASE_URL=http://127.0.0.1:17645/openai/v1`
|
|
51
|
-
|
|
52
|
-
---
|
|
53
|
-
|
|
54
|
-
## Model catalog & gateway aliases
|
|
55
|
-
|
|
56
|
-
`loadServerModels()` (`src/server/index.ts`) assembles `ServerModelInfo[]` from Zen/Go models plus every materialized local provider, enriching each with reasoning metadata (`enrichServerModelReasoning` adds `defaultEffort`). `createGatewayModelCatalog(models, opts?)` (`src/server/models.ts`) builds a bidirectional lookup keyed by `model.id` and by gateway alias.
|
|
57
|
-
|
|
58
|
-
Helpers in `src/server/models.ts`:
|
|
59
|
-
|
|
60
|
-
- `gatewayAliasId(model)` / `exposedGatewayAliasId(model, opts?)` — canonical alias `anthropic-{provider}__{model}` (via `aliasModelId`), masked or not.
|
|
61
|
-
- `gatewayDisplayName(model, opts?)` — "Model Name" or "Model Name (Provider Label)" when masked.
|
|
62
|
-
- `upstreamModelId(model)` — strips the `[1m]` context suffix for the wire call.
|
|
63
|
-
- `formatGatewayAnthropicModels` / `formatOpenAIModels` — endpoint payloads.
|
|
64
|
-
|
|
65
|
-
Filtering (`src/server/catalog-filter.ts`): `filterServerModelsByProviders`, `filterServerModelsByFavorites`, `summarizeServerProviders` (human summary like "OpenCode Zen (5), Groq (3)").
|
|
66
|
-
|
|
67
|
-
### Discovery-id masking
|
|
68
|
-
|
|
69
|
-
For Claude Desktop / Cowork, exposing raw vendor model ids may be undesirable. When the wizard enables masking (`gateway.maskGatewayIds = true`), `maskGatewayModelId(aliasId)` (`src/server/vendor-mask.ts`) reverses the provider-slug and model-suffix segments to hide vendor names; it is **self-inverse** (`unmaskGatewayModelId` is the same operation). The response `model` field is also set to the masked `gatewayDisplayName`. Example: `anthropic-openai__gpt-4o` → a reversed-segment alias.
|
|
70
|
-
|
|
71
|
-
---
|
|
72
|
-
|
|
73
|
-
## Vertex AI mode (`--vertex`)
|
|
74
|
-
|
|
75
|
-
`rflectr server --vertex` exposes **Claude on Google Vertex AI** using local gcloud Application Default Credentials — no OpenCode API key. `src/server/vertex-config.ts`:
|
|
76
|
-
|
|
77
|
-
- `buildVertexRuntimeConfig(env?)` reads the project (`ANTHROPIC_VERTEX_PROJECT_ID` → `GOOGLE_CLOUD_PROJECT` → `GOOGLE_VERTEX_PROJECT`) and location (`GOOGLE_CLOUD_LOCATION` → `CLOUD_ML_REGION` → `GOOGLE_VERTEX_LOCATION` → `global`).
|
|
78
|
-
- `hasApplicationDefaultCredentials()` checks `GOOGLE_APPLICATION_CREDENTIALS` or `~/.config/gcloud/application_default_credentials.json`.
|
|
79
|
-
- `vertexModelsToServerModels(config)` / `createVertexModelCatalog(models)` build the catalog with short aliases (`sonnet` / `haiku` / `opus`) and `[1m]` context variants. Defaults: `claude-sonnet-4-6`, `claude-opus-4-6`, `claude-haiku-4-5`. An optional catalog override lives at `~/.rflectr/vertex-models.json` (see `assets/vertex-models.example.json`).
|
|
80
|
-
|
|
81
|
-
The models route through `@ai-sdk/google-vertex/anthropic` (`VERTEX_ANTHROPIC_NPM`) — see [`../ai/translation-layer.md`](../ai/translation-layer.md).
|
|
82
|
-
|
|
83
|
-
---
|
|
84
|
-
|
|
85
|
-
## Auth
|
|
86
|
-
|
|
87
|
-
`isAuthorized(request, serverPassword)` (`src/server/auth.ts`) accepts a `Bearer` token or `x-api-key` header and compares it to the configured server password. A `null` password (local mode) allows all callers. `extractBearerToken` and `sanitizeCredential` (first-line only) harden header parsing. In **network mode** the wizard requires a server password; it is the only gate once the port is reachable beyond localhost, so treat it as a real secret. See [`../security/credential-storage.md`](../security/credential-storage.md#server-mode-caveat).
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
# Integrations
|
|
2
|
-
|
|
3
|
-
The local proxy and the per-host harness wiring.
|
|
4
|
-
|
|
5
|
-
| Doc | Covers |
|
|
6
|
-
|---|---|
|
|
7
|
-
| [`local-proxy.md`](local-proxy.md) | The throwaway `127.0.0.1` proxy, `ProxyRoute` dispatch, `aliasModelId`, shared translation helpers. |
|
|
8
|
-
| [`harnesses.md`](harnesses.md) | Codex CLI/desktop, Gemini CLI, Claude Desktop — how each host is pointed at a translating proxy; macOS/Windows differences. |
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
# Host Harnesses: Codex, Gemini, and the Desktop Apps
|
|
2
|
-
|
|
3
|
-
> Category: Integrations | Version: 1.0 | Date: June 2026 | Status: Active
|
|
4
|
-
|
|
5
|
-
How `rflectr` wires each non-Claude-Code host to a translating proxy. The Claude Code flow is in [`../architecture/launch-flow-claude.md`](../architecture/launch-flow-claude.md); this doc covers Codex CLI, Codex desktop, Gemini CLI, and Claude Desktop. Read [`local-proxy.md`](local-proxy.md) first.
|
|
6
|
-
|
|
7
|
-
**Related:**
|
|
8
|
-
- [`local-proxy.md`](local-proxy.md)
|
|
9
|
-
- [`../infrastructure/server-gateway.md`](../infrastructure/server-gateway.md)
|
|
10
|
-
- [`../ai/translation-layer.md`](../ai/translation-layer.md)
|
|
11
|
-
- Source: `src/codex.ts`, `src/codex/`, `src/codex-app.ts`, `src/codex-proxy.ts`, `src/codex-responses-adapter.ts`, `src/gemini.ts`, `src/gemini/`, `src/gemini-proxy.ts`, `src/claude-app.ts`, `src/claude-desktop/`
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## The pattern, and where each host departs from it
|
|
16
|
-
|
|
17
|
-
Every host follows the same skeleton: find the binary → resolve provider+model → start a proxy that speaks the host's wire format → launch the child with env (CLIs) or a patched config (apps) pointing at the proxy → restore/cleanup on exit. The differences are in *how the host is pointed at the proxy* and *whether config files must be written and restored*.
|
|
18
|
-
|
|
19
|
-
```mermaid
|
|
20
|
-
flowchart TD
|
|
21
|
-
cli["CLI hosts (codex, gemini)"] -->|env var| proxy["translating proxy"]
|
|
22
|
-
app["Desktop apps (codex-app, claude-app)"] -->|patched config file + backup| proxy
|
|
23
|
-
proxy --> adapter["Vercel AI SDK adapter"]
|
|
24
|
-
app -.->|lock file| restore["restore original config on exit"]
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
## Codex CLI — `rflectr codex`
|
|
30
|
-
|
|
31
|
-
Entry: `runCodexCommand` (`src/codex.ts`). Codex speaks the **OpenAI Responses API**.
|
|
32
|
-
|
|
33
|
-
- **Binary:** `findCodexBinary()` (`src/codex/launch.ts`).
|
|
34
|
-
- **Proxy:** `startCodexProxy(routes, { requireAuth: true })` (`src/codex-proxy.ts`) serves `POST /v1/responses`, translating through `src/codex-responses-adapter.ts` (`translateResponsesRequest` → SDK params; `streamResponsesResponse` / `generateResponsesResponse` → Responses SSE/JSON).
|
|
35
|
-
- **Profile:** a TOML overlay (`buildCodexProfileToml`, `src/codex/profile.ts`) written to `~/.codex/rflectr-launch.config.toml`. It defines a `model_providers.rflectr-proxy` block whose `base_url = http://127.0.0.1:<port>/v1`, `wire_api = "responses"`, and `env_key = "RFLECTR_CODEX_KEY"`. Codex is launched with `--profile rflectr-launch -m <modelId>`.
|
|
36
|
-
- **Catalog:** `~/.rflectr/codex/models-<providerId>.json` (single) or `models-favorites.json` (favorites mode), via `src/codex/catalog.ts`.
|
|
37
|
-
- **Env:** `RFLECTR_CODEX_KEY=proxy-local` for proxy-tier routes; direct providers get their real key via `codexProviderEnvKey()` (`src/codex/routing.ts`).
|
|
38
|
-
- **Sandbox:** default `danger-full-access` (`CODEX_LAUNCH_SANDBOX`, `src/codex/profile.ts`).
|
|
39
|
-
|
|
40
|
-
**Favorites catalog mode:** when `prefs.favoriteModels.length > 0`, Codex resolves each favorite via the shared `src/favorites-resolver.ts` (filtering by an `agent: 'codex'` blacklist — Zen/Go favorites are skipped, since Codex has no gateway path for them), builds a `CodexProxyRoute[]`, and starts a single multi-route proxy. Catalog slugs are `${providerId}__${modelId}`.
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
|
|
44
|
-
## Codex desktop app — `rflectr codex-app`
|
|
45
|
-
|
|
46
|
-
Entry: `runCodexAppCommand` (`src/codex-app.ts`). The app can't inherit env, so its config is patched in place and restored on exit.
|
|
47
|
-
|
|
48
|
-
- **Config patch:** `applyAppConfigPatch` (`src/codex/app-config.ts`) edits `~/.codex/config.toml`, writing `model`, `model_provider = 'openai'`, `openai_base_url`, `model_catalog_json`, and `model_context_window` (`buildCodexAppRootConfig`, `src/codex/app-profile.ts`). Display model defaults to `CODEX_APP_DISPLAY_MODEL = 'gpt-5.5'`.
|
|
49
|
-
- **Backup + lock:** the original `config.toml` is copied to `config.toml.bak`; a lock file `~/.codex/.rflectr.lock.json` records `pid`, `configPath`, `catalogPaths`, `backupPath`, and `proxyPort`. `restoreCodexAppOverlay` (`src/codex/app-session.ts`) restores the backup on exit or recovery.
|
|
50
|
-
- **Catalog:** `app-models-<providerId>.json` / `app-models-favorites.json`.
|
|
51
|
-
- **Proxy:** same `startCodexProxy`, but `requireAuth: false` (the app cannot send the proxy token).
|
|
52
|
-
- **`--restore`** globs `app-models-*.json` to clean up prior sessions.
|
|
53
|
-
|
|
54
|
-
---
|
|
55
|
-
|
|
56
|
-
## Gemini CLI — `rflectr gemini`
|
|
57
|
-
|
|
58
|
-
Entry: `runGeminiCommand` (`src/gemini.ts`). Gemini speaks the **Gemini REST protocol**, and every model is routed through the proxy.
|
|
59
|
-
|
|
60
|
-
- **Binary:** `findGeminiBinary()` (`src/gemini/launch.ts`).
|
|
61
|
-
- **Proxy:** `startGeminiProxy(routes, debug?)` (`src/gemini-proxy.ts`) serves `GET /v1beta/models`, `GET /v1beta/models/<model>`, and `POST /v1beta/models/<model>:generateContent` / `:streamGenerateContent`. `translateGeminiRequest` extracts the system instruction, contents, tools, and generation config, and strips the Gemini-CLI-injected identity. Parts are parsed by `src/gemini-parts.ts`.
|
|
62
|
-
- **Env:** `buildGeminiChildEnv` (`src/gemini/launch.ts`) sets `GOOGLE_GEMINI_BASE_URL=http://127.0.0.1:<port>` and `GEMINI_API_KEY=<random proxy token>`, and clears conflicting `GOOGLE_GENAI_API_KEY` / `GOOGLE_API_KEY`.
|
|
63
|
-
- **Mid-session switch:** the proxy intercepts a `.model <id>` command to switch routes without restarting.
|
|
64
|
-
|
|
65
|
-
---
|
|
66
|
-
|
|
67
|
-
## Claude Desktop — `rflectr claude-app`
|
|
68
|
-
|
|
69
|
-
Entry: `runClaudeAppCommand` (`src/claude-app.ts`). Claude Desktop has a first-class "inference gateway" config, so instead of a per-protocol proxy it is pointed at the full **`server` gateway** (see [`../infrastructure/server-gateway.md`](../infrastructure/server-gateway.md)).
|
|
70
|
-
|
|
71
|
-
- **App discovery/launch:** `src/claude-desktop/app-launch.ts` finds `Claude.app` (macOS) or `Claude.exe` (Windows) and `launchOrRestartClaudeApp()`. macOS/Windows only (`claudeAppSupported()`).
|
|
72
|
-
- **Gateway injection:** a config `<uuid>.json` is written into the Claude Desktop **3P config library** — `~/Library/Application Support/Claude-3p/configLibrary/` (macOS) or `%LOCALAPPDATA%\Claude-3p\configLibrary\` (Windows) — with `inferenceProvider: 'gateway'`, `inferenceGatewayBaseUrl: http://127.0.0.1:<port>/anthropic`, `inferenceGatewayApiKey: 'dummy'`, `inferenceGatewayAuthScheme: 'bearer'`, and `coworkEgressAllowedHosts`. A `_meta.json` points `appliedId` at the new uuid (`src/claude-desktop/app-config.ts`).
|
|
73
|
-
- **Backup + lock:** `_meta.json.bak` is created before the patch; a `.rflectr.lock` records `pid`, `uuid`, `proxyPort`. On exit or recovery, `cleanupSession(uuid)` / `recoverSession()` (`src/claude-desktop/app-session.ts`) restore the backup and remove the injected config.
|
|
74
|
-
- **Gateway:** the in-process `startServer()` serves `/anthropic` with `createGatewayModelCatalog()`; favorites filter via `filterServerModelsByFavorites`, or a single selected model.
|
|
75
|
-
|
|
76
|
-
---
|
|
77
|
-
|
|
78
|
-
## Platform differences (apps)
|
|
79
|
-
|
|
80
|
-
| Concern | macOS | Windows |
|
|
81
|
-
|---|---|---|
|
|
82
|
-
| Claude Desktop config root | `~/Library/Application Support/Claude-3p/` | `%LOCALAPPDATA%\Claude-3p\` |
|
|
83
|
-
| App launch | `open` / `open -b <bundle id>` | direct `.exe` exec / registry lookup |
|
|
84
|
-
| "Is it running?" | `osascript` | PowerShell `Get-Process` |
|
|
85
|
-
| CLI binary discovery | `which` + fallbacks | `where` + `.cmd` priority + `%APPDATA%\npm\` |
|
|
86
|
-
|
|
87
|
-
All proxies bind `127.0.0.1:0` on both platforms (Node `http.createServer`).
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
# The Local Proxy
|
|
2
|
-
|
|
3
|
-
> Category: Integrations | Version: 1.0 | Date: June 2026 | Status: Active
|
|
4
|
-
|
|
5
|
-
The throwaway HTTP server that sits between a host tool and the upstream model. This doc covers `src/proxy.ts` (the Anthropic-facing proxy) and its routing model; the Codex and Gemini variants are summarized in [`harnesses.md`](harnesses.md). Read [`../ai/translation-layer.md`](../ai/translation-layer.md) for what the proxy delegates to.
|
|
6
|
-
|
|
7
|
-
**Related:**
|
|
8
|
-
- [`harnesses.md`](harnesses.md)
|
|
9
|
-
- [`../ai/translation-layer.md`](../ai/translation-layer.md)
|
|
10
|
-
- [`../architecture/launch-flow-claude.md`](../architecture/launch-flow-claude.md)
|
|
11
|
-
- Source: `src/proxy.ts`, `src/proxy-shared.ts`, `src/proxy-types.ts`, `src/upstream-forward.ts`
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## What it is
|
|
16
|
-
|
|
17
|
-
A local HTTP server on `127.0.0.1:<random ephemeral port>` (bind to port `0`, let the OS choose) that accepts Anthropic-format requests at `/v1/messages` and serves a synthetic `GET /v1/models`. The host tool is pointed at it via `ANTHROPIC_BASE_URL=http://127.0.0.1:<port>`. It is created at launch and torn down (`proxyHandle.close()`) when the host process exits.
|
|
18
|
-
|
|
19
|
-
Two entry points:
|
|
20
|
-
|
|
21
|
-
- `startProxy(completionsUrl, modelId, debug, contextWindow?, sdk?, apiKey?)` — single-model wrapper.
|
|
22
|
-
- `startProxyCatalog(routes, startingAliasId, debug)` — multi-route catalog for switch-menu sessions.
|
|
23
|
-
|
|
24
|
-
`startProxy` is just `startProxyCatalog` with one route. Both return a `ProxyHandle` (`{ port, token, close() }`); the `token` becomes the child's `ANTHROPIC_API_KEY`, so only the launched child can call the proxy.
|
|
25
|
-
|
|
26
|
-
---
|
|
27
|
-
|
|
28
|
-
## Per-request dispatch
|
|
29
|
-
|
|
30
|
-
```mermaid
|
|
31
|
-
flowchart TD
|
|
32
|
-
req["POST /v1/messages (Anthropic format)"]
|
|
33
|
-
req --> lookup["resolve ProxyRoute by model id (alias or real)"]
|
|
34
|
-
lookup --> fmt{"route.modelFormat"}
|
|
35
|
-
fmt -->|anthropic| fwd["relayAnthropicMessages() → {baseUrl}/v1/messages (raw)"]
|
|
36
|
-
fmt -->|"openai (else)"| sdkguard{"isSdkMigratedNpm(route.npm)"}
|
|
37
|
-
sdkguard -->|true| adapter["createLanguageModel + sdk-adapter stream/generate"]
|
|
38
|
-
fwd --> resp["Anthropic SSE / JSON back to host"]
|
|
39
|
-
adapter --> resp
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
Each `ProxyRoute` carries everything needed to serve it: `aliasId`, `realModelId`, `displayName`, `upstreamUrl` / `baseURL`, `apiKey`, `modelFormat`, `contextWindow`, `npm`, `providerId`, `authType`, `oauthAccountId`, `supportedParameters`, `reasoning`, `interleavedReasoningField`.
|
|
43
|
-
|
|
44
|
-
- `modelFormat === 'anthropic'` → direct passthrough via `relayAnthropicMessages` (`src/upstream-forward.ts`), which builds Anthropic auth headers (`anthropicUpstreamHeaders`) and relays both streaming and non-streaming.
|
|
45
|
-
- otherwise → the SDK adapter (`createLanguageModel` + `streamAnthropicResponse` / `generateAnthropicResponse`).
|
|
46
|
-
|
|
47
|
-
`src/upstream-forward.ts` is shared by both the proxy and the `server` command's router, so the raw-forward path is identical in both. `UpstreamUnreachableError` distinguishes a network failure from an upstream error response.
|
|
48
|
-
|
|
49
|
-
---
|
|
50
|
-
|
|
51
|
-
## aliasModelId — making ids gateway-safe
|
|
52
|
-
|
|
53
|
-
Claude Code's gateway model discovery rejects model ids that don't look like provider-prefixed gateway ids. `aliasModelId(realId, providerId)` (`src/proxy.ts`) rewrites any non-`claude-*` id to the form `anthropic-{provider}__{id}` (e.g. `anthropic-opencode-go__deepseek-v4-flash`). `claude-*` ids pass through unchanged. This is why, after a switch-menu session, a bare `claude` may show a relay alias in `/model` — Claude Code cached the gateway id (see [`../security/credential-storage.md`](../security/credential-storage.md)).
|
|
54
|
-
|
|
55
|
-
The synthetic `GET /v1/models` returns one entry per route, each formatted by `formatAnthropicModelEntry` with `context_window` so the host's status bar is accurate (single-model mode only; the gateway-discovery payload carries no window).
|
|
56
|
-
|
|
57
|
-
---
|
|
58
|
-
|
|
59
|
-
## Shared translation helpers
|
|
60
|
-
|
|
61
|
-
`src/proxy-shared.ts` holds the format-agnostic glue reused across the Anthropic, Responses, and Gemini proxies:
|
|
62
|
-
|
|
63
|
-
- `sseChunk()` — formats one SSE event.
|
|
64
|
-
- `encodeToolUseId()` / `splitToolUseId()` — round-trip a `thought_signature` through a tool-use id as `{id}::ts::{signature}` (see [`../ai/translation-layer.md`](../ai/translation-layer.md#the-thought_signature-round-trip)).
|
|
65
|
-
- `grabRoundTripSignature()` — pull the Google/OpenAI signature off a stream part.
|
|
66
|
-
- `parseToolArguments()` — tolerant JSON parse of tool-call args.
|
|
67
|
-
- `serializeToolResultContent()` — normalize tool-result content blocks.
|
|
68
|
-
- `silenceSdkWarnings()` — suppress noisy SDK debug logging.
|
|
69
|
-
- `FullStreamPart` — the unified stream-chunk type the adapters map onto.
|
|
70
|
-
|
|
71
|
-
`src/proxy-types.ts` defines the Anthropic and Gemini request/response shapes (`AnthropicMessageRequest`, `AnthropicContentBlock`, `GeminiPart`, `GeminiFunctionCall`, …).
|
|
72
|
-
|
|
73
|
-
---
|
|
74
|
-
|
|
75
|
-
## Variants
|
|
76
|
-
|
|
77
|
-
The Codex and Gemini hosts speak different wire formats, so they have sibling proxies that share `proxy-shared.ts` and `provider-factory.ts` but expose different endpoints:
|
|
78
|
-
|
|
79
|
-
- `src/codex-proxy.ts` — `startCodexProxy(routes, { requireAuth })`, endpoint `POST /v1/responses`, uses `src/codex-responses-adapter.ts`.
|
|
80
|
-
- `src/gemini-proxy.ts` — `startGeminiProxy(routes, debug?)`, endpoints `GET /v1beta/models` and `POST /v1beta/models/<model>:generateContent` / `:streamGenerateContent`.
|
|
81
|
-
|
|
82
|
-
See [`harnesses.md`](harnesses.md) for how each host is wired to its proxy.
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
# Security
|
|
2
|
-
|
|
3
|
-
Credential handling, environment isolation, and trust boundaries.
|
|
4
|
-
|
|
5
|
-
| Doc | Covers |
|
|
6
|
-
|---|---|
|
|
7
|
-
| [`credential-storage.md`](credential-storage.md) | Keyring accounts, credential resolution order, the `buildChildEnv` contract (set/removed vars), per-platform key setup, trust boundaries, server-mode caveat. |
|
|
8
|
-
|
|
9
|
-
For the OAuth sign-in flows that produce stored tokens, see [`../auth/oauth-device-flows.md`](../auth/oauth-device-flows.md).
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
# Credential Storage & Environment Isolation
|
|
2
|
-
|
|
3
|
-
> Category: Security | Version: 1.0 | Date: June 2026 | Status: Active
|
|
4
|
-
|
|
5
|
-
Where secrets live, how they're resolved at launch, and the exact environment contract handed to each child process. This is the security-critical surface of `rflectr`. Read [`../architecture/system-overview.md`](../architecture/system-overview.md) first.
|
|
6
|
-
|
|
7
|
-
**Related:**
|
|
8
|
-
- [`../auth/oauth-device-flows.md`](../auth/oauth-device-flows.md)
|
|
9
|
-
- [`../data/provider-registry.md`](../data/provider-registry.md)
|
|
10
|
-
- [`../architecture/launch-flow-claude.md`](../architecture/launch-flow-claude.md)
|
|
11
|
-
- Source: `src/env.ts`, `src/key-setup.ts`, `src/constants.ts`
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## Where secrets live
|
|
16
|
-
|
|
17
|
-
Secrets are **never** written to `providers.json` or `config.json`. Those files hold only an `authRef` pointer. The actual secret lives in one of three places, resolved in priority order by `resolveProviderCredential(providerId, authRef)` (`src/env.ts`):
|
|
18
|
-
|
|
19
|
-
1. **Env var** — `RFLECTR_KEY_<PROVIDER_ID_UPPER>` (highest priority), or whatever `env:VAR_NAME` the `authRef` names (e.g. `env:OPENCODE_API_KEY`).
|
|
20
|
-
2. **OS keyring** — via `@napi-rs/keyring`, service `rflectr`. Accounts:
|
|
21
|
-
- `provider:<id>` — an API key.
|
|
22
|
-
- `oauth:provider:<id>` — a JSON `StoredOAuthCredential` (see [`../auth/oauth-device-flows.md`](../auth/oauth-device-flows.md)).
|
|
23
|
-
- `global:opencode` — the shared OpenCode Zen/Go key.
|
|
24
|
-
3. **Legacy keyring entries** — `rflectr` / `opencode-starter` accounts, auto-migrated on first successful read.
|
|
25
|
-
|
|
26
|
-
`@napi-rs/keyring` is an `optionalDependency` loaded via dynamic `import()`, so a missing native binary degrades gracefully rather than crashing. `classifyKeyringError(err)` turns native failures into human messages ("Secret Service daemon is not running", "keychain access was denied or the keychain is locked", "native keyring module not available", …).
|
|
27
|
-
|
|
28
|
-
```mermaid
|
|
29
|
-
flowchart TD
|
|
30
|
-
need["launch needs a key for provider X"] --> env{"RFLECTR_KEY_X or env:VAR set?"}
|
|
31
|
-
env -->|yes| use["use it"]
|
|
32
|
-
env -->|no| ref{"authRef kind"}
|
|
33
|
-
ref -->|keyring:provider:X| kr["read keyring account"]
|
|
34
|
-
ref -->|keyring:oauth:provider:X| oauth["read + refresh OAuth credential"]
|
|
35
|
-
ref -->|keyring:global:opencode| zen["readGlobalOpencodeCredential() chain"]
|
|
36
|
-
kr --> use
|
|
37
|
-
oauth --> use
|
|
38
|
-
zen --> use
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### The OpenCode Zen/Go fallback chain
|
|
42
|
-
|
|
43
|
-
`readGlobalOpencodeCredential()` tries, in order: `OPENCODE_API_KEY` env var → keyring `global:opencode` → legacy keyring `rflectr` → oldest legacy service `opencode-starter`. On a successful legacy read, `migrateGlobalOpencodeCredential()` rewrites it to `global:opencode` using a **read → write → verify → delete** protocol (the old entry is only deleted after the new one verifies).
|
|
44
|
-
|
|
45
|
-
---
|
|
46
|
-
|
|
47
|
-
## Child process environment
|
|
48
|
-
|
|
49
|
-
`buildChildEnv(baseUrl, model, apiKey, proxyPort?, contextWindow?, enableGatewayDiscovery?)` (`src/env.ts`) builds the env for the launched host. It is the security boundary: the parent shell is never mutated (except `OPENCODE_API_KEY` during interactive key setup).
|
|
50
|
-
|
|
51
|
-
**Removed** — every var in `CONFLICTING_ENV_VARS` (`src/constants.ts`), so stale cloud config can't leak into the child:
|
|
52
|
-
|
|
53
|
-
```
|
|
54
|
-
CLAUDE_CODE_USE_VERTEX, ANTHROPIC_VERTEX_PROJECT_ID, ANTHROPIC_VERTEX_BASE_URL,
|
|
55
|
-
CLOUD_ML_REGION, ANTHROPIC_BEDROCK_BASE_URL, ANTHROPIC_AWS_BASE_URL,
|
|
56
|
-
ANTHROPIC_AWS_API_KEY, ANTHROPIC_AWS_WORKSPACE_ID, ANTHROPIC_FOUNDRY_API_KEY,
|
|
57
|
-
ANTHROPIC_FOUNDRY_BASE_URL, ANTHROPIC_AUTH_TOKEN, ANTHROPIC_API_KEY,
|
|
58
|
-
ANTHROPIC_BASE_URL, ANTHROPIC_MODEL, ANTHROPIC_DEFAULT_OPUS_MODEL,
|
|
59
|
-
ANTHROPIC_DEFAULT_SONNET_MODEL, ANTHROPIC_DEFAULT_HAIKU_MODEL
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
**Set:**
|
|
63
|
-
|
|
64
|
-
| Var | Value |
|
|
65
|
-
|---|---|
|
|
66
|
-
| `ANTHROPIC_BASE_URL` | `http://127.0.0.1:<proxyPort>` when a proxy is used, else `baseUrl` (which must **not** end in `/v1`) |
|
|
67
|
-
| `ANTHROPIC_API_KEY` | the provider key, or the proxy token when proxying |
|
|
68
|
-
| `ANTHROPIC_MODEL` | `claudeCodeClientModelId(stripOneMContextSuffix(model), contextWindow)` |
|
|
69
|
-
| `CLAUDE_CODE_MAX_CONTEXT_TOKENS` | `resolveContextWindow(bareModel, contextWindow)` |
|
|
70
|
-
| `CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY` | `1` when `enableGatewayDiscovery` (switch-menu mode) |
|
|
71
|
-
| `ENABLE_TOOL_SEARCH` | `true` — defer MCP tools like native Claude Code (`applyClaudeCodeThirdPartyCompat`) |
|
|
72
|
-
| `CLAUDE_CODE_SIMPLE_SYSTEM_PROMPT` | `0` — keep the full system prompt on proxy routes |
|
|
73
|
-
|
|
74
|
-
On the **anthropic direct-passthrough** path, the single-model launch additionally sets `CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1` to strip beta headers on the direct hop. On proxy routes the betas stay enabled so tool search works through the local proxy.
|
|
75
|
-
|
|
76
|
-
`detectConflicts()` reports which of these vars were present (shown in `--dry-run` and warnings) so a user can see what was scrubbed.
|
|
77
|
-
|
|
78
|
-
---
|
|
79
|
-
|
|
80
|
-
## Interactive key setup
|
|
81
|
-
|
|
82
|
-
`resolveOrCollectApiKey(simulate?, trace?)` (`src/key-setup.ts`) is called for the OpenCode Zen/Go key. On startup it silently calls the credential-store read first — if a key is found, no prompt appears. Otherwise it prompts for paste and offers platform-specific save options. In every case `process.env['OPENCODE_API_KEY']` is set immediately so the key is live for the current session regardless of save choice.
|
|
83
|
-
|
|
84
|
-
| Platform | Options |
|
|
85
|
-
|---|---|
|
|
86
|
-
| **macOS** | Keychain only · Keychain + `~/.zshrc` autoload · shell profile (plaintext) · session only |
|
|
87
|
-
| **Windows** | Credential Manager · `setx` user env var (plaintext) · session only |
|
|
88
|
-
| **Linux desktop** | Secret Service (GNOME Keyring / KWallet) · shell profile (plaintext) · session only |
|
|
89
|
-
| **Linux headless** | shell profile · session only (with a note explaining why secure storage is unavailable) |
|
|
90
|
-
|
|
91
|
-
Notes:
|
|
92
|
-
|
|
93
|
-
- The macOS autoload line uses the `security` CLI directly so the shell can source it: `export OPENCODE_API_KEY="$(security find-generic-password -s rflectr -a rflectr -w 2>/dev/null)"`.
|
|
94
|
-
- `setx` is invoked with piped stdio to suppress its "SUCCESS" stdout.
|
|
95
|
-
- Secret Service availability is probed with a test `getPassword()` (`isSecretServiceAvailable()`); if the daemon isn't running the option is hidden.
|
|
96
|
-
- `detectShellProfile()` chooses the right profile file per platform/shell (`~/.zshrc`, `~/.bash_profile`, `~/.bashrc`, `~/.profile`).
|
|
97
|
-
|
|
98
|
-
---
|
|
99
|
-
|
|
100
|
-
## Trust boundaries
|
|
101
|
-
|
|
102
|
-
```mermaid
|
|
103
|
-
flowchart TD
|
|
104
|
-
subgraph trusted["Trusted — rflectr process"]
|
|
105
|
-
keyring["OS keyring"]
|
|
106
|
-
registry["providers.json (no secrets)"]
|
|
107
|
-
env["buildChildEnv()"]
|
|
108
|
-
end
|
|
109
|
-
subgraph child["Child host (Claude Code / Codex / Gemini)"]
|
|
110
|
-
proc["host process"]
|
|
111
|
-
end
|
|
112
|
-
subgraph net["Network"]
|
|
113
|
-
prov["upstream provider"]
|
|
114
|
-
end
|
|
115
|
-
keyring -->|resolved at launch| env
|
|
116
|
-
env -->|"scrubbed env + proxy token"| proc
|
|
117
|
-
proc -->|"127.0.0.1 only"| localproxy["local proxy"]
|
|
118
|
-
localproxy -->|"provider key (never to child)"| prov
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
Key properties:
|
|
122
|
-
|
|
123
|
-
- The **provider's real key never reaches the child** when proxying — the child gets a random proxy token; the proxy holds the real key and calls upstream.
|
|
124
|
-
- The proxy binds `127.0.0.1` only, on a random port, and validates the token, so other local processes can't use it.
|
|
125
|
-
- Secrets are keyring-backed by default; plaintext options (`setx`, shell profile) are opt-in and clearly labelled.
|
|
126
|
-
|
|
127
|
-
### Server-mode caveat
|
|
128
|
-
|
|
129
|
-
The `server` command can bind in network mode and asks for a server password (`isAuthorized`, `sanitizeCredential` in `src/server/auth.ts`). When exposed beyond localhost, that password is the only gate — see [`../infrastructure/server-gateway.md`](../infrastructure/server-gateway.md).
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
# Documentation Framework
|
|
2
|
-
|
|
3
|
-
> Category: Standards | Version: 1.0 | Date: (fill in on init) | Status: Canonical
|
|
4
|
-
|
|
5
|
-
The single source of truth for how documentation is written in this repository. Every document — feature PRDs, issue PRDs, QA reports, architecture docs, API references, guides — must conform to the standards defined here. If a document type is not covered, add a new section to this file rather than inventing a local convention.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## 1. Document Types
|
|
10
|
-
|
|
11
|
-
| Type | Purpose | Location | Primary audience |
|
|
12
|
-
|---|---|---|---|
|
|
13
|
-
| **Issue IRD** | Implementation plan for a specific GitHub issue | `library/requirements/issues/issue-<###>-<title>/ird-issue-<###>-<title>.md` | Implementation engineer |
|
|
14
|
-
| **Feature PRD** | Planned feature spec (forward or retroactive) | `library/requirements/features/feature-<###>-<title>/prd-feature-<###>-<title>.md` (or `prd-feature-<###>-<title>-ck-<clickupId>.md` if from ClickUp) | Implementation engineer |
|
|
15
|
-
| **QA Report (tied)** | Audit of an implementation against its plan | The plan's own `reports/<date>-qa-report.md` subfolder | Team lead, author of the feature |
|
|
16
|
-
| **QA Report (standalone)** | Audit not tied to a single plan | `library/qa/<domain>/<date>-qa-report.md` | Team lead, audit reviewer |
|
|
17
|
-
| **Architecture Doc** | System design, data flows, component relationships | `library/knowledge-base/architecture/` | Senior engineers, architects |
|
|
18
|
-
| **API Reference** | Endpoint-by-endpoint documentation with schemas | `library/knowledge-base/api/` | Frontend devs, API consumers |
|
|
19
|
-
| **How-to Guide** | Runbooks for setup, testing, deploying, adding features | `library/knowledge-base/how-to-guides/` | New engineers, DevOps |
|
|
20
|
-
| **Integration Doc** | Third-party service configuration and error handling | `library/knowledge-base/integrations/` | DevOps, engineers wiring services |
|
|
21
|
-
| **UX/UI Standard** | Visual design language — tokens, components, patterns | `library/knowledge-base/design/` | Designers, frontend devs |
|
|
22
|
-
| **Feature Doc** | Completed feature reference (post-ship) | `library/knowledge-base/features/` | Any engineer joining the project |
|
|
23
|
-
| **Spec** | Feature-level handoff spec for a UI flow | `library/knowledge-base/specs/` | Frontend engineers |
|
|
24
|
-
| **Product Brief** | Product vision, scope, roadmap | `library/knowledge-base/product/` | Team, stakeholders |
|
|
25
|
-
| **Standards Doc** | Rules for writing documentation itself | `library/knowledge-base/standards/` | All contributors |
|
|
26
|
-
| **Release Notes** | What changed in each release | `library/knowledge-base/releases/` | All team members |
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## 2. Universal Document Header
|
|
31
|
-
|
|
32
|
-
Every markdown file under `library/knowledge-base/` starts with:
|
|
33
|
-
|
|
34
|
-
```markdown
|
|
35
|
-
# <Document Title>
|
|
36
|
-
|
|
37
|
-
> Category: <Type> | Version: <X.Y> | Date: <Month YYYY> | Status: <Active | Draft | Archived>
|
|
38
|
-
|
|
39
|
-
<One-sentence description of what this document covers and who should read it.>
|
|
40
|
-
|
|
41
|
-
**Related:**
|
|
42
|
-
- [Link to related doc]
|
|
43
|
-
- [Link to source code: `src/path/to/file.ts`]
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
- **Version** — starts at `1.0`; patch bumps (`1.0` → `1.1`) for additions, minor bumps (`1.x` → `2.0`) for reorganizations.
|
|
47
|
-
- **Date** — current month/year on the last meaningful edit.
|
|
48
|
-
- **Status** values:
|
|
49
|
-
- `Active` — current, should be kept up to date
|
|
50
|
-
- `Draft` — work in progress, not authoritative
|
|
51
|
-
- `Archived` — historical, no longer maintained
|
|
52
|
-
- `Canonical` — (for standards docs only) highest authority; overrides ad-hoc conventions
|
|
53
|
-
|
|
54
|
-
Requirements-type docs (issue IRDs, feature PRDs, QA reports) use a different header format documented in their respective guides.
|
|
55
|
-
|
|
56
|
-
---
|
|
57
|
-
|
|
58
|
-
## 3. Filename Conventions
|
|
59
|
-
|
|
60
|
-
| Document type | Folder + filename pattern | Example |
|
|
61
|
-
|---|---|---|
|
|
62
|
-
| Issue IRD | `issue-<###>-<title>/ird-issue-<###>-<title>.md` (with sibling `reports/`) | `issue-046-stale-cached-responses/ird-issue-046-stale-cached-responses.md` |
|
|
63
|
-
| Feature PRD | `feature-<###>-<title>/prd-feature-<###>-<title>.md` (with sibling `reports/`) | `feature-007-user-profile-export/prd-feature-007-user-profile-export.md` |
|
|
64
|
-
| Feature PRD (from ClickUp) | `feature-<###>-<title>/prd-feature-<###>-<title>-ck-<clickupId>.md` | `feature-007-user-profile-export/prd-feature-007-user-profile-export-ck-86c8wq2k1.md` |
|
|
65
|
-
| QA report (tied to plan) | `<plan-folder>/reports/<date>-qa-report.md` | `feature-007-user-profile-export/reports/2026-04-26-qa-report.md` |
|
|
66
|
-
| QA report (standalone) | `library/qa/<domain>/<date>-qa-report.md` | `library/qa/auth/2026-04-26-qa-report.md` |
|
|
67
|
-
| Knowledge-base | `<domain>/<kebab-slug>.md` (no numeric prefix) | `architecture/authentication-flow.md` |
|
|
68
|
-
|
|
69
|
-
**Numbering rules:**
|
|
70
|
-
- `<###>` is **3-digit zero-padded** (`006`, `046`, `093`, `100`). 4+ digit natural width.
|
|
71
|
-
- Issue numbers follow the GitHub issue number.
|
|
72
|
-
- Feature numbers are repo-local sequential; take `max + 1` from existing folders (open + `completed/`).
|
|
73
|
-
- Titles are lowercase kebab-case, ≤60 chars.
|
|
74
|
-
- The optional ClickUp suffix `-ck-<clickupId>` goes on the **main file only**, never on the folder name.
|
|
75
|
-
|
|
76
|
-
---
|
|
77
|
-
|
|
78
|
-
## 4. Folder Location Rules
|
|
79
|
-
|
|
80
|
-
| Folder | Meaning |
|
|
81
|
-
|---|---|
|
|
82
|
-
| `library/requirements/features/feature-<###>-<title>/` | Feature work in progress. |
|
|
83
|
-
| `library/requirements/features/completed/feature-<###>-<title>/` | Feature has shipped. Move the entire folder (PRD + `reports/`). |
|
|
84
|
-
| `library/requirements/issues/issue-<###>-<title>/` | Issue work in progress (GitHub issue OPEN). |
|
|
85
|
-
| `library/requirements/issues/completed/issue-<###>-<title>/` | Issue has been resolved (GitHub issue CLOSED). Move the entire folder (IRD + `reports/`). Symmetric to features. |
|
|
86
|
-
| `<plan-folder>/reports/` | QA reports tied to that specific feature/issue. Travel with the folder when it moves. |
|
|
87
|
-
| `library/qa/<domain>/` | Standalone QA reports — broad audits not tied to a single plan. |
|
|
88
|
-
|
|
89
|
-
Move folders when status changes. Never edit lifecycle state in frontmatter alone.
|
|
90
|
-
|
|
91
|
-
---
|
|
92
|
-
|
|
93
|
-
## 5. Writing Rules (all doc types)
|
|
94
|
-
|
|
95
|
-
1. **Ground every claim in code.** Quote source with file path + line range; never paraphrase signatures.
|
|
96
|
-
2. **One topic per document.** Split if a doc exceeds ~500 lines.
|
|
97
|
-
3. **Progressive disclosure.** Open with "why this exists" and "who should read it"; deep details below.
|
|
98
|
-
4. **Link out, don't duplicate.** If another doc covers a subtopic, link to it.
|
|
99
|
-
5. **Diagrams use mermaid.** Prefer `flowchart TD` or `sequenceDiagram`. No explicit colors.
|
|
100
|
-
6. **No time-sensitive language.** Avoid "currently", "recently", "as of". Use explicit dates.
|
|
101
|
-
7. **No personal opinions.** Docs describe decisions and rationale, not preferences.
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
|
|
105
|
-
## 6. Cross-Linking Conventions
|
|
106
|
-
|
|
107
|
-
- Use relative paths: `[title](../relative/path.md)`.
|
|
108
|
-
- Link to code with file paths (and line numbers where useful): `` `src/routes/users.ts:42-80` ``.
|
|
109
|
-
- PRDs and IRDs link to their related issues, features, and QA reports in a **Related** section at the end.
|
|
110
|
-
- Knowledge-base docs link to the PRDs that drove them (when applicable) and to source code.
|
|
111
|
-
|
|
112
|
-
---
|
|
113
|
-
|
|
114
|
-
## 7. Diagram Rules
|
|
115
|
-
|
|
116
|
-
- Mermaid preferred (renders everywhere GitHub does).
|
|
117
|
-
- Use `flowchart TD` (top-down) for process flows; `sequenceDiagram` for temporal flows; `erDiagram` for data models.
|
|
118
|
-
- Node IDs: no spaces (use `camelCase` or `under_scores`).
|
|
119
|
-
- No explicit colors (breaks dark mode).
|
|
120
|
-
- No `click` events.
|
|
121
|
-
- Quote labels containing parentheses, brackets, or colons.
|
|
122
|
-
|
|
123
|
-
---
|
|
124
|
-
|
|
125
|
-
## 8. Versioning + Dates
|
|
126
|
-
|
|
127
|
-
- **Versioning** is per-document, not repo-wide. Bump on meaningful content change.
|
|
128
|
-
- **Dates** use the current month/year (from the system clock), not arbitrary timestamps.
|
|
129
|
-
- Each document optionally ends with a **Changelog** section listing version bumps.
|
|
130
|
-
|
|
131
|
-
---
|
|
132
|
-
|
|
133
|
-
## 9. Ownership
|
|
134
|
-
|
|
135
|
-
- Requirements docs (issue IRDs, feature PRDs) are owned by the implementation author. QA reports are owned by `quality-guardian`.
|
|
136
|
-
- Knowledge-base docs are owned by the team collectively — anyone may edit with a PR.
|
|
137
|
-
- Standards docs (this file included) require team consensus before changing.
|
|
138
|
-
|
|
139
|
-
---
|
|
140
|
-
|
|
141
|
-
## 10. Bootstrap — After `initialize`
|
|
142
|
-
|
|
143
|
-
When `library-guardian initialize` seeds a repo:
|
|
144
|
-
|
|
145
|
-
1. Replace the placeholder "(fill in on init)" in the header above with the current month/year.
|
|
146
|
-
2. Replace any project-name placeholders in the seeded README files with your repo's actual name.
|
|
147
|
-
3. Edit any section of this framework that doesn't match your team's conventions — then commit.
|
|
148
|
-
4. Start using the agent: ingest issues, plan features, document architecture.
|
|
149
|
-
|
|
150
|
-
---
|
|
151
|
-
|
|
152
|
-
## Changelog
|
|
153
|
-
|
|
154
|
-
- v1.0 — Initial template seeded by `library-guardian`. Customize per repo.
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
ai_description: |
|
|
3
|
-
This folder contains customer-facing / end-user documentation.
|
|
4
|
-
Approved sub-folders: overview/, guides/, faqs/, and any domain
|
|
5
|
-
folder explicitly designated public by the team.
|
|
6
|
-
Do NOT file internal engineering docs, ADRs, pricing strategy, or
|
|
7
|
-
security-sensitive material here.
|
|
8
|
-
Write path: library/knowledge/public/<domain>/<kebab-slug>.md.
|
|
9
|
-
All files here may eventually be surfaced in the public help center
|
|
10
|
-
(Phase 2). Mark each doc with the standard knowledge-base header:
|
|
11
|
-
Category / Version / Date / Status.
|
|
12
|
-
human_description: |
|
|
13
|
-
Customer-facing documentation. Content here may be published externally.
|
|
14
|
-
- overview/: what this product is, glossary, elevator pitch
|
|
15
|
-
- guides/: how-to guides written for users, not developers
|
|
16
|
-
- faqs/: frequently asked questions
|
|
17
|
-
Only add content here that you are comfortable sharing publicly.
|
|
18
|
-
Internal notes, pricing strategy, and architecture docs belong in
|
|
19
|
-
knowledge/private/ instead.
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
# Knowledge — Public
|
|
23
|
-
|
|
24
|
-
Customer-facing documentation for **rflectr** by [Legion Code Inc.](https://github.com/legioncodeinc) Anything in this folder may eventually be published to the help center.
|
|
25
|
-
|
|
26
|
-
## Documentation map
|
|
27
|
-
|
|
28
|
-
**Start here:** [What is rflectr?](overview/what-is-rflectr.md)
|
|
29
|
-
|
|
30
|
-
| Section | Docs |
|
|
31
|
-
|---|---|
|
|
32
|
-
| [Overview](overview/) | [What is rflectr?](overview/what-is-rflectr.md) |
|
|
33
|
-
| [Guides](guides/) | [Providers](guides/providers.md) · [Claude Desktop](guides/claude-desktop.md) · [Codex](guides/codex.md) · [Gemini CLI](guides/gemini-cli.md) · [API Server](guides/api-server.md) · [AI Agents](guides/ai-agents.md) · [Model Compatibility](guides/model-compatibility.md) |
|
|
34
|
-
| [FAQs](faqs/) | [Troubleshooting](faqs/troubleshooting.md) |
|
|
35
|
-
|
|
36
|
-
## Approved sub-folders
|
|
37
|
-
|
|
38
|
-
| Folder | Contents |
|
|
39
|
-
|---|---|
|
|
40
|
-
| `overview/` | What this product is, glossary, elevator pitch, high-level FAQs |
|
|
41
|
-
| `guides/` | Step-by-step user guides (written for customers, not developers) |
|
|
42
|
-
| `faqs/` | Frequently asked questions from customers |
|
|
43
|
-
|
|
44
|
-
## What does NOT belong here
|
|
45
|
-
|
|
46
|
-
- Internal architecture docs or ADRs
|
|
47
|
-
- Pricing strategy or competitive analysis
|
|
48
|
-
- Engineering standards
|
|
49
|
-
- Anything you would not want a customer to read
|