# H1.9: Invalid or mismatched skill name

The skill name is invalid or does not match its containing directory.

<div class="rule-facts"><span>H1.9</span><span>MEDIUM</span><span>LintLang 0.8.0</span></div>

**Applies to:** SKILL.md read from disk, with a declared name and directory. Manual repair; no automatic fix for this example.

## What triggers it

The released check needs the directory identity provided by a file named SKILL.md. It checks name syntax and name/directory agreement.

## How to repair it

Use 1–64 lowercase letters, digits, and single separating hyphens; make the SKILL.md directory and declared name agree.

## Reproduce the finding

Use [uv and Python 3.10+](/docs/install), plus curl. Run the examples in a scratch directory.

[Download the finding example](/examples/rules/h1.9-bad.md).

```markdown
---
name: Invoice Review
description: "Use when the user asks to review an invoice."
---

# Invoice review

Compare the invoice total with its line items. Report discrepancies by line number.
```

```sh
mkdir -p rule-check/invoice-review
curl -fsS https://lintlang.ai/examples/rules/h1.9-bad.md -o rule-check/invoice-review/SKILL.md
uvx --from lintlang==0.8.0 lintlang scan rule-check/invoice-review/SKILL.md --format json
```

Expected with **0.8.0**: the JSON report includes **H1.9**, severity **MEDIUM**. The downloaded files have neutral names. For this check, copy each into invoice-review/SKILL.md as shown below; scanning the download under its neutral name does not exercise directory matching.

## Improved example

[Download the improved example](/examples/rules/h1.9-improved.md).

```markdown
---
name: invoice-review
description: "Use when the user asks to review an invoice."
---

# Invoice review

Compare the invoice total with its line items. Report discrepancies by line number.
```

```sh
mkdir -p rule-check/invoice-review
curl -fsS https://lintlang.ai/examples/rules/h1.9-improved.md -o rule-check/invoice-review/SKILL.md
uvx --from lintlang==0.8.0 lintlang scan rule-check/invoice-review/SKILL.md --format json
```

Expected with **0.8.0**: **H1.9 is absent**. Other diagnostics may still appear; this repair targets the rule above.

Both commands use advisory mode: a finding does not itself make the command fail. To fail CI on MEDIUM findings, add --fail-on review. --fail-on fail gates only HIGH and CRITICAL. See [outputs and exit codes](/docs/outputs).

## Detection details

<details>
<summary>Released H1 detection contract and scope</summary>

Checks empty and underspecified short descriptions, selected vague opening verbs, duplicate
tool names, high word overlap, and relational nondistinction. Findings keep
`pattern_id: H1`; `code` provides the more specific stable identifier.

| Code | Reports | Severity |
| --- | --- | --- |
| H1.1 | Tool has no description | CRITICAL |
| H1.2 | Description shorter than 20 characters without a recognized concrete action and domain object | HIGH |
| H1.3 | Description opens with a selected vague verb | MEDIUM |
| H1.4 | Two tools share a name | CRITICAL |
| H1.5 | Near-duplicate descriptions under the word-overlap model | HIGH |
| H1.6 | One or both tools lack a distinguishing analyzed term | MEDIUM |
| H1.7 | Skill description longer than 1024 characters | HIGH |
| H1.8 | Skill description does not say when to use the skill | MEDIUM under 120 characters, else LOW |
| H1.9 | Skill `name` invalid, or different from its `SKILL.md` directory | MEDIUM |

One-sided H1.6 containment and non-identical H1.5 overlap are suppressed when
both tools declare different input names, types, or choices in nonempty property
schemas: those inputs provide a selection distinction. Descriptions that are
nearly identical (95% or greater word overlap) still receive H1.5.
H3 does not demand duplicate descriptions for scalar parameters explained by an
enum, const, format, a named boolean switch, or the tool description. Ambiguous
parameters such as an unconstrained role or line/column coordinates still need
semantics. These are bounded heuristics, not proof of semantic completeness.

Server manifests with `server`, `tools`, and root `instructions` retain their
instruction text for evidence-bearing checks, but do not inherit host-agent
requirements for a retry budget, output format, version, or priority ordering.
Percent-delimited localization references are not counted as inspected tool
prose; `not_inspected` names unresolved tool and schema descriptions. No sibling
files or remote localization resources are fetched. Skill source catalogs with
`repo` and `skillPath` are explicitly skipped; their bodies are not present.

For a Markdown file with `name`/`description` front matter (a skill or sub-agent
definition) the description is the selection-time text, so H1.1 (no description,
HIGH) and H1.2 (under 20 characters, MEDIUM) apply to it, located at
`frontmatter.description` with its line. H1.8 looks for trigger vocabulary ("use
when", "if the user", "before", a description written as the situation); it is a
finite vocabulary, which is why a long description is only LOW. H1.9's directory
comparison runs only for a file named `SKILL.md`.

H1.3's vague verbs are handle, process, manage, do, perform, deal, work, and it
reports only a description under 60 characters: a vague opener followed by the
specifics has said what the tool does. `get`,
`set`, `run`, `execute`, `use` and `make` were removed: on real MCP manifests every
hit on them was a precise description ("Get the current time in a timezone").
One-sided H1.6 (domination) additionally requires that the two tools share a
domain term, not only a generic verb class, and open with the same action.

H1.5 uses Jaccard word similarity with stopword removal. Differently named tools
whose descriptions each carry a term the other lacks are a parallel family
("List code scanning alerts" / "List secret scanning alerts", add / remove) and
are not reported below 95% overlap; nor is a pair in which a description states
the selection rule ("Prefer this tool over X"). H1.6 compares analyzed
terms from tool names and descriptions under a finite synonym lexicon. It can
reach some pairs missed by word overlap: "Look up an order" and "Search for
orders in the system" have Jaccard 0.00 under H1.5 but no differentia under H1.6's
term model. Mutual nondistinction means neither member distinguishes itself;
directional domination identifies the less-specific member when one contributes
no terms beyond the other. Explicit named boundaries and distinguishing tool
names can exempt a pair; declared aliases are not automatically exempted.

The comparison scope is one parsed input. Directory scans do not aggregate tools
across files or infer a shared selection namespace. H1.6 is MEDIUM and cannot
alone trip `--fail-on fail`; use `--fail-on review` to gate MEDIUM findings.
Its lexicon is finite: pairs outside it, such as kill/terminate or approve/authorize,
are not detected. External labeled-corpus precision and recall have not been
measured. The absence of a finding is not semantic or runtime validation.

Alias recognition is also phrase-bound. `Compatibility alias for X`,
`Deprecated. Use X`, and `Superseded by X` are recognized. Paraphrases such as
"does the same thing as X, kept for backward compatibility" or "older entry
point, prefer X in new code" are not equivalent coverage promises. See
[Tool Differentia and research lineage](/docs/research) for provenance.

</details>

Related: [H1: Tool Description Ambiguity](/rules/h1) · [H1.1: Missing description](/rules/h1.1) · [H1.2: Underspecified short description](/rules/h1.2) · [H1.3: Vague opening verb](/rules/h1.3) · [H1.4: Duplicate tool name](/rules/h1.4) · [H1.5: Near-duplicate descriptions](/rules/h1.5) · [H1.6: Missing tool differentia](/rules/h1.6) · [H1.7: Oversized skill description](/rules/h1.7) · [H1.8: Missing skill trigger](/rules/h1.8).

[All scan rules](/rules) · [Quickstart](/docs/quickstart) · [Separate preflight checks](/docs/preflight).

