humanize-library · git:20260914.5e8ef0f · 2026-09-14 · sha256 67622321d1a1bb63
humanize-library git:20260914.5e8ef0fA
Immutable. This exact content never changes and is served at /api/v1/blob/67622321d1a1bb63.
--- name: humanize-library description: 'Behavior-preserving refactor that makes an existing library, module or folder readable — small focused files, no duplication, clear names, SOLID. Use when asked to humanize, clean up, split large files or remove duplication at a path. Not for new features or bug fixes.' --- # Humanize Library Transform a target folder so a new developer can read it top-to-bottom and understand it: single-responsibility files, clear names, no copy-paste — **without changing observable behavior**. This skill is repo-agnostic. It carries no assumptions about your framework, folder layout, DI style, test runner or naming convention. Steps 1 and 2 exist to *learn* those from the repo in front of you. Never substitute conventions from another codebase you have seen. ## Operating principles (read first) 1. **Behavior-preserving only.** No new features, no bug "fixes", no API shape changes unless the user explicitly asks. Found a real bug? Write it down for the user. Do not silently fix it. 2. **Learn the repo before you cut.** Steps 1–2 are not ceremony. A refactor that violates a rule you never discovered is worse than no refactor. 3. **Never refactor without a working gate.** If typecheck/lint/test do not actually run over the target, repairing that is batch 0 — before a single line of source moves. See [references/discover-the-repo.md](references/discover-the-repo.md) §Verification gate. 4. **Plan before you cut.** Produce the audit + plan and get user sign-off before editing. Large refactors have large blast radius. 5. **Small reversible batches.** One concern per batch. Verify after each. Never one giant rewrite. 6. **Commit each green batch.** Stage explicit paths only — never `git add -A`, never touch uncommitted work you did not create. Assume other sessions share this working tree. --- ## Step 1 — Scope the target Confirm the exact path with the user. Then establish what kind of unit it is: - Is there a manifest? (`package.json`, `project.json`, `pyproject.toml`, `Cargo.toml`, `go.mod`, `build.gradle`, `*.csproj`). Read it — it names the unit, its scripts/targets, and its deps. - Is there a public entry point? (`index.ts`, `__init__.py`, `lib.rs`, `mod.rs`, a barrel export). **The entry point is the refactor's contract.** Everything behind it is yours to move; everything it exports must keep its name and shape unless dependents are updated in the same batch. - Are there local instruction files? (`CLAUDE.md`, `AGENTS.md`, `README.md`, `CONTRIBUTING.md`, `.cursorrules`) — in the folder *and* in every parent directory up to the repo root. ## Step 2 — Discover the repo's contract and gate Read [references/discover-the-repo.md](references/discover-the-repo.md) and follow it. It produces two artifacts you will use in every later step: - **A contract card** — the rules this repo actually enforces, each with the evidence that proves it is real (a lint rule, a CI step, a test, a written doc). Rules with no enforcement are preferences; label them as such. - **A verified gate** — the exact commands that typecheck, lint and test *this specific target*, each one run once and observed to pass or fail. A command that silently skips the target is not a gate. > Do not skip this because the repo "looks like" one you know. The most common failure mode of > this skill is importing another project's conventions. The second most common is trusting a gate > command that never touched the code. ## Step 3 — Audit Run the analyzer for an objective inventory: ```bash node <skill-dir>/scripts/analyze_library.mjs <path> --json ``` It reports per file: code lines, export count, max nesting depth, longest function, whether an adjacent test file exists, and a **shape** classification (`logic` / `registry` / `types` / `generated`). Then read the flagged files and score them against [references/quality-rubric.md](references/quality-rubric.md). **Calibrate before you score.** Line count alone is a bad signal and will mislead you: | Shape | What it looks like | How to weight it | | --- | --- | --- | | `logic` | branching, state, nesting depth ≥ 4, methods calling each other | Full weight. This is what "god file" means. | | `registry` | a flat list — routes, tool schemas, command definitions, a long `switch` where arms don't interact | **Down**-weight. 2000 navigable lines of one-symbol-per-concept is not a defect. | | `types` | interfaces, enums, DTOs, a barrel | **Down**-weight. Split only if the entry point forces consumers to import implementation to get a type. | | `generated` | codegen output, lockfile-adjacent, `@generated` header | **Exclude entirely.** Never refactor generated code — fix the generator. | The axes that actually separate a broken unit from a big one, in order: 1. **Concern count** — how many unrelated reasons to change live in one file. 2. **Test safety net** — is the code you want to move pinned by a test? Beware aggregate coverage ratios: in most repos the largest file is the *least* tested one. Check per-file, not per-project. 3. **Duplication that has already diverged** — two copies that now behave differently is a shipped defect. Two identical copies is only debt. 4. **Contract violations** — measured against the card from step 2, not your taste. ## Step 4 — Produce the plan Write ordered batches. For each: the smell, the target shape, the files touched, the risk, and the exact gate command for that batch. Use [references/refactor-recipes.md](references/refactor-recipes.md) to pick the move. Ordering rules: - Gate repair first, if step 2 found a hole. - Then extractions that *shrink the diff* of later batches (lift types out, lift primitives out) before the batch that splits the class. - Batches touching the same file are strictly serial. Say so. - Any step that changes observable behavior gets its **own** batch, sequenced last, gated on explicit user sign-off — not on a green suite. - Untested code gets a characterization test as its own committed batch *before* it is touched. Present the plan and **wait for approval**. ## Step 5 — Execute, batch by batch 1. Make the change. Prefer mechanical, reviewable edits. 2. Keep the public entry point exporting the same symbols — or update every dependent in the same batch. Find dependents before moving an exported symbol (`ptah_get_dependents`, `ptah_lsp_references`, or a plain grep for the symbol across the repo). 3. Run this batch's gate. Green → commit with a clear message. Red → fix or revert the batch. 4. Never declare a batch done on red. Report failures with the actual output. ## Step 6 — Summarize Give the user: what changed, before/after numbers on the worst offenders, duplication removed, bugs spotted-but-not-fixed, behavior changes that needed sign-off, and the final gate status. --- ## What "human-written" means here - A file does one job and is named for that job. Size follows from that — a cohesive 900-line registry is fine; a 400-line class with four reasons to change is not. - One level of abstraction per function. No mixing orchestration with string munging. - Names state intent, not mechanism. No `data2`, `handleStuff`, `tmp`. - Shared behavior lives in one place, in a location the dependency rules actually allow. - Comments explain *why*. Dead code is deleted, not commented out. - Dependency arrows point the way this repo's contract says they should.