Keep a Codebase Maintainable
A maintainability job is not a feature with extra polish. The deliverable is a smaller, truer tree: unused gone, twins collapsed, names honest, docs matching code, diff containing only the ask.
Mined from Cooper's OMP Hindsight bank (how he actually prompts coding agents). Source instances: references/instances.md (copy also at /var/lib/hermes/workspace/omp-maintainability-asks.md).
Core principle: If it isn't the ask, it doesn't ship. Prefer delete over abstract. Prefer the library over a wrapper. Prefer one owner over two that will drift.
When to Use
Load this when the user (or the task) sounds like any of:
- clean up / tidy / prune / hygiene / leftover / dead / unused
- simplify / trim the diff / surgical / no tangents
- audit, repair, and reorganize
- rename / consolidate / disentangle / one package / short names
- "don't add", "no new services", "stop coding", "out of scope"
- comment the why / docs are stale / fix AGENTS.md
- keep it maintainable / reduce maintenance / cohesion
Don't use for: implementing a requested feature, fixing a failing behavior, or a post-feature pass over your own just-written diff — that last one is simplify-code.
If the user mixes "add X and also clean Y", split the commits. This skill owns Y.
Standing Rules
These override default "helpful agent" instincts.
- Deletion test. A symbol/file/package/dep/flag/scope dies if it has zero real importers and is not a public contract (exported API, framework peer, Helm value a live app still declares). Grep the name. Then grep the old name.
knip/ts-prune/depcheckare hints, not proof — they flag framework peers and dynamic imports. - Don't recreate the dead. Removing a stale git declaration is the fix. Syncing / applying / resurrecting the resource to "clear Missing" is the bug. Same for reserved-for-later knobs: clean cutover, not a tombstone comment.
- One owner, one name. Twins drift (two schedulers,
menuvsx,ManualCommitStepleftover after a unify). After a collapse, grep the retired name and delete the twin. - Native over custom. If the library already has the hook / client / convention, use it and delete the wrapper. Keep customizations thin. Heuristic > extra flag.
- Short honest names.
@czxtm/utilsnotworkflow-contracts. Public docs use the canonical surface (x), never the legacy alias. - Package = unit of cohesion. Prefer self-contained packages over a root split of docs/tests/src that "feels fragmented." Unit tests sit beside their source as
*.test.ts; only end-to-end tests get atests/directory. - Surgical diff. Stage specific paths. Never
git add -A. One concern per commit. Revert unauthorized extras without arguing. "Cleanup approved" is not "land on main." - Live user instruction beats advisory AGENTS.md. Binders about commits/pushes still apply to remote mutations. They do not authorize you to spawn extra agents or expand scope.
- Comment the why. Design intent, invariants, edge-case rationale. No
// increment counter. Stale docs are a contract bug — update or delete. - Stop means stop. "Stop all coding." "Don't modify production auto/flash." Honor scope locks immediately.
Process
1. Name the job
Write one sentence: what gets smaller or truer, and what is out of scope.
Done when: the sentence has no feature in it. If it does, this is the wrong skill.
2. Inventory before you touch
Build a list of candidates. Do not delete yet.
path:symbol → why it looks dead → consumers found (grep) → contract? → action
Search, in this order:
- unused files / exports / deps / flags / Slack scopes / Helm leftovers
- leftover twins from an incomplete unify (old name still present)
- stale comments, READMEs, AGENTS.md pins that contradict lockfiles
- commands / aliases still advertising a retired surface
- "reserved for later" knobs and unused error variants
- temp artifacts (
/tmp/*, worktrees, stale tags, merged branches)
Done when: every candidate has a grep result (including "zero hits") and a contract verdict. Live-consumer check is mandatory for anything that can take production down (bindings, PVCs, Hyperdrive, DNS, secrets).
3. Apply in risk order
| Tier | Examples | Action |
|---|---|---|
| SAFE | unused import, leftover /tmp, commented-out block, duplicate config section from a failed edit |
Delete now. |
| CAREFUL | unused file with no importers, dep with no app import, rename to the short name, collapse a twin helper | Delete/rename, then run the targeted test/lint for that package. |
| RISKY | anything with a live binding, public export, Helm/Argo resource, secret, peer dependency, "zero knip hits" | Verify live consumers. If any exist, stop and say so. Never delete by name-group. |
Do not add a helper, flag, service, or abstraction as part of this job unless the user asked for that specific thing. The cleanup is the absence.
Done when: every SAFE/CAREFUL item is applied or explicitly skipped with a reason, and no RISKY item was applied without a live-consumer check.
4. Keep the contract true
In the same change-set, only if they are now false:
- AGENTS.md / README claims (versions, who posts reviews, where creds live)
- comments that describe a path you just deleted
- public command catalogue /
xmenu entries that point at removed scripts - snapshot / fixture leftovers that still use the old marker
Do not write new design docs unless the user asked. Do not start a planning loop — mechanical refactors skip brainstorming.
Done when: a stranger grepping the old name finds either nothing, or a one-line pointer to the new name.
5. Land narrowly
- Diff contains only the inventory items you accepted.
- Separate commit from any unrelated WIP. Use the dirty-worktree recipe if needed: backup diff → revert unrelated hunks → verify
git diff→ commit → re-apply WIP. - Do not push / Sync / deploy unless the user asked for that land path.
- If you drifted (extra files, extra agents, extra scope): revert first, then report.
Done when: git diff against the starting point is explainable line-by-line from the inventory, and the project's targeted check for touched packages is green (or the baseline already failed the same way).
What "clean" looks like here
Recurring shapes from real asks — match these, don't invent new ones:
- Catalogue audit — remove broken commands, prefix the rest, one grouping scheme.
- Diff diet — net-negative lines; misplaced tests pulled out of the commit.
- Replace a custom stack with the library hook (bash-preexec, Polar SDK, vendor client).
- Collapse to one owner (one SessionHost, one scheduler, one SDK repo, two-repo end state).
- Delete the reserved knob rather than keep it "for the bounded API later."
- Uniform over decorative when the extra style costs code or bugs.
- Heuristic over flag when the flag would become a recovery bug.
- Vendor references as plain files so the next agent can follow AGENTS.md without extra setup.
Common Pitfalls
- Deleting by name group. Hyperdrive configs deleted by production name took down live Workers. Always resolve the live ID / binding first.
- Syncing to clear Missing. Recreates the unused claim. Edit git; hard-refresh if you only need status.
- Trusting unused-export tools. Grep. Check framework peers. Check string-dynamic imports.
- Hearing "cleanup OK" as "push to main." Land path is a separate ask.
- Leaving the twin. Incremental unifies leave
ManualCommitStep. Grep the old name after. - Keeping reserved dead API. It becomes a lying classifier. Cut over.
- AGENTS.md theater. Don't spawn work the user didn't ask for because a blocker advisory exists. Do still refuse remote mutations without authority.
- Planning the cleanup. Discovery → do the inventory → apply. No redesign of an approved shape.
- Commenting the deletion. If the code is gone, the comment goes too — unless it records a load-bearing why we don't do X.
- Mixing feature and cleanup in one commit. Split.
Verification Checklist
- One-sentence job has no feature in it
- Inventory table exists; every delete has a grep + contract verdict
- Live bindings checked for RISKY items
- Old name greps clean (or points at the new name)
- No new abstraction / flag / service was introduced
- Diff is explainable from the inventory; no unauthorized files
- Targeted tests/lint for touched packages ran; only pre-existing failures remain
- Stale docs / AGENTS.md / menu entries that the change falsified were updated or deleted
- Did not push / Sync / deploy unless asked