Docs

ChatPanel from the terminal and from your own code — the CLI, the SDKs, and the local gateway's API they all use.

The pieces The gateway CLI SDK HTTP API Tokens & pairing Versions & compatibility

The pieces

Every ChatPanel client — the browser extension, the desktop app, the terminal CLI, and anything you build with the SDK — is a client of the same thing: the gateway, a small server on your machine that only answers on 127.0.0.1:4320. It replaces names, emails, numbers and secrets with placeholders before a request leaves the machine and restores them in the reply; routes each turn to the model or coding agent you pick; and holds what every client shares — your searchable history (chats, notes, meetings), durable memory, settings, and the team and project boards.

PieceWhat it isGet it
ExtensionThe side panel in Chrome, Edge and Firefox. Works alone with an in-browser model or your own key.Install
GatewayThe local privacy proxy. Brings redaction, routing, dictation, and the shared history to every client. Bundles the bridge, which runs coding agents (Codex, Claude Code, OpenCode…) and MCP servers.below
DesktopA native app that bundles the gateway and bridge, so there is one thing to install.Install
CLIchatpanel — the same chats, models, tools, memory and teams in a terminal, and as commands you can script.below
SDKTyped clients for TypeScript, Python, Go, Rust, Java, Kotlin, C#, Ruby, PHP, Swift and Dart — your application as one more client.below

The gateway

The CLI and the SDKs need it running. Pick one of these (the desktop app counts):

# the standalone binary (macOS / Linux) — also installs the bridge
curl -fsSL https://dl.chatpanel.net/install.sh | bash

# or, with Node 22+
npm i -g @chatpanel/gateway
chatpanel-gateway

Check it: curl -s http://127.0.0.1:4320/health answers with its version. The extension detects it automatically; nothing else to configure. Details and which build to pick: FAQ.

CLI — chatpanel

npm i -g @chatpanel/cli

chatpanel                      # the chat screen (also `cpcli`)
chatpanel -c                   # continue the last chat · -r picks one
chatpanel ask "what did we decide about the rollback?"

The screen is the side panel in your terminal: settled messages scroll into your terminal's own history, the reply streams with what the turn is doing (which tool it called, what a coding agent is reading), and every answer ends with what it cost. Type / for the menu — /model, /search, /memory, /skills, /teams, /redact… and every skill, recipe, team and agent you saved in the extension or the desktop is a /command here too, because they live on the gateway. !git status runs a shell command and carries its output into your next question. Ctrl+P picks a model, Ctrl+O opens a past chat, Esc stops a reply.

Commands you can script

chatpanel ask "<question>" [--model <id>] [--chat <id> | --continue] [--no-tools] [--redaction off] [--json]
chatpanel models [--all]                 # what can answer, agents first
chatpanel chats [filter]                 # your chats; continue one with --chat <id>
chatpanel show <record id>               # a chat, note or meeting
chatpanel search "<query>" [--type note] [--since 7d]
chatpanel memory [remember "<fact>" | forget <id>]
chatpanel skills · teams · runs [<id> | stop <id>]
chatpanel sync [--push] [--pull]
chatpanel status
chatpanel config set model codex         # this terminal's defaults
chatpanel redact "<text>"                # what the model would receive

ask reads stdin as context when piped, streams the answer, and prints the chat id so you can continue it. --json gives a script the answer, the model, usage, timing and the tool steps in one object — never scrape prose.

# review a diff with a coding agent, through the redacting proxy
git diff | chatpanel ask "review this for bugs" --model claude

# a script: one JSON object on stdout
chatpanel ask "list the action items from yesterday's standup" --json | jq -r .answer

# search everything you've captured — chats, notes, meetings — then read one
chatpanel search "rollback" --since 30d
chatpanel show chat:mu5bogfxq6ouzk

# what would the model actually receive?
chatpanel redact "Call Jordan Blake at 555-0100 about invoice 4471"
# → Call [[PERSON_1]] at [[PHONE_1]] about invoice [[NUMBER_1]]

Working in a project folder

Start chatpanel inside a repository and it asks, once, whether coding agents may work there. Say yes and a Codex or Claude Code turn from that chat reads and changes files in that folder. /cwd shows or changes it; chatpanel config trust [dir] from a script; ask --cwd <dir> for a one-off. Your home directory and / are never a project.

Everything lives under ~/.chatpanel. CHATPANEL_GATEWAY_URL points the CLI at another gateway. It authenticates to the gateway as you, with the token in ~/.chatpanel/gateway-token (see tokens).

SDK

One OpenAPI contract for the gateway, generated into every language, in the chatpanel-sdk repository. TypeScript and Python are first-class — zero dependencies, streaming, pairing, and a runtime that enforces the rules below. Go, Rust, Java, Kotlin, C#, Ruby, PHP, Swift and Dart are generated whole from the same contract.

LanguageInstallImport
TypeScript / JavaScriptnpm i @chatpanel/sdkimport { ChatPanel } from '@chatpanel/sdk'
Python 3.11+pip install chatpanelfrom chatpanel import ChatPanel
Go 1.23+go get github.com/chatpanel/chatpanel-sdk/generated/gochatpanel "github.com/chatpanel/chatpanel-sdk/generated/go"
Rust, Java, Kotlin, C#, Ruby, PHP, Swift, Dartgenerated/<lang> in the repo, each with its own README

Ask a model through the privacy proxy

import { ChatPanel } from '@chatpanel/sdk';

const cp = await ChatPanel.fromEnvironment();   // finds ~/.chatpanel/gateway-token

for await (const text of cp.chat.text({
  model: 'claude',                                // any id from cp.models.list(); 'claude/opus' picks the agent's model
  messages: [{ role: 'user', content: 'Summarise the rollback decision for the team.' }],
})) {
  process.stdout.write(text);                    // names/emails were redacted on the way out, restored here
}

Search history, recall memory, preview redaction

// Several phrasings, rank-fused; briefs (compactions of many records) come first
const { results } = await cp.history.smartSearch({
  question: 'what did we decide about the rollback?',
  queries: ['rollback decision', 'roll back friday'],
  limit: 5,
});
const record = await cp.history.get({ id: results[0].id, maxChars: 4000 });

// Durable facts about the user, as a prompt block you can drop into your own model call
const { block } = await cp.memory.recall({ text: 'how does the user like answers written' });

// Writes need the token (fromEnvironment found it); attribution is recorded
await cp.memory.remember({ text: 'Prefers short answers with a code sample', source: { via: 'my-app' } });

// What the model would receive if this text were sent now — never the real values back
const { text, count } = await cp.redaction.preview({ text: 'Call Jordan Blake at 555-0100' });
// text === 'Call [[PERSON_1]] at [[PHONE_1]]', count === 2

// Follow a team run live
for await (const ev of cp.teams.runEvents(runId, { after: -1 })) console.log(ev.data.type);

From a web page

A browser cannot read the token file, so it pairs: the user runs chatpanel-gateway pair (or opens the desktop's pairing screen) and types the six-digit code into your page.

const cp = new ChatPanel();                       // http://127.0.0.1:4320; localhost origins are allowed
const { token } = await cp.pair(codeTheUserTyped); // single use, five minutes
// keep `token` somewhere only this user can read; next time: new ChatPanel({ token })

What every SDK guarantees

The SDK never redacts by itself — redaction is the gateway's job and happens between the gateway and the model. Your code sees the user's real text on both sides, like any local client; redaction.preview shows what the model would get.

The HTTP API

Everything the SDKs do is plain HTTP on 127.0.0.1:4320, described in one OpenAPI document. The chat endpoint is OpenAI-compatible, so any tool that takes a base URL can use the gateway as its "provider" and get redaction and routing for free.

# is it up, and which version?
curl -s http://127.0.0.1:4320/health

# what can answer (coding agents first; `available` says whether the CLI is installed)
curl -s http://127.0.0.1:4320/v1/models | jq '.data[] | {id, provider_type, available}'

# a turn — OpenAI shape; add "stream": true for server-sent events.
# A coding agent (codex, claude, …) needs the token; a cloud/API model does not.
curl -s http://127.0.0.1:4320/v1/chat/completions -H 'content-type: application/json' \
  -H "Authorization: Bearer $(cat ~/.chatpanel/gateway-token)" \
  -d '{"model":"codex","messages":[{"role":"user","content":"Reply with the single word: pong"}]}'

# search your history
curl -s http://127.0.0.1:4320/v1/history/search -H 'content-type: application/json' \
  -d '{"query":"rollback","limit":5,"since":"7d"}'

# what the model would receive
curl -s http://127.0.0.1:4320/redact -H 'content-type: application/json' -d '{"text":"mail alex.rivera@example.com"}'
# {"text":"mail [[EMAIL_1]]","count":1,...}
GroupRoutesAuth
gatewayGET /health · POST /whoami · POST /pair · POST /pair/code · GET /auditopen · open · open · token · token
models / chatGET /v1/models · POST /v1/chat/completionsopen · open for API models, token for coding agents (401 otherwise)
redactionPOST /redactopen
historysearch · smart-search · related · status · list · get · records · stream (SSE) · ingest · PUT recordsreads open · writes token
memorylist · recall · remember · forget · syncreads open · writes token
prefsGET/POST/DELETE /v1/prefs · /v1/prefs/events (SSE)open
teams · projects · agents · engines · skillsruns, boards, events (SSE), scorecards, engine cards, skillsopen

Errors are { "error": { "message", "type" } } with the HTTP status; type is a stable word (not_found, invalid_request, unavailable, …). Admin and destructive routes (/config, /logs, clearing history or memory) exist for the extension and the CLI and are deliberately not part of the SDK contract.

Tokens & pairing

Reads on the /v1 data plane are open to any process on your machine — that is the product; the gateway only listens on loopback and rejects web origins it does not know. Writes that change what every client sees (remember, forget, ingest) and anything admin-shaped need the per-install token the gateway writes to ~/.chatpanel/gateway-token (mode 0600). A program running as you may read it — the CLI does, and ChatPanel.fromEnvironment() does. Send it as Authorization: Bearer …. Asking a coding agent (codex, claude, opencode…) needs it too: an agent turn spawns a process on your machine, so the gateway only takes it from a caller you trust — an anonymous request gets 401 agent_lane_token_required. Cloud and local API models are a proxy hop and stay open.

A client that cannot read that file — a web page, a container — pairs: you run chatpanel-gateway pair, get a six-digit code (single use, five minutes, five attempts), and the client exchanges it with POST /pair. POST /whoami tells any client what the gateway makes of it.

curl -s -X POST http://127.0.0.1:4320/whoami
# {"ok":true,"trust":"local","paired":false,"version":"0.11.1"}

curl -s -X POST http://127.0.0.1:4320/whoami -H "Authorization: Bearer $(cat ~/.chatpanel/gateway-token)"
# {"ok":true,"trust":"token","paired":true,"version":"0.11.1"}

Keep a paired token in the platform keychain or a 0600 file — never in a URL, a log, or source control.

Versions & compatibility

The gateway ships continuously; clients update at their own pace. The API is therefore additive only: a new route, a new optional field, never a rename or a removal. An older extension, CLI or SDK keeps working against a newer gateway. The other direction is handled by the SDKs' version gate — each route knows the gateway version that introduced it and a call your gateway predates is refused with the version you have and the one you need. Update with npm i -g @chatpanel/gateway, the installer, or the desktop app; GET /health tells you what is running.

Contract and generators: chatpanel/chatpanel-sdk (Apache-2.0). Questions: FAQ.