revka gateway, daemon & service
Run the gateway, the full daemon, or an OS-managed service; manage pairing codes and bind hosts/ports.
These commands run the Revka HTTP runtime: revka gateway for the dashboard and API alone, revka daemon for the full autonomous runtime, and revka service to keep either alive as an OS-managed background service. This page is the reference for all three, plus the pairing-code workflow and the bind-host restrictions that gate network exposure.
Reach for revka gateway for local dashboard work, revka daemon for production (channels, heartbeat, and cron together), and revka service once you want Revka to start on login or boot and survive crashes. For a first-time, click-through walkthrough see Run the dashboard; for OS-by-OS service detail see Run as a background service.
revka gateway
Section titled “revka gateway”revka gateway starts just the HTTP/WebSocket gateway: the embedded React dashboard at /, the REST API under /api/*, the Server-Sent Events stream at /api/events, and the WebSocket endpoints (/ws/chat, /ws/canvas/{id}, /ws/nodes). It does not start channels, the heartbeat, or the cron scheduler — use revka daemon for those.
revka gateway # start on config defaultsrevka gateway start # explicit startrevka gateway start -p 8080 # custom portrevka gateway start --host 0.0.0.0 # bind all interfaces (see bind restrictions)revka gateway start -p 0 # bind a random available portrevka gateway restart # graceful restartrevka gateway restart -p 9090revka gateway get-paircode # show the current pairing coderevka gateway get-paircode --new # rotate to a fresh pairing codeSubcommands and flags
Section titled “Subcommands and flags”| Subcommand | Flags | Purpose |
|---|---|---|
start | -p / --port <u16> (0 = random), --host <STRING> | Start the gateway. Bare revka gateway is equivalent to revka gateway start. |
restart | -p / --port <u16>, --host <STRING> | Graceful restart with the same flags as start. |
get-paircode | --new | Print the current pairing code, or rotate to a fresh one with --new. |
The default bind is 127.0.0.1:42617. The listen port is read from [gateway].port in your config (schema default 42617), and --port/--host override the config per invocation. The process prints its URL on startup.
revka daemon
Section titled “revka daemon”revka daemon launches the complete Revka runtime as a single foreground process: the gateway server, every configured channel supervisor (Telegram, Discord, Slack, and so on), the heartbeat monitor, and the cron scheduler. This is the recommended production entrypoint — register it with revka service so the OS keeps it alive.
revka daemon # use config defaultsrevka daemon -p 9090 # gateway on port 9090revka daemon --host 127.0.0.1 # localhost onlyrevka daemon --host 0.0.0.0 # all interfaces (requires allow_public_bind)| Flag | Default | Meaning |
|---|---|---|
-p / --port <u16> | [gateway].port | Gateway listen port. 0 binds a random available port. |
--host <STRING> | [gateway].host | Bind address. Non-loopback addresses are gated — see bind restrictions. |
--config-dir <PATH> | ~/.revka | Global flag; must precede the subcommand. Also sets REVKA_CONFIG_DIR for the process. |
The daemon terminates cleanly on SIGINT or SIGTERM. SIGHUP is explicitly ignored, so the process survives an SSH or terminal disconnect. A warning is logged if the binary is running from a user home directory instead of a system install location such as /usr/local/bin.
Component supervisor
Section titled “Component supervisor”Each of the four daemon components — gateway, channels, heartbeat, scheduler — runs in its own task wrapped by a supervisor. On crash or exit, the supervisor waits channel_initial_backoff_secs (default 2), then doubles the delay on each subsequent failure up to channel_max_backoff_secs (default 60) before restarting. The restart count and last error are recorded in the health snapshot.
[reliability]channel_initial_backoff_secs = 2 # initial retry delay (minimum 1)channel_max_backoff_secs = 60 # exponential cap; must be >= initial| Key | Type | Default | Meaning |
|---|---|---|---|
reliability.channel_initial_backoff_secs | integer | 2 | Initial retry delay in seconds. Minimum 1. |
reliability.channel_max_backoff_secs | integer | 60 | Exponential backoff cap. Must be greater than or equal to the initial value. |
Daemon state file
Section titled “Daemon state file”While running, the daemon writes daemon_state.json alongside config.toml (<config_dir>/daemon_state.json) every 5 seconds. The file contains a health snapshot of every component and a written_at timestamp.
- Liveness monitoring — a state file older than 45 seconds means the daemon has died. External monitors can poll this file directly.
- Windows —
revka service startreads this file to detect whether a direct-daemon fallback is already running, because the Windows Task Scheduler cannot be queried reliably.
Pairing codes and tokens
Section titled “Pairing codes and tokens”Every /api/* request carries Authorization: Bearer <token>, and that token is minted by exchanging a one-time pairing code. Pairing is what stops an unknown client on your network from driving your agent.
Show or rotate the code from the CLI
Section titled “Show or rotate the code from the CLI”revka gateway get-paircode # show the current coderevka gateway get-paircode --new # rotate to a fresh codeThese call the localhost-only admin endpoints GET /admin/paircode and POST /admin/paircode/new. Codes are single-use: once a client pairs with a code it is consumed, and you must rotate to issue another.
Exchange a code for a token (revka pair token)
Section titled “Exchange a code for a token (revka pair token)”revka pair token exchanges a pairing code for a bearer token from the command line — useful for pairing a headless device or a script.
revka pair token --code 123456revka pair token --code 123456 --name "Field phone" --device-type mobile --hardware "Pixel 8 / Android"revka pair token --url http://revka.local:8080 --code 123456 --jsonrevka pair token --code 123456 --host 192.168.1.10 --port 8080| Flag | Required | Meaning |
|---|---|---|
--code <STRING> | yes | The one-time pairing code. |
--url <URL> | no | Full gateway base URL, e.g. http://127.0.0.1:8080. |
--host <STRING> | no | Gateway host, used when --url is omitted. |
-p / --port <u16> | no | Gateway port, used when --url is omitted. |
--name <STRING> | no | Device name shown on the dashboard Pairing page. |
--device-type <STRING> | no | Device type label. Default: cli. |
--hardware <STRING> | no | Hardware / platform label, e.g. Pixel 8 / Android. |
--json | no | Print machine-readable JSON instead of human text. |
Under the hood this posts the code to the gateway and returns the bearer token:
POST /api/pairContent-Type: application/json
{ "code": "123456", "device_name": "Field phone", "device_type": "mobile", "hardware": "Pixel 8 / Android"}{ "token": "<bearer-token>", "persisted": true, "message": "Pairing successful"}For the dashboard-side flow, QR-based device pairing, and device revocation, see Pairing & authentication and Secrets, pairing & device auth.
Bind restrictions
Section titled “Bind restrictions”The gateway can bind to 127.0.0.1 (localhost only — the default), 0.0.0.0 (all IPv4 interfaces), or [::] (all IPv6 interfaces). Binding to any non-loopback address without allow_public_bind = true (and no active tunnel) logs a warning but still binds. This is a deliberate safety default — 0.0.0.0 exposes the gateway to every connected network.
[gateway]host = "0.0.0.0"port = 42617allow_public_bind = truerevka daemon --host 127.0.0.1 # localhost only (default)revka daemon --host 0.0.0.0 # LAN access — needs allow_public_bind = true| Key | Type | Default | Meaning |
|---|---|---|---|
gateway.host | string | 127.0.0.1 | Bind address. Inside Docker containers the default is [::]. |
gateway.port | integer | 42617 | Listen port. 0 binds a random available port. |
gateway.allow_public_bind | boolean | false | Must be true to bind any non-loopback address. |
Both keys have environment overrides for containers and CI: REVKA_GATEWAY_HOST / HOST, REVKA_GATEWAY_PORT / PORT, and REVKA_ALLOW_PUBLIC_BIND.
REVKA_ALLOW_PUBLIC_BIND=true revka gateway start --host 0.0.0.0OS Service Management
Section titled “OS Service Management”revka service runs revka daemon as a persistent, OS-managed background service so it starts automatically and is restarted on failure. The init system is auto-detected per platform:
- macOS — a launchd agent at
~/Library/LaunchAgents/com.revka.daemon.plist(RunAtLoadandKeepAliveenabled). - Linux — a systemd user unit at
~/.config/systemd/user/revka.service(no root required), or an OpenRC init script at/etc/init.d/revka. - Windows — a Scheduled Task named
Revka Daemonthat runs at logon, with a direct background-spawn fallback if the scheduler is unavailable.
Commands
Section titled “Commands”revka service installrevka service startrevka service stoprevka service restartrevka service statusrevka service logs -n 100 --followrevka service logsrevka service uninstall
# Override the init system (Linux only)revka service --service-init systemd installrevka service --service-init openrc install| Subcommand | Purpose |
|---|---|
install | Generate and register the service unit / plist / scheduled task. |
start | Start the service. Rotates daemon logs first if they exceed 20 MB. |
stop | Stop the running service. |
restart | Stop then start. |
status | Report whether the daemon is running. Also checks the 45-second-fresh daemon state file as a fallback. |
logs | Tail the daemon logs. -n / --lines <N> sets the line count (default 50); -f / --follow streams new output like tail -f. |
uninstall | Remove the service unit / plist / scheduled task. |
| Flag | Values | Default | Meaning |
|---|---|---|---|
--service-init | auto, systemd, openrc | auto | Force a specific init system on Linux. Applies to all subcommands. |
--service-init
Section titled “--service-init”revka service auto-detects the right init system, but on Linux you can force one with --service-init. Pass it before the subcommand:
auto(default) — detect systemd, OpenRC, launchd, or Windows Task Scheduler automatically.systemd— install a systemd user unit. Runssystemctl --user enable revka.serviceso it starts on login. For start-on-boot without an active session, enable lingering withloginctl enable-linger $USER.openrc— install an OpenRC init script. System-wide and root-only; see the Linux tab below.
Per-platform notes
Section titled “Per-platform notes”The launchd agent runs revka daemon with RunAtLoad and KeepAlive. Homebrew installs are detected automatically: the service then uses <brew_prefix>/var/revka/logs/ for logs and carries REVKA_CONFIG_DIR as an environment key in the plist, so config and workspace data survive brew upgrade. The plist raises the file-descriptor limit (SoftResourceLimits/HardResourceLimits for NumberOfFiles, 4096 soft / 8192 hard) to avoid “Too many open files” when many MCP servers run at once.
brew services start revka uses the same plist.
revka service installrevka service startThe systemd user unit runs revka daemon with Restart=always and RestartSec=3, sets LimitNOFILE=4096:8192, injects a curated PATH (covering ~/.cargo/bin, ~/.local/bin, /opt/homebrew/bin, plus the install-time PATH), passes DISPLAY and XDG_RUNTIME_DIR for headless browser support, and orders after network.target. No root is required.
revka service installrevka service startloginctl enable-linger $USER # optional: start on boot without an active loginOpenRC is system-wide and requires root. Installation creates /etc/init.d/revka, creates a revka:revka system user (UID < 1000, shell /sbin/nologin), sets ownership on /etc/revka/, /var/lib/revka/, and /var/log/revka/, and migrates an existing ~/.revka config into /etc/revka on first install.
sudo revka service install # auto-detects OpenRC on Alpinesudo rc-update add revka defaultsudo rc-service revka startA pre-existing revka user with UID ≥ 1000 or a non-nologin shell causes a clear error with remediation steps.
revka service install registers a Scheduled Task named Revka Daemon via schtasks /SC ONLOGON that launches the daemon at user logon — no elevation required. A .cmd wrapper with a snapshotted PATH is placed in the config logs directory. If the Task Scheduler is unavailable, Revka falls back to a direct background spawn and prints instructions to run revka service install later.
revka service installrevka service startrevka service statusrevka service logs --followrevka service uninstallLogs are written to <config_dir>/logs/daemon.stdout.log and daemon.stderr.log; revka service logs --follow uses PowerShell Get-Content -Wait.
Log rotation
Section titled “Log rotation”Before revka service start, daemon logs are rotated if they exceed 20 MB. Up to 5 rotated copies are kept (daemon.stdout.log.1 through .5); the oldest is deleted before renaming. Logs live in the Homebrew var/revka/logs/ directory or <config_dir>/logs/.
Quick start: install and run as a service
Section titled “Quick start: install and run as a service”-
Install the service. The init system is auto-detected.
Terminal window revka service install -
Start it.
Terminal window revka service start -
Confirm it is healthy. Check the service state and the public health endpoint.
Terminal window revka service statuscurl http://127.0.0.1:42617/health -
Pair a client. Read the pairing code and exchange it for a token.
Terminal window revka gateway get-paircoderevka pair token --code 123456
Verifying and troubleshooting
Section titled “Verifying and troubleshooting”- Liveness.
GET /healthreturns200with pairing status and a component snapshot and needs no auth — ideal for load balancers.revka status --format exit-codeexits0when healthy and1otherwise (the canonical DockerHEALTHCHECK). Runrevka doctorfor structured diagnostics. - Service won’t start (Windows).
revka service statusalso consults the daemon state file; a state file fresher than 45 seconds means a daemon is already running. - Restart loops in the logs. A component keeps failing and the supervisor keeps restarting it with growing backoff. Check the recorded last error and tune
reliability.channel_max_backoff_secs. - Can’t reach the gateway from another machine. The default bind is loopback-only. Set
allow_public_bind = trueor front it with a tunnel. - Pairing input rejects your code. Codes are single-use. Rotate with
revka gateway get-paircode --newand try again.