Skip to content

Latest commit

 

History

History
452 lines (377 loc) · 30.3 KB

File metadata and controls

452 lines (377 loc) · 30.3 KB

Cacheboard server

The server turns Cacheboard from a manual/browser-only page into the Docker-backed local multi-account metrics Dashboard. It serves the card UI, protects provider access behind one bearer token, reads account-scoped Claude data, and projects the verified signed Codex snapshot published by the Windows Orchestrator. The Dashboard does not run Codex or receive a Codex credential path.

The universal Claude/Codex controller is the separate Windows-local orchestrator/ Hub on 127.0.0.1:8790. The ordinary one-click launcher starts and verifies both layers together, establishes the signed Dashboard browser session, and follows the same bounded one-time bridge into Orchestrator as the primary experience. The original Dashboard remains available through Orchestrator's reciprocal Dashboard link, while -NoOrchestrator intentionally opens the metrics-only Dashboard. Neither bridge direction exposes DASHBOARD_TOKEN or provider credentials to the controller. See the high-level feature overview and implemented control-plane map.

The eight intended local provider profiles—four Claude and four Codex—were enrolled and returned identity-verified plan/activity data by 2026-08-10. The shared stable IDs are earl, bbpyderz, ehayestrainer, and claude; claude is verified as claude@bigbwain.com on both providers. server/.env and provider credentials remain machine-local and must never be committed. Re-run the health and route checks below before relying on that receipt after provider, credential, image, or configuration changes.

Start here

On Windows, from the repository root:

Copy-Item server/.env.example server/.env
$earlEmail = Read-Host 'Exact email for earl'
$bbpyderzEmail = Read-Host 'Exact email for bbpyderz'
$trainerEmail = Read-Host 'Exact email for ehayestrainer'
$claudeEmail = Read-Host 'Exact email for claude'
.\server\setup-claude-profiles.ps1 -Accounts "earl=$earlEmail","bbpyderz=$bbpyderzEmail","ehayestrainer=$trainerEmail","claude=$claudeEmail" -SkipRestart
.\server\setup-codex-profiles.ps1 -Accounts "earl=$earlEmail","bbpyderz=$bbpyderzEmail","ehayestrainer=$trainerEmail","claude=$claudeEmail"

Codex setup accepts only a subset of those four fixed IDs. It acquires the shared setup mutex and requires port 8790 to be proven closed before it resolves Codex, creates or changes a profile, or invokes the provider. Run it only in a deliberate stopped-Orchestrator window, normally before starting Cacheboard after Windows sign-in. An open or unknown listener is left untouched; never terminate it by PID merely to make setup continue.

Set DASHBOARD_TOKEN in server/.env. For normal Windows use, the one-click launcher starts the container, waits for health, and opens an authenticated browser session:

.\server\start-cacheboard.ps1

Install or repair the ordinary Desktop shortcut from the current checkout with:

.\server\install-desktop-launcher.ps1

The generated Start Cacheboard.cmd forwards only options supplied by the person launching it. It never makes -SkipClaudeRecovery the default, so an ordinary double-click first tries the saved Claude refresh credential and can guide exact-email browser reauthentication only when that credential is not locally usable. The same integrated start prepares the Codex metrics bridge, starts or safely reuses the sole Windows writer, and reports typed exact-account Codex repair guidance without opening provider login automatically.

When an already-running Orchestrator has a different artifact identity, normal startup requests a graceful refresh only if that broker is the authenticated exact owner, is idle, and advertises /healthz.lifecycle.contract: cacheboard-orchestrator-lifecycle-v1 with restart: graceful. Pass -NoRuntimeRefresh to disable that request; a stale broker is then left untouched with concise next-step guidance. Busy, unowned, and legacy brokers fail closed the same way. The launcher does not print raw structured receipt data and never falls back to Stop-Process, taskkill, or a forced replacement; after an accepted refresh it waits for the old PID, port 8790 listener, and owner lock to close before starting the current artifact. See the runtime identity boundary for the exceptional owner-verified legacy recovery path.

Before opening Cacheboard, the launcher checks authenticated /health. If an exact-email-configured Claude plan credential is expired or not ready, it runs isolated setup one account at a time. A signed native Claude Code 2.1.233+ executable first exchanges a locally usable saved refresh credential in an owner-only staging profile; the result is promoted only after first-party status returns the configured exact email. A locally unusable refresh state (for example a missing, expired, invalid, or incomplete credential) selects the guided browser flow. Any ambiguous provider nonzero, timeout, or transport failure preserves live bytes and stops with retry plus explicit -ForceLogin guidance instead of silently opening a browser. A wrong identity or failed post-restart readiness check stops startup instead of guessing or opening a misleading dashboard. Recovery uses the exact host root from CLAUDE_PROFILES_HOST_DIR; it never writes to a guessed profile location. The launcher passes -RefreshOnly -SkipRestart; this credential-only mode rejects missing or mismatched .env paths, email mappings, or profile metadata before invoking Claude. Ordinary setup does not use -RefreshOnly and still creates or repairs those mappings when an existing credential is already ready. Use -SkipClaudeRecovery only for an intentional offline/stale-data launch; Codex profiles are not changed by this Claude recovery pass. Codex saved-credential refresh and exact-email reads belong to the separately started Windows Orchestrator and its pinned app-server.

If Docker's Linux engine is not reachable, the launcher first uses Docker Desktop's supported docker desktop start command when available, then falls back to the installed Desktop executable. It waits up to three minutes and reports the active Docker context, Desktop/backend process presence, and Desktop status without changing Docker settings. Keep Docker Desktop visible so a first-run license, WSL update, or recovery prompt can be completed. Normal one-click startup still fails rather than silently returning a partial product. For deliberate continuity while repairing Docker, rerun Start-Cacheboard.cmd -OrchestratorOnlyIfDockerUnavailable: it starts the local broker, uses its loopback-only bearer exchange to create the same short-lived one-time browser ticket, and clearly reports the Dashboard, provider usage cards, Dashboard bridge, and container-backed provider readings as unavailable. This is an explicit degraded Orchestrator-only mode, not a successful start of the full Cacheboard product. Controller features that depend on current Dashboard capacity readings remain stale or unavailable until Docker is healthy again.

The launcher sends DASHBOARD_TOKEN only in the authorization header of a loopback request. Cacheboard exchanges it for a random 60-second, single-use bootstrap path bound to one exact destination, then sets a 30-day HttpOnly; SameSite=Strict session cookie. Normal startup redirects through /auth/orchestrator; -NoOrchestrator redirects to the Dashboard. The dashboard token is never placed in a URL or printed. The visible Orchestrator link targets the authenticated same-origin /auth/orchestrator bridge. The server uses its configured token to request a separate one-time Orchestrator ticket over the fixed loopback boundary, then redirects the browser only to that bounded ticket path. After consumption, Orchestrator delivers its own signed exact-origin session once in a URL fragment; its client immediately moves the value to origin-scoped sessionStorage, clears the fragment, and uses separate purpose-bound SSE tickets. Neither bearer token enters HTML, browser JavaScript, logs, or a URL. Orchestrator has its own persistence contract. Its local queued-action vault encrypts pending local provider prompts/action payloads at rest, but its remote Host Fabric stores bounded remote managed launch/follow-up prompts and non-secret question answers as plaintext JSON command payloads in broker SQLite history. The launch UI does not derive a title from the prompt; its separate optional operator-entered chat title is limited to 200 characters and persists as plaintext session metadata. Do not put credentials, secrets, or unrestricted transcript bodies into remote prompts or answers, or sensitive text into titles. That Fabric retention is documented in the Host Agent guide; it is not Dashboard credential storage. -NoBrowser starts and verifies Cacheboard without minting a ticket or opening a browser. Browser bootstrap is disabled whenever the effective published bind is not loopback; use bearer authentication behind an authenticated HTTPS reverse proxy for intentional LAN access.

For a degraded Dashboard-only diagnostic without opening a browser:

docker compose -f server/docker-compose.yml up -d --build
docker compose -f server/docker-compose.yml logs --tail 100 dashboard

Raw Compose does not prepare or validate the protected host metrics bridge and does not start the Windows Orchestrator. Unless a previously prepared bridge is deliberately supplied, all four Codex rows are orchestrator_unavailable. Use the repository launcher for the supported complete-product startup.

The default URL is http://127.0.0.1:8787. Compose binds to loopback even though Node listens on 0.0.0.0 inside the container. Change CACHEBOARD_BIND only if LAN access is intentional; use a reverse proxy with HTTPS for untrusted networks.

The image uses the digest-pinned Node 22 runtime on Debian with CA certificates for its remaining HTTPS integrations. It contains only the Dashboard server, the snapshot reader, the shared normalization/verification contract, and runtime-identity inputs; it has no Codex package, executable, bootstrap, credential mount, or provider writer. It does not force public DNS, so LAN name resolution follows Docker/host configuration. CACHEBOARD_HOST_PORT changes the host-side port; the container's internal PORT remains 8787. When the host port changes, update ALLOWED_ORIGINS to the same exact browser origin/port or authenticated browser calls will be rejected by CORS.

Identity and profile contract

Stable account IDs use lowercase letters, numbers, and underscores. IDs select data; labels never do.

On Windows, setup and startup apply a fail-closed owner-only ACL to server/.env and the managed Claude/Codex credential roots and files without reading their contents. Inheritance is removed; only the current user, SYSTEM, and BUILTIN\Administrators receive FullControl, with child inheritance only on directories. Existing links, junctions/reparse points, access-denied ancestors, and path escapes are rejected rather than followed. Claude's configured profile root may also contain an unrelated ordinary sibling directory left by an older/manual Claude setup. Cacheboard does not treat that directory as an identity or traverse it during configured-identity validation, so it cannot strand startup. A configured identity that is not a real directory, any link/reparse point at the root, or any link/escape inside a configured identity still fails closed before credential setup.

In either setup script, earl=person@example.test supplies an expected identity and hard-fails if the provider authenticates a different address. earl=Friendly Label supplies only cosmetic text. The same verified provider email cannot populate two IDs, including persisted mappings, and a shared Claude/Codex ID cannot resolve to different emails.

Claude

Preferred variables for account earl:

CLAUDE_ACCOUNTS=earl
CLAUDE_PROFILE_EARL=/profiles/claude/earl
CLAUDE_CREDENTIALS_FILE_EARL=/profiles/claude/earl/.credentials.json
CLAUDE_PROJECTS_DIR_EARL=/profiles/claude/earl/projects
CLAUDE_PROFILE_METADATA_EARL=/profiles/claude/earl/.cacheboard-profile.json
CLAUDE_EMAIL_EARL=exact-verified-email
CLAUDE_LABEL_EARL=Earl

CLAUDE_PROFILE_<ID> is a convenience root that derives the credential, project, and metadata paths. Explicit paths take precedence. Metadata must be <profile>/.cacheboard-profile.json with:

{
  "accountId": "earl",
  "provider": "claude",
  "email": "exact-address-returned-by-claude",
  "verifiedAt": "2026-08-09T00:00:00.0000000Z"
}

The setup script produces this only after claude auth status --json confirms the exact email. It stores no token. CLAUDE_CREDENTIALS_FILE plus CLAUDE_PROJECTS_DIR remains an explicit unnamed single-account fallback. Named cards always require ?account= and do not silently fall back.

Cacheboard performs supported Claude Code refresh-token exchange first through a signed native Claude Code 2.1.233+ executable, then verifies logged-in, first-party status and the configured exact email before atomic promotion. It does not infer provider error classes from CLI text or silently fall back to a browser after an ambiguous failure. When browser repair is required or an owner explicitly wants replacement, use only the transactional setup script with an exact mapping, for example setup-claude-profiles.ps1 -Accounts "earl=person@example.test" -ForceLogin. Do not point Claude's login command directly at a live Cacheboard profile: the setup script signs into a staging profile, verifies the returned email, and only then promotes the credential. It restores the prior credential, metadata, and .env byte-for-byte if login, validation, persistence, or restart fails. A newly written bearer is revision-keyed, so it does not inherit a rejected previous bearer's 180-second failure cooldown.

Codex

Windows Orchestrator is the sole active Codex credential writer. The fixed profiles derive only from CODEX_PROFILES_HOST_DIR plus the stable ID. Setup writes the protected host root and exact per-ID email/label mappings; legacy global or per-ID home overrides fail closed instead of selecting another credential authority.

Preferred variables:

CODEX_PROFILES_HOST_DIR=C:/Users/you/codex-profiles
CODEX_EMAIL_EARL=exact-verified-email
CODEX_LABEL_EARL=Earl

Each profile remains an ordinary owner-protected directory such as %USERPROFILE%\codex-profiles\earl. The Orchestrator uses the pinned official app-server to read the current ChatGPT identity, perform supported saved-credential refresh when required, verify the configured exact email, and collect rate-limit and usage data. An exact signed-in email mismatch fails closed; metadata, directory names, labels, and plan type never choose an identity.

The broker atomically publishes one bounded HMAC-authenticated codex-metrics.v1.json snapshot into the protected %LOCALAPPDATA%\Cacheboard\Orchestrator\dashboard-bridge directory by default. The launcher exports that ordinary directory as CACHEBOARD_CODEX_METRICS_BRIDGE_DIR; Compose mounts it read-only at /bridge/codex. The snapshot contains exactly earl, bbpyderz, ehayestrainer, and claude in that order. It contains normalized readings and identity evidence, never credentials or the HMAC key.

The Dashboard reader opens the exact ordinary single-link file, bounds the read, verifies stable file custody, HMAC, schema, fixed order, and signed lifetime, and rejects an observed unsafe, invalid, or older replacement immediately. A previously verified in-memory generation may be reused only for a missing or transiently unavailable file while that signed generation remains unexpired. Missing, invalid, or expired bridge custody is exposed as orchestrator_unavailable; configured-email mapping drift is temporarily_unavailable, never an identity mismatch. Only a signed record that proves a different provider email is identity_mismatch.

Normal startup accepts ready records plus the typed unavailable reasons credential_expired, credential_unavailable, refresh_rejected, identity_mismatch, and temporarily_unavailable. Only the first three are browser-required states, and the launcher prints a setup command bound to the exact fixed ID and configured email. It never invokes that command. Identity mismatch, Orchestrator absence, missing configured email, and ambiguous or temporary failures do not recommend or open provider login.

For an explicitly typed browser-required account, first establish a verified stopped-broker window, then run the exact printed setup-codex-profiles.ps1 -Accounts "<id>=<email>" -ForceLogin command. Setup verifies the exact provider identity before retaining the protected Windows profile and metadata. It has no restart, Docker, or runtime-replacement path.

The historical Docker Codex volume remains sensitive dormant rollback custody. It is declared but unmounted and is never an implicit fallback or automatic reactivation path. A future owner-reviewed rollback must deliberately stop the Windows writer and transfer credential authority before mounting it. Do not run docker compose -f server/docker-compose.yml down -v; it would delete both active Dashboard state and this retained dormant custody.

Strict identity is mandatory for Codex; there is no unverified mode. Claude's separate temporary migration gate never overrides an actual email mismatch.

Claude identityVerified means the current configuration agrees with setup-time metadata created from claude auth status --json; it is not continuous provider-side proof. Rerun setup-claude-profiles.ps1 after any Claude sign-out, login change, or manual reauthentication. Codex identity and readings are refreshed by the Windows broker before it publishes the corresponding signed snapshot generation; the Dashboard performs no provider request.

HTTP routes

All API routes except /healthz require either Authorization: Bearer <DASHBOARD_TOKEN> or the signed browser session cookie created by the one-click launcher. Bearer authentication remains compatible with scripts and configured CORS origins. Session cookies are HMAC-signed with DASHBOARD_TOKEN, checked for tampering and expiry, survive server restarts, and are invalidated when the dashboard token changes. Ticket minting and browser-session cookie acceptance are loopback-only; ticket minting always requires bearer authentication.

Route Purpose
GET /healthz Public process liveness only: { "ok": true }
POST /auth/bootstrap Loopback-only, bearer-authenticated minting of one short-lived browser bootstrap path
GET /auth/bootstrap/<ticket> Consumes the ticket once, sets the signed HttpOnly session cookie, and redirects to its exact minted destination (/ or /auth/orchestrator)
GET /auth/orchestrator Requires the signed Dashboard browser session, mints a bounded one-time Orchestrator ticket server-side, and redirects only to http://127.0.0.1:8790/auth/ticket/<ticket>
GET /health Authenticated provider inventory and per-account readiness/identity details
GET /usage/claude-plan?account=<id> Claude subscription windows and reset times
GET /usage/claude-code?account=<id>&tzOffsetMin=<n> Claude Code transcript activity for today/week/month/all
GET /usage/codex-plan?account=<id> Codex rate-limit windows, credits, and plan type
`GET /usage/codex-usage?account=&period=today week
* /proxy/<provider>/<path> Strict allowlisted provider proxy
POST /token/<provider>/refresh OAuth refresh for configured providers
POST /token/fitbit/seed Loopback-only handoff of Fitbit's rotating refresh token, bound to the verified Fitbit user ID
GET /security/<check> Named self-assessment against targets fixed in .env

The plan endpoints normalize provider windows into series entries with used, totalLimit: 100, unit: "%", and reset metadata. Codex activity returns both tokens and used for the selected period, plus totals and dailyUsageBuckets. It intentionally returns no subscription token ceiling; the UI keeps the user's configured target.

The public Codex DTOs remain compatible with the former Dashboard collector. The HTTP wrapper still adds source followed by tookMs; successful snapshot projections retain cached followed by cacheAgeMs in addition to the existing plan or usage fields. /health retains the four ordered codexAccountDetails, and /usage/codex-plan plus /usage/codex-usage retain their existing success shapes. Typed unavailable routes fail without exposing a bridge path, signature, provider payload, or credential detail.

/health also adds the versioned, server-owned aiLaneDirectory projection:

{
  "contract": "cacheboard-ai-lane-directory-v1",
  "lanes": [{
    "laneKey": "earl:claude",
    "identityId": "earl",
    "provider": "claude",
    "expectedEmail": "earl@example.test",
    "verifiedEmail": "earl@example.test",
    "identityState": "verified",
    "reasonCode": null,
    "capacity": { "authority": "allowed", "reasonCode": null },
    "activity": { "authority": "allowed", "reasonCode": null }
  }],
  "providerIssues": []
}

The projection always contains exactly eight rows: Claude rows for earl, bbpyderz, ehayestrainer, and claude, followed by Codex rows in the same frozen identity order. A missing fixed row remains present and blocked; labels, plan names, directories, and browser input never create or select a lane. identityState is limited to verified, unverified, mismatch, or unavailable. A lane or reading reason is either null or one of configuration_unavailable, contract_unavailable, identity_unverified, identity_mismatch, credential_expired, credential_unavailable, refresh_rejected, orchestrator_unavailable, temporarily_unavailable, capacity_unavailable, and activity_unavailable.

providerIssues is bounded attention metadata within this same fixed shape: each item can contain only provider claude or codex plus reason contract_unavailable. It never contains an upstream message. The directory does not expose credentials, native errors, profile paths, prompts, provider payloads, raw output, or the signed-snapshot HMAC. The legacy account arrays and detail DTOs remain available unchanged for existing consumers.

This health projection states current identity and reading authority only. A successful health response never refreshes a meter, changes its measurement timestamp, clears its route error, or makes a retained Capacity or Activity reading current.

Dashboard connection and readiness presentation

The browser treats connection truth and measurement truth as orthogonal. Its persistent compact Dashboard connection state is loading, ready, auth_required, or unavailable. ready means only that the authenticated health response and versioned eight-row directory validated; it does not mean that every lane or meter is readable. A missing/expired browser session remains visibly auth_required. Backend or contract failure reports the typed compact connection failure without inventing a readable-lane count.

Every lane's Capacity and Activity presentation independently records:

  • intent: enabled or hidden;
  • authority: allowed or blocked;
  • availability: available, unavailable, or not_requested;
  • freshness: current, stale, or never_measured;
  • one bounded reason code; and
  • nullable measurement/stale timestamps plus existing window/reset provenance.

The authenticated fixed eight-lane directory and this per-reading model remain the internal source of identity, authority, availability, and freshness truth. They are not rendered as a second Account readiness matrix. The two canonical Claude and Codex provider overview cards are the visible capacity/activity surface: together they retain every configured lane reading, window, reset, value, freshness, and bounded status without creating one duplicate card per lane.

Metric-card status chrome is actionable-only. It stays absent when the visible cards are healthy and appears as one compact native disclosure only when cards need attention. Attention is the total actionable set; error and stale controls are labeled as overlapping subsets and keep their established filter keys. Count and pressed-state updates patch stable nodes in place so background refresh does not replace the disclosure, its open state, or a still-visible focused control. If a focused subset reaches zero, focus moves to the connected status summary and an empty subset filter reconciles to Attention while other actionable cards remain. If the last actionable count reaches zero, focus moves to the visible All filter and the view reconciles to All before the status section hides. No hidden control remains focused or selected as invisible filter truth.

Health success changes only connection and lane authority. A prior meter value, timestamp, route error, series, and history remain untouched until that exact meter succeeds. If connection health later fails, retained provider-overview measurements remain measurement evidence and are labeled stale through their existing typed source state; rendering does not clear or rewrite the underlying measurement object.

Lane and meter reasons pass through a fixed copy allowlist; an unknown reason renders only Reading unavailable. Raw identity errors, provider output, credential text, backend bodies, paths, tokens, and payloads are never used as visible status copy. Ordinary loading/ready transitions use a polite status announcement, while each new authentication/backend failure transition uses a once-only alert; repeated renders of the same state do not reannounce it.

This presentation changes neither provider calculations nor the existing % used · % left, Activity, history, or reset semantics. Provider-free fixtures do not prove parity with the visible ChatGPT application; that comparison still requires the same exact account, window, timestamp, and bucket.

Verification

$headers = @{ Authorization = 'Bearer YOUR_DASHBOARD_TOKEN' }
$health = Invoke-RestMethod http://127.0.0.1:8787/health -Headers $headers
$health.claudeAccountDetails | Format-Table name,expectedEmail,identityVerified,mismatch,ready
$health.codexAccountDetails  | Format-Table name,expectedEmail,identityVerified,mismatch,ready

Invoke-RestMethod 'http://127.0.0.1:8787/usage/claude-plan?account=earl' -Headers $headers
Invoke-RestMethod 'http://127.0.0.1:8787/usage/codex-plan?account=earl' -Headers $headers
Invoke-RestMethod 'http://127.0.0.1:8787/usage/codex-usage?account=earl&period=week' -Headers $headers

Do not treat a card as correctly mapped until health reports the expected email, identityVerified: true, mismatch: false, and ready: true.

Failure guide

Symptom Action
Codex credential_expired, credential_unavailable, or refresh_rejected Use only the exact ID/email setup command printed by the launcher, after proving port 8790 is closed. The launcher never opens login automatically.
Codex identity_mismatch Stop. Inspect the signed actual/expected identity and correct that exact Windows profile during an owner-approved stopped-broker setup window; do not relabel it or infer login from a directory.
Codex orchestrator_unavailable Repair/start the exact Orchestrator and protected signed bridge. Do not reauthenticate a provider to repair absent, invalid, or expired snapshot custody.
Codex temporarily_unavailable Retry the ordinary launcher and inspect broker/provider diagnostics. Ambiguous transport or configured-email mapping drift never opens or recommends login.
Claude 401/403 Reauthenticate the isolated Claude profile; setup-token is not a valid replacement
Claude 429 Preserve the script-generated claude-code/<version> user agent and wait for the per-account 180-second cache window
Startup reports an Orchestrator runtime identity mismatch Rerun the normal launcher to permit its bounded graceful refresh. Use -NoRuntimeRefresh only when you intentionally want to leave the stale broker untouched and receive concise guidance. Never terminate a process by PID alone.
Orchestrator refresh is refused or does not finish Active work, uncertain ownership, or a broker without cacheboard-orchestrator-lifecycle-v1 is intentionally not replaced. Preserve it and follow the owner-verified recovery boundary; do not use a force-kill fallback.
Empty Claude activity Confirm CLAUDE_PROJECTS_DIR_<ID> points to that profile's projects directory
Activity percentage seems wrong The provider gives usage, not a token ceiling; edit the card's planning target

Claude plan failures are throttled by credential identity for at least 180 seconds and honor longer upstream Retry-After values. If a prior successful reading exists, the route returns it explicitly marked stale with refreshError and retryAt; the dashboard displays that fallback without treating it as a fresh reading.

Launcher recovery helpers are covered separately so they can be validated without opening provider login windows:

powershell -NoProfile -ExecutionPolicy Bypass -File .\server\startup-auth.test.ps1
powershell -NoProfile -ExecutionPolicy Bypass -File .\server\startup-docker.test.ps1
powershell -NoProfile -ExecutionPolicy Bypass -File .\server\setup-claude-transaction.test.ps1
node --test .\server\claude-plan-throttle.test.mjs

Other server features

OpenAI API billing requires an organization Admin API key in OPENAI_API_KEY; normal project keys cannot read organization costs. Provider OAuth refresh, a strict generic proxy, and passive checks (port-drift, tls-expiry, http-headers) remain supported. Fitbit's browser flow can seed its refresh token only while Cacheboard is loopback-bound. That durable refresh state is bound to one verified Fitbit user ID; a different profile is rejected instead of silently replacing or reading the first profile. Targets and secrets come only from .env; callers cannot choose arbitrary scan targets or proxy hosts.

The official Codex app-server protocol used only by the Windows Orchestrator is documented in the OpenAI Codex repository. Claude plan collection is deliberately isolated and documented in PLAN-USAGE-SEAM.md because its endpoint is not a public contract.