/addlightness-review -- read-only weight report
Measure code weight and surface removable "fat" candidates. This is the
diagnostic half of addlightness: it reports, it never edits. For actual
trimming use /addlightness; for performance numbers use /addlightness-bench.
Scope -- READ-ONLY
This skill NEVER modifies files. It reads, measures, and reports. Period.
- No
Edit, no Write, no in-place fixes, no "I went ahead and removed it".
- Output is a report the human reads and decides on.
- If the user wants the trims applied, tell them to run
/addlightness <file...>
(which spawns the edit-capable code-trimmer agent behind an equivalence gate).
- When in doubt, do less: describe the candidate, do not touch the code.
Repeat this contract back to the user if they ask you to "just fix it" here --
review reports, /addlightness edits.
How to run
For each target file, get its weight metrics from the zero-dependency engine.
Two equivalent paths -- prefer the agent for multi-file work, the direct call
for a single quick read:
Via the agent (preferred for >1 file or a fat-candidate narrative):
spawn the weight-analyst agent. It is read-only by contract (its prompt
forbids mutating Bash commands; it has no Edit/Write) and returns the metrics
table plus a ranked fat list and a KEEP list. The agent analyzes one file per
invocation — spawn one weight-analyst invocation per file and aggregate the
JSON yourself.
Direct (single file, fastest):
node "${CLAUDE_PLUGIN_ROOT}/lib/weigh.js" path/to/file.js --json
The engine emits one JSON object per file with the scalar weight plus the
raw components (loc, cyclomatic, imports, functions, nesting,
tokens), an approx boolean (true = JS/TS regex approximation, false =
Python ast-accurate), and the weight_formula string. Parse the JSON line;
do not screen-scrape prose. The approx flag is the authoritative
accuracy signal — read it rather than guessing from the language.
weight = 1.0*loc + 2.0*cyclomatic + 1.5*imports + 1.0*functions + 3.0*nesting
JS/TS metrics are regex-on-stripped-source approximations (comments,
strings, and templates are stripped first). Python metrics come from the
stdlib ast module and are accurate. Say which is which when you report.
Aggregate across all targets into one report. Glob the user's pattern (e.g.
src/**/*.js) yourself, then weigh each match.
Fat categories to flag
For every candidate, report a row -- never an edit:
| field |
meaning |
| category |
one of the categories below |
| location |
file:line (or file:start-end) |
| current |
the exact code as it stands |
| proposed |
what a trim would look like (for the human, not applied) |
| why-safe |
the specific reason removing it preserves behavior |
| risk |
low / medium / high -- residual doubt after why-safe |
Categories:
- single-use-wrapper -- a function/helper called from exactly one site that
adds no abstraction value; inlining removes a hop. Confirm the single call
site with Grep before flagging.
- impossible-defensive-check -- a guard that the local control flow or the
type system already proves can never fire. Only flag when you can show the
proof (the value is produced two lines up, the type is non-null by
construction, etc.). If the value crosses a trust boundary, it goes on the
KEEP list instead -- see below.
- redundant-destructure -- destructuring then immediately re-wrapping, or
pulling fields never used.
- redundant-coercion --
Boolean(x) in a boolean context, String(x) in a
template, !!x where truthiness already suffices, +x on a known number.
- dead-branch / unreachable -- a branch no input can reach, an
if (false), a return followed by code, an arm shadowed by an earlier one.
- useless-async --
async on a function that never awaits and whose
caller does not rely on the Promise wrapping. (Flag cautiously -- check call
sites; removing async changes the return type and turns sync throws into
thrown errors instead of rejected Promises.)
- restate-comment -- a comment that restates the next line (
// increment i
above i++). Why-comments are NOT fat -- never flag those.
- verbose-identifier -- an over-long name in a narrow/private scope where a
shorter one is clearer. Never flag public/exported names.
- unused-import -- an import/require with no remaining reference. Confirm
with Grep across the file (and re-exports) before flagging.
Output
Produce three sections, in this order:
- Metrics table -- one row per file:
weight | loc | cyclomatic | imports | functions | nesting | tokens, with a total/average row. Note JS=approx,
Python=ast-accurate.
- Ranked fat-candidate list -- the rows above, sorted by value-to-risk
(high-confidence, high-payoff first). Group by file.
- KEEP list -- co-equal in importance to the removals. Every defensive
check, validation, guard, or coercion that looks like fat but must stay,
with the reason it stays. The headline reason is the trust boundary:
any value that is externally controlled -- public API parameters, file/socket
IO, parsed/network/env/user/CLI data -- keeps its validation even if current
tests pass without it. A passing test suite with well-formed inputs is NOT
proof the check is dead; it is the #1 way validation gets wrongly stripped.
A review with an empty KEEP list on real code is suspect -- you probably
mislabeled a boundary check as fat.
Weight interpretation
The scalar is a relative before/after metric, not an industry standard.
Lower = lighter. Read the ratios, not raw size:
- comment/LOC > ~0.25 -- comment-heavy; check whether comments restate code
(fat) or explain why (keep).
- high tokens/LOC -- dense long lines / verbose identifiers / long literals;
candidate for naming or extraction (report, don't apply).
- low cyclomatic-per-LOC -- lots of straight-line filler relative to actual
decisions; suggests padding, boilerplate, or copy-paste.
- high LOC/function with low complexity -- long but simple functions =
ceremony/padding rather than essential logic.
- high nesting -- the heaviest-weighted dimension (3.0); deep nesting is the
strongest structural-fat signal (early returns / guard clauses often flatten
it).
Raw LOC alone is a weak signal -- a 200-line file of essential branching can
be leaner than a 60-line file of wrappers. Always pair LOC with the complexity
and nesting ratios.
What NOT to do
- Never modify a file. Not even "a tiny obvious one". Report it.
- Never claim AST precision for JS/TS. Those numbers are regex
approximations on stripped source; say "approximate". Python via
ast may be
called accurate.
- Never flag externally-controlled validation as fat. Trust-boundary checks
go on the KEEP list, with the boundary named.
- Never delete why-comments from the recommendation -- only restate-comments
are candidates.
- Don't flag a single-use-wrapper or unused-import without confirming call
sites / references via Grep first.
- Don't present static metrics as a behavioral guarantee -- they are
change-magnitude and structural signals. The user's own test suite is the
only true equivalence proof, and that proof belongs to
/addlightness, not
here.
1---2name: addlightness-review3description: Read-only code-weight report. Measures LOC, cyclomatic complexity, import count, function count, and nesting depth for one or more files and lists removable 'fat' candidates -- WITHOUT changing any code. Use when the user says "how heavy is this", "weight report", "what's the fat here", "review weight", "analyze complexity", "where can this be trimmed", "is this bloated", or invokes /addlightness-review. Triggers on /addlightness-review. Reports only, never edits; to actually apply trims use /addlightness.4---56# /addlightness-review -- read-only weight report78Measure code weight and surface removable "fat" candidates. This is the9**diagnostic** half of addlightness: it reports, it never edits. For actual10trimming use `/addlightness`; for performance numbers use `/addlightness-bench`.1112## Scope -- READ-ONLY1314**This skill NEVER modifies files.** It reads, measures, and reports. Period.1516- No `Edit`, no `Write`, no in-place fixes, no "I went ahead and removed it".17- Output is a report the human reads and decides on.18- If the user wants the trims applied, tell them to run `/addlightness <file...>`19 (which spawns the edit-capable `code-trimmer` agent behind an equivalence gate).20- When in doubt, do less: describe the candidate, do not touch the code.2122Repeat this contract back to the user if they ask you to "just fix it" here --23review reports, `/addlightness` edits.2425## How to run2627For each target file, get its weight metrics from the zero-dependency engine.28Two equivalent paths -- prefer the agent for multi-file work, the direct call29for a single quick read:30311. **Via the agent (preferred for >1 file or a fat-candidate narrative):**32 spawn the `weight-analyst` agent. It is read-only by contract (its prompt33 forbids mutating Bash commands; it has no Edit/Write) and returns the metrics34 table plus a ranked fat list and a KEEP list. The agent analyzes one file per35 invocation — spawn one weight-analyst invocation per file and aggregate the36 JSON yourself.37382. **Direct (single file, fastest):**3940 ```bash41 node "${CLAUDE_PLUGIN_ROOT}/lib/weigh.js" path/to/file.js --json42 ```4344 The engine emits one JSON object per file with the scalar `weight` plus the45 raw components (`loc`, `cyclomatic`, `imports`, `functions`, `nesting`,46 `tokens`), an `approx` boolean (true = JS/TS regex approximation, false =47 Python ast-accurate), and the `weight_formula` string. Parse the JSON line;48 do not screen-scrape prose. The `approx` flag is the authoritative49 accuracy signal — read it rather than guessing from the language.5051 ```52 weight = 1.0*loc + 2.0*cyclomatic + 1.5*imports + 1.0*functions + 3.0*nesting53 ```5455 JS/TS metrics are **regex-on-stripped-source approximations** (comments,56 strings, and templates are stripped first). Python metrics come from the57 stdlib `ast` module and are accurate. Say which is which when you report.5859Aggregate across all targets into one report. Glob the user's pattern (e.g.60`src/**/*.js`) yourself, then weigh each match.6162## Fat categories to flag6364For every candidate, report a row -- never an edit:6566| field | meaning |67| --- | --- |68| category | one of the categories below |69| location | `file:line` (or `file:start-end`) |70| current | the exact code as it stands |71| proposed | what a trim would look like (for the human, not applied) |72| why-safe | the specific reason removing it preserves behavior |73| risk | `low` / `medium` / `high` -- residual doubt after why-safe |7475Categories:7677- **single-use-wrapper** -- a function/helper called from exactly one site that78 adds no abstraction value; inlining removes a hop. Confirm the single call79 site with Grep before flagging.80- **impossible-defensive-check** -- a guard that the local control flow or the81 type system already proves can never fire. **Only flag when you can show the82 proof** (the value is produced two lines up, the type is non-null by83 construction, etc.). If the value crosses a trust boundary, it goes on the84 KEEP list instead -- see below.85- **redundant-destructure** -- destructuring then immediately re-wrapping, or86 pulling fields never used.87- **redundant-coercion** -- `Boolean(x)` in a boolean context, `String(x)` in a88 template, `!!x` where truthiness already suffices, `+x` on a known number.89- **dead-branch / unreachable** -- a branch no input can reach, an90 `if (false)`, a `return` followed by code, an arm shadowed by an earlier one.91- **useless-async** -- `async` on a function that never awaits and whose92 caller does not rely on the Promise wrapping. (Flag cautiously -- check call93 sites; removing `async` changes the return type and turns sync throws into94 thrown errors instead of rejected Promises.)95- **restate-comment** -- a comment that restates the next line (`// increment i`96 above `i++`). Why-comments are NOT fat -- never flag those.97- **verbose-identifier** -- an over-long name in a narrow/private scope where a98 shorter one is clearer. Never flag public/exported names.99- **unused-import** -- an import/require with no remaining reference. Confirm100 with Grep across the file (and re-exports) before flagging.101102## Output103104Produce three sections, in this order:1051061. **Metrics table** -- one row per file: `weight | loc | cyclomatic | imports |107 functions | nesting | tokens`, with a total/average row. Note JS=approx,108 Python=ast-accurate.1092. **Ranked fat-candidate list** -- the rows above, sorted by value-to-risk110 (high-confidence, high-payoff first). Group by file.1113. **KEEP list** -- *co-equal in importance to the removals.* Every defensive112 check, validation, guard, or coercion that **looks like fat but must stay**,113 with the reason it stays. The headline reason is the **trust boundary**:114 any value that is externally controlled -- public API parameters, file/socket115 IO, parsed/network/env/user/CLI data -- keeps its validation even if current116 tests pass without it. A passing test suite with well-formed inputs is NOT117 proof the check is dead; it is the #1 way validation gets wrongly stripped.118119A review with an empty KEEP list on real code is suspect -- you probably120mislabeled a boundary check as fat.121122## Weight interpretation123124The scalar is a **relative** before/after metric, not an industry standard.125Lower = lighter. Read the ratios, not raw size:126127- **comment/LOC > ~0.25** -- comment-heavy; check whether comments restate code128 (fat) or explain why (keep).129- **high tokens/LOC** -- dense long lines / verbose identifiers / long literals;130 candidate for naming or extraction (report, don't apply).131- **low cyclomatic-per-LOC** -- lots of straight-line filler relative to actual132 decisions; suggests padding, boilerplate, or copy-paste.133- **high LOC/function with low complexity** -- long but simple functions =134 ceremony/padding rather than essential logic.135- **high nesting** -- the heaviest-weighted dimension (3.0); deep nesting is the136 strongest structural-fat signal (early returns / guard clauses often flatten137 it).138139**Raw LOC alone is a weak signal** -- a 200-line file of essential branching can140be leaner than a 60-line file of wrappers. Always pair LOC with the complexity141and nesting ratios.142143## What NOT to do144145- **Never modify a file.** Not even "a tiny obvious one". Report it.146- **Never claim AST precision for JS/TS.** Those numbers are regex147 approximations on stripped source; say "approximate". Python via `ast` may be148 called accurate.149- **Never flag externally-controlled validation as fat.** Trust-boundary checks150 go on the KEEP list, with the boundary named.151- **Never delete why-comments** from the recommendation -- only restate-comments152 are candidates.153- **Don't flag a single-use-wrapper or unused-import without confirming** call154 sites / references via Grep first.155- **Don't present static metrics as a behavioral guarantee** -- they are156 change-magnitude and structural signals. The user's own test suite is the157 only true equivalence proof, and that proof belongs to `/addlightness`, not158 here.