Skip to content

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:

  1. Run just dev from the repository root.
  2. Optional: just status prints a formatted health summary (published gateway + console, internal Rust services via clickhouse exec, infra probes, and dev-only observability warnings).
  3. Create the first user through the console sign-up flow, which provisions a personal workspace, default organization, default project, and manager memberships.
  4. Or curl the published gateway and console /healthz routes and get HTTP 200.

Cold Docker builds can take several minutes; warm rebuilds are faster.

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-crates submodule (clone with --recursive or run git submodule update --init --recursive)
  • Copy .env.example to .env before starting the stack
  • On Apple Silicon, set DOCKER_PLATFORM=linux/arm64 in .env before the first Docker build

Quick prerequisite check (from the repository root):

Terminal window
just --version
docker compose version
rustc --version
cargo --version
pnpm --version
buf --version
protoc --version
test -f vortex-common-crates/Cargo.toml && echo "submodule ok"

Install local hooks once:

Terminal window
pre-commit install

The hook and CI behavior is summarized in CI/CD Pipeline.

From the repository root with .env in place:

Terminal window
# Stand up the full stack (Postgres, ClickHouse, MinIO, NATS, Valkey,
# OTel Collector, the Rust services, and the Next.js console).
just dev

The first invocation compiles every Rust service inside the Docker build steps.

Terminal window
# 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_total

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.

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.

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:

Terminal window
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_NEXT

Scope 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:

Terminal window
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.

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.

Terminal window
# 1. Enable PTB in .env, then recreate the gateway.
# NEXUS_GATEWAY_PTB=1
just compose up -d gateway
# 2. Load operator-managed platform provider keys from .env.
just load-provider-keys
just 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 list
just 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-smoke
PTB_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).

PTB credits are funded by auditable operator grants. Auto-refill settings are alerting configuration only.

Terminal window
nexus ops grants create \
--workspace ws_... \
--amount-usd 100.00 \
--reason "pilot credit" \
--idempotency-key pilot-credit-001
nexus ops grants list ws_...
Terminal window
just down # stops containers, preserves volumes
just dev-clean # stops containers and destroys volumes

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.

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.

Terminal window
nexus ops registration-invites create \
--email newuser@example.com \
--base-url http://127.0.0.1:14449

The 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:

Terminal window
nexus ops registration-invites list
nexus ops registration-invites revoke inv_...

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.

Terminal window
nexus ops registration-codes create --max-uses 10 --base-url http://127.0.0.1:14449
nexus ops registration-codes list
nexus 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.

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.

  • 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.