Thanks for helping improve this skill. It teaches an LLM (and now a deterministic engine) to spot and fix AI-writing tells. Contributions are welcome — a few things keep the project coherent.
Check the assignee, comments, and linked PRs to see whether someone is already working on an issue. For an unclaimed issue, leave a short comment letting us know you're starting. We appreciate the heads-up, and you can begin right away: you do not need to wait for assignment or maintainer confirmation. If someone is already working on it, coordinate with them before duplicating their work. If the issue explicitly needs a design decision before implementation, resolve that question first.
Issues labeled good first issue are reserved for people making their first
contribution to this repository. Take only one for your first PR; leave the
others for fellow newcomers, including while your PR is awaiting review.
You are also welcome to propose your own issues and ideas.
Important
If you've already contributed here, choose a help wanted issue without the
good first issue label, propose another improvement, or help review and test
newcomer PRs. Please leave good first issues for new contributors.
| Path | What it holds |
|---|---|
SKILL.md |
Entry instructions, severity tiers, output formats, and guardrails. |
references/patterns.md |
Canonical pattern catalog, word tiers, context and voice profiles. |
detector/patterns.js |
The deterministic engine — the executable subset of the rules. |
detector/CATEGORIES.md |
The map between references/patterns.md rules and detector types. Keep it current. |
README.md |
The pitch and the numbered prose-pattern list. |
GLOSSARY.md |
One-line definitions of the project's terms, each linked to its canonical source. |
cursor-rules/, plugins/ |
Editor and tool integrations. |
First decide which kind of rule it is:
- Regex-detectable (a phrase, a character, a structural shape) → add it to
references/patterns.md, add the detection todetector/patterns.jswith a newtype, and add a row todetector/CATEGORIES.md. Cover it with a fixture indetector/patterns.test.js(both a true positive and a case that must not fire). The category contract indetector/categories.test.jsrequires each type to appear by name in that fixture file. The phrase-level gaps listed in itsLEGACY_UNCOVERED_TYPESare explicit exceptions while #213 and the related false-positive fixes are open; remove an entry when its fixtures land, and never add one. The name check prevents omissions but does not replace assertions that the intended behavior fires and stays clean. - Judgment-only (needs reading for meaning — tone, structure, name-dropping)
→ add it to
references/patterns.mdprose and list it under "Skill-only" indetector/CATEGORIES.md. There is no detector type for these.
If you are unsure which it is, open an issue first and we will sort it out. The pattern proposal form asks for what triage needs, including the example that must stay clean.
When you add or remove a detection ### under ## What to remove or fix in
references/patterns.md (not judgment-only prose or writer-side tests), CI
derives the new total and compares it to two literals:
README.md— update the**NN pattern categories**feature bullet to match the derived count.CLAUDE.md— update the quotedREADME "NN pattern categories" bulletphrase in the pattern-count guidance so it matches the same number.
scripts/check-pattern-count.sh enforces both on every PR. Adding a word-table
row instead only requires bumping the separate **NN-entry word replacement table** README bullet (same script).
This skill is deliberately biased toward false negatives: a rule that wrongly flags ordinary human writing is worse than one that misses a tell, because false positives erode trust in every other rule. Before proposing a rule, ask who would get flagged by mistake, and add carve-outs for the legitimate cases. A signal that fires on most normal prose is not worth adding.
If your rule rests on a factual claim about how AI or humans write — "ChatGPT emits curly quotes by default," "most writers rarely do X" — link a source for it. These claims get checked, and some turn out wrong or more nuanced than they first seem (smart quotes, for instance, are a typing-time default on macOS and in Word, not a publication-step artifact). A claim with a citation can be verified; an asserted one can't. Put the links in the PR description or inline in the rule.
This skill and its deterministic detector are calibrated for English. Start a non-English adaptation in a separately maintained fork or repository, with its own language-specific rules and release process. We can discuss bringing a well-maintained adaptation into this repo later if its maintainers want shared ownership and we can sustain its tests and review. A translated word list alone does not establish that the rules work in another language.
Identify the target language, dialect, audience, and registers. Rebuild lexical tiers from native-language writing rather than translating English entries; check which structural rules transfer and add language-specific exceptions. Show positive and must-not-fire examples across relevant registers, especially ordinary human writing that a rule might flag. Describe your sample provenance, what was measured, and what remains editorial judgment. Do not publish authorship or false-positive claims without evidence for that language and register. State known limitations, including dialect and formal-register cases. Keep the upstream license and attribution when adapting this work.
To request a link in the community section, open an issue with the repository URL, maintainer, language and dialect, a short description of the native-language changes, evidence and limitations, and where users should report problems. We review links for a clear scope, an accountable maintainer, and honest claims. A link helps readers discover your adaptation; it does not mean this repository maintains it or certifies its accuracy.
The rules from the #88 license audit, recorded here so nobody has to rediscover them:
- This repo bundles no style guide it cannot verify the license for. The
--stylelayer is config-driven; users supply their own conventions. - Openly-licensed guides may ship later as example configs (Google, Microsoft, GOV.UK, and 18F qualify), using Vale's attribution pattern: disclaim endorsement, name the license, link the guide upstream.
- Paywalled guides (CMOS, APA, MLA, AP) are never shipped, in any form, under any name. Passing one to
--stylefalls through to the fallback that claims no compliance. The reason is trademark and verifiability, not maintenance burden.
npm testnpm test runs every suite via scripts/run-tests.js and prints a combined
summary; earlier failures do not skip later files. To run one suite:
node scripts/run-tests.js detector/patterns.test.js
# or invoke the file directly:
node detector/patterns.test.jsThis runs the engine fixtures and the CATEGORIES.md contract checks: every
detector type must be documented, every documented type must be real, and every
prose statement of the engine type total must match the code. All must pass. No
dependencies to install; Node 18+ only.
The SSOT / ssot CI job checks repository-local Node requirements using
.ssot-local.yaml on every PR. package.json owns the detector's Node minimum;
README and contributor instructions carry checked copies. Existing generated
skill, version, and pattern-count checks keep their own ownership.
The separate .ssot.yaml and promo-drift workflow track cross-repo promotional
counts on release and schedule. Both workflows pin the checker revision; the
local PR check needs no sibling repositories or private credentials.
Registered drift, missing copies, and malformed manifests fail CI. Fix the claim and its copies, and explain any change to canonical ownership or removed locators. Do not remove checks merely to make a failure disappear.
Discovery is advisory and scans prose, not every source format or value. The Node minimum needs its explicit locators. Historical releases, example corpora, and generated bundles are excluded from discovery. The initial remaining warnings are fictional funding/percentage examples and repeated editing-budget guidance. Inspect a warning before registering a fact or excluding a path; explicitly registered copies remain checked even in excluded files.
To reproduce CI, check out the checker revision pinned in
.github/workflows/ssot.yml into a sibling ssot-check directory, then run:
python3 ../ssot-check/ssot_check.py check --manifest .ssot-local.yaml
python3 ../ssot-check/ssot_check.py discover --manifest .ssot-local.yaml --untracked-only --github-annotations
python3 scripts/check-ssot-controls.py ../ssot-check/ssot_check.pyThe controls mutate disposable copies and verify drift, restoration, missing
locations/manifests, and invalid manifests. They also prove that history can be
excluded while a new unregistered current copy still warns without failing
check. Record useful findings, repeated warnings, and maintenance effort in
the pilot PR or a follow-up issue before expanding coverage.
This repo polices writing quality, so the prose you add has to clear the same
bar. Run your additions through the skill itself. Keep rule bullets terse and
lead with the directive — match the length and tone of the bullets already in
SKILL.md. Drop intensifiers like "strong" or "powerful"; let the rule stand on
its own.
Add an entry under ## [Unreleased] in CHANGELOG.md when a change affects
users: detection or rewriting behavior, writing rules, public APIs or CLI
options, configuration, installation or packaging, compatibility, or security.
Skip the changelog for routine docs corrections, links, formatting, contributor guidance, tests, and internal refactoring or CI maintenance with no user-facing effect. Describe those changes in the PR. A docs or maintenance label does not exempt a change that affects how the tool works, is installed or used, or is supported.
When preparing a release, move its Unreleased entries under a dated, versioned
heading (## [X.Y.Z] — YYYY-MM-DD) and update the matching versions in
SKILL.md, package.json, and both plugin manifests. A release that adds a
writing rule needs a minor version bump. Exempt changes need no version bump;
leave published release entries intact.
After changing either canonical file, run bash scripts/sync-plugin-skill.sh && bash scripts/sync-cursor-rules.sh. This regenerates both bundles, SKILL.full.md, and the portable paste/Cursor artifacts; CI checks parity. Do not edit generated copies.
Maintainers should follow the release recovery procedure instead of moving a tag or reusing a published version after a failed run.