> ## Documentation Index
> Fetch the complete documentation index at: https://docs.airun.me/llms.txt
> Use this file to discover all available pages before exploring further.

# Script Variables

> Make scripts reusable with YAML front-matter and CLI overrides

## 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:

```markdown theme={null}
#!/usr/bin/env -S ai --haiku
---
vars:
  topic: "machine learning"
  style: casual
  audience:
---
Write a summary of {{topic}} in {{style}} style.
Target audience: {{audience}}.
```

### 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:

```markdown theme={null}
Write a {{length}} summary of {{topic}} in a {{style}} tone.
```

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:

```markdown theme={null}
---
vars:
  topic:
---
Summarize {{topic}}.
```

Without `--topic` flag: "Summarize {{topic}}." (literal text)
With `--topic "AI"`: "Summarize AI."

## CLI Overrides

Override variables from the command line using flag syntax:

```bash theme={null}
./script.md --varname value
./script.md --varname="value with spaces"
./script.md --varname                      # boolean — sets to "true"
```

Hyphens in flag names are normalized to underscores when matching variables. `--my-var` matches `my_var`, so you can use natural CLI conventions:

```bash theme={null}
./script.md --brief-only                   # matches vars: brief_only
./script.md --max-retries 5                # matches vars: max_retries
./script.md --output-dir="/tmp/results"    # matches vars: output_dir
```

### Examples

Given this script:

```markdown summarize-topic.md theme={null}
#!/usr/bin/env -S ai --haiku
---
vars:
  topic: "machine learning"
  style: casual
  length: short
---
Write a {{length}} summary of {{topic}} in a {{style}} tone.
```

Run with defaults:

```bash theme={null}
./summarize-topic.md
# Uses: topic="machine learning", style=casual, length=short
```

Override one variable:

```bash theme={null}
./summarize-topic.md --topic "AI safety"
# Uses: topic="AI safety", style=casual, length=short
```

Override multiple variables:

```bash theme={null}
./summarize-topic.md --topic "AI safety" --style formal
# Uses: topic="AI safety", style=formal, length=short
```

Equals form works too:

```bash theme={null}
./summarize-topic.md --topic="robotics" --length="100 words"
```

Boolean flag (no value — sets to `"true"`):

```bash theme={null}
./summarize-topic.md --verbose
# Sets verbose to "true" if declared in vars
```

## Mixing with AI Runner Flags

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

```bash theme={null}
# --live is an AI Runner flag, --topic is a variable override
./summarize-topic.md --live --topic "quantum computing"

# Override provider + model alongside variables
ai --aws --opus summarize-topic.md --topic "the fall of rome"

# All together
./summarize-topic.md --live --length "100 words" --topic "the fall of rome" --style "peter griffin"
```

### 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:

```markdown summarize-topic.md theme={null}
#!/usr/bin/env -S ai --haiku
---
vars:
  topic: "machine learning"
  style: casual
  length: short
---
Write a {{length}} summary of {{topic}} in a {{style}} tone.
```

### Usage Examples

**Default behavior:**

```bash theme={null}
./summarize-topic.md
```

Output: Short, casual summary of machine learning

**Override topic:**

```bash theme={null}
./summarize-topic.md --topic "quantum computing"
```

Output: Short, casual summary of quantum computing

**Override all variables:**

```bash theme={null}
./summarize-topic.md \
  --topic "the fall of rome" \
  --style "peter griffin" \
  --length "100 words"
```

Output: 100-word summary of the fall of Rome in Peter Griffin's style

**With live streaming:**

```bash theme={null}
./summarize-topic.md --live --topic "AI safety"
```

Output: Streams the summary in real-time

**With provider override:**

```bash theme={null}
ai --aws --opus summarize-topic.md --topic "climate change" --style formal
```

Uses AWS Bedrock with Claude Opus, formal style summary of climate change

## Advanced Patterns

### Optional vs Required Variables

**Optional (with default):**

```markdown theme={null}
---
vars:
  format: markdown
  verbose: false
---
Generate output in {{format}} format. Verbose mode: {{verbose}}.
```

Toggle a boolean variable from the CLI:

```bash theme={null}
./script.md --verbose         # sets verbose to "true"
./script.md                   # uses default "false"
```

**Required (no default):**

```markdown theme={null}
---
vars:
  target_file:
  operation:
---
Perform {{operation}} on {{target_file}}.
```

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:

```markdown analyze.md theme={null}
---
vars:
  language: python
  depth: basic
---
Analyze {{language}} code with {{depth}} depth.
```

```markdown review.md theme={null}
---
vars:
  language: python
  depth: basic
---
Review {{language}} code for {{depth}} issues.
```

Both scripts accept the same flags:

```bash theme={null}
./analyze.md --language go --depth thorough
./review.md --language go --depth thorough
```

### Pipeline with Variables

Pass variables through a pipeline:

```bash theme={null}
./extract.md --source data.json | \
./transform.md --format csv | \
./validate.md --schema schema.json > output.csv
```

Each script in the pipeline can have its own variables.

## Common Use Cases

### 1. Documentation Generator

```markdown generate-docs.md theme={null}
#!/usr/bin/env -S ai --skip
---
vars:
  source_dir: src
  output_file: ARCHITECTURE.md
  style: technical
---
Read files in {{source_dir}}/
Generate {{output_file}} documenting the codebase.
Use {{style}} writing style.
```

Usage:

```bash theme={null}
./generate-docs.md
./generate-docs.md --source_dir lib --output_file README.md --style casual
```

### 2. Test Runner

```markdown run-tests.md theme={null}
#!/usr/bin/env -S ai --skip
---
vars:
  test_pattern: "*.test.js"
  framework: jest
  coverage: false
---
Run tests matching {{test_pattern}} using {{framework}}.
Generate coverage report: {{coverage}}.
```

Usage:

```bash theme={null}
./run-tests.md
./run-tests.md --test_pattern "integration/*.test.ts" --coverage true
```

### 3. Code Reviewer

```markdown review.md theme={null}
#!/usr/bin/env -S ai --opus
---
vars:
  focus: security
  severity: high
  output_format: markdown
---
Review code for {{focus}} issues.
Only report {{severity}} severity and above.
Output in {{output_format}} format.
```

Usage:

```bash theme={null}
./review.md
./review.md --focus performance --severity medium --output_format json
```

### 4. Data Analyzer

```markdown analyze-data.md theme={null}
#!/usr/bin/env ai
---
vars:
  metric: revenue
  period: monthly
  visualization: false
---
Analyze {{metric}} trends over {{period}} periods.
Include visualization: {{visualization}}.
```

Usage:

```bash theme={null}
cat data.csv | ./analyze-data.md --metric users --period weekly
```

## Best Practices

<Check>
  **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`
</Check>

<Warning>
  **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_processing` → `target_file`)
</Warning>

## 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"`

<Note>
  **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"`.
</Note>

### 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

<CardGroup cols={2}>
  <Card title="Writing Scripts" icon="scroll" href="/guides/scripting">
    Learn script basics and common patterns
  </Card>

  <Card title="Live Output" icon="signal-stream" href="/guides/live-output">
    Stream progress in real-time
  </Card>

  <Card title="CI/CD Automation" icon="gears" href="/guides/automation">
    Use variables in CI/CD pipelines
  </Card>

  <Card title="Permissions" icon="shield-check" href="/guides/permissions">
    Control what scripts can do
  </Card>
</CardGroup>
