Skip to content

Agent Skill

Braden Seaborn edited this page Aug 26, 2026 · 1 revision

Agent Skill

STE-Linter ships a Claude Code Agent Skill at .claude/skills/ste100-lint/SKILL.md. It teaches Claude how to run the linter, read every output format, and rewrite prose against each finding -- more than a report of the findings back to you.

What the skill is, and why it exists

The CLI reports. It walks files, prints file:line:col SEVERITY TEST RULE_ID -- message lines, and exits nonzero if anything error-tier fired. That is all a linter needs to do on its own.

An agent driving that linter needs more than a report. It needs to know, for each of the six test families (T1 replaceable words, T2 vague claims, T3 hedges, T4 dangling references, T5 non-atomic sentences, T6 filler) plus the structural checks, what a correct rewrite requires -- and the skill supplies that as worked before/after pairs for every family, not a generic "fix this" instruction.

The more important half of the skill is the other direction: recognizing when a finding is a false positive for the sentence it fired on, and suppressing it structurally instead of mangling the prose to meet it. The skill states this directly:

A linter that trains blind compliance produces worse writing than no linter. When a finding is wrong for the context, do not contort correct prose to meet it.

It lays out an order of preference for handling a wrong finding: re-read the finding's cited source first, since a mis-firing rule is sometimes still worth a light rewrite for clarity; reach for --profile NAME when a whole file is the wrong genre for its auto-detected profile; pin a profile per-file with a <!-- lint-profile: NAME --> comment when the CLI invocation itself cannot change (a pre-commit hook, a CI job); and use --baseline PATH only for triage on an existing body of prose, not to hide a problem permanently. The skill is explicit that inventing a workaround -- renaming a variable, wrapping plain prose in a code span, splitting a sentence in a way that changes its meaning -- to dodge a finding is never acceptable: when a rewrite makes the sentence worse to read, the finding is a profile mismatch, and you suppress it with one of those four mechanisms instead of fighting it.

That combination -- rewrite strategy per test family, plus a documented off-ramp for false positives -- is what the skill adds on top of the bare CLI. See How the Linter Works for what the six test families detect, and Configuration for the profile and preset mechanics the skill leans on.

What triggers it

Claude Code decides whether to load a skill automatically by matching your wording against the description field in the skill's YAML frontmatter -- the description is the entire trigger surface; nothing else in SKILL.md is scanned before the skill loads. The shipped description reads:

description: >-
  Lints and rewrites technical prose against ste100-linter's ASD-STE100-derived
  rule set (T1 replaceable words, T2 vague/unfalsifiable claims, T3 hedges and
  optionality, T4 dangling references, T5 non-atomic sentences, T6 filler and
  weasel words, structural rules like passive voice and TBD). Use whenever the
  user is writing or editing a README, spec, design doc, release notes, PR
  description, or any technical/documentation prose and wants it tightened or
  verified -- and whenever they explicitly ask to "lint", "check my writing",
  "run STE100", "simplify this", "make this clearer", "tighten this doc", or
  "make this more precise". Also use before presenting any Markdown or CSV
  deliverable in a repo that ships ste_lint.py, since a clean run (exit 0) is
  often a project requirement.

Two distinct triggers follow from that text:

  • Implicit. You are writing or editing a README, spec, design doc, release notes, or a PR description, and ask for it to be tightened or verified -- no lint-specific wording required.
  • Explicit. You say "lint this," "check my writing," "run STE100," "simplify this," "make this clearer," "tighten this doc," or "make this more precise."

A standing trigger does not depend on wording at all: before presenting any Markdown or CSV deliverable in a repo that ships ste_lint.py, since a clean run is a project need commonly. CLAUDE.md in a repo such as this one's parent project states that need explicitly ("All output shall pass python tools/ste_lint.py <file> at exit code 0 before you present work"); the skill's description independently tells Claude to check before presenting, even without that project-level instruction.

You can also invoke the skill directly, regardless of description matching, by typing /ste100-lint -- the command name comes from the skill's directory name, ste100-lint, not from anything in the frontmatter.

How to install it

.claude/skills/ste100-lint/ is a self-contained folder holding only SKILL.md, no supporting scripts or data files. Installing it means copying that one folder to one of three places.

1. Personal skill -- available in every project

Copies to ~/.claude/skills/ste100-lint/ (Windows: %USERPROFILE%\.claude\skills\ste100-lint\). Claude Code loads it for every project you open, independent of what any given repo has.

macOS / Linux (bash), run from a checkout of this repo:

mkdir -p ~/.claude/skills
cp -r .claude/skills/ste100-lint ~/.claude/skills/ste100-lint

Windows (PowerShell), run from a checkout of this repo:

New-Item -ItemType Directory -Force "$env:USERPROFILE\.claude\skills" | Out-Null
Copy-Item -Recurse -Force ".claude\skills\ste100-lint" "$env:USERPROFILE\.claude\skills\ste100-lint"

The result in both cases must be a file at ~/.claude/skills/ste100-lint/SKILL.md. Claude Code reads the directory name as the skill name; an extra nesting level (for example ~/.claude/skills/STE-Linter/ste100-lint/SKILL.md) will not be picked up.

2. Project skill -- checked into a repo, so the whole team gets it

Copies to <project>/.claude/skills/ste100-lint/ inside a different repository -- the one whose docs and PR descriptions you want linted. Commit that folder, and everyone who clones the project gets the skill without a personal install step.

macOS / Linux (bash):

mkdir -p /path/to/other-project/.claude/skills
cp -r .claude/skills/ste100-lint /path/to/other-project/.claude/skills/ste100-lint

Windows (PowerShell):

New-Item -ItemType Directory -Force "C:\path\to\other-project\.claude\skills" | Out-Null
Copy-Item -Recurse -Force ".claude\skills\ste100-lint" "C:\path\to\other-project\.claude\skills\ste100-lint"

Commit the result (git add .claude/skills/ste100-lint && git commit). Every skill in this scenario still needs ste100/ste_lint.py reachable in that project -- see Installation and the prerequisite note below.

3. Already in this repo -- nothing to install

Anyone who clones STE-Linter itself already has the skill, because it lives at .claude/skills/ste100-lint/SKILL.md in this repository's own tree. git clone (or git pull on an existing checkout) is the entire install step. This is also how contributors working on the linter's own docs and rule tables get the skill applied to their own commits.

Confirming it loaded

Run /skills inside Claude Code and look for ste100-lint in the listing. Asking Claude directly also works -- "what skills do you have available?" -- and it names ste100-lint if the description loaded correctly.

If it does not appear:

  • Check the path depth. The path resolves to .claude/skills/ste100-lint/SKILL.md under the personal, project, or repo root you copied it into -- not one level deeper or shallower.
  • If you created the top-level .claude/skills/ (or ~/.claude/skills/) directory for the first time as part of this install, restart Claude Code. Claude Code watches an existing skills directory for live changes within a running session, but picking up a brand-new top-level skills directory requires a restart.
  • Confirm you are in (or below) the project root the skill was installed into -- project skills load from .claude/skills/ in your starting directory and every parent directory up to the repository root, but not from unrelated directories elsewhere on disk.

Using it

The following are illustrative examples of how a session plays out, written to show the shape of the interaction -- not captured transcripts from a session.

Implicit trigger, from an everyday edit:

You: Can you tighten up the second paragraph of our README? It reads a little soft.

Claude: (loads ste100-lint, runs ste100 --format json README.md, sees a T3 hedge finding on "as needed" and a T2 finding on "small teams") The linter flagged two issues in that paragraph: "as needed" is an escape clause (T3), and "small teams" is an unfalsifiable claim with no number attached (T2). Here's the rewrite:

Before: "We support small teams and provision resources as needed." After: "We support teams of 2-8 people and provision resources within one business day."

Without the skill, Claude might still make the prose read better, but it would not systematically check every sentence against six specific, mechanically-defined smell categories, and it would not know to add a number rather than just deleting "small."

Explicit trigger:

You: Run STE100 on docs/release-notes.md and fix whatever it finds.

Claude: (runs ste100 docs/release-notes.md, works through the findings test-family by test-family per the skill's rewrite guidance, re-lints, reports remaining findings if any)

Recognizing a false positive instead of obeying blindly:

You: The linter is flagging "this" in our architecture doc as a dangling reference, but it's obviously referring to the diagram right above it.

Claude: (re-reads the finding's source, and per the skill's false-positive guidance, checks whether the file's profile is the correct genre before rewriting) That's a T4 finding on a pronoun with an antecedent one clause earlier -- STE100's stance is that a machine-checkable proxy for ambiguity is worth listening to even when a human reader wouldn't be confused, but if this keeps firing across the whole document because it's a narrative-style doc under the wrong profile, the better fix is --profile design or a <!-- lint-profile: design --> comment at the top of the file, not chasing every pronoun.

Prerequisite

The skill drives the CLI -- it does not reimplement any linting logic itself. ste100 must be installed, or a checkout of this repository must be present, wherever Claude Code is running the commands. See Installation for both paths.

Clone this wiki locally