Skip to content

Configuration

Soul Stack is configured by two typed YAML files:

  • keeper.yml — the config for one instance of a Keeper cluster (listeners, PostgreSQL/Redis/Vault, operator authentication, observability, background subsystems). Full reference — keeper.yml.
  • soul.yml — the config for the agent on a managed host (identity, Keeper endpoints, TLS, paths, observability). Full reference — soul.yml.

Both files are validated against a typed schema at startup: unknown keys, wrong types, and violated invariants are rejected with a clear error instead of being silently ignored.

Secrets are never written into the config in plaintext. Instead of a value you put a vault: reference, which Keeper resolves through its Vault client at startup:

postgres:
dsn_ref: vault:secret/keeper/postgres # read from Vault, not stored in the file

This is how the PostgreSQL DSN, the Redis password, the operator-token signing key, the host CA for push, and the rest are declared. Plaintext where a vault: ref is expected is rejected by the schema.

The agent (soul.yml) has no vault: refs: soul has no Vault client (a deliberate isolation measure — the agent has no way to read secrets). The few local secrets the agent does need (for example, the password for Basic auth on /metrics) are given as a path to a file with restricted permissions, not as a value in the YAML.

Cross-cutting capabilities need no separate integration — they are built into both binaries and driven by config blocks:

CapabilityKeeperSoulWhere it’s configured
Metrics (Prometheus)mandatory listener (:9090)optional, loopback by defaultlisten.metrics / metrics
OpenTelemetry (traces)push to an OTLP collectorpush to an OTLP collectorotel
Log rotationbuilt-in, no logrotatebuilt-in, no logrotatelogging.rotation
Config hot-reloadSIGHUP + write-back for API mutationsSIGHUP (pull daemon)hot_reload
Vault integrationsecrets + PKI + KV via vault: refs— (no Vault client)vault
RBACcatalog in PostgreSQL, managed through the API(in the DB, not the config)

Details on each capability — in the corresponding sections of keeper.yml and soul.yml.

Not every change applies without a restart. The general principle:

  • Without a restart, parameters of a specific run or background-task iteration change: log level, timeouts, thresholds, limits, plugin policies.
  • A restart is needed for changes to the process’s external surface: listener addresses, TLS certificates, PostgreSQL/Redis DSN, log-file paths.

Full “reload-able / restart-required” tables for each block — in keeper.yml → Hot-reload and soul.yml → Hot-reload.

The soul-stack-keeper and soul-stack-soul packages drop a commented example config next to the binary. A minimal valid config with all required fields is given at the end of each reference: