Tutorials-as-Code: Execute and validate Markdown tutorials to prevent documentation drift.
GuideRails enables you to write interactive, executable tutorials in Markdown that can be:
- ✅ Validated automatically in CI/CD pipelines
- 🚀 Run interactively in guided mode for step-by-step execution
- 📝 Authored with minimal, unobtrusive markup
- 🌐 Executed from local files or web URLs
- Markdown-first: Write tutorials in plain Markdown with minimal annotations
- Interactive mode: Step-by-step guided execution with user prompts
- CI mode: Automated validation for continuous integration
- Flexible validation: Support for exit codes, output matching, regex, and exact comparisons
- File generation: Create files directly from code blocks with
.gr-file - Output capture: Store command output and exit codes in variables
- Variable substitution: Use
${VAR}syntax for continuity across steps - Web support: Load tutorials from URLs with meta tag discovery
- Developer-friendly: Simple attribute syntax for marking executable steps
- Safe by default: Sandboxed file operations within working directory
Note: As of version 0.2.0, the CLI tool has been renamed from
guideruntoguiderailsfor consistency with the project name. Please update your scripts and workflows accordingly. See CHANGELOG.md for details.
pip install guiderailsOr install from source:
git clone https://github.com/srbouffard/guiderails.git
cd guiderails
pip install -e .Create a Markdown file with GuideRails annotations:
# My First Tutorial
## Step 1: Setup {.gr-step #step1}
Let's create a test directory:
\```bash {.gr-run data-mode=exit data-exp=0}
mkdir -p /tmp/test
\```
## Step 2: Verify {.gr-step #step2}
Check that it was created:
\```bash {.gr-run data-mode=contains data-exp="/tmp/test"}
ls -d /tmp/test
\```guiderails exec --guided tutorial.mdguiderails exec --ci tutorial.mdMark tutorial steps by adding {.gr-step} to headings:
## Setup Environment {.gr-step #setup}Optional: Add an ID with #step-id for reference.
Mark code blocks for execution with {.gr-run}:
\```bash {.gr-run data-mode=exit data-exp=0}
echo "Hello, World!"
\```GuideRails supports four validation modes:
\```bash {.gr-run data-mode=exit data-exp=0}
test -f myfile.txt
\```\```bash {.gr-run data-mode=contains data-exp="success"}
./my-script.sh
\```\```bash {.gr-run data-mode=regex data-exp="Error: [0-9]+"}
./check-status.sh
\```\```bash {.gr-run data-mode=exact data-exp="Hello, World!"}
echo "Hello, World!"
\```Create files directly from your tutorial using .gr-file blocks:
\```bash {.gr-file data-path="script.sh" data-mode=write data-exec=true}
#!/bin/bash
echo "Hello from GuideRails!"
\```Attributes:
data-path: Target file path (relative to working directory)data-mode:write(default, overwrite) orappenddata-exec:trueto make file executable (chmod +x)data-template:none(default) orshell(enables ${VAR} substitution)data-once:trueto skip if file already exists
Example with variable substitution:
\```python {.gr-file data-path="config.py" data-template=shell}
VERSION = "${APP_VERSION}"
PORT = ${PORT}
\```Capture command output and exit codes for use in later steps:
\```bash {.gr-run data-out-var=GREETING data-code-var=EXIT_STATUS}
echo "Hello, World!"
exit 0
\```Capture Options:
data-out-var=VARNAME: Store combined stdout/stderr in a variabledata-out-file=path: Write stdout to a filedata-code-var=VARNAME: Store exit code in a variable
Use captured variables in subsequent blocks with ${VAR} syntax:
\```bash {.gr-run data-out-var=NAME}
echo -n "Alice"
\```
\```bash {.gr-run data-mode=contains data-exp="Hello, Alice"}
echo "Hello, ${NAME}"
\```Variables are automatically substituted when:
- Running
.gr-runcode blocks (command is substituted before execution) - Writing
.gr-fileblocks withdata-template=shell
Safety: File paths are sandboxed to the working directory by default. Absolute paths and .. traversal are rejected unless explicitly allowed with CLI flags.
- Timeout:
data-timeout=60(seconds, default: 30) - Working Directory:
data-workdir=/tmp - Continue on Error:
data-continue-on-error=true
Example:
\```bash {.gr-run data-mode=exit data-exp=0 data-timeout=60 data-workdir=/tmp}
long-running-command
\```Execute a tutorial:
guiderails exec [OPTIONS] TUTORIALBasic Options:
--guided: Run in interactive mode (shows each step, prompts for execution)--ci: Run in CI mode (non-interactive, fails fast, defaults to quiet output)--working-dir, -w PATH: Set base working directory for execution
Verbosity Options:
--verbosity LEVEL: Set verbosity level (quiet,normal,verbose,debug)--quiet, -q: Quiet mode (minimal output, alias for--verbosity=quiet)--verbose, -v: Increase verbosity (-vfor verbose,-vvor-vvvfor debug)--debug: Debug mode (maximum verbosity, alias for--verbosity=debug)
Output Toggle Options:
--show-commands / --no-show-commands: Show/hide commands being executed--show-substituted / --no-show-substituted: Show/hide variable substitution hints--show-expected / --no-show-expected: Show/hide expected validation values--show-captured / --no-show-captured: Show/hide captured variable information--timestamps / --no-timestamps: Show/hide execution timestamps--step-banners / --no-step-banners: Show/hide step banners and boxes--previews / --no-previews: Show/hide command previews and extra details
Output Format:
--output FORMAT: Output format (textorjsonl)
Verbosity Level Behaviors:
- quiet: Shows only step titles, commands (if
--show-commands), command output, and PASS/FAIL status. Minimal decoration. - normal (default): Adds step banners, content boxes, and basic execution results.
- verbose: Adds command previews, substitution details, timing information, and working directory.
- debug: Adds internal diagnostics, parser events, and variable table state.
Tutorial Sources:
- Local file:
./tutorial.md - Direct URL:
https://example.com/tutorial.md - HTML page with meta tag:
https://example.com/tutorial.html
Run locally with interaction:
guiderails exec --guided examples/getting-started.mdValidate in CI (defaults to quiet output):
guiderails exec --ci examples/getting-started.mdRun with verbose output:
guiderails exec --ci --verbose examples/getting-started.mdRun in quiet mode with no command display:
guiderails exec --ci --quiet --no-show-commands examples/getting-started.mdRun from URL:
guiderails exec --guided https://example.com/tutorial.mdFrom HTML with meta tag:
guiderails exec --guided https://example.com/tutorial.htmlThe HTML page should include:
<meta name="guiderails:source" content="https://example.com/raw/tutorial.md">GuideRails supports configuration through multiple sources with the following precedence:
1. Command-line flags (highest priority)
2. Environment variables
3. Configuration file (guiderails.yml)
4. Built-in defaults (lowest priority)
# Verbosity level
export GUIDERAILS_VERBOSITY=quiet|normal|verbose|debug
# Output toggles
export GUIDERAILS_SHOW_COMMANDS=true|false
export GUIDERAILS_SHOW_SUBSTITUTED=true|false
export GUIDERAILS_SHOW_EXPECTED=true|false
export GUIDERAILS_SHOW_CAPTURED=true|false
export GUIDERAILS_TIMESTAMPS=true|false
export GUIDERAILS_STEP_BANNERS=true|false
export GUIDERAILS_PREVIEWS=true|falseCreate a guiderails.yml file in your project root:
# Verbosity level (quiet, normal, verbose, debug)
verbosity: normal
# Output toggles
show_commands: true
show_substituted: false
show_expected: true
show_captured: true
show_timestamps: false
show_step_banners: true
show_previews: falseGuideRails will search for guiderails.yml in the current directory and parent directories.
Create .github/workflows/validate-tutorials.yml:
name: Validate Tutorials
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install GuideRails
run: pip install guiderails
- name: Validate tutorials
run: |
guiderails exec --ci docs/tutorial.mdSee the examples directory for sample tutorials:
- getting-started.md - Basic GuideRails tutorial
- file-generation-and-capture.md - File generation, output capture, and variable substitution
- tutorial-page.html - HTML page with meta tag
# Clone the repository
git clone https://github.com/srbouffard/guiderails.git
cd guiderails
# Install in development mode
pip install -e ".[dev]"pytest tests/ -vblack src/ tests/
ruff check src/- Support for reStructuredText (reST) tutorials
- Environment variable support
- Parallel execution of independent steps
- Step dependencies and conditional execution
- Plugin system for custom validators
- Web UI for tutorial execution and monitoring
Contributions are welcome! Please feel free to submit a Pull Request.
MIT License - see LICENSE file for details.
Inspired by the need for validated, executable documentation that stays in sync with code.