feat+test+docs: D71+D72+D73 — olp-plugin/ (OpenClaw /olp Telegram+Discord) + docs/integrations/*.md + README cross-refs (#44)

Final Phase 4 substantive D-day group. 3 D-days bundled per Iron Rule 11
IDR (plugin consumes existing endpoints; integration docs reference plugin
+ olp CLI + olp-connect together; README index links all).

After this PR merges, Phase 4 has shipped all 5 D-day groups (D60 charter
+ port / D61-D63 SSE heartbeat+ring+/status / D64-D67 olp CLI+doctor /
D68-D70 olp-connect+anonymous-key+ADR0011 / D71-D73 plugin+docs). The
v0.4.0 close PR is maintainer-triggered per CLAUDE.md release_kit overlay.

## D71 — olp-plugin/ (OpenClaw gateway plugin)

Port OCP ocp-plugin/index.js (311 lines) → OLP olp-plugin/index.js (482
lines) as the /olp Telegram+Discord slash command, but MINUS mutations
(no /olp keys keygen, no /olp keys revoke, no /olp restart, no /olp logs
— all of these require SSH out of chat for security).

Plugin shape:
- olp-plugin/index.js — registers /olp command via OpenClaw api.registerCommand
- olp-plugin/openclaw.plugin.json — manifest, apiKey REQUIRED, proxyUrl
  default http://127.0.0.1:4567 (matches D60)
- olp-plugin/package.json — minimal: name/version/type:module + OpenClaw
  discovery block
- olp-plugin/README.md — install + configure + use docs; documents the
  "no mutations from chat" security stance and the dedicated-bot-key
  pattern (don't share maintainer's personal key with the bot)

Subcommand parity with olp CLI (D64-D67):
- /olp status   → GET /v0/management/status         (owner-only)
- /olp health   → GET /health                       (public-ok)
- /olp usage    → GET /v0/management/dashboard-data (owner-only)
- /olp models   → GET /v1/models                    (public-ok)
- /olp cache    → GET /cache/stats                  (owner-only)
- /olp providers → local cross-ref                  (public-ok)
- /olp chain show [<model>] → local                 (public-ok, advisory
  if no FS access — defer to ssh + olp chain show)
- /olp doctor   → informational (HTTP doctor endpoint deferred; advisory
  to ssh + olp doctor for live use)
- /olp help     → usage text

Port resolution: OLP_PROXY_URL env → OLP_PORT env → plugin config
proxyUrl → http://127.0.0.1:4567. Output: Telegram/Discord monospace
code block with status icons (🟢🟡🔴). Long responses truncated for the
4096-char message limit.

No npm deps. OpenClaw provides Telegram/Discord transport; plugin uses
fetch + node builtins only.

## D72 — docs/integrations/*.md (6 IDE pages + index)

Per the Phase 4 brainstorm prior-art survey + ADR 0010 § Out-of-scope
posture for Claude Code:

- continue.md    — config.yaml (NOT config.json); apiBase; requestOptions.headers
- cline.md       — "OpenAI Compatible" provider; Cline #7128 base-URL UI bug warning
- cursor.md     ⚠️  — known base-URL fragility; only enable models OLP serves
- aider.md       — OPENAI_API_BASE env + openai/ prefix; .env support
- claude-code.md  — explicitly NOT supported per ADR 0010 § /v1/messages defer
                     rationale; recommended alternative: Cline + OLP
- openclaw.md    — install olp-plugin via CLI or symlink; configure apiKey;
                    restart gateway

Each ~60-120 lines: status / quick setup / known issues / OLP-specific
notes / test-it command. docs/integrations/README.md is the index.

## D73 — README cross-references

- New § "IDE Setup" links to docs/integrations/README.md
- New § "Telegram / Discord Usage" — install + configure + restart + use
- Quick Start mentions olp-connect <ip> as family-onboarding command
- package.json `files` field extended to include olp-plugin/ so the
  published tarball ships the plugin

## Test count

672 → 696 (+24 D71-D73 tests in Suite 35: helpers / formatters /
dispatch / error paths). All 696 pass locally.

## Scope discipline

- server.mjs UNTOUCHED (plugin consumes EXISTING endpoints)
- No new npm deps (no Telegram or Discord SDK — OpenClaw provides transport)
- No /v1/messages (out of Phase 4 per ADR 0010)
- No CHANGELOG / package.json version bump (Phase 4 close handles versioning;
  only package.json `files` extended for olp-plugin/ publication)

## Implementor flagged for reviewer

1. /olp doctor returns SSH advisory (no HTTP doctor endpoint yet). When
   future phase exposes /v0/management/doctor, swap advisory branch for
   real fetchJSON + fmtDoctor (already implemented + tested).
2. /olp providers + chain show have no FS access (plugin runs in OpenClaw
   gateway process); registry read via lazy-imported models-registry.json
   from repo root. For live enabled-state visibility users still need
   /olp status (owner-tier) or ssh + olp providers / olp chain show.
3. No live-server wire test in Suite 35 — existing Suites 31/32 already
   cover the integration path against the same endpoints; mock-fetch in
   Suite 35 is sufficient signal for the plugin layer.

## Authority

- ADR 0010 § Phase 4 D-day plan D71-D73 line
- OCP ocp-plugin/index.js (port reference)
- ADR 0010 § Out-of-Phase-4-scope (claude-code.md  rationale)
- 2026-05-26 brainstorm (Top OCP inheritance candidates + prior-art
  survey IDE-specific quirks for cline/cursor/continue docs)

Co-authored-by: dtzp555 <dtzp555@gmail.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
dtzp555-max
2026-05-26 09:35:23 +10:00
committed by GitHub
co-authored by taodeng Claude Opus 4.7
parent 0bdecd1235
commit 53afea47ca
14 changed files with 1801 additions and 0 deletions
+47
View File
@@ -0,0 +1,47 @@
# OLP IDE & client integrations
This directory documents per-tool setup for the IDEs and AI clients OLP
supports. Every page follows the same shape: one-line description, status
icon, copy-paste-able config block, known issues, OLP-specific notes, and a
one-line verification command.
## Index
| Tool | Status | Path | Notes |
|---|---|---|---|
| [Continue.dev](./continue.md) | ✅ Supported | VS Code / JetBrains extension | `config.yaml` (NOT `config.json`); supports custom headers |
| [Cline](./cline.md) | ✅ Supported | VS Code extension | OpenAI-compatible provider; UI field occasionally vanishes (Cline #7128) |
| [Cursor](./cursor.md) | ⚠️ Best-effort | Cursor editor | "Override OpenAI Base URL" — known fragile across releases |
| [Aider](./aider.md) | ✅ Supported | terminal CLI | `OPENAI_API_BASE` env + `openai/` model prefix |
| [Claude Code](./claude-code.md) | ❌ Not supported | terminal CLI | Anthropic wire format only; OLP serves OpenAI wire format. Use Cline instead. |
| [OpenClaw](./openclaw.md) | ✅ Supported | Telegram + Discord gateway | `/olp` slash command via the [`olp-plugin/`](../../olp-plugin/) plugin |
## Status legend
-**Supported** — works against OLP's OpenAI-compatible `/v1/chat/completions`
endpoint; the tool's IR fields flow through OLP's IR without lossy translation
warnings on the documented chain.
- ⚠️ **Best-effort** — works in current versions but the tool has known
upstream bugs around base-URL configuration; expect occasional weirdness.
-**Not supported** — the tool's wire protocol or transport is incompatible
with what OLP serves; recommended alternative is documented on the page.
## How OLP's response headers help debugging
Every response carries (see [README § Response Headers](../../README.md#response-headers)):
- `X-OLP-Provider-Used` — which provider's plugin served the request
- `X-OLP-Model-Used` — which model the served provider used
- `X-OLP-Fallback-Hops``0` = primary chain entry served it
- `X-OLP-Cache``hit | miss | bypass`
- `X-OLP-Latency-Ms` — end-to-end latency at the proxy
When something looks wrong in an IDE, the first sanity check is `curl -i`
against `/v1/chat/completions` with the same key — those headers tell you
whether the IDE config is broken or OLP routed somewhere unexpected.
## Cross-references
- [ADR 0010](../adr/0010-phase-4-charter-operator-and-client-ux.md) — Phase 4 charter; documents why `/v1/messages` is not supported and points to Cline as the recommended Anthropic-CLI replacement.
- [ADR 0011](../adr/0011-anonymous-key-deployment-context.md) — trusted-LAN-only invariant for `auth.advertise_anonymous_key`.
- [`bin/olp-connect`](../../bin/olp-connect) — automated client setup helper (D68-D70).
+106
View File
@@ -0,0 +1,106 @@
# Aider + OLP
[Aider](https://aider.chat) is a terminal-native pair programmer that
edits files in your local git repo and commits each change. It speaks
OpenAI's `/v1/chat/completions` wire format via the `openai/` model
prefix.
**Status:** ✅ Supported.
**Tested against:** Aider v0.6x. Aider's OpenAI integration has been stable
across many releases — this is the most reliable IDE/CLI binding to OLP.
## Quick setup
Three knobs, all environment variables or `.env`:
```bash
# Required: point Aider at OLP's chat-completions endpoint
export OPENAI_API_BASE=http://127.0.0.1:4567/v1
# Required: OLP plaintext token
export OPENAI_API_KEY=olp_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# Then invoke Aider with an OLP-routable model, prefixed `openai/`:
aider --model openai/claude-sonnet-4-5
```
The `openai/` prefix tells Aider to use its OpenAI-compatible adapter for
the named model. Aider's litellm layer parses this and sends the request
to whatever `OPENAI_API_BASE` resolves to.
Replace the API key with the plaintext token printed by `olp-keys keygen
--name=aider`. Family members on the LAN should substitute the OLP host's
IP for `127.0.0.1` (or use `olp-connect <ip>`).
## Aider's `.env` support
Aider auto-loads a `.env` file from the current directory or the git repo
root. The accepted keys are:
```bash
# .env at the project root
OPENAI_API_BASE=http://127.0.0.1:4567/v1
OPENAI_API_KEY=olp_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# Optional: Aider's own AIDER_-prefixed equivalents work too
AIDER_OPENAI_API_BASE=http://127.0.0.1:4567/v1
```
The `AIDER_` prefix wins over the bare prefix when both are set. Pick one;
mixing them invites surprises during debugging.
**Hygiene:** add `.env` to `.gitignore` if your repo doesn't already. The
OLP token is plaintext-recoverable from disk only because the chat surface
explicitly opts into it (see [ADR 0011](../adr/0011-anonymous-key-deployment-context.md))
— do not let your IDE bind unintentionally.
## Known issues
- **No custom-headers support.** Aider does not expose a way to set extra
HTTP headers on outgoing requests. OLP's optional `X-OLP-Chain` /
`X-OLP-Bypass-Cache` headers are therefore not available via Aider —
routing is determined by the model name alone.
- **`/v1` trailing matters.** `OPENAI_API_BASE` must end at `/v1` (without
`/chat/completions`); Aider appends the remainder. Setting it to the bare
host or with a trailing `/chat/completions` causes 404s.
- **Aider sends `max_tokens` by default.** OLP forwards `max_tokens` to
every provider. If you see "model X does not support max_tokens" errors,
the underlying provider rejects it — check `X-OLP-Provider-Used` and
filter that provider out of the chain for the affected model.
## OLP-specific notes
Aider's request shape is faithful to OpenAI's `/v1/chat/completions`
spec — `messages`, `model`, `max_tokens`, `stream`, `temperature`,
`tools`. All map cleanly into OLP's IR with no lossy-translation warnings.
For long-context work (codebase summaries, large diffs), set
`streaming.heartbeat_interval_ms: 15000` in `~/.olp/config.json` (see
[README § Environment Variables](../../README.md#configjson-keys-introduced-at-phase-4))
so the SSE stream stays alive through reverse proxies during silent
windows.
## Test it
```bash
# In a scratch dir:
aider --model openai/claude-haiku-4-5 --no-stream --message "say ok"
```
Then check OLP's audit log:
```bash
npx olp logs 5
```
The most recent entry should show `provider: anthropic` (or whatever
provider haiku routes to in your chain) and `cache_status: miss`.
## Cross-references
- Aider model config docs: https://aider.chat/docs/llms/openai-compat.html
- [`olp-connect`](../../bin/olp-connect) writes `~/.aider/.env` if Aider is
detected on PATH.
+89
View File
@@ -0,0 +1,89 @@
# Claude Code + OLP
[Claude Code](https://docs.anthropic.com/en/docs/claude-code/overview) is
Anthropic's official terminal-native agent. It speaks the Anthropic
`/v1/messages` wire format and cannot be configured to use an
OpenAI-compatible chat-completions endpoint.
**Status:** ❌ Not supported.
## Why
OLP serves only the OpenAI `/v1/chat/completions` wire format. Adding
`/v1/messages` (the Anthropic shape) was explicitly considered for
Phase 4 and rejected, per
[ADR 0010 § Out of Phase 4 scope](../adr/0010-phase-4-charter-operator-and-client-ux.md).
The short version of the rationale:
- **No billing benefit.** After Anthropic's 2026-06-15 split, `claude -p` /
Agent SDK / third-party agent traffic moves out of the Pro/Max
subscription pool and into a separate paid Agent SDK Credit pool. OLP's
fallback discipline ("when one provider's quota runs out, try the next")
does not save money for this traffic — it just routes the same paid
request to a different paid backend. The subscription leverage that
makes OLP valuable for OpenAI-shape traffic does not exist for
Anthropic-shape traffic.
- **Degrades worse on fallback.** When OLP's primary chain entry (Anthropic)
is exhausted, the fallback hop is typically OpenAI Codex or Mistral Vibe.
Those providers speak OpenAI tool-calling schema; OLP would have to
translate Anthropic's `/v1/messages` tool shape into OpenAI tool shape on
every fallback. That translation is lossy and is what ADR 0010 calls out
as "net non-positive under P0 failure".
- **Same outcome reachable via the recommended alternative.** Cline, Cursor,
Aider, and Continue.dev all speak OpenAI's wire format and have parity
with Claude Code on the "AI edits files in my repo" use case. OLP serves
them today.
## What to use instead
**Recommended:** [Cline](./cline.md). It's an in-IDE autonomous coder that
operates on the same loop Claude Code does (read files, propose edits,
run tools, iterate). The "OpenAI Compatible" provider points cleanly at
OLP's `/v1/chat/completions` endpoint. You get OLP's full fallback chain
(Anthropic → OpenAI Codex → Mistral) instead of being pinned to one
provider.
For terminal users specifically:
- **[Aider](./aider.md)** if you want the Claude-Code-style git-aware
pair programmer in the terminal.
- **OpenClaw** if you want Telegram/Discord-driven access to the
fallback chain (see [`openclaw.md`](./openclaw.md)).
## Re-open trigger
ADR 0010 documents the conditions under which OLP would reconsider
`/v1/messages`:
> (a) ADR 0009 P0 confirms interactive-mode billing classification as
> subscription (≥ 2026-07-15) AND (b) maintainer explicitly opens
> Phase 5 "Anthropic-shape hub" scope with the name of at least one
> family member who wants CC access.
Until both conditions fire, OLP intentionally does not implement
`/v1/messages`. The decision is recorded in ADR 0010 § "Out of Phase 4
scope" and ADR 0009 (Anthropic interactive-mode path placeholder).
## If you absolutely must use Claude Code
Point Claude Code at api.anthropic.com directly. OLP cannot proxy that
traffic. You will:
- Burn against the Anthropic Pro/Max OAuth subscription (pre-2026-06-15) or
the Agent SDK Credit pool (≥ 2026-06-15).
- Lose every fallback property OLP provides — when Anthropic's quota is
exhausted, Claude Code stops working until the quota resets.
- Lose OLP's response headers (`X-OLP-Provider-Used` etc.), audit log
entries, cache hits, and `/health` visibility.
This is documented here only so the trade-off is explicit, not as a
recommendation.
## Cross-references
- [ADR 0010](../adr/0010-phase-4-charter-operator-and-client-ux.md) § "Out of Phase 4 scope" — full defer rationale.
- [ADR 0009](../adr/0009-interactive-mode-path-placeholder.md) — Anthropic 2026-06-15 billing split and re-open trigger.
- [`cline.md`](./cline.md) — the recommended alternative for Claude-Code-style workflows.
+94
View File
@@ -0,0 +1,94 @@
# Cline + OLP
[Cline](https://github.com/cline/cline) is an autonomous-coder VS Code
extension. It speaks OpenAI's `/v1/chat/completions` wire format via its
"OpenAI Compatible" provider option.
**Status:** ✅ Supported.
**Tested against:** Cline v3.x (extension version visible in VS Code's
extension panel). Cline's settings UI has shipped multiple variants of the
base-URL field across 2025-2026; if your version doesn't show the field
described below, see the Known Issues section.
## Quick setup
1. Open the Cline panel in VS Code (sidebar icon).
2. Click the settings gear → "API Provider".
3. Select **OpenAI Compatible**.
4. Fill the fields:
| Field | Value |
|---|---|
| Base URL | `http://127.0.0.1:4567/v1` |
| API Key | `olp_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX` |
| Model ID | `claude-sonnet-4-5` |
5. Save. Cline shows the model name in the bottom-right corner of the panel.
Replace the API key with the plaintext token printed by `olp-keys keygen
--name=cline`. Family members on the LAN should substitute the OLP host's
IP for `127.0.0.1` (or use `olp-connect <ip>`).
## Known issues
- **Cline issue [#7128](https://github.com/cline/cline/issues/7128) —
base-URL UI field intermittently disappears.** Several Cline releases in
2025-2026 shipped a settings UI where the "Base URL" field is hidden when
the "OpenAI Compatible" provider is freshly selected. Workaround: switch
to a different provider, save, switch back to "OpenAI Compatible" — the
field returns. Verify the field is visible in your version BEFORE
troubleshooting OLP itself.
- **Cline writes settings to `.vscode/settings.json` under a
`cline.apiConfiguration` key (workspace-scoped) and to the VS Code global
state (machine-scoped) depending on the "save to workspace" toggle.** If
Cline keeps "forgetting" the OLP base URL across VS Code restarts, the
workspace state is overriding the global state. Either save to workspace
explicitly, or clear the workspace key and use global state.
- **Cline sometimes lowercases the model ID before sending.** OLP's
`models-registry.json` uses canonical case (e.g. `claude-sonnet-4-5`).
This is fine — OLP's router lowercases the requested model for chain
lookup. But if you see `unknown model` errors, double-check the exact
string Cline sent via the OLP response headers (curl test below).
## OLP-specific notes
Cline does not expose a custom-headers field in its OpenAI Compatible
provider UI as of v3.x. The OLP routing chain is selected purely from the
model ID — pick the canonical name (e.g. `claude-sonnet-4-5`) that matches
a `routing.chains` key in your `~/.olp/config.json`.
OLP's response headers (`X-OLP-Provider-Used`, `X-OLP-Cache`,
`X-OLP-Latency-Ms`) are not visible in Cline's UI but are captured by VS
Code's Developer Tools Network panel when Cline runs the request.
## Test it
```bash
# 1. Verify OLP accepts Cline-shape requests
curl -sI -X POST http://127.0.0.1:4567/v1/chat/completions \
-H "Authorization: Bearer olp_XXXXXX" \
-H "Content-Type: application/json" \
-d '{"model":"claude-sonnet-4-5","messages":[{"role":"user","content":"ok"}],"max_tokens":5,"stream":false}' \
| grep -i x-olp
```
Expect `X-OLP-Provider-Used: anthropic` (or whichever provider serves
sonnet in your chain) and `X-OLP-Cache: miss` on first request.
## Why not /v1/messages?
Cline supports Anthropic-shape requests via a separate "Anthropic" provider
in its UI. OLP does not implement `/v1/messages`. Use Cline's **OpenAI
Compatible** option pointed at OLP rather than Cline's **Anthropic** option
pointed at api.anthropic.com — the OLP chain gives you fallback to OpenAI
Codex / Mistral / etc. when the Anthropic subscription hits its quota
ceiling. See [ADR 0010 § /v1/messages defer rationale](../adr/0010-phase-4-charter-operator-and-client-ux.md).
## Cross-references
- Cline issue tracker: https://github.com/cline/cline/issues
- [`olp-connect`](../../bin/olp-connect) automates writing the Cline workspace
state.
+95
View File
@@ -0,0 +1,95 @@
# Continue.dev + OLP
[Continue.dev](https://continue.dev) is an open-source autocomplete +
chat extension for VS Code and JetBrains IDEs. It speaks OpenAI's
`/v1/chat/completions` wire format, so it works against OLP with no
shim layer.
**Status:** ✅ Supported.
**Tested against:** Continue.dev v0.10.x (`config.yaml` schema). The
older `config.json` schema (≤ v0.8) is **not** documented here — Continue
deprecated it in late 2025 and emits a one-shot migration warning.
## Quick setup
Edit `~/.continue/config.yaml` (or open the Continue config from the IDE's
extension panel and paste this in):
```yaml
models:
- name: olp-chat
provider: openai
model: claude-sonnet-4-5
apiBase: http://127.0.0.1:4567/v1
apiKey: olp_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
roles:
- chat
requestOptions:
headers:
# Optional: pin which routing chain key applies. If omitted, OLP
# looks up the chain via the model name above.
X-OLP-Chain: claude-sonnet-4-5
- name: olp-autocomplete
provider: openai
model: claude-haiku-4-5
apiBase: http://127.0.0.1:4567/v1
apiKey: olp_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
roles:
- autocomplete
```
Replace the API key with the plaintext token printed by `olp-keys keygen
--name=continue-dev`. Family members on the LAN should substitute the OLP
host's IP for `127.0.0.1` (or use `olp-connect <ip>` to do this for them
automatically).
## Known issues
- **`apiBase`, NOT `baseURL`.** Continue's YAML schema uses `apiBase` (no
`URL` casing). The older `config.json` `baseURL` key was renamed during the
v0.10 schema cut. If you copy a snippet from a 2024 blog post and it
silently routes to api.openai.com, this is why.
- **Trailing `/v1` matters.** OLP's chat-completions endpoint is at
`/v1/chat/completions`; Continue appends `/chat/completions` to whatever
`apiBase` resolves to. Set `apiBase: http://host:4567/v1` (with `/v1`),
not the bare host.
- **Provider stays `openai`.** Continue's `provider: anthropic` would send
Anthropic-shape requests to `/v1/messages`, which OLP does not implement
(see [`claude-code.md`](./claude-code.md) for the rationale).
## OLP-specific notes
Continue's `requestOptions.headers` lets you pin OLP-specific routing
behaviour without altering the model name itself. Useful headers:
- `X-OLP-Chain: <chain-key>` — explicitly select the routing chain.
- `X-OLP-Bypass-Cache: true` — force a fresh spawn for the next request
(debugging cache-poisoning suspicions).
OLP's response headers (`X-OLP-Provider-Used`, `X-OLP-Cache`, etc.) are
visible via VS Code's `Developer: Toggle Developer Tools` → Network panel
when Continue runs the request.
## Test it
After config save, open the Continue chat panel and send a one-word
message ("ok"). Then on the terminal:
```bash
curl -sI -X POST http://127.0.0.1:4567/v1/chat/completions \
-H "Authorization: Bearer olp_XXXXXX" \
-H "Content-Type: application/json" \
-d '{"model":"claude-haiku-4-5","messages":[{"role":"user","content":"ok"}],"max_tokens":5}' \
| grep -i x-olp
```
Expect `X-OLP-Provider-Used: anthropic` (or whichever provider your chain
routes haiku to) and `X-OLP-Cache: miss` on first request, `hit` on the
second.
## Cross-references
- Continue.dev config reference: https://docs.continue.dev/customization/models
- [`olp-connect`](../../bin/olp-connect) automates the Continue.dev branch
of this setup.
+116
View File
@@ -0,0 +1,116 @@
# Cursor + OLP
[Cursor](https://cursor.com) is an AI-first VS Code fork. It has an
"Override OpenAI Base URL" setting that, when populated, routes its
default-model traffic to your URL using the OpenAI wire format.
**Status:** ⚠️ Best-effort.
**Reason:** Cursor's base-URL override is known to be fragile across
releases. Multiple 2025-2026 forum threads document the setting silently
reverting, model-list dropdowns not populating from the override URL, and
streaming responses falling back to the default backend on parse errors.
The behaviour is not specific to OLP — every OpenAI-compatible proxy
maintainer documents the same caveats — but Cursor's release cadence is
faster than most third-party proxies can test against.
## Quick setup
1. Open Cursor → Settings → "Models" → enable **OpenAI API Key**.
2. Paste your OLP plaintext token into the **API Key** field.
3. Click "Override OpenAI Base URL" and paste:
```
http://127.0.0.1:4567/v1
```
4. Click "Verify". Cursor sends a probe; on success the indicator turns
green.
5. **Crucial step:** in the model list, disable every model that is NOT
in your `~/.olp/config.json` `routing.chains`. Cursor's chat will round-
robin across enabled models and any model OLP can't route will error.
Replace the API key with the plaintext token printed by `olp-keys keygen
--name=cursor`. Family members on the LAN should substitute the OLP host's
IP for `127.0.0.1` (or use `olp-connect <ip>`).
## Known issues
- **Override URL silently reverts on Cursor update.** Two reported variants:
(a) the field empties; (b) the field shows the OLP URL but Cursor still
hits api.openai.com under the hood. Workaround: after every Cursor
update, re-open settings, click "Verify" again, and check the OLP
server's `/health` for incoming probe requests.
- **Model-list dropdown does not populate from the override URL.** Cursor
hardcodes its model list rather than reading `GET /v1/models`. This is
why step 5 above is required — there is no way to make Cursor "discover"
your models. You have to disable each model individually that OLP can't
serve.
- **Streaming response parsing is stricter than OpenAI's actual SSE spec.**
Cursor occasionally falls back to the default backend if the SSE stream
contains a slightly malformed chunk (e.g. an empty `data:` line that
OpenAI's API does emit but Cursor's parser doesn't expect). OLP's SSE
emitter follows the spec; this is on Cursor's side. If you see traffic
hitting api.openai.com despite the override, this is the most likely
cause.
- **Cursor's "Tab" autocomplete is NOT covered by the override.** Tab
completion uses a Cursor-proprietary endpoint that is not affected by the
OpenAI base URL setting. Only the chat panel is. This is documented
Cursor behaviour and is not a bug.
## OLP-specific notes
Cursor sends `model: "gpt-4"` or `model: "gpt-3.5-turbo"` (legacy aliases)
unless you explicitly select another from its dropdown. Add aliases to
your `~/.olp/config.json` `routing.chains` so these route somewhere sane:
```json
{
"routing": {
"chains": {
"gpt-4": [ { "provider": "openai", "model": "gpt-5" } ],
"gpt-3.5-turbo": [ { "provider": "openai", "model": "gpt-5-mini" } ]
}
}
}
```
(Substitute the OpenAI Codex model names listed by `olp models`.)
## Recommendation
**Do not engineer workarounds for Cursor-side bugs.** Cursor's release
cadence will fix or re-break the override URL handling at unpredictable
intervals. If your daily-driver flow is unreliable, switch to Cline (see
[`cline.md`](./cline.md)) — it has a stable OpenAI-compatible provider
that does not break across releases.
## Test it
```bash
curl -sI -X POST http://127.0.0.1:4567/v1/chat/completions \
-H "Authorization: Bearer olp_XXXXXX" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-4","messages":[{"role":"user","content":"ok"}],"max_tokens":5}' \
| grep -i x-olp
```
After hitting "Send" in Cursor's chat, check the OLP server's recent
requests via:
```bash
npx olp logs 10
```
If you don't see Cursor's request in the audit log, traffic isn't reaching
OLP — re-check the override URL.
## Cross-references
- Cursor forum threads on base-URL fragility: https://forum.cursor.com/ (search "OpenAI base URL")
- [`olp-connect`](../../bin/olp-connect) writes Cursor's `cursorrc` if
detected, but cannot guarantee the override survives a Cursor update.
+146
View File
@@ -0,0 +1,146 @@
# OpenClaw + OLP
[OpenClaw](https://github.com/openclaw/openclaw) is a multi-bot gateway
that exposes slash commands on Telegram, Discord, and other chat
surfaces. OLP ships [`olp-plugin/`](../../olp-plugin/) as a native
OpenClaw plugin that registers a `/olp` slash command with read-only
parity to the local `olp` CLI.
**Status:** ✅ Supported.
## What you get
After install, from Telegram or Discord:
| Slash command | Maps to | Tier |
|---|---|---|
| `/olp status` | GET `/v0/management/status` | owner |
| `/olp health` | GET `/health` | public |
| `/olp usage` | GET `/v0/management/dashboard-data` | owner |
| `/olp models` | GET `/v1/models` | public |
| `/olp cache` | GET `/cache/stats` | owner |
| `/olp providers` | local registry view | public |
| `/olp chain show [model]` | local chain view | public |
| `/olp doctor` | informational (HTTP endpoint not yet shipped) | — |
| `/olp help` | usage text | — |
**Mutating subcommands are deliberately not exposed via chat.** `keygen`,
`revoke`, `restart`, `logs` are SSH-only. See
[`olp-plugin/README.md`](../../olp-plugin/README.md#what-you-can-not-do-from-chat-by-design)
for the rationale.
## Quick setup
### 1. Install the plugin
Two install paths — either works.
**Option A — OpenClaw CLI:**
```bash
openclaw plugins install /path/to/olp/olp-plugin/
```
**Option B — symlink:**
```bash
mkdir -p ~/.openclaw/extensions/
ln -s /path/to/olp/olp-plugin/ ~/.openclaw/extensions/olp
```
### 2. Mint a bot owner key
Run on the OLP host (NOT in chat):
```bash
npx olp-keys keygen --owner --name=openclaw-bot
```
Capture the printed plaintext token — it is shown exactly once.
### 3. Configure
Edit `~/.openclaw/openclaw.json`:
```json
{
"plugins": {
"olp": {
"proxyUrl": "http://127.0.0.1:4567",
"apiKey": "olp_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
}
}
```
### 4. Restart the gateway
```bash
openclaw gateway restart
```
The plugin is now active. Try `/olp help` in your bot's chat.
## Known issues
- **`openclaw gateway restart` is required after install.** OpenClaw caches
plugin discovery at gateway start. `openclaw plugins reload` does not
guarantee a fresh import of the plugin module.
- **Owner key revocation kicks the plugin out immediately.** If you revoke
the bot's owner key (`npx olp-keys revoke --id=<id>`), the next `/olp
status` will return `401 unauthorized`. Mint a replacement key with a
new name and edit `~/.openclaw/openclaw.json`; do NOT reuse the revoked
key's UUID.
- **Long responses are truncated.** Telegram caps messages at ~4096
characters. The plugin truncates with a `... [truncated, use SSH for
full]` suffix when the rendered output would exceed ~3900 chars. Use
SSH + the local `olp` CLI for full output.
## OLP-specific notes
The plugin honours these env vars on the OpenClaw gateway process:
- `OLP_PROXY_URL` — full URL, overrides plugin config `proxyUrl`.
- `OLP_PORT` — port only, localhost assumed; overrides `proxyUrl` when
`OLP_PROXY_URL` is unset.
If you run the OpenClaw gateway under launchd or systemd with custom env
vars, set `OLP_PROXY_URL` there rather than editing the plugin config —
that way the same plugin install can serve multiple OLP hosts.
## Per-bot vs maintainer key
**Always create a dedicated bot key**, never the maintainer's personal
owner key. The bot key:
- Has its own `id` so you can revoke it without affecting other clients.
- Has its own audit-log entries so you can attribute `/v0/management/*`
traffic to the bot.
- Can be rotated routinely (every 90 days etc.) without coordinating with
the maintainer's daily-driver IDE configs.
## Test it
After restart, in Telegram or Discord:
```
/olp health
/olp status
/olp models
```
Each should return a code-block-wrapped response within a few seconds.
If you see `401 unauthorized`: the configured key is missing / wrong /
revoked. If you see `403 forbidden`: the key is not owner-tier. If you
see `OLP error: fetch failed` or similar: the `proxyUrl` is unreachable
from the gateway host (test with `curl http://<proxyUrl>/health` from
that host).
## Cross-references
- [`olp-plugin/README.md`](../../olp-plugin/README.md) — full plugin docs.
- [ADR 0010 § Phase 4 D71-D73](../adr/0010-phase-4-charter-operator-and-client-ux.md) — the plugin's charter.
- [OCP `/ocp` plugin](https://github.com/dtzp555-max/ocp/tree/main/ocp-plugin) — the OCP predecessor (includes mutating subcommands that OLP deliberately drops).