From docs-hygiene
Audit and remediate skill-encapsulation violations — external citations reaching into private surfaces inside `.claude/skills/<X>/` beyond the slash invocation. Use when: 'audit encapsulation', 'find skill leaks', 'skill boundary violation', 'who is reaching into <skill>', 'check skill boundaries', 'public API drift', or before refactoring a skill.
How this skill is triggered — by the user, by Claude, or both
Slash command
/docs-hygiene:audit-encapsulation [detect|fix|file-issues][detect|fix|file-issues]The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Skills have a public API and a private body — the contract is `context/public-surface-contract.md` (bundled with this skill). External consumers — rules, agents, other skills, prose docs — must cite the public surface only. Editing the private body must not break external consumers because no external consumer is allowed to depend on it.
Skills have a public API and a private body — the contract is context/public-surface-contract.md (bundled with this skill). External consumers — rules, agents, other skills, prose docs — must cite the public surface only. Editing the private body must not break external consumers because no external consumer is allowed to depend on it.
Without enforcement, private bodies leak. A rule file cites a path inside <skill>/<some-subdir>/ because the content is convenient. The skill author refactors that subdir and the citation breaks silently — nothing fails the build, nothing greps red. The skill cannot evolve without coordinating with every leaker.
This skill provides the detection + classification + remediation discipline that closes that gap. Distinct concern from /extract-ssot (which detects content duplication via Rule of Three). Encapsulation violations are single-violation matters — Rule of Three does not gate them.
The Skill surface — public = frontmatter + documented actions + args/flags + /skill-name slash invocation + the scripts/ entry surface; private = everything else inside .claude/skills/<X>/ (any OTHER subdirectory, all *.schema.json at any depth, all heading anchors) — is defined by context/public-surface-contract.md, including the data-file and scripts/ entry-surface carve-outs and the rip-and-paste-portability rationale. This skill audits cites against two more authoring surfaces the contract file does not enumerate:
| Surface | Public (cite externally) | Private |
|---|---|---|
Rule file (.claude/rules/*.md) | All H2/H3 headings (entire file is shared vocabulary) | n/a |
Scheduled-automation prompt (e.g. .claude/routines/*.md, if the consumer repo keeps them) | Top-of-file orchestration prompt | Internal exclusion lists, escape conditions |
Workflows and git hooks needing logic that ALSO lives in a skill must not reach into skill internals. Pick a sharing technique by logic size — scripts/ facade (the skill exposes a public scripts/<name>.sh entry delegating to a private backend; hooks/CI invoke it), intentional duplication, plugin packaging, or headless claude -p '/skill <action>' invocation — per context/public-surface-contract.md "CI / git-hook consumption — entry surface, not internals".
The choice is per-cite. The bundled detect script is this plugin's detector; any hard gate (pre-commit hook, CI job, drift comparison against a vendored copy) is whatever the consuming repo wires around it.
| Argument | Action | Purpose |
|---|---|---|
(empty) / detect | Default | Run detection grep, classify legal vs illegal, output violation table |
fix <file>:<line> | Targeted remediation | Interactive Path A (promote-out) vs Path B (route-via-/<skill>) for one hit |
file-issues | Batch | File one tracking work item per illegal hit in the consumer's tracker (e.g. gh issue create); emit a checklist if no tracker is available |
One action per response.
bash "${CLAUDE_SKILL_DIR}/scripts/detect.sh" (--apply-filters optional)
<X>/<any-subdir>/... — regardless of subdir name) except scripts/ (entry-surface carve-out, see below)SKILL.md body structure (<X>/SKILL.md#<anchor>)*.schema.json file at any depth (<X>/<file>.schema.json)Legal external cites: bare <X>/SKILL.md path (discouraged but legal — natural-language + slash invocation is canonical), <X>/<file>.json data files at skill root (data-file carve-out), and <X>/scripts/<entry> entry scripts (entry-surface carve-out below).
scripts/ entry-surface carve-out: a skill's scripts/ is its declared ENTRY surface per context/public-surface-contract.md. Harness / CI / hooks / workflow registries MAY path-cite a skill's entry scripts directly, so this inbound audit treats <X>/scripts/... cites as legal (like data files and bare SKILL.md) and never flags them. The skill-to-skill half of the asymmetry — a sibling SKILL.md citing another skill's scripts/ stays slash-only — is out of this inbound audit's scope; a consuming repo that wants it enforced wires its own outbound gate.
The script scans the consumer repo it runs in: every .claude/ child directory except skills/ (self-citation domain; opt in via --include-skills for skill-maintenance review) and worktrees/, plus .github/, docs/, .lefthook/, root instruction/config files (AGENTS.md, CLAUDE.md, README.md, CONTRIBUTING.md, lefthook.yml), and .claude/ top-level files — each filtered to what exists.
Or invoke the skill (the agent applies the filter taxonomy below):
/audit-encapsulation detect
detect.sh output is broad without --apply-filters. Use the filter taxonomy below for KIND-1/2/3; --apply-filters drops self-citation, plugin cache, and worktree paths.
| Filter | Hit shape | Why legal |
|---|---|---|
| Self-citation | .claude/skills/<X>/SKILL.md cites .claude/skills/<X>/<private-path> | Intra-skill progressive disclosure (per context/public-surface-contract.md) |
| KIND-1 meta-prose | A rule or doc describing the encapsulation contract itself, OR documenting skill internals as a worked example / historical narrative / empirically-verified quirk | Self-referential explanatory prose, not citation |
| KIND-2 forced-cite | Another tool's semantics structurally require a verbatim path (a path-scoped rule trigger, a watch-glob, a drift-gate comparing against a vendored copy) | Citation IS the structural contract |
| KIND-3 self-test | This skill's / a hook's own regression fixtures embed literal violation strings | Exercise the filter; not real citations |
| Mirror-automation | A scheduled-automation prompt (e.g. .claude/routines/<name>.md) cites .claude/skills/<name>/<private-path> when its basename matches the skill name | Such prompts are cron arms of slash skills; mirror cites are part of the skill contract per the Public surface matrix |
| Glob-config | Skill-internal path used as a glob/filter in an exclusion list, hooks allowlist, or .gitignore — not a content Read cite | Path is structural filter syntax, not progressive-disclosure content (overlaps KIND-2; named separately for grading) |
| Plugin cache | ~/.claude/plugins/cache/<plugin>/... | Upstream territory; foreign contract |
| Worktree path | <worktree-root>/<n>/.claude/skills/<X>/... (per the repo's worktree convention — e.g. .worktrees/, .claude/worktrees/, .git/worktrees/) | Worktrees share the tracked tree; same rules apply at the root path |
Hits that survive ALL filters = illegal. Report.
Use when: the caller needs data the private file contains, and the data is genuinely shared vocabulary or constraint.
/extract-ssot verify (the 6-gate refuse-fast check) to the private file's content.claude/rules/<topic>.md, or extend an existing one)/rename-references to sweep all syntactic forms/skill-name invocation (caller wants the behavior)Use when: the caller wants the skill's behavior, not the data. A reference into the private body is a workaround because the skill has no public action covering the use case.
/<skill-name> <action> <args># TODO(audit-encapsulation): missing /<skill> <action> markerWhen invoked from another skill's execute pass (e.g. /extract-ssot execute):
| Step | Action |
|---|---|
| 1 | Run the detection grep against the caller list (or repo-wide) |
| 2 | Classify each match via the filter taxonomy: legal hit vs violation |
| 3 | For each violation, choose Path A (promote) or Path B (route via /name) |
| 4 | DO NOT preserve a violation because "it works today" — broken-window pattern |
| 5 | If Path B is needed but the action is missing, file a tracking work item and STOP — don't ship a partial fix |
| 6 | Run a /rename-references sweep after edits |
A surfaced violation is never silently ignored: fix it, capture it as a side note to the user, or file a tracking work item.
# Encapsulation audit — N violations
## Violations
| File | Line | Cite | Suggested path |
|------|------|------|----------------|
| ... | ... | `<skill>/<dir>/<file>` | A or B |
## Filtered (legal — sample for verification)
| File | Line | Filter applied |
|------|------|----------------|
## Summary
- Total raw hits: M
- Filtered legal: M-N
- Illegal violations: N
- Path A candidates: a
- Path B candidates: b
- Missing public action (Path B blocked): c
## Recommended next step
`/audit-encapsulation fix <file>:<line>` for one-by-one OR `/audit-encapsulation file-issues` for batch work-item filing
# TODO(audit-encapsulation) marker requirement.| When | Check | Evidence |
|---|---|---|
| Pre-detection | git ls-files enumerable in scope | Bash output |
| Post-detection | Each raw hit classified per filter taxonomy OR illegal | Diff against filter table |
| Pre-fix | Path A vs Path B chosen with explicit data-vs-behavior reasoning | Session notes or plan artifact |
| Post-fix | Detection grep re-run; violation count decreased | Bash output |
| Post-fix | /rename-references sweep ran | Tool output |
/extract-ssotexport, .NET internal, Python _prefix) → language-level tooling (compiler, lint)context/public-surface-contract.md — canonical definition of what's public vs private, both carve-outs, the violation-shape table, and the CI / git-hook consumption techniques/extract-ssot verify — 6-gate refuse-fast check for Path A "promote out" decisions/extract-ssot execute — writes the SSOT and sweeps citations after a Path A migration/extract-ssot — duplication-skill counterpart; an encapsulation violation is one of its failure modes (cross-cite)/rename-references — load-bearing multi-pattern sweep after any heading change| Condition | Action |
|---|---|
context/public-surface-contract.md changes | Re-sync the Public surface matrix here and the pattern comments in scripts/detect.sh |
| A new CI workflow or git hook needs skill logic | Pick a technique from context/public-surface-contract.md "CI / git-hook consumption — entry surface, not internals"; prefer a skill scripts/ facade the hook invokes — no vendored copy |
| Violations recur across audits | Promote the detect action to a scheduled cadence in the consumer repo (e.g. /loop or /schedule) |
| Anthropic ships a native skill-boundary linter | Demote this skill to advisory or sunset it |
Guides completion of development work by verifying tests, detecting environment, and presenting structured options for merge, PR, or cleanup.
Guides creation and editing of skills using test-driven development with pressure scenarios and subagents to verify agent compliance.
Dispatches multiple subagents concurrently for independent tasks without shared state. Use when facing 2+ unrelated failures or subsystems that can be investigated in parallel.
npx claudepluginhub melodic-software/claude-code-plugins --plugin docs-hygiene