Contributing to Ansible-lint

To contribute to ansible-lint, please use pull requests on a branch of your own fork.

After [creating your fork on GitHub], you can do:

$ git clone
$ cd ansible-lint
$ git checkout -b your-branch-name
$ git add your new files
$ git commit -v
$ git push origin your-branch-name

You will then be able to create a pull request from your commit.

All fixes to core functionality (i.e. anything except docs or examples) should be accompanied by tests that fail prior to your change and succeed afterwards.

Feel free to raise issues in the repo if you feel unable to contribute a code fix.


ansible-lint is flake8 compliant with max-line-length set to 100.

ansible-lint works only with supported Ansible versions at the time it was released.

Automated tests will be run against all PRs for flake8 compliance and Ansible compatibility — to check before pushing commits, just use tox.

Module dependency graph

Extra care should be taken when considering adding any dependency. Removing most dependencies on Ansible internals is desired as these can change without any warning.

$ pipdeptree -p ansible-lint
  - ansible-compat [required: >=2.0.4, installed: 2.0.4]
    - PyYAML [required: Any, installed: 6.0]
    - subprocess-tee [required: >=0.3.5, installed: 0.3.5]
  - ansible-core [required: >=2.12.0, installed: 2.13.0]
    - cryptography [required: Any, installed: 37.0.2]
      - cffi [required: >=1.12, installed: 1.15.0]
        - pycparser [required: Any, installed: 2.21]
    - jinja2 [required: >=3.0.0, installed: 3.1.2]
      - MarkupSafe [required: >=2.0, installed: 2.1.1]
    - packaging [required: Any, installed: 21.3]
      - pyparsing [required: >=2.0.2,!=3.0.5, installed: 3.0.9]
    - PyYAML [required: Any, installed: 6.0]
    - resolvelib [required: >=0.5.3,<0.6.0, installed: 0.5.4]
  - enrich [required: >=1.2.6, installed: 1.2.7]
    - rich [required: >=9.5.1, installed: 12.4.1]
      - commonmark [required: >=0.9.0,<0.10.0, installed: 0.9.1]
      - pygments [required: >=2.6.0,<3.0.0, installed: 2.12.0]
      - typing-extensions [required: >=4.0.0,<5.0, installed: 4.2.0]
  - jsonschema [required: >=4.5.1, installed: 4.5.1]
    - attrs [required: >=17.4.0, installed: 21.4.0]
    - importlib-resources [required: >=1.4.0, installed: 5.7.1]
      - zipp [required: >=3.1.0, installed: 3.8.0]
    - pyrsistent [required: >=0.14.0,!=0.17.2,!=0.17.1,!=0.17.0, installed: 0.18.1]
  - packaging [required: Any, installed: 21.3]
    - pyparsing [required: >=2.0.2,!=3.0.5, installed: 3.0.9]
  - pytest [required: Any, installed: 7.1.2]
    - attrs [required: >=19.2.0, installed: 21.4.0]
    - iniconfig [required: Any, installed: 1.1.1]
    - packaging [required: Any, installed: 21.3]
      - pyparsing [required: >=2.0.2,!=3.0.5, installed: 3.0.9]
    - pluggy [required: >=0.12,<2.0, installed: 1.0.0]
    - py [required: >=1.8.2, installed: 1.11.0]
    - tomli [required: >=1.0.0, installed: 2.0.1]
  - pyyaml [required: Any, installed: 6.0]
  - rich [required: >=9.5.1, installed: 12.4.1]
    - commonmark [required: >=0.9.0,<0.10.0, installed: 0.9.1]
    - pygments [required: >=2.6.0,<3.0.0, installed: 2.12.0]
    - typing-extensions [required: >=4.0.0,<5.0, installed: 4.2.0]
  - ruamel.yaml [required: >=0.15.34,<0.18, installed: 0.17.21]
    - ruamel.yaml.clib [required: >=0.2.6, installed: 0.2.6]
  - wcmatch [required: >=7.0, installed: 8.3]
    - bracex [required: >=2.1.1, installed: 2.2.1]
  - yamllint [required: >=1.25.0, installed: 1.26.3]
    - pathspec [required: >=0.5.3, installed: 0.9.0]
    - pyyaml [required: Any, installed: 6.0]
    - setuptools [required: Any, installed: 62.3.1]

Adding a new rule

Writing a new rule is as easy as adding a single new rule, one that combines implementation, testing and documentation.

One good example is MetaTagValidRule which can easily be copied in order to create a new rule by following the steps below:

  • Use a short but clear class name, which must match the filename

  • Pick an unused id, the first number is used to determine rule section. Look at rules page and pick one that matches the best your new rule and ee which one fits best.

  • Include experimental tag. Any new rule must stay as experimental for at least two weeks until this tag is removed in next major release.

  • Update all class level variables.

  • Implement linting methods needed by your rule, these are those starting with match prefix. Implement only those you need. For the moment you will need to look at how similar rules were implemented to figure out what to do.

  • Update the tests. It must have at least one test and likely also a negative match one.

  • If the rule is task specific, it may be best to include a test to verify its use inside blocks as well.

  • Optionally run only the rule specific tests with a command like: tox -e py38-core -- -k NewRule

  • Run tox in order to run all ansible-lint tests. Adding a new rule can break some other tests. Update them if needed.

  • Run ansible-lint -L and check that the rule description renders correctly.

  • Build the docs using tox -e docs and check that the new rule is displayed correctly in them.