ConceptsConfiguration

Configuration

The Gestalt config file is the platform’s control plane. gestaltd does not have a large imperative setup process; instead, it reads one YAML document and derives the running system from it.

Config Discovery

When you do not pass --config, gestaltd resolves the config path in this order:

  1. GESTALT_CONFIG
  2. ./config.yaml
  3. ~/.gestalt/config.yaml
  4. /etc/gestalt/config.yaml

The default command gestaltd has one extra behavior: if no config exists anywhere in that search path, it generates ~/.gestalt/config.yaml and starts with a local-only configuration that uses auth.provider: none and SQLite.

What Happens During Load

Loading a config is more than YAML parsing:

  1. ${ENV_VAR} placeholders are expanded first.
  2. YAML is decoded with known-field checking.
  3. Defaults are applied.
  4. Connection auth is validated against surface references.
  5. Relative paths are resolved against the directory that contains the config file.
  6. Validation runs.
  7. During bootstrap, secret://... values are resolved through the configured secret manager.

secret://... resolution is intentionally later than basic config parsing. That keeps the config loader simple and lets the secret manager itself be configured normally.

The Top-Level Feature Sets

This is the complete top-level shape of the config:

auth: {}
datastore: {}
secrets: {}
telemetry: {}
providers: {}
bindings: {}
server: {}
egress: {}
ui: {}

Each block controls a distinct part of the runtime:

BlockWhat it defines
serverPort, base URL, encryption key, and API token TTL.
authHow users authenticate to Gestalt itself.
datastoreWhere Gestalt stores users, tokens, and related runtime state.
secretsHow secret://... values are resolved.
telemetryObservability: traces, metrics, and structured logs.
providersThe provider graph users call.
bindingsAdditional inbound surfaces.
egressOutbound allow or deny policy plus credential grants.
uiOptional custom web UI plugin.

Defaults And Required Fields

The loader applies a small number of defaults:

  • server.port defaults to 8080
  • secrets.provider defaults to env
  • telemetry.provider defaults to stdout

Some fields are effectively mandatory:

  • auth.provider
  • datastore.provider
  • server.encryption_key

server.encryption_key is the root secret for the deployment. Gestalt derives other cryptographic material from it, including session-related secrets for some auth providers.

Prepared State: init, validate, And serve --locked

Gestalt supports both mutable startup and deterministic startup.

Mutable Startup

gestaltd or gestaltd serve without --locked may mutate local state at startup:

  • remote REST or GraphQL API sources can be fetched and compiled
  • packaged plugins can be prepared locally
  • missing or stale lock state can be regenerated

This is convenient for development.

Deterministic Startup

gestaltd init --config PATH resolves remote dependencies and writes lock state next to the config:

  • gestalt.lock.json
  • .gestalt/providers/*.json
  • .gestalt/plugins/...

After that, gestaltd serve --locked --config PATH starts only if the prepared state exactly matches the config.

Validation

gestaltd validate --config PATH is non-mutating and expects existing lock state. Init first, then validate:

gestaltd init --config ./config.yaml
gestaltd validate --config ./config.yaml

Relative Paths

Paths in config are resolved relative to the config file directory, not the process working directory. This matters for:

  • providers.<name>.icon_file
  • providers.<name>.from.command
  • local providers.<name>.from.package paths

That makes configs portable across local runs, Docker mounts, and Kubernetes volumes.

The Smallest Explicit Config

server:
  port: 8080
  base_url: http://localhost:8080
  encryption_key: change-me
 
auth:
  provider: none
 
datastore:
  provider: sqlite
  config:
    path: ./gestalt.db
 
providers: {}

That is enough to boot a real server. Everything else is additive.