npx skills add ...
npx skills add mblode/agent-skills --skill codebase-architecture
Designs module interfaces, deepens shallow modules, and installs enforceable repository guardrails and agent wayfinding. Use when asked to "design the architecture", "simplify our modules", "find shallow modules", "harden the repo", "gate an unattended agent fix job", or "triage alerts with an agent".
npx skills add mblode/agent-skills --skill codebase-architecture
Decide a TypeScript codebase's structure, improve it where change has become expensive, and make it hold. The target is a codebase a reader can hold in their head: few surfaces, one canonical way to do each job, and behaviour where you would first look for it.
scaffold-nextjs for a Next.js turborepo, scaffold-cli for a TypeScript CLI), multi-tenant domain/isolation/routing (multi-tenant-architecture), the content of AGENTS.md itself (agents-md), a plan for one feature (planning), a diff-scoped cleanup pass (tidy), structural review of a local diff (tidy), or a product's own verify CLI, doctor command, and feature map (app-verification, call it by name).Pick by the problem, not by the artifact, and say which you picked.
| Mode | You are here when | Output |
|---|---|---|
| Design | Starting a new app, service, or surface, and the structure is not decided yet | An architecture brief |
| Deepen | The code works, but change is expensive: concepts scattered, seams leaking, one idea under three names | Ranked opportunities, then one migrated slice |
| Harden | The structure is decided and keeps decaying, or agents keep doing the wrong thing in this repo | Wired checks, markers, and recipes |
Modes compose, and running more than one is normal. Design ends in Harden, because a contract with no check is a suggestion. Deepen ends in Harden, so the new seam cannot decay back. Harden runs alone when the structure is already right and only the enforcement is missing, which is the common case in a repo that agents work in.
When two look equally right, prefer Deepen. "Agents keep using the old pattern" sounds like Harden, but if the cause is one concept living in two places, quarantine only freezes the duplicate: Deepen deletes it and Harden holds the line until that lands. Harden alone is right when the old thing genuinely has to stay.
When you cannot write to the repo (no checkout, read-only request, or a question rather than a change), each mode's output degrades to its plan: the brief, the ranked opportunities, or the named checks with their rungs. Say which checks remain unproven, since none of them are wired.
As simple as possible, no simpler. Every mode cuts: surfaces in Design, concepts in Deepen, dual paths and dormant config in Harden. The floor does not get cut: validation at trust boundaries, error handling that prevents data loss, security, accessibility, observability on anything deployed, and whatever was explicitly asked for. A simplification that reaches one of those is a bug. Where a corner is cut on purpose, mark it with its ceiling and upgrade path rather than leaving the next reader to guess whether it is finished.
Copy this to track progress, and delete the lines for modes you are not running:
Load only when the condition applies.
| Reference | Mode | Read when |
|---|---|---|
| references/vocabulary.md | All | Before naming a module, interface, seam, or adapter in any output; it defines the deletion test |
| references/stack-defaults.md | Design | Choosing libraries, tooling, or deploy targets |
| references/api-design.md | Design, Deepen | Designing endpoints, module interfaces, request context, error shapes, or forwarded credentials |
| references/distributed-correctness.md | Design, Deepen | The work provably touches an external system, webhook, retry, audit trail, or money. In Deepen you can grep for it; in Design it is a question about requirements, so confirm before loading rather than inferring it from the product's domain |
| references/brief-conventions.md | Design | Writing the conventions, testing, quality-bar, or rollout and rollback sections of the brief |
| references/deepening-existing.md | Deepen | Running Deepen: opportunity patterns, design it twice, ranking, measuring an agent-facing change, output template |
| references/domain-language.md | Deepen | Writing or fixing a glossary, resolving naming divergence, recording a decision |
| references/enforcement-ladder.md | Harden | Adding any check to a repo that already violates it |
| references/guardrail-tooling.md | Harden | Choosing and wiring the actual checks: dead code, duplication, cycles, module and package boundaries, file size, staleness gates |
| references/wayfinding.md | Harden | Agents cannot find things, or keep re-deriving the same path |
| references/contagion-markers.md | Harden | The repo has legacy, generated, dual-path, or deliberately simplified code |
| references/verification-tiers.md | Harden | Defining which commands an agent should run, and when |
| references/agent-runtime.md | Harden | Configuring the post-edit hook, the permission allowlist, or a job where an agent drafts fixes or triages alerts unattended |
Before any of this, ask whether each surface needs to exist. A module, service, app, or entrypoint that could be a folder in something that already ships is the cheapest architecture decision available, and the only one that stays cheap. Every surface you do accept pays the relationship cost in the surface-area budget (brief-conventions.md): name its owner, tests, observability, and deletion path before it goes in the brief.
apps/ for deployable surfaces (api, web, admin).packages/ for shared libraries (shared, ui, icons, auth, proto).handler: transport only.service: business orchestration.dao: database access only.mapper: DB/proto/domain transformations.constants and types: module-local contracts.tenantId, userId, and traceId in an AsyncLocalStorage-backed RequestContext, initialized in every entrypoint (RPC, HTTP, jobs, CLI) and read via getContext(). A threaded ctx parameter grows every signature, and adding one field later touches every call site. Implementation in references/api-design.md.app/ holds routing files only (page, layout, loading, error, route). Domain code lives in src/modules/<name>/ behind its root files; UI private to one route goes in a _components/ folder beside its page. A page that grows logic moves it to a module, not to a sibling file in app/."use client" at the interactive leaves. Where a client wrapper needs server-rendered content, pass it in as children.useState, or two stores synced with useEffect, is the sign that ownership is unclear.proxy.ts (Next 16's name for middleware.ts) handles redirects, rewrites, and headers. Authorization is decided inside each route handler and Server Function, because a matcher-excluded path skips the proxy and Server Functions post to their page's route.Goal: domain-informed deepening, not a rewrite. Load references/deepening-existing.md for the analysis method, opportunity patterns, and output template.
CONTEXT.md, docs/adr/, or local equivalents if present, then read the code for entities, actions, and contexts as the team names them. Note divergence (one concept, three names; or one name, three concepts). Format and ADR rules in references/domain-language.md.git log --oneline over a good stretch of history first and weight the files that keep coming up. An unscoped scan drifts into speculative cleanup.Two halves: guardrails stop the wrong thing landing, wayfinding makes the right thing cheap to find. Both exist because agents arrive by grep, not by reading docs, so the warning has to live where they land and the rule has to be an exit code rather than a sentence someone might recall.
Reach for the strongest mechanism first: structure, then lint and CI, then prose, then human review; every review comment, incident, or repeated mistake is a missing check (references/enforcement-ladder.md).
Steps 1 to 3 always run. Steps 4 to 6 run only when their condition holds, and a request to add one check stops at step 3. Running all six for every request loads most of the bundle and is the failure this mode is most prone to.
verification-tiers.md, "Commands that lie"), and dormant config nobody invokes. Wire the first, fix the second, delete the third (references/contagion-markers.md).Run the items matching the modes you ran, and record results in the output. Each needs evidence; "looks consistent" is not a pass. An item that cannot execute yet, because nothing is installed or the repo is not writable, is recorded N/A with that reason. Silently passing it is how an unenforced contract ships looking verified.
npm run lint, npm run check-types, npm run test --workspace=<pkg> or equivalents). Evidence: passing output, quoted.On failure: fix the brief, the conventions, or the wiring, then re-run the loop.
Design mode produces this brief. Deepen mode's ranked-opportunity template is in references/deepening-existing.md. Harden mode's output is the wiring itself plus the loop's evidence, not a document.
Size the brief to the decisions, not to the template. Drop any heading the project does not face rather than filling it: a single-tenant internal service with no frontend does not owe you a Frontend boundaries section. Each section carries the decision and the constraint that forced it, not a restatement of the conventions in the references. A brief that pads to nine sections costs the review attention that the two contested decisions needed.
Harden-mode gotchas live in the reference each step loads (guardrail-tooling.md, enforcement-ladder.md, contagion-markers.md, verification-tiers.md, wayfinding.md).
package.json hoist silently, so an app builds locally and breaks when deployed alone. Each app owns its deps.handler/service/dao contract with no import-boundary rule decays at the first deadline. Add the rule (dao may not import handler) the day you write the contract."use client" at page or layout level converts the whole subtree to client rendering and forfeits streaming and direct server data access. Push it to leaves.packages/ before 3+ apps need the code couples release cycles for nothing. The exception is the contract two surfaces already share (generated types, the RPC schema, branded IDs): that is the interface between them, and it belongs in a package at two apps.references/distributed-correctness.md.proxy.ts as the only authorization layer: a matcher-excluded path skips it, and Server Functions post to their page's route, so a matcher change silently removes coverage. Check authorization in the handler or Server Function itself.git log hot-spot scoping fills the list with modules nobody touches, and every entry on it is speculative by definition.agents-md: the AGENTS.md / CLAUDE.md file itself. This skill owns the checks and docs tree that file points at; a rule a linter can enforce goes here as an exit code, not there as prose.tidy: review and diff-scoped cleanup, which Harden's guardrails keep small.planning: a plan for one feature; architecture briefs from Design mode feed into it.scaffold-nextjs, scaffold-cli: creating the repo this skill then structures.multi-tenant-architecture: tenant identification, isolation, and routing; this skill supplies the module layout underneath.dx-audit: the developer-facing surface a package ships outward; api-design.md here covers only the contract shape.app-verification: builds and maintains the verify CLI, doctor command, and feature map a repo runs itself with; this skill's Harden mode wires the CI checks that harness's own scripts and fixtures should pass. Call it by name.Maintenance only: evals/evals.json and evals/evaluation-scenarios.md hold regression scenarios for changes to this skill; neither loads during a user task.