Infrastructure
Rikoo is two application services, the api and the worker, on top of three stores: PostgreSQL, Redis and an S3-compatible object store. Two optional services add document parsing and the embedded tools.
Application services
| Service | Role | Required | State |
|---|---|---|---|
api | REST API, Studio, widget script, authentication, enqueueing. Applies database migrations when it starts. | Yes | Stateless |
worker | Runs agents: model calls, retrieval, tool calls, e-mails and webhooks. | Yes | Stateless |
sidecar-parsing | Extracts text from PDF and Office documents. Without it, the worker falls back to its own parsers. | No | Stateless |
mcp-sandbox | The embedded tools: a workspace per conversation and a browser. Without it, those tools return an error and runs continue. | No | Stateful: one workspace per conversation |
playwright-mcp | The browser driven by the sandbox. | With the sandbox | Stateless |
mcp-egress | The only way out for the sandbox browser, behind the same anti-SSRF guard as the worker. | With the sandbox | Stateless |
The api and the worker scale horizontally: they keep no state outside the stores.
PostgreSQL
- Version: PostgreSQL 16 is the tested version (the reference stacks run
pgvector/pgvector:pg16). - Extensions:
vector(pgvector) andcitext. Vector indexes use thehalfvectype, available from pgvector 0.7.0. - Roles: migrations create the extensions and a
rikoo_approle, so the migrating role needs the rights to create extensions and roles. Givingrikoo_appa password and pointingAPP_DATABASE_URLat it makes row-level security filter every tenant query. - Variables:
DATABASE_URL(required),APP_DATABASE_URL(recommended). - Managed PostgreSQL services work, provided they offer pgvector and let the migrating role create roles.
Everything except files lives here, vectors included. Back it up.
Redis
- Version: Redis 7.
- Used for: job queues, sessions and login counters, and the events that stream a run to the browser.
- Configuration: persistence on (
appendonly yesin the reference stacks) and no eviction (maxmemory-policy noeviction): an evicted key is a lost job or session. - Variable:
REDIS_URL(required),redis://orrediss://. - Rikoo connects to a single Redis endpoint, without Cluster or Sentinel mode.
Object storage
- Any S3-compatible service: MinIO, bundled with both reference stacks, or your cloud provider's object storage.
- One bucket holds ingested source files, attachments, large tool outputs and audit exports, each under a per-organization prefix.
- Variables:
S3_ENDPOINT,S3_BUCKET,S3_ACCESS_KEY_IDandS3_SECRET_ACCESS_KEY(required);S3_REGION(defaults tous-east-1, same value on the api and the worker);S3_FORCE_PATH_STYLE(defaults totrue);S3_BROWSER_ENDPOINT. - Browser access: browsers exchange files with the bucket directly, through signed URLs, so
S3_BROWSER_ENDPOINTmust be reachable by your users. MinIO accepts every origin by default; a cloud bucket has no CORS rule until you add one. AllowPUTfromPUBLIC_URL, where the Studio uploads documents, andGETfrom the sites where the widget runs, which fetches files for "download all" and "copy image".
Network
| From | To | Why |
|---|---|---|
| Users | api | Studio, widget, public API |
| Users | object storage | Attachment uploads, at S3_BROWSER_ENDPOINT |
| api | PostgreSQL, Redis, your trace collector | No other outbound access |
| worker | PostgreSQL, Redis, object storage | Data |
| worker | Model providers, MCP servers, webhook targets, SMTP server, your trace collector | Everything that leaves the platform |
Every outbound request of the worker passes an anti-SSRF guard, which refuses private and link-local
addresses. To reach a model server on your own network, for example vLLM or Ollama, allow its
address range with RIKOO_EGRESS_ALLOW_CIDRS, set to the same value on the api, the worker and
mcp-egress. Keep the range as narrow as possible: each entry is a hole in the guard.
Model provider credentials are not environment variables. They are entered in the Studio, sealed in the vault, and only the worker can open them.
Observability
| Endpoint | Service | Use |
|---|---|---|
GET /healthz | api | Liveness: answers while the process runs, without touching any dependency |
GET /readyz | api | Readiness: 503 until PostgreSQL and Redis answer |
GET /api/v1/health | api | Status and version |
GET /health on port 3100 | worker | Worker health, internal |
GET /metrics on port 3100 | worker | Prometheus metrics |
GET /metrics on port 9464 | api | Prometheus metrics, when OTEL_METRICS_EXPORTER_API=prometheus |
Traces are exported over OTLP (HTTP) to your own collector. Set OTEL_EXPORTER_OTLP_ENDPOINT for the
worker and OTEL_EXPORTER_OTLP_ENDPOINT_API for the api. Without a collector nothing is exported,
and nothing fails.