d71e0455e3 feat(ocp-connect): auto-discover anonymous key from /health (v1.3.0) (#16)
Closes the zero-config loop opened by #15 (server anonymous allowlist).

## Why

After #15 (v3.7.0) the OCP server exposes the admin-chosen anonymous
key via `GET /health.anonymousKey` whenever `PROXY_ANONYMOUS_KEY` is
set. Before this PR, users still had to copy that key manually and
pass it as `--key` every time they ran `ocp-connect`. This commit
closes the last mile: `ocp-connect <host>` now reads the key from
the server and uses it automatically when no `--key` was provided.

Result: `ocp-connect 172.16.2.30` (zero args) on a fresh machine
configures OpenClaw multi-agent correctly against a v3.7.0 OCP
instance that has `PROXY_ANONYMOUS_KEY` set. No admin coordination,
no per-user keys, no manual flags.

## What changes

`OCP_CONNECT_VERSION` 1.2.0 to 1.3.0.

New Step 2.5 between the existing Step 2 (Show remote info) and
Step 3 (Determine if key is needed). The block:

1. Short-circuits if `--key` was passed explicitly, so user intent
   always wins over auto-discovery.
2. Parses `health_json.anonymousKey` via python3 with try/except,
   defensively treating any parse error as "no anon key" so the
   script falls through to the existing Step 3 path.
3. If the server advertised a non-empty anon key, assigns it to the
   internal `key` variable and prints an info banner with the
   truncated key value and a reference to issue #12 section 14
   Path A so users can understand what happened.

All downstream code (key verification via /v1/models, rc file
exports, launchctl setenv, OpenClaw agentDir profile seeding, smoke
test, IDE hints) works unchanged because it reads the same `key`
variable.

Also: defensive check on `--key` to reject explicit empty values
(`--key ""`) with a clear error message. Existing bash `${2:?msg}`
expansion already rejects empty strings, but the new check is an
extra safety net and gives a friendlier error (`omit --key entirely
for anonymous mode`).

## Backward compatibility

Old OCP servers (less than 3.7.0) that don't have the
`anonymousKey` field in `/health`: `python3 d.get("anonymousKey")`
returns None, new block outputs empty string, `[[ -n "" ]]` is
false, block falls through to the existing Step 3 path. Script
behavior is 100% identical to v1.2.0 for these users.

New OCP servers that haven't set `PROXY_ANONYMOUS_KEY`: field is
null, same fall-through path as above.

No user-visible regression in either case. No new CLI flag, no new
prompt, no new error path for existing users.

## Test evidence

Live offline test on macOS 13 against real 172.16.2.30 (OCP v3.7.0
with `PROXY_ANONYMOUS_KEY=ocp_public_anon_v1`):

Step 1: cold install state
  - stopped OpenClaw gateway
  - rm ~/.openclaw/agents/{main,macbook_bot}/agent/auth-profiles.json
  - stripped models.* and agents.defaults.{model,models} from openclaw.json
  - cleaned OCP LAN block from .bashrc
  - unset OPENAI_BASE_URL and OPENAI_API_KEY from launchctl env

Step 2: ran ~/projects/ocp/ocp-connect 172.16.2.30 (no args)

Output:
  OCP Connect v1.3.0
  Remote OCP v3.7.0 (auth: multi)
  Using server-advertised anonymous key: ocp_publ...n_v1
    (set by admin via PROXY_ANONYMOUS_KEY; see issue #12 section 14 Path A)
  API accessible (3 models available)
  Per-agent auth profile seeded (2):
    - ~/.openclaw/agents/main/agent/auth-profiles.json
    - ~/.openclaw/agents/macbook_bot/agent/auth-profiles.json
  Smoke test passed: OK
  EXIT 0

Step 3: verified profiles contain the anon key
  macbook_bot: key = ocp_public_anon_v1
  main: key = ocp_public_anon_v1

Additional regression tests:
  - ocp-connect 172.16.2.30 --key ocp_real_admin_key -> still uses
    the explicit key, auto-discovery banner NOT shown
  - ocp-connect --version -> "ocp-connect 1.3.0"
  - ocp-connect 172.16.2.30 --key "" -> rejected with clear error

## Code review

One independent opus reviewer. Verdict PASS WITH CONCERNS, 0
blockers. Reviewer's Concern B (--key "" edge case) turned out to
be a false alarm on my side verification: bash `${2:?}` expansion
already rejects empty strings. I added an extra defensive check
anyway for clearer error message and safety if the arg parser is
refactored in the future. Other concerns (nice-to-have
simplifications like `print(k or '')`) are cosmetic and deferred.

Co-authored-by: taodeng <taodeng@Taos-MBP>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 21:12:44 +10:00
2026-04-10 20:37:11 +10:00

OCP — Open Claude Proxy

Status: Stable (v3.6.0) — Feature-complete. Bug fixes only.

Already paying for Claude Pro/Max? Use your subscription as an OpenAI-compatible API — $0 extra cost.

OCP turns your Claude Pro/Max subscription into a standard OpenAI-compatible API on localhost. Any tool that speaks the OpenAI protocol can use it — no separate API key, no extra billing.

Cline          ──┐
OpenCode       ───┤
Aider          ───┼──→ OCP :3456 ──→ Claude CLI ──→ Your subscription
Continue.dev   ───┤
OpenClaw       ───┘

One proxy. Multiple IDEs. All models. $0 API cost.

Supported Tools

Any tool that accepts OPENAI_BASE_URL works with OCP:

Tool Configuration
Cline Settings → OPENAI_BASE_URL=http://127.0.0.1:3456/v1
OpenCode OPENAI_BASE_URL=http://127.0.0.1:3456/v1
Aider aider --openai-api-base http://127.0.0.1:3456/v1
Continue.dev config.json → apiBase: "http://127.0.0.1:3456/v1"
OpenClaw setup.mjs auto-configures
Any OpenAI client Set base URL to http://127.0.0.1:3456/v1

Installation

OCP has two roles: Server (runs the proxy, needs Claude CLI) and Client (connects to a server, zero dependencies).

┌─ Server (always-on device) ─────────────────────────────┐
│  Mac mini / NAS / Raspberry Pi / Desktop                │
│  Claude CLI + OCP server → bound to 0.0.0.0:3456       │
└───────────────────────┬─────────────────────────────────┘
                        │ LAN
    ┌───────────────────┼───────────────────┐
    ▼                   ▼                   ▼
 Laptop             Phone/Tablet        Pi / Server
 (client)           (browser)           (client)

Server Setup

Recommended: Install OCP on a device that stays powered on — Mac mini, NAS, Raspberry Pi, or a desktop that doesn't sleep. This ensures all clients always have access.

Prerequisites:

  • Node.js 18+
  • Claude CLI installed and authenticated (claude auth login)
# 1. Clone and run setup
git clone https://github.com/dtzp555-max/ocp.git
cd ocp
node setup.mjs

The setup script will:

  1. Verify Claude CLI is installed and authenticated
  2. Start the proxy on port 3456
  3. Install auto-start (launchd on macOS, systemd on Linux)
  4. Symlink ocp to /usr/local/bin for CLI access

Single-machine use — just set your IDE to use the proxy:

export OPENAI_BASE_URL=http://127.0.0.1:3456/v1

LAN mode — share with other devices on your network:

# Enable LAN access with per-user auth (recommended)
node setup.mjs --bind 0.0.0.0 --auth-mode multi

Then create API keys for each person/device:

export OCP_ADMIN_KEY=your-secret-admin-key

ocp keys add wife-laptop
#  ✓ Key created for "wife-laptop"
#    API Key: ocp_xDYzOB9ZKYzn...
#    Copy this key now — you won't see it again.

ocp keys add son-ipad
ocp keys add pi-server

Run ocp lan to see your IP and ready-to-share instructions.

Verify:

curl http://127.0.0.1:3456/v1/models
# Returns: claude-opus-4-6, claude-sonnet-4-6, claude-haiku-4

Client Setup

Clients do not need to install Node.js, Claude CLI, or the OCP repo. Only curl and python3 are required (pre-installed on most Linux/Mac systems).

One-command setup — download the lightweight ocp-connect script:

curl -fsSL https://raw.githubusercontent.com/dtzp555-max/ocp/main/ocp-connect -o ocp-connect
chmod +x ocp-connect
./ocp-connect <server-ip>

If the server requires a key, pass it with --key:

./ocp-connect <server-ip> --key <your-api-key>

Or as a one-liner (no file saved):

curl -fsSL https://raw.githubusercontent.com/dtzp555-max/ocp/main/ocp-connect | bash -s -- <server-ip>

Example:

$ ./ocp-connect 192.168.1.100

OCP Connect
─────────────────────────────────────
  Remote: http://192.168.1.100:3456

  Checking connectivity...
  ✓ Connected

  Remote OCP v3.6.0  (auth: multi)

  Server allows anonymous access — no key needed.

  Testing API access...
  ✓ API accessible (3 models available)

  Shell config:
    ✓ .bashrc
    ✓ .zshrc
    OPENAI_BASE_URL=http://192.168.1.100:3456/v1

  System-level (launchctl):
    ✓ OPENAI_BASE_URL set for GUI apps and daemons

  IDE Configuration
  ─────────────────────────────────────
  Detected: OpenClaw (~/.openclaw/openclaw.json)

  Configure OpenClaw to use this OCP? [Y/n] y
  Provider name (models show as <name>/model-id) [ocp]: ocp

  How should OCP models be configured?
    1) Primary — use OCP by default, keep existing models as backup
    2) Backup  — keep current primary, add OCP as additional option

  Choice [1]: 1

  ✓ OpenClaw configured
    Provider: ocp
    Models:
      • ocp/claude-opus-4-6
      • ocp/claude-sonnet-4-6
      • ocp/claude-haiku-4
    Priority: PRIMARY (default model)

    Restart OpenClaw to apply: openclaw gateway restart

  Running smoke test...
  ✓ Smoke test passed: OK

  Done. Reload your shell to apply:
    source ~/.zshrc

The script automatically:

  • Writes env vars to all relevant shell rc files (.bashrc, .zshrc)
  • Sets system-level env vars (launchctl setenv on macOS, environment.d on Linux)
  • Detects and configures IDEs (OpenClaw, Cline, Continue.dev, Cursor)

On macOS, launchctl setenv vars reset on reboot — re-run ocp-connect after restart.

Manual setup — if you prefer not to use the script:

export OPENAI_BASE_URL=http://<server-ip>:3456/v1
export OPENAI_API_KEY=ocp_<your-key>

Add these lines to ~/.bashrc or ~/.zshrc to persist across sessions.


Monitoring (Server-side)

# Per-key usage stats
ocp usage --by-key
#  Key                  Reqs   OK  Err  Avg Time
#  wife-laptop             5    5    0      8.0s
#  son-ipad                3    3    0      6.2s

# Manage keys
ocp keys              # List all keys
ocp keys revoke son-ipad   # Revoke a key

Web Dashboard: Open http://<server-ip>:3456/dashboard in any browser for real-time monitoring — per-key usage, request history, plan utilization, and system health.

OCP Dashboard

Auth Modes

Mode Env Use Case
none CLAUDE_AUTH_MODE=none Trusted home network, no auth needed
shared CLAUDE_AUTH_MODE=shared + PROXY_API_KEY=xxx Everyone shares one key
multi CLAUDE_AUTH_MODE=multi + OCP_ADMIN_KEY=xxx Per-person keys with usage tracking (recommended)

Anonymous Access (optional)

In multi mode, the admin can designate a single well-known "anonymous" key that bypasses validateKey() and grants public read/write access. This is useful for letting LAN users (or clients like OpenClaw multi-agent setups) connect without individual per-user keys.

Enable:

export PROXY_ANONYMOUS_KEY=ocp_public_anon   # or any string of your choice
ocp start                                    # or however you start the server

Client side: the anonymous key value is exposed via GET /health as the field anonymousKey (null when not set). Clients like ocp-connect can auto-discover and use it, so the end user doesn't need to get a personal key from the admin.

Security note: setting this env var is an opt-in to public access — anyone who can reach your OCP endpoint can use it, up to any rate limits you configure. Don't enable this on internet-exposed OCP instances without additional protection.

Not a secret: because /health is an unauthenticated endpoint, the anonymous key is publicly readable by anyone who can reach the server. That is intentional — the key exists so clients can self-configure without out-of-band coordination. Treat it as a convenience handle, not as an access credential.

Important Notes

  • All users share your Claude Pro/Max rate limits (5h session + 7d weekly)
  • ocp usage shows how much quota remains
  • Keys are stored in ~/.ocp/ocp.db (SQLite, zero external dependencies)
  • Admin key is required for key management API endpoints
  • The dashboard (/dashboard) and health check (/health) are always public

Built-in Usage Monitoring

Check your subscription usage from the terminal:

$ ocp usage
Plan Usage Limits
─────────────────────────────────────
  Current session       21% used
                      Resets in 3h 12m  (Tue, Mar 28, 10:00 PM)

  Weekly (all models)   45% used
                      Resets in 4d 2h  (Tue, Mar 31, 12:00 AM)

  Extra usage         off

Model Stats
Model          Req   OK  Er  AvgT  MaxT  AvgP  MaxP
──────────────────────────────────────────────────────
opus             5    5   0   32s   87s   42K   43K
sonnet          18   18   0   20s   45s   36K   56K
Total           23

Proxy: up 6h 32m | 23 reqs | 0 err | 0 timeout

All Commands

ocp usage              Plan usage limits & model stats
ocp usage --by-key     Per-key usage breakdown (LAN mode)
ocp status             Quick overview
ocp health             Proxy diagnostics
ocp keys               List all API keys (multi mode)
ocp keys add <name>    Create a new API key
ocp keys revoke <name> Revoke an API key
ocp connect <ip>       One-command LAN client setup
ocp lan                Show LAN connection info & IP
ocp settings           View tunable settings
ocp settings <k> <v>   Update a setting at runtime
ocp logs [N] [level]   Recent logs (default: 20, error)
ocp models             Available models
ocp sessions           Active sessions
ocp clear              Clear all sessions
ocp restart            Restart proxy
ocp restart gateway    Restart gateway
ocp update             Update to latest version
ocp update --check     Check for updates without applying
ocp --help             Command reference

Install the CLI

# Symlink to PATH (recommended)
sudo ln -sf $(pwd)/ocp /usr/local/bin/ocp

# Verify
ocp --help

Cloud/Linux servers: If ocp: command not found, the binary isn't in PATH. Full path: ~/.openclaw/projects/ocp/ocp

Self-Update

# Check if a new version is available
ocp update --check

# Pull latest, sync plugin, restart proxy — one command
ocp update

Runtime Settings (No Restart Needed)

$ ocp settings maxPromptChars 200000
✓ maxPromptChars = 200000

$ ocp settings maxConcurrent 4
✓ maxConcurrent = 4

How It Works

Your IDE → OCP (localhost:3456) → claude -p CLI → Anthropic (via subscription)

OCP translates OpenAI-compatible /v1/chat/completions requests into claude -p CLI calls. Anthropic sees normal Claude Code usage — no API billing, no separate key needed.

Available Models

Model ID Notes
claude-opus-4-6 Most capable, slower
claude-sonnet-4-6 Good balance of speed/quality
claude-haiku-4 Fastest, lightweight

API Endpoints

Endpoint Method Description
/v1/models GET List available models
/v1/chat/completions POST Chat completion (streaming + non-streaming)
/health GET Comprehensive health check
/usage GET Plan usage limits + per-model stats
/status GET Combined overview (usage + health)
/settings GET/PATCH View or update settings at runtime
/logs GET Recent log entries (?n=20&level=error)
/sessions GET/DELETE List or clear active sessions
/dashboard GET Web dashboard (always public)
/api/keys GET/POST List or create API keys (admin only)
/api/keys/:id DELETE Revoke an API key (admin only)
/api/usage GET Per-key usage stats (?since=&until=&hours=&limit=)

OpenClaw Integration

OCP was originally built for OpenClaw and includes deep integration:

  • setup.mjs auto-configures the claude-local provider in openclaw.json
  • Gateway plugin registers /ocp as a native slash command in Telegram/Discord
  • Multi-agent — 8 concurrent requests sharing one subscription
  • No conflicts — uses neutral service names (dev.ocp.proxy / ocp-proxy) that don't trigger OpenClaw's gateway-like service detection

Install the Gateway Plugin

cp -r ocp-plugin/ ~/.openclaw/extensions/ocp/

Add to ~/.openclaw/openclaw.json:

{
  "plugins": {
    "allow": ["ocp"],
    "entries": { "ocp": { "enabled": true } }
  }
}

Restart: openclaw gateway restart

Telegram / Discord Usage

After installing the gateway plugin, use /ocp slash commands in your chat:

/ocp status        — Quick overview
/ocp usage         — Plan usage limits & model stats
/ocp models        — Available models
/ocp health        — Proxy diagnostics
/ocp keys          — List all API keys (multi mode)
/ocp keys add <name>   — Create a new key
/ocp keys revoke <name> — Revoke a key

Note: Terminal CLI uses ocp <command>, Telegram/Discord uses /ocp <command>.

Troubleshooting

Requests fail or agents stuck

# Clear sessions and restart
ocp clear
ocp restart

# If using OpenClaw gateway
openclaw gateway restart

Usage shows "unknown"

Usually caused by an expired Claude CLI session. Fix:

claude auth login
ocp restart

Environment Variables

Variable Default Description
CLAUDE_PROXY_PORT 3456 Listen port
CLAUDE_BIND 127.0.0.1 Bind address (0.0.0.0 for LAN access)
CLAUDE_AUTH_MODE none Auth mode: none, shared, or multi
OCP_ADMIN_KEY (unset) Admin key for key management (multi mode)
CLAUDE_BIN (auto-detect) Path to claude binary
CLAUDE_TIMEOUT 600000 Request timeout (ms, default: 10 min)
CLAUDE_MAX_CONCURRENT 8 Max concurrent claude processes
CLAUDE_MAX_PROMPT_CHARS 150000 Prompt truncation limit (chars)
CLAUDE_SESSION_TTL 3600000 Session expiry (ms, default: 1 hour)
CLAUDE_ALLOWED_TOOLS Bash,Read,...,Agent Comma-separated tools to pre-approve
CLAUDE_SKIP_PERMISSIONS false Bypass all permission checks
CLAUDE_NO_CONTEXT false Suppress CLAUDE.md and auto-memory injection (pure API mode)
PROXY_API_KEY (unset) Bearer token for shared-mode authentication

Security

  • Localhost by default — binds to 127.0.0.1; set CLAUDE_BIND=0.0.0.0 to enable LAN access
  • 3-tier authnone (trusted network), shared (single key), multi (per-user keys with usage tracking)
  • Timing-safe key comparison — prevents timing attacks on API keys and admin keys
  • Admin-only key management — creating, listing, and revoking keys requires the admin key
  • Public endpoints/health and /dashboard are always accessible without auth
  • No API keys needed — authentication goes through Claude CLI's OAuth session
  • Keys stored locally~/.ocp/ocp.db (SQLite), never sent to external services
  • Auto-start — launchd (macOS) / systemd (Linux)

License

MIT

S
Description
No description provided
Readme MIT
4.6 MiB
Languages
JavaScript 90%
Shell 8.5%
HTML 1.5%