The picture
Processes
Ravi runs as PM2 processes. Each one is started by a different command.ravi daemon start starts only ravi. If you use Slack, you also run ravi channels start once. If you skip Omni because you only use Slack, you run your own nats-server under PM2 instead of omni-nats (see Install).
Restarting the daemon does not restart the runner, and the other way around. ravi update restarts only the processes that were online before it ran. When native channels are enabled and ravi-channels was not running, it warns, and you start the runner with ravi channels start.
NATS JetStream: the bus
Every Ravi process talks through one NATS server with JetStream, atNATS_URL (default nats://127.0.0.1:4222). Ravi does not ship a NATS server. It uses the one Omni installs, or one you run yourself.
Ravi creates these streams itself: the daemon creates SESSION_PROMPTS and RAVI_EVENTS at start, and the channel runner creates CHANNEL_OUTBOUND.
Omni owns the
MESSAGE, INSTANCE and REACTION streams, which the daemon reads. See Events for every topic.
How a message flows
- Slack (native)
- WhatsApp (Omni)
Inbound. Slack sends the event to
ravi-channels over Socket Mode. The runner resolves the channel account, applies the instance policies and routes, picks the agent and session, saves any attachment into the agent’s working directory, and publishes a prompt to ravi.session.<name>.prompt. The daemon picks it up from SESSION_PROMPTS and runs the turn.Outbound. When the agent replies, the daemon’s delivery layer sees that the target channel is Slack and writes an outbound job to CHANNEL_OUTBOUND. The runner consumes the job and posts it with the Slack Web API, in the thread the routing policy chose. While the turn runs, the runner shows a “working” status in the thread.Slack tokens are read by the runner from the credential broker. See Slack.Sessions and the runtime
A session is one conversation thread with an agent, with its own history and provider state. Its key encodes where it came from, for exampleagent:main:dm:<peer> or agent:main:slack:<account>:group:<id>. See Sessions.
When a prompt arrives, the daemon runs the turn with the session’s provider, in the agent’s working directory (~/ravi/<agent>), which holds the agent’s AGENTS.md:
A session uses its own override if it has one (
ravi sessions set-provider), otherwise the provider it last used, then the agent’s preset or provider, then the runtime.defaultProvider setting, then codex; ravi agents set moves sessions that have no override to the agent’s new provider. Set your agent explicitly:
ravi CLI as their tools, checked against their permissions (see Permissions). Provider CLIs that run in a sandbox reach ravi through a local socket, ~/.ravi/cli-gateway.sock.
Background runners
Inside the daemon, runners handle work that is not a reply to a message: cron jobs, heartbeats, event triggers, hooks, background jobs, task checkpoints and the Console inbox poller. If you run more than one daemon against the same NATS server, they elect a leader through a NATS key-value lease (30 seconds, renewed every 10). Only the leader runs cron, heartbeat and the other scheduled runners, so a job never fires twice. Every daemon runs triggers, hooks and the Console poller.Storage
All of it is local SQLite and files. The full list is in Configuration.
HTTP gateway and SDK
SetRAVI_HTTP_PORT and the daemon serves an HTTP API on 127.0.0.1 (change it with RAVI_HTTP_HOST). Under /api/v1/ it exposes the CLI’s commands (a few long-running ones stay CLI-only), authorized with Authorization: Bearer rctx_... runtime context keys. The same server receives webhooks. Binding a non-loopback address requires RAVI_GATEWAY_NETWORK_AUTHORIZED=1. The gateway builds its routes from the CLI’s command registry, and the TypeScript, Dart and Swift SDKs and the OpenAPI spec are generated from it; the pre-push hook and CI fail if they drift. See SDKs and HTTP gateway.
The Ravi Console
The Console (https://console.ravi.bot) is optional. ravi login links this install to your Console organization and stores the login in ~/.ravi/cloud-auth/. After that:
- Inbox. The daemon polls the Console agent inbox every 15 seconds and publishes each item locally on
ravi.console.inbox.item, where triggers can react to it. Without a login the poller stays paused. - Pages.
ravi pages shippublishes HTML to your project host,<org>-<project>.ravi.page. See Pages. - Bases.
ravi basesmanages typed tables in a Console project.ravi bases subscribe <base>sends row changes to the inbox, so they arrive as events. See Bases.
Related
- Configuration: every variable, setting and file.
- Events: the topics on the bus.
- Troubleshooting: where to look when a message gets no answer.