Skip to content

How Revka works

Conceptual overview of the runtime, gateway, channels, operator, memory, and security layers and how they fit together.

Revka is a Rust-first, audit-first agent runtime that ships as a single binary (revka). That binary embeds a REST + WebSocket gateway, a React dashboard, a cron scheduler, a channel supervisor, and the CLI — and it coordinates two Python MCP sidecars (Kumiho memory and the Operator) plus optional cloud agents. This page explains the layers, what runs where, and how a message becomes an agent turn.

Read this once before you wire up channels, providers, or workflows — it gives you the mental model the rest of the docs assume. If you just want to get running, start with Installation and the Quickstart, then come back here.

Revka is layered. Each layer has a narrow job and a clear boundary with the layers around it.

Gateway runtime

The Axum HTTP server. Hosts the REST API, WebSocket and SSE transports, the embedded dashboard, webhook ingress, and an in-process MCP server. Default bind is http://127.0.0.1:42617.

Channel supervisor

Connects the agent to messaging platforms (Telegram, Discord, Slack, Matrix, and more). Runs inside the daemon alongside the gateway, heartbeat, and cron.

Operator + Kumiho sidecars

Two Python MCP servers. The Operator orchestrates sub-agents, teams, and workflows; Kumiho is the persistent graph-memory backend.

Security policy

A defence-in-depth model — autonomy levels, command allowlists, path sandboxing, OTP gating, emergency stop, and a tamper-evident audit log — evaluated before any tool runs.

Everything starts from the single binary. You build or download revka, run a command (revka gateway, revka daemon, or revka agent), and the binary brings up the layers that command needs.

These three commands all start the runtime, but they bring up different combinations of components. Pick the one that matches what you are doing.

CommandWhat it runsUse it when
revka gatewayThe HTTP gateway only: REST API, dashboard, WebSocket, SSE. No channels.You want the dashboard and API but no messaging integrations.
revka daemonThe gateway plus all configured channels, the heartbeat, and the cron scheduler.You are running Revka as a full, always-on agent.
revka serviceInstalls and manages the daemon as an OS service (launchd, systemd, or OpenRC).You want Revka to survive reboots and run unattended.
Terminal window
# Gateway only — dashboard + API at http://127.0.0.1:42617
revka gateway
# Full runtime — gateway + channels + heartbeat + cron
revka daemon
# Run as a managed background service
revka service install && revka service start
revka service status
revka service logs --follow

The gateway binds to 127.0.0.1:42617 by default. Override with --host and --port. On first start with pairing enabled, the gateway prints a one-time pairing code; a client exchanges it for a bearer token via POST /pair. See Pairing & authentication for the full flow.

A few endpoints are always available without a bearer token, by design:

  • GET /health — public liveness for load balancers (no secrets leaked).
  • GET /metrics — Prometheus text format, only when [observability] backend = "prometheus".
  • POST /webhook — generic agent ingress (optionally secured with X-Webhook-Secret).
  • POST /admin/shutdown, GET|POST /admin/paircode — localhost-only admin endpoints (remote callers get 403).

A runtime adapter is the layer that decides how an agent actually executes on the host. The same agent definition can run in different modes depending on your deployment and resource constraints — foreground process, gateway-only, managed service, or container. The mode you choose maps directly onto the gateway / daemon / service commands above.

ModeHow to run it
Foreground runtimerevka daemon
Gateway onlyrevka gateway
Managed servicerevka service install && revka service start
Docker / Composedocker compose up -d

For the full treatment of runtime modes, adapter selection, and resource limits, see Runtime modes, adapters & resource limits and Docker, Compose & one-click PaaS.

Revka keeps the orchestration brain and the memory backend out of the Rust binary and runs them as two Python MCP sidecars. The Rust daemon launches and supervises both over stdio, and exposes their tools to agents through the Model Context Protocol.

The Operator is a Python 3.11+ MCP server, spawned fresh per agent chat session by the daemon. It gives the agent tools for spawning and coordinating sub-agents, running declarative YAML workflows, managing teams, recording outcomes, and talking to other agents over the A2A protocol. Operator code can change without restarting the daemon.

The Operator pairs with a Node.js Session Manager sidecar that manages agent SDK sessions (Claude SDK and Codex) and relays live agent events to the gateway’s WebSocket channel — this is what drives the dashboard’s live workflow view. Without the Session Manager, orchestration still works but the live execution overlay receives no events.

[operator]
mcp_path = "~/.revka/operator_mcp/run_operator_mcp.py"

See Operator MCP, Spawning & coordinating agents, and the Workflows overview.

Revka does not persist memory locally. At the Rust level the memory binding is always a no-op (NoneMemory); all persistence is delegated to the Kumiho MCP sidecar, a client stub that talks to the Kumiho graph-memory control plane. Setting backend = "kumiho" or backend = "none" both resolve to that no-op binding — any other backend name (sqlite, qdrant, …) is rejected at startup.

[memory]
backend = "kumiho" # or "none"; both run NoneMemory locally
[kumiho]
enabled = true
mcp_path = "~/.revka/kumiho/run_kumiho_mcp.py"
api_url = "https://api.kumiho.cloud"
space_prefix = "Revka"
memory_project = "CognitiveMemory"

Agents use a two-reflex pattern: call kumiho_memory_engage before responding to load relevant context, and kumiho_memory_reflect after responding to store structured captures (decisions, facts, preferences, and so on) with provenance edges. Memories are stored as items in hierarchical spaces, each with immutable revisions.

Learn more in the Memory overview, Kumiho setup, and Graph model: spaces, items & provenance.

The channel supervisor runs inside revka daemon. It connects the agent to messaging platforms and routes inbound messages into the agent loop and agent replies back out. Channels fall into two delivery classes:

  • Polling channels (Telegram, Discord, Nostr, …) need no public port — they poll or hold a long-lived connection outward.
  • Webhook channels (WhatsApp, Nextcloud Talk, generic /webhook, …) require a public HTTPS endpoint so the platform can POST to your gateway.
Terminal window
revka channel list # show configured channels and status
revka channel start # start the channel supervisor
revka channel doctor # diagnose channel configuration

Allowlist semantics are consistent across channels: an empty allowlist denies everyone, "*" allows everyone, and an explicit list allows only the named users. Inbound messages pass through prompt-injection scanning before they reach the LLM, and outbound messages pass through credential-leak detection before delivery.

See the Channels overview and Connect a messaging channel.

When a message arrives — from a channel, the dashboard chat, the /webhook endpoint, a cron job, or revka agent — Revka runs it through a tool-using agent loop:

  1. Ingress. The message enters via a channel, WebSocket (/ws/chat), SSE, a webhook, or the CLI. Inbound text is scanned for prompt injection.

  2. Engage memory. The agent calls kumiho_memory_engage to pull relevant prior context from the Kumiho graph and inject it into the prompt.

  3. Reason and call tools. The LLM reasons and issues tool calls. Every tool call is checked against the security policy before it executes.

  4. Iterate. Tool results feed back into the loop until the task is done or a limit (max_tool_iterations, default 60) is reached. Tools can run in parallel when [agent] parallel_tools = true.

  5. Reflect. The agent calls kumiho_memory_reflect to persist decisions and facts as captures with provenance edges.

  6. Respond. The reply streams back to the originating surface. Outbound text is scanned for credential leaks; the turn is recorded to the audit log.

Key knobs live in [agent] in ~/.revka/config.toml:

KeyDefaultMeaning
max_tool_iterations60Max tool-call rounds per turn
max_history_messages1000Conversation history retained
max_context_tokens1050000Context window budget
parallel_toolstrueAllow concurrent tool calls

For a deeper walkthrough, see The agent loop, Autonomy levels & approvals, and Sessions & conversation state.

Security is enforced in independent layers, each evaluated before a tool is allowed to act. No single bypass defeats the model.

Autonomy level

read_only, supervised (default), or full. Controls whether the agent can act at all, and whether risky commands need approval.

Command allowlist

A quote-aware shell parser splits compound commands and validates each segment, blocking chaining, subshells, redirections, and risk-classified commands.

Path sandboxing

File operations are pinned to the workspace and allowed_roots, with traversal, symlink-escape, and forbidden-path checks.

OTP & emergency stop

TOTP gates sensitive actions; revka estop freezes tools, kills network, or blocks domains instantly, with OTP-gated resume.

Beyond these, Revka encrypts secrets at rest (ChaCha20-Poly1305), hashes pairing tokens (SHA-256), supports optional OS-level sandbox backends (Firejail, Bubblewrap, Landlock, sandbox-exec, Docker), and applies per-domain trust scoring that automatically downgrades autonomy when an agent keeps making mistakes in a domain.

Every security-relevant event is appended to a tamper-evident audit log — a SHA-256 Merkle hash chain, optionally HMAC-signed. You can query and verify it:

Terminal window
# Query recent audit events
curl "http://127.0.0.1:42617/api/audit?limit=50&event_type=command_execution" \
-H "Authorization: Bearer rk_<token>"
# Verify chain integrity (detects tampering)
curl "http://127.0.0.1:42617/api/audit/verify" \
-H "Authorization: Bearer rk_<token>"
[autonomy]
level = "supervised" # read_only | supervised | full
block_high_risk_commands = true
require_approval_for_medium_risk = true
workspace_only = true
[audit]
enabled = true # tamper-evident Merkle hash chain

Dig into the details in the Security model, Policy, commands & sandboxing, OTP gating & emergency stop, and the Audit log.