First-run setup
What the first-run setup screen checks on a new self-hosted install, how Production and Test flight report each result, and how to fix a failed check.
In this page
The first time you open a new self-hosted install in a browser, it sends you to /setup. The screen asks how you plan to run the instance, which is the launch mode, then runs pre-flight checks against every service the app depends on. It names the setup it runs in (Standalone, Distributed or Helm) and shows that setup’s fix for anything that is down. Continue then takes you to sign-in, or to sign-up when the instance has no account yet.
Production, the default, requires all 13 checks and holds you on the screen while one fails. Test flight requires seven and lets the rest through as Caution or Optional. The launch mode changes how results are reported, never which services run, and nothing stores it. A service your install does not run reads Optional in both modes.
%%{init: {"flowchart": {"curve": "linear"}}}%%
flowchart TD
accTitle: The first-run setup flow
accDescr: A first visit opens the setup screen. You pick a launch mode, the pre-flight checks run, and Continue leads to sign-in when an account exists or to sign-up when none does.
A["First visit to the UI"] --> B["Pick a launch mode"]
B --> C["Pre-flight checks"]
C -->|"Continue"| D{"Account exists?"}
D -->|"Yes"| E["Sign in"]
D -->|"No"| F["Sign up"]
When the screen appears
Opening the UI (http://localhost:3000 on a default install) sends a browser to /setup until you click Continue on it. The browser remembers that in its local storage, so each new browser or private window sees the screen once. Open /setup again at any time to re-run the checks.
The screen and its checks exist only on an open-source install. On an install with an Enterprise Edition license, the UI skips the screen and the checks endpoint answers 404.
The two launch modes
You pick one on the first screen, and Production is selected by default. The choice lives only in that browser tab: it is not written to .env and nothing reads it later.
| Mode | For | Required checks | A down service that is not required |
|---|---|---|---|
| Production | An instance that will carry real traffic | All 13 | None: every down service reads Failed and blocks Continue |
| Test flight | Trying Future AGI out locally | Core application database, Tracing data warehouse, LLM request gateway, Async task engine, Trace ingestion, Django backend, React frontend | Reads Caution. SSL/TLS certificate reads Optional |
Results never block Continue in Test flight, even a Failed row, so read them before you go on. When Production is blocked, the screen offers Continue with Test flight; in Test flight, Switch to Production runs the stricter mode.
What each status means
| Status | Meaning |
|---|---|
| Ready | The service answered. A Ready row can carry a note, such as Standalone’s built-in code sandbox running Python but not JavaScript |
| Caution | The service is down, and this mode does not require it |
| Failed | The service is down, and this mode requires it. In Production it blocks Continue |
| Optional | Your install does not run the service, a local install needs no certificate, or Test flight skips the certificate check |
| Checking… | The result is still being revealed: after the first response, the rows flip one by one |
Whether a service is up never depends on the mode. Only the label on a down service changes.
The pre-flight checks
The screen shows 13 rows. Eleven probe a service, all at the same time. Django backend and React frontend are not probed: the page loading at all shows they are up, so they always read Ready.
| Check | What breaks when it is down | Production | Test flight |
|---|---|---|---|
| Core application database | Nothing loads | Failed | Failed |
| Tracing data warehouse | Traces, spans and dashboards will not load | Failed | Failed |
| Cache and session store | Sessions, caching and rate limits will not work | Failed | Caution |
| Websocket connection | Live updates will not reach the browser | Failed | Caution |
| Object storage service | Dataset uploads, exports and media will fail | Failed | Caution |
| LLM request gateway | Every LLM call fails: evaluations, playground and agents | Failed | Failed |
| Async task engine | Evaluations, optimizations and scheduled jobs will not run | Failed | Failed |
| Trace ingestion | Spans sent by the SDK will not arrive | Failed | Failed |
| Django backend | Not probed, always Ready | n/a | n/a |
| React frontend | Not probed, always Ready | n/a | n/a |
| Agent fixer (evals) | Embedding-based evals, ground truth and Vector DB columns will not run | Failed | Caution |
| Code execution sandbox | Custom code evaluations will not run | Failed | Caution |
| SSL/TLS certificate | Browser and SDK traffic travels unencrypted | Failed | Optional |
Websocket connection checks the channel layer that carries live updates to the browser, which is Redis in both Compose setups, and the WEBSOCKET_ENDPOINT that workers send those updates to.
Checks that can read Optional
- Agent fixer (evals) reads Optional when model serving is not deployed: Standalone without the
mlprofile, or Helm withserving.enabled=false, the default. The row then reads “Embedding-based evals, ground truth and Vector DB columns are off; everything else works”. Distributed always runsserving, so there the row reads Failed or Caution while it is down, never Optional. - Code execution sandbox reads Optional on Helm with
codeExecutor.enabled=false, the default. Custom code evals are refused until you setcodeExecutor.enabled=true(the nodes must allow privileged pods), or run them in the worker pods withcodeExecutor.localFallback=truewhen everyone who can write evals is trusted. In Standalone without thesandboxprofile the row reads Ready, with a note that JavaScript evals need thesandboxprofile. - SSL/TLS certificate reads Optional on a local install, in both modes. An install is local when every configured URL (
FRONTEND_URL, andVITE_HOST_APIor elseBASE_URL; on Helm,urls.appandurls.api) nameslocalhost, a private or CGNAT (Tailscale) address, a single-label host name, or a.local,.internalor.lanname, and the browser reached the API on such a host. While every configured URL is local, as on a default Helm install, a browser that came in on a public host name or address fails the check.
Fix a failed check
The Details panel under the checks gives one fix per Failed or Caution row, for the setup the screen runs in. Each row’s name links to the matching “Pre-flight says …” section of INSTALLATION.md on GitHub. Most fixes start or restart a container:
| Check | Standalone | Distributed |
|---|---|---|
| Core application database | docker compose up -d postgres | docker compose up -d postgres |
| Tracing data warehouse | docker compose up -d clickhouse | docker compose up -d clickhouse |
| Cache and session store | docker compose restart app | docker compose up -d redis |
| Websocket connection | docker compose restart app | docker compose up -d redis, then check WEBSOCKET_ENDPOINT |
| Object storage service | docker compose restart app | docker compose up -d minio |
| LLM request gateway | docker compose restart app | docker compose up -d agentcc-gateway |
| Async task engine | docker compose restart app | docker compose up -d temporal |
| Trace ingestion | docker compose restart app | docker compose up -d fi-collector |
| Agent fixer (evals) | docker compose up -d serving (only with the ml profile; without it the row reads Optional) | docker compose up -d serving |
| Code execution sandbox | docker compose restart app, or with the sandbox profile docker compose up -d code-executor | docker compose up -d code-executor |
In Standalone, Redis, object storage, the gateway, Temporal, the trace collector and the built-in code sandbox all run inside the app container, so restarting app brings them back. docker compose logs app shows why one stopped. The code executor needs a host that allows privileged: true. If the screen keeps waiting for the instance, start the API with docker compose up -d app (Distributed: backend) and read its logs.
On Helm the screen gives kubectl commands with your namespace and Deployment names filled in: kubectl -n <namespace> get pods for a bundled datastore, the values key to check for an external one (such as postgres.external), and the component’s logs for the rest.
For SSL/TLS certificate, serve the UI and the API over https through a reverse proxy with a valid certificate. The check reads FRONTEND_URL and VITE_HOST_API (on Helm, urls.app and urls.api), but change them together with the other public URLs, such as APP_URL, which builds invite and password-reset links. Security & TLS has proxy examples and the full set of URLs. If a check keeps failing, Troubleshooting covers the common causes.
When Continue is blocked
Three things hold you on the checks screen:
- The instance is not reachable yet. The screen reads “Waiting for your instance to power up. Normal on a first run.” while containers start.
- The results are still being revealed one by one.
- You are in Production and at least one check reads Failed.
The screen keeps polling while services come up. It stops once every row is Ready or Optional, or once the results have not changed for a minute. Re-run pre-flight probes everything again without reloading the page. The server caches each result for three seconds, so clicking faster than that returns the same answer.
To read the same results from a script, call the endpoint the screen uses. It needs no authentication; mode=live is Production and mode=experiment is Test flight:
curl -s "http://localhost:8000/api/setup-checks/?mode=live"
After Continue
Continue sends you to sign-in when the instance already has an account, such as the one ./bin/install asked you for, and to sign-up when it has none. If you are already signed in, it takes you into the app. Users & sign-in covers creating accounts.
Once nothing blocks you, the screen lists what to do next:
- Open Keys in the sidebar and copy your API key and secret key.
- Send a first trace from the same machine, with
FI_BASE_URLset to the collector URL the screen shows (http://localhost:4318by default):
pip install fi-instrumentation-otel
export FI_API_KEY="YOUR_API_KEY" FI_SECRET_KEY="YOUR_SECRET_KEY" FI_BASE_URL="http://localhost:4318"
from fi_instrumentation import register
from fi_instrumentation.fi_types import ProjectType
tracer_provider = register(project_name="my-first-project", project_type=ProjectType.OBSERVE)
with tracer_provider.get_tracer("quickstart").start_as_current_span("hello-future-agi") as span:
span.set_attribute("input.value", "Hello, Future AGI")
tracer_provider.force_flush()
Open Tracing in the sidebar: my-first-project holds the span. On Docker Compose the collector listens on the install’s host only, so an SDK on another machine needs a reverse proxy in front of 127.0.0.1:4318 and FI_COLLECTOR_PUBLIC_URL set to the proxy’s URL (see Environment variables). The tracing guide goes further.
Launch mode is not a profile
Profiles decide which containers run and are set in .env before the stack starts. The launch mode is a choice in the browser that changes nothing about your deployment. A service a profile leaves out reads Optional rather than Failed, so a local Standalone install without profiles passes pre-flight in either mode.
Dive deeper
Questions & Discussion