Version: Current
Historical release snapshot. These docs are frozen. Read current docs.
Onboarding
The consumer surface is a browser application mounted ahead of KeyAuth:
/, /i/{token}, /signin, /signout, /app/* and /account. It exists
because a person signing in has no key yet. It is invite-only: there is no
self-registration, no payment flow and no email delivery on this path.
The shape of a deployment
Section titled “The shape of a deployment”Two facts drive it, both from the code.
The public host must be in ACUMEN_ALLOWED_HOSTS. Guard checks Host
before any handler and answers 403 forbidden host otherwise; the same set gates
a browser Origin.
The listener must stay loopback with no process bearer. main reads
ACUMEN_BEARER_TOKEN only for a non-loopback bind, and Guard then demands it
on every path except /healthz. A browser cannot send that header, so a
non-loopback consumer deployment answers 401 unauthorized on /, /signin
and every page.
Do not embed the token in a page and do not add a consumer exemption: either would hand the process token to every visitor. The supported shape is loopback plus TLS and policy at the edge:
browser ──TLS──► Caddy (public host) ──► 127.0.0.1:4020 ├─ /console*, /metrics, /health, /readyz, │ /v1/router/*, /debug/* → 404 └─ /, /i/*, /signin, /app/*, /account → acumenCaddy must send X-Forwarded-Proto: https; the session cookie is Secure only
when the request arrived over TLS or carries that header. It must not cache
/app/* or /account; acumen already sends Cache-Control: no-store.
Issue the first invite
Section titled “Issue the first invite”No session exists yet, so bootstrap from the CLI with the same binary and database:
acumen invite create -db /var/lib/acumen/acumen.db \ -email person@example.com -base https://ai.tcp.systemsThe token is printed once and stored only as a hash. -ttl defaults to 72h
and must be greater than zero and at most 720h; -note is optional. Run it as
the account that owns the database file.
The invite URL is a credential. Print it once to the person who needs it, never into a shared log, a ticket, or this documentation.
A person’s path
Section titled “A person’s path”- Open
https://<public-host>/i/{token}. An unknown, expired or already-used token answers410; the page does not say which. - Set a recovery code and a display name, and accept the invite
(
POST /i/{token}). Accepting consumes the token and creates the account, the firstsessiongrant and theacumen_sessioncookie. - Sign in afterwards at
/signinwith the email and recovery code. There is no password reset by email: mail is not configured on this surface. - From
/app, create a key (POST /app/grants/new), read the ledger, and revoke what is no longer needed. The key’s plaintext is shown once.
What the person sees
Section titled “What the person sees”| Path | Purpose |
|---|---|
/ |
public landing page; shadows the operator HTML index when mounted |
/i/{token} |
invite acceptance; needs no session |
/signin, /signout |
session sign-in and teardown |
/app |
the account’s grants, keys and events |
/app/grants/new |
create a key (kind=api grant plus its virtual_keys row) |
/app/grants/{id}/revoke |
revoke a key or session |
/account |
account state, including freeze |
Operator checks after a release
Section titled “Operator checks after a release”tools/edge-check.sh https://<public-host>For a complete migration guide covering base URLs, key handling, model aliases, streaming, error handling, and failover, see Migrating a client to acumen.
The script asserts every operator path is 401/403/404 and /healthz is 200. Run
it from the deploy host after a release. Model doors must answer 401/403 so a
missing door cannot pass as a closed one.
Known gaps
Section titled “Known gaps”POST /v1/router/keyswritesvirtual_keyswithout the matchingapigrant. Enforcement readsvirtual_keys, so the key works; the ledger is incomplete for keys minted on the operator path.- Operator
DELETE /v1/router/keysdeletes the key row but leaves the grant row untouched. Both gaps are recorded, not hidden. - OIDC and passkeys are deferred; sign-in is invite plus recovery code.