Enforce complexity, linting, tests, and CI so AI-written code stays decoupled, tractable, and commit-blocked until quality gates pass.
- AI-generated code tends to be tightly coupled and overly complex, creating technical debt quickly.
- As complexity grows, agents struggle to reason about the code and bugs become hard to troubleshoot.
- Manually enforcing tests and linting fails in practice—agents routinely forget to run them.
- This repo automates complexity, lint, and test gates via hooks and CI so the agent must fix issues before commit/push, keeping code manageable at any size.
- Automated setup / self-destruct installer
- Code metrics and quality gates (FTA, ESLint + SonarJS cognitive complexity; xenon/radon for Python)
- Tests must pass before commit/push (Husky or pre-commit enforced)
- Leaves lightweight scripts and a Safety Manual under
docs/ - Supports JavaScript/TypeScript (Vite/Vitest) and Python (uv + pytest)
Quick start (one-shot, no checkout):
# Frontend
bash <(curl -fsSL https://raw.githubusercontent.com/CaliLuke/quality-workflow-meta/main/docs/one-shot-installer.sh) --type frontend --pm bun
# Python
bash <(curl -fsSL https://raw.githubusercontent.com/CaliLuke/quality-workflow-meta/main/docs/one-shot-installer.sh) --type python
What happens
- Copies
bin/installer into your repo, runs the selected bootstrap, and (by default) self-destructs the installer. - Adds Git hooks and baseline configs; scaffolds CI workflows under
.github/workflows/. - Writes docs and analysis helpers under
docs/andscripts/. - Safe to revert: changes are standard files; remove or edit as needed.
Suggested workflow
- Create a feature branch.
- Run the installer (one-shot or local
bin/). - Review diffs, run local checks, and commit.
- Merge or delete the branch if undesired.
Alternatives
- Run from a local checkout of this repo:
- Frontend (TypeScript/React):
bash bin/bootstrap-frontend.sh- Ephemeral mode:
SELF_DESTRUCT=1 bash bin/bootstrap-frontend.sh - Use a specific package manager:
PM=pnpm bash bin/bootstrap-frontend.sh - Install dev dependencies (pick one):
- bun:
bun add -d eslint @eslint/js typescript-eslint eslint-plugin-react-hooks eslint-plugin-react-refresh eslint-plugin-sonarjs husky lint-staged vitest @testing-library/react @testing-library/jest-dom @testing-library/user-event jsdom typescript vite @vitejs/plugin-react-swc vite-plugin-checker fta-cli - pnpm:
pnpm add -D eslint @eslint/js typescript-eslint eslint-plugin-react-hooks eslint-plugin-react-refresh eslint-plugin-sonarjs husky lint-staged vitest @testing-library/react @testing-library/jest-dom @testing-library/user-event jsdom typescript vite @vitejs/plugin-react-swc vite-plugin-checker fta-cli - yarn:
yarn add -D eslint @eslint/js typescript-eslint eslint-plugin-react-hooks eslint-plugin-react-refresh eslint-plugin-sonarjs husky lint-staged vitest @testing-library/react @testing-library/jest-dom @testing-library/user-event jsdom typescript vite @vitejs/plugin-react-swc vite-plugin-checker fta-cli
- bun:
- Verify:
bun run verify
- Python:
bash bin/bootstrap.sh --type python(ephemeral via one‑shot above)- Sync dev tools (uv):
uv sync --all-groups - Enable hooks:
uv run pre-commit install - Verify:
uv run scripts/python_verify.sh - Reports:
uv run scripts/python_reports.sh(coverage.xml,htmlcov/,docs/analysis/*)
- Frontend (TypeScript/React):
- Or copy
docs/one-shot-installer.shinto your project and run:bash docs/one-shot-installer.sh --type frontend --pm bun(defaults to self-destruct)bash docs/one-shot-installer.sh --type python
- Scripts are idempotent and won’t overwrite existing configs without cause.
- Default setup excludes Storybook/Docker/backend docs sync; add them later if needed. (Note from original README)
- Ephemeral mode removes the
bin/installer after setup; the Safety Manual remains atdocs/safety-manual.md. - Security: Always review install scripts before piping to
bash.
- Runs once to scaffold configs, scripts, and hooks; leaves
docs/andscripts/for ongoing use. - Frontend: installs Husky hooks (
.husky/pre-commit,.husky/pre-push), ESLint (+ SonarJS), TypeScript, Vite, Vitest, and FTA complexity tools. - Python: writes
pyproject.toml,.pre-commit-config.yaml, and CI; uses uv for tooling, pytest for tests, xenon/radon for complexity. - Enforces tests and metrics locally: commits re-run lint, typecheck, tests, and FTA checks; pre-push runs lint + typecheck.
- CI mirrors local checks and uploads artifacts (coverage, analysis reports).
This section defines exactly what an AI (or a human) should do before committing or pushing changes. It starts with a common install step, then provides stack-specific flows.
- Create a feature branch, then install the safeguards in your repo using one of:
# Frontend (JavaScript/TypeScript)
bash <(curl -fsSL https://raw.githubusercontent.com/CaliLuke/quality-workflow-meta/main/docs/one-shot-installer.sh) --type frontend --pm bun
# Python
bash <(curl -fsSL https://raw.githubusercontent.com/CaliLuke/quality-workflow-meta/main/docs/one-shot-installer.sh) --type python
- The installer is ephemeral by default (self-destructs) and leaves standard files (hooks/configs/scripts) plus
docs/safety-manual.md. - After install, follow the appropriate stack section below.
- In the target project, add an
AGENT.md(orAgent.md) with the following working agreement to prevent “cheating” and skipped checks:
# Agent Working Agreement
1. Never skip checks: do not run `git commit --no-verify`, set `HUSKY=0`, remove/alter hooks, or bypass CI without explicit human approval.
2. Always run the full local gate before commit:
- JS/TS: `bun run complexity:json && bun scripts/check-fta-cap.mjs && bun run test`
- Python: `uv run scripts/python_verify.sh`
3. When blocked by hooks or tests, stop and report:
- Paste the failing command and top relevant error output.
- Propose a fix and request confirmation if risky.
4. Do not weaken thresholds or disable lint rules to pass:
- JS/TS: do not raise `FTA_HARD_CAP` or lower coverage thresholds without approval.
- Python: do not relax xenon flags or reduce coverage without approval.
5. Keep changes small and incremental; re-run checks after each change.
Prerequisites
- Node.js 20+ and a package manager (bun/pnpm/yarn). Install Bun v1+.
Steps
- Run metrics
bun run complexity:json
bun scripts/check-fta-cap.mjs
Pass/Fail
- Pass: proceed to tests. Output includes
[FTA] All files under cap (X). - Fail: commit blocked by complexity. Report:
FTA hard cap exceededand list offending files fromscripts/check-fta-cap.mjs. Suggest refactoring or lowering complexity before continuing.
- Run tests
bun run test
Pass/Fail
- Pass: proceed to commit.
- Fail: report which tests failed (Vitest output). Do not commit until passing.
- Commit (hook rechecks)
git add -A
git commit -m "<message>"
Hook behavior
- Pre-commit runs: lint-staged → typecheck → tests → FTA cap. If no tests exist, commit fails with:
No test files found (e.g., src/**/*.test.ts). Add at least one test before committing. - On FTA failure, commit fails with offending files and scores.
- Pre-push checks
bun run lint
bun run typecheck
- Push
git push
If your project uses different scripts, run them in the analogous step. For example, replace bun run test with your project’s test command. (Clarify: do not invent scripts; use actual ones in your repo.)
Related config files (JS/TS)
eslint.config.js,vitest.config.ts,.husky/*,scripts/check-fta-cap.mjs,scripts/compare-fta.mjs,scripts/generate-complexity-report.mjs.
Prerequisites
- Python 3.11+ recommended.
- Install uv (https://docs.astral.sh/uv/):
- macOS (Homebrew):
brew install uv - Linux/macOS (official):
curl -LsSf https://astral.sh/uv/install.sh | sh - Verify:
uv --version
- macOS (Homebrew):
Steps
- Run metrics (and reports)
uv sync --all-groups
uv run scripts/python_reports.sh
Pass/Fail
- Non-blocking reports write to:
coverage.xml,htmlcov/,docs/analysis/*.txt. For a blocking gate locally, run the verify script (next step).
- Run tests and gates
uv run scripts/python_verify.sh
What it does
- Ensures at least one pytest file exists; otherwise exits with:
[verify:py] No pytest files found (e.g., tests/test_example.py). Add tests before committing. - Runs ruff, black (check), isort (check-only), mypy, pytest, radon cc (non-blocking), and xenon (blocking complexity gate
--max-absolute B --max-modules B --max-average B). Pass/Fail - Pass: proceed to commit.
- Fail: report the first failing tool and its output; do not commit.
- Commit (hooks)
git add -A
git commit -m "<message>"
Hook behavior
- After
uv run pre-commit install, pre-commit enforces ruff/black/isort/mypy and a test-existence check on commit.
- Pre-push checks (optional but recommended)
uv run scripts/python_verify.sh
- Push
git push
Related config files (Python)
pyproject.toml,.pre-commit-config.yaml,scripts/python_verify.sh,scripts/python_reports.sh.
Frontend
- FTA hard cap:
FTA_HARD_CAPenv var (default 50). Used byscripts/check-fta-cap.mjsand CI. - FTA delta percent:
FTA_DELTA_PCTenv var (default 10). Used by PR quality gate. - ESLint complexity rules: in
eslint.config.jssetcomplexity: ['error', 15]andsonarjs/cognitive-complexity: ['error', 15]. - Coverage thresholds: edit
vitest.config.tsundertest.coverage.thresholds(lines, functions, branches, statements; defaults start low at 20% lines).
Python
- Xenon thresholds: adjust flags in
scripts/python_verify.shand.github/workflows/ci-python.yml(e.g.,--max-absolute B). - Coverage threshold: in
pyproject.tomlunder[tool.pytest.ini_options].addopts(--cov-fail-under=20). Ratchet up over time. - Lint/format/type: tune
[tool.ruff.*],[tool.black],[tool.isort],[tool.mypy]inpyproject.toml.
Example changes
- Increase FTA hard cap temporarily for a branch:
export FTA_HARD_CAP=60
bun run complexity:json && bun scripts/check-fta-cap.mjs
- Raise Vitest coverage lines from 20 to 30 in
vitest.config.ts:
# In vitest.config.ts
thresholds: {
lines: 30,
functions: 20,
branches: 10,
statements: 20,
},
- Increase Python coverage to 40 in
pyproject.toml:
# In pyproject.toml
[tool.pytest.ini_options]
addopts = "-q --cov --cov-report=term-missing:skip-covered --cov-report=xml:coverage.xml --cov-report=html:htmlcov --cov-fail-under=40"
- Projects started without safeguards that need a quick, enforceable baseline.
- Repos where AI agents make substantial changes and must be gated.
- Teams wanting local quality gates before CI or alongside it.
Common issues and fixes
- Tests missing (Frontend): pre-commit fails with:
No test files found (e.g., src/**/*.test.ts).Add at least one test file. - FTA cap exceeded:
scripts/check-fta-cap.mjslists offending files. Refactor or temporarily raiseFTA_HARD_CAPwith caution. - Hooks not firing (Frontend): ensure Husky is installed and
prepareexists inpackage.json(runbunx huskyor re-run bootstrap). Files:.husky/pre-commit,.husky/pre-push. - Hooks not installed (Python): run
uv run pre-commit install. Ensure.pre-commit-config.yamlis present. - CI failures (Frontend): check
.github/workflows/ci.ymlandquality-gate.ymllogs; ensure devDependencies installed and FTA artifacts generated (reports/fta.json). - CI failures (Python): review
.github/workflows/ci-python.yml. Coverage under threshold or xenon gate failing; adjust inpyproject.tomlor xenon flags if appropriate.
(Note from original README) Default setup excludes Storybook/Docker/backend docs sync; add later if needed.
- Issues and PRs are welcome. Useful areas: additional languages/stacks, improved reports, better defaults for thresholds, and documentation upgrades.
This project is licensed under the MIT License (see LICENSE). MIT permits use and modification as long as attribution is retained.