Skip to main content

Overview

Variables make runbooks reusable. Define them once, and reference them in step values with {{variableName}} syntax. Values can come from interactive prompts, environment variables, context files, secrets, or static values.

Variable sources

Variables are defined in the runbook with a source that determines how their value is resolved:
SourceDescriptionExample use case
promptAsks the user at execution time (CLI only)Login credentials, one-time values
fixedHardcoded static valueBase URLs, constants
contextAI extracts from the --context markdown fileValues described in documentation
envRead from an environment variableAWS_REGION, APP_URL
expressionEvaluate a template expression{{Date.now()}}, computed values
dataRead from a data fileRow-specific values in batch workflows

Examples

variables:
  email:
    source: prompt
    description: "Login email address"
    required: true
  baseUrl:
    source: fixed
    value: "https://staging.example.com"
  region:
    source: env
    envKey: "AWS_REGION"
  timestamp:
    source: expression
    expression: "{{Date.now()}}"
  appName:
    source: context
    description: "Application name from context"

Resolution priority

At execution time, variables are resolved in this order. The first match wins:
PrioritySourceDescription
1secretsValues from --secrets flag or SDK secrets option
2dataValues from data files
3contextAI extraction from --context markdown
4envEnvironment variables
5expressionTemplate expression evaluation
6fixedStatic value from the definition
7promptInteractive prompt (CLI only)
This means secrets always take precedence. If you pass a value via --secrets, it overrides any other source.

Secrets handling

Secrets are sensitive values that should never appear in logs or reports. There are two ways to provide them:

Via --secrets flag

Create a JSON file with key-value pairs:
{
  "password": "s3cret!",
  "apiToken": "tok_abc123"
}
npx @refrainai/cli execute -- \
  --runbook ./flow.yaml \
  --secrets ./secrets.json
All values in the secrets file are automatically treated as sensitive and masked in all output.

Via sensitive: true flag

Mark individual variables as sensitive in the runbook:
variables:
  password:
    source: prompt
    description: "Login password"
    sensitive: true

Context-based resolution

When a variable has source: context, AI reads the --context markdown file and extracts the value based on the variable’s description. This is useful when values are documented but not hardcoded:
variables:
  adminUrl:
    source: context
    description: "Admin dashboard URL"
# App context

The admin dashboard is at https://admin.example.com/dashboard
AI will resolve adminUrl to https://admin.example.com/dashboard.

Template syntax

Reference variables in any string field using double curly braces:
steps:
  - ordinal: 0
    description: "Navigate to {{baseUrl}}"
    action:
      type: navigate
      url: "{{baseUrl}}/login"
  - ordinal: 1
    description: "Enter email"
    action:
      type: input
      value: "{{email}}"
      selector:
        role: textbox
        ariaLabel: "Email"
Templates support:
  • Simple references: {{variableName}}
  • Dot notation for captured objects: {{captured.field}}
  • Nesting up to 3 levels deep

Best practices

  • Use prompt for credentials — Never hardcode passwords in runbooks
  • Use env for environment-specific values — Base URLs, API endpoints, regions
  • Use context for documented values — Keep context.md as the source of truth
  • Mark sensitive values — Use sensitive: true or --secrets to ensure masking
  • Keep secrets out of version control — Add secrets.json to .gitignore

What’s next