Thanks for considering a contribution — issues, pull requests, and discussion are all welcome. This project is small enough that a short read here should be all you need before opening a PR.
- Report a false positive/negative. The scanner is deterministic pattern matching; it will occasionally misjudge a real repository (a linter it doesn't recognize, a rule format it doesn't parse). These reports are the most valuable contribution there is — see tech-leads-club/fakeflix in our own history for an example of a real-world test that shipped several fixes.
- Propose or add a check. New tools, new conventions, new artifacts worth rewarding. See ROADMAP.md for what's already planned.
- Improve the guide. Docs fixes, clearer recipes, better examples.
- Fix a bug in the CLI, the plugin, or the GitHub Action.
Open an issue before a large PR (a new check, a check change) so we can agree on the approach first — check changes touch multiple files that must stay in sync (see below) and are easiest to get right with agreement up front. Small fixes (typos, docs, obvious bugs) can go straight to a PR.
packages/cli/ the scanner — TypeScript, ESM, zero runtime dependencies
src/checks/ one file per dimension
src/score.ts the maturity model (levels L0–L4)
test/ vitest; fixtures/level-0..4 pin each maturity level
docs/ the VitePress guide (deploys to GitHub Pages)
plugins/ one directory per editor/agent (cursor/, claude-code/, …),
plus shared/ (see PLUGINS-ROADMAP.md)
action/ the composite GitHub Action wrapping the CLI
Full conventions — written for agents, equally useful for humans — live in
AGENTS.md. Read it before touching packages/cli.
- The CLI stays deterministic. No LLM calls, no network, no telemetry,
no
Date.now()-dependent output. Filesystem reads and parsing only — a PR that breaks this will be asked to change approach. - Zero runtime dependencies in
packages/cli. Fastnpx, no supply chain surface. Dev dependencies are fine. - The maturity model lives in three places that must change together:
packages/cli/src/score.ts(implementation),docs/guide/maturity-model.md(levels),docs/guide/measure-and-improve.md(check catalog). A docs-sync test enforces that check IDs, points, and anchors match across all three —npm testwill fail loudly if you update one and not the others.
Check IDs (CTX-01, SNS-03, …) are public API: never renumber or reuse
one, even if a check is removed.
.github/CODEOWNERS auto-requests review on PRs touching checks, the
maturity model, the maturity docs, fixtures, or the release workflow — not a
gate, just a heads-up on the highest-stakes paths in the repo.
This is the highest-value contribution and the one most likely to need a design discussion first, because it changes what every existing repository scores:
- Open an issue using the Check change template, describing the artifact you want to detect and why it deserves points (or why an existing check's points/logic should change, or why a check should be removed).
- Implement the check in the relevant
packages/cli/src/checks/*.ts, wire it into the dimension total, and add/update fixtures underfixtures/level-0..4/so the maturity ladder still makes sense at every level. - Update
docs/guide/maturity-model.mdanddocs/guide/measure-and-improve.mdin the same PR —packages/cli/test/docs.test.tsandpackages/cli/test/maturity-sync.test.tsenforce that check IDs, points, dimension totals, and level thresholds all stay in sync acrossscore.tsand both docs pages;npm testfails loudly otherwise. - Run the full gate before opening the PR (see below).
.harness-score.json's extends key applies named, maintainer-curated
presets — bundles of per-check severity overrides (see Team customization
in the guide). This is deliberately not a free-form per-repo opt-out:
presets go through the same review that protects the check catalog, so a
badge that says "L3 under preset X" still means something comparable across
every repo that adopts X.
- Open an issue (the Check change template is close enough — describe
which checks the preset would set to
"off"and why the exclusion is structural, not a preference: a policy constraint, not "we don't feel like it"). Presets that reduce a whole dimension to zero applicable checks are the highest-scrutiny case, since they can cap the maturity ladder (see below). - Add the preset to
PRESET_REGISTRYinpackages/cli/src/config.ts. Derive its severity map fromALL_CHECKSwhere possible (filter by dimension or check ID) instead of hardcoding IDs, so it never drifts as the catalog changes. - If the preset excludes every check in a dimension that a
LEVEL_REQUIREMENTSentry depends on (dimAtLeastinscore.ts), the affected level becomes unreachable under that preset —computeLevelreports this ascappedwith acapReason, not as a silent pass. That's expected, not a bug to work around: don't add special-casing to let a preset "skip" a ladder requirement it structurally can't satisfy. - Document the preset in
docs/guide/metrics-and-codes.md's "Built-in presets" table with a{#preset-<name>}anchor matching the preset's key —packages/cli/test/docs.test.tsasserts everyPRESET_REGISTRYkey has one. Mirror the section indocs/pt-BR/guide/metrics-and-codes.mdtoo. - Add tests: severity resolution in
packages/cli/test/config.test.ts, and — if the preset can cap a level — acapped/capReasonassertion inpackages/cli/test/score.test.tsorscoring-integration.test.ts.
npm install
npm test # build + vitest — must pass
npm run lint # biome — lints and checks formatting
npm run scan # self-audit — this repo must stay at L4
npm run docs:build # builds the guide — dead links fail itCI runs the same checks; a red run will block review.
If your change is user-facing (a new/changed check, a CLI flag, a bug fix a
user would notice), add a changeset: npm run changeset, pick a bump type,
and describe the change — it becomes an entry in packages/cli/CHANGELOG.md
the next time a maintainer runs the release process. Skip it for
docs-only/internal changes.
Releases (versioning, publishing to npm/GitHub Packages/JSR, docs deploy) are handled by a maintainer — see RELEASING.md if you're picking that up.
Participation in this project is governed by our Code of Conduct.