QUALITY.md is an open file format for declaring a project's quality model: which qualities matter (security, testability, whatever you choose), what each one requires, and how an evaluator should check it. It lives in the repo root as YAML frontmatter plus a Markdown body, sits next to AGENTS.md, and comes with a /quality agent skill and a qualitymd CLI. The current release is qualitymd 0.35.2, implementing specification 0.12 (Draft), MIT licensed. I installed it, ran it against a small TypeScript package that already had AGENTS.md and CLAUDE.md, and wrote down what changed.
Quick take:
npm i -D quality.md@0.35.2, thennpx qualitymd init --no-agent-instructionsif you don't want your agent files edited.qualitymd lintexits 1 on errors, so it works as a CI gate in one line. It validates structure only. The untouched template, placeholders included, passes.
One honest limit before anything else. The loop the project is built around (/quality evaluate, /quality improve) drives a coding agent, and I didn't run it. Everything measured below is the deterministic CLI.
What Is QUALITY.md, and How Is It Different From AGENTS.md?
QUALITY.md describes what "good" means for a project and how to check it, while AGENTS.md tells a coding agent how to work: which commands to run, which folders to leave alone. The first is a typed model a tool can validate. The second is free-form prose that nothing checks.
| AGENTS.md | QUALITY.md | |
|---|---|---|
| Content | free-form instructions | typed model in YAML + context in Markdown |
| Validated by | nothing | qualitymd lint, JSON Schema via qualitymd schema |
| Main unit | a rule or command | a requirement with an assessment |
| Status | widely read by coding agents | spec 0.12 Draft, "early alpha" per its README |
The format's author launched it as a Show HN on July 2, 2026, where it collected 29 points and 29 comments. The thread was split. One commenter argued the same content already fits in AGENTS.md or a skill; another asked for even one benchmark showing it improves agent output. Neither got a number back, and the README still doesn't offer one. Is that a dealbreaker? Not for the file itself, which works as plain documentation even if no agent ever opens it.
What Does a QUALITY.md Schema Look Like?
A valid model needs three things: a title, a ratingScale ordered from best to worst with a criterion on every level, and at least one of factors, requirements or areas. Here's the smallest honest file I could write for a two-function TypeScript package:
---
title: demo-api
ratingScale:
- level: target
title: Target
description: Good enough to ship.
criterion: "Satisfies the requirement."
- level: unacceptable
title: Unacceptable
description: Blocks a release.
criterion: "Does not meet the requirement."
factors:
type-safety:
title: Type safety
description: Public functions are typed so callers and agents get compiler feedback.
requirements:
no-implicit-any:
title: no implicit any in src
assessment: Run tsc with strict enabled and confirm zero errors under src/.
---
The vocabulary is small. A factor is a quality dimension such as type safety or reliability. A requirement is one expectation you can assess, and an assessment is the instruction for checking it, written inline or as a pointer to an existing runbook or test plan. An area is a narrower part of the project, say one service folder, that deserves its own factors. Names must match ^[A-Za-z0-9](?:[A-Za-z0-9_-]*[A-Za-z0-9])?$, so dots and slashes are out, and root is reserved.
Every element also gets a stable ID: qualitymd model tree printed factor:root::type-safety and requirement:root::no-implicit-any for the file above. How big does a real model get? The project's own QUALITY.md runs to 710 lines, and model tree counts 10 areas (root included), 38 factors and 30 requirements in it. It lints clean.
How Do You Add QUALITY.md to an Existing Repo?
Install the CLI as a pinned dev dependency, run init, and read the diff before committing, because init edits more than one file by default. The pin matters: the README calls the format early alpha, and npm lists 60 releases between June 12 and July 15, 2026.
npm i -D quality.md@0.35.2npx qualitymd init, adding--no-agent-instructionsif your agent files are off limitsnpx qualitymd lint QUALITY.md- Replace every placeholder by hand, then commit
On the test package, init wrote a 7.8 KB QUALITY.md and printed Agent instructions: AGENTS.md, CLAUDE.md. Both files got the same two lines appended:
- Use strict TypeScript.
+
+<!-- Added by qualitymd init. -->
+See [QUALITY.md](QUALITY.md) for this project's quality model.
Harmless, but it touches files your team probably reviews line by line. The --no-agent-instructions flag skips that, and --minimal drops the long guidance comments from the template. A second init refused with QUALITY.md already exists; pass --force to overwrite and exit code 70, so you can't clobber a finished model by accident.
Why Does the Template Pass Lint Before You Write a Word?
I ran qualitymd lint on the freshly generated file, still full of <the system, component, or artifact this model is about> placeholders, and got QUALITY.md is valid. with exit 0.
Correct by the spec, which defines structure and not content. Still a trap. The monorepo behind this site hit the same pattern elsewhere: a bare tsc --noEmit at a root with project references reported success while checking nothing.
A passing QUALITY.md lint proves the YAML has the right shape, not that anyone on the team has agreed what quality means.
What Does qualitymd lint Catch, and What Won't --fix Repair?
The linter rejects missing required fields and references that don't resolve, and it exits 1 when it finds any error. To see real findings I broke a copy on purpose: dropped one criterion, one assessment and one factor description, then pointed a requirement at a factor that doesn't exist. Output from 0.35.2, verbatim:
warning missing-factor-description: The factor `type-safety` declares no `description`; a description is recommended for each factor. (factors.type-safety.description)
error invalid-assessment: The requirement `no-implicit-any` has no `assessment`; a requirement must declare exactly one non-empty scalar assessment. (factors.type-safety.requirements.no-implicit-any.assessment)
error missing-criterion: A rating level declares no `criterion`; each rating level requires a non-empty criterion. (ratingScale[0].criterion)
error unknown-factor: The requirement `readme-current` references unknown factor `docs`; factor references must resolve within the declaring area. (requirements.readme-current.factors.0)
3 error(s), 1 warning(s).
Three errors, one warning, exit code 1. Every message names the rule ID and the exact model path. Running qualitymd lint --fix on the same file changed zero bytes and still exited 1. The JSON report says why: every finding came back with "fixable": false. Don't expect --fix to behave like eslint --fix; it applies deterministic repairs only, and none of these four qualified. Would an automatic fix even make sense here? Not really. A missing assessment is a decision nobody has made yet.
How Do You Run QUALITY.md Lint in CI?
Add one step that runs qualitymd lint QUALITY.md --json on every pull request, and the non-zero exit fails the job. The project's own CI runs the same lint QUALITY.md --json command against its own model with QUALITYMD_NO_UPDATE_CHECK=1 and NO_COLOR=1 set, so the workflow below copies both variables:
name: quality-model
on: [pull_request]
jobs:
lint-quality-md:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- run: npx qualitymd lint QUALITY.md --json
env:
QUALITYMD_NO_UPDATE_CHECK: "1"
NO_COLOR: "1"
I ran those commands locally, not inside GitHub Actions, so treat the file as a template rather than a tested workflow. Two things I could measure. Lint itself is quick: a median of 104 ms for the direct binary and 124 ms through the npm launcher, over 30 runs on an Apple M1, and the 710-line upstream model took 104 ms and 131 ms. Process startup dominates, so file size barely registers. The install is the heavy part. The npm package is a tiny launcher, and the real binary arrives as a platform-specific optional dependency: for linux-x64, the 0.35.2 tarball is 36.8 MB and unpacks to 95.2 MB.
Cache ~/.npm (the cache: npm line does it) and the added time per pull request should stay small. Should a CLI you'll mostly use as a linter be a 37 MB download, though? For a project at this stage, it's a fair question.
Should You Adopt QUALITY.md Yet?
Adopt the file format, and hold off on building process around the tooling. Writing each requirement with an explicit assessment is useful discipline whether or not an agent ever reads it, and it pairs well with the quality gates for AI-generated code you may already run. If your team keeps a quality framework for vibe-coded TypeScript, QUALITY.md gives it a machine-readable home.
The project itself is young. On September 29, 2026 the GitHub repo showed 33 stars and zero forks, and the last commit on main was the 0.35.2 release on July 15. A quiet repo isn't a dead one, but two and a half months without a commit is a reason to pin versions and keep your model small enough to rewrite by hand. Nothing else in your agent setup has to change, whether that's a Claude Code workflow for React or a plain AGENTS.md.
Every CLI behavior described here (exit codes, rule IDs, --fix, the init diff) is asserted in a quality-md-lint code example kept in this site's repository, pinned to quality.md@0.35.2, so a release that changes it fails that check instead of quietly contradicting this page.