This skill should be used when running ansible-lint, configuring linting rules, testing Ansible playbooks, validating playbook syntax, or setting up integration tests. Covers ansible-lint configuration and testing strategies.
Provides ansible-lint configuration and testing strategies for Ansible playbooks. Claude will use this when running ansible-lint, validating syntax, testing idempotency, or setting up integration tests.
/plugin marketplace add basher83/lunar-claude/plugin install ansible-workflows@lunar-claudeThis skill inherits all available tools. When active, it can use any tool Claude has access to.
references/testing-comprehensive.mdTesting strategies and ansible-lint configuration for Ansible automation.
# Via mise (recommended)
mise run ansible-lint
# Directly with uv
uv run ansible-lint ansible/playbooks/
# Specific file
uv run ansible-lint ansible/playbooks/my-playbook.yml
# With verbose output
uv run ansible-lint -v ansible/
Located at ansible/.ansible-lint:
---
# Profile: null, min, basic, moderate, safety, shared, production
profile: moderate
# Offline mode - don't download Galaxy requirements
offline: true
# Exclude paths
exclude_paths:
- .cache/
- .venv/
- .git/
- "*/templates/"
- "*.j2"
- .deprecated/
# Rules to skip completely
skip_list:
- var-naming[no-role-prefix] # We use descriptive names
- run-once[task] # Safe with our strategy
- command-instead-of-module # CLI tools require command
- yaml[line-length] # Long lines in infra configs
# Rules to warn but not fail
warn_list:
- fqcn[action-core]
- fqcn[action]
- no-handler
- name[play]
| Category | Description |
|---|---|
fqcn | Fully qualified collection names |
yaml | YAML formatting (indentation, line length) |
name | Task/play naming conventions |
command-instead-of-module | Using command when module exists |
no-changed-when | Missing changed_when on command |
risky-file-permissions | Missing explicit file permissions |
Missing name on task:
# BAD
- ansible.builtin.apt:
name: nginx
# GOOD
- name: Install nginx
ansible.builtin.apt:
name: nginx
Short module name:
# BAD (triggers fqcn warning)
- name: Install package
apt:
name: nginx
# GOOD
- name: Install package
ansible.builtin.apt:
name: nginx
Using shell instead of command:
# BAD (when no shell features needed)
- name: List files
ansible.builtin.shell: ls -la /tmp
# GOOD
- name: List files
ansible.builtin.command: ls -la /tmp
changed_when: false
Missing changed_when:
# BAD (always shows changed)
- name: Check status
ansible.builtin.command: systemctl status app
# GOOD
- name: Check status
ansible.builtin.command: systemctl status app
register: status_check
changed_when: false
failed_when: false
Validate playbook syntax before running:
# Check syntax only
uv run ansible-playbook --syntax-check playbooks/my-playbook.yml
# Check mode (dry run)
uv run ansible-playbook playbooks/my-playbook.yml --check
# Diff mode (show changes)
uv run ansible-playbook playbooks/my-playbook.yml --check --diff
Verify playbooks are idempotent by running twice:
# First run - may show changes
uv run ansible-playbook playbooks/setup.yml
# Second run - should show 0 changes
uv run ansible-playbook playbooks/setup.yml
# If second run shows changes, playbook is NOT idempotent
#!/bin/bash
set -euo pipefail
PLAYBOOK="$1"
echo "First run..."
uv run ansible-playbook "$PLAYBOOK"
echo "Second run (checking idempotency)..."
OUTPUT=$(uv run ansible-playbook "$PLAYBOOK" 2>&1)
if echo "$OUTPUT" | grep -q "changed=0"; then
echo "✓ Playbook is idempotent"
exit 0
else
echo "✗ Playbook is NOT idempotent"
echo "$OUTPUT" | grep -E "(changed|failed)="
exit 1
fi
# Limit to test hosts
uv run ansible-playbook playbooks/deploy.yml --limit test_hosts
# With verbose output
uv run ansible-playbook playbooks/deploy.yml --limit test_hosts -vv
Add validation tasks at playbook start:
---
- name: Deploy with validation
hosts: all
become: true
pre_tasks:
- name: Validate target environment
ansible.builtin.assert:
that:
- ansible_distribution == "Debian"
- ansible_distribution_major_version | int >= 11
fail_msg: "Requires Debian 11+"
- name: Check connectivity
ansible.builtin.ping:
- name: Verify disk space
ansible.builtin.assert:
that:
- ansible_mounts | selectattr('mount', 'equalto', '/') | map(attribute='size_available') | first > 1073741824
fail_msg: "Insufficient disk space"
Create test playbooks for validation:
# playbooks/test-role.yml
---
- name: Test role functionality
hosts: test_hosts
become: true
vars:
test_mode: true
roles:
- role: my_role
tasks:
- name: Verify service is running
ansible.builtin.systemd:
name: myservice
register: service_status
failed_when: service_status.status.ActiveState != "active"
- name: Verify config file exists
ansible.builtin.stat:
path: /etc/myservice/config.yml
register: config_stat
failed_when: not config_stat.stat.exists
- name: Verify port is listening
ansible.builtin.wait_for:
port: 8080
timeout: 10
name: Ansible Lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.13'
- name: Install uv
run: pip install uv
- name: Install dependencies
run: uv sync
- name: Run ansible-lint
run: uv run ansible-lint ansible/
# Increase verbosity
uv run ansible-playbook playbook.yml -v # Basic
uv run ansible-playbook playbook.yml -vv # More detail
uv run ansible-playbook playbook.yml -vvv # Connection debugging
uv run ansible-playbook playbook.yml -vvvv # Maximum detail
- name: Debug variable value
ansible.builtin.debug:
var: my_variable
- name: Debug with message
ansible.builtin.debug:
msg: "The value is {{ my_variable }}"
- name: Debug registered result
ansible.builtin.debug:
var: command_result
when: ansible_verbosity > 0
# Pause after each task
uv run ansible-playbook playbook.yml --step
Choose appropriate profile based on needs:
| Profile | Strictness | Use Case |
|---|---|---|
min | Lowest | Legacy code, quick fixes |
basic | Low | Development |
moderate | Medium | General infrastructure |
safety | High | Security-sensitive |
production | Highest | Production deployments |
For detailed testing patterns and techniques, consult:
references/testing-comprehensive.md - ansible-lint configuration, integration testing strategies, CI/CD patternsThis skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.