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

User journeys

How the people who use rolter get from “I have a job to do” to “it is done”, written as scripts: one per person and goal, step by step, with the branches a real deployment takes. They exist for three reasons at once:

  • Planning. Each script describes the journey as it should go. Where the product does not support a step yet, the step says so and links the issue, so the gaps read as a list in the gap register instead of being rediscovered by every new user.
  • Testing. The scripts are what the pre-1.0 live pass (#1789) walks, on the dogfooding fleet: headless by an agent driving the dashboard in Chromium plus the API, and by a real person while an observer watches the telemetry. See running a script.
  • Onboarding. The steps that already work end to end are also the public guides, minus the gap tracking.

The user-facing docs describe features; these describe people. When the two disagree about what a person can do, one of them is wrong — file it.

The people

rolter has three scoped roles — viewer, member, admin — granted at an org, a team or a project, plus the deployment-wide superadmin (the admin token, or an account with the superadmin bit). Custom roles and access profiles can only widen a scoped role (see RBAC & auth). Every persona below is one of those, at one scope:

PersonaRole todayScriptTheir question
Platform operator / org adminsuperadmin, or admin at the orgplatform-admin.md“How do I stand this up, connect our models and hand it to people?”
Team leadadmin at a teamteam-lead.md“How do I give my team models, keep them inside a budget, and see the bill?”
LLM / ML / software engineermember at a projectengineer.md“How do I get a key, call models, and see why my call failed?”
Application / service accounta virtual key (no human)app-service.md“What happens to my traffic, my limits and my key over time?”
Finance / FinOpsviewer at the org (admin to cap)finops.md“What did we spend, on what, for whom — and can it stop at a limit?”
SecOpssuperadmin (a narrower role: #1834)secops.md“Can I prove who reads what, and that secrets never land in a log?”
DevOps / SRE (maintenance only)superadmin (a narrower role: #1834)devops.md“Is it healthy, and can I upgrade, drain and restore it without a surprise?”
Viewer (stakeholder, PM, auditor)viewer at a project, team or orgviewer.md“What is happening here — and can I keep my own view of it?”

SecOps and DevOps are superadmin today only because nothing narrower reaches the deployment-wide settings they need. Both scripts start from that and mark it as the first gap.

The simplest paths

Most people only ever need one of these. Every longer script is a branch off one of them.

  1. Five minutes, no credentials. rolter easy-up, open the dashboard and send a Playground message to the built-in fake-llm model. Proves the gateway and the dashboard before a single provider key exists. Add --clickhouse-url pointing at a ClickHouse that has rolter’s schema (clickhouse/*.sql) and LLM Logs shows the row too, which proves the log pipeline. (platform-admin A0-a)
  2. One hour to a team deployment. Install with Postgres, Redis and ClickHouse, sign in as the seeded admin, follow the dashboard’s Getting started card — connect a provider, add a route, mint a key — and hand people either an invitation or single sign-on. (platform-admin A0-c to A4)
  3. Configuration as code. Keep providers, groups, routes, prices and prompt templates in a rolter.toml, apply it with rolter-seed --import (desired state), and read the live state back with rolter config export. What the file cannot carry — keys, budgets, SSO, policy — stays in the dashboard or the API. (platform-admin A3-d)
  4. An engineer’s first call. Sign in, Settings → My Virtual Keys → Generate virtual key, point the OpenAI or Anthropic SDK (or a coding agent) at the gateway with that key. (engineer E1–E4) Until #1846, the dashboard half works only for someone who also holds a role at the org: an invitation to a project grants nothing above it.

How to read a script

Each script is a table of steps. A step names what the person does, where they do it — the dashboard path first, the API equivalent second, so the same step can be run by hand, by a browser driver or by curl — what they should see, and its status:

statusmeaning
verifiedpassed in a recorded dogfood run (the run log names the date)
worksthe product supports it and nothing is known to be wrong, but no recorded run has walked it yet
partialit can be done, with a workaround the step spells out; the linked issue removes the workaround
gapthe product cannot do this yet; the linked issue is the plan
bugit should work and does not; the linked issue is the bug

Where the path forks — no identity provider or OIDC, one model or a fleet — the script names the fork, the question that decides it, and gives each branch its own steps (A1-a, A1-b, …). A branch is walked in a run only when the run is testing that branch; the rest are still read, because a branch nobody walks rots.

Dogfood data

Every script runs against the stack just dogfood brings up (the dogfooding fleet). Seed the fleet and the personas once:

just dogfood                                    # the stack, SigNoz, the sheet
just dogfood-seed                               # 15 fake providers, 3 groups, 11 routes
just dogfood-personas                           # one account per persona

personas.sh is idempotent and prints the roster. Every account shares the dogfood password from integration/dogfood/creds.env:

accountrolescopepersona
dev@rolter.localsuperdeploymentplatform operator, DevOps, SecOps
orgadmin@rolter.localadminorg defaultorg admin
lead@rolter.localadminteam defaultteam lead
engineer@rolter.localmemberproject default/defaultengineer
engineer2@rolter.localmemberproject research/sandboxan engineer on a different project
viewer@rolter.localviewerproject default/defaultviewer
finops@rolter.localviewerorg defaultFinOps

The fleet lives in project default/default: routes gpt-4o, gpt-4o-mini, claude-sonnet-4, llama-3.1-8b (round robin), llama-3.1-8b-cached (cache-aware), llama-3.1-8b-fastest, qwen-32b (power of two), mistral-7b (predicted latency), gemma-27b (weighted), deepseek-r1 (adaptive) and text-embedding, plus group addresses such as vllm-a100/…. Three targets are bad on purpose — vllm-a100-03 is slow, vllm-spot-01 answers 503 a quarter of the time, vllm-spot-02 takes 1.4 s to first token — so failure, retry and latency screens have something to show. research/sandbox has no routes; it exists so one project’s people can be shown not seeing another’s traffic.

Running a script

Headless — an agent drives it

This is how a script runs when nobody can open the dashboard: the stack is in a cloud container, or the run is a regression pass.

  1. Bring the stack up and seed it (above). Mint nothing by hand: every key and account a script needs is made by its own steps or by personas.sh.
  2. Walk the steps as the persona. Dashboard steps are driven in headless Chromium (Playwright) signed in as the persona’s account — a screenshot of each step’s end state is kept, because “the button was there” is not the same claim as “the button was usable”. API steps use curl with the persona’s session (POST /api/v1/auth/login) or the virtual key the script minted.
  3. Check every Expect against the source of truth rather than the screen: the API’s answer, a request_logs row in ClickHouse, an audit_log row in Postgres.
  4. Record the result per step in the run log. A failed step is either a bug in rolter (file it), a wrong script (fix the script in the same PR as the run log), or a known gap (already linked).

just dogfood-journeys does steps 2 and 3 for every script: one runner per persona in integration/dogfood/journeys/, results and screenshots in integration/dogfood/.journeys/, and a summary.md to copy into the run log. just dogfood-screens adds the persona × screen matrix. See walking it as someone else. A runner step and its script step share an id; when a script changes, change its runner in the same PR.

Watched — a person drives it, an observer watches

This is the #1789 pass: someone who did not build the screen uses it, and the struggle is the finding.

  1. The person runs the stack locally (just dogfood) or on a shared host and signs in as the persona. They get the script’s goal, not its steps — the steps are what the observer checks them against.
  2. The observer runs just dogfood-watch (live ui_events and gateway traffic), keeps SigNoz open on rolter · dashboard UX, and notes every place the person hesitates, backs out, reaches for a refused control (refused_click) or abandons a form (form_abandon).
  3. Afterwards the two walk the script together and mark each step. A step the person completed by a route the script did not foresee is a finding too: the script, or the screen, is wrong about how people think.

What the observer watches

signalwheretells you
screen views and struggleClickHouse ui_events, just dogfood-watchwhich screen, how long to interactive, refused clicks, abandons
requestsClickHouse request_logs, LLM Logswhat reached the gateway, the status, the target, the cost
who did whatPostgres audit_log, Governance → Audit Logsevery mutation a step claims to make
tracesSigNoz, rolter · overviewwhere a slow step spent its time
the gateway’s own viewGET :4000/metrics, Cluster, Adaptive Routingconfig version, breaker state, queue, adaptive engagement

Run log

datemodescriptsresult
2026-09-24headlesssmoke over A0, A3, P2, P5 (API only)stack up; fake-llm on every dialect; 11/12 fleet routes answer; found #1815, #1816, #1817, #1818, #1819, and the unauthenticated analytics read fixed in #1820
2026-09-24headlessrequest-log visibility for every personaafter #1820: org admin all rows and bodies; team lead and engineer their project’s rows and bodies, no provider health (#1833); engineer2 nothing; viewer and FinOps rows with bodies withheld
2026-09-24headlessevery screen as every persona account (49 screens × 7 accounts)org admin 32 usable, FinOps 28; team lead, both engineers and the viewer 5, because their scope switcher stops at the org (#1846); the superadmin cannot open the Playground (#1847); non-admins get the setup checklist as an error (#1848)
2026-09-24headlessall eight scripts, 94 steps, just dogfood-journeys59 pass, 17 bug, 10 partial, 8 gap. New: #1844–#1856. Script claims the run disproved were corrected: A1a.4, S2.1, P1.2, P2.4, A3.14

Add a row per run. The full walk of every script is the #1789 pass.

Gap register

Every step marked partial, gap or bug, in one place. Milestones and priorities live on the issues.

issuewhat is missingblocks
#1846team- and project-scoped members cannot select their own scope in the dashboardE1–E3, T1, V1, V4: every persona below the org
#1844a route with no visibility list is served to virtual keys of every orgA3, A4 on any multi-org deployment
#1845a same-named route in a second project freezes config for every gatewayA3, T3
#1847a superadmin with no membership cannot open the Playground or mint a personal keyA3.4
#1853the Playground asks for models before its key is live, then defaults to a dead routeA3.4, E3.1
#2008nothing can check that a provider serves an upstream model name (UI: #2009)A3.3a
#1851cache_aware sends every request to one replica and never checks loadA3-d, P2.4, P5
#1850a team admin cannot list their own team’s membersT2, T6
#1852no second-factor enrolment at sign-in when an org requires oneA1a.4, S2.1
#1854sign-in and second-factor audit rows are written with no org, so nothing reads themS2, S6
#1856a flag stored on but unavailable blocks every feature-flag changeD3.3
#1848the Dashboard’s setup checklist shows an access error to everyone below adminE1, V1, F1
#1861LLM Logs cannot look a request up by the x-request-id a client received (API: #1863)E5.2
#1395requests refused before routing (401, 402, 403, 404, 429) never reach LLM LogsE5, P5.4
#1855no per-provider queue depth or in-flight metricD2.4, D3.1
#1815the provider queue serialises every provider to one in-flight requestP5, D3 — any concurrent traffic
#1822self-service account area (epic)E10, V2, V3, V5
#1823display name and bio, editable by the account itselfV2, E10
#1824preferences and defaults stored server-sideV3, E10
#1825saved filter presets on LLM Logs and the DashboardV5, F2
#1831members cannot read their own MCP tool-call logsE6
#1841a deprovisioned person’s own virtual keys keep workingT6, S2
#1840anonymous /api/v1/config still describes the upstream topologyS1.3
#1133a database-backed provider cannot opt out of the hosted host pinA3-e
#1826LDAP is implemented but not reachable from sign-inA1-c
#1827no SAML single sign-onA1-b (SAML-only IdPs)
#1828invitations are links an admin passes on by handA1-a, T2
#1829alert rules are superadmin-only and deployment-wideA5, T5, F4
#337no warning before a budget blocksA5, T4, F4
#1830no budget per person across their keysT4, F3, E9
#1833project members cannot see the health of their own routes’ providersE5, T5
#1834no operator or security-auditor role short of superadminD0, S0
#1835payload redaction matches key names, not secrets inside text; no previewS3
#1085one subject’s logs and captured payloads cannot be erased on requestS3.6
#1836no scoped control-plane token for automationP4, D6
#1837shared project keys cannot be rotated in placeP3
#1838no CSV export of spend or logsF5
#1816a request abandoned while waiting on its upstream is logged with no providerD4, E5
#1817the dogfood fleet’s adaptive route never engagesA3-d (adaptive), D2
#1818rolter-seed --import is silent about sections it skipsA3-d
#1819compose ClickHouse fails where nofile cannot reach 262144A0-b on constrained hosts
#1890the compose stack takes no secrets and its gateway ignores the control planeA0-b, A0.6
#1939a default Helm install fails its own strict preflightA0-c, A0.6
#1897rolter-seed ships in no image or packageA0.8
#1891the published image binds loopback, so docker run -p reaches nothingthe quickstart’s docker run
#1832raw MCP traffic inspection for local servers (mcp-snoop)E7
#1839a member cannot route their own local model through rolter (idea)E8

Public guides

The paths that already work end to end are published as user-facing guides in docs/user-docs/guides/, without the gap tracking: the admin’s first hour, connecting models, an engineer’s first call, and tracking spend. When a gap here closes, the matching guide gains the step.