From mateonunez-skills
Organizes code by vertical slices in monorepos: features as workspace packages. Guides file placement, new feature addition, package structure proposals, anti-pattern avoidance.
How this skill is triggered — by the user, by Claude, or both
Slash command
/mateonunez-skills:vertical-slicesThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Layered organisation (`controllers/`, `services/`, `repositories/`) makes every change a horizontal cut across the whole codebase. One feature edit touches five folders. Tests in one place, code in another, types in a third. Then six months in, every PR is a tour through the entire repo.
Layered organisation (controllers/, services/, repositories/) makes every change a horizontal cut across the whole codebase. One feature edit touches five folders. Tests in one place, code in another, types in a third. Then six months in, every PR is a tour through the entire repo.
I organise by feature instead. A feature owns its handlers, its services, its types, its tests, its migrations, its fixtures. The seam between features is a package boundary, not a layer convention.
The canonical example is ait — see the package layout in personal/ait/references/core-architecture.md: @ait/core, @ait/connectors, @ait/postgres, @ait/qdrant, @ait/scheduler, @ait/gateway. Each one owns its slice end to end.
You are about to:
utils/ or lib/ pileWhen deciding where a new file lives, ask in order:
@scope/auth, @scope/billing).@scope/shared package, but only if the abstraction is real. Three callers is the bar. Two is duplication; one is premature.In pnpm monorepos, the slice boundary is enforced by package boundaries:
packages/
feature-a/
src/
test/
package.json # name: @scope/feature-a
feature-b/
src/
package.json # depends on "@scope/feature-a": "workspace:*"
apps/
api/
web/
Internal deps use workspace:*. Scoped names (@scope/feature) make the boundary visible at every import site.
utils/ mega-package. Becomes a junk drawer with no cohesion. Every feature ends up depending on it; nothing depends on a clear contract. Split or delete.@scope/auth-controllers, @scope/auth-services, @scope/auth-repositories. Re-creates layered organisation at the package level. Collapse to @scope/auth.@scope/billing imports from @scope/auth/src/internals/, the boundary is fake. Re-export through the package's index.ts or push the shared concept down to a third package.@scope/types package when the types belong to one feature. Types live with their owner.// package.json (root)
{
"scripts": {
"dev": "pnpm run:recursive --parallel dev",
"build": "pnpm run:recursive build",
"test": "pnpm run:recursive test",
"lint": "biome check .",
"run:recursive": "pnpm -r --workspace-concurrency=1 --if-present"
}
}
run:recursive is a reusable base — -r traverses workspaces, --workspace-concurrency=1 respects build order, --if-present skips packages that don't define the script. Override with --parallel for dev servers.
Don't rewrite the world. Pick one feature, slice it vertically into its own package, prove the pattern, then iterate. A half-finished refactor is worse than no refactor.
If the existing codebase is small (<10 files), just leave it. Premature monorepo-isation is a real failure mode.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub mateonunez/skills