diff --git a/.claude/skills/add-surface/SKILL.md b/.claude/skills/add-surface/SKILL.md new file mode 100644 index 0000000..5a1331a --- /dev/null +++ b/.claude/skills/add-surface/SKILL.md @@ -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//`. A new route inside an existing feature goes in that feature's directory. +2. Put everything the feature owns in `src/features//`. 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. diff --git a/.claude/skills/verify/SKILL.md b/.claude/skills/verify/SKILL.md new file mode 100644 index 0000000..77841c8 --- /dev/null +++ b/.claude/skills/verify/SKILL.md @@ -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. diff --git a/AGENTS.md b/AGENTS.md index 643577d..bcf7b07 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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. + +# 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/` | 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`. |