LLM Gateway Local Development
Status: Active local runbook Last updated: 2026-03-27
Sidecar integration reference:
llm-gateway/docs/sidecar-agent-registration.md
1. Prerequisites
Section titled “1. Prerequisites”- Go 1.23+
justcurlpython3docker+docker compose(for local Postgres)
From repo root:
cd /path/to/gatewayjust --justfile llm-gateway/justfile --list2. Local Modes
Section titled “2. Local Modes”2.1 Postgres gateway mode
Section titled “2.1 Postgres gateway mode”Start DB:
just --justfile llm-gateway/justfile audit-db-upRun gateway with registry backend and registration endpoint enabled:
just --justfile llm-gateway/justfile gateway-registryOr run from local TOML runtime config:
just --justfile llm-gateway/justfile gateway-configThis mode enables:
- trusted registry in Postgres
POST /v1/agents/registrations- audit writes to Postgres (default in
gateway-registry) - Anthropic/OpenAI/ChatGPT backend endpoint routing
3. Generate signing key
Section titled “3. Generate signing key”SEED=$(just --justfile llm-gateway/justfile gen-key | awk -F= '/seed_b64url/{print $2; exit}')4. Register agent in registry mode
Section titled “4. Register agent in registry mode”Create provisioning token from the local registration token secret:
TOKEN=$(just --justfile llm-gateway/justfile reg-token | awk -F= '/^token=/{print $2; exit}')Register the agent (uses SEED public key):
just --justfile llm-gateway/justfile register-agent "$TOKEN" "$SEED"5. Build signed headers and run E2E
Section titled “5. Build signed headers and run E2E”5.1 Registry mode
Section titled “5.1 Registry mode”just --justfile llm-gateway/justfile e2e-prepare-registry "$TOKEN" "$SEED"just --justfile llm-gateway/justfile e2e-successjust --justfile llm-gateway/justfile e2e-replayjust --justfile llm-gateway/justfile e2e-missing-signature6. Useful commands
Section titled “6. Useful commands”Gateway health:
just --justfile llm-gateway/justfile gateway-healthShow migrations applied:
just --justfile llm-gateway/justfile audit-db-migrationsRun tests:
just --justfile llm-gateway/justfile test7. OTEL Validation Workflow (OBS-01.8 + OBS-02.3)
Section titled “7. OTEL Validation Workflow (OBS-01.8 + OBS-02.3)”Run the fast headless validation flow (collector + artifact contract check with propagation matrix assertions):
just --justfile llm-gateway/justfile obs-otel-validateExpected success output includes:
PASS: telemetry contract validatedpropagation scenarios validated: 9- artifact paths:
llm-gateway/observability/.artifacts/traces.jsonlllm-gateway/observability/.artifacts/logs.jsonl
Run the UI-backed validation flow (Jaeger + terminal-correlated logs):
just --justfile llm-gateway/justfile obs-otel-validate-uiThis deterministic UI validation run:
- generates proxy telemetry via the collector export test harness
- defaults to
3agents with5requests each (15total) - validates telemetry contract artifacts
- renders span/log correlation plus per-agent request counts in terminal
- prints Jaeger URL (
http://localhost:16686/search)
UI artifacts are written to:
llm-gateway/observability/.artifacts/traces.jsonlllm-gateway/observability/.artifacts/logs.jsonl
Run both validation flows in sequence:
just --justfile llm-gateway/justfile obs-otel-validate-allRun the fast observability contract test (topology + required fields) directly:
just --justfile llm-gateway/justfile obs-otel-contract-testRun propagation contract tests directly (including upgrade-handshake propagation contract checks):
just --justfile llm-gateway/justfile obs-otel-propagation-contract-testRun p95 instrumentation overhead check (delta <= 5ms by default):
just --justfile llm-gateway/justfile obs-otel-overhead-checkOverride samples or threshold:
just --justfile llm-gateway/justfile obs-otel-overhead-check samples=300 max_delta_ms=4.5Run the reproducible OBS-02.3 regression flow in one command:
just --justfile llm-gateway/justfile obs-otel-regression-checkThis runs:
obs-otel-validate(artifact + propagation contract validation)obs-otel-propagation-contract-test(Go propagation contract checks)obs-otel-overhead-check(p95 delta <= 5ms)
This command writes a report artifact at:
llm-gateway/observability/.artifacts/overhead-report.json
When recording OBS-02.3 evidence in an issue/PR note, include:
- command run (
obs-otel-regression-check) - pass/fail summary from validation output
- overhead report summary from
overhead-report.json(delta_p95_ms,max_allowed_delta_ms,pass)
Collector lifecycle helpers:
just --justfile llm-gateway/justfile obs-otel-collector-upjust --justfile llm-gateway/justfile obs-otel-collector-downCompatibility alias:
just --justfile llm-gateway/justfile obs-otel-demoobs-otel-demo maps to obs-otel-validate-ui.
Re-render existing UI/demo artifacts without generating new telemetry:
just --justfile llm-gateway/justfile obs-otel-demo-showOverride UI/demo traffic volume:
OBS_OTEL_DEMO_AGENT_COUNT=4 OBS_OTEL_DEMO_REQUESTS_PER_AGENT=8 \ just --justfile llm-gateway/justfile obs-otel-validate-uiUI stack lifecycle helpers:
just --justfile llm-gateway/justfile obs-otel-demo-upjust --justfile llm-gateway/justfile obs-otel-demo-down8. Local config files
Section titled “8. Local config files”Tracked templates:
llm-gateway/service/configs/runtime.example.tomlllm-gateway/docs/local-plugin-e2e.md
Local mutable files (gitignored):
llm-gateway/service/configs/runtime.local.toml
9. Troubleshooting
Section titled “9. Troubleshooting”-
invalid config: registry-db-dsn is required when registry-backend=postgres- pass
-registry-db-dsn, or usejust --justfile llm-gateway/justfile gateway/gateway-registry
- pass
-
registration_invalid_token- ensure token was minted with the configured registration token secret
- ensure token not expired
-
registration_conflictagent_idconflicts with existing records, or active key ownership conflict in registry
-
sig_invalid- ensure registered key matches signing seed
- ensure
keyidusesdid:key:z...
-
obs-otel-validatefails before telemetry validation- rerun with shell trace for more detail:
bash -x llm-gateway/observability/run_otel_validation.sh llm-gateway - ensure Docker is running and ports
4317/4318are free for the local collector - ensure
go test ./internal/gatewayhttp -run '^TestProxyCollectorExportValidation$'can reachOBS_OTEL_COLLECTOR_ENDPOINT(default127.0.0.1:4318) - if overriding collector volume env vars, ensure
OBS_OTEL_COLLECTOR_AGENT_COUNT * OBS_OTEL_COLLECTOR_REQUESTS_PER_AGENT >= 9so the propagation scenario matrix is fully exercised
- rerun with shell trace for more detail:
-
obs-otel-validate-ui(orobs-otel-demo) fails before telemetry validation- rerun with shell trace for more detail:
bash -x llm-gateway/observability/run_otel_demo.sh llm-gateway - ensure Docker is running and ports
14317/14318/16686are free for demo collector + Jaeger - ensure
go test ./internal/gatewayhttp -run '^TestProxyCollectorExportValidation$'can reachOBS_OTEL_DEMO_COLLECTOR_ENDPOINT(default127.0.0.1:14318) - if overriding demo traffic env vars, ensure
OBS_OTEL_DEMO_AGENT_COUNT * OBS_OTEL_DEMO_REQUESTS_PER_AGENT >= 9
- rerun with shell trace for more detail:
10. Codex/OpenAI local sidecar profile
Section titled “10. Codex/OpenAI local sidecar profile”Run the thin test sidecar in Codex profile:
cd llm-gateway/serviceGOWORK=off go run ./scripts/test_sidecar.go \ -listen 127.0.0.1:18082 \ -gateway-base-url http://127.0.0.1:10000 \ -seed-b64url "$SEED" \ -register-token "$TOKEN" \ -client-profile codexOptional fallback key injection (only used when incoming Authorization is missing):
GOWORK=off go run ./scripts/test_sidecar.go \ -listen 127.0.0.1:18082 \ -gateway-base-url http://127.0.0.1:10000 \ -seed-b64url "$SEED" \ -register-token "$TOKEN" \ -client-profile codex \ -openai-api-key "$OPENAI_API_KEY"Project-local env (example):
export OPENAI_BASE_URL=http://127.0.0.1:18082/v1export OPENAI_API_KEY=sk-...client-profile=codex rewrites OpenAI-style request paths to gateway provider-prefix routes under /v1/openai_api/v1/....