Copy Editing
coreyhaines31/marketingskills
When the user wants to edit, review, or improve existing marketing copy, or refresh outdated content.
Find tests that enumerate a domain by copying it, and declare the invariants a codebase depends on.
$ npx skills add oaustegard/claude-skills --skill declaring-invariants -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install oaustegard/claude-skills declaring-invariants --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/oaustegard/claude-skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/declaring-invariants .claude/skills/declaring-invariants && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "declaring-invariants" agent skill from https://github.com/oaustegard/claude-skills/tree/main/declaring-invariants into .claude/skills/declaring-invariants/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "declaring-invariants", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/oaustegard/claude-skills/tree/main/declaring-invariantsType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add oaustegard/claude-skills --skill declaring-invariants -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install oaustegard/claude-skills declaring-invariants --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/oaustegard/claude-skills.git skills-src && mkdir -p .agents/skills && cp -r skills-src/declaring-invariants .agents/skills/declaring-invariants && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "declaring-invariants" agent skill from https://github.com/oaustegard/claude-skills/tree/main/declaring-invariants into .agents/skills/declaring-invariants/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "declaring-invariants", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add oaustegard/claude-skills --skill declaring-invariants -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install oaustegard/claude-skills declaring-invariants --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/oaustegard/claude-skills.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/declaring-invariants .cursor/skills/declaring-invariants && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "declaring-invariants" agent skill from https://github.com/oaustegard/claude-skills/tree/main/declaring-invariants into .cursor/skills/declaring-invariants/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "declaring-invariants", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/oaustegard/claude-skills.git --path declaring-invariants--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add oaustegard/claude-skills --skill declaring-invariants -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install oaustegard/claude-skills declaring-invariants --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/oaustegard/claude-skills.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/declaring-invariants .gemini/skills/declaring-invariants && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "declaring-invariants" agent skill from https://github.com/oaustegard/claude-skills/tree/main/declaring-invariants into .gemini/skills/declaring-invariants/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "declaring-invariants", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install oaustegard/claude-skills declaring-invariantsInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add oaustegard/claude-skills --skill declaring-invariants -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/oaustegard/claude-skills.git skills-src && mkdir -p .github/skills && cp -r skills-src/declaring-invariants .github/skills/declaring-invariants && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "declaring-invariants" agent skill from https://github.com/oaustegard/claude-skills/tree/main/declaring-invariants into .github/skills/declaring-invariants/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "declaring-invariants", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add oaustegard/claude-skills --skill declaring-invariants -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install oaustegard/claude-skills declaring-invariants --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/oaustegard/claude-skills.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/declaring-invariants .opencode/skills/declaring-invariants && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "declaring-invariants" agent skill from https://github.com/oaustegard/claude-skills/tree/main/declaring-invariants into .opencode/skills/declaring-invariants/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "declaring-invariants", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
declaring-invariantsFind tests that enumerate a domain by copying it, and declare the invariants a codebase depends on.
Declaring Invariants is an agent skill from oaustegard/claude-skills. Find tests that enumerate a domain by copying it, and declare the invariants a codebase depends on. Reports where a parametrize list, for-loop, or it.each iterates a hand-written subset of a dict/set/tuple/Enum that exists in the source, and names the members nothing covers. Use when reviewing tests, when a module gains a name-to-thing table, registry, enum, or dispatch map, before trusting a green suite as evidence a domain is covered, or when asked "is this test actually total", "does anything cover X", "what…
Its SKILL.md is about 3.6k tokens, which your agent loads only when the skill is triggered. The skill folder holds 8 other files, including scripts (for example `CHANGELOG.md`, `README.md` and `scripts/claims.py`).
The repository describes itself as: My collection of Claude skills. The licence is MIT.
5 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit 90b0f1b. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Ships 2 files in scripts/ (Python), which the agent can run.
Shell commands in SKILL.md call:
python3From the folder's file list and the shell code blocks in SKILL.md.
Links to these hosts (documentation or services it may open):
github.comFrom URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Declaring Invariants loads about 3.6k tokens when it runs. Until then it costs about 199 tokens; SKILL.md has 1,915 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); the scripts in this folder are not scanned.
The full file from oaustegard/claude-skills at commit 90b0f1b, republished under its MIT licence (© oaustegard). 1,915 words, ~3,626 tokens.
.claude/skills/declaring-invariants/SKILL.md (or your agent's skills folder). This skill also uses 6 other files; get the full folder from GitHub.Two scripts over one idea: a test that enumerates a domain must loop the registry rather than a copy of it. Someone also has to say which domains matter in the first place.
python3 scripts/totality_lint.py <repo> # tests that copy a domain
python3 scripts/claims.py <repo> # what the repo declares, and what backs itPython only, stdlib ast only: no install, no config file, no network.
A test that loops a hand-written list passes its runner and proves nothing about completeness. When the same members also exist as a registry in the source, the list is a copy, and the copy drifts the moment someone adds a member to the registry and not to the test. Nothing goes red.
Measured on oaustegard/remex, 2026-08-24: adding a fourth member to
ROTATION_CODES with no construction behind it left the entire 267-test
suite green. Four separate tests looked total; each parametrized
["haar", "rht"] against a three-member registry. Only a test that looped the
registry itself caught it.
Adapted from the meta-oracle in daniloc/coherence
(src/oracle-domain.ts), which classifies an oracle's iteration root as LIVE
or LITERAL by parsing the oracle's own AST. That harness needs spec files, a
claim grammar, a ledger and Node; the check does not.
totality_lint.py — tests that copy a domain| finding | meaning |
|---|---|
sampled-domain | a parametrize or for over a literal whose members are a strict subset of a source registry. The uncovered members are named. |
ratchet-broken | a hand-list marked ratchet names a member the registry no longer contains. Detected statically, without running anything. |
unratcheted | a registry enumerated live with nothing pinning its membership. Suppressed when no-floor already claimed the same line. |
no-floor | a test iterates a live registry with no len(...) >= n assertion in the file, so an emptied registry passes vacuously. |
stale-ack | an acknowledgement on a test that now covers the whole domain. |
python3 scripts/totality_lint.py <repo> # the report
python3 scripts/totality_lint.py <repo> --json
python3 scripts/totality_lint.py <repo> --strict # exit 1 if any finding
python3 scripts/totality_lint.py --selftest # fixtures, no repoA partial domain is often correct. Say so on the test and it stops being a finding:
# totality: partial — mojo has no construction for "none"
@pytest.mark.parametrize("rotation", ["haar", "rht"])
def test_save_params_accepts_every_mojo_rotation(rotation): ...The marker also works as totality: partial — <why> inside the docstring. An
acknowledgement on a test that later covers the whole domain is reported as
stale-ack, so a suppression cannot become a silence.
An enumeration loops whatever the domain currently holds, so it is
structurally blind to the domain narrowing. Remove a member and the loop simply
ranges over fewer of them, green. Raised by Yep, 2026-08-24; reproduced on
oaustegard/remex before being believed:
perturbation of ROTATION_CODES | domain floor | enumeration | parity | hand-list |
|---|---|---|---|---|
grow — add "hadamard2" | pass | RED | RED | pass |
shrink — drop "none" | RED | pass | RED* | pass |
substitute — "none" → "xyz" in both spellings | pass | pass | pass | pass |
* only because the other spelling of the domain did not shrink, which is incidental to that repository.
In the substitution row cardinality holds, both spellings agree, and five green tests cover a registry that quietly stopped supporting a rotation every index on disk was written with. The floor is a cardinality check; it cannot see a member swapped for another.
The second form is a ratchet: a hand-list asserting the domain keeps containing it. Mark it and the linter checks the pin rather than taking the marker's word for it.
# totality: ratchet — these three shipped; one leaving is a compatibility break
def test_no_shipped_rotation_is_ever_removed():
for shipped in ("haar", "rht", "none"):
assert shipped in ROTATION_CODESUnder that same substitution the linter reports ratchet-broken naming
'none' statically, before any test runs, and the test itself goes red
while the other five pass.
So: an enumeration proves every current member is handled, and a ratchet proves
no member left without a decision. unratcheted names a registry that has the
first and not the second. Neither half alone is the answer.
A ratchet covers shrink only. Over a strict subset it still reports
sampled-domain for the members it never listed, because pinning two of three
says nothing about the third. Suppressing that would make the marker a
laundering channel — the escape hatch these notes criticise via guard for
being in coherence. It was one: until 2026-08-25, # totality: ratchet over
two of three members silenced the report entirely and checked nothing about the
third. Caught by an adversarial pass on this skill, not by its own tests.
claims.py — what the repo declarestotality_lint asks whether a test's domain is complete. It presumes a test
exists. This asks the prior question, the one coherence's own Known Limits
concedes it does not answer: nothing enforces exists ⇒ declared.
A claim is a test whose docstring opens with invariant:. No new file
format, and the claim inherits its test's pass/fail:
def test_every_skipped_directory_is_actually_skipped(self):
"""invariant: every name in SKIP_DIRS is excluded from the walk.
refuted: replaced the walk's `part in SKIP_DIRS` check with
`part in {"node_modules"}` -> this test went red naming `.coherence`,
while the other 25 tests in this file stayed green.
"""| finding | meaning |
|---|---|
unrefuted | a claim nobody has watched fail |
literal | the claiming test iterates a copy of the registry, so the claim cannot see a new member |
unanchored | a registry no invariant names — a question, not a verdict |
A claim whose test carries a ratchet marker is reported as pinning its
registries rather than copying them, and a ratcheted registry is not
unanchored.
python3 scripts/claims.py <repo> [--json] [--strict] [--selftest]refuted: is the half that costs something. Break the chokepoint, watch the
claim go red by name, restore, and record what you saw. A green test and an
unfalsifiable one look identical from outside; the refutation is what separates
them.
Never write a refutation you have not run. The first refutation authored
for the SKIP_DIRS invariant above asserted a failure that did not occur — the
fixture placed the registry outside the test's reachability, so the test passed
under perturbation for an unrelated reason. A vacuous claim, written while
building the tool that catches vacuous claims, and caught only by running the
perturbation instead of trusting the sentence.
Procedure, in order:
refuted: <the edit> -> <what went red, by name>.The reference wiring lives in oaustegard/claude-workspace
(scripts/tdd_hook.py): a commit where a registry gained a member and no
invariant: test iterates it live is denied, naming the registry and what it
gained. Override with no-invariant: <why> in the commit body.
Registry shrink is gated the same way, and needs a ratchet rather than an enumeration to clear it. A new function or a new branch is behavioural growth too, but neither is diffable without guessing, and a gate that guesses stops being consulted. A brand-new registry is not gated. Declaring one is a judgement call; growing one has already made it.
Both filters exist because the unfiltered version was noise. Reproduce either by removing the filter and re-running against a real repo.
no-floor fires only on a name independently recognised as a registry.
Firing on every for x in <local> produced 27 findings on remex, all
noise: numpy arrays, query matrices, loop counters.tests/test_<mod>.py. Matching against any registry in the tree joined a
test in discrepancy/ to registries in kb-k-sweep/ and
remex-vs-higgs-ablation/ on a monorepo, because small integer sets collide
by chance. Four findings became one, and the survivor was real.The join key is membership, not names: [1, 2, 3, 4, 8] and
SUPPORTED_BITS share no token, so containment is what ties them together. No
naming convention is assumed, and none is required.
_registries_py and _domains_py; a
tree-sitter pair for another language slots in beside them. The join, the
acknowledgements and the reports are all language-independent.--strict opts into a nonzero exit. The
tool this was adapted from gates by default, and its parity arm false-fails a
correct oracle that binds its domain to a local name first. A gate that
false-fails stops being consulted.parametrize is read.unanchored is a question. Most registries need no invariant. Treat the
list as candidates for declaration, never as a backlog to clear.ROTATION_CODES = {"haar": 0, "rht": 1, "none": 2} exists to pin
bytes on disk; permuting it to {"haar": 0, "rht": 2, "none": 1} keeps every
key, every count and every ratchet intact, and every index already written
decodes under the wrong rotation. Verified 2026-08-25 on a fixture: the
linter reports nothing and the gate's registry half reports nothing. (The
gate denied that fixture, but on the unrelated TDD rule — checked, because
claiming otherwise would have been the overclaim this skill exists to catch.)
Nothing here checks a name-to-code mapping. Extracting (key, value) pairs
as the member set would, at the cost of breaking the subset join against a
parametrize list of keys."none"
to "identity" in both files was silent, while every index already on disk
still decodes byte 2 as the old name. Both sides of a co-located hand-list
move together, so no static check over one working tree can see it. The
commit gate can, because it diffs against git history — and only if the
ratchet itself is untouched in that commit, which it now requires.unanchored and
unratcheted surface it in the report; the gate deliberately does not, on
the grounds that gating every new module is how a gate stops being consulted.
That is a judgement, not a proof, and it is the largest hole a cross-model
review found.@register("name") populating a
dict at import time is the common Python registry idiom and is not a literal,
so nothing here sees it. Named because it is the shape most likely to be
mistaken for coverage.verifying-claims covers the prose layer: does the documentation match
reality? Agent-judged, non-deterministic, run as a triggered review. This
skill is the deterministic half, over code and tests rather than prose.tree-sitting locates the registry or the test before you edit it.© oaustegard, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 6 other files (scripts) in declaring-invariants of oaustegard/claude-skills.
Open the folder on GitHubat commit 90b0f1b
Declaring Invariants next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Declaring Invariants this skilloaustegard/claude-skills | 150 | — | ~3.6k | Automated safety check: Pass | MIT | |
| Copy Editingcoreyhaines31/marketingskills | 54k | 1 repos | ~4.5k | Automated safety check: Pass | MIT | |
| Sitemap Domainthedaviddias/Front-End-Checklist | 74k | — | ~531 | Automated safety check: Pass | MIT | |
| Domain Driven Designdavila7/claude-code-templates | 33k | 5 repos | ~623 | Automated safety check: Pass | MIT | |
| Domain Modeling and Glossarywindmill-labs/windmill | 18k | — | ~622 | Automated safety check: Pass | Custom licence | |
| Invariant Guardsickn33/agentic-awesome-skills | 47k | 1 repos | ~4.5k | Automated safety check: Pass | Apache-2.0 |
coreyhaines31/marketingskills
When the user wants to edit, review, or improve existing marketing copy, or refresh outdated content.
thedaviddias/Front-End-Checklist
A skill your agent uses when applies to sites that have recently migrated from HTTP to HTTPS, changed domain name, or have www/non-www redirect configurations.
davila7/claude-code-templates
Plan and route Domain-Driven Design work from strategic modeling to tactical implementation and evented architecture patterns.
windmill-labs/windmill
Actively challenges vague or conflicting terminology as you design, and keeps a living domain glossary file up to date in real time.
sickn33/agentic-awesome-skills
Correctness-first: forces writing the function contract, loop invariant, termination argument, and edge cases BEFORE code.
github/awesome-copilot
Complete development kit for Microsoft 365 Copilot declarative agents with three comprehensive workflows (basic, advanced, validation), TypeSpec support, and Microsoft 365 Agents Toolkit integration
oaustegard/claude-skills
Builds interactive Vega-Lite charts from uploaded data: analyzes the fields, picks five to ten fitting chart types, and produces a React artifact with the data embedded inline.
oaustegard/claude-skills
Builds self-contained single-file HTML pages such as reports, decks, postmortems, flowcharts and prototypes from a small spec using a bundled Python composer and templates.
oaustegard/claude-skills
Routes, triages, flags and rates a piece of text with a probability for every option: which department or queue a ticket goes to, which intent a message expresses, whether a yes/no condition holds…
oaustegard/claude-skills
Rewrites model-sounding prose into plain technical writing and checks that every claim survives, for PR text, docs, commit messages and similar drafts.
oaustegard/claude-skills
Guides building standards-based Preact apps with native-first choices, HTM syntax, import maps and vendored ESM, from single-file demos to larger builds.
oaustegard/claude-skills
Deprecated sampler that captures short windows of the Bluesky firehose, clusters trending terms and builds an HTML report; replaced by the browsing-bluesky skill.
Find tests that enumerate a domain by copying it, and declare the invariants a codebase depends on. Declaring Invariants is an agent skill from oaustegard/claude-skills. Find tests that enumerate a domain by copying it, and declare the invariants a codebase depends on.
Declaring Invariants fits situations like: reviewing tests; A module gains a name-to-thing table; before trusting a green suite as evidence a domain is covered; asked is this test actually total.
Run `npx skills add oaustegard/claude-skills --skill declaring-invariants -a claude-code`. Or copy the skill folder (declaring-invariants in oaustegard/claude-skills) into .claude/skills/declaring-invariants in your project. Claude Code loads it when a task matches its description.
Run `npx skills add oaustegard/claude-skills --skill declaring-invariants -a codex`. Or copy the skill folder (declaring-invariants in oaustegard/claude-skills) into .agents/skills/declaring-invariants in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add oaustegard/claude-skills --skill declaring-invariants -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/declaring-invariants, .gemini/skills/declaring-invariants, .github/skills/declaring-invariants and .opencode/skills/declaring-invariants in your project.
Going by SKILL.md and its folder, Declaring Invariants needs Python for the scripts in its folder and the command-line tools its instructions call (python3). Our summary lists: Python 3.
SKILL.md names 1 domain. As links in the text: github.com. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. The check reads SKILL.md only: the scripts in the folder are not scanned, so read them before running anything.
Declaring Invariants is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 3.6k tokens (SKILL.md is roughly 15k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Declaring Invariants: Copy Editing (coreyhaines31/marketingskills, 54k stars), Sitemap Domain (thedaviddias/Front-End-Checklist, 74k stars), Domain Driven Design (davila7/claude-code-templates, 33k stars) and Domain Modeling and Glossary (windmill-labs/windmill, 18k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
oaustegard (a GitHub user) maintains it in oaustegard/claude-skills, which has 150 GitHub stars. The repository holds 67 skills in this directory. The repository was last updated on October 9, 2026.
Source: oaustegard/claude-skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.