Normalized linting, formatting, and CI for eustasy applications. Covers HTML, Markdown, JS/TS, CSS/SCSS, Python, PHP, XML, JSON, SQL, YAML, and Shell.
Powered by Qlty.
git clone https://github.com/eustasy/.normal.git &&
cp .normal/install.sh install.sh &&
chmod 755 install.sh &&
./install.sh &&
rm install.sh &&
rm -Rf .normal
git add -A
git commit -m "Install eustasy/.Normal 4.0beta11"
git push| File | Purpose |
|---|---|
.editorconfig |
Universal editor settings (indent, line length) |
.vscode/settings.json |
Format-on-save + recommended extensions |
.qlty/qlty.toml |
Qlty orchestration: plugins, smells, exclusions |
.qlty/configs/oxlint.json |
JS/TS linter (OXC) |
.qlty/configs/.stylelintrc.json |
CSS/SCSS linter |
.qlty/configs/.markdownlint.jsonc |
Markdown linter |
.qlty/configs/.htmlvalidate.json |
HTML linter (void-style: selfclosing) |
.qlty/configs/ruff.toml |
Python lint + format |
.qlty/configs/.php-cs-fixer.php |
PHP formatter |
.qlty/configs/.sqlfluff |
SQL lint + format (default dialect: mysql) |
.qlty/configs/.prettierrc.json |
Prettier config (JS/TS, JSON) |
.github/dependabot.yml |
Automated dependency updates (only ecosystems whose manifests are present) |
.github/workflows/security.yml |
Security scanning (every push) |
.github/workflows/{language}.yml |
Per-language lint + format CI |
.github/workflows/test-{language}.yml |
Test + coverage CI (activate by removing if: false) |
.github/workflows/type-{language}.yml |
Typecheck CI — TS (tsc), Python (mypy) (activate by removing if: false) |
The CI workflows trigger on pushes and pull requests to main. If your repository's
default branch is not main, the workflows will never run until you update them.
GitHub Actions does not allow referencing the default branch dynamically in the on:
trigger, so the branch name must be set explicitly. After running install.sh, replace
main in the branches: filters across .github/workflows/*.yml:
# example: default branch is `trunk`
sed -i 's/branches: \[main\]/branches: [trunk]/' .github/workflows/*.yml| Plugin | Language | Lint | Format |
|---|---|---|---|
| oxc | JS / TS | Yes | — |
| knip | JS / TS | Yes | — |
| prettier | JS/TS, JSON | — | Yes |
| stylelint | CSS / SCSS | Yes | Yes |
| markdownlint | Markdown | Yes | — |
| html-validate | HTML | Yes | — |
| xmllint | XML | Yes | — |
| ruff | Python | Yes | Yes |
| phpstan | PHP | Yes | — |
| php-cs-fixer | PHP | — | Yes |
| sqlfluff | SQL | Yes | Yes |
| shellcheck | Shell | Yes | — |
| shfmt | Shell | — | Yes |
| yamllint | YAML | Yes | — |
| actionlint | YAML (GH Actions) | Yes | — |
| zizmor | YAML (GH Actions) | Yes | — |
| dotenv-linter | .env |
Yes | — |
| gitleaks | All | Yes | — |
| trivy | All | Yes | — |
| osv-scanner | All | Yes | — |
The default SQL dialect is mysql. To override it in a project, add or edit
.qlty/configs/.sqlfluff after running install.sh:
[sqlfluff]
dialect = postgresAny dialect supported by SQLFluff is valid (e.g. postgres, sqlite, tsql, ansi).
git clone https://github.com/eustasy/.normal.git &&
cp .normal/install.sh install.sh &&
chmod 755 install.sh &&
./install.sh &&
rm install.sh &&
rm -Rf .normal;
git add -A;
git commit -m "Migrate to eustasy/.Normal 4.0beta11 (Qlty)";
git pushThen:
- Connect the repo on qlty.sh (replaces Code Climate)
- Add
QLTY_COVERAGE_TOKENto repo secrets (Settings → Secrets → Actions) - Remove the
if: falseguard from whichever test/typecheck workflows apply to the repo
install.sh will automatically delete the old .codeclimate.yml, .eslintrc.json,
.stylelintrc.json, .mdlrc, and related files.
Files are kept out of scope two ways:
- Git. Gitignored paths are never linted. qlty respects
.gitignore, and the JSON, JS, XML, and HTML workflows go further by feeding onlygit ls-filesoutput (tracked files) to their tool — so build output, dependencies, and machine-managed files stay out without needing a pattern. - qlty
exclude_patterns. Tracked files matching these are skipped by every qlty-driven plugin:
**/*.min.* **/*.pack.* **/*.custom.* **/_libs/**
**/vendor/** **/node_modules/** **/dist/** **/build/**
**/out/** **/coverage/** **/__pycache__/** **/.pytest_cache/**
xmllint and html-validate run outside qlty, so they obey git tracking only —
the patterns above do not apply to XML or HTML. To drop an XML or HTML file
from CI, add it to .gitignore.