Project architecture
The first hour of a project decides whether it scales. Folders are the easy part; the hard part is ownership: who is allowed to know about what. A codebase where the UI can reach Stripe, or where page.tsx calls the ORM directly, does not get better with time. It gets bigger.
This matters more with coding agents than without them. An agent reads the conventions already in the repo and builds on top of them. Bad structure does not stay bad at constant size; it compounds. Set the boundaries first and the agent's shortcuts become impossible rather than merely discouraged.
Which is why this skill has a second job. Conventions decided in week one are forgotten by week six, by the agent whose context has rolled over and by the human who moved on. Bootstrap builds the architecture. Convention keeps it.
Pick the mode
| Situation |
Mode |
| Nothing exists yet, or only bare framework CLI output |
Bootstrap |
| A project already exists and work is happening inside it |
Convention |
Everything version-specific is a moving target
references/ holds distilled architecture knowledge: layering, the dependency rule, DAL/DTO/policy, ERD design and migrations, tenant isolation, API contracts, list views, mutations, accessibility, async work, uploads, security, performance, operations, lint guardrails and design tokens. Those principles hold across versions.
Every concrete API, file name, flag, and command in them is a moving target. The reference files mark those with VERIFY: blocks stating exactly what to look up. Resolve them against the live docs before writing code, in both modes, not just at bootstrap. Context7 goes through Executor; see the mcp-integrations skill for the tool path and the two-step flow. Read the version attached to whatever comes back: it is the difference between "the docs say X" and "the docs for the version installed here say X".
Never write code from what a reference file, or your training data, implies the current API is. Live example: Next.js renamed middleware to proxy, and now ships its own docs inside node_modules/next/docs. Anything that hardcoded those is already wrong.
When the live docs contradict a reference file, the docs win and you say so out loud. If a reference file's principle no longer has a mechanism in the current version, say that too rather than inventing one.
The non-negotiables
The compressed form of the rules, for recall. Each one expands in the reference file named; that file is the authority.
- The dependency rule. UI → Transport → Domain → Capabilities → Vendors, each layer reaching only the one below it. Shared contracts and the database client flow upward to everyone. (
architecture.md)
- The DAL is the only path to the database. No ORM call in a page, a component, a route handler, or an action. (
data-layer.md)
- In a multi-tenant product, the tenant is a required argument. Never optional, never inherited, never taken from a client-controlled value. This covers jobs, caches and storage keys, not just queries. (
multi-tenancy.md)
- Authorization before data, next to the data. Upstream gates are an optimization, not the security model. (
data-layer.md)
- Validate in and out. Inputs because users lie; outputs because the database returns more than the client should see. (
data-layer.md)
- Server-only is a build error, not a convention. Sensitive modules import the server-only marker so a client import fails loudly. (
security.md)
- Every entry point is public. A server action compiles to a POST endpoint; arriving through your form is not a fact you get to assume. (
security.md)
- Server Components by default.
"use client" lives on the leaves, only where there is interactivity. (performance.md)
- One contract, both directions. The schema is the single source of truth for input, output, types and docs. (
api-design.md)
- The state of a view lives in the URL. Filters, sort, search and page are query params, parsed against a schema. State trapped in a component is a view nobody can share, bookmark or restore. (
list-views.md)
- A boundary that is not linted is a preference. The dependency rule is only real once an illegal import fails the build. (
lint-guardrails.md)
- A URL that has been shared is a contract. Do not encode a movable relationship in a path, and never let a rename silently kill existing links. (
url-design.md)
- The right element before any ARIA. Native elements carry role, focus and keyboard behavior; a div reimplementing them is a permanent debt. Focus and announcements are owned, not assumed. (
accessibility.md)
- Semantic tokens, never literal colors.
bg-primary, not bg-blue-500. (design-system.md)
- One naming format. kebab-case for source files, snake_case in the database. (
architecture.md, database.md)
Bootstrap
Create a todo per phase. Do not skip phase 3's checkpoint.
1. Discovery
Understand the product before touching the stack. Ask only what you cannot infer, and ask it through the AskUserQuestion selector per the global CLAUDE.md rules: tenancy, profile and everything already decided are enumerable, so they are tabs. Only the mini-PRD paragraph is genuinely open, so that one goes in prose after the selector.
- What is it? One paragraph. This becomes the mini-PRD.
- Features in scope. A list. Every noun in it is a candidate entity.
- Who are the users, and does it have tenancy? Single-user, multi-user, or multi-tenant (organizations/workspaces). This one decision reshapes the whole schema, and if the answer is multi-tenant,
references/multi-tenancy.md governs the model before anything else does.
- What is already decided? Deployment target, database, auth provider, payments, anything the user already pays for or knows they want.
- Does anything run outside a request? Uploads, scheduled work, emails, exports, anything slow. These need a home in the blueprint rather than an improvised one later. Per
references/async-work.md and references/file-uploads.md.
Then pick the profile, and say which one you picked and why:
| Profile |
When |
Shape |
| Single app (default) |
Most projects. One deployable, one team, one product surface. |
One app, layering enforced by folders and lint rules inside it. |
| Monorepo |
Multiple deployables (web + docs + marketing), or capabilities that genuinely need to be swappable behind stable APIs (payments, storage, email across products). |
Workspaces, one package per layer. |
Do not default to the monorepo. It is the right end state for a product with real scale, and premature weight for anything smaller. The layering principles are identical in both; only the enforcement mechanism differs (folders + lint vs. package boundaries).
2. Version verification
Resolve, at minimum:
- The framework. Current major, what the CLI creates today, which conventions were renamed or removed, which config flags the planned features need.
- The ORM / database client. Current schema syntax, id generation, migration commands.
- The auth provider, if any. Current session API and its server-side entry point.
- The component library. Current CLI command and init flow.
- The transport layer, if the project exposes an external API. Current setup for the typed-RPC library and its OpenAPI handler.
Then walk references/ and resolve every VERIFY: block that applies to the chosen stack. Record the resolved versions: they go in the blueprint and in AGENTS.md.
3. Blueprint, then stop
Present, compactly:
- Mini-PRD: the paragraph and the feature list.
- Entities and ERD: tables, fields, keys, relationship types. Per
references/database.md. Present as a diagram or a clear list; this is the piece most worth getting right before any code exists.
- The route space: the URLs the product will have, where the tenant sits in them, and what identifies a resource. Per
references/url-design.md. It belongs in the blueprint rather than emerging from the folder tree, because URLs become a public contract the moment anyone shares one.
- Folder tree: the actual tree you will create, per
references/architecture.md and the chosen profile.
- Stack and exact versions: resolved in phase 2, plus anything the live docs corrected.
- What you will not do: explicitly out of scope for this scaffold.
Then stop and wait for approval, asked through the selector (approve as-is / revise the entities / revise the stack). Do not scaffold before the user approves. If they change the entities or the stack, revise and present again.
4. Scaffold
In this order, so the project works end to end at every step:
- Run the framework CLI with the flags verified in phase 2. Let it create what it creates; do not fight it.
- Apply the folder structure from the approved blueprint. Empty directories are fine as placeholders only if something in them is coming in this same scaffold; otherwise leave them out.
- Database schema from the approved ERD, plus the initial migration. Verify it applies.
- Design system: install the component library, set semantic tokens in the global stylesheet, configure dark mode. Per
references/design-system.md.
- Guardrails, before the slice. Copy the preset from
lint/ in the dotfiles repo: oxlint.config.ts, .oxfmtrc.json, tools/oxlint/ and rule-tests/, plus ci.yml into .github/workflows/. Its README.md has the five install steps; references/lint-guardrails.md has the reasoning. Adapt the boundaries block and its fixtures to this project's layer names, then run node tools/oxlint/rule-tests/check.mjs — a boundary table nobody verified is a boundary table that may be denying everything or nothing. Guardrails go in first so the vertical slice is the first thing checked against them; boundary rules added after twenty files exist are boundary rules you weaken to make the build pass.
- One vertical slice. Pick a single real entity from the ERD and build it all the way through: DTO, policy, DAL, action, and a page that renders it. This is the template every future feature copies, and it is what proves the architecture actually runs. Per
references/data-layer.md. If the entity has a list — and most do — build the list the way references/list-views.md describes and the write the way references/mutations.md does, because whatever this slice does is what every later feature will copy. The URL-state dependency enters here and only here: install it when the slice actually has filters to put in the URL, not as part of the baseline, so a project without a list never carries it. Run the tdd skill here. The slice is the template every later feature copies, so whatever testing habit it establishes is the one the project keeps: a slice shipped without a test teaches the agent that features do not come with tests.
- Security baseline: security headers, the server-only markers, environment variable split, locked-down install scripts. Per
references/security.md.
- Configuration and logging: the environment schema that fails the build when a variable is missing, plus structured logging with a trace id. Per
references/operations.md.
AGENTS.md at the repo root, documenting conventions, the dependency rule, and the resolved versions. A CLAUDE.md that points at AGENTS.md rather than duplicating it.
5. Verify
Run the build, the linter, node tools/oxlint/rule-tests/check.mjs, and the slice's tests. The four must pass. If the vertical slice has a page, run the dev server and confirm it renders.
Then audit the repo against the non-negotiables:
python <skill>/scripts/audit_project.py --path .
It reports three things, and the last two are different. MISSING is something the repo says is absent. BY HAND is a non-negotiable with a semantic signature that no tool can decide, which is exactly the kind that gets quietly dropped when a session's context rolls over. A BY HAND line is not a pass, it is the list of what still needs a person. Walk it before reporting the bootstrap done.
Report what was created, the resolved versions, anything the live docs corrected, and what is deliberately left for later. Do not claim it works without the command output.
Convention
The failure this mode exists to prevent: an agent six weeks in, writing a query straight into a page component because nothing in its context said not to.
Order of authority
AGENTS.md at the repo root. This is the project's own record: resolved versions, layer names, the illegal imports, the domain vocabulary, where a new feature goes. Read it before answering anything architectural.
- The code already there. One existing module of the same kind outranks any general rule. Copy its shape.
references/. The principle behind the rule, and the answer when the repo is silent.
When the repo contradicts a reference file, the repo wins and you say so. A project that deliberately diverged is not a project that made a mistake. When the repo is silent, apply the reference and offer to write the decision into AGENTS.md.
The procedure
- Audit first when you are new to the repo.
python <skill>/scripts/audit_project.py --path . gives you, in one pass, which non-negotiables are in place and which are not. Cheaper than reading nineteen references to find out the project never had lint boundaries.
- Read
AGENTS.md. If there is none, say so: the project has no written conventions, and writing one is usually the highest-value next move. Per references/architecture.md.
- Name the layer. Answer "who should be allowed to know about this?" before "where does this file go?". The layer decides the folder, not the other way around.
- Open the one reference for the concern, not all nineteen. The table below maps concern to file.
When the question is not this skill's
Three questions arrive dressed as architecture questions and are answered better elsewhere. Hand them over instead of improvising:
| The question actually is |
Skill |
Why not here |
| "What should this module's interface be?", "where does the seam go?", "is this abstraction worth it?" |
codebase-design |
This skill owns layers: who may know about whom. That one owns depth: how much a module hides behind its interface. A file can be in the right layer and still be a shallow wrapper |
| "How do I test this?", "is this test worth keeping?", anything written test-first |
tdd |
The linter cannot see a missing tenant filter or a non-idempotent job; lint-guardrails.md says so explicitly. Those are caught by tests, which makes tdd the other half of the guardrails, not a separate topic |
| "This is broken", "this got slow", a failing behaviour with no obvious cause |
diagnosing-bugs |
An architecture answer to a bug report is a guess. That skill starts from a reproduction and does not stop at the first plausible story |
They are siblings, not alternatives: a diagnosis usually ends in a regression test, and a deepened module usually changes what the tests attach to.
4. Resolve the VERIFY: blocks that apply against the live docs before writing any code. A principle that is right and an API that is stale still produces a broken file.
5. Point at the closest existing example in the repo and match it: naming, file split, order of operations inside the function.
Keeping AGENTS.md alive
A convention that only lives in this skill is a convention the next session loses. When work establishes something durable (a new layer, a chosen library, a rule you had to explain twice), write it into AGENTS.md in the same change. Keep CLAUDE.md a pointer at AGENTS.md; two copies of the conventions means one of them is stale.
Reference files
Read the one the work is about. Reading all nineteen for a question about a foreign key wastes the context the actual task needs.
| File |
Covers |
Reach for it when |
architecture.md |
Layers, dependency rule, folder trees for both profiles, route groups and colocation, naming, boundary enforcement, AGENTS.md |
Where a file goes, whether an import is legal, how to split packages |
url-design.md |
Where the tenant lives in the URL, nesting vs flattening, ids and slugs, redirects and slug history, canonical forms, modals with their own URL |
Designing the route space, or restructuring one that already has shared links |
routing.md |
Layouts, loading/error/not-found, metadata and SEO |
Building out a route's shell, states, or social preview |
data-layer.md |
DAL, DTO, policy, multi-layered auth, per-render session caching |
Anything that reads or writes the database |
list-views.md |
URL as state, query param schemas, keyset pagination and tiebreakers, sort allowlists, search, empty vs no-results, cached filter combinations, exports |
Any screen that lists records with filters, sorting, search or pages |
mutations.md |
Action results, field-level errors, pending and optimistic states, cache invalidation after a write, double submission |
A form, or anything the user submits |
database.md |
PRD to entities to ERD, keys, relationships, referential actions, production migrations |
Designing the schema, or changing one that already has traffic |
multi-tenancy.md |
Isolation models, organizations and memberships, roles, tenant scoping, row-level security, cross-tenant leaks |
The product has organizations or workspaces, in any form |
direct-data-access.md |
Managed backends where the browser can reach the database, the three postures, RLS as the whole security model, realtime channels, staying portable |
Using Supabase or any platform that exposes the database to the client |
api-design.md |
Server actions vs route handlers, contract-first schemas, typed RPC, OpenAPI, error codes, webhooks |
Exposing an endpoint or shaping a mutation |
async-work.md |
What leaves the request, job tiers, retries and idempotency, cron, job context |
Work that is slow, scheduled, or can fail on its own |
file-uploads.md |
Presigned URLs, content validation, storage keys, metadata split, orphans |
Users send you files |
security.md |
server-only, taint, env vars, XSS, security headers, validation, supply chain |
Handling secrets, user-supplied content, or public entry points |
performance.md |
Waterfalls, streaming and Suspense, PPR, server vs client components, caching directives, images, bundle |
Something is slow, or a route turned dynamic |
operations.md |
Structured logs, trace ids, redaction, error tracking, environment schema and secrets |
Instrumenting the app, or wiring up configuration |
lint-guardrails.md |
Layer boundary rules, type-evidence rules, anti-slop, house rules, verifying the rules still bite, what lint cannot catch |
Setting up lint, or turning a repeated convention into an enforced one. The working preset lives in lint/ in dotfiles |
design-system.md |
Component ownership, semantic tokens, variants vs. wrappers, theming |
Styling anything |
accessibility.md |
Semantic markup, table and sort semantics, focus lifecycle, live regions, form errors, what tooling misses |
Building a table, a form, a modal or any custom interactive control |
maintenance.md |
How this skill is refreshed, what belongs in a VERIFY block, signals a reference went stale, what survives a change of stack |
Updating these references after a major release, or evaluating a different framework, ORM or database |
1---2name: project-architecture3description: Senior-level architecture for a product, in two modes. **Bootstrap** starts a project from zero (discovery, ERD, layered folders, data access layer, lint guardrails, design tokens) instead of shipping whatever the framework CLI left behind. **Convention** answers architecture questions mid-build so the rules set in week one still hold in week six: where does this file go, may this layer import that one, how do I model this table, does this query stay inside the tenant, is this endpoint safe, why is this route slow. Use when starting/creating/bootstrapping/scaffolding a project, and whenever work touches folder structure, layer boundaries, data access, schema design, migrations, multi-tenancy, API contracts, background jobs, file uploads, security, performance or observability. Use it too for the screens most products are made of — any list, table or feed with filters, sorting, search, pagination or shareable URLs, and any form or mutation (validation errors, pending and optimistic states, cache invalidation a4---56# Project architecture78The first hour of a project decides whether it scales. Folders are the easy part; the hard part is **ownership**: who is allowed to know about what. A codebase where the UI can reach Stripe, or where `page.tsx` calls the ORM directly, does not get better with time. It gets bigger.910This matters more with coding agents than without them. An agent reads the conventions already in the repo and builds on top of them. Bad structure does not stay bad at constant size; it compounds. Set the boundaries first and the agent's shortcuts become impossible rather than merely discouraged.1112Which is why this skill has a second job. Conventions decided in week one are forgotten by week six, by the agent whose context has rolled over and by the human who moved on. **Bootstrap** builds the architecture. **Convention** keeps it.1314## Pick the mode1516| Situation | Mode |17|---|---|18| Nothing exists yet, or only bare framework CLI output | [Bootstrap](#bootstrap) |19| A project already exists and work is happening inside it | [Convention](#convention) |2021## Everything version-specific is a moving target2223`references/` holds distilled architecture knowledge: layering, the dependency rule, DAL/DTO/policy, ERD design and migrations, tenant isolation, API contracts, list views, mutations, accessibility, async work, uploads, security, performance, operations, lint guardrails and design tokens. Those **principles** hold across versions.2425**Every concrete API, file name, flag, and command in them is a moving target.** The reference files mark those with `VERIFY:` blocks stating exactly what to look up. Resolve them against the live docs before writing code, in **both** modes, not just at bootstrap. Context7 goes through Executor; see the `mcp-integrations` skill for the tool path and the two-step flow. Read the version attached to whatever comes back: it is the difference between "the docs say X" and "the docs for the version installed here say X".2627Never write code from what a reference file, or your training data, *implies* the current API is. Live example: Next.js renamed `middleware` to `proxy`, and now ships its own docs inside `node_modules/next/docs`. Anything that hardcoded those is already wrong.2829When the live docs contradict a reference file, **the docs win** and you say so out loud. If a reference file's *principle* no longer has a mechanism in the current version, say that too rather than inventing one.3031## The non-negotiables3233The compressed form of the rules, for recall. Each one expands in the reference file named; that file is the authority.34351. **The dependency rule.** UI → Transport → Domain → Capabilities → Vendors, each layer reaching only the one below it. Shared contracts and the database client flow upward to everyone. (`architecture.md`)362. **The DAL is the only path to the database.** No ORM call in a page, a component, a route handler, or an action. (`data-layer.md`)373. **In a multi-tenant product, the tenant is a required argument.** Never optional, never inherited, never taken from a client-controlled value. This covers jobs, caches and storage keys, not just queries. (`multi-tenancy.md`)384. **Authorization before data, next to the data.** Upstream gates are an optimization, not the security model. (`data-layer.md`)395. **Validate in and out.** Inputs because users lie; outputs because the database returns more than the client should see. (`data-layer.md`)406. **Server-only is a build error, not a convention.** Sensitive modules import the server-only marker so a client import fails loudly. (`security.md`)417. **Every entry point is public.** A server action compiles to a POST endpoint; arriving through your form is not a fact you get to assume. (`security.md`)428. **Server Components by default.** `"use client"` lives on the leaves, only where there is interactivity. (`performance.md`)439. **One contract, both directions.** The schema is the single source of truth for input, output, types and docs. (`api-design.md`)4410. **The state of a view lives in the URL.** Filters, sort, search and page are query params, parsed against a schema. State trapped in a component is a view nobody can share, bookmark or restore. (`list-views.md`)4511. **A boundary that is not linted is a preference.** The dependency rule is only real once an illegal import fails the build. (`lint-guardrails.md`)4612. **A URL that has been shared is a contract.** Do not encode a movable relationship in a path, and never let a rename silently kill existing links. (`url-design.md`)4713. **The right element before any ARIA.** Native elements carry role, focus and keyboard behavior; a div reimplementing them is a permanent debt. Focus and announcements are owned, not assumed. (`accessibility.md`)4814. **Semantic tokens, never literal colors.** `bg-primary`, not `bg-blue-500`. (`design-system.md`)4915. **One naming format.** kebab-case for source files, snake_case in the database. (`architecture.md`, `database.md`)5051## Bootstrap5253Create a todo per phase. Do not skip phase 3's checkpoint.5455### 1. Discovery5657Understand the product before touching the stack. Ask only what you cannot infer, and ask it through the `AskUserQuestion` selector per the global `CLAUDE.md` rules: tenancy, profile and everything already decided are enumerable, so they are tabs. Only the mini-PRD paragraph is genuinely open, so that one goes in prose after the selector.5859- **What is it?** One paragraph. This becomes the mini-PRD.60- **Features in scope.** A list. Every noun in it is a candidate entity.61- **Who are the users, and does it have tenancy?** Single-user, multi-user, or multi-tenant (organizations/workspaces). This one decision reshapes the whole schema, and if the answer is multi-tenant, `references/multi-tenancy.md` governs the model before anything else does.62- **What is already decided?** Deployment target, database, auth provider, payments, anything the user already pays for or knows they want.63- **Does anything run outside a request?** Uploads, scheduled work, emails, exports, anything slow. These need a home in the blueprint rather than an improvised one later. Per `references/async-work.md` and `references/file-uploads.md`.6465Then pick the **profile**, and say which one you picked and why:6667| Profile | When | Shape |68|---|---|---|69| **Single app** (default) | Most projects. One deployable, one team, one product surface. | One app, layering enforced by folders and lint rules inside it. |70| **Monorepo** | Multiple deployables (web + docs + marketing), or capabilities that genuinely need to be swappable behind stable APIs (payments, storage, email across products). | Workspaces, one package per layer. |7172Do not default to the monorepo. It is the right end state for a product with real scale, and premature weight for anything smaller. The layering principles are identical in both; only the enforcement mechanism differs (folders + lint vs. package boundaries).7374### 2. Version verification7576Resolve, at minimum:7778- **The framework.** Current major, what the CLI creates today, which conventions were renamed or removed, which config flags the planned features need.79- **The ORM / database client.** Current schema syntax, id generation, migration commands.80- **The auth provider**, if any. Current session API and its server-side entry point.81- **The component library.** Current CLI command and init flow.82- **The transport layer**, if the project exposes an external API. Current setup for the typed-RPC library and its OpenAPI handler.8384Then walk `references/` and resolve every `VERIFY:` block that applies to the chosen stack. Record the resolved versions: they go in the blueprint and in `AGENTS.md`.8586### 3. Blueprint, then stop8788Present, compactly:89901. **Mini-PRD**: the paragraph and the feature list.912. **Entities and ERD**: tables, fields, keys, relationship types. Per `references/database.md`. Present as a diagram or a clear list; this is the piece most worth getting right before any code exists.923. **The route space**: the URLs the product will have, where the tenant sits in them, and what identifies a resource. Per `references/url-design.md`. It belongs in the blueprint rather than emerging from the folder tree, because URLs become a public contract the moment anyone shares one.934. **Folder tree**: the actual tree you will create, per `references/architecture.md` and the chosen profile.945. **Stack and exact versions**: resolved in phase 2, plus anything the live docs corrected.956. **What you will not do**: explicitly out of scope for this scaffold.9697**Then stop and wait for approval**, asked through the selector (approve as-is / revise the entities / revise the stack). Do not scaffold before the user approves. If they change the entities or the stack, revise and present again.9899### 4. Scaffold100101In this order, so the project works end to end at every step:1021031. **Run the framework CLI** with the flags verified in phase 2. Let it create what it creates; do not fight it.1042. **Apply the folder structure** from the approved blueprint. Empty directories are fine as placeholders only if something in them is coming in this same scaffold; otherwise leave them out.1053. **Database schema** from the approved ERD, plus the initial migration. Verify it applies.1064. **Design system**: install the component library, set semantic tokens in the global stylesheet, configure dark mode. Per `references/design-system.md`.1075. **Guardrails, before the slice.** Copy the preset from `lint/` in the dotfiles repo: `oxlint.config.ts`, `.oxfmtrc.json`, `tools/oxlint/` and `rule-tests/`, plus `ci.yml` into `.github/workflows/`. Its `README.md` has the five install steps; `references/lint-guardrails.md` has the reasoning. Adapt the boundaries block **and its fixtures** to this project's layer names, then run `node tools/oxlint/rule-tests/check.mjs` — a boundary table nobody verified is a boundary table that may be denying everything or nothing. Guardrails go in first so the vertical slice is the first thing checked against them; boundary rules added after twenty files exist are boundary rules you weaken to make the build pass.1086. **One vertical slice.** Pick a single real entity from the ERD and build it all the way through: DTO, policy, DAL, action, and a page that renders it. This is the template every future feature copies, and it is what proves the architecture actually runs. Per `references/data-layer.md`. If the entity has a list — and most do — build the list the way `references/list-views.md` describes and the write the way `references/mutations.md` does, because whatever this slice does is what every later feature will copy. The URL-state dependency enters here and only here: install it when the slice actually has filters to put in the URL, not as part of the baseline, so a project without a list never carries it. **Run the `tdd` skill here.** The slice is the template every later feature copies, so whatever testing habit it establishes is the one the project keeps: a slice shipped without a test teaches the agent that features do not come with tests.1097. **Security baseline**: security headers, the server-only markers, environment variable split, locked-down install scripts. Per `references/security.md`.1108. **Configuration and logging**: the environment schema that fails the build when a variable is missing, plus structured logging with a trace id. Per `references/operations.md`.1119. **`AGENTS.md`** at the repo root, documenting conventions, the dependency rule, and the resolved versions. A `CLAUDE.md` that points at `AGENTS.md` rather than duplicating it.112113### 5. Verify114115Run the build, the linter, `node tools/oxlint/rule-tests/check.mjs`, and the slice's tests. The four must pass. If the vertical slice has a page, run the dev server and confirm it renders.116117Then audit the repo against the non-negotiables:118119```bash120python <skill>/scripts/audit_project.py --path .121```122123It reports three things, and the last two are different. `MISSING` is something the repo says is absent. `BY HAND` is a non-negotiable with a semantic signature that no tool can decide, which is exactly the kind that gets quietly dropped when a session's context rolls over. **A `BY HAND` line is not a pass, it is the list of what still needs a person.** Walk it before reporting the bootstrap done.124125Report what was created, the resolved versions, anything the live docs corrected, and what is deliberately left for later. Do not claim it works without the command output.126127## Convention128129The failure this mode exists to prevent: an agent six weeks in, writing a query straight into a page component because nothing in its context said not to.130131### Order of authority1321331. **`AGENTS.md` at the repo root.** This is the project's own record: resolved versions, layer names, the illegal imports, the domain vocabulary, where a new feature goes. Read it before answering anything architectural.1342. **The code already there.** One existing module of the same kind outranks any general rule. Copy its shape.1353. **`references/`.** The principle behind the rule, and the answer when the repo is silent.136137When the repo contradicts a reference file, **the repo wins** and you say so. A project that deliberately diverged is not a project that made a mistake. When the repo is silent, apply the reference and offer to write the decision into `AGENTS.md`.138139### The procedure1401410. **Audit first when you are new to the repo.** `python <skill>/scripts/audit_project.py --path .` gives you, in one pass, which non-negotiables are in place and which are not. Cheaper than reading nineteen references to find out the project never had lint boundaries.1421. **Read `AGENTS.md`.** If there is none, say so: the project has no written conventions, and writing one is usually the highest-value next move. Per `references/architecture.md`.1432. **Name the layer.** Answer "who should be allowed to know about this?" before "where does this file go?". The layer decides the folder, not the other way around.1443. **Open the one reference for the concern**, not all nineteen. The table below maps concern to file.145146### When the question is not this skill's147148Three questions arrive dressed as architecture questions and are answered better elsewhere. Hand them over instead of improvising:149150| The question actually is | Skill | Why not here |151|---|---|---|152| "What should this module's interface be?", "where does the seam go?", "is this abstraction worth it?" | `codebase-design` | This skill owns *layers*: who may know about whom. That one owns *depth*: how much a module hides behind its interface. A file can be in the right layer and still be a shallow wrapper |153| "How do I test this?", "is this test worth keeping?", anything written test-first | `tdd` | The linter cannot see a missing tenant filter or a non-idempotent job; `lint-guardrails.md` says so explicitly. Those are caught by tests, which makes `tdd` the other half of the guardrails, not a separate topic |154| "This is broken", "this got slow", a failing behaviour with no obvious cause | `diagnosing-bugs` | An architecture answer to a bug report is a guess. That skill starts from a reproduction and does not stop at the first plausible story |155156They are siblings, not alternatives: a diagnosis usually ends in a regression test, and a deepened module usually changes what the tests attach to.1574. **Resolve the `VERIFY:` blocks that apply** against the live docs before writing any code. A principle that is right and an API that is stale still produces a broken file.1585. **Point at the closest existing example** in the repo and match it: naming, file split, order of operations inside the function.159160### Keeping `AGENTS.md` alive161162A convention that only lives in this skill is a convention the next session loses. When work establishes something durable (a new layer, a chosen library, a rule you had to explain twice), write it into `AGENTS.md` in the same change. Keep `CLAUDE.md` a pointer at `AGENTS.md`; two copies of the conventions means one of them is stale.163164## Reference files165166Read the one the work is about. Reading all nineteen for a question about a foreign key wastes the context the actual task needs.167168| File | Covers | Reach for it when |169|---|---|---|170| `architecture.md` | Layers, dependency rule, folder trees for both profiles, route groups and colocation, naming, boundary enforcement, `AGENTS.md` | Where a file goes, whether an import is legal, how to split packages |171| `url-design.md` | Where the tenant lives in the URL, nesting vs flattening, ids and slugs, redirects and slug history, canonical forms, modals with their own URL | Designing the route space, or restructuring one that already has shared links |172| `routing.md` | Layouts, loading/error/not-found, metadata and SEO | Building out a route's shell, states, or social preview |173| `data-layer.md` | DAL, DTO, policy, multi-layered auth, per-render session caching | Anything that reads or writes the database |174| `list-views.md` | URL as state, query param schemas, keyset pagination and tiebreakers, sort allowlists, search, empty vs no-results, cached filter combinations, exports | Any screen that lists records with filters, sorting, search or pages |175| `mutations.md` | Action results, field-level errors, pending and optimistic states, cache invalidation after a write, double submission | A form, or anything the user submits |176| `database.md` | PRD to entities to ERD, keys, relationships, referential actions, production migrations | Designing the schema, or changing one that already has traffic |177| `multi-tenancy.md` | Isolation models, organizations and memberships, roles, tenant scoping, row-level security, cross-tenant leaks | The product has organizations or workspaces, in any form |178| `direct-data-access.md` | Managed backends where the browser can reach the database, the three postures, RLS as the whole security model, realtime channels, staying portable | Using Supabase or any platform that exposes the database to the client |179| `api-design.md` | Server actions vs route handlers, contract-first schemas, typed RPC, OpenAPI, error codes, webhooks | Exposing an endpoint or shaping a mutation |180| `async-work.md` | What leaves the request, job tiers, retries and idempotency, cron, job context | Work that is slow, scheduled, or can fail on its own |181| `file-uploads.md` | Presigned URLs, content validation, storage keys, metadata split, orphans | Users send you files |182| `security.md` | server-only, taint, env vars, XSS, security headers, validation, supply chain | Handling secrets, user-supplied content, or public entry points |183| `performance.md` | Waterfalls, streaming and Suspense, PPR, server vs client components, caching directives, images, bundle | Something is slow, or a route turned dynamic |184| `operations.md` | Structured logs, trace ids, redaction, error tracking, environment schema and secrets | Instrumenting the app, or wiring up configuration |185| `lint-guardrails.md` | Layer boundary rules, type-evidence rules, anti-slop, house rules, verifying the rules still bite, what lint cannot catch | Setting up lint, or turning a repeated convention into an enforced one. The working preset lives in `lint/` in dotfiles |186| `design-system.md` | Component ownership, semantic tokens, variants vs. wrappers, theming | Styling anything |187| `accessibility.md` | Semantic markup, table and sort semantics, focus lifecycle, live regions, form errors, what tooling misses | Building a table, a form, a modal or any custom interactive control |188| `maintenance.md` | How this skill is refreshed, what belongs in a `VERIFY` block, signals a reference went stale, what survives a change of stack | Updating these references after a major release, or evaluating a different framework, ORM or database |