Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/claude-code-marketplace.json",
"name": "clean-code-toolkit",
"version": "3.5.1",
"version": "3.5.2",
"description": "Clean-code and product-handoff tools for AI-assisted builders.",
"owner": {
"name": "Tarik Moody"
Expand All @@ -10,7 +10,7 @@
{
"name": "clean-code-toolkit",
"description": "Review code, assess product readiness, refactor safely, and prepare a developer handoff.",
"version": "3.5.1",
"version": "3.5.2",
"author": {
"name": "Tarik Moody"
},
Expand Down
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "clean-code-toolkit",
"version": "3.5.1",
"version": "3.5.2",
"description": "Practical clean-code, product-readiness, and developer-handoff workflows for AI-assisted projects.",
"author": {
"name": "Tarik Moody"
Expand Down
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Changelog

## 3.5.2

A developer-experience audit of the toolkit itself: install it fresh, run the CLI, break it on purpose, read every doc link. Four things it found.

**An empty folder used to get a grade.** Pointed at a directory with nothing in it, the tool reported "Repository Controls Score: 65/100, D, release blockers present" with four CRITICAL findings, and never said the folder was empty. A mistyped path produced a confident report about nothing, which is the same failure 3.5.1 shipped three fixes for. It now refuses: it says what is wrong, says to pass `--repo .` instead, and exits 2. **This is a behavior change.** A pipeline pointed at a path with no files used to exit 0 and now exits 2. See `docs/decisions/008`.

**A folder that is not a git repository now says so, at the top of the report.** The scan still runs, because there are real files and the findings mean something, but `git ls-files` is unavailable, so `.gitignore` is not applied and `node_modules` or build output can be read as source. That caveat now appears above the score instead of nowhere.

**The toolkit shipped ten files its own linter rejects.** `check_report.py` refuses em and en dashes in generated documents. Eight shipped files contained em dashes, including `plain-english-glossary.md`, the file that defines the plain-English house style, and all five stack reference files. Two contained en dashes. The 3.5.0 entry claiming em dashes were "gone from every skill, command and template" was true of those three directories and never covered `references/`. All ten are fixed, and `validate-toolkit.sh` now enforces the rule, so it cannot come back. The rule was previously enforced only on documents the tool generated, never on the documents it ships.

**`add-clean-code.sh --help` was a dead end.** It printed "Unknown option: --help" and exited 64. The usage text already existed as a comment at the top of the same file and was never printed. `--help` and `-h` now print it and exit 0, and an unknown flag prints it too.

Tests: 92.

## 3.5.1

Five defects, and one thing underneath all of them: the engine only really knew Node. Two of these were saying something false about any repository a user ran them on today.
Expand Down
21 changes: 21 additions & 0 deletions docs/decisions/008-refuse-to-grade-an-empty-folder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# 008: An empty folder gets refused, not graded

**Decision.** When the target directory contains no files, the audit stops with an error and exit code 2 instead of producing a report. A directory that has files but is not a git repository still runs, and the report opens with a warning that `.gitignore` was not applied.

**Why this came up.** A developer experience audit ran the tool against an empty directory. It returned "Repository Controls Score: 65/100, D, release blockers present" and four CRITICAL findings, and never mentioned that the folder was empty. A person who mistypes a path gets a confident grade about nothing. This is the same failure the v3.5.1 release existed to fix, three times over: a tool claiming more than it checked. What was at stake is the only thing this tool sells, which is that its output can be trusted without re-checking it by hand.

**Options.**
1. Leave it. The report does say "none detected" on every stack line, so a careful reader could work it out. Cost: the score, the grade and the word CRITICAL are the parts people actually read, and all three are false.
2. Produce the report but add a banner saying the folder is empty. Cost: it still prints a grade. A grade for nothing is not made true by a banner above it, and CI gating on `--fail-on` would still act on it.
3. Refuse. Print what is wrong, print what to do instead, exit non-zero. Cost: exit code 2 on an empty directory is a behavior change. Anyone whose pipeline pointed at the wrong path was previously getting a silent pass and will now get a failure.

**What we chose and why.** Option 3. Joint call. The cost of option 3 is a pipeline that breaks and tells you why, which is the correct outcome for a pipeline that was auditing nothing. The cost of options 1 and 2 is a false grade that somebody acts on.

The "not a git repository" case is deliberately treated differently. There are real files, so the checks have something to read and the findings mean something. But `git ls-files` is unavailable, so `.gitignore` is not applied and `node_modules` or build output can be read as source. That is a caveat on a real result, not a refusal.

**What we gave up.** A pipeline pointed at a wrong path used to exit 0 and now exits 2. We judged that a fix, not a regression, but it is a breaking change in a patch release and the CHANGELOG says so.

**How we'll know if this was right.** Nobody reports a score for a directory they did not mean to audit. If someone's CI breaks after upgrading, the error message tells them their path is wrong in one line, and that is the finding.

**What actually happened.**
(Tarik fills this in.)
20 changes: 19 additions & 1 deletion scripts/add-clean-code.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,31 @@

set -euo pipefail

usage() {
cat <<'USAGE'
Install or update the Clean Code Standards block in a project's CLAUDE.md.

Usage: add-clean-code.sh [target-dir] [--update] [--check] [--help]

target-dir project to install into (default: the current directory)
(no flag) install if absent; if present but out of date, say so and exit 3
--check report only, change nothing (exit 3 if an update is available)
--update replace the managed block in place, leaving everything else alone
--help show this message

The block is delimited by BEGIN/END markers and carries a version, so an
installed copy can be compared with the shipped one.
USAGE
}

target_dir="."
mode="install"
for arg in "$@"; do
case "${arg}" in
--update) mode="update" ;;
--check) mode="check" ;;
--*) echo "Unknown option: ${arg}" >&2; exit 64 ;;
-h|--help) usage; exit 0 ;;
--*) echo "Unknown option: ${arg}" >&2; echo >&2; usage >&2; exit 64 ;;
*) target_dir="${arg}" ;;
esac
done
Expand Down
24 changes: 23 additions & 1 deletion scripts/validate-toolkit.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,16 +159,38 @@ def validate_installer() -> None:
raise ValidationError("Installer did not preserve a legacy Clean Code Standards section")


def validate_house_style() -> None:
"""check_report.py rejects em and en dashes in generated docs. The toolkit
that enforces that rule on other people's reports cannot ship them itself."""
offenders = []
for base in ("skills", "commands", "templates"):
directory = ROOT / base
if not directory.exists():
continue
for path in sorted(directory.rglob("*.md")):
text = path.read_text(encoding="utf-8", errors="ignore")
for lineno, line in enumerate(text.splitlines(), 1):
if "\u2014" in line or "\u2013" in line:
offenders.append(f"{path.relative_to(ROOT)}:{lineno}")
if offenders:
raise ValidationError(
"em or en dash in shipped text (house style uses plain punctuation): "
+ ", ".join(offenders[:10])
+ (f" and {len(offenders) - 10} more" if len(offenders) > 10 else "")
)


def main() -> int:
try:
validate_skills()
validate_plugin()
validate_installer()
validate_house_style()
except (ValidationError, OSError, subprocess.CalledProcessError) as error:
print(f"Validation failed: {error}")
return 1

print("Validated skills, plugin manifests, and installer runtime successfully.")
print("Validated skills, plugin manifests, installer runtime, and house style successfully.")
return 0


Expand Down
4 changes: 2 additions & 2 deletions skills/boy-scout-cleanup/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: boy-scout-cleanup
description: "Make 35 small, local, behavior-preserving improvements to existing code. Use when the user asks to tidy a file, clean up code while working nearby, remove local clutter, or make a module easier to read. Do not use for a read-only review, public API changes, file moves, broad rewrites, or feature work."
description: "Make 3 to 5 small, local, behavior-preserving improvements to existing code. Use when the user asks to tidy a file, clean up code while working nearby, remove local clutter, or make a module easier to read. Do not use for a read-only review, public API changes, file moves, broad rewrites, or feature work."
---

# Boy Scout Cleanup
Expand Down Expand Up @@ -42,7 +42,7 @@ Use `/refactor` for structural work and `clean-code-review` for read-only assess

## Workflow

1. Choose at most 35 related improvements.
1. Choose at most 3 to 5 related improvements.
2. Apply the smallest possible patches; do not rewrite the whole file.
3. Preserve strictness, ordering, side effects, mutation, exceptions, and public names.
4. Run the narrowest relevant checks, followed by broader configured checks when practical.
Expand Down
2 changes: 1 addition & 1 deletion skills/clean-code-review/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,5 @@ Report in chat by default. Write a file only if the user asks, and then to a pat

- For a product-level assessment, use `product-readiness-review`.
- For a developer-ready handoff document, use `developer-handoff`.
- For 35 local, behavior-preserving improvements, use `boy-scout-cleanup`.
- For 3 to 5 local, behavior-preserving improvements, use `boy-scout-cleanup`.
- For structural edits, use `/refactor` and verify behavior before and after.
8 changes: 4 additions & 4 deletions skills/clean-code-review/references/report-format.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ State what was reviewed, overall confidence, and whether the code appears safe t
Order findings by severity. For each finding include:

1. **Title and severity**
2. **Location** file and tight line range
3. **Evidence** what the code demonstrably does
4. **Impact** realistic user, operational, or maintenance consequence
5. **Recommendation** smallest credible fix
2. **Location**: file and tight line range
3. **Evidence**: what the code demonstrably does
4. **Impact**: realistic user, operational, or maintenance consequence
5. **Recommendation**: smallest credible fix

For beginner-facing reports, express evidence, impact, and recommendation as What / Why / Fix.

Expand Down
4 changes: 2 additions & 2 deletions skills/clean-code-review/references/review-rubric.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Only make claims supported by code or configured tools. Recommend a dedicated se

- Prefer visible, unsurprising flow and manageable nesting.
- Flag duplicated decisions, invalid states that are easy to construct, and mutation that is hard to track.
- Early returns, tables, composition, or polymorphism are optionsnot automatic answers.
- Early returns, tables, composition, or polymorphism are options, not automatic answers.

## 6. Interfaces and dependencies

Expand All @@ -55,7 +55,7 @@ Only make claims supported by code or configured tools. Recommend a dedicated se
## 8. Tests and change safety

- Test important behavior, business rules, boundaries, and regressions.
- Evaluate whether the tests would catch the proposed failurenot merely whether a test file exists.
- Evaluate whether the tests would catch the proposed failure, not merely whether a test file exists.
- Prefer characterization tests before risky behavior-preserving refactors of untested code.
- Do not require a unit test for trivial pass-through code when higher-level coverage is clearer.

Expand Down
Loading
Loading