taodengandClaude Opus 4.7 (noreply@anthropic.com) 95dc072245 feat(phase-1): land Mistral Vibe provider plugin (D8)
Phase 1 Day 5. Mistral Vibe provider plugin lands as Candidate. STATIC_
REGISTRY now length 3 (anthropic + openai + mistral). vibe CLI not
installed on the orchestrator machine and owner has no Le Chat Pro
subscription, so D8 follows the D6 docs-only authority pattern. D-later
verification (once a tester with a vibe install and subscription is
available) will resolve UNPINNED assumptions A4, A6, A7, A8.

Files:
  NEW:  lib/providers/mistral.mjs (~720 lines) — Mistral Vibe provider.
        Spawns `vibe --prompt PROMPT --output streaming` per docs.
        Reads MISTRAL_API_KEY env var with ~/.vibe/.env fallback.
        Supports VIBE_HOME env override per docs. Mirrors D4/D6 plugin
        structure incl. __setSpawnImpl/__resetSpawnImpl for tests.
  MOD:  lib/providers/index.mjs (+12/-1) — STATIC_REGISTRY now length 3.
        listAllProviderNames returns [anthropic, openai, mistral].
  MOD:  models-registry.json (+26 lines) — providers.mistral with 2
        canonical date-stamped IDs (devstral-2-25-12, devstral-small-2-
        25-12) and 4 short-form aliases for user convenience.
  MOD:  test-features.mjs — Suite 12 with 48 tests covering contract
        conformance, IR translation, mock-spawn behaviour, healthCheck,
        estimateCost, auth-artifact reading.

Authority citations (all WebFetched and verified during reviewer pass):
  DOCS-1: docs.mistral.ai/mistral-vibe/terminal/quickstart — `vibe
    --prompt PROMPT --max-turns 5 --max-price 1.0 --output json` example
    + Output Format Options enumeration: text default, json single blob,
    streaming NDJSON.
  DOCS-2: docs.mistral.ai/mistral-vibe/terminal/configuration — pin
    `~/.vibe/.env`, MISTRAL_API_KEY env var, VIBE_HOME override.
  DOCS-3: docs.mistral.ai/mistral-vibe/introduction/configuration —
    second confirmation of MISTRAL_API_KEY + ~/.vibe/.env (model
    selection via config.toml `/config` slash command, NOT --model
    flag).
  DOCS-4: deepwiki.com/mistralai/mistral-vibe/9.3-cli-commands-reference
    — full flag enumeration confirms no --model flag exists. Programmatic
    mode trigger is --prompt; flags are: --continue, --max-price,
    --max-turns, --output, --prompt, --resume, --setup, --trust,
    --upgrade, --version, --workdir, --no-autofill, --no-header,
    --no-dev, --enabled-tools, --help.
  DOCS-5: mistral.ai/news/devstral-2-vibe-cli — launch announcement,
    names Devstral 2 (123B) and Devstral Small 2 (24B), 256K context,
    pricing $0.40/$2.00 and $0.10/$0.30 per MTok.
  DOCS-6: help.mistral.ai/en/articles/347532 — Vibe included in Le Chat
    Pro.
  DOCS-7: legal.mistral.ai/terms/usage-policy — no anti-third-party
    clauses; ADR 0006 Tier D classification holds.
  DOCS-MAIN: docs.mistral.ai/mistral-vibe/overview — main Vibe overview.
  DOCS-8: docs.mistral.ai/getting-started/models/models_overview —
    canonical Mistral models registry. Pin for date-stamped IDs
    devstral-2-25-12 / devstral-small-2-25-12. Caught by D8 review-2.

Architectural decisions:
  1. `--output streaming` (NOT `json`). Per DOCS-1 verbatim: streaming
     emits NDJSON per message; json emits a single blob at the end.
     Original D8 draft used `json` which is incompatible with the
     plugin's line-buffered stdout parser. Review-2 caught this; fixed
     before commit.
  2. No --model flag. Per DOCS-4 full flag enumeration there is no
     --model flag in programmatic mode. Model selection happens via
     ~/.vibe/config.toml. The IR's `model` field is used by OLP for
     routing only; Vibe uses whatever model is in user-level config.
     Documented in lossy translations + as A5 CONFIRMED-NOT-APPLICABLE.
  3. Canonical IDs primary, short forms as aliases. models-registry.json
     uses devstral-2-25-12 / devstral-small-2-25-12 as primary `id`s
     matching the canonical Mistral models registry; user-facing short
     forms (devstral-2, devstral-small-2, devstral, devstral-small) are
     aliases. Plugin's models[] array includes both canonical IDs AND
     alias keys so getProviderForModel routes either form. Same pattern
     codified for Codex aliases in D6.
  4. Auth precedence: MISTRAL_API_KEY env > ~/.vibe/.env > null.
     Documented in DOCS-2. readAuthArtifact supports
     MISTRAL_VIBE_AUTH_PATH env override for testing.
  5. Mistral stays Candidate. STATIC_REGISTRY.length === 3 but
     loadProviders({}) returns empty Map; only loadProviders({
     enabled: { mistral: true }}) loads it. POST /v1/chat/completions
     devstral-* still returns 503 until config flag is set and E2E
     audit passes.

Reviewer chain (Iron Rule 10):
  Implementer: sonnet (general-purpose).
  Fresh-context reviewer: opus (ecc:code-reviewer). Verdict round-1:
    REQUEST_CHANGES (2 blockers caught).
  Reviewer ran npm test (222/222 pass), WebFetched all 8 canonical
    Mistral docs URLs, discovered DOCS-8 (models registry) which
    sonnet missed — exactly the D6 failure pattern, repeated. Reviewer
    independently verified `--output streaming` vs `json` semantics
    against the live docs page text, not paraphrases.

Reviewer blocking findings folded in this commit:
  B-1 (--output json wrong): Plugin now passes `--output streaming` per
    docs verbatim. Test "irToMistral: user message → args with --prompt
    and --output streaming" updated to assert the new arg and reject
    the old one.
  B-2 (canonical models page missed): models-registry.json refactored
    to use date-stamped canonical IDs as primary; short forms as
    aliases. mistral.mjs header adds DOCS-8 as the new canonical
    authority pin for model IDs. Plugin's models[] array merges
    canonical + alias keys so existing routing tests pass with either
    form.
  B-3 (404 claim incorrect): mistral.mjs header DOCS-MAIN updated.
    docs.mistral.ai/mistral-vibe/overview is 200 OK; sonnet's 404
    claim was a path-normalization mismatch.

Reviewer non-blocking suggestions (deferred to D-later / not D8 scope):
  - VIBE_HOME env override has no Suite 12 test (implementation
    present at mistral.mjs:262). Parallel gap to D6 CODEX_HOME.
  - _extractKeyFromDotenv has no direct unit test.
  - config.toml model selection mechanism (Vibe-specific quirk —
    no --model flag means OLP can't pass model per request). A D-later
    ADR note will discuss whether OLP should write a project-local
    ./.vibe/config.toml before spawn or accept the user-level config
    as authoritative.

Test count: 174 (after D6) → 222 (after D8).

Verification:
  node --check on all touched files: clean.
  npm test on Node 25.8.0: 222/222 pass in 210ms.
  STATIC_REGISTRY = [anthropic, openai, mistral] verified.
  hygiene grep: zero personal-name/path/token hits. Fixtures use
    <fake-mistral-api-key> placeholders.

Co-Authored-By: Claude Opus 4.7 (noreply@anthropic.com)
2026-05-23 21:48:29 +10:00

OLP — Open LLM Proxy

A personal- and family-scale multi-provider LLM proxy. One HTTP endpoint, many subscriptions behind it, automatic routing, automatic fallback, content-addressed caching — so your IDEs and family clients keep working as long as any of your subscriptions has quota left.

Status: v0.1 — bootstrap. Most of this README is a skeleton; sections marked placeholder land alongside the relevant phase of work (see phase plan).


Why OLP

On 2026-05-14, Anthropic announced (effective 2026-06-15) that claude -p, the Agent SDK, and third-party agent traffic move out of the Pro/Max subscription pool into a separate fixed monthly Agent SDK Credit pool. OCP, OLP's predecessor, was a proxy around a single CLI — its core assumption was "subscription = unlimited within rate limits". That assumption breaks for Anthropic on the effective date.

The structural response is to stop relying on one provider's subscription terms remaining favourable. OLP spreads risk across multiple providers whose subscriptions still include CLI/programmatic use, routes intelligently between them, and caches aggressively so every request that does spawn a CLI counts.

OLP is not: a commercial multi-tenant SaaS; an enterprise gateway competing with LiteLLM / OpenCode / CLIProxyAPI on breadth; a model-capability router ("route to the smartest model" — you pick the model); a conversation-state store (your client handles that).

See ALIGNMENT.md for OLP's constitution and docs/adr/ for the founding ADRs.


Quick Start

placeholder — lands with Phase 1.

Anticipated shape:

# install
npm install -g @dtzp555-max/olp

# run setup (writes ~/.olp/config.json, asks which providers to enable)
olp setup

# start the proxy (default port 3456 — same as OCP if you migrate)
olp start

# point your IDE at http://localhost:3456/v1/chat/completions with the OLP API key from `olp keys list`.

Supported Providers

Source of truth: models-registry.json. This table is regenerated from the registry per the release_kit overlay; do not edit it out of sync.

OLP distinguishes Candidate Providers (declared as intended, not yet pinned) from Enabled Providers (authority pin filled + plugin landed + Phase audit passed). The v0.1 founding commit ships zero Enabled Providers — enablement is a Phase audit deliverable, not a bootstrap claim. See ALIGNMENT.md § Provider Inventory for the transition gate.

Candidate Providers

Provider key CLI Subscription / auth Anticipated Tier Anticipated Phase
anthropic claude -p Pro / Max OAuth (pre-2026-06-15); Agent SDK Credit pool after D (re-eval post-2026-06-15) Phase 1
openai codex exec --json ChatGPT Pro OAuth or API key D Phase 2
mistral vibe --prompt --output json Le Chat Pro API key D Phase 3
grok grok -p --output-format streaming-json xAI Build xai-... API key C Phase 8+
kimi kimi -p --output-format stream-json Moonshot Kimi API key C Phase 8+
minimax TBD MiniMax Token Plan (¥29+/mo) B Phase 8+
glm TBD Zhipu Coding Plan ($10+/mo) B Phase 8+
qwen TBD Alibaba Coding Plan ($50/mo) B Phase 8+

Risk tier guide. D = permissive / safe (eligible for default-enabled); C = tightening signal, no enforcement history (opt-in); B = service-level key revocation risk (opt-in + consent); A = excluded by default (cannot be opt-in enabled). Tier B providers prompt for explicit consent on first enable and record consent in ~/.olp/config.json. See ALIGNMENT.md § Risk Tier Framework.

Excluded by default (Tier A — evidence-backed, pending primary-source pin). Google Antigravity. See ADR 0006 for the named-prohibition + no-cost-advantage + reinstatement-friction rationale, and for the primary-source pinning follow-up that may force a Tier reconsideration if the Google FAQ language cannot be sourced within 90 days of 2026-05-23.


Configuration

placeholder — full configuration reference lands with Phase 4 (fallback engine).

OLP reads its config from ~/.olp/config.json. The minimum useful shape:

{
  "routing": {
    "chains": {
      "<requested-model>": [
        { "provider": "<key>", "model": "<provider-model-id>" },
        { "provider": "<key>", "model": "<provider-model-id>" }
      ]
    },
    "soft_triggers": {
      "<provider-key>": { "<trigger>": <threshold> }
    }
  }
}

Trigger types, fallback safety, idempotency rules, and the full example config land here when Phase 4 ships. See ADR 0004 (Fallback Engine Semantics & Safety) for the design.


API Endpoints

placeholder — full table lands as each endpoint lands.

Endpoint Method Phase Description
/v1/chat/completions POST 1 OpenAI-compatible Chat Completions entry. Internally normalized to IR, dispatched to a provider plugin, response shape converted back.
/v1/models GET 1 Lists models from models-registry.json.
/health GET 1 Per-provider health snapshot (owner-only).
/cache/stats GET 5 Cache hit rate, by-provider breakdown.
/v0/management/quota GET 6 Per-provider quota / credit pool status (best-effort).
/dashboard GET 6 Owner-only dashboard (localhost-bound by default).

Environment Variables

placeholder — full table lands per-phase as variables are introduced.

Variable Default Description
OLP_PORT 3456 HTTP listener port.
OLP_HOME ~/.olp Config, providers, keys, cache, logs root.
OLP_LOG_LEVEL info One of error, warn, info, debug.

Further variables (per-provider auth path overrides, cache size limits, fallback-engine knobs) land with the relevant phase.


Response Headers

Every response served through OLP carries:

  • X-OLP-Provider-Used: <provider-key> — which provider's plugin served the request.
  • X-OLP-Model-Used: <model-id> — which model the served provider used.
  • X-OLP-Fallback-Hops: <n> — number of fallback hops (0 if served by the primary chain entry).
  • X-OLP-Cache: hit | miss | bypass — cache layer outcome.
  • X-OLP-Latency-Ms: <ms> — end-to-end latency observed at the proxy.

If a fallback chain is exhausted, X-OLP-Fallback-Exhausted lists the tried providers in order.


Architecture

OLP is a Node.js (ESM, .mjs) HTTP proxy with no build step and minimal dependencies. The high-level shape:

  • Entry surfaceserver.mjs handles /v1/chat/completions and the administrative endpoints. Governed by OpenAI's /v1/chat/completions specification as the wire authority. See ALIGNMENT.md § Authorities.
  • Intermediate Representation (IR)lib/ir/ normalizes between the entry surface and provider-native shapes. The IR is the lingua franca; any extension is an ADR 0003 amendment.
  • Provider pluginslib/providers/<name>.mjs. Each plugin implements the contract in ADR 0002 (Plugin Architecture for Providers), spawns its CLI, and translates between IR and provider-native IO.
  • Cache layerlib/cache/ is a content-addressed cache keyed on (provider, model, messages, tools, temperature, response_format, cache_control). Per-key isolation, prompt-caching bypass, chunked stream replay, and singleflight. See ADR 0005 (Cache Layer Cross-Provider Design).
  • Fallback enginelib/fallback/ advances a configured chain one provider at a time on configured triggers, never retrying after the first response chunk has been emitted to the client. See ADR 0004.
  • Multi-key authlib/keys.mjs carries OCP's per-OLP-key namespace isolation forward. Each OLP API key has independent quota, cache namespace, and audit log; each key declares which providers it can access.

Read the ADRs in docs/adr/ in order before proposing structural changes.


Phase plan

OLP lands in phases. Each phase has its own PR series and Iron-Rule-10 reviewer; this README's placeholders are filled per-phase via the release_kit overlay.

  • Phase 0 — Repo bootstrap, ALIGNMENT.md, founding ADRs, CI workflows, PR template. (current)
  • Phase 1 — server.mjs skeleton, IR, Anthropic plugin, cache D1+D4. Port from OCP.
  • Phase 2 — OpenAI Codex plugin.
  • Phase 3 — Mistral Vibe plugin.
  • Phase 4 — Fallback engine + routing chains config + quota poll worker.
  • Phase 5 — Cache cross-provider hardening (D2+D3).
  • Phase 6 — Dashboard + observability (/v0/management/quota).
  • Phase 7 — Release v0.1, OCP enters maintenance.
  • Phase 8+ — Optional Grok / Kimi / tier-2 plugins; provider-native protocol endpoints; deterministic triggers.

Full spec (decision rationale, open questions, risks): ~/.cc-rules/memory/projects/olp_v0_1_spec.md on the maintainer's workstations.


Migration from OCP

placeholder — scripts/migrate-from-ocp.mjs lands with Phase 7.

Anticipated user-facing flow (target: <5 minutes):

  1. Stop OCP (launchctl bootout the OCP service or ocp stop).
  2. Install OLP.
  3. Run olp migrate-from-ocp — copies ~/.ocp/keys/ to ~/.olp/keys/ and points provider plugins at OCP's existing auth artifacts where applicable.
  4. Start OLP. Clients pointing at port 3456 keep working; their existing OLP API keys remain valid.

OCP's cache directory is not migrated: OLP's cache key format includes provider+model and warms cold naturally. OCP enters maintenance mode (stability fixes only) when OLP v0.1 ships; new development happens in OLP.


License

MIT.


Acknowledgements

OLP evolved from OCP (Open Claude Proxy). OCP's per-key isolation model, cache-layer design (D1D4), dashboard, and alignment-constitution discipline are all carried forward. The structural generalization from single-CLI to multi-provider is what makes this a new project rather than an OCP minor version — see ALIGNMENT.md § Reference: How OCP's cli.js discipline maps to OLP.

Authors: project maintainer (with AI drafting assistance).

S
Description
No description provided
Readme MIT
2.4 MiB
Languages
JavaScript 95.8%
HTML 2.3%
Shell 1.9%