Advanced Playbook Patterns¶
This guide covers advanced playbook patterns and complex syntax for experienced ADARE users. These patterns demonstrate sophisticated control flow, error handling, and dynamic behavior that goes beyond basic playbook concepts.
Note
If you’re new to ADARE playbooks, start with Actions for basic conditional flow control examples.
Conditional Flow Control¶
Complex Stop Patterns¶
Stop with Regex Matching
Use regex patterns to validate complex string formats and stop on invalid data.
actions:
- command:
command: "echo 'Version: 3.14.159'"
capture:
variable: version_string
parser: "re.search(r'Version: (.+)', output).group(1) if re.search(r'Version: (.+)', output) else ''"
- stop:
condition:
variable: version_string
matches: '^\d+\.\d+\.\d+$'
description: "Stop if version doesn't match X.Y.Z format"
Stop with JSON Data Validation
Parse JSON output and validate specific fields before continuing.
actions:
- command:
command: "echo '{\"status\": \"success\", \"code\": 200, \"data\": {\"count\": 42}}'"
capture:
variable: api_response
parser: "json.loads(output)"
# Stop if status is not success
- stop:
condition:
variable: api_response
contains: '"status": "error"'
description: "Stop if API returned error"
# Extract nested field for further validation
- command:
command: "echo '{{api_response}}'"
capture:
variable: response_code
parser: "json.loads(output)['code']"
- stop:
condition:
variable: response_code
greater_than: 299
description: "Stop if HTTP status code indicates failure"
Multi-Stage Validation with Stops
Chain multiple validation steps to create robust error checking.
actions:
# Stage 1: Capture system state
- command:
command: "df -h / | tail -1 | awk '{print $5}' | sed 's/%//'"
capture:
variable: disk_usage_percent
parser: "int(output.strip())"
- stop:
condition:
variable: disk_usage_percent
greater_than: 90
description: "Stop if disk usage exceeds 90%"
# Stage 2: Check process status
- command:
command: "pgrep -c nginx"
capture:
variable: nginx_count
parser: "int(output.strip())"
- stop:
condition:
variable: nginx_count
equals: 0
description: "Stop if nginx is not running"
# Stage 3: Validate configuration
- command:
command: "nginx -t 2>&1"
capture:
variable: config_status
source: all
parser: "'valid' if output['returncode'] == 0 else 'invalid'"
- stop:
condition:
variable: config_status
equals: "invalid"
description: "Stop if nginx configuration is invalid"
Complex Continue Patterns¶
Continue with Substring Matching
Skip loop iterations based on partial string matches.
variables:
file_patterns:
type: list
value: ["report_2024.pdf", "temp_data.csv", "report_2025.pdf", "cache.tmp"]
actions:
- loop:
items: "{{file_patterns}}"
item_var: filename
description: "Process only report files"
actions:
- continue:
condition:
variable: filename
contains: "temp"
description: "Skip temporary files"
- continue:
condition:
variable: filename
contains: "cache"
description: "Skip cache files"
- command:
command: "echo 'Processing {{filename}}'"
Skip Iterations Based on Computed Values
Use captured values from within the loop to decide whether to continue.
actions:
- loop:
times: 10
description: "Process even iterations only"
actions:
- command:
command: "echo $(({{index}} % 2))"
capture:
variable: is_odd
parser: "int(output.strip())"
- continue:
condition:
variable: is_odd
equals: 1
description: "Skip odd iterations"
- command:
command: "echo 'Processing even iteration {{index}}'"
Continue with Multiple Conditions (Pattern)
While ADARE doesn’t support AND/OR logic in VariableCondition, you can chain continues for complex logic.
actions:
- loop:
times: 20
actions:
# Skip if index < 5
- continue:
condition:
variable: index
less_than: 5
description: "Skip first 5 iterations"
# Skip if index > 15
- continue:
condition:
variable: index
greater_than: 15
description: "Skip after iteration 15"
# Only iterations 5-15 will execute this
- command:
command: "echo 'Processing iteration {{index}}'"
Advanced Command Capture¶
JSON Parsing with Error Handling
Safely parse JSON with fallback values for malformed data.
actions:
- command:
command: "curl -s https://api.example.com/data || echo '{\"error\": true}'"
allow_failure: true
capture:
variable: api_data
parser: |
try:
result = json.loads(output)
return result if 'error' not in result else None
except:
return None
- stop:
condition:
variable: api_data
is_empty: true
description: "Stop if API call failed or returned error"
Regex Extraction with Groups
Extract specific patterns from complex output.
actions:
- command:
command: "systemctl status nginx"
capture:
variable: nginx_pid
parser: |
match = re.search(r'Main PID: (\d+)', output)
return int(match.group(1)) if match else 0
- stop:
condition:
variable: nginx_pid
equals: 0
description: "Stop if nginx PID not found"
Multi-Output Capture (stdout + stderr + returncode)
Capture all command outputs for comprehensive analysis.
actions:
- command:
command: "make build 2>&1"
allow_failure: true
capture:
variable: build_result
source: all
parser: |
return {
'success': output['returncode'] == 0,
'warnings': output['stderr'].count('warning'),
'errors': output['stderr'].count('error'),
'output_lines': len(output['stdout'].split('\n'))
}
# Access nested dictionary values in subsequent commands
- command:
command: "echo '{{build_result}}'"
capture:
variable: build_success
parser: "json.loads(output)['success']"
- stop:
condition:
variable: build_success
equals: false
description: "Stop if build failed"
Chaining Captured Variables
Use captured variables to build complex workflows.
actions:
# Step 1: Get username
- command:
command: "whoami"
capture:
variable: current_user
# Step 2: Get home directory based on username
- command:
command: "echo $HOME"
capture:
variable: home_dir
# Step 3: Check for specific file in home directory
- command:
command: "test -f {{home_dir}}/.config/app.conf && echo 'exists' || echo 'missing'"
capture:
variable: config_exists
# Step 4: Conditional action based on chain
- stop:
condition:
variable: config_exists
equals: "missing"
description: "Stop if user config is missing"
Conditional Blocks and Keyboard¶
When Conditions with Multiple Checks
Check for multiple UI elements before executing a block.
actions:
# Wait for specific UI state before proceeding
- wait_until:
condition:
all:
- exists:
text: "Ready"
- not_exists:
text: "Loading"
timeout: 30.0
- block:
when:
- exists:
text: "Save"
- exists:
text: "Cancel"
description: "Save dialog is present"
actions:
- click:
target:
text: "Save"
- wait_until:
condition:
not_exists:
text: "Save"
timeout: 10.0
Combining When Conditions with Variable Conditions
Use both UI-based and variable-based conditions together.
actions:
# Capture system state
- command:
command: "date +%H"
capture:
variable: current_hour
parser: "int(output.strip())"
# Skip during off-hours (example pattern)
- continue:
condition:
variable: current_hour
less_than: 9
description: "Skip if before 9 AM"
# Now check UI state
- block:
when:
- exists:
text: "Submit"
actions:
- click:
target:
text: "Submit"
Real-World Conditional UI Automation
Handle optional dialogs that may or may not appear.
actions:
- click:
target:
text: "Open File"
# Optional: Handle "unsaved changes" dialog if it appears
- keyboard:
combination: ["ctrl", "s"]
when:
- exists:
text: "Unsaved Changes"
description: "Save if prompted"
- keyboard:
key: "enter"
when:
- exists:
text: "Unsaved Changes"
description: "Confirm dialog if present"
# Continue with main workflow
- click:
target:
text: "File Explorer"
Complex Loop Patterns¶
Nested Loops with Continue
Use continue in nested loops for granular control.
variables:
users:
type: list
value: ["alice", "bob", "charlie"]
actions_list:
type: list
value: ["read", "write", "execute"]
actions:
- loop:
items: "{{users}}"
item_var: user
actions:
- loop:
items: "{{actions_list}}"
item_var: action
actions:
# Skip write/execute for specific users
- continue:
condition:
variable: action
contains: "write"
description: "Skip write action (example)"
- command:
command: "echo 'User {{user}} can {{action}}'"
Loops with Captured Variable Iteration
Dynamically generate loop items from captured command output.
actions:
# Get list of files from command
- command:
command: "ls /tmp/*.txt"
capture:
variable: txt_files
parser: "output.strip().split('\n')"
# Loop over captured file list
- loop:
items: "{{txt_files}}"
item_var: filepath
actions:
- command:
command: "cat {{filepath}}"
capture:
variable: file_content
- continue:
condition:
variable: file_content
is_empty: true
description: "Skip empty files"
- command:
command: "echo 'Processing {{filepath}}'"
Dynamic Loop Control with Stops
Stop the entire playbook from within a loop based on critical conditions.
actions:
- loop:
times: 100
description: "Process up to 100 items"
actions:
- command:
command: "check_system_health.sh"
capture:
variable: health_status
source: returncode
# Stop entire playbook if system health check fails
- stop:
condition:
variable: health_status
greater_than: 0
description: "Critical: System health check failed"
- command:
command: "process_item.sh {{index}}"
Real-World Patterns¶
Error Recovery Pattern¶
Try an action, capture the result, and stop on failure with detailed diagnostics.
actions:
# Attempt critical operation
- command:
command: "docker build -t myapp:latest ."
allow_failure: true
capture:
variable: build_result
source: all
parser: |
{
'success': output['returncode'] == 0,
'exit_code': output['returncode'],
'error_log': output['stderr'][-500:] if output['stderr'] else '' # Last 500 chars
}
# Capture success flag
- command:
command: "echo '{{build_result}}'"
capture:
variable: build_success
parser: "json.loads(output)['success']"
# Stop with diagnostic info if failed
- stop:
condition:
variable: build_success
equals: false
description: "Docker build failed - check artifacts for error logs"
# Continue with deployment if successful
- command:
command: "docker push myapp:latest"
Validation Chain Pattern¶
Capture → validate → conditional continue for robust data processing.
variables:
endpoints:
type: list
value: ["/api/users", "/api/posts", "/api/comments"]
actions:
- loop:
items: "{{endpoints}}"
item_var: endpoint
description: "Validate each API endpoint"
actions:
# Step 1: Capture response
- command:
command: "curl -s -o /dev/null -w '%{http_code}' https://example.com{{endpoint}}"
capture:
variable: http_code
parser: "int(output.strip())"
# Step 2: Validate response code
- continue:
condition:
variable: http_code
greater_than: 399
description: "Skip failed endpoints"
# Step 3: Only successful endpoints reach here
- command:
command: "echo '✓ Endpoint {{endpoint}} is healthy ({{http_code}})'"
# Step 4: Pull detailed response for successful endpoints
- command:
command: "curl -s https://example.com{{endpoint}}"
capture:
variable: response_data
Dynamic Behavior Pattern¶
Capture system state and adjust actions accordingly.
actions:
# Detect operating system
- command:
command: "uname -s"
capture:
variable: os_name
# Detect available memory
- command:
command: "free -m | awk '/^Mem:/{print $7}'"
capture:
variable: available_memory
parser: "int(output.strip())"
# Adjust behavior based on available resources
- continue:
condition:
variable: available_memory
less_than: 1000
description: "Skip heavy operations on low memory systems"
# This heavy operation only runs on systems with sufficient memory
- command:
command: "run_memory_intensive_task.sh"
# OS-specific commands
- command:
command: "apt update"
when:
- exists:
text: "Ubuntu"
description: "Update packages on Ubuntu"
Tips and Best Practices¶
- Keep Conditions Simple
Complex conditions are harder to debug. Chain multiple simple conditions instead of trying to create one complex condition.
- Use Descriptive Variable Names
captured_usernameis better thanvar1. Descriptive names make playbooks self-documenting.- Add Description to Every Stop/Continue
Explain why the condition exists. Future maintainers (including yourself) will thank you.
- Test Parsers Separately
Complex parser expressions can be tested in Python REPL before adding to playbooks.
- Capture Diagnostic Info Before Stopping
When stopping due to errors, ensure you’ve captured enough information to debug the issue.
- Use allow_failure for Exploratory Commands
Commands that might fail (like testing file existence) should use
allow_failure: true.- Consider Stop vs Continue
Use
stopfor critical failures that invalidate the entire experimentUse
continuefor expected variations that should skip non-critical actions
Future Extensions¶
This advanced patterns guide will be expanded with additional topics:
File operation patterns (bulk file processing, recursive operations)
Complex testing patterns (conditional test execution, test result branching)
Performance optimization patterns (parallel execution, caching strategies)
Error handling patterns (retry logic, fallback actions)
Integration patterns (external API workflows, database interactions)
Check back for updates as new patterns are documented.