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.
What Keeper does
Section titled “What Keeper does”- 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.
Listeners and ports
Section titled “Listeners and ports”Keeper brings up several independent listeners:
| Port | Listener | Protocol | Purpose |
|---|---|---|---|
8080 | Operator API | HTTP / OpenAPI | the primary operator interface, /readyz health check, /docs spec viewer, /ui built-in web UI |
8081 | MCP | HTTP | interface for MCP clients (optional listener) |
9090 | metrics | HTTP | Prometheus scrape (/metrics) |
9442 | gRPC bootstrap | server-only TLS | agent onboarding (soul init): exchanges token + CSR for an mTLS identity |
8443 | gRPC EventStream | mTLS | long-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.
HA and scaling
Section titled “HA and scaling”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 primary operator interface
Section titled “The primary operator interface”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.
Installation and startup
Section titled “Installation and startup”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.