Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Platform operator and org admin

The person who stands rolter up and hands it to everyone else. In a small shop that is one person holding superadmin; in a larger one it splits into a platform operator (superadmin: the deployment, its policies and its fleet) and an org admin (admin at the org: its providers, people, keys and budgets). The scripts mark which of the two a step needs.

Goal: from nothing to “our people and our applications call our models through rolter, inside limits we chose, and we can see what they did.”

Dogfood accounts: dev@rolter.local (superadmin), orgadmin@rolter.local (admin at org default). See dogfood data.

The observer watches: audit_log for every mutation below, ui_events for the Getting started card and the sheets, and Cluster Config for the config version reaching the gateway after each change.

A0 — choose the install shape

The first fork, decided by one question: who will use it, and from where?

branchwhenshape
A0-a“I want to see it work” — one person, one laptoprolter easy-up: no database, no keys, loopback only
A0-bone person, one host (trial)docker compose -f docker/docker-compose.yml up -d: Postgres, Redis, ClickHouse, both planes (open by design, see below)
A0-cproductionHelm (charts/rolter), managed Postgres/Redis/ClickHouse, TLS in front, secrets from a manager
A0-dno internet at allA0-b or A0-c from mirrors (air-gapped)

docker/docker-compose.yml is the local stack and is open on purpose: the control plane binds every interface with ROLTER_ALLOW_OPEN_MODE=1, 4001 is published, no admin token is set, the file reads none of the A0.5 secrets, and its gateway serves the bundled rolter.toml instead of polling the control plane. It also publishes Postgres (example rolter/rolter login), Redis (no password) and ClickHouse (passwordless default user) on every interface, so an admin token added by hand still leaves the data reachable around it. A0-b is a single-person trial until a compose shape for a shared host exists (#1890); a team goes to A0-c.

A0-c has its own gap: with default values the chart’s preflight init container cannot pass (preflight.strict fails on the 0.0.0.0 bind the Service needs, and the gateway pod runs the control plane’s checks), so today an install sets preflight.enabled=false (#1939).

A0-a — five minutes, no credentials

#stepwhereexpectstatus
A0.1start everythingrolter easy-upboth planes up; the startup banner prints a ready-to-run curl for fake-llmworks
A0.2call the built-in modelthe printed curl, or the dashboard’s Playgrounda deterministic lorem-ipsum completion; no provider or key configuredverified
A0.3see the requestObservability → LLM Logs (needs ClickHouse)the row, with model fake-llm and a latencyworks
A0.4notice the deployment is openthe dashboard banneran open-mode banner: no admin token, so anyone who reaches the port is superadminworks

A0-b / A0-c — a real deployment

#stepwhereexpectstatus
A0.5generate the deployment secretsrolter init (preflight)admin token, internal token, KEK, key pepper and session pepper written somewhere they outlive a restartworks
A0.6bring the stack updocker compose … up -d, or helm installPostgres, Redis, ClickHouse healthy; migrations applied on control-plane bootverified (compose datastores); partial on constrained hosts — #1819; the compose planes do not take the A0.5 secrets — #1890; the chart’s default preflight cannot pass — #1939
A0.7check the configuration before trusting itrolter checkadmin token, KEK and database URL present; a warning for a missing key pepper, a missing session pepper or a control plane on every interfaceworks
A0.8create the first accountrolter-seed --admin-email … --admin-password …a superadmin that can sign in; the org, team and project default existpartial — #1897 (verified from a checkout; not in the image or package)
A0.9sign in and enrol a second factordashboard sign-in, then Settings → My Virtual Keys → Two-factor authenticationTOTP enrolled, ten recovery codes shown onceworks
A0.10confirm the planes agreeCluster Configevery gateway node live and converged on the current config versionverified

A1 — decide how people sign in

The second fork: does the company have an identity provider rolter should trust? Branches A1-a to A1-c are alternatives; A1-d and A1-e combine with any.

A1-a — no identity provider: invitations and passwords

#stepwhereexpectstatus
A1a.1invite a colleague at a scope and roleGovernance → Users → Invite user · POST /api/v1/orgs/{org}/invitationsa one-time link, valid for days, naming the role and scope it grantsverified
A1a.2get the link to themcopy the link into chat or email by handthe invitee receives itpartial — #1828
A1a.3the invitee accepts and chooses a passwordthe link opens Accept invitationan account with exactly the invited role; the link is dead once usedverified
A1a.4require a second factor for the orgGovernance → Single Sign-On → Org sign-in policy (mfa_policy)members without a factor are refused a session until they enrol (the confirmation says so)partial — #1852
A1a.5withdraw a link sent to the wrong addressGovernance → Users → Pending invitations, the × · DELETE /api/v1/invitations/{id}the link stops working at once; the address can be invited againworks — #2054
A1a.6block a leaver, or remove their accountGovernance → Users, deactivate or Edit → Delete · /api/v1/users/{id}a confirmation names the account; sign-in is blocked and sessions endworks — #2055

A1-b — an OIDC identity provider (Okta, Entra ID, Google, Keycloak)

#stepwhereexpectstatus
A1b.1create an OIDC web app in the IdPthe IdP, redirect URI https://<control>/auth/sso/<slug>/callbacka client id and secretworks
A1b.2register itGovernance → Single Sign-On · POST /api/v1/orgs/{org}/sso-providersthe provider card; the login screen offers Continue with …works
A1b.3map IdP groups to roles at scopesthe provider card’s Group mappingsa user in platform-eng becomes admin of team platform, and nothing elseworks
A1b.4decide what an unmapped user getsthe provider’s default role (empty refuses them)an unmapped user is refused, or lands as the default role at the orgworks
A1b.5turn passwords off for the orgOrg sign-in policy: single sign-on onlyone button on the login screen; the superadmin keeps a password as the break-glassworks
A1b.6sign in from a private window as a mapped userthe login screenthe dashboard, scoped to what the mapping grantedworks
A1b.xthe IdP speaks only SAML——gap — #1827

A1-c — an LDAP / Active Directory directory

#stepwhereexpectstatus
A1c.1point rolter at the directory and bind users——gap — #1826

A1-d — provisioning from the IdP (SCIM), with any of the above

#stepwhereexpectstatus
A1d.1issue an org-scoped provisioning tokenGovernance → User Provisioning → Issue tokenthe token, shown once, named after the IdP connectorverified
A1d.2configure the IdP’s SCIM connectorthe IdPa test user is created in rolter as an org viewer, nothing moreverified
A1d.3map IdP groups to teams and rolesGroup mappings on the same screengroup membership in the IdP becomes a role in rolter on the next syncworks
A1d.4deprovision the test user in the IdPthe IdPthe account is deactivated, its sessions droppedverified
A1d.5their personal keys stop working toothe gatewaya key the leaver minted is refusedbug — #1841

A1-e — custom roles and access profiles (optional)

#stepwhereexpectstatus
A1e.1define a role that widens a built-in one by specific grantsGovernance → Roles & Permissionse.g. “viewer, plus create routes in project X”verified
A1e.2hand it to people, with an optional model/route policyGovernance → Access Profilesthe grant shows in GET /api/v1/rbac/effective for those peopleverified

A2 — lay out the tenancy

#stepwhereexpectstatus
A2.1create teams and projects that match how money and access flowthe scope switcher’s + · POST /api/v1/orgs/{org}/teams, /teams/{id}/projectsthe chain appears in every screen’s scopeverified
A2.2decide who reads prompts, per projectthe gear beside the project → Viewers can read captured payloadsoff by default: members and admins read bodies, viewers see rows only (#1820)verified
A2.3create business units and customers for attributionGovernance → Business Units, Customersslugs spend can be recorded againstverified

A3 — connect models

The third fork, and the one with the most branches: how many models, from how many places, and does traffic need spreading?

branchshapebalancing
A3-aone hosted provider, one or two modelsnone — one target per route
A3-bthe same model from two providersfailover: retries and cooldowns move traffic off a failing target
A3-cseveral vendors behind named routesnone or failover, per route
A3-da self-hosted fleet, many replicasload-balanced: a strategy per route
A3-ea hosted API reached through a proxy or a re-implementationas A3-a, with the host pin relaxed

A3-a — one provider, one route

#stepwhereexpectstatus
A3.1add the provider with its keyModels → Model Providers → + Add provider · POST /api/v1/orgs/{org}/providersthe key is sealed with the KEK and never shown againverified
A3.2check it before anything depends on itthe provider’s Test connectiona model list from the upstream, or the reason there is noneverified
A3.3add a route: public name → provider/modelModel Catalog → + Add model or Routing Rules → + Add route, one sheet · POST /api/v1/projects/{id}/routesthe public name appears in Model Catalog and in /v1/models for keys that may reach itverified (seed)
A3.3acheck the upstream name before savingModel Catalog → + Add model, the sheetthe provider’s catalogue lists the upstream model, or the reason it could not tellgap — #2008 (UI: #2009)
A3.4try itPlayground, the new modelan answer; a row in LLM Logs naming the provider and the costbug — #1853; #1847 for a superadmin with no membership

A3-b — the same model from two providers, with failover

#stepwhereexpectstatus
A3.5give the route two targetsthe model sheet’s Targets; Model Catalog lists them per rowboth targets listed with weightsverified
A3.6set the retry budget and cooldownSettings → Performance Tuning, Circuit Breakera transient 5xx on one target is retried on the other before the caller sees itverified (dogfood deepseek-r1: vllm-spot-01 503s never reached a caller)
A3.7watch a target tripCircuit Breaker, Observability → Dashboardthe failing target’s breaker opens, traffic moves, and it is probed back inworks

A3-c — several vendors behind named routes

#stepwhereexpectstatus
A3.8one provider per vendor, one route per public model nameas A3-a, repeatedclients ask for gpt-4o or claude-sonnet-4 and never learn which vendor answeredverified
A3.9pin defaults on a route and decide what callers may overridethe route’s params and param policytemperature defaulted, max_tokens capped, overrides allowed or deniedworks
A3.10fill in what callers omit, deployment-wideModels → Model Settings (superadmin)a default temperature and fallback model, never overwriting a caller’s valueworks

A3-d — a self-hosted fleet, load-balanced

#stepwhereexpectstatus
A3.11describe the fleet as a filerolter.toml: providers, provider groups, routes, prices—works
A3.12apply it as desired staterolter-seed --import rolter.tomlrows created or updated to match the file; the gateway picks them up within its poll intervalverified (4 s)
A3.13notice what the import did not applythe import’s outputsections it does not import ([adaptive_routing], [retry], budgets, keys) namedgap — #1818
A3.14choose a strategy per routethe model sheet’s Strategy, at creation; changing it later is #2208round robin for identical replicas, cache_aware for prefix-heavy chat, fastest/predicted_latency for latency, weighted for a canary, adaptive to let live latency, cost and load decideverified, except cache_aware: it sends every request to one replica — bug #1851
A3.15address a whole groupvllm-a100/meta-llama/Llama-3.1-8B-Instructthe group’s members share the trafficverified
A3.16turn adaptive routing onAdaptive Routing → Settings (superadmin)deepseek-r1 engages once it has samplesworks; dogfood never engages — #1817
A3.17take the live state back out as a filerolter config export --output rolter.tomlan importable file with no credential in itverified

A3-e — a hosted API behind a proxy or a local re-implementation

#stepwhereexpectstatus
A3.18point a hosted kind (e.g. openrouter) at another hostallow_custom_api_base = truethe provider reaches the gatewayworks in a gateway-only file; gap in the database — #1133 (the dogfood claude-sonnet-4 route 404s)

A4 — give access to people and applications

#stepwhereexpectstatus
A4.1make engineers members of their projectsA1-a invitations, A1-b mappings or A1-d groupsthey can mint their own keys (see engineer E2)works
A4.2mint a shared key for an applicationGovernance → Virtual Keys · POST /api/v1/projects/{id}/virtual-keysshown once; models and providers allow-lists, expiry, business unit and customer set on the keyverified
A4.3rotate that key later—a new secret on the same key with an overlap windowpartial — #1837 (mint a second key, redeploy, delete the first)
A4.4automate the control plane from CI—a token scoped to one projectgap — #1836 (the admin token is superadmin)

A5 — spend and budgets

#stepwhereexpectstatus
A5.1price every model that costs moneyModels → Pricing Overrides (superadmin), or [[model_prices]]cost_usd on every row; nothing counts as free by accidentworks
A5.2find unpriced trafficDashboard (unpriced share), LLM Logs (unpriced flag)the dogfood fleet shows 12 unpriced models — every fake routeverified
A5.3cap spend per org, team, project, key, unit or customerModels → Budgets & Limits → Add budget (admin at that scope)the next request past the cap gets HTTP 402; counters in Redisverified
A5.4cap throughputAdd rate limitHTTP 429 with Retry-Afterverified
A5.5hear about it before the cap—a warning at a thresholdgap — #337
A5.6alert on spend velocityAlerting → Rules, spend_velocity (superadmin, deployment-wide)a webhook when spend per hour crosses the lineworks; scoped rules — #1829

A6 and A7 — run it, and keep it safe

Day-2 operations (health, upgrades, drains, backups) are the DevOps script; identity hardening, payload redaction and audit are the SecOps script. An admin who is both walks those next.