Playbook Format
YAML schema reference for Nefia playbook files.
Playbooks define multi-step operations as declarative YAML files. Each playbook contains a sequence of steps that run against target hosts in order, with support for conditionals, retries, and output chaining.
File Structure
A playbook is a single YAML file with three top-level fields:
name: deploy-app
description: Build and deploy the web application
steps:
- name: stop-service
exec: "systemctl stop app"
- name: deploy-files
fs_write:
path: /var/www/app/index.html
content: "<h1>Deployed</h1>"
- name: start-service
exec: "systemctl start app"Top-Level Fields
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | Unique identifier for the playbook. Used in CLI commands and logs. |
description | string | no | Human-readable description of what the playbook does. |
version | int | no | Schema version of the playbook format. Used for forward-compatible parsing. |
vars | map[string]string | no | Top-level variables available for template substitution in step commands and content. |
steps | step[] | yes | Ordered list of steps to execute. |
Step Schema
Each step in the steps array supports the following fields:
| Field | Type | Default | Description |
|---|---|---|---|
name * | string | — | Unique name for this step. Used in logs and as a reference key for output chaining. |
exec | string | — | Shell command to execute. Exactly one of exec, sudo, fs_write, fs_read, fs_mkdir, fs_remove, fs_chmod, or service must be present. |
sudo | string | — | Command to run with sudo privileges. |
fs_write | object | — | File write operation with path and content fields. |
fs_read | object | — | File read operation with path field. |
fs_mkdir | string | — | Path of a directory to create (parents are created automatically). |
fs_remove | string | — | Path to remove (file or directory). |
fs_chmod | object | — | Change file permissions with path and mode fields. |
service | object | — | Control a system service with name and action fields. |
os | string | — | Target OS filter: macos, linux, or windows. Step is skipped on non-matching hosts. |
when | string | — | Conditional expression. Supports Go templates and simple comparisons (e.g., {{ .Steps.<name>.OK }} == true). Step runs only when the expression evaluates to a non-empty/truthy string. |
register | string | — | Store the step output as a named variable for use in subsequent steps. Name must use [a-zA-Z0-9_] only (no hyphens). |
continue_on_error | boolean | false | If true, playbook execution continues even if this step fails. |
timeout_ms | int | 0 | Per-step timeout in milliseconds. 0 means no timeout (falls back to --step-timeout if set on the CLI). |
retry | object | — | Retry configuration with max_attempts and interval_ms. |
Step Types
Executes a shell command on the target host. The exec field contains the command string.
- name: check-disk
exec: "df -h /"
timeout_ms: 10000Retry Configuration
The retry object controls automatic retry behavior for flaky operations:
| Field | Type | Default | Description |
|---|---|---|---|
max_attempts | int | 1 | Maximum number of attempts (including the initial try). |
interval_ms | int | 1000 | Delay in milliseconds between retry attempts. |
- name: health-check
exec: "curl -sf http://localhost:8080/health"
retry:
max_attempts: 5
interval_ms: 3000Template Variables
Playbook fields that accept strings (exec, fs_write.content, when) support Go template syntax. The following variables are available:
Host Variables
| Variable | Description | Example Value |
|---|---|---|
{{.Host.ID}} | Host identifier (name) | prod-web-1 |
{{.Host.OS}} | Target operating system | linux |
{{.Host.Address}} | Host VPN address | 10.99.0.2 |
User Variables
Pass variables at runtime with the --var flag:
nefia playbook run deploy.yaml --target group:webservers --var version=2.1.0 --var env=productionReference them with {{.Vars.<name>}}:
- name: deploy-artifact
exec: "wget https://releases.example.com/app-{{.Vars.version}}.tar.gz -O /tmp/app.tar.gz"Step Output Variables
When a step uses register, its output and exit code become available to subsequent steps:
| Variable | Description |
|---|---|
{{.Steps.<register_name>.Output}} | Standard output captured from the step. |
{{.Steps.<register_name>.ExitCode}} | Exit code (0 = success). |
{{.Steps.<register_name>.OK}} | Boolean indicating whether the step succeeded. |
{{.Steps.<register_name>.Skipped}} | Boolean indicating whether the step was skipped (e.g., by when or os filter). |
Only steps that specify a register field are stored in .Steps. The map key is the value of register, not the step name.
- name: get-version
exec: "cat /var/www/app/VERSION"
register: current_version
- name: log-version
exec: 'echo "Current version is {{.Steps.current_version.Output}}"'Conditional Execution
The when field accepts Go template expressions. A step runs only when the expression produces a non-empty string.
- name: install-nginx
exec: "apt-get install -y nginx"
os: linux
when: "{{if eq .Host.OS \"linux\"}}true{{end}}"
- name: restart-if-changed
exec: "systemctl restart app"
when: "{{if ne .Steps.deploy_config.ExitCode 0}}{{else}}true{{end}}"The os field is a shorthand for OS-based filtering. It is simpler than writing a when expression for the same purpose:
# These two are equivalent:
- name: restart-launchd
exec: "launchctl kickstart -k system/com.example.app"
os: macos
- name: restart-systemd
exec: "systemctl restart app"
os: linux
- name: restart-service-windows
exec: "Restart-Service -Name app -Force"
os: windowsExample Playbooks
System Update
name: system-update
description: Update packages and reboot if required
steps:
- name: update-packages
exec: "apt-get update && apt-get upgrade -y"
os: linux
timeout_ms: 300000
- name: update-packages-windows
exec: "choco upgrade all -y"
os: windows
timeout_ms: 300000
- name: check-reboot
exec: '[ -f /var/run/reboot-required ] && echo yes || echo no'
os: linux
register: needs_reboot
- name: reboot
exec: 'shutdown -r +1 "Rebooting for kernel update"'
os: linux
when: "{{if eq .Steps.needs_reboot.Output \"yes\"}}true{{end}}"Application Deployment
name: deploy-webapp
description: Deploy a new version of the web application
steps:
- name: download-artifact
exec: >
wget -q https://releases.example.com/app-{{.Vars.version}}.tar.gz
-O /tmp/app-{{.Vars.version}}.tar.gz
- name: stop-service
exec: "systemctl stop webapp"
- name: extract
exec: "tar xzf /tmp/app-{{.Vars.version}}.tar.gz -C /var/www/app/"
- name: write-version
fs_write:
path: /var/www/app/VERSION
content: "{{.Vars.version}}"
- name: start-service
exec: "systemctl start webapp"
- name: health-check
exec: "curl -sf http://localhost:8080/health"
retry:
max_attempts: 5
interval_ms: 3000Config Sync with Rollback
name: config-sync
description: Push configuration with automatic rollback on failure
steps:
- name: backup-config
exec: "cp /etc/app/config.yaml /etc/app/config.yaml.bak"
- name: write-config
fs_write:
path: /etc/app/config.yaml
content: |
server:
port: {{.Vars.port}}
workers: 4
database:
host: {{.Vars.db_host}}
name: {{.Vars.db_name}}
- name: validate-config
exec: "app --validate-config /etc/app/config.yaml"
continue_on_error: true
register: validation
- name: rollback-on-failure
exec: "mv /etc/app/config.yaml.bak /etc/app/config.yaml"
when: "{{if ne .Steps.validation.ExitCode 0}}true{{end}}"
- name: reload-service
exec: "systemctl reload app"
when: "{{if eq .Steps.validation.ExitCode 0}}true{{end}}"Validating Playbooks
Check a playbook for syntax errors and schema violations before running it:
nefia playbook validate deploy.yamlPlaybook: deploy-webapp Steps: 6 Template variables required: version
Validation: OK
Running Playbooks
Execute a playbook against a target selector:
nefia playbook run deploy.yaml --target group:webservers --var version=2.1.0Running: deploy-webapp (6 steps) Target: 3 hosts (group:webservers)
[1/6] download-artifact ... OK (3 hosts, 4.2s) [2/6] stop-service ... OK (3 hosts, 1.1s) [3/6] extract ... OK (3 hosts, 2.3s) [4/6] write-version ... OK (3 hosts, 0.2s) [5/6] start-service ... OK (3 hosts, 1.4s) [6/6] health-check ... OK (3 hosts, 6.8s)
All steps completed successfully on 3/3 hosts.
Related
Complete reference for playbook-related CLI commands.
Configure scheduling, timeouts, and concurrency in nefia.yaml.
Execute ad-hoc commands with target selectors and concurrency control.