Install
openclaw skills install klimatex911Generate, review, and optimize Ansible automation artifacts. Use this skill whenever the user mentions Ansible, playbooks, roles, inventory, tasks, handlers, Jinja2 templates, ansible.cfg, Galaxy, AWX, or any infrastructure automation using YAML-based configuration management. Trigger even for vague requests like "automate server setup", "deploy my app with Ansible", "write a role for nginx", "create an inventory file", or "how do I configure hosts in Ansible". This skill covers the full lifecycle: generating playbooks, scaffolding roles, writing inventories, creating Jinja2 templates, designing variable structures, and producing CI/CD-ready Ansible project layouts.
openclaw skills install klimatex911A skill for generating production-grade Ansible automation: playbooks, roles, inventories, Jinja2 templates, variable files, and complete project structures following official best practices.
1. Clarify Intent → Understand target OS, task type, scale, idempotency needs
2. Choose Output Type → Playbook / Role / Inventory / Template / Full Project
3. Generate Artifacts → Produce YAML files with best practices embedded
4. Validate & Annotate → Add lint hints, --check commands, and idempotency notes
5. Deliver Structure → Present files with clear directory paths and run instructions
Before generating, collect the following (infer from context when possible):
| Parameter | Description | Example |
|---|---|---|
target_os | OS family of managed hosts | Ubuntu 22.04, RHEL 9 |
task_type | What to automate | deploy app, manage users |
connection_type | How Ansible connects | SSH (default), WinRM |
privilege | Needs sudo/become? | yes / no |
scale | Number of hosts / groups | 3 webservers, 1 DB |
idempotency | Must be safe to re-run? | yes (always recommended) |
var_source | Where variables come from | group_vars, vault, extra |
If context is clear, skip the interview and generate directly.
Use for: ad-hoc tasks, simple automation, one-off operations.
Template:
---
# playbooks/<name>.yml
- name: <Descriptive play name>
hosts: <inventory_group>
become: true
gather_facts: true
vars:
app_port: 8080
app_user: deploy
pre_tasks:
- name: Ensure required packages are present
ansible.builtin.package:
name: "{{ item }}"
state: present
loop:
- curl
- git
roles:
- role: <role_name>
when: ansible_os_family == "Debian"
tasks:
- name: Task description (use verb + object)
ansible.builtin.module:
param: value
notify: Restart service
tags:
- setup
- deploy
handlers:
- name: Restart service
ansible.builtin.service:
name: <service>
state: restarted
Rules:
ansible.builtin.copy, not copystate: present/absent for idempotencytags for selective executionnotify + handlers for service restarts (never restart inline)loop over with_items (deprecated)Use for: reusable, shareable, testable automation units.
Directory structure:
roles/<role_name>/
├── defaults/
│ └── main.yml # Low-priority defaults (overridable)
├── vars/
│ └── main.yml # High-priority role-internal vars
├── tasks/
│ ├── main.yml # Entry point (import_tasks per OS/feature)
│ ├── install.yml
│ ├── configure.yml
│ └── service.yml
├── handlers/
│ └── main.yml
├── templates/
│ └── <config>.conf.j2
├── files/
│ └── <static_files>
├── meta/
│ └── main.yml # Galaxy metadata, dependencies
└── README.md
tasks/main.yml pattern:
---
- name: Include OS-specific variables
ansible.builtin.include_vars: "{{ ansible_os_family }}.yml"
failed_when: false
- ansible.builtin.import_tasks: install.yml
tags: [install]
- ansible.builtin.import_tasks: configure.yml
tags: [configure]
- ansible.builtin.import_tasks: service.yml
tags: [service]
defaults/main.yml pattern:
---
# Role: <role_name>
# All variables with safe defaults
role_package_name: nginx
role_service_name: nginx
role_config_path: /etc/nginx/nginx.conf
role_user: www-data
role_port: 80
role_enabled: true
Static inventory (INI format):
# inventory/hosts
[webservers]
web01.example.com ansible_host=10.0.1.10
web02.example.com ansible_host=10.0.1.11
[databases]
db01.example.com ansible_host=10.0.2.10
[loadbalancers]
lb01.example.com
[production:children]
webservers
databases
loadbalancers
[all:vars]
ansible_user=deploy
ansible_ssh_private_key_file=~/.ssh/id_rsa
ansible_python_interpreter=/usr/bin/python3
Static inventory (YAML format — preferred):
# inventory/hosts.yml
all:
vars:
ansible_user: deploy
ansible_python_interpreter: /usr/bin/python3
children:
webservers:
hosts:
web01:
ansible_host: 10.0.1.10
http_port: 80
web02:
ansible_host: 10.0.1.11
http_port: 80
databases:
hosts:
db01:
ansible_host: 10.0.2.10
db_port: 5432
staging:
children:
webservers:
databases:
group_vars structure:
inventory/
├── hosts.yml
├── group_vars/
│ ├── all.yml # Applies to all hosts
│ ├── all/
│ │ ├── vars.yml
│ │ └── vault.yml # ansible-vault encrypted secrets
│ ├── webservers.yml
│ └── databases.yml
└── host_vars/
└── web01.yml
Config file template pattern:
{# templates/nginx.conf.j2 #}
{# Managed by Ansible - Do not edit manually #}
user {{ nginx_user | default('www-data') }};
worker_processes {{ nginx_worker_processes | default(ansible_processor_vcpus) }};
events {
worker_connections {{ nginx_worker_connections | default(1024) }};
}
http {
include mime.types;
default_type application/octet-stream;
{% if nginx_log_format is defined %}
log_format main '{{ nginx_log_format }}';
{% endif %}
{% for vhost in nginx_vhosts | default([]) %}
server {
listen {{ vhost.port | default(80) }};
server_name {{ vhost.name }};
root {{ vhost.root }};
{% if vhost.ssl | default(false) %}
listen 443 ssl;
ssl_certificate {{ vhost.ssl_cert }};
ssl_certificate_key {{ vhost.ssl_key }};
{% endif %}
}
{% endfor %}
}
Key Jinja2 patterns:
{# Default filter #}
{{ variable | default('fallback_value') }}
{# Conditional block #}
{% if ansible_os_family == "Debian" %}
apt_cache_valid_time: 3600
{% elif ansible_os_family == "RedHat" %}
yum_releasever: latest
{% endif %}
{# Loop over dict #}
{% for key, value in config_dict.items() %}
{{ key }} = {{ value }}
{% endfor %}
{# Join list #}
{{ my_list | join(', ') }}
{# Uppercase / replace #}
{{ service_name | upper | replace('-', '_') }}
Priority order (high → low):
extra vars (-e) # Highest priority
task vars
block vars
role and include vars
play vars
host facts
host_vars
group_vars/all
role defaults # Lowest priority
vault.yml pattern (sensitive data):
# group_vars/all/vault.yml
# Encrypt with: ansible-vault encrypt vault.yml
vault_db_password: "super_secret_password"
vault_api_key: "abc123xyz"
vault_ssl_cert_content: |
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
vars.yml (reference vault vars):
# group_vars/all/vars.yml
db_password: "{{ vault_db_password }}"
api_key: "{{ vault_api_key }}"
[defaults]
inventory = ./inventory/hosts.yml
roles_path = ./roles:~/.ansible/roles
collections_paths = ./collections:~/.ansible/collections
remote_user = deploy
private_key_file = ~/.ssh/id_rsa
host_key_checking = False
retry_files_enabled = False
stdout_callback = yaml
callbacks_enabled = profile_tasks, timer
interpreter_python = auto_silent
# Performance tuning
forks = 10
pipelining = True
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts
fact_caching_timeout = 3600
[privilege_escalation]
become = True
become_method = sudo
become_user = root
become_ask_pass = False
[ssh_connection]
ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s
control_path_dir = /tmp/.ansible/cp
For complete projects, generate this layout:
<project_name>/
├── ansible.cfg
├── requirements.yml # Galaxy roles/collections
├── site.yml # Master playbook
├── playbooks/
│ ├── deploy.yml
│ ├── rollback.yml
│ └── maintenance.yml
├── roles/
│ └── <role_name>/ # See Role Scaffold above
├── inventory/
│ ├── production/
│ │ ├── hosts.yml
│ │ ├── group_vars/
│ │ └── host_vars/
│ └── staging/
│ ├── hosts.yml
│ └── group_vars/
├── collections/
│ └── requirements.yml
├── filter_plugins/ # Custom Jinja2 filters
├── library/ # Custom modules
└── .github/
└── workflows/
└── ansible-lint.yml # CI validation
requirements.yml:
---
collections:
- name: community.general
version: ">=7.0.0"
- name: ansible.posix
- name: community.docker
version: "3.4.0"
roles:
- name: geerlingguy.nodejs
version: "6.1.0"
- src: https://github.com/org/role.git
scm: git
version: main
name: custom_role
Always append these to generated output:
Syntax check:
ansible-playbook playbooks/deploy.yml --syntax-check
Dry run (no changes):
ansible-playbook playbooks/deploy.yml --check --diff
Lint (requires ansible-lint):
pip install ansible-lint
ansible-lint playbooks/deploy.yml
Run with vault:
ansible-playbook playbooks/deploy.yml --ask-vault-pass
# or with vault password file:
ansible-playbook playbooks/deploy.yml --vault-password-file ~/.vault_pass
Limit to specific hosts/groups:
ansible-playbook site.yml --limit webservers
ansible-playbook site.yml --limit web01.example.com
Run specific tags:
ansible-playbook site.yml --tags deploy,configure
ansible-playbook site.yml --skip-tags debug
Ad-hoc commands:
# Ping all hosts
ansible all -m ping
# Gather facts
ansible webservers -m ansible.builtin.setup
# Run shell command
ansible databases -m ansible.builtin.shell -a "df -h"
# Copy file
ansible all -m ansible.builtin.copy -a "src=file.conf dest=/etc/file.conf"
Always apply these principles:
ansible.builtin.copy, not copystate: on resource modulesshell/commandchanged_when / failed_when: Set on shell/command taskswhen conditions: Use Ansible facts, not shell conditionals# Managed by Ansible| Task | Module |
|---|---|
| Install packages | ansible.builtin.package |
| Copy files | ansible.builtin.copy |
| Template files | ansible.builtin.template |
| Manage services | ansible.builtin.service |
| Manage users | ansible.builtin.user |
| Run commands | ansible.builtin.command |
| Run shell | ansible.builtin.shell |
| Manage files/dirs | ansible.builtin.file |
| Edit lines in files | ansible.builtin.lineinfile |
| Download files | ansible.builtin.get_url |
| Unarchive tarballs | ansible.builtin.unarchive |
| Manage cron jobs | ansible.builtin.cron |
| Manage firewall | ansible.posix.firewalld |
| Docker containers | community.docker.docker_container |
| Git clone | ansible.builtin.git |
| Wait for condition | ansible.builtin.wait_for |
| Set facts | ansible.builtin.set_fact |
| Assert conditions | ansible.builtin.assert |
| Include variables | ansible.builtin.include_vars |
| Debug output | ansible.builtin.debug |
When delivering Ansible artifacts:
# comment