Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .claude/skills/add-surface/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
name: add-surface
description: Add a new page, route handler or metadata image to this app so it lands in the right directories with its feature-map row. Use whenever a change creates a new URL.
---

Read the relevant guide in `node_modules/next/dist/docs/01-app/` before writing the route file. This Next.js version differs from older ones.

1. Pick the feature name. A new page gets `src/features/<name>/`. A new route inside an existing feature goes in that feature's directory.
2. Put everything the feature owns in `src/features/<name>/`. That means its components, its data and its tests. Import only from the same directory, `@/lib` and `@/components`. Lint rejects an import of another feature.
3. Move code that two features need into `src/lib` when it is logic or data, and into `src/components` when it renders.
4. Add the route file under `src/app`. Keep it thin. `src/app/page.tsx` is the model: it re-exports the component from the feature.
5. Add the row to `docs/feature-map.md` in the same change. Fill every column, and write a Proof that would fail if the surface were broken, such as a literal the page must contain.
6. Run the `verify` skill. `pnpm check` confirms the row exists and `pnpm smoke` requests it.
59 changes: 59 additions & 0 deletions .claude/skills/verify/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
name: verify
description: Prove a change to this app works. Run the full gate, drive the changed surface in the running app, and paste the real output. Use before saying a task is done and before opening a pull request.
---

A change is done when this skill has run and its output is in the reply. Never weaken a check to make it pass. If a step cannot run, name the step and say the result is inconclusive.

## Gate

Run `nvm use` first. The gate refuses to run on a Node major other than the one in `.nvmrc`.

```bash
pnpm verify
```

It runs, in order, `typecheck`, `lint`, `format:check`, `check`, `test`, `build` and `smoke`, and stops at the first failure. These are the same commands as the CI jobs in `.github/workflows/ci.yml`. Paste the output. For a failure, paste the failing step and fix the cause.

## Launch

`pnpm smoke` launches the production build on a free port, requests every row in `docs/feature-map.md` and stops the server. Use it for any change that a request can prove.

To drive a surface by hand or with a browser, start the production build on a port of your own and keep the process id. Start it with `node`, not `pnpm start`. Killing the pnpm wrapper leaves the server running.

```bash
pnpm build
node node_modules/next/dist/bin/next start -p 3100 & echo $! > .next/verify.pid
```

## Doctor

One read-only check that the instance is worth driving.

```bash
curl -sI localhost:3100/ | head -1
```

It must print `HTTP/1.1 200 OK`. Anything else means the build is stale or the port belongs to another process. Fix that before driving.

## Drive

Find the surface in `docs/feature-map.md`. Its row has the files and a command that reaches it.

- A route or an image. Run the row's Reproduce command against your port and read the status, the header or the body.
- A page in a browser. Open `http://localhost:3100/` and use roles and names, not coordinates. The placeholder homepage has the links named `Deploy Now` and `Documentation`.
- Both color schemes. The styles follow `prefers-color-scheme`, so emulate `dark` and `light` for a visual change.

## Evidence

Paste the command and its output in the reply and in the Verification section of the pull request. For a visual change, attach a screenshot of the changed section before and after. State each result as `VERIFIED`, `NOT VERIFIED` or `INCONCLUSIVE`.

## Cleanup

Stop only the server this run started, by its process id.

```bash
kill "$(cat .next/verify.pid)" && rm .next/verify.pid
```

Never stop a server by name or by port. Another session may own it.
42 changes: 42 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,45 @@ This version has breaking changes — APIs, conventions, and file structure may
This block is written and re-added by `next dev` — verify at `node_modules/next/dist/server/lib/generate-agent-files.js`. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean.

<!-- END:nextjs-agent-rules -->

# Project rules

A Next.js 16 App Router app with React 19, Tailwind CSS 4, TypeScript, pnpm and Node 24. It currently serves only the create-next-app starting page. The app reads no environment variables and has no database.

## How to work

- Follow the agentic engineering manual at https://expeditionlabs.co/resources/agentic-manual/llms.txt for any task with more than one step. An explicit instruction from the user wins, then this file, then the manual.
- Trust rung 2. Work on a branch, open one pull request per issue, and leave review and merge to a human. Never push to `main` and never merge your own pull request.
- Done means the `verify` skill ran and its real output is in your reply. `pnpm verify` is the single gate and runs the same commands as CI. Run `nvm use` first.
- Never weaken a check, disable a lint rule or edit a test to get a pass. Fix the cause or report the failure.
- A new URL goes through the `add-surface` skill and gets its row in `docs/feature-map.md` in the same change.
- When behavior changes, update the doc that describes it in the same change. `pnpm check` validates the feature map and every relative markdown link.
- Change this file and `.claude/skills/` only in a pull request of their own, with an eval run from `docs/agent-evals.md`.

## Where things live

| Path | Holds |
| ------------------------------- | ---------------------------------------------------------------------------------------------- |
| `src/app` | Route files only. Each one is thin and hands off to a feature. |
| `src/features/<name>` | Everything one feature owns. A feature never imports another feature or a route. |
| `src/components` | Rendering shared by more than one feature or route. Create it with the first shared component. |
| `src/lib` | Shared data and logic with no I/O. Create it with the first shared module. |
| `scripts/checks` | Repository checks run by `pnpm check`, each with a test that proves it can fail. |
| `scripts/smoke.mjs` | Requests every surface in the feature map against the production build. |
| `docs/feature-map.md` | Every URL, its files, how to reach it and what proves it works. |
| `docs/guardrails.md` | Every rule and the mechanism that enforces it. |
| `docs/engineering-practices.md` | The audit against the engineering practices, with what was declined and why. |

## Commands

| Command | Does |
| ------------------- | ---------------------------------------------------------------- |
| `pnpm dev` | Development server on port 3000. |
| `pnpm verify` | The whole gate. Stops at the first failure. |
| `pnpm typecheck` | Generates route types, then runs the compiler. |
| `pnpm lint` | Read-only lint. `pnpm lint:fix` is for humans, never for a gate. |
| `pnpm format:check` | Read-only format check. `pnpm format` rewrites files. |
| `pnpm check` | Feature map, markdown links and version agreement. |
| `pnpm test` | Tests for the repository checks and the lint boundaries. |
| `pnpm build` | Production build. |
| `pnpm smoke` | Serves the build and requests every surface. Needs `pnpm build`. |
Loading