C:\> Documentation

On-prem connector

For teams whose production database must never be reachable from the cloud: a slim container that runs inside your network, dials out to Codepanion, and executes the agent's read-only queries locally. No inbound ports, and your connection string never leaves your network.

Documentation

How it works

The connector is outbound-only. It opens a long-poll control channel to Codepanion and waits. When the agent needs your database, the query travels down that channel, the connector runs it locally — with the same read-only enforcement Codepanion applies everywhere (a read-only connection plus a transaction that is always rolled back, a 5-second timeout, and a 1,000-row cap) — and posts the result back. Your firewall stays closed.

Good to know

The database connection string is configured on your side, as an environment variable on the container. Codepanion never sees it, never stores it, and cannot connect to your database itself — every query is executed by the connector, inside your network, under read-only enforcement that runs on your side of the channel.

Create a connector token

The connector authenticates with a token scoped connector — minted through the same API-token flow as your ingest key, with "scope": "connector". It can't upload code, and your ingest key can't open the connector channel: one credential, one job. The token value is shown once; rotation is the usual create-new-then-revoke-old.

POST /settings/ingest-tokens
{ "label": "datacentre-east", "scope": "connector" }

Run the connector

One container, three environment variables. Run it anywhere inside your network that can reach the database — Docker, Kubernetes, or a VM with Docker installed:

docker run -d --restart unless-stopped \
  --name codepanion-connector \
  -e CODEPANION_URL="https://api.codepanion.app/api" \
  -e CONNECTOR_TOKEN="<your connector-scoped token>" \
  -e CONNECTOR_DB_CONNECTION_STRING="Server=db.internal;Database=prod;User Id=codepanion_reader;Password=...;" \
  ghcr.io/codepanion-app/connector:latest

Use a dedicated read-only database user, exactly as you would for a direct connection — least privilege applies on your side too. SQL Server and PostgreSQL are both supported; the connector detects the provider from the connection string. The image is hardened: a chiseled, distroless-style runtime — no shell, no package manager — that runs as a non-root user.

Point the agent at it

Mark a database environment as connector-mode and the agent routes that environment's queries through the channel instead of a stored connection string:

POST /settings/databases/prod
{ "mode": "connector" }

If the connector isn't running when the agent asks, the query fails fast with a clear "no connector connected" answer — nothing hangs, and the agent tells the support engineer what's wrong.

Catalog resolver (multi-tenant databases)

If your real database isn't a single connection string but is looked up per tenant from a catalog — a registry table that maps a tenant key to its database — the connector can resolve it for you, entirely inside your network. Point the connector at your local catalog database, and a small resolver snippet turns a tenant key into the actual connection string. The connector then runs the agent's query against the resolved database and posts back only the rows — the resolved per-tenant connection string never crosses the channel. We hold nothing.

docker run -d --restart unless-stopped \
  --name codepanion-connector \
  -e CODEPANION_URL="https://api.codepanion.app/api" \
  -e CONNECTOR_TOKEN="<your connector-scoped token>" \
  -e CONNECTOR_CATALOG_CONNECTION_STRING="Server=catalog.internal;Database=registry;User Id=codepanion_reader;Password=...;" \
  ghcr.io/codepanion-app/connector:latest

Mark the environment as both connector-mode and catalog, supplying the resolver snippet and the lookup key:

POST /settings/databases/prod
{
  "mode": "connector",
  "kind": "catalog",
  "resolverJs": "return connection.query({ table: 'tenants', where: [{ column: 'key', op: '=', value: resolveKey }], limit: 1 })[0].cs;",
  "resolveKey": "acme"
}

What runs, and how it's contained

The resolver runs on your connector, in a hardened sandbox: a JavaScript interpreter with no access to the host, the filesystem, or .NET — only a read-only connection.query() against your catalog, under strict time, memory, and statement limits. It is the one place the connector executes a snippet that came from Codepanion. If you would rather the connector never run a snippet delivered over the channel, pin your own resolver locally with CONNECTOR_RESOLVER_JS (inline) or CONNECTOR_RESOLVER_JS_FILE (a file path) — a pinned resolver always wins, and the connector logs which source is active at startup.

Network requirements

Outbound only. No inbound rules, no port forwarding, no VPN. If your egress is allow-listed, permit HTTPS (443) to:

api.codepanion.app                    # the control channel
ghcr.io                               # pulling connector images
pkg-containers.githubusercontent.com  # GHCR's blob storage (image layers)

The two registry hosts cover both your initial docker pull and the connector's future automatic updates.

What we can and can't reach

Through the connector, the agent can do two things: run read-only queries expressed in Codepanion's structured query language, and read your database schema (tables, columns, keys, indexes). That's it. It cannot write — the connector wraps every query in a read-only connection and a transaction that is always rolled back. It cannot run arbitrary SQL — queries arrive as a structured definition that is compiled and parameterised locally, against your actual schema. And it cannot reach anything else on your network: the connector connects only to the database(s) you configured, and nothing in the protocol can change that from our side.

The connector can also reach an on-prem log source the same way: mark an environment's Seq log source as connector-mode and the agent's read-only search_logs / get_log_context queries travel down the same channel, run against your in-network Seq, and post back only the entries. As with the database, we hold no credential — the connector reaches the log store with a node-local key or the host's ambient cloud identity.

The one exception is the optional catalog resolver: if you enable it, the connector runs a resolver snippet to look up a per-tenant connection string. That snippet runs in a hardened, locked-down sandbox (no host, filesystem, or .NET access; read-only catalog queries only; strict resource limits), and the resolved string never leaves your network. If you don't want the connector running a snippet delivered from the cloud, pin your own — see that section.

Updates

The connector reports its version on every heartbeat, so we can see who is running what. Today, updating is a normal docker pull + restart (or your orchestrator's rolling update).

Coming: automatic updates

The connector is designed to keep itself current so you don't have to: roughly every 24 hours it will check ghcr.io for a newer image, verify the publisher's cosign signature, pin the exact image digest it verified, and restart onto it — so the update channel can't be hijacked between check and run. Until that ships, releases are infrequent by design (the connector is deliberately tiny) and announced in the changelog.

Need help getting set up?

Every pilot customer gets hands-on onboarding from the founding team. We'll walk through setup together and make sure everything is working.