Skip to main content

Reference Dockerfile

QiForge has no runtime dependency on itself — anywhere Node 22+ runs, an oracle runs. This Dockerfile is the shortest path from pnpm dev to a container you can ship.
Everything below explains the moving parts. The reference oracle (apps/qiforge-example) builds with pnpm build and runs with node dist/main.js — see apps/qiforge-example/src/main.ts.

Prerequisites

  • Node.js 22+
  • A reachable Matrix homeserver
  • A persistent volume for the Matrix store and SQLite checkpointer
  • Core env vars (per baseEnvSchema)
  • Optional: Redis (only if credits or tasks plugins are loaded)

Build and ship

1

Build the production bundle

For the example app this runs tsc -p tsconfig.build.json and outputs dist/. Your package.json’s start script should be node dist/main.js.
2

Pin every required env var

Production .env (or your platform’s secret manager) needs every core var plus the vars for each plugin you’ve kept.
Per-plugin vars come on top — see environment variables reference for the full list. Boot validates every var declared by every loaded plugin’s configSchema; missing required vars fail loudly.
3

Run the entity setup once per deployment

Identity and Matrix keys are provisioned via the CLI — see identity and auth for the full flow.

Persistent volumes

1

Mount /data as a persistent volume

Two things must survive restarts. Lose either and you lose state.In Docker Compose:
On Railway / Fly.io: attach a persistent volume mounted at /data.
2

Add Redis only when needed

Redis is required only if you load the credits plugin (or the tasks plugin once it ships). Without those, skip it entirely.
Pass the Redis client to CreditsPlugin explicitly — see enable bundled plugins.

Health probes

1

Use /health as the liveness probe

The framework exposes GET /health, always public, never goes through AuthHeaderMiddleware. Returns 200 once Nest is up. The built-in auth-excluded routes are / (a JSON landing payload), /health, /docs, and /docs/(.*) — everything else requires auth.Docker:
Kubernetes:
2

There is no separate readiness probe

Matrix init runs in the background. The process accepts requests immediately after Nest boots. If you need to delay traffic until Matrix is up, subscribe via app.onPluginStatusChange and signal your platform when matrix transitions to loaded — see observability.
3

The /docs Swagger UI is also auth-excluded

Useful for debugging in production behind a private network. To remove it in public deployments, host-supply your own Nest module that re-mounts /docs behind auth, or block it at your reverse proxy.

CORS

CORS_ORIGIN controls who can call your oracle from a browser. The framework allows these headers on every request:
Authorization and x-auth-type carry the primary invocation-auth path (Authorization: Bearer <invocation> + X-Auth-Type: ucan); x-ucan-delegation carries the downstream-authorization delegation. If you replicate CORS at a reverse proxy, mirror this full list — dropping x-auth-type breaks browser clients on the primary auth path.

Logging

The runtime uses NestJS’s default Logger. Pipe stdout/stderr to your aggregator. Override the bootstrap logger with createOracleApp({ logger }) if you need a custom format — see createOracleApp reference. For structured tracing instead of free-form logs, set the LangSmith env vars — see observability.

Graceful shutdown

The runtime registers a SIGTERM / SIGINT handler that drains in order: (1) flushes the per-user checkpoint to Matrix, (2) closes the Nest app, (3) shuts down the Matrix client, (4) runs any plugin teardowns. Each step is isolated — a failure in one is logged and the rest still run. That first step is why a clean SIGTERM matters: an abrupt SIGKILL skips the checkpoint upload and loses recent thread state. See graceful-shutdown.ts.
Disable graceful shutdown only when your platform’s process manager guarantees a clean app.close() on termination. Otherwise you’ll skip the checkpoint flush and risk Matrix sync corruption.

Environment variables

Every var per plugin, exhaustively.

Observability

LangSmith, plugin lifecycle, logger.

Identity and auth

Entity setup and per-request UCAN auth.

Troubleshooting

Boot errors, Matrix issues, common runtime errors.