Skip to main content

Overview

Reliant runs as three independently deployable server types: an API server, a Temporal worker, and a daemon gateway. Each runs as a separate process, communicates through shared infrastructure, and can be scaled according to its workload characteristics. The deployment requires a Postgres database, an external Temporal cluster (self-hosted or Temporal Cloud), and a NATS message broker. Tool execution runs on a separate client-side daemon that connects through the gateway. The three server types are started via reliant server subcommands:
Distributed Architecture

The Three Server Types

API Server (reliant server api)

The API server handles every client-facing request. It is entirely stateless—it stores nothing locally and derives all state from Postgres, Temporal, and NATS. This makes it safe to run as N replicas behind a load balancer with no session affinity required. On startup, the API server connects to Postgres for application data, to Temporal for workflow orchestration, and to NATS for both real-time event streaming and daemon tool routing. NATS is the only streaming driver: an API server replica cannot receive cross-process events through an in-memory hub. The server exposes three network endpoints:
  • ConnectRPC (default port 9090) — Every typed service: chat, workflow management, projects, settings, streaming updates, and the browser’s view of a daemon (FileSystemService, BackgroundService, TerminalService, DaemonService), which it reaches through NATS. A WebSocket endpoint at /api/v2/terminal/ws carries terminal I/O.
  • Health check (default port 8081) — /health for liveness and /ready for readiness. The readiness check validates connectivity to Postgres, NATS, and the streaming hub before returning 200, and turns 503 when the server begins draining for shutdown.
  • pprof (default port 6060) — Go profiling endpoints for debugging, plus /debug/db for the database write queue.
When the API server needs to execute a tool on a developer’s machine, it publishes the request to NATS via the NATSDaemonRouter. The gateway that holds the developer’s daemon connection picks up the request and forwards it. This indirection is what allows the API server to remain stateless—it never holds daemon connections directly.

Configuration Reference

Worker (reliant server worker)

The worker processes Temporal workflow executions. It connects to the external Temporal cluster, registers workflow and activity handlers, and polls for tasks. Activities include LLM inference, tool execution routing, and database operations. Like the API server, the worker is stateless and can run as N replicas for horizontal scaling. Temporal handles task distribution automatically—adding more worker replicas increases throughput without any coordination between them. When a workflow activity needs to execute a tool on a developer’s machine, the worker publishes the request to NATS using the same NATSDaemonRouter as the API server. It also uses NATS update hubs to publish real-time chat and user update events that API server replicas pick up and stream to connected clients. Each tool declares a placement: daemon (it needs the user’s files or shell), server or any. The worker runs server and any tools itself, avoiding the NATS round-trip to a daemon for operations that don’t need a machine.

Configuration Reference

Gateway (reliant server gateway)

The gateway manages persistent bidirectional gRPC streams to tools-daemon processes running on developer machines. It is the bridge between the cloud infrastructure (NATS) and the developer’s local environment (daemon gRPC streams). The gateway is stateful—each instance maintains active gRPC connections to whichever daemons have connected to it. This means it should be deployed as few replicas rather than freely scaled like the API server and worker. A gateway going down disconnects its daemons, which must reconnect (potentially to a different gateway instance). Internally, the gateway bridges NATS to its daemon connections with the NATSToolBridge. When a daemon connects, the bridge subscribes to that daemon’s own subjects (tools.request.{userID}.{daemonID}, daemon.command.{userID}.{daemonID} and their siblings for cancellation, background processes, config and terminal streams) and unsubscribes when it disconnects. Because a subject names one daemon, exactly one gateway instance (the one holding that daemon’s stream) receives each message, for fire-and-forget requests and request-reply alike. Commands sent while a daemon is offline are queued and delivered when it next connects. The gateway serves only daemons. The browser’s view of a daemon (file browsing, terminals, background processes) is served by the API server, which reaches the daemon through NATS. Daemons authenticate with their rlat_ access token, which the gateway resolves on every connection. Remote trace context from a daemon is never trusted: daemons run on user machines, so a daemon’s traceparent is recorded only as a span link.

Configuration Reference

Infrastructure Requirements

Distributed mode depends on three external services that all server types connect to. Postgres serves as the shared application database. All three server types connect to the same Postgres instance (or cluster) for chats, messages, workflows, projects, worktrees, and user data. Every server validates its database connection as part of the /ready health check. Temporal orchestrates workflow execution. The API server uses the Temporal client to start and signal workflows. The worker registers with Temporal to process workflow tasks. Both connect via temporal.NewExternalClient using the configured host, port, and namespace. This can be a self-hosted Temporal deployment or Temporal Cloud—Reliant only needs a standard Temporal gRPC endpoint. NATS serves two distinct purposes. First, it acts as the real-time notification channel for update events (NATSUpdateHub). When a worker or API server writes a chat message to Postgres, it publishes an update event to NATS, and all API server replicas with connected clients receive it for streaming. Second, NATS is the transport layer for daemon tool routing (NATSDaemonRouter and NATSToolBridge), carrying tool execution requests between workers/API servers and gateways. NATS is a delivery mechanism, not a store: messages and events are durable in Postgres. JetStream is used where a short replay window matters: the streaming deltas a reconnecting client catches up on (in memory, kept for minutes), commands queued for a daemon that is offline, and daemon connection events.

The Tools Daemon

The tools daemon runs as a separate reliant daemon process on a machine the user owns, or on a managed cloud machine. It provides local tool execution capabilities — shell commands, file operations, MCP server management, terminal sessions — to the cloud platform via a persistent bidirectional gRPC stream to the gateway. The desktop app starts one for you; this section is for running one by hand.

Connecting a Daemon

daemon register opens a browser to sign in and approve a long-lived access token for the daemon, and stores it locally. It is a login of its own: a reliant auth login session is a different credential and is never reused for a daemon. The token is scoped to your user and can be revoked independently of your main session, in Settings → Access Tokens. Each daemon keeps its own identity under ~/.reliant/instances/<server>/<account>/<workspace>/, so one machine can serve several accounts, and several workspaces, side by side.

Credential Resolution

daemon start resolves credentials in order:
  1. --token: an access token read from stdin, which is the form for automation.
  2. The daemon’s credentials file (~/.reliant/daemon.json), written by an earlier daemon start or by daemon register.
  3. Its own browser login: otherwise it opens a browser to sign in and registers, exactly as daemon register does. Being logged in with reliant auth login does not skip this. With --non-interactive (how the desktop app starts it) it never opens a browser; it stays idle, reporting that it is awaiting credentials, until a credentials file appears.

TLS

TLS mode is inferred from the gateway URL (https:// → TLS, http:// → h2c). Override with --tls-mode: tls (full verification), insecure_tls_skip_verify (self-signed certificates), h2c (plaintext HTTP/2, for local development) or disabled.

Lifecycle

Once connected, the daemon receives tool execution requests from the gateway and executes them locally. The gateway sends a heartbeat every 15 seconds and treats a stream it has heard nothing on for 90 seconds as dead. On disconnect, the daemon reconnects automatically with exponential backoff. A user can have several daemons connected at once (one per machine or workspace); every request names the daemon it is for.

Tool Routing Architecture

Tool execution in distributed mode involves multiple hops across NATS and gRPC. The routing works as follows:
  1. A worker (or API server) needs to execute a tool on a developer’s machine. It calls NATSDaemonRouter.SendToolRequest(), which publishes a JSON-encoded ToolExecutionRequest to the NATS subject tools.request.{userID}.{daemonID}.
  2. The NATSToolBridge in the gateway that holds that daemon’s stream subscribed to the daemon’s subjects when it connected. It receives the message and forwards the request to the local ToolsDaemonService.
  3. The ToolsDaemonService holds the daemon’s bidirectional gRPC stream. It sends the tool execution request down the stream to the daemon.
  4. The daemon executes the tool locally (running a shell command, reading a file, calling an MCP server, etc.) and sends the result back up the gRPC stream.
  5. The response flows back: ToolsDaemonService → NATSToolBridge → NATS → the requesting worker or API server.
For synchronous tool execution, the worker uses NATSDaemonRouter.SendToolRequestSync(), which issues a NATS request-reply on tools.request.sync.{userID}.{daemonID} and blocks until the daemon responds. NATS subjects are partitioned by user and daemon, so a request reaches exactly the gateway that holds its daemon’s stream, and no other gateway sees it. A large request or response is split into chunks and reassembled on the other side.

Scaling Characteristics

API servers and workers scale linearly with load. Adding more API server replicas handles more concurrent HTTP/gRPC requests. Adding more worker replicas increases workflow processing throughput. Gateways scale differently because each daemon maintains a single persistent connection to one gateway. The gateway’s capacity is bounded by the number of concurrent daemon connections it can manage, which is typically large (thousands of gRPC streams per instance). Deploy multiple gateways for availability rather than throughput—if a gateway goes down, its daemons reconnect to a surviving instance.