Installation for contributors
This guide covers the nexus gateway and observability platform as a standalone repository.
Both the Rust workspace (Cargo.toml) and the TypeScript workspace (pnpm-workspace.yaml) are rooted at the repository root.
The shared vortex-* crates ship as the nested vortex-common-crates git submodule, so clone with --recursive (or run git submodule update --init --recursive after cloning). The submodule URL is deliberately relative (../vortex-common-crates.git): the repository is hosted on more than one GitLab instance, and each instance carries the sibling repository at the same group path, so the submodule resolves against whichever remote you cloned from.
After that, a new nexus contributor should be able to:
- Run
just devfrom the repository root. - Optional:
just statusprints a formatted health summary (published gateway + console, internal Rust services viaclickhouseexec, infra probes, and dev-only observability warnings). - Create the first user through the console sign-up flow, which provisions a personal workspace, default organization, default project, and manager memberships.
- Or
curlthe published gateway and console/healthzroutes and get HTTP 200.
Cold Docker builds can take several minutes; warm rebuilds are faster.
Prerequisites
Section titled “Prerequisites”| Tool | Minimum version | Notes |
|---|---|---|
| Docker | with Compose v2 | For running the dev stack |
just |
any | Command runner for development tasks |
| Node | 20+ | For console and TypeScript workspace |
| pnpm | 9.12+ | Package manager for Node dependencies |
buf |
any | Protocol buffer tooling |
protoc |
any | Protocol buffer compiler |
| Rust | 1.96.1 | Pinned by rust-toolchain.toml (auto-installed via rustup) |
pre-commit |
any | For local git hooks (if committing changes) |
| gitleaks | any | Secret scanning (pre-commit dependency) |
| prettier | any | Code formatting (pre-commit dependency) |
Additional requirements:
- Initialize the
vortex-common-cratessubmodule (clone with--recursiveor rungit submodule update --init --recursive) - Copy
.env.exampleto.envbefore starting the stack - On Apple Silicon, set
DOCKER_PLATFORM=linux/arm64in.envbefore the first Docker build
Quick prerequisite check (from the repository root):
just --versiondocker compose versionrustc --versioncargo --versionpnpm --versionbuf --versionprotoc --versiontest -f vortex-common-crates/Cargo.toml && echo "submodule ok"Install local hooks once:
pre-commit installThe hook and CI behavior is summarized in CI/CD Pipeline.
First-run sequence
Section titled “First-run sequence”From the repository root with .env in place:
# Stand up the full stack (Postgres, ClickHouse, MinIO, NATS, Valkey,# OTel Collector, the Rust services, and the Next.js console).just devThe first invocation compiles every Rust service inside the Docker build steps.
Verify
Section titled “Verify”# One-shot summary (published gateway + console, internal Rust + infra).# Dev-only LGTM readiness is reported as a warning and does not block core stack health.just status
# Or manually — gateway and console are the primary published app endpoints:curl -fsS http://127.0.0.1:14450/healthz && echo " (gateway ok)"curl -fsS http://127.0.0.1:14449/healthz && echo " (console ok)"
# Most other Rust services are also host-published: control-plane :14451,# auth :14453, ingest :14457, trace-ingest :14458, audit :14459, query :14461/:14462.# Only policy (:14455) is compose-network-only; probe it with# `docker compose -f deploy/compose/docker-compose.yml exec -T clickhouse wget -qO- http://policy:14455/healthz`.
# Prometheus counters on the gateway (same published port):curl -sS http://127.0.0.1:14450/metrics | grep vortex_service_starts_totalDev credentials
Section titled “Dev credentials”All credentials below are set in deploy/compose/docker-compose.yml and are for local development only.
| Service | URL | User / Access Key | Password / Secret Key |
|---|---|---|---|
| MinIO Console | http://127.0.0.1:9001 | vortex |
vortex-dev-minio |
| MinIO S3 API | http://127.0.0.1:9000 | (see service users below) | |
| Postgres | postgres:5432 inside Compose |
vortex |
vortex |
| ClickHouse | http://clickhouse:8123 inside Compose |
vortex |
vortex |
| Grafana | http://127.0.0.1:14470 | anonymous admin | (no login required) |
| NATS | nats://nats:4222 inside Compose |
(no auth) | |
| Valkey | redis://redis:6379 inside Compose |
(no auth) | Redis-compatible cache/rate-limit backend |
Host-published service ports are listed in Ports. Postgres, ClickHouse, NATS, and Valkey are intentionally Compose-network-only in the stock dev stack.
MinIO service users (created by deploy/compose/minio/bucket-init.sh on first boot):
| User | Secret | Policy | Used by |
|---|---|---|---|
ingest |
ingest-dev-secret |
ingest-write |
ingest service (sole MinIO writer) |
gateway |
gateway-dev-secret |
gateway-readonly |
gateway (read-only; PutObject denied) |
Beyond compose: real BYOK chat through the gateway
Section titled “Beyond compose: real BYOK chat through the gateway”The Compose stack above proves every Rust service answers /healthz. It does not by itself seed users, workspaces, orgs, API keys, or provider keys inside the gateway container.
Create the first user at http://127.0.0.1:14449/sign-up; sign-up provisions a personal workspace, default organization, default project, and manager memberships.
For an annotated flow that uses the running compose stack, mints a Nexus API key, registers a BYOK provider key, sends one curl to POST /v1/chat/completions, and inspects audit.log, follow Installation.
CLI contexts and completion
Section titled “CLI contexts and completion”Use nexus context create / nexus context use to pin DB URLs, tenant id, and state dir for repeated admin work.
Shell completion is provided by nexus completions <shell> and includes dynamic value completion for positional refs (org/workspace/project slugs and ids) when the active context can reach Postgres.
Managed PTB platform keys
Section titled “Managed PTB platform keys”Tenant BYOK provider keys are managed with nexus credentials provider-keys flows. Production PTB uses separate operator-managed platform keys through nexus credentials platform-keys:
nexus credentials platform-keys set \ --provider openai \ --secret-env OPENAI_PLATFORM_API_KEY \ --workspace ws_... \ --org org_... \ --label prod-openai-us
nexus credentials platform-keys list --provider openai --workspace ws_...nexus credentials platform-keys rm ppk_...nexus credentials platform-keys rotate ppk_... --secret-env OPENAI_PLATFORM_API_KEY_NEXTScope flags are optional. Project-scoped keys win over org-scoped keys, org over workspace, workspace over tenant/operator-global, and broader keys are fallback material when a more-specific key is absent, revoked, unhealthy, or disallowed.
To seed all supported platform keys from .env values that are present:
just load-provider-keys# optionally scope loaded keys to a workspace id:just load-provider-keys ws_...The loader checks common provider env vars such as OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY, GROQ_API_KEY, MISTRAL_API_KEY, COHERE_API_KEY, XAI_API_KEY, TOGETHER_API_KEY, FIREWORKS_API_KEY, DEEPSEEK_API_KEY, and PERPLEXITY_API_KEY.
Local PTB smoke
Section titled “Local PTB smoke”This is optional and separate from BYOK.
Use it when you want to verify operator-managed platform credentials and wallet-funded pass-through billing.
It requires NEXUS_GATEWAY_PTB=1 in .env; after changing that value, recreate the gateway with just compose up -d gateway so the container receives the new environment.
Platform provider keys and Wallet eligibility are control-plane data.
The gateway reads them at request time with a short provider-key cache, so wait up to 60 seconds after changing those rows or recreate the gateway if you need immediate verification.
Provider keys and model registry sync are separate control-plane data.
just models-sync refreshes model endpoints and pricing only; it does not reload provider keys.
# 1. Enable PTB in .env, then recreate the gateway.# NEXUS_GATEWAY_PTB=1just compose up -d gateway
# 2. Load operator-managed platform provider keys from .env.just load-provider-keysjust validate-provider-keys --live
# 3. Enable Wallet/PTB eligibility in the console.# Workspace scope: Workspace -> Limits -> check# "Wallet enabled by default for this workspace".# Organization scope: on the same Workspace -> Limits page, edit the target# organization row and check "Wallet enabled for this organization".# Project scope: open the project -> Limits page and check# "Wallet enabled for this scope".## 4. Fund the workspace wallet with a local operator grant.just cli workspaces listjust cli ops grants create \ --workspace <workspace_slug_or_id> \ --amount-usd 10.00 \ --reason "local PTB smoke" \ --idempotency-key local-ptb-smoke-001
# 5. Create a project with no BYOK key and mint a Nexus API key for it.just cli projects create --org <org_slug> --slug ptb-smoke --name PTB-smokePTB_TOKEN=$(just cli credentials api-keys create \ --org <org_slug> \ --project ptb-smoke \ --name ptb-smoke \ --issued-by "$(whoami)")
# If the console is already open, refresh the browser so its org/project list reloads.
# 6. Send a request through the PTB project.curl http://localhost:14450/v1/chat/completions \ -H "Authorization: Bearer $PTB_TOKEN" \ -H "Content-Type: application/json" \ -d '{"model":"openai/gpt-5.4-mini","messages":[{"role":"user","content":"ptb hello"}],"max_tokens":8}'The PTB project must not have a BYOK provider key for the requested provider, otherwise routing prefers the tenant BYOK key.
There is no CLI helper for the Wallet eligibility toggles today; use the console or the underlying limits API (PATCH /api/workspaces/:id/limits, /api/orgs/:id/limits, or /api/projects/:id/limits with ptb_enabled: true).
Workspace wallet grants
Section titled “Workspace wallet grants”PTB credits are funded by auditable operator grants. Auto-refill settings are alerting configuration only.
nexus ops grants create \ --workspace ws_... \ --amount-usd 100.00 \ --reason "pilot credit" \ --idempotency-key pilot-credit-001
nexus ops grants list ws_...Stop / reset
Section titled “Stop / reset”just down # stops containers, preserves volumesjust dev-clean # stops containers and destroys volumesDay-to-day commands
Section titled “Day-to-day commands”Run from the repository root unless noted.
| Command | Purpose |
|---|---|
just up / just dev / just down |
Start or stop the nexus dev stack |
just status |
Pretty health summary for the dev stack |
just proto |
buf generate into packages/proto/src/gen |
just proto-lint |
Lint protobuf sources |
just migrate |
Apply dev database migrations via compose |
just models-sync |
Sync model registries for providers with a tenant-scope platform key |
just load-provider-keys |
Load PTB platform provider keys from supported .env API key variables |
just node-install |
pnpm install across the nexus TS workspace |
just node-build |
pnpm build across every pnpm workspace package |
just node-lint |
Lint nexus TS packages |
just node-test |
Test nexus TS packages |
just compose-it |
Smoke test: stack up, /healthz probe, teardown |
just cli … |
Run nexus inside dev compose; e.g. just cli orgs list |
just cli-local … |
Host cargo run -p nexus-cli (needs DB at NEXUS_DATABASE_URL) |
just test … |
Vitest contract suite against a running gateway |
The one-shot just cli ... passthrough is best for arguments without spaces.
Use just cli to open the interactive shell when a command needs quoted values.
Rust workspace commands (just lint, just test-workspace, just fmt, just deny, just build) run cargo against the workspace at the repository root.
Use Testing to choose the right test suite and CI/CD Pipeline to map local commands to GitLab jobs.
Registration invites (invite-only sign-up)
Section titled “Registration invites (invite-only sign-up)”To gate self-service sign-up without attaching new users to a shared org or workspace, set AUTH_ALLOW_REGISTRATION=invite in .env and issue registration credentials with the operator CLI.
Email-bound registration invite
Section titled “Email-bound registration invite”Creates a single-use invite for one email. The user receives only a token link (no email in the URL) and must register with the invited address.
nexus ops registration-invites create \ --email newuser@example.com \ --base-url http://127.0.0.1:14449The command prints:
email=on stderr for you to communicate out-of-band- the raw invite token on the first stdout line
- the sign-up URL, such as
http://127.0.0.1:14449/sign-up?invite=nxi_..., on the second stdout line
List or revoke pending invites:
nexus ops registration-invites listnexus ops registration-invites revoke inv_...Reusable registration code
Section titled “Reusable registration code”Allows any email to register while uses remain.
The command prints the raw code on the first stdout line and the sign-up URL (/sign-up?code=nxr_...) on the second stdout line.
nexus ops registration-codes create --max-uses 10 --base-url http://127.0.0.1:14449nexus ops registration-codes listnexus ops registration-codes revoke rc_...New accounts still receive only their auto-provisioned personal workspace. Org and workspace membership invites remain separate and additive via /accept-invite.
Membership invites as sign-up credentials
Section titled “Membership invites as sign-up credentials”Under invite-only registration, a membership invite link (/accept-invite?token=nxi_...) cannot by itself create an account, so inviting someone who has no account yet leaves them unable to join. Set AUTH_INVITE_CODE_SIGNUP=true to let membership invitation tokens also satisfy the sign-up gate.
With the flag enabled, the accept-invite page offers a Create account action that carries the invite token into /sign-up?invite=nxi_.... The recipient must register with the email the invitation was sent to. The token is not consumed at sign-up; membership is granted (and the invite marked accepted) when the new account lands back on /accept-invite and accepts.
What this dev stack is not
Section titled “What this dev stack is not”- Not a guarantee that every container participates in the BYOK chat path without extra setup (see the end-to-end doc).
- Not production-shaped telemetry dashboards for every histogram described in Telemetry Conventions.
- Not a substitute for release-artifact verification; use Releases and Verification for signed image, SBOM, and provenance checks.
If any of the above fail on your machine, include just status output and the failing service logs in the issue.
