Skip to content

FAQ

Common questions when you’re first getting to know Soul Stack. The answers are short; for details, follow the links to the relevant sections.

So the managed host has no runtime dependencies. The soul agent is a static Go binary: the host needs no Python, Ruby, or any other interpreter. Modules are native Go code compiled into that same binary; custom extensions attach as separate plugin binaries over gRPC, so a plugin’s language doesn’t impose a dependency on the host.

The practical upshot: no interpreter version drift across the souls — there’s nothing to install, reconcile, or upgrade on the hosts. This works on minimal, tightly locked-down images where installing an interpreter is undesirable.

More in Components → Soul.

Yes. Keeper’s required infrastructure baseline is PostgreSQL + Redis + Vault (all three). Keeper checks each one at startup and refuses to start if even one is unavailable (fail-fast). Without Vault, Keeper won’t come up: it underpins the PKI for agents’ mTLS identities and the signing of operator tokens, without which souls and operator authentication cannot work at all.

  • PostgreSQL — the sole cold storage for a Keeper cluster: agent and operator registries, the service catalog, incarnation states, logs.
  • Redis — the heartbeat cache, leases on agent identifiers, coordination between Keeper instances.
  • Vault — PKI for issuing agents’ mTLS identity, signing operator JWTs, and secret storage (the PostgreSQL DSN, the Redis password, Destiny application secrets).

All three are external components that you run and operate yourself; Soul Stack does not bundle them. More in Installation → Overview and Quick Start → What you’ll need.

Both modes are handled by the same soul binary with the same set of modules — there are no separate implementations.

  • Pull (daemon). The agent runs as a systemd service, initiates a long-lived gRPC stream to Keeper over mTLS itself, and applies the tasks that arrive over the stream.
  • Push (one-shot over SSH). No persistent daemon: Keeper delivers the binary and modules to the host over SSH and runs a one-off apply; modules are cached on the host by SHA-256.

Applying a task works the same whether it’s the daemon or a one-shot. More in Components → Soul.

Yes — both are optional on the Keeper side.

  • Web-UI is controlled by the top-level web_ui_enabled toggle (tri-state, default-ON). An explicit web_ui_enabled: false opts out: the /ui static assets aren’t mounted, while /v1/* and /docs are untouched. The UI is compiled into the Keeper binary and needs no separate backend; enabling it opens no new ports (the static assets share the Operator API port). See Configuration → keeper.yml → web_ui_enabled.
  • MCP comes up only if listen.mcp.addr is set. Drop the block or leave addr empty, and the listener doesn’t start — MCP is off. See Configuration → keeper.yml → listen.

Metrics can’t be turned off. listen.metrics.addr is a required listener: Keeper always serves Prometheus /metrics (only protecting the endpoint via the metrics block is optional). On the agent, by contrast, metrics are optional (metrics.enabled) — not every host opens the port. See Configuration → keeper.yml → metrics.

Do I need to open inbound ports on managed hosts?

Section titled “Do I need to open inbound ports on managed hosts?”

No. The agent initiates the stream to Keeper itself — the connection is always outbound, to Keeper’s bootstrap and EventStream ports. The only thing listening externally on the host is the local metrics listener (and even that is optional). You don’t need to open any inbound ports for management. See Components → Soul → Host requirements and Security → Transport.

An incarnation’s state (the runtime instance of a service) is versioned by the state_schema_version field. Moving to a new schema version is an explicit operator action through the Operator API, not a lazy auto-upgrade:

  • the operator initiates the incarnation upgrade to the target version;
  • the migration chain is applied atomically, in a single PostgreSQL transaction — the state either moves fully to the new version or stays as it was on error;
  • before the change, a snapshot of the previous state is saved to history (migrations are forward-only; there is no reverse migration — the rollback path goes through history).

The DSL grammar, the migrations/ layout, and tests are in DSL → State migrations. The operational side of the upgrade is in Operations → Incarnation upgrade.

How is Soul Stack different from traditional tools?

Section titled “How is Soul Stack different from traditional tools?”

In short: no runtime on the host (a single static Go binary instead of an interpreter), a type-safe template engine (CEL + Go text/template instead of a general-purpose text templating engine), a stateless Keeper cluster that scales horizontally over shared PostgreSQL/Redis (instead of a stateful master), mTLS / RBAC / audit / Vault built into the core, and a single pull + push model with one set of modules.

Yes, thanks to two rules.

  • Resolution on the Keeper side. Secrets are pulled from Vault on Keeper at the moment a Destiny is rendered — before tasks leave for the host. The agent carries no Vault client, there are no Vault tokens on the host, and secrets are never written to the cluster’s disk.
  • Masking on the way out. Secret values are masked at every boundary where data leaves the system — logs, OpenTelemetry traces, UI and API responses, run reports. A secret never leaves in cleartext.

More in Security → Secrets.