Skip to content

Keeper

The central server of Soul Stack. A stateless cluster over shared PostgreSQL and Redis; it scales horizontally — adding an instance requires no state replication between them.

  • Holds the registries — of managed hosts (souls), operators (operators), and the service catalog. The authoritative state lives in PostgreSQL.
  • Renders Destiny on its side. Templating (CEL for YAML expressions + Go text/template for files) runs on Keeper; the agent receives an already-rendered set of tasks. The agent carries no templating engine, no Vault client, and no resolution logic — which keeps the host simpler and safer.
  • Dispatches runs. Decides which tasks to apply on which hosts (targeting by covens and predicates), delivers them, and collects the reports.
  • Enforces RBAC and audit. Every Operator API call goes through an operator permission check and is written to the audit log.
  • Background subsystems — for example, cleaning expired records out of the registry and reconciling presence against the actual live streams.

Keeper brings up several independent listeners:

PortListenerProtocolPurpose
8080Operator APIHTTP / OpenAPIthe primary operator interface, /readyz health check, /docs spec viewer, /ui built-in web UI
8081MCPHTTPinterface for MCP clients (optional listener)
9090metricsHTTPPrometheus scrape (/metrics)
9442gRPC bootstrapserver-only TLSagent onboarding (soul init): exchanges token + CSR for an mTLS identity
8443gRPC EventStreammTLSlong-lived bidi stream to the agent (soul run): task delivery, reports

Agents initiate the connection to Keeper themselves — no inbound ports need to be opened on managed hosts.

Keeper instances are stateless: all authoritative state lives in the shared PostgreSQL, presence and coordination in the shared Redis. As a result:

  • several Keeper instances run behind an L4 load balancer (a TCP check of the EventStream port is enough for the probe);
  • any instance serves any operator request and any agent stream;
  • horizontal scaling is simply adding instances against the same PostgreSQL + Redis.

Each instance in the cluster has its own identifier (kid in the config), unique within the cluster.

The main way to work with Keeper is the Operator API (HTTP/OpenAPI) and MCP. The soulctl CLI is a thin wrapper over the same endpoints. Keeper serves the full OpenAPI spec — with search and a “Try It” button — in the browser at GET /docs.

Keeper also serves a built-in operator web UI at GET /ui — it is compiled into the binary and available immediately on startup, with no separate deployment (on the same port 8080). The UI is on by default; it can be turned off with a config toggle without affecting the Operator API. It is a layer over that same Operator API — everything the UI does is also available through the CLI/MCP/OpenAPI.

Keeper is installed from the soul-stack-keeper package, a binary release, or a source build. Bootstrapping the first operator is done with the keeper init admin subcommand. The full procedure (provisioning Vault, TLS material, config, starting under systemd) is in Install from packages.