Configuration Management Tutorial#

This tutorial covers managing scafctl’s application configuration using the config CLI commands.

Overview#

scafctl uses a YAML configuration file to control application behavior including logging, HTTP client settings, resolver timeouts, catalog locations, and more.

CommandDescription
config initCreate config file
config viewView current config
config get/setRead/write values
config validateValidate config
config schemaView JSON schema
config pathsShow XDG paths

Quick Start#

1. Initialize Configuration#

Create a new config file:

# Create minimal config
scafctl config init

# Create with all options documented
scafctl config init --full

# Preview without writing
scafctl config init --dry-run

# Write to custom path
scafctl config init --output ./my-config.yaml
# Create minimal config
scafctl config init

# Create with all options documented
scafctl config init --full

# Preview without writing
scafctl config init --dry-run

# Write to custom path
scafctl config init --output ./my-config.yaml

2. View Configuration#

See the current effective configuration:

# Full config (YAML format)
scafctl config view

# As JSON
scafctl config view -o json

# Filter with CEL expression
scafctl config view -e '_.settings'

# Interactive TUI explorer
scafctl config view -i
# Full config (YAML format)
scafctl config view

# As JSON
scafctl config view -o json

# Filter with CEL expression
scafctl config view -e '_.settings'

# Interactive TUI explorer
scafctl config view -i

3. Show Config Sources#

See where each value comes from (file, environment, default):

scafctl config show
scafctl config show

Getting and Setting Values#

Read Values#

Use dot notation to read specific config values:

# Get logging level
scafctl config get logging.level

# Get default catalog
scafctl config get settings.defaultCatalog

# Get HTTP timeout
scafctl config get httpClient.timeout
# Get logging level
scafctl config get logging.level

# Get default catalog
scafctl config get settings.defaultCatalog

# Get HTTP timeout
scafctl config get httpClient.timeout

Write Values#

# Set logging level
scafctl config set logging.level debug

# Set HTTP timeout
scafctl config set httpClient.timeout 60s

# Set resolver concurrency
scafctl config set resolver.concurrency 8

# Enable a boolean
scafctl config set httpClient.caching.enabled true
# Set logging level
scafctl config set logging.level debug

# Set HTTP timeout
scafctl config set httpClient.timeout 60s

# Set resolver concurrency
scafctl config set resolver.concurrency 8

# Enable a boolean
scafctl config set httpClient.caching.enabled true

Reset to Default#

# Reset a value to its default
scafctl config unset logging.level

# Reset HTTP configuration
scafctl config unset httpClient.timeout
# Reset a value to its default
scafctl config unset logging.level

# Reset HTTP configuration
scafctl config unset httpClient.timeout

Managing Catalogs#

Add a Catalog#

# Add a local filesystem catalog
scafctl catalog remote add my-catalog --type filesystem --path ~/my-solutions

# Add an OCI registry catalog
scafctl catalog remote add company --type oci --url oci://ghcr.io/myorg/scafctl-catalog

# Add and set as default
scafctl catalog remote add primary --type filesystem --path ~/catalogs/main --default

# Add with auth provider for automatic token injection
scafctl catalog remote add corp --type oci --url oci://registry.example.com/artifacts --auth-provider github
# Add a local filesystem catalog
scafctl catalog remote add my-catalog --type filesystem --path ~/my-solutions

# Add an OCI registry catalog
scafctl catalog remote add company --type oci --url oci://ghcr.io/myorg/scafctl-catalog

# Add and set as default
scafctl catalog remote add primary --type filesystem --path ~/catalogs/main --default

# Add with auth provider for automatic token injection
scafctl catalog remote add corp --type oci --url oci://registry.example.com/artifacts --auth-provider github

Remove a Catalog#

scafctl catalog remote remove my-catalog
scafctl catalog remote remove my-catalog

Set Default Catalog#

scafctl catalog remote default my-catalog
scafctl catalog remote default my-catalog

Validation#

Validate Config File#

# Validate current config
scafctl config validate

# Validate a specific file
scafctl config validate path/to/config.yaml
# Validate current config
scafctl config validate

# Validate a specific file
scafctl config validate path/to/config.yaml

View Config Schema#

# Pretty-printed JSON Schema
scafctl config schema

# Minified (for piping)
scafctl config schema --compact
# Pretty-printed JSON Schema
scafctl config schema

# Minified (for piping)
scafctl config schema --compact

View System Paths#

See where scafctl stores files on your system:

# Show all XDG paths
scafctl config paths

# As JSON
scafctl config paths -o json

# Show paths for a different platform
scafctl config paths --platform linux
# Show all XDG paths
scafctl config paths

# As JSON
scafctl config paths -o json

# Show paths for a different platform
scafctl config paths --platform linux

Typical output:

 💡 scafctl Paths
Platform: darwin/arm64
Config:      ~/.config/scafctl/config.yaml
Secrets:     ~/.local/share/scafctl/secrets
Data:        ~/.local/share/scafctl
Catalog:     ~/.local/share/scafctl/catalog
Cache:       ~/.cache/scafctl
HTTP Cache:  ~/.cache/scafctl/http-cache
State:       ~/.local/state/scafctl
Override paths with XDG environment variables or SCAFCTL_SECRETS_DIR.

 💡 Config sources (merge order)

  1. built-in defaults
  2. ~/.config/scafctl/config.d/10-telemetry.yaml
  3. ~/.config/scafctl/config.d/50-clusters.yaml
  4. ~/.config/scafctl/config.yaml
  5. SCAFCTL_* environment variables

Later sources override earlier ones.

The Config sources section lists every layer that feeds the merged configuration, in the order they are applied. Later sources override earlier ones, so a value in config.d/50-clusters.yaml wins over one in 10-telemetry.yaml, and your config.yaml wins over both. This makes the config.d/ drop-in directory discoverable – otherwise it is easy to miss where a value like kube.clusters is actually set. A missing user config file is shown as (not present).

Configuration Reference#

Key Settings#

KeyTypeDefaultDescription
logging.levelstringnoneLog level: none, error, warn, info, debug, trace, or numeric V-level
logging.formatstringconsoleLog format: console (colored), json (structured)
settings.defaultCatalogstringlocalDefault catalog name
httpClient.timeoutduration30sHTTP request timeout
httpClient.retry.maxRetriesint3Max HTTP retries
httpClient.caching.enabledbooltrueEnable HTTP response caching
httpClient.maxResponseBodySizeint104857600Max HTTP response body size (bytes, default 100 MB)
httpClient.allowPrivateIPsboolfalseAllow requests to private/loopback IPs (SSRF protection)
settings.requireSecureKeyringboolfalseFail if OS keyring unavailable instead of insecure fallback
resolver.timeoutduration5mOverall resolver timeout
resolver.concurrencyint4Max parallel resolver execution
action.timeoutduration10mOverall action timeout
action.concurrencyint4Max parallel action execution
plugins.grpcMaxMessageSizeint67108864Max gRPC message size in bytes for plugin communication (64 MB default). Increase for very large provider inputs/outputs
plugins.fetchCooldownduration5mCooldown between failed plugin auto-fetch retries
settings.disableOfficialAuthHandlersboolfalseDisable auto-resolution of the official auth handlers (entra, github, gcp)
settings.disableThirdPartyAuthHandlersboolfalseDisable catalog-by-name resolution of non-official auth handlers (official-only policy)
auth.entra.*objectEntra (Azure AD) auth handler config
auth.github.hostnamestringgithub.comGitHub hostname (or GHES hostname)
auth.github.clientIdstringbuilt-inOAuth App client ID
auth.github.defaultScopes[]string[gist, read:org, repo, workflow]Default OAuth scopes
auth.handlers.<name>.plugin.refstringhandler nameCatalog artifact name for a pinned third-party auth handler
auth.handlers.<name>.plugin.versionstringlatestVersion constraint for a pinned third-party auth handler
auth.handlers.<name>.trustedVerificationDomains[]stringPer-handler trusted device-code verification domains (required trust source for third-party handlers)

Config File Location#

The config file is located at the XDG config path:

PlatformDefault Location
macOS~/.config/scafctl/config.yaml
Linux~/.config/scafctl/config.yaml
Windows%APPDATA%\scafctl\config.yaml

Override with the --config flag on any command:

scafctl run solution my-solution --config ./custom-config.yaml
scafctl run solution my-solution --config ./custom-config.yaml

Examples#

Minimal Config#

See examples/config/minimal-config.yaml :

version: 1
settings:
  defaultCatalog: "local"
logging:
  level: "none"
catalogs:
  - name: local
    type: filesystem
    path: ~/scafctl-catalog/

Full Config#

See examples/config/full-config.yaml for a complete reference with all options documented.

Common Workflows#

Initial Setup#

# 1. Initialize config
scafctl config init

# 2. Set up a catalog
scafctl catalog remote add local --type filesystem --path ~/scafctl-catalog --default

# 3. Verify
scafctl config view
scafctl config validate
# 1. Initialize config
scafctl config init

# 2. Set up a catalog
scafctl catalog remote add local --type filesystem --path ~/scafctl-catalog --default

# 3. Verify
scafctl config view
scafctl config validate

Switch Environments#

# Use staging catalog
scafctl catalog remote default staging

# Increase logging for debugging
scafctl config set logging.level debug

# After debugging, reset
scafctl config unset logging.level
# Use staging catalog
scafctl catalog remote default staging

# Increase logging for debugging
scafctl config set logging.level debug

# After debugging, reset
scafctl config unset logging.level

API Server: Token Delegation#

The apiServer section includes configuration for token delegation when running in API mode (scafctl serve). These settings control how the server exchanges or forwards tokens to downstream providers.

Server Identity (Entra ID)#

Configure the server’s identity for OBO and client credentials flows:

# Set up Entra identity for token delegation
scafctl config set apiServer.identity.entra.tenantId "your-tenant-id"
scafctl config set apiServer.identity.entra.clientId "your-client-id"
scafctl config set apiServer.identity.entra.credential.type "secret"
scafctl config set apiServer.identity.entra.credential.clientSecret "env://SCAFCTL_API_ENTRA_CLIENT_SECRET"

# Configure allowed delegation flows
scafctl config set apiServer.identity.entra.allowedFlows.flows '["obo", "client_credentials"]'

# View the identity config
scafctl config get apiServer.identity
# Set up Entra identity for token delegation
scafctl config set apiServer.identity.entra.tenantId "your-tenant-id"
scafctl config set apiServer.identity.entra.clientId "your-client-id"
scafctl config set apiServer.identity.entra.credential.type "secret"
scafctl config set apiServer.identity.entra.credential.clientSecret "env://SCAFCTL_API_ENTRA_CLIENT_SECRET"

# Configure allowed delegation flows
scafctl config set apiServer.identity.entra.allowedFlows.flows '["obo", "client_credentials"]'

# View the identity config
scafctl config get apiServer.identity

The credential clientSecret field uses SecretRef URI format:

  • env://VAR_NAME – reads from an environment variable
  • file:///path/to/secret – reads from a file

Token Pass-Through#

Configure which provider-specific tokens can be forwarded from API request headers:

# Allow GitHub and Artifactory tokens to be passed through
scafctl config set apiServer.tokenPassThrough.allowedHeaders '["Github", "Artifactory"]'

# View the token pass-through config
scafctl config get apiServer.tokenPassThrough
# Allow GitHub and Artifactory tokens to be passed through
scafctl config set apiServer.tokenPassThrough.allowedHeaders '["Github", "Artifactory"]'

# View the token pass-through config
scafctl config get apiServer.tokenPassThrough

When configured, callers send tokens via X-Authorization-<Suffix> headers (e.g., X-Authorization-Github). The server makes these available to providers via the authProvider input field. When tokenPassThrough is omitted entirely, only Github is allowed by default.

For a complete guide, see the Token Delegation Tutorial .

Next Steps#