grounded-copy
A style gate for marketing and web copy. It enforces one rule: every value proposition states what the subject IS or DOES — a feature, a number, a mechanism. It bans the contrast move ("not just X", "unlike others", "say goodbye to") in every disguise it wears, plus hype vocabulary and vague attribution, across nine languages. A deterministic Python linter backs the rules and blocks the task until the copy complies.
Before and after
| Draft | After grounded-copy |
|---|---|
| "This isn't just a task tracker — it's your team's second brain." | "The tracker links every task to its pull request and posts a status digest to Slack each morning." |
| "Say goodbye to hidden fees." | "The listed price is the complete price; the invoice adds nothing." |
| "Experts agree Acme leads the market." | "Acme holds 34% of the segment, per Gartner's 2025 market report." |
Same information, carried by specifics.
How it works
Three layers, each catching what the previous one misses:
SKILL.mdteaches the agent the banned move and its ten disguises, with loophole closures written against the ways agents rationalize around style rules (cross-sentence contrast, invented testimonials, "the banned string doesn't appear").scripts/copy_lint.pyis a zero-dependency Python 3 linter with 50+ enumerated patterns. Exit code 1 blocks the task; the agent must rewrite the copy, and the skill forbids editing the linter.- Hooks and CI (see
references/setup.md) enforce the gate on every file write and every pull request, including human ones.
Nine languages
The linter catches the same moves in English, Chinese, Russian, Spanish,
Arabic, French, German, Japanese, and Korean — 不仅仅是, не просто,
no es solo, ليس مجرد, pas seulement, mehr als nur, 単なる〜ではない,
단순한 ~이 아닙니다 are all "not just". Constructions with common factual
uses (だけでなく, 뿐만 아니라) lint as warnings and go through the
deletion test in references/patterns.md. This makes the gate usable on
locale files: a translation that re-introduces contrast fails CI even
when the English source passed.
Install
Skills CLI
npx skills@latest add HiroHyun/grounded-copy
The Skills CLI reads the root SKILL.md, detects supported agents, and
installs the skill in their configured skill directories.
For a global installation with confirmation prompts skipped:
npx skills@latest add HiroHyun/grounded-copy --skill grounded-copy --global --yes
To inspect the skill metadata before installation:
npx skills@latest add HiroHyun/grounded-copy --list
Manual installation
git clone https://github.com/HiroHyun/grounded-copy ~/.claude/skills/grounded-copy
The skill activates on copywriting, localization, and review tasks.
Repository enforcement
The Skills CLI installs the skill definition and its linter. A project-local checkout supplies stable paths for hooks and CI:
git clone https://github.com/HiroHyun/grounded-copy .style/grounded-copy
Use the copy-paste blocks in references/setup.md to connect the linter to
Claude Code hooks, AGENTS.md, GEMINI.md, GitHub Actions, and CODEOWNERS.
Linter only
python3 scripts/copy_lint.py draft.md locales/en.json
cat draft.md | python3 scripts/copy_lint.py --stdin
Exit 0 = pass, 1 = rewrite and re-run. No dependencies beyond Python 3.
Repository layout
grounded-copy/
├── SKILL.md # Core rules + workflow + integrity rules
├── references/
│ ├── patterns.md # Full catalog: bad → good per category
│ └── setup.md # Claude Code hooks, Codex, CI, CODEOWNERS
├── scripts/copy_lint.py # The deterministic gate
└── tests/
├── bad-samples.md # Must FAIL the linter (self-test)
└── good-samples.md # Must PASS the linter (self-test)
The example rows and quoted phrases in this README and tests/bad-samples.md contain banned
patterns on purpose; the CI self-test lints only the test corpus.
Contributing
See CONTRIBUTING.md. Short version: every new pattern
needs a real-world sighting, a failing line in tests/bad-samples.md,
and a factual counterexample check for false positives.
No comments yet
Be the first to share your take.