npm.io
0.6.28 • Published 14h agoCLI

@chatpanel/gateway

Licence
SEE LICENSE IN LICENSE
Version
0.6.28
Deps
3
Size
226 kB
Vulns
0
Weekly
0

ChatPanel Privacy Gateway

A localhost server that puts ChatPanel's PII redaction / pseudonymization in the middle of two CLI agents — so you can use the privacy features outside the ChatPanel extension. Point opencode / pi at the gateway, and it drives codex / Claude Code behind your existing subscription login (via the bridge), redacting on the way out and restoring on the way back. The model only ever sees opaque placeholders like [[PERSON_1]] / [[EMAIL_2]]the real values never leave your machine.

  opencode / pi   (configured with a custom provider → the gateway)
        │   baseURL → http://127.0.0.1:4320/v1
        ▼
  ┌──────────────────────────────────────────────┐
  │  ChatPanel Privacy Gateway                    │
  │   1. detect + redact   →  [[PERSON_1]] …       │
  │   2. drive the agent behind your login        │
  │   3. restore placeholders in the reply         │
  └──────────────────────────────────────────────┘
        │   POST /chat  (bridge: subscription-authed CLI)
        ▼
  chatpanel-bridge ──spawns──▶ codex / claude   (your ChatGPT / enterprise / Claude login)

Two backends (config backend):

  • bridge (default) — drive the bridge's subscription-authed CLI agents (codex / claude / opencode / pi). No API keys, uses your login. This is the "privacy bridge between two agents" path above.
  • api — forward redacted traffic to a native OpenAI/Anthropic-compatible endpoint (local models, BYO keys). The client's own auth header passes through; the gateway stores no keys.

The redaction engine is the same code the ChatPanel extension runs — the @chatpanel/pii package is the single source of truth, so a privacy feature added once is shared everywhere.

Quick start (bridge backend)

You need the ChatPanel bridge running and logged into codex/claude (the same bridge the extension uses).

# Standalone binary — no Node.js required:
curl -fsSL https://dl.chatpanel.net/gateway/install.sh | bash   # macOS / Linux
#   Windows (PowerShell):  irm https://dl.chatpanel.net/gateway/install.ps1 | iex

# Or via npm (needs Node):
npm install -g @chatpanel/gateway
chatpanel-gateway
# → ChatPanel Privacy Gateway on http://127.0.0.1:4320
#     backend  : bridge (agent: codex, via http://127.0.0.1:4319)

Binary vs. npm — same features, very different local-AI speed. Both run identical redaction/routing. But the standalone binary runs the local models (speech-to-text, diarization, NER) on the WASM runtime — fp32-only, single-threaded, slow. The npm install uses the native runtime with quantized (q8) models — in our tests ~10× faster speech-to-text (real-time even on larger, more accurate models). If you'll use voice/meeting features, install via npm. Don't run both — they can shadow each other on PATH; check GET /healthstt.runtime (native vs wasm).

Then point your front-end agent at it. opencode (opencode.json):

{
  "provider": {
    "chatpanel": {
      "npm": "@ai-sdk/openai-compatible",
      "options": { "baseURL": "http://127.0.0.1:4320/v1" },
      "models": { "codex": {}, "claude": {} }   // selects the agent behind the gateway
    }
  }
}

Now opencode talks to codex through the gateway — every prompt is redacted before codex sees it, and the reply is restored before opencode renders it. The request's model (codex/claude/opencode/pi) picks which agent the bridge drives; otherwise the configured default (codex) is used.

Quick start (api backend — no bridge)

If all you want is the gateway as a redacting proxy in front of an API model, you do not need the bridge. Set backend: "api" and (optionally) point the gateway's upstream at your provider — in ~/.chatpanel/gateway.config.json:

{
  "backend": "api",
  "upstreams": {
    "openai":    { "baseUrl": "https://api.openai.com" },
    "anthropic": { "baseUrl": "https://api.anthropic.com" }
  }
}

Then point your client at the gateway and send your own API key — the gateway redacts, forwards to the provider with your key (it stores none), and restores the reply:

# In your CLIENT's environment (NOT the gateway's — see the footgun below):
export OPENAI_BASE_URL=http://127.0.0.1:4320/v1     # OpenAI-compatible: codex / aider / cursor / SDKs
export ANTHROPIC_BASE_URL=http://127.0.0.1:4320     # Claude Code / Anthropic SDK

To target a non-OpenAI provider (a local model, OpenRouter, Azure, …) change the gateway's upstreams.*.baseUrl in the config above — that's where the gateway forwards to. Flow: client → gateway (redact) → provider (your key) → gateway (restore) → client.

Footgun: OPENAI_BASE_URL means two different things — for your client it's "where the gateway is", for the gateway it's "where my upstream is". Don't set OPENAI_BASE_URL=…:4320 in the gateway's own environment, or it forwards to itself (the loop guard returns 508). Set the gateway's upstream in the config file; use the env var only in the client's shell.

Name/org redaction is built in (in-process NER, no Python)

Deterministic redaction (emails, phones, cards, SSNs, API keys, IPs) needs no setup. To also blind names, organizations and locations, the gateway runs an in-process entity detector — an ONNX transformer model via transformers.js — with ner.autostart on (the default). There's no Python, no second port, no separate process: the same model runs identically on macOS / Windows / Linux. The model loads from ~/.chatpanel/models and is downloaded once on first run if absent (set ner.allowDownload: false to require it be pre-placed). It's fail-open, so if the model can't load the gateway just runs deterministic-only. Once the detector is ready, redaction switches to the full tier automatically.

The default model (Xenova/bert-base-NER) matches or beats spaCy's small model on people/orgs/locations. Larger or alternative models can be installed from the ChatPanel extension's Gateway settings.

Prefer a local LLM or your own external NER service? Set redaction.detection yourself and the gateway won't load the bundled one (yours takes precedence).

Configuration

Precedence: defaults < gateway.config.json (or $CHATPANEL_GATEWAY_CONFIG) < env vars. See gateway.config.example.json.

Key Env Default Meaning
backend bridge bridge (drive CLI agents via login) or api (forward to a provider)
bridge.url http://127.0.0.1:4319 the ChatPanel bridge
bridge.agent codex default agent the bridge drives
bridge.token (auto) bridge bearer token; empty = read ~/.chatpanel/bridge-token
host / port CHATPANEL_GATEWAY_HOST / _PORT 127.0.0.1 / 4320 bind address
upstreams.openai.baseUrl OPENAI_BASE_URL https://api.openai.com api backend only
upstreams.anthropic.baseUrl ANTHROPIC_BASE_URL https://api.anthropic.com api backend only
redaction.tier CHATPANEL_REDACTION_TIER basic basic (regex) or full (+ NER + dictionary)
redaction.detection (off → bundled engine) external detector; set to override the bundled in-process one
redaction.dictionary [] custom { value|pattern, type, alias? } entries
ner.autostart true load the bundled in-process NER on startup
ner.model Xenova/bert-base-NER model id under ~/.chatpanel/models
ner.allowDownload true download the model on first run if absent

Endpoints

Route Behavior
GET /health { ok, version, backend, tier }
GET /v1/models the agent(s) this gateway exposes
POST /v1/chat/completions OpenAI protocol — redact → backend → restore
POST /v1/responses OpenAI Responses protocol (Codex)
POST /v1/messages Anthropic protocol (Claude Code)

Streaming (SSE) is supported on all three: placeholders are restored on the fly, holding back a tail so a token split across chunks ([[PERSON_1]]) still restores cleanly.

How it fits with ChatPanel

The extension redacts inside the browser; the bridge lets the browser drive local CLI agents. This gateway reuses the bridge to put the same redaction engine (@chatpanel/pii) in front of any agent — so non-browser tools get the privacy too, and the agent's own multi-turn loop is blinded, not just the first prompt.

Caveats

  • Reversibility is best-effort: if the model paraphrases a placeholder instead of echoing it, that one reference shows the token. The privacy guarantee (the real value never left the device) always holds.
  • A dictionary alias is a permanent pseudonym — the agent sees the alias, not the original, by design.
  • Code edits: redacting values that appear inside source can affect round-trip edits. The default tier touches only structured secrets and (in full) detected entities — keep your dictionary prose-focused.

License

Source-available under the same license as the ChatPanel extension and bridge — see LICENSE.

Keywords