Skip to main content
rule

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.

Install into Cursor · Manually: put the files in place All methods and platforms ↓
.cursor/rules/ansible.mdc
Open on GitHub

What 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.mdc

Frontmatter: description, globs, alwaysApply

Step 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.

From the same set240

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor