From shipshitdev-library
Reviews PR diffs for structural health: file size, abstraction quality, layer violations, type discipline, and stack-specific hygiene (Bun, Tailwind v4, Next.js 16, shadcn/ui). Use alongside /code-review for thorough code quality and architecture reviews.
How this skill is triggered — by the user, by Claude, or both
Slash command
/shipshitdev-library:structural-reviewWhen to use
structural review, maintainability review, code quality review, architecture review, thermo-nuclear review, code judo, simplify this PR, is this code clean, before merge review
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Opinionated structural and maintainability review rubric. Report-only — this skill produces findings; it does not mutate files or open PRs.
Opinionated structural and maintainability review rubric. Report-only — this skill produces findings; it does not mutate files or open PRs.
Every structural finding must answer: "What exactly should the author delete, collapse, or rename — and which specific file/line is the canonical landing zone?" Vague nits ("this could be cleaner") are noise. High-conviction, actionable findings only.
This rubric is explicitly complementary to /code-review. Do not re-flag correctness bugs or CLAUDE.md rule violations already covered there. Own the orthogonal structural/maintainability/devex dimensions.
Ask these first, before scanning for individual issues:
unknown, and as X casts hiding future breakage, and are interfaces inlined where they should be in *.types.ts?npm invocations, raw HTML in a shadcn project, middleware.ts in a Next.js 16 app — these are regressions, not style notes.A file crossing ~1000 lines is a presumptive blocker. It is not a hard numeric law but a strong prior that the module has taken on too many responsibilities.
Flag when:
Preferred remedy: Split into colocated slices — *.service.ts, *.queries.ts, *.types.ts, *.hooks.ts — before the PR lands. Not after.
Phrase: "File is now 1 180 lines. Split the query layer into *.queries.ts before this ships — the 1 000-line rule exists exactly for PRs like this one."
Severity: Blocker.
Every new function, hook, class, or file must justify its existence. Thin wrappers, identity helpers, and passthrough re-exports fail this test unconditionally.
Flag when:
useState with no co-located logic.Preferred remedy: Delete the abstraction; inline the real symbol at the call site. Bun + TS path aliases make the original easy to reach.
Phrase: "This helper is an identity function over formatDate — inline it and delete the file. Code-judo."
Severity: Request Changes.
Ad-hoc forks bolted onto existing flows are the primary mechanism by which a clean codebase becomes unmaintainable.
Flag when:
if (isAdmin) / if (featureFlag) / if (isPremium) fork appears in 2+ files changed by this PR.Preferred remedy: Collapse all branches into one canonical decision point — a hook for client state, a server action or domain service for mutations. Branches then disappear from the components.
Phrase: "Three if (isAdmin) forks scattered across the render tree. Collapse the decision into one hook or server action; the branches can then disappear from the component."
Severity: Request Changes.
In this stack, logic belongs in a specific layer. Violating the layer model is a structural defect, not a preference.
Layer map:
<form onSubmit>, not in useEffect.packages/ui components. Not raw <button>, <input>, <dialog>.proxy.ts. Not middleware.ts (Next.js 16).Flag when:
packages/ui or shadcn.Phrase: "<button onClick={...}> in a component that already imports Button from packages/ui — swap it; raw HTML is a regression in this codebase."
Severity: Request Changes; Blocker when the element is a raw interactive element in a shadcn/packages/ui project.
This axis covers structural placement and shape issues — not any existence, which is owned by the /code-review harness.
Violations (flag all):
unknown without an adjacent type guard — this is deferred any, structurally equivalent to leaving the shape unresolved.as X casts without a comment explaining why the type system cannot infer the narrowing.*.types.ts or packages/types.Preferred remedy: Define the shape in *.types.ts. Add the type guard at the boundary where the unknown enters.
Phrase: "Bare unknown without a type guard is deferred any. Define the shape in *.types.ts or add the guard here."
Severity: Bare unknown without guard → Blocker. Inline interface → Request Changes. as X without comment → Minor.
Sequential await calls that each write to the database are a correctness-adjacent structural defect. A crash between writes leaves the system in a half-written state.
Flag when:
await db.update() / await db.insert() calls appear in the same function without a wrapping transaction.Preferred remedy: Wrap in a DB transaction or model as a single atomic write. If the external call cannot be inside a transaction, add explicit compensation logic.
Phrase: "These two await db.update() calls are non-atomic. A failure between them leaves the row in an invalid state — wrap in a transaction or model as a single atomic write."
Severity: Blocker.
Functions that orchestrate 5+ sequential steps with no intermediate abstraction are a future maintenance hazard. They are hard to test, hard to reuse, and hard to understand in isolation.
Flag when:
await calls with no intermediate named steps or helper functions.Preferred remedy: Extract named phases. Each phase is testable in isolation. The orchestrator becomes a readable list of intents.
Severity: Request Changes.
These are not style notes — they are regressions introduced by the PR that must be fixed before merge.
| Issue | Rule | Phrase |
|---|---|---|
middleware.ts created or left in place | Next.js 16 renamed the entry point to proxy.ts; the old name is silently ignored | "This is middleware.ts. Rename to proxy.ts — Next.js 16 renamed the entry point." |
tailwind.config.ts or tailwind.config.js added | v4 uses CSS-based config (@theme in CSS); JS config is v3 | "tailwind.config.ts created by this PR — that's v3. Delete it and move the theme tokens into the CSS @theme block per v4." |
@apply directive or bg-opacity-* class added | v3 patterns; must migrate to v4 slash syntax | Cite the exact line and the v4 equivalent. |
npm run, npx, yarn add, pnpm exec in scripts, CI YAML, or docs | Bun is the only package manager; replace with bun run / bunx / bun add | "npx prisma migrate two lines below must be bunx prisma migrate." |
Severity: All Blocker.
The sharpest structural question is not "is this correct?" but "could this same behavior be expressed with materially less structure?" A change that ships the right behavior on top of avoidable complexity is a missed simplification, and missed simplifications compound.
Flag when:
Preferred remedy: Reframe the state model. Collapse the special case into a default. Deletion and collapse beat polishing — "code-judo" the complexity category out of existence rather than tidying it.
Phrase: "This three-state flag collapses to one derived boolean — the same behavior with a whole branch deleted. Reframe rather than polish."
Severity: Request Changes (Blocker when the simpler form also removes a correctness footgun).
Prefer the obvious mechanism over the clever one. Over-generic abstractions, hidden assumptions, and indirection that hides control flow cost more to read than they save to write.
Flag when:
Preferred remedy: Inline to the direct form for the one real caller. Make the assumption explicit at the boundary, or remove the magic.
Phrase: "Generic registry for a single handler — delete it, call the handler directly. Add the abstraction back when the second caller actually arrives."
Severity: Request Changes.
/code-review./security-audit.Order findings by severity:
## Structural Review
### Blockers (must fix before merge)
[File-size violations, non-atomic mutations, stack regressions (middleware.ts, tailwind config, npm/yarn usage), bare unknown without guard, design-purity simplifications that also remove a correctness footgun]
### Request Changes (significant structural debt)
[Abstraction-earns-keep failures, canonical-layer violations, spaghetti branching, sequential orchestration smells, inline interfaces, missed design-purity simplifications, speculative generality / magic indirection]
### Minor (low-debt, flag for awareness)
[as X casts without comments, small layer suggestions with obvious inlines]
### Approved Axes
[Axes with no findings — confirm clean]
Include for each finding:
Blocker and request-changes criteria are embedded in each axis above. When ambiguous, default to Request Changes — the ambiguity tax is paid by the author, not the codebase.
npx claudepluginhub shipshitdev/skills --plugin worktreeRuns an unusually strict maintainability review focused on abstraction quality, file size limits, and spaghetti-condition growth. Use for deep code quality audits or harsh structural reviews.
Performs an unusually strict maintainability review focused on abstraction quality, modularity, and spaghetti code reduction. Useful for deep code audits or harsh maintainability reviews.
Reviews code across five axes: correctness, readability, architecture, security, and performance. Use before merging any change.