Skip to main content

Overview

Script variables let you write reusable markdown scripts with customizable parameters. Users can override variables from the command line without editing the script itself.

YAML Front-Matter Syntax

Declare variables in a YAML front-matter block at the top of your script:

Syntax Rules

  • Opt-in: Variables only activate when front-matter contains vars:. No vars: = no behavior change.
  • Front-matter stripped: The --- block is removed from the prompt when vars: is present.
  • Default values: Variables can have default values (like topic: "machine learning")
  • No default: Variables declared with just the key (like audience:) have no default value

Placeholder Substitution

Use {{varname}} syntax to insert variable values into your prompt:
The {{placeholder}} syntax:
  • Doesn’t collide with shell variables ($VAR)
  • Doesn’t collide with markdown syntax
  • Doesn’t collide with Claude syntax
  • Is visually distinct and easy to read

Unset Variables

A variable declared with no default (just key:) and no CLI override leaves {{key}} as-is in the prompt:
Without --topic flag: “Summarize .” (literal text) With --topic "AI": “Summarize AI.”

CLI Overrides

Override variables from the command line using flag syntax:
Hyphens in flag names are normalized to underscores when matching variables. --my-var matches my_var, so you can use natural CLI conventions:

Examples

Given this script:
summarize-topic.md
Run with defaults:
Override one variable:
Override multiple variables:
Equals form works too:
Boolean flag (no value — sets to "true"):

Mixing with AI Runner Flags

Variable overrides mix freely with AI Runner flags and provider overrides:

How Flag Consumption Works

Override flags matching declared var names are consumed by the variable system — they don’t pass through to Claude Code:
  • --topic, --style, --length are consumed (match declared vars)
  • --live, --aws, --opus pass through to AI Runner
  • Unrecognized flags (like --verbose) pass through to Claude Code

Complete Example

Here’s a real-world script with variables:
summarize-topic.md

Usage Examples

Default behavior:
Output: Short, casual summary of machine learning Override topic:
Output: Short, casual summary of quantum computing Override all variables:
Output: 100-word summary of the fall of Rome in Peter Griffin’s style With live streaming:
Output: Streams the summary in real-time With provider override:
Uses AWS Bedrock with Claude Opus, formal style summary of climate change

Advanced Patterns

Optional vs Required Variables

Optional (with default):
Toggle a boolean variable from the CLI:
Required (no default):
Users must provide --target-file and --operation (or --target_file — both work) or the placeholders remain literal.

Multiple Scripts with Shared Variables

Create a family of scripts that accept the same variables:
analyze.md
review.md
Both scripts accept the same flags:

Pipeline with Variables

Pass variables through a pipeline:
Each script in the pipeline can have its own variables.

Common Use Cases

1. Documentation Generator

generate-docs.md
Usage:

2. Test Runner

run-tests.md
Usage:

3. Code Reviewer

review.md
Usage:

4. Data Analyzer

analyze-data.md
Usage:

Best Practices

Do:
  • Provide sensible defaults for optional parameters
  • Use descriptive variable names (source_dir not src)
  • Document expected values in comments
  • Keep variable names lowercase with underscores (users can override with hyphens: --my-var matches my_var)
  • Use boolean variables for feature flags (verbose: false) — users toggle with --verbose
Don’t:
  • Use variable names that match Claude Code flags — they’ll shadow the flag (prefix with your domain, e.g., report_format not format; check claude --help if unsure)
  • Put sensitive data in default values (use environment variables instead)
  • Create too many variables (makes scripts hard to use)
  • Use complex variable names (target_file_for_processingtarget_file)

Troubleshooting

Variables Not Substituting

Problem: {{topic}} appears literally in output Solutions:
  1. Check YAML syntax (must have vars: key)
  2. Ensure front-matter is at the top of the file
  3. Verify closing --- after front-matter
  4. Check variable is declared in vars: block

CLI Override Not Working

Problem: --topic "AI" doesn’t override the default Solutions:
  1. Check variable is declared in front-matter
  2. Verify flag syntax: --topic value, --topic="value", or --topic (boolean)
  3. Check for typos in variable name — hyphens and underscores are interchangeable (--my-var and --my_var both match my_var)
  4. Ensure flag comes after script name: ./script.md --topic "AI"
Boolean vs value flags: --varname without a following value sets the variable to "true". If you intended to pass a value, make sure it follows the flag: --topic "AI" not just --topic. For values starting with --, use equals form: --topic="--special".

Conflicts with Claude Code Flags

Problem: --format json is interpreted as a variable instead of a Claude Code flag Solution: Variable names that match Claude Code flags will shadow them — the variable system consumes the flag before Claude Code sees it. To avoid conflicts:
  • Prefix variable names with your script’s domain (e.g., report_format instead of format)
  • Check claude --help if unsure whether a name conflicts
  • AI Runner flags (--live, --quiet, --aws, --model, etc.) are consumed before variable matching, so they can’t conflict
  • Short flags (-c, -n, -p) also can’t conflict — variable matching only checks -- double-dash form

Next Steps

Writing Scripts

Learn script basics and common patterns

Live Output

Stream progress in real-time

CI/CD Automation

Use variables in CI/CD pipelines

Permissions

Control what scripts can do