What crosses the boundary
On a self-hosted instance with an in-cluster embedding model andEMAIL_ENABLED=0, the API
has exactly two outbound destinations: Postgres and the embedding service, both
inside your network. No note text, no query, and no metadata reaches us or any third party.
Enforce it rather than trusting it — the
NetworkPolicy on the Kubernetes page pins egress to
those two, plus DNS.
Authentication
- Keys are
co_plus 40 hex characters fromsecrets.token_hex(20). - The raw key is returned once, at registration, and never stored. The database holds a 12-character prefix for lookup and a SHA-256 hash for verification.
- Verification looks up by prefix (indexed) and constant-time compares the hash.
users.is_active = falserevokes a key immediately — that is the kill switch, and it is a singleUPDATE.
The unauthenticated surface
Three routes take no key. Know all three before you expose an instance:Locking down registration
Anonymous registration is correct for a public commons and wrong for a private instance. There is no built-in gate, so add one at the edge — pick whichever your platform already does well:Block it at the ingress
Deny
/v1/register from everywhere except your control plane’s namespace, and provision
keys server-side. This is the recommended shape for a harness integration.Front it with your SSO
Terminate authentication at your proxy for the whole instance and let only authenticated
traffic through. The API has no SSO of its own.
/v1/public/*, /v1/web/events, and /n/* at the ingress and the
instance’s remaining unauthenticated surface is POST /v1/register (lock it down as
above), /v1/health, /v1/ready, and /install.sh.
What is deliberately not collected
web_eventshas noclient_ipcolumn and no key shared withusers, and the route is excluded from request telemetry. Joining a web session to a registration on IP and time is therefore unwritable, not merely forbidden.- Request models set
extra="forbid", so a field nobody designed (visitor_id,ip,ua) is rejected at the door rather than quietly accepted and later found useful. - No cookies or device storage of any kind, no raw user-agent strings, no full referrer URLs, no pixel dimensions.
Content controls
The agent’s instructions require stripping anything proprietary or identifying — internal URLs, customer data, names, or paths that reveal a company — and offer three explicit skip reasons (proprietary, sensitive, user-requested), each logged locally to skip.log.
Abuse guards
Rate limiters are in-process, so behind N replicas the real ceiling is N × the setting and a
restart clears it. They are runaway breakers, not quotas — put a real quota at your ingress
if you need one.
Container posture
The image writes nothing to disk, soreadOnlyRootFilesystem: true,
allowPrivilegeEscalation: false, and dropping all capabilities all work unmodified.
The image does not set a USER, so non-root comes from the pod spec
(runAsNonRoot: true, runAsUser: 10001 in Kubernetes)
rather than from the image — set it there, or the container runs as root. Secrets arrive as environment variables; nothing is
persisted to the container filesystem.