Contributing to falsegreen-skill
July 8, 2026 · View on GitHub
falsegreen-skill is the LLM semantic pass companion to the falsegreen Python scanner. It detects false-positive test patterns that no static tool can see, across Python, TypeScript, and JavaScript.
30-second cheat sheet
# 1. Fork the repo on GitHub first (vinicq/falsegreen-skill → your-username/falsegreen-skill)
# 2. Clone your fork
git clone https://github.com/<your-username>/falsegreen-skill
cd falsegreen-skill
# no runtime dependencies — this is a skill definition, not a package
Branch, make your changes, and open a pull request against vinicq/falsegreen-skill.
Validate your changes
Before opening a PR, run:
npm run validate
This checks required files, skill frontmatter, manifest JSON, schema field names, and unsupported language claims. It takes under a second.
For CLI changes, also run:
node --check bin/falsegreen-llm.js
If you changed SKILL.md, check that the same text appears in llm.md, AGENTS.md, and GEMINI.md - they carry the same protocol and must stay in sync.
How the skill is built
One file does the work: SKILL.md. It defines the protocol Claude follows
when analyzing a test. reference.md is the supporting catalog: per-language
patterns, framework cues, and the J1-J6 judgment index.
The skill inherits the same methodology as the scanner: a test is useful only if it fails when the code breaks. Cases 10, 11, 12, 15, and 18 need semantic judgment that a parser cannot make. This skill makes that judgment.
Repository layout contract
Two host-packaging details depend on the current file layout. Keep them in mind before moving or renaming files at the repo root.
- The Claude skill entry point is a thin pointer that resolves the protocol by
relative path.
skills/falsegreen-skill/SKILL.mdreferences../../SKILL.mdand../../reference.md. Those paths resolve two levels up, at the repo root, inside the installed plugin cache. MovingSKILL.mdorreference.mdout of the root, or relocating the skill directory, breaks the reference silently - the plugin still installs, but the protocol never loads. If you change the layout, update the relative paths in the skill entry and re-runnpm run validate. - The marketplace entries use the root form
"source": "./"..claude-plugin/marketplace.jsonand.agents/plugins/marketplace.jsonpoint at the repo root, so the host runs its defaultskills/scan to find the skill. If you ever add an explicitskillsfield to a marketplace entry, it replaces that default scan - the host then looks only where the field points. Leave"source": "./"without askillsoverride unless you intend to take over discovery yourself.
Releasing: bump the version
plugin.json, .codex-plugin/plugin.json, and gemini-extension.json pin a
version. New commits do not reach installed plugins until that version is
bumped and published - a fix merged to master without a release is invisible
to users. Before publishing, run npm version <patch|minor|major> (the
version npm script syncs the number into all three manifests and stages
them), move the [Unreleased] entries in CHANGELOG.md under the new version,
then follow RELEASE.md. (.antigravity-plugin/plugin.json is intentionally
versionless - its schema forbids a version key - so it stays out of the sync.)
Refreshing the scanner snapshot
schema/scanner-codes.json pins, per sibling scanner, the version and the exact
set of codes it emits. check-scanner-coverage.mjs diffs that snapshot against
the catalog and fails if any sibling emits a code the skill catalog does not
cover (the #105 regression). The snapshot is generated, not hand-edited:
# from checkouts next to this repo (../falsegreen, ../falsegreen-robot, ../falsegreen-js)
node scripts/refresh-scanner-snapshot.mjs
# point at checkouts elsewhere (per sibling; env vars work too)
node scripts/refresh-scanner-snapshot.mjs \
--falsegreen=/path/to/falsegreen \
--falsegreen-js=/path/to/falsegreen-js
# CI-friendly: fail if the committed snapshot lags the checkouts, no write
node scripts/refresh-scanner-snapshot.mjs --check
The script reads each sibling's version and its CASES code set straight from
source, so the refresh no longer relies on a human copying codes by hand. A
sibling that is not checked out is skipped with a warning and its existing
snapshot entry is kept. After refreshing, run npm run validate so
check-scanner-coverage.mjs confirms the catalog still covers every code. This
check is not in npm run validate because the sibling repos are not present at
this repo's CI time (ADR 0002); run it locally against live checkouts before a
release.
Precision over recall
Same rule as the scanner: a finding that wrongly flags a legitimate test is worse than a missed finding. Before adding a detection cue or tightening a boundary rule, test it against common legitimate patterns (characterization tests, TDD tests, integration doubles).
Filing an issue
A useful false-positive report includes the test snippet, the case number the skill attributed, and why that attribution is wrong. A useful false-negative report shows the bad test and the case it should have caught.
Adding a language pattern
A new language-specific pattern touches two places:
reference.md: the case entry for the relevant language, with a bad-pattern example and a clean look-alike.SKILL.md: the detection cues section for that language, if the pattern requires a new cue the model should look for.
Authorship and AI tooling
Use any tools you like. The authorship is yours. Do not add Co-Authored-By
trailers for AI agents. Human co-authors are welcome.
Commit messages: Conventional Commits
Format: type(scope): summary. Recognised types: feat, fix, docs,
refactor, chore. Scope is usually the language or case number.
feat(python): add C35 flaky-decorator detection to reference
fix(typescript): stop flagging jest.spyOn when SUT is an edge
docs(reference): add JavaScript Sinon stub look-alike examples
License
By contributing you agree your contributions are MIT-licensed.