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: acceptableStatusCodes, authProvider, autoParseJson, body, headers, method, pagination, poll, retry, scope, timeout, url)

# Completely unknown key
scafctl run provider http unknown=value
# Error: provider "http" does not accept input "unknown" (valid inputs: acceptableStatusCodes, authProvider, autoParseJson, body, headers, method, pagination, poll, retry, scope, 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: acceptableStatusCodes, authProvider, autoParseJson, body, headers, method, pagination, poll, retry, scope, timeout, url)

# Completely unknown key
scafctl run provider http unknown=value
# Error: provider "http" does not accept input "unknown" (valid inputs: acceptableStatusCodes, authProvider, autoParseJson, body, headers, method, pagination, poll, retry, scope, 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

Version Pinning#

When multiple versions of a plugin provider are cached locally, you can pin a specific version using name@version syntax or the --plugin-version flag:

# Pin via @version syntax (recommended)
scafctl run provider exec@0.5.0 command="echo hello"

# Pin via --plugin-version flag
scafctl run provider exec --plugin-version 0.5.0 command="echo hello"
# Pin via @version syntax (recommended)
scafctl run provider exec@0.5.0 command="echo hello"

# Pin via --plugin-version flag
scafctl run provider exec --plugin-version 0.5.0 command="echo hello"

Without version pinning, the latest cached version is used automatically.

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


Discovering Providers#

List All Providers#

scafctl get providers
scafctl get providers

This lists all available providers with their source (builtin or official), category, capabilities, and version. Official providers are auto-fetched from the OCI catalog on first use – no manual installation required.

Note: When --capability or --category filters are active, only built-in providers are shown since official providers do not expose this metadata.

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. If the provider is not found in the built-in registry, scafctl falls back to the official provider registry and displays catalog information.

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):
  acceptableStatusCodes  array         Status codes treated as successful (e.g. [200, 404], "2xx", "200-204")
  authProvider   string                Authentication provider to use for this request
  autoParseJson  boolean               When true and the response Content-Type is application/json, automatically parse the body into a structured object
  body           any                   Request body for POST/PUT/PATCH requests (string sent verbatim; object/array serialized to JSON)
  headers        any                   HTTP headers as key-value pairs
  method         string                HTTP method
  pagination     object                Pagination configuration for automatically following paginated API responses
  poll           object                Polling configuration for re-executing the request until a condition is met
  retry          any                   Retry configuration for transient failures
  scope          string                OAuth scope for authentication
  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#