Run Provider Tutorial#

This tutorial covers the scafctl run provider command — a tool for executing individual providers directly without a solution or resolver file. This is useful for testing, debugging, and exploring providers in isolation.

Prerequisites#

  • scafctl installed and available in your PATH
  • Familiarity with providers

Table of Contents#

  1. Basic Usage
  2. Passing Inputs
  3. File-Based Inputs
  4. Capabilities
  5. Dry Run
  6. Output Formats
  7. Plugin Providers
  8. Discovering Providers
  9. Common Examples

Basic Usage#

The scafctl run provider command takes a provider name as its first argument. Provider inputs can be passed as positional key=value arguments or via the traditional --input flag:

# Positional key=value (recommended)
scafctl run provider <provider-name> <key>=<value>

# Explicit --input flag
scafctl run provider <provider-name> --input <key>=<value>
# Positional key=value (recommended)
scafctl run provider <provider-name> <key>=<value>

# Explicit --input flag
scafctl run provider <provider-name> --input <key>=<value>

Both forms can be mixed freely. When the same key appears multiple times, later values override earlier ones.

Your First Provider Execution#

Run the static provider to return a simple value:

scafctl run provider static value=hello
scafctl run provider static value=hello

Output:

{
  "data": "hello"
}

The output always contains a data field with the provider’s return value. Additional fields like warnings and metadata appear when relevant.


Passing Inputs#

Inputs can be passed as positional key=value arguments or via the --input flag. Both forms can be combined.

Simple Key-Value Pairs#

# Positional key=value (recommended)
scafctl run provider http url=https://httpbin.org/get method=GET

# Explicit --input flag
scafctl run provider http --input url=https://httpbin.org/get --input method=GET
# Positional key=value (recommended)
scafctl run provider http url=https://httpbin.org/get method=GET

# Explicit --input flag
scafctl run provider http --input url=https://httpbin.org/get --input method=GET

Output:

{
  "data": {
    "body": "{...}",
    "headers": {
      "Content-Type": "application/json",
      "...": "..."
    },
    "statusCode": 200
  }
}

Array Values#

Comma-separated values are automatically converted to arrays:

scafctl run provider exec command=echo args=hello,world
scafctl run provider exec shell=pwsh command=Write-Output "args=hello,world"

Values Containing Commas#

If a value itself contains commas (not intended as array separators), wrap it in quotes inside the flag value. Use single quotes around the entire flag to prevent shell interpretation:

scafctl run provider cel 'expression="[1,2,3].map(x, x * 2)"'
scafctl run provider cel 'expression="[1,2,3].map(x, x * 2)"'

Multiple Values for the Same Key#

Repeating the same key creates an array:

scafctl run provider exec command=echo args=hello args=world
scafctl run provider exec shell=pwsh command=Write-Output "args=hello args=world"

File-Based Inputs#

For complex inputs, load them from a YAML or JSON file using the @ prefix:

Create an Input File#

Create inputs.yaml:

url: https://httpbin.org/post
method: POST
body: '{"message": "hello"}'
headers:
  Content-Type: application/json

Run with File Input#

scafctl run provider http --input @inputs.yaml
# Wrap @file in single quotes to avoid splatting operator
scafctl run provider http --input '@inputs.yaml'

Read Inputs from Stdin#

Use @- to pipe inputs from stdin as YAML or JSON:

echo '{"url": "https://api.example.com", "method": "GET"}' | scafctl run provider http --input @-
cat inputs.yaml | scafctl run provider http @-
'{"url": "https://api.example.com", "method": "GET"}' | scafctl run provider http --input '@-'
Get-Content inputs.yaml | scafctl run provider http '@-'

Pipe Raw Content into a Single Input#

Use key=@- to read raw stdin into a specific input key, or key=@file to read a file’s content:

# Pipe raw text into the message input
echo hello | scafctl run provider message message=@-

# Pipe a request body from stdin
cat body.json | scafctl run provider http url=https://api.example.com body=@-

# Read a file's raw content into an input
scafctl run provider message message=@greeting.txt
scafctl run provider http url=https://api.example.com body=@request.json
# Pipe raw text into the message input
'hello' | scafctl run provider message 'message=@-'

# Pipe a request body from stdin
Get-Content body.json | scafctl run provider http 'url=https://api.example.com' 'body=@-'

# Read a file's raw content into an input
scafctl run provider message 'message=@greeting.txt'
scafctl run provider http 'url=https://api.example.com' 'body=@request.json'

Note: A single trailing newline is trimmed automatically. key=@- reads raw text — it does not parse YAML/JSON.

Output:

{
  "data": {
    "body": "{...}",
    "headers": { "...": "..." },
    "statusCode": 200
  }
}

Mix File and Inline Inputs#

File and inline inputs are merged. When the same key appears in both, the values are combined into an array. To override a file value, omit that key from the file:

scafctl run provider http --input @inputs.yaml timeout=30
scafctl run provider http --input '@inputs.yaml' timeout=30

This loads all values from inputs.yaml and adds timeout=30.


Input Key Validation#

When you pass inputs, scafctl validates the input keys against the provider’s schema. Unknown keys are rejected early with a helpful error message. If the key is close to a valid one (a likely typo), a suggestion is included:

# Typo in key name
scafctl run provider http urll=https://example.com
# Error: provider "http" does not accept input "urll" — did you mean "url"? (valid inputs: body, headers, method, timeout, url)

# Completely unknown key
scafctl run provider http unknown=value
# Error: provider "http" does not accept input "unknown" (valid inputs: body, headers, method, timeout, url)
# Typo in key name
scafctl run provider http urll=https://example.com
# Error: provider "http" does not accept input "urll" — did you mean "url"? (valid inputs: body, headers, method, timeout, url)

# Completely unknown key
scafctl run provider http unknown=value
# Error: provider "http" does not accept input "unknown" (valid inputs: body, headers, method, timeout, url)

This validation also applies to resolver and solution parameters:

# Typo in parameter name
scafctl run resolver -f solution.yaml envrionment=prod
# Error: solution does not accept input "envrionment" — did you mean "environment"? (valid inputs: environment, region)
# Typo in parameter name
scafctl run resolver -f solution.yaml envrionment=prod
# Error: solution does not accept input "envrionment" — did you mean "environment"? (valid inputs: environment, region)

Capabilities#

Providers declare capabilities that define what kind of operation they perform:

CapabilityDescription
fromData sourcing (default for most providers)
transformData transformation
validationInput validation
authenticationAuthentication flows
actionSide-effecting operations

By default, scafctl run provider uses the provider’s first declared capability. Use --capability to select a specific one:

# Run a provider with a specific capability
scafctl run provider cel expression="1 + 2" --capability transform
# Run a provider with a specific capability
scafctl run provider cel expression="1 + 2" --capability transform

Viewing Available Capabilities#

Use scafctl get provider <name> to see which capabilities a provider supports:

scafctl get provider cel
scafctl get provider cel

Dry Run#

Use --dry-run to see what would be executed without actually running the provider:

scafctl run provider http url=https://example.com --dry-run
scafctl run provider http url=https://example.com --dry-run

The provider will return simulated output without performing any side effects (no HTTP request, no command execution, etc.).

Provider vs solution dry-run: run provider --dry-run invokes the provider’s Execute() method with a dry-run context flag, so the provider returns mock data. run solution --dry-run is different — it uses the WhatIf model where resolvers run normally and actions are never executed. See Dry-Run & WhatIf design for details.


Output Formats#

The default output format is JSON. Use -o to change it:

# JSON output (default)
scafctl run provider static value=hello -o json

# YAML output
scafctl run provider static value=hello -o yaml

# Table output
scafctl run provider static value=hello -o table

# Quiet mode (exit code only)
scafctl run provider static value=hello -o quiet
# JSON output (default)
scafctl run provider static value=hello -o json

# YAML output
scafctl run provider static value=hello -o yaml

# Table output
scafctl run provider static value=hello -o table

# Quiet mode (exit code only)
scafctl run provider static value=hello -o quiet

Interactive Mode#

Explore complex output in an interactive TUI:

scafctl run provider http --input url=https://httpbin.org/get -i
scafctl run provider http --input url=https://httpbin.org/get -i

CEL Expressions#

Filter or transform output using CEL expressions:

scafctl run provider http url=https://httpbin.org/get -e "_.data"
scafctl run provider http url=https://httpbin.org/get -e '_.data'

Execution Metrics#

Use --show-metrics to display timing information:

scafctl run provider http url=https://httpbin.org/get --show-metrics
scafctl run provider http url=https://httpbin.org/get --show-metrics

Plugin Providers#

Load providers from plugin executables using --plugin-dir:

# Load plugins from a directory
scafctl run provider echo message=hello --plugin-dir ./plugins

# Multiple plugin directories
scafctl run provider my-plugin key=value --plugin-dir ./plugins --plugin-dir /opt/plugins
# Load plugins from a directory
scafctl run provider Write-Output "message=hello --plugin-dir ./plugins"

# Multiple plugin directories
scafctl run provider my-plugin key=value --plugin-dir ./plugins --plugin-dir /opt/plugins

See the Provider Development Guide for creating custom providers (including plugin delivery ).


Discovering Providers#

List All Providers#

scafctl get providers
scafctl get providers

View Provider Details#

scafctl get provider http
scafctl get provider http

This shows the provider’s schema, capabilities, examples, and auto-generated CLI usage examples.

Dynamic Help for Provider Inputs#

When you run --help with a specific provider name, the help output automatically includes the provider’s input parameters with types, required/optional status, defaults, and descriptions:

scafctl run provider http --help
scafctl run provider http --help

At the end of the standard help text, you’ll see a section like:

Provider Inputs (http):
  body     string               Request body for POST/PUT/PATCH requests
  headers  any                  HTTP headers as key-value pairs
  method   string               HTTP method
  timeout  integer              Request timeout in seconds
  url      string   (required)  The URL to request

This works for any provider — just include the provider name before --help:

scafctl run provider env --help
scafctl run provider static --help
scafctl run provider file --help
scafctl run provider env --help
scafctl run provider static --help
scafctl run provider file --help

Filter by Capability#

scafctl get providers --capability=validation
scafctl get providers --capability=validation

Browse Interactively#

scafctl get providers -i
scafctl get providers -i

Common Examples#

Read an Environment Variable#

scafctl run provider env operation=get name=HOME
scafctl run provider env operation=get name=HOME

Execute a Shell Command#

scafctl run provider exec command=date
scafctl run provider exec command=date

Read a File#

scafctl run provider file operation=read path=README.md
scafctl run provider file operation=read path=README.md

List a Directory#

scafctl run provider directory operation=list path=./pkg
scafctl run provider directory operation=list path=./pkg

Evaluate a CEL Expression#

# Simple expression (no commas)
scafctl run provider cel expression="1 + 2"

# Expressions with commas must be quoted to avoid CSV splitting
scafctl run provider cel 'expression="[1,2,3].map(x, x * 2)"'
# Simple expression (no commas)
scafctl run provider cel expression="1 + 2"

# Expressions with commas must be quoted to avoid CSV splitting
scafctl run provider cel 'expression="[1,2,3].map(x, x * 2)"'

Make an HTTP Request#

scafctl run provider http url=https://httpbin.org/get method=GET
scafctl run provider http url=https://httpbin.org/get method=GET

Get Git Repository Status#

scafctl run provider git operation=status path=.
scafctl run provider git operation=status path=.

Render a Go Template#

scafctl run provider go-template name=greeting 'template=Hello World'
scafctl run provider go-template name=greeting 'template=Hello World'

Redact Sensitive Output#

Use --redact to mask sensitive values in the output. This example retrieves a secret (which must already exist in the scafctl secrets store):

scafctl run provider secret operation=get name=my-secret --redact
scafctl run provider secret operation=get name=my-secret --redact

Next Steps#