Doolta
ansible-static-lint
GitHub →Ansible linting went from a minute to milliseconds the day the runtime was removed: 38 ansible-lint rules reimplemented in Go, byte-for-byte identical output.

Project Details
- The problemAnsible linting drags CI processing time down: 46.8 s to pass a 478-file corpus, 2.1 s for a 6-line playbook. On every push, in pre-commit, or on editor save, that wait breaks the feedback loop.
- The analysisThe cost is not in the rules, it is in launching Ansible: the Python interpreter, imports, collection resolution, a syntax-check subprocess, all before the first check runs. Even
ansible-lint --versioncosts half a second. A rule itself is just a predicate over an already-parsed document: its marginal cost is measured in microseconds. - The intuitionWhat if we only did the static analysis? Most rules can be decided from the YAML source alone, with no Ansible runtime. A binary that parses YAML and applies predicates only pays for startup, I/O and parsing: the number of rules becomes almost free.
- The smart executionSorting ansible-lint’s 51 default rules: 38 are statically decidable and reimplemented in Go, the 13 that need the runtime stay with the original. Within that scope, compatibility is total: pep8 output reproduced byte for byte,
.ansible-lintconfig andnoqacomments unchanged, a contract frozen on the ansible-lint 26.8.0 corpus. Result: from a minute to milliseconds (37 ms on the corpus, 2.2 ms cold start), withmake benchfailing the build past 150 ms. - Associated offerBuilds on the DevOps Sprint offer: shortening CI feedback loops and hardening tooling.
A pipeline that waits 47 seconds for its linter has a problem, and that problem is not the linting: it is launching Ansible. astl starts from that diagnosis and follows it all the way: if the runtime is the cost, remove the runtime, and keep every rule that never needed it. 38 of ansible-lint’s 51 default rules, reimplemented in Go, delivered in milliseconds, with the same output byte for byte.
The winning pipeline runs both: astl on every push for the rules that block most CI runs, ansible-lint nightly for the 13 rules that need the runtime. This project demonstrates a directly transferable capability: finding where the time actually goes, deriving an architecture from it, and locking the result down with a compatibility contract and a performance guard.