constraint-driven-development

github:addyosmani/agent-skills · first seen 2026-10-30 · source · badge

Establishes a project's quality bar as a written contract and stops agents quietly lowering it. Interviews the user on which dimensions matter, supplies sane default thresholds when they have no number in mind, records everything in CONSTRAINTS.md, and watches the diff for a weakened bar — new @ts-ignore or eslint-disable suppressions, skipped or deleted tests, assertions stripped out, unimplement

Works with

using-agent-skills
Shares development, bar, constraint, driven
0.16
interview-me
Shares constraint, development, down, driven
0.15
code-review-and-quality
Shares dimensions, diff, quality, written
0.14
test-driven-development
Shares development, tests, driven, green
0.14
tdd
Shares development, tests, driven, green
0.13

Used with

using-agent-skills
Shares development, bar, constraint, driven
0.16
ci-cd-and-automation
Shares eslint, quality, skipped, gates
0.12

Skill Health 100 (freshness and quality) estimated by backskills

Listed, not yet scored. This skill has no public model test yet. It is in the scoring queue; submitted skills go first, then the most-installed.

Freshness 100 · Quality 100 · Efficacy not yet tested

Version history

2026-10-31T09:00:38+00:00 · sha256 5a690018d415
2026-10-30T20:36:17 · sha256 313323d6a746

Diff at 2026-10-31T09:00:38+00:00

--- previous
+++ current
@@ -115,9 +115,9 @@
 | Lint | Zero errors from our config | `biome check` | every edit |
 | Secrets | No secrets in source | `gitleaks dir . --redact` | every edit |
 | Coverage | Changed lines ≥ 80% covered | `vitest run --coverage` + git diff | task end, CI |
-| Security: code | No high findings | `semgrep scan --config p/default` | CI |
+| Security: code | Nothing at high or above | `npm run check:security` | CI |
 | Security: deps | Nothing at high or above | `osv-scanner scan source -r .` | CI |
-| Accessibility | Zero critical or serious | `axe $PREVIEW_URL --tags wcag2a,wcag2aa,wcag21aa` | preview deploy |
+| Accessibility | Zero critical or serious | `npm run check:a11y` | preview deploy |
 | Performance | LCP ≤ 2500ms, CLS ≤ 0.1 | `lighthouse $PREVIEW_URL --output=json` | preview deploy |
 
 Every row names the command that produces the verdict. A dimension with a
@@ -150,12 +150,12 @@
 | Lint | your existing config | already there | `eslint .` / `biome check` / `ruff check` | any error |
 | Coverage (JS) | your test runner | Vitest: `npm i -D @vitest/coverage-v8`; Jest: already there | `vitest run --coverage` (or `jest --coverage`) | coverage of changed lines |
 | Coverage (Python) | pytest-cov | `pip install pytest-cov` | `pytest --cov --cov-report=lcov` | same |
-| Security: code | Semgrep | `pipx install semgrep` | `semgrep scan --config p/default --config p/owasp-top-ten` | any high finding |
+| Security: code | Semgrep | `pipx install semgrep` | `npm run check:security` (below) | high or critical, including legacy `ERROR` |
 | Security: secrets | gitleaks | `brew install gitleaks` | `gitleaks dir . --redact --no-banner` | any finding |
 | Security: dependencies | osv-scanner | `brew install osv-scanner` | `osv-scanner scan source -r .` | high or above |
 | Performance: page | Lighthouse | `npm i -D lighthouse` | `lighthouse $URL --output=json --quiet` | LCP, CLS, performance score |
 | Performance: bundle | size-limit | `npm i -D size-limit` | `size-limit --json` | per-entry byte budget |
-| Accessibility | axe-core | `npm i -D @axe-core/cli` | `axe $URL --tags wcag2a,wcag2aa,wcag21aa` | zero critical or serious |
+| Accessibility | axe-core | `npm i -D @axe-core/cli` | `npm run check:a11y` (below) | zero critical or serious |
 | Architecture | dependency-cruiser | `npm i -D dependency-cruiser` | `depcruise --validate src` | any violation |
 | Assertion quality | Stryker | `npm i -D @stryker-mutator/core` | `stryker run --mutate <changed files>` | mutation score |
 
@@ -167,6 +167,9 @@
 4. **Coverage needs no second test run.** Read the lcov your suite already writes and intersect it with `git diff`. Running the suite twice to get a number is the fastest way to make people hate this.
 5. **Semgrep's registry rules are free to run; check the licence before redistributing them.** `opengrep` is a drop-in fork with the same rule format and JSON output if that matters to your legal team.
 
+`semgrep scan` and `axe` can exit 0 on findings; copy [scripts/quality-gate.mjs](scripts/quality-gate.mjs) into the project's `scripts/` directory to enforce these thresholds.
+Keep the scanner before `&&` so a failed scan stops the command.
+
 Add each one to the project's own script so it's reproducible without an agent:
 
 ```json
@@ -174,12 +177,16 @@
   "scripts": {
     "check:fast": "tsc --noEmit && eslint . && gitleaks dir . --redact --no-banner",
     "check:task": "npm run check:fast && vitest run --coverage",
-    "check:full": "npm run check:task && semgrep scan --config p/default && osv-scanner scan source -r ."
+    "check:security": "semgrep scan --config p/default --strict --json > semgrep-results.json && node scripts/quality-gate.mjs semgrep semgrep-results.json",
+    "check:a11y": "axe \"$PREVIEW_URL\" --tags wcag2a,wcag2aa,wcag21aa --stdout > axe-results.json && node scripts/quality-gate.mjs axe axe-results.json",
+    "check:full": "npm run check:task && npm run check:security && osv-scanner scan source -r ."
   }
 }
 ```
 
-That mapping matters more than the tools. `check:fast` is what runs after an edit, `check:task` when the agent thinks it's done, `check:full` in CI.
+That mapping matters more than the tools. `check:fast` is what runs after an edit, `check:task` when the agent thinks it's done, `check:full` in CI. Run `check:a11y` after the preview is reachable, with `PREVIEW_URL` set (the example uses POSIX shell syntax).
+
+Before calling any row enforced, run its actual CI command against a known violation and a clean control. Confirm that the violation fails, the control passes, and scanner errors fail too. For a severity threshold, also confirm a below-threshold finding passes. Apply this to every dimension, including coverage and Lighthouse: generating a report alone does not enforce the number in `CONSTRAINTS.md`.
 
 The commands now live in two places — the `Checked by` column in `CONSTRAINTS.md` and these scripts. `CONSTRAINTS.md` is the canonical source: it carries the reason alongside each command and it shows up in review. The scripts are convenience wrappers that must mirror it, not a second source of truth; if they drift, the file wins.
 
@@ -300,6 +307,7 @@
 - [ ] Exceptions have an owner and an expiry date
 - [ ] `AGENTS.md` or `CLAUDE.md` points at the file
 - [ ] A trial run on the current branch produces no failures the user disagrees with
+- [ ] Each enforced command fails on a deliberate violation and scanner error, passes a clean control, and preserves the agreed severity threshold
 
 ## See Also