About architecture
An architecture skill for developers maintaining codebases as they grow. It emphasizes domain-oriented organization, clear module boundaries, acyclic dependencies, thin transport layers, and authorization on protected request paths.
Key features
- 01Organize code by domain
- 02Communicate through public APIs
- 03Keep dependency graphs acyclic
- 04Keep transport logic thin
- 05Authorize on the request path
Use cases
- 01Plan directories for new features
- 02Reduce cross-module internal imports
- 03Identify and break dependency cycles
- 04Review handler logic and authorization placement
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ liaoann/ skills --skill architectureAfter installing, type/architecturein Claude Code to confirm it loaded.
Details
From the project READMEArchitecture
Principles for keeping a codebase navigable as it grows. Apply against the project's own conventions — these are defaults, not overrides for a repo that already has a documented structure.
Organize by Domain, Not by Layer
Group code by the capability it serves, so one feature can be understood by exploring one area:
features/
bookings/ ← services, data access, UI, tests for bookings
availability/ ← services, data access, UI, tests for availability
Avoid top-level technical layers (controllers/, services/, repositories/) when they scatter one domain change across many directories. Local technical subfolders inside a feature are fine when they make that feature easier to navigate.
Communicate Through Public APIs
A feature imports another feature only through its public entry point, never by reaching into internal files:
// ❌ reaching into internals
import { calculateSlots } from "features/availability/services/internal/slotCalculator";
// ✅ through the public API
import { getAvailability } from "features/availability";
Put domain-agnostic utilities (logging, auth, generic helpers) in a shared low-level module; put shared UI primitives in a shared UI module. Enforce import boundaries with lint rules where the toolchain allows.
Keep the Dependency Graph Acyclic
Dependencies should flow one direction, from lower-level shared code toward higher-level application entry points:
shared utils → shared domain modules → features → transport/API → app entry
Lower layers must not import higher ones. A utility that imports a feature, or two features that import each other, is a cycle — it causes build failures, type errors, and a structure that no longer reflects what depends on what. Break cycles by extracting the shared piece downward.
Keep Transport Thin
HTTP handlers, RPC routers, CLI commands, queue consumers, and UI event handlers are delivery mechanisms. They should validate input, adapt it into application data, call the domain/application code, and adapt the result back out.
Do not let a transport boundary become the place where business decisions, persistence details, or complex orchestration accumulate. If the same behavior would be needed from another transport, move it behind a domain-facing interface.
Place Authorization on the Request Path
This is a placement decision like the rest of this skill: a guard belongs at the boundary it actually protects, not one level out where coverage is assumed but not guaranteed.
Put the authorization check on the path every request provably passes — the handler that guards the resource itself. A shared outer shell (an inherited layout, a wrapping decorator, a middleware some entry points skip) is bypassable whenever a request can reach the protected resource without traversing it. Validate identity and role before any restricted data is read, and fail closed: deny by default, redirect or return early for the unauthorized.
Completion Criterion
The change respects existing boundaries: new files sit with the capability they serve, cross-module imports go through public entry points, no import introduces a cycle or points from a lower layer to a higher one, transport code stays thin, and any authorization check sits on the protected request path rather than in a bypassable wrapper. A single violation means it is not met.