Purpose
Every reference the plugin prints, every lane's collector order, the scope exclusions, and the
coverage artifact paths resolve through one consumer surface, .claude/code-metrics.yaml,
layered as user-global (~/.claude/code-metrics.yaml), team (tracked), and local overlay
(.claude/code-metrics.local.yaml, gitignored) with per-key override. All three layers absent is
a valid state: every key has a bundled default. This skill is the check-centric setup for that
surface and for the external collectors the audits probe: check inspects and verifies, apply
persists, and neither installs anything. Keys, defaults, and provenance:
${CLAUDE_PLUGIN_ROOT}/reference/config.md.
Action routing: no argument or check runs the check; apply runs the check first, then
persists. apply is non-interactive when complete <key>=<value> arguments are supplied
(automation and headless use pass them and are never prompted); with none, it interviews one key
at a time, recommendation first.
check (read-only)
Run and present the table as printed:
"${CLAUDE_SKILL_DIR}/scripts/setup-check.sh"
Rows, each PASS, FAIL, WARN, or INFO:
- python: the interpreter resolved (
python3, python, or py -3) and the plugin's floor.
FAIL stops the table: Python is required for correctness, so name the remediation.
- layer user-global / team / local: absent (INFO), or present and parsed in the YAML subset
the plugin reads (block mappings, block sequences, flow sequences of scalars, scalars,
comments). A flow mapping, anchor, tag, or block scalar is FAIL with its line; the operator
rewrites the file in block style.
- layer team tracked:
git check-ignore -v on the team file reports no match (a match is
FAIL with the rule: an ignored team layer never reaches the team) and git ls-files --error-unmatch sees it (untracked is WARN: written but uncommitted).
- layer local ignored: the overlay is gitignored, else WARN with the recommended consumer
line
.claude/**/*.local.*. Recommend the line; never edit the consumer's .gitignore.
- ecosystem
<lane>.yaml: each consumer ecosystem file parses; its globs and enabled
override lane detection.
- reference
<measure>: the resolved value with the layer that supplied it and its
provenance, so a personal layer that changed a value is visible.
- collector
<tool>: PASS with the version when the adapter's probe resolves the tool on
PATH; INFO missing with the install hint otherwise. Missing is not a failure: the lane
reports unavailable at audit time and the run continues.
Exit 0 with no FAIL row, 1 with one, 2 on a usage or environment error.
apply (idempotent)
Run check and read its table.
Resolve the values. With complete <key>=<value> arguments, use them directly. Otherwise
interview one key at a time, recommendation first, walking the annotated template
${CLAUDE_SKILL_DIR}/templates/config-template.yaml (every key with its default and
provenance, in the subset; the key reference is ${CLAUDE_PLUGIN_ROOT}/reference/config.md):
the cyclomatic reference (20, ISO/IEC 5055 §8.2.117; 10 and 15 are the cited alternatives),
the file-length reference (1000, the plugin's own number; 500 selectable) and size.mode,
scope exclusions, coverage artifact paths, per-lane opt-outs and collector order, duplication
registries. Offer every declared key, preserve every key the existing file carries, and never
invent a key beyond the contract. A key outside the contract is written but reported, because
unknown keys are inert to the plugin.
Persist. One call per run, every value as <key>=<value> in the YAML subset:
"${CLAUDE_SKILL_DIR}/scripts/setup-apply.py" size.file_lines=500 'scope.exclude=["vendor/**"]'
The script merges per key into the repository root's .claude/code-metrics.yaml (the root
git reports from the current directory; --dir <root> or --file <path> overrides it),
writes block style, and prints already configured without touching the file when nothing
changes.
Verify. Re-run check; report the persisted values from its table, never from the write
alone. The tracked-file pair decides the outcome: a WARN written but untracked means "commit
it to share with the team", never success; an ignored team file is FAIL and the operator's
.gitignore is theirs to fix.
Output
check: the table. apply: the table before and after, the written path, and one line on how
to re-run this skill to reconfigure. Say which layer supplied each reference that differs from the
bundled default.
What this skill does NOT do
- Install, download, or
npx-fetch a collector. It prints install hints; the operator installs.
- Write the user-global or local layers. Those are personal files the operator edits.
- Write Claude Code user settings or
pluginConfigs; the plugin has no userConfig.
- Edit the consumer's
.gitignore; it recommends the one recursive line.
- Run an audit. The audit skills read the same resolved document at run time.
Next
/code-metrics:audit-complexity. The sibling audit-* skills cover the other measures.
Gotchas
- The team file must be committed to reach the team;
apply leaves it untracked on purpose and
the check row says so until it is committed.
apply judges idempotence on parsed content, so hand-written comments never force a rewrite
by themselves; a value that differs does, and the file is rewritten in block style.
- A layer written with a flow mapping (
{ enabled: true }) is outside the subset; every audit
reports the file as unreadable with the line, and check shows the same row.
size.mode: iso-8.2.115 needs a collector that reports function ranges (lizard, radon);
Bash has none, and its row says so.
1---2name: setup-303description: Verify or configure the code-metrics plugin for this repository: `check` probes the interpreter, every configuration layer (user-global, team, local overlay, and the consumer's ecosystem files) for the YAML subset and the tracked-file guard, prints every reference with the layer that supplied it, and probes each collector adapter (a version, or missing with its install hint); `apply` writes the tracked `.claude/code-metrics.yaml` team layer per key, idempotently, never installing a tool and never editing `.gitignore`. Use when: 'set up code-metrics', 'configure code metrics', 'is code-metrics configured', 'which collectors are installed', 'set the cyclomatic reference', 'change the file length reference', 'code-metrics setup', or an audit skill reports a configuration layer it could not read.4---56## Purpose78Every reference the plugin prints, every lane's collector order, the scope exclusions, and the9coverage artifact paths resolve through one consumer surface, `.claude/code-metrics.yaml`,10layered as user-global (`~/.claude/code-metrics.yaml`), team (tracked), and local overlay11(`.claude/code-metrics.local.yaml`, gitignored) with per-key override. All three layers absent is12a valid state: every key has a bundled default. This skill is the check-centric setup for that13surface and for the external collectors the audits probe: `check` inspects and verifies, `apply`14persists, and neither installs anything. Keys, defaults, and provenance:15`${CLAUDE_PLUGIN_ROOT}/reference/config.md`.1617Action routing: no argument or `check` runs the check; `apply` runs the check first, then18persists. `apply` is non-interactive when complete `<key>=<value>` arguments are supplied19(automation and headless use pass them and are never prompted); with none, it interviews one key20at a time, recommendation first.2122## `check` (read-only)2324Run and present the table as printed:2526```bash27"${CLAUDE_SKILL_DIR}/scripts/setup-check.sh"28```2930Rows, each PASS, FAIL, WARN, or INFO:31321. **python**: the interpreter resolved (`python3`, `python`, or `py -3`) and the plugin's floor.33 FAIL stops the table: Python is required for correctness, so name the remediation.342. **layer user-global / team / local**: absent (INFO), or present and parsed in the YAML subset35 the plugin reads (block mappings, block sequences, flow sequences of scalars, scalars,36 comments). A flow mapping, anchor, tag, or block scalar is FAIL with its line; the operator37 rewrites the file in block style.383. **layer team tracked**: `git check-ignore -v` on the team file reports no match (a match is39 FAIL with the rule: an ignored team layer never reaches the team) and `git ls-files40 --error-unmatch` sees it (untracked is WARN: written but uncommitted).414. **layer local ignored**: the overlay is gitignored, else WARN with the recommended consumer42 line `.claude/**/*.local.*`. Recommend the line; never edit the consumer's `.gitignore`.435. **ecosystem `<lane>.yaml`**: each consumer ecosystem file parses; its `globs` and `enabled`44 override lane detection.456. **reference `<measure>`**: the resolved value with the layer that supplied it and its46 provenance, so a personal layer that changed a value is visible.477. **collector `<tool>`**: PASS with the version when the adapter's probe resolves the tool on48 `PATH`; INFO `missing` with the install hint otherwise. Missing is not a failure: the lane49 reports `unavailable` at audit time and the run continues.5051Exit 0 with no FAIL row, 1 with one, 2 on a usage or environment error.5253## `apply` (idempotent)54551. Run `check` and read its table.562. **Resolve the values.** With complete `<key>=<value>` arguments, use them directly. Otherwise57 interview one key at a time, recommendation first, walking the annotated template58 `${CLAUDE_SKILL_DIR}/templates/config-template.yaml` (every key with its default and59 provenance, in the subset; the key reference is `${CLAUDE_PLUGIN_ROOT}/reference/config.md`):60 the cyclomatic reference (20, ISO/IEC 5055 §8.2.117; 10 and 15 are the cited alternatives),61 the file-length reference (1000, the plugin's own number; 500 selectable) and `size.mode`,62 scope exclusions, coverage artifact paths, per-lane opt-outs and collector order, duplication63 registries. Offer every declared key, preserve every key the existing file carries, and never64 invent a key beyond the contract. A key outside the contract is written but reported, because65 unknown keys are inert to the plugin.663. **Persist.** One call per run, every value as `<key>=<value>` in the YAML subset:6768 ```bash69 "${CLAUDE_SKILL_DIR}/scripts/setup-apply.py" size.file_lines=500 'scope.exclude=["vendor/**"]'70 ```7172 The script merges per key into the repository root's `.claude/code-metrics.yaml` (the root73 git reports from the current directory; `--dir <root>` or `--file <path>` overrides it),74 writes block style, and prints `already configured` without touching the file when nothing75 changes.764. **Verify.** Re-run `check`; report the persisted values from its table, never from the write77 alone. The tracked-file pair decides the outcome: a WARN `written but untracked` means "commit78 it to share with the team", never success; an ignored team file is FAIL and the operator's79 `.gitignore` is theirs to fix.8081## Output8283`check`: the table. `apply`: the table before and after, the written path, and one line on how84to re-run this skill to reconfigure. Say which layer supplied each reference that differs from the85bundled default.8687## What this skill does NOT do8889- Install, download, or `npx`-fetch a collector. It prints install hints; the operator installs.90- Write the user-global or local layers. Those are personal files the operator edits.91- Write Claude Code user settings or `pluginConfigs`; the plugin has no `userConfig`.92- Edit the consumer's `.gitignore`; it recommends the one recursive line.93- Run an audit. The audit skills read the same resolved document at run time.9495## Next9697`/code-metrics:audit-complexity`. The sibling `audit-*` skills cover the other measures.9899## Gotchas100101- The team file must be committed to reach the team; `apply` leaves it untracked on purpose and102 the `check` row says so until it is committed.103- `apply` judges idempotence on parsed content, so hand-written comments never force a rewrite104 by themselves; a value that differs does, and the file is rewritten in block style.105- A layer written with a flow mapping (`{ enabled: true }`) is outside the subset; every audit106 reports the file as unreadable with the line, and `check` shows the same row.107- `size.mode: iso-8.2.115` needs a collector that reports function ranges (`lizard`, `radon`);108 Bash has none, and its row says so.