Getting Started with scafctl#

This guide will help you get up and running with scafctl in under 10 minutes.

What is scafctl?#

scafctl is a CLI tool for declarative configuration and workflow automation. It uses:

  • Resolvers to gather and transform data
  • Actions to perform side effects
  • Providers as the execution primitives for both

Think of it as a way to define “what you want” (data + operations) in YAML, and let scafctl figure out “how to do it” (dependency order, parallelization, error handling).

Installation#

# Build from source
go build -ldflags "-s -w" -o scafctl ./cmd/scafctl/scafctl.go

# Move to PATH
mv scafctl /usr/local/bin/
# Build from source
go build -ldflags "-s -w" -o scafctl ./cmd/scafctl/scafctl.go

# Move to PATH (macOS/Linux)
Move-Item -Force ./scafctl /usr/local/bin/scafctl

Quick Start#

1. Your First Solution#

Create a file called hello.yaml:

apiVersion: scafctl.io/v1
kind: Solution
metadata:
  name: hello-world
  version: 1.0.0

spec:
  resolvers:
    greeting:
      type: string
      resolve:
        with:
          - provider: static
            inputs:
              value: "Hello, World!"

  workflow:
    actions:
      say-hello:
        provider: exec
        inputs:
          command:
            expr: "'echo ' + _.greeting"

Run it:

scafctl run solution -f hello.yaml
scafctl run solution -f hello.yaml

Output:

Hello, World!

This solution has two parts:

  • Resolver (greeting) — gathers a value using the static provider
  • Action (say-hello) — runs a shell command that references the resolver via _.greeting

Want to go deeper with resolvers? The Resolver Tutorial covers parameters, dependencies, transforms, validation, and more.

2. Action Dependencies#

Actions can depend on other actions and access their results. scafctl automatically infers dependencies from __actions references in CEL expressions and Go templates. Create a new file called action-deps.yaml:

apiVersion: scafctl.io/v1
kind: Solution
metadata:
  name: action-deps
  version: 1.0.0

spec:
  workflow:
    actions:
      fetch-data:
        provider: http
        inputs:
          url: https://httpbin.org/get

      process:
        provider: exec
        inputs:
          command:
            expr: "'echo Got status: ' + string(__actions['fetch-data'].results.statusCode)"

Because process references __actions['fetch-data'], scafctl automatically determines that process depends on fetch-data and schedules it to run after fetch-data completes. You can still use dependsOn to declare dependencies that aren’t expressed via __actions references (e.g., ordering actions that don’t consume each other’s results).

Run it:

scafctl run solution -f action-deps.yaml
scafctl run solution -f action-deps.yaml

Output:

Got status: 200

Key Concepts#

Solutions#

A Solution is the top-level unit. It contains:

  • metadata - Name, version, description
  • spec.resolvers - Data gathering/transformation
  • spec.workflow.actions - Side effects to perform
  • spec.workflow.finally - Cleanup actions (always run)

Resolvers#

Resolvers compute values. They:

  • Execute before any actions
  • Form a dependency graph (DAG)
  • Run in parallel when possible
  • Support fallback chains (try providers in order)
resolvers:
  config:
    resolve:
      with:
        - provider: env         # Try environment first
          inputs:
            operation: get
            name: APP_CONFIG
        - provider: file        # Fallback to file
          inputs:
            operation: read
            path: ./config.json
        - provider: static      # Final fallback
          inputs:
            value: "{}"

Actions#

Actions perform work. They:

  • Execute after all resolvers complete
  • Form a dependency graph (DAG)
  • Can access resolver data via _
  • Can access prior action results via __actions

Providers#

Providers are the execution primitives. Common ones:

ProviderUse Case
staticReturn constant values
parameterCLI parameters (-r key=value)
envEnvironment variables
fileRead/write files
httpAPI calls
execShell commands
celExpression evaluation
hclParse Terraform/OpenTofu HCL files
validationData validation
secretEncrypted secrets

See Provider Reference for full documentation.

Common Commands#

# Run a solution from file
scafctl run solution -f solution.yaml

# Run a solution from catalog (by name)
scafctl run solution my-solution

# Build a solution to local catalog
scafctl build solution -f solution.yaml --version 1.0.0

# List cataloged solutions
scafctl catalog list

# Dry-run (show what would happen)
scafctl run solution -f solution.yaml --dry-run

# Render without executing
scafctl render solution -f solution.yaml

# Show resolver dependency graph
scafctl run resolver --graph -f solution.yaml

# List available providers
scafctl get provider

# Get details about a specific provider
scafctl get provider http

# Pass parameters
scafctl run solution -f solution.yaml -r key1=value1 -r key2=value2

# Interactive output exploration
scafctl run resolver -f solution.yaml -i

# JSON/YAML output
scafctl render solution -f solution.yaml -o json

# Scaffold a new solution
scafctl new solution --name my-app --description "My application scaffold" --output my-app.yaml

# Browse and download examples
scafctl examples list
scafctl examples get resolvers/hello-world.yaml -o hello.yaml

# Evaluate a CEL expression
scafctl eval cel --expression '"hello".upperAscii()'

# Validate a solution file
scafctl lint -f solution.yaml

# List lint rules
scafctl lint rules

# Explain a lint rule
scafctl lint explain <rule-id>
# Run a solution from file
scafctl run solution -f solution.yaml

# Run a solution from catalog (by name)
scafctl run solution my-solution

# Build a solution to local catalog
scafctl build solution -f solution.yaml --version 1.0.0

# List cataloged solutions
scafctl catalog list

# Dry-run (show what would happen)
scafctl run solution -f solution.yaml --dry-run

# Render without executing
scafctl render solution -f solution.yaml

# Show resolver dependency graph
scafctl run resolver --graph -f solution.yaml

# List available providers
scafctl get provider

# Get details about a specific provider
scafctl get provider http

# Pass parameters
scafctl run solution -f solution.yaml -r key1=value1 -r key2=value2

# Interactive output exploration
scafctl run resolver -f solution.yaml -i

# JSON/YAML output
scafctl render solution -f solution.yaml -o json

# Scaffold a new solution
scafctl new solution --name my-app --description "My application scaffold" --output my-app.yaml

# Browse and download examples
scafctl examples list
scafctl examples get resolvers/hello-world.yaml -o hello.yaml

# Evaluate a CEL expression
scafctl eval cel --expression '"hello".upperAscii()'

# Validate a solution file
scafctl lint -f solution.yaml

# List lint rules
scafctl lint rules

# Explain a lint rule
scafctl lint explain <rule-id>

Next Steps#