Run from Source¶
Purpose¶
Build and start the Console, split-listener gateway, Agent runtime, and Collector from a reviewed checkout. Bootstrap your first organization, load its file catalog at startup, then continue to the developer quickstart to make a governed request and inspect its Trace.
This is the operator setup path. If your organization already provides a Console and gateway, start with the developer quickstart instead.
Prerequisites¶
- A local checkout; the examples below assume
/srv/mission-control/source. Substitute your actual absolute checkout path in each terminal. - Node.js 24, pnpm 11.22.0, Python
>=3.12,<3.15,uv, and Go1.25.14. - PostgreSQL 16 or newer and a new, empty database created by the Postgres superuser with
Ccollation and owned by a dedicated login role (see Bootstrap and first sign-in), plus a reachable private ClickHouse host. Existing current deployments use Upgrade and roll back; an installation that still keeps its data in SQLite files uses Migrate from SQLite. - Contributors who also run the test suites need a separate throwaway PostgreSQL server for them (
pnpm db:test:upfromplatform/,MISSION_CONTROL_TEST_DATABASE_URL); see Test databases for contributors. Never point tests at this database. - ClickHouse migration, gateway writer/cleanup and Console read credentials, plus trusted TLS certificates for ClickHouse and Collector prepared through Telemetry operations and Environment variables.
- Access to configure service environments and restart the processes. Bootstrap creates the first
organization.owner; subsequent catalog management requiresorganization.ownerororganization.admin.
Procedure¶
1. Prepare service environments and the catalog¶
From the repository root, follow Configure the services. Store independent generated BETTER_AUTH_SECRET, API_KEY_PEPPER, and INTERNAL_SERVICE_SECRET values in protected local service environments outside Git. Console and gateway must share the same DATABASE_URL and API-key pepper. Provision the four distinct transport secrets in the service guide. Gateway gets all four; Console and Collector get only internal transport (Collector names it MISSION_CONTROL_INTERNAL_SERVICE_SECRET), while runtime gets inbound/heartbeat only. The derivation master stays gateway-only.
Use these local overrides with those protected environments:
export DATABASE_URL="postgres://mission_control:replace-with-a-generated-password@127.0.0.1:5432/mission_control"
export MISSION_CONTROL_CONFIG="/srv/mission-control/config/mission-control.yaml"
export APP_URL="http://127.0.0.1:3000"
export TRUSTED_ORIGINS="http://127.0.0.1:3000"
export GATEWAY_PUBLIC_URL="http://127.0.0.1:4000"
export GATEWAY_MANAGEMENT_URL="http://127.0.0.1:4001"
export INFERENCE_GATEWAY_HOST="127.0.0.1"
export INFERENCE_GATEWAY_PORT="4000"
export CONTROL_GATEWAY_HOST="127.0.0.1"
export CONTROL_GATEWAY_PORT="4001"
export AGENT_RUNTIME_URL="http://127.0.0.1:4100"
export NODE_ENV="development"
export MAIL_TRANSPORT="console"
export MAIL_OUTBOX_PATH="/srv/mission-control/data/mail.jsonl"
export BOOTSTRAP_ADMIN_EMAIL="owner@example.com"
export BOOTSTRAP_ORGANIZATION_NAME="Acme"
export BOOTSTRAP_ORGANIZATION_SLUG="acme"
Create the data and configuration directories with access restricted to your service account. At MISSION_CONTROL_CONFIG, create a global YAML file selecting your organization:
Create organizations/acme.yaml relative to that global file using the organization YAML example. Set organization: acme, choose your actual provider model and virtual model, and set every referenced env/NAME in the gateway environment. Enable telemetry.standardOtlp if you want the request's exported spans to appear in Observability. The repository's platform/config/organizations/example.yaml uses organization example; it must be adapted to match the bootstrap slug. An unresolved required provider credential prevents startup.
2. Install, build, migrate, and bootstrap¶
In terminal 1, load the protected Console/bootstrap environment and the DATABASE_URL above. From the checkout:
cd /srv/mission-control/source/platform
pnpm install --frozen-lockfile
pnpm build
pnpm --filter @mission-control/database db:migrate
pnpm --filter @mission-control/console bootstrap
Bootstrap prints userId, organizationId, organizationMemberId and teamId, creates Default Team with no allowance, and reuses compatible active state on repetition. Keep the same email for first sign-in. db:migrate prints Applied N migration(s); M recorded in total.; only one process may migrate a database at a time. The gateway and the Console refuse to start with STORAGE_MIGRATION_REQUIRED: run pnpm --filter @mission-control/database db:migrate if this step is skipped.
In this terminal, load the separate ClickHouse migration environment (CLICKHOUSE_URL, CLICKHOUSE_MIGRATION_DATABASE, migration username/password, and TLS settings) from the telemetry setup, then apply the whole chain:
Expected tables and migration checks are in Apply the schema. Stop on a non-empty-storage refusal; do not discard existing data to get past it.
3. Start the gateway¶
In terminal 2, load the gateway environment prepared in step 1, including catalog credentials and MISSION_CONTROL_OTLP_ENDPOINT pointing to the trusted TLS Collector /v1/traces URL. From the checkout:
Leave it running. The same process binds public inference on 4000 and private control on 4001. Private health should succeed now; readiness waits for all compatible components.
4. Start the Agent runtime¶
In terminal 3, load matching AGENT_RUNTIME_INBOUND_SECRET and AGENT_RUNTIME_HEARTBEAT_SECRET and the trusted OTLP endpoint from step 1:
cd /srv/mission-control/source/runtime/agent-runtime
uv sync --locked --all-groups
export MISSION_CONTROL_GATEWAY_URL="http://127.0.0.1:4000"
export MISSION_CONTROL_CONTROL_URL="http://127.0.0.1:4001"
export AGENT_RUNTIME_HOST="127.0.0.1"
export AGENT_RUNTIME_PORT="4100"
export MISSION_CONTROL_OTLP_PROTOCOL="http/protobuf"
uv run --locked mission-control-agent-runtime
Leave it running. The runtime uses signed workload identity and holds no provider, Connector, or Agent key.
5. Start the Collector¶
In terminal 4, load the Collector environment from the telemetry setup: OTLP TLS certificate/key paths and memory limits, plus the Console/Collector transport secret under MISSION_CONTROL_INTERNAL_SERVICE_SECRET.
cd /srv/mission-control/source/telemetry/collector
export MISSION_CONTROL_INTERNAL_URL="http://127.0.0.1:4001"
make build
./dist/otelcol-mission-control --config config/collector.yaml
Leave it running. This configuration uses TLS on the OTLP listeners; use the corresponding trusted HTTPS endpoint for gateway/runtime exports. Collector health remains private at http://127.0.0.1:13133/health. See Collector procedure for the synchronous pipeline contract.
6. Start the Console and inspect configuration¶
In terminal 5, load the Console environment from step 1 plus its read-only ClickHouse HTTP credentials:
Leave it running. This source setup uses development Console mail; supervised deployments build and use start with SMTP instead.
- Open
http://127.0.0.1:3000/sign-inand enterowner@example.com. - Read the magic link in terminal 5 or the protected mail outbox and use it within five minutes. The first sign-in must use a magic link even if GitHub sign-in is configured.
- Open Manage → Settings and inspect the current redacted catalog loaded at startup. No Apply action is required.
- Open Manage → Teams → Default Team and configure its allowance for the model.
- Continue with the developer quickstart to issue a personal key, call a model, and inspect the Trace.
Expected result¶
The Console is available locally and private readiness returns 200 after Agent runtime, Collector, and Console heartbeats. The owner can inspect the loaded catalog and allow a Team resource. A successful developer quickstart call returns X-Mission-Control-Trace-Id; with standard OTLP configured and enabled, exported spans appear under Observe → Traces.
Verification¶
In terminal 1, from any working directory:
curl --fail http://127.0.0.1:4001/healthz
curl --fail http://127.0.0.1:4001/readyz
curl --output /dev/null --write-out '%{http_code}\n' http://127.0.0.1:4000/v1/models
curl --output /dev/null --write-out '%{http_code}\n' http://127.0.0.1:4000/readyz
Expected results are {"status":"ok"}, {"status":"ready"}, 401 without a key, and 404 on inference readiness. Retired /runtime/v1/runs and /apps/v1 routes remain absent. Probes alone do not test your provider: finish the developer quickstart's authenticated call.
Failure recovery¶
- Private readiness
503: restore matchingmission-control.trace-native/v3Agent runtime, Collector, and Console heartbeats; verify every private-control URL and matching purpose-separated secrets. STORAGE_MIGRATION_REQUIRED: runpnpm --filter @mission-control/database db:migratefromplatform/with the sameDATABASE_URL, then start the process again.- Migration refusal or connection failure: verify
DATABASE_URL, the role's password and that the server runs PostgreSQL 16 or newer. Never copy earlier rows into the new schema by hand; SQLite data moves only through Migrate from SQLite. - Validation failure: correct the selected organization file and nonempty secret references. Run optional
pnpm --filter @mission-control/gateway config:checkfromplatform/, then restart with the corrected files and environment. operation_denied: review current Team allowance and key policy/owner.- Missing spans: verify OTLP TLS trust, loaded standard OTLP configuration, Collector health and ClickHouse reachability; preserve canonical Request and ledger evidence while recovering observations.