Skip to main content

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​

ServiceRoleRequiredState
apiREST API, Studio, widget script, authentication, enqueueing. Applies database migrations when it starts.YesStateless
workerRuns agents: model calls, retrieval, tool calls, e-mails and webhooks.YesStateless
sidecar-parsingExtracts text from PDF and Office documents. Without it, the worker falls back to its own parsers.NoStateless
mcp-sandboxThe embedded tools: a workspace per conversation and a browser. Without it, those tools return an error and runs continue.NoStateful: one workspace per conversation
playwright-mcpThe browser driven by the sandbox.With the sandboxStateless
mcp-egressThe only way out for the sandbox browser, behind the same anti-SSRF guard as the worker.With the sandboxStateless

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) and citext. Vector indexes use the halfvec type, available from pgvector 0.7.0.
  • Roles: migrations create the extensions and a rikoo_app role, so the migrating role needs the rights to create extensions and roles. Giving rikoo_app a password and pointing APP_DATABASE_URL at 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 yes in the reference stacks) and no eviction (maxmemory-policy noeviction): an evicted key is a lost job or session.
  • Variable: REDIS_URL (required), redis:// or rediss://.
  • 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_ID and S3_SECRET_ACCESS_KEY (required); S3_REGION (defaults to us-east-1, same value on the api and the worker); S3_FORCE_PATH_STYLE (defaults to true); S3_BROWSER_ENDPOINT.
  • Browser access: browsers exchange files with the bucket directly, through signed URLs, so S3_BROWSER_ENDPOINT must be reachable by your users. MinIO accepts every origin by default; a cloud bucket has no CORS rule until you add one. Allow PUT from PUBLIC_URL, where the Studio uploads documents, and GET from the sites where the widget runs, which fetches files for "download all" and "copy image".

Network​

FromToWhy
UsersapiStudio, widget, public API
Usersobject storageAttachment uploads, at S3_BROWSER_ENDPOINT
apiPostgreSQL, Redis, your trace collectorNo other outbound access
workerPostgreSQL, Redis, object storageData
workerModel providers, MCP servers, webhook targets, SMTP server, your trace collectorEverything 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​

EndpointServiceUse
GET /healthzapiLiveness: answers while the process runs, without touching any dependency
GET /readyzapiReadiness: 503 until PostgreSQL and Redis answer
GET /api/v1/healthapiStatus and version
GET /health on port 3100workerWorker health, internal
GET /metrics on port 3100workerPrometheus metrics
GET /metrics on port 9464apiPrometheus 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.