Loading...
Loading...
Apply vertical (domain-first) codebase architecture to any project. Use this skill whenever a user asks where to put a file, how to structure a codebase, how to organize code by feature or domain, how to refactor a "horizontal" structure (components/, hooks/, utils/, types/), or asks about code colocation, monorepo boundaries, shared code, or module ownership. Also trigger when the user creates a new module and needs to decide where it belongs, or when reviewing a PR that touches file organization. Works for any language or framework (Python, TypeScript, Go, Rust, etc.) — not just React or frontend.
npx skill4agent add kirdesmf/agent-skills vertical-codebase"What does this code DO, not what TYPE of thing is it?"
src/
components/ ← all UI components mixed together
hooks/ ← all hooks mixed together
utils/ ← everything else
types/ ← all types
services/ ← all API callssrc/
dashboard/ ← everything related to the dashboard
billing/ ← everything billing-related
auth/ ← everything auth-related
design-system/ ← truly generic, reusable across projects
shared/ ← shared business logic (not generic enough for design-system)1. Is it tied to a specific feature or domain?
YES → put it in that vertical (e.g. src/billing/)
│
└── Is it used by multiple features?
YES → does it contain business logic specific to this app?
YES → make it its own vertical or put in /shared
NO → put it in /design-system (or /lib)
NO → keep it private inside the feature vertical
2. Is it purely generic with zero business logic?
(could live in any project, any company)
YES → /design-system or /lib
3. Is it infrastructure / cross-cutting concern?
(logging, config, error handling, i18n, routing)
YES → /infrastructure or /coresrc/billing/
billing-service.ts
billing-types.ts
billing-utils.ts
invoice-list.tsx (if frontend)
use-invoice.ts (if frontend)
invoice.test.tsA feature vertical can only import from,shared, andinfrastructure. Never from another feature vertical.design-system
feature vertical → shared ✅
feature vertical → infrastructure ✅
feature vertical → design-system ✅
feature vertical → feature vertical ❌ lint error
shared → feature vertical ❌ lint error
design-system → anything ❌ lint error/sharedeslint-plugin-boundaries// eslint.config.js
import boundaries from "eslint-plugin-boundaries";
export default [
{
plugins: { boundaries },
settings: {
"boundaries/elements": [
{
type: "feature",
pattern: "src/!(shared|infrastructure|design-system)/*",
},
{ type: "shared", pattern: "src/shared/*" },
{ type: "infrastructure", pattern: "src/infrastructure/*" },
{ type: "design-system", pattern: "src/design-system/*" },
],
},
rules: {
"boundaries/element-types": [
"error",
{
default: "disallow",
rules: [
{
from: "feature",
allow: ["shared", "infrastructure", "design-system"],
},
{ from: "shared", allow: ["infrastructure", "design-system"] },
{ from: "infrastructure", allow: ["design-system"] },
{ from: "design-system", allow: [] },
],
},
],
},
},
];| Language | Tool |
|---|---|
| Python | |
| Go | |
| Rust | Cargo workspaces + |
| Java/Kotlin | Package-private + ArchUnit |
| Monorepo (any) | |
| Code | Where it goes | Why |
|---|---|---|
| Generic button, input, modal | | No business logic, reusable anywhere |
| | Pure utility, zero business logic |
| | Business logic, even if used everywhere |
| | Shared but product-specific |
| | Depends: generic math → shared, billing-specific → billing |
| Error boundary wrapper | | Cross-cutting concern |
src/
auth/
auth-service.ts
auth-middleware.ts
auth-types.ts
auth.test.ts
users/
user-repository.ts
user-service.ts
user-types.ts
billing/
stripe-client.ts
billing-service.ts
billing-types.ts
shared/
pagination.ts
date-utils.ts
infrastructure/
logger.ts
config.ts
database.tssrc/
auth/
__init__.py
service.py
middleware.py
models.py
test_auth.py
billing/
__init__.py
stripe.py
service.py
models.py
shared/
__init__.py
pagination.py
date_utils.py
infrastructure/
logger.py
config.py
database.pyinternal/
auth/
handler.go
service.go
repository.go
types.go
billing/
handler.go
service.go
stripe.go
shared/
pagination.go
timeutil.go
pkg/ ← truly public/reusable packages (like design-system)
middleware/
validator/src/
dashboard/
DashboardPage.tsx
dashboard-store.ts
use-dashboard-data.ts
dashboard-types.ts
widgets/
WidgetCard.tsx
use-widget.ts
widget-types.ts
widget-api.ts
design-system/
Button.tsx
Modal.tsx
useMediaQuery.ts
tokens.css
shared/
use-current-user.ts
format-currency.ts
infrastructure/
router.ts
i18n.ts
error-boundary.tsx"It's a hook/service/util, so it goes in /hooks /services /utils"
"I might need this elsewhere, so I'll put it in /shared"
"It's used in billing AND dashboard, so it goes in /shared"
/invoices/reports"is used in 10 places, so it's design-system material"useCurrentUser
src/features/billing/components/invoice/list/items/InvoiceItem.tsx
💡 Readfor a step-by-step migration plan.references/refactoring-guide.md
| Question | Answer |
|---|---|
| Where does X go? | In the vertical that OWNS the functionality |
| What's a vertical? | A folder grouping code by what it does, not what it is |
| What goes in design-system? | Zero business logic, could exist in any project |
| What goes in shared? | Business logic used by multiple verticals |
| What goes in infrastructure? | Cross-cutting concerns (logging, config, DB) |
| How do verticals talk to each other? | Direct imports, but direction enforced by linter |
| Two verticals need to share code? | Extract to /shared — never create a linter exception |
| When to create a new vertical? | When a concept is big enough to own, or when shared code warrants it |