ansible · sanjeed5 — Cursor rule: what it does, how to install
Enforces Ansible standards in Cursor: role structure, clean YAML formatting, idempotency, and Jinja2 template handling.
.cursor/rules/ansible.mdcWhat ansible does
This rule guides Cursor to generate structured Ansible code instead of monolithic playbooks. It forces tasks into focused roles and collections, isolating setup logic and delegating information gathering to dedicated _facts tasks.
The guide mandates strict YAML syntax. Cursor stops using inline key=value strings for module parameters, switching to structured dictionaries. Every file must begin with ---, use two-space indentation, and standard boolean values like true or false.
Forcing declarative modules over raw shell or command runs guarantees idempotency. When files need editing, atomic operations via template or copy prevent incomplete writes from breaking system states.
What it helps with
- split monolithic playbooks into reusable roles
- refactor legacy key=value module parameters into structured YAML
- replace fragile shell scripts with declarative idempotent tasks
- organize role variables between defaults and inventory configs
Example prompts for the agent
- Generate an Ansible role to install and configure PostgreSQL
- Refactor this shell task into an idempotent ansible.builtin module
- Convert these legacy key=value task arguments into structured YAML maps
How to install ansible
Manually: put the files in place
.cursor/rules/ansible.mdcFrontmatter: description, globs, alwaysApply
Manually: put the files in place
.claude/rules/ansible.mdThe paths frontmatter field limits the files: move globs from the source into paths
AGENTS.md
Codex reads AGENTS.md: paste the rule text there
Manually: put the files in place
.github/instructions/ansible.instructions.mdThe applyTo field sets which files it applies to: move globs from the source into applyTo
Manually: put the files in place
.devin/rules/ansible.mdManually: put the files in place
.clinerules/ansible.mdStep by step, with commands for each platform: Cursor rules: .mdc files, four modes and what replaced .cursorrules
Questions about ansible
How to install the ansible rule in Cursor?
Create .cursor/rules/ansible.mdc in your project root and paste the rule text into the file.
What does this rule do?
It guides Cursor to generate clean YAML, enforce role-based project architecture, and write idempotent tasks instead of raw shell commands.
How does this rule handle module parameters and naming?
All variables, tasks, and filenames must follow snake_case. Module options use structured mapping blocks rather than inline strings, and octal file modes require quotes.
Source text
ansible.mdc · CC0-1.0
---
description: This guide defines definitive best practices for writing maintainable, performant, and robust Ansible code, focusing on modern YAML hygiene, role design, and CI/CD integration.
globs: **/*
---
# ansible Best Practices
Ansible excels when treated as infrastructure-as-code. These guidelines ensure your playbooks, roles, and modules are consistent, idempotent, and production-ready.
## 1. Code Organization and Structure
**Always structure your Ansible content into roles and collections.** Roles encapsulate specific functionalities, while collections group related roles, modules, and plugins, promoting reusability and discoverability.
- **Role Scoping:** Each role or module must focus on a single, well-defined task. Avoid monolithic roles.
❌ BAD:
```yaml
# roles/webserver/tasks/main.yml
- name: Install Nginx
ansible.builtin.apt: name=nginx state=present
- name: Configure Nginx
ansible.builtin.template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
- name: Start Nginx
ansible.builtin.service: name=nginx state=started
- name: Install PHP-FPM
ansible.builtin.apt: name=php-fpm state=present
# ... and more
```
✅ GOOD:
```yaml
# roles/nginx/tasks/main.yml
- name: Ensure Nginx is installed and configured
ansible.builtin.include_tasks: setup.yml
- name: Ensure Nginx service is running
ansible.builtin.service: name=nginx state=started enabled=true
# roles/php-fpm/tasks/main.yml
- name: Ensure PHP-FPM is installed and configured
ansible.builtin.include_tasks: setup.yml
```
- **Fact Modules:** Create dedicated `_info` or `_facts` modules/tasks for gathering information, rather than overloading existing ones.
✅ GOOD:
```yaml
# roles/system_facts/tasks/main.yml
- name: Gather custom system facts
ansible.builtin.set_fact:
custom_os_version: "{{ ansible_facts['distribution_major_version'] }}"
```
## 2. YAML Hygiene and Syntax
**Enforce strict YAML formatting.** Consistent syntax improves readability and prevents subtle parsing errors.
- **File Start:** All YAML files must begin with `---`.
- **Indentation:** Use two spaces for indentation, never tabs.
- **Quotes:** Quote strings only when necessary (e.g., when they contain special characters or Jinja map references). Prefer single quotes. Use double quotes for escaping characters or multi-line strings.
❌ BAD:
```yaml
- name: "Install a package"
ansible.builtin.apt: name="my-package" state="present"
- name: Set fact
set_fact:
myvar: '{{ item["key"] }}' # Incorrect quoting for Jinja map
```
✅ GOOD:
```yaml
---
- name: Install a package
ansible.builtin.apt:
name: my-package
state: present
- name: Set fact
ansible.builtin.set_fact:
my_var: "{{ item['key'] }}" # Double quotes for Jinja map
- name: Print multi-line message
ansible.builtin.debug:
msg: |
This is line one.
This is line two.
```
- **Colon Spacing:** Use exactly one space after a colon in key-value pairs.
❌ BAD:
```yaml
- name : start service
service:
name : my_service
state : started
```
✅ GOOD:
```yaml
- name: start service
ansible.builtin.service:
name: my_service
state: started
```
- **Structured Map Style:** Always use the structured map style for module parameters, not the legacy `key=value` style.
❌ BAD:
```yaml
- name: Create directory
ansible.builtin.file: path=/opt/app state=directory mode=0755
```
✅ GOOD:
```yaml
- name: Create directory
ansible.builtin.file:
path: /opt/app
state: directory
mode: '0755' # Quote octal modes
```
- **Booleans:** Standardize on `true`/`false`.
❌ BAD:
```yaml
- name: Enable service
ansible.builtin.service: name=my_service enabled=yes
become: True
```
✅ GOOD:
```yaml
- name: Enable service
ansible.builtin.service: name=my_service enabled=true
become: true
```
## 3. Naming Conventions
**Adopt consistent `snake_case` naming.** This applies to variables, tasks, files, and role names. Prefix role names with the collection namespace to prevent collisions.
- **Variables, Tasks, Files:**
❌ BAD:
```yaml
# vars/main.yml
myVariable: "value"
My_Task_Name: "Install Software"
```
✅ GOOD:
```yaml
# vars/main.yml
my_variable: "value"
# tasks/install_software.yml
- name: Install software
ansible.builtin.apt: name=software state=present
```
- **Role Names:**
✅ GOOD: `my_namespace.my_collection.webserver`
## 4. Idempotency and Declarative Style
**Write idempotent tasks.** Running a playbook multiple times should yield the same result without unintended side effects. Favor declarative modules over imperative `command` or `shell`.
- **Declarative Modules:**
❌ BAD:
```yaml
- name: Check if file exists and create if not
ansible.builtin.shell: |
if [ ! -f /etc/myapp.conf ]; then
cp /etc/myapp.conf.template /etc/myapp.conf
fi
args:
creates: /etc/myapp.conf # Still imperative logic
```
✅ GOOD:
```yaml
- name: Ensure myapp.conf exists
ansible.builtin.copy:
src: myapp.conf.template
dest: /etc/myapp.conf
owner: root
group: root
mode: '0644'
backup: true # Idempotent file management
```
- **Atomic File Operations:** Always use `atomic_move` (implicitly via `copy`, `template` modules) for file modifications to prevent data corruption.
## 5. Configuration Management
**Manage configurations with templates and structured variables.**
- **Templates:** Use Jinja2 templates (`template` module) for dynamic configuration files.
- **Variables:** Define role variables in `defaults/main.yml` (overridable) and `vars/main.yml` (not overridable by inventory/extra-vars). Prefer inventory variables for host-specific data.
❌ BAD:
```yaml
# playbook.yml
- hosts: webservers
vars:
nginx_port: 8080 # Hardcoded in playbook
tasks:
- name: Configure Nginx
ansible.builtin.template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
```
✅ GOOD:
```yaml
# roles/nginx/defaults/main.yml
nginx_port: 80 # Default port
# inventory/group_vars/webservers.yml
nginx_port: 8080 # Override default for webservers group
# roles/nginx/templates/nginx.conf.j2
listen {{ nginx_port }};
```
## 6. Performance Considerations
**Optimize playbook execution for speed.**
- **Fact Gathering:** Disable fact gathering (`gather_facts: false`) if not explicitly needed. Use `setup` or `ansible.builtin.gather_facts` module selectively.
❌ BAD:
```yaml
- hosts: all
# gather_facts: true by default, even if not used
tasks:
- name: Ping all hosts
ansible.builtin.ping:
```
✅ GOOD:
```yaml
- hosts: all
gather_facts: false # No facts needed for ping
tasks:
- name: Ping all hosts
ansible.builtin.ping:
```
- **Parallelism:** Leverage Ansible's parallelism by default, but be mindful of resource constraints.
## 7. Error Handling and Logging
**Implement robust error handling and informative logging.**
- **Fail Gracefully:** Use `fail_json` (in custom modules) or `ansible.builtin.fail` for clear error messages. Avoid raw tracebacks.
✅ GOOD:
```yaml
- name: Ensure critical variable is defined
ansible.builtin.fail:
msg: "Required variable 'app_version' is not defined."
when: app_version is not defined
```
- **Debug Verbosity:** Use the `ansible.builtin.debug` module with verbosity levels for controlled output.
✅ GOOD:
```yaml
- name: Show debug info
ansible.builtin.debug:
var: my_variable
when: ansible_verbosity >= 2 # Only show with -vv or higher
```
## 8. Testing and Linting
**Integrate linting and testing into your development workflow.**
- **Ansible Lint:** Run `ansible-lint` on every pull request. It enforces the official style guide and detects common issues.
- **Ansible Test:** Use `ansible-test` for unit and integration testing of custom modules and roles.
✅ GOOD:
```bash
# In your CI pipeline or pre-commit hook
ansible-lint .
ansible-test sanity --test flake8 --test ansible-doc --test pep8 # For custom modules
```
## 9. CI/CD Integration
**Embed Ansible into your automated CI/CD pipelines.**
- **Git Triggers:** Trigger playbook runs on Git pushes to automatically provision or update infrastructure.
- **Collections:** Store reusable roles and modules in Ansible Collections (Galaxy or private registries) for easy dependency management.
- **Pipeline Checks:** Include `ansible-lint` and collection dependency checks in your CI pipeline.
✅ GOOD:
```yaml
# .github/workflows/ansible.yml
name: Ansible CI/CD
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Ansible and dependencies
run: pip install ansible ansible-lint
- name: Run Ansible Lint
run: ansible-lint .
deploy:
runs-on: ubuntu-latest
needs: lint
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Install Ansible Collections
run: ansible-galaxy collection install -r requirements.yml
- name: Run Playbook
env:
ANSIBLE_VAULT_PASSWORD: ${{ secrets.ANSIBLE_VAULT_PASSWORD }}
run: ansible-playbook -i inventory/prod.yml site.yml --vault-password-file /dev/stdin
```
© sanjeed5 · CC0-1.0 · sanjeed5/awesome-cursor-rules-mdc
Similar IDE rules
All IDE rules for DevOps and infrastructure →ansible by other authors comes first.