CodeVetter · Repo Unpack · Contributor handoff
vercel/next.js
Read `AGENTS.md` first — `CLAUDE.md` is a symlink to it, and it encodes the non-obvious rules an agent will otherwise get wrong (watch-mode-before-editing, mode-specific test scripts, the PR-description policy for fork contributions, the internal-header security review rule). Work in a throwaway git worktree rather than the user's checkout. Expect slow feedback loops: a full `pnpm build-all` is minutes, `pnpm --filter=next build` ~60s, `pnpm --filter=next types` ~10s, and a single e2e file can take minutes because it installs a real tarball. The dominant trap is the env-var matrix: the same test can pass under webpack and fail under Turbopack, or pass plainly and fail under `__NEXT_CACHE_COMPONENTS=true`.
- `CLAUDE.md` is a symlink to `AGENTS.md` (verified via `ls -la`), so editing either edits the same 524-line file — do not treat them as two documents to keep in sync.
- Before editing Next.js source or integration tests, start `pnpm --filter=next dev` (the taskr watch build, ~1-2s per change) in a separate session; skipping it means tests run against a stale `packages/next/dist`, and the project convention is to state explicitly why if you skip it.
- Rebuild rules by change scope: edits under `packages/next/**` after bootstrap → `pnpm --filter=next build`; any Rust/Turbopack change or a branch switch → `pnpm build-all`; type errors only → `pnpm --filter=next types`.
- Always run a test with the script matching the mode AND bundler under verification (`test-dev-turbo`, `test-dev-webpack`, `test-start-turbo`, `test-start-webpack`); never re-run the same suite with different `-t` filters — capture output once with `> /tmp/test-output.log 2>&1` and grep the file.
- Files to read first for any server-side change: `packages/next/src/server/lib/router-server.ts` (request entry), `packages/next/src/server/base-server.ts` (render core contract), `packages/next/src/server/route-modules/route-module.ts` (route kind contract), and `packages/next/src/build/define-env.ts` (what actually reaches the bundle).
- Prefer a throwaway worktree (`git worktree add /tmp/scratch-work <branch>`) and symlink the root `node_modules` into it; expect `TS2307: Cannot find module` for `fast-glob`, `dotenv`, `@playwright/test` as worktree artifacts — those are not regressions and must not be 'fixed'.
- Type-check with the repo's own commands only: `pnpm typescript` runs `tsc --noEmit` against the root `tsconfig.json`, which pulls in `packages/next/types/global.d.ts` augmentations (e.g. `NodeJS.ProcessEnv` requiring `NODE_ENV`); a hand-rolled single-file tsconfig reports clean while CI fails.
- Pre-validate before committing to avoid ~2min lint-staged failures by running exactly what the hook runs: `pnpm prettier --with-node-modules --ignore-path .prettierignore --write <files>` then `npx eslint --config eslint.config.mjs --fix <files>`.
- Hard policy boundary: you may not write full PR descriptions for fork PRs targeting `vercel/next.js`, and you may not create issues/discussions/comments unless the user is verified (via `gh api /user/memberships/orgs`) as a `vercel`/`vercel-labs` org member — offer drafting help and links instead.
- Security review boundary: if a change reads a non-standard request header, check it against `INTERNAL_HEADERS` in `packages/next/src/server/lib/server-ipc/utils.ts` — this is called out in AGENTS.md as a mandatory PR review step, not a suggestion.
- Known trap — `app-page.ts` is a build template compiled by the *user's* bundler, so relative `require()` of internal modules will not resolve in a user project; new helpers must be exported from `entry-base.ts` and reached as `entryBase.*`, and all `react-server-dom-webpack/*` imports must stay in `entry-base.ts`.
- Known trap — keep `require()` behind compile-time `if/else` branches (not early-return/throw) so webpack DCE can eliminate Node-only imports from edge builds, and force Node-gating flags to `false` for edge in `define-env.ts`.
- Known trap — a stale `packages/next-swc/native/*.node` after a branch switch produces bogus Turbopack errors; delete it and re-run `pnpm install` to fall back to the npm-published binary.
- For debugging, set `__NEXT_SHOW_IGNORE_LISTED=true` to disable the ignore-list frame collapsing implemented in `packages/next/src/server/patch-error-inspect.ts`, and use `DEBUG=next:*` plus `NEXT_TELEMETRY_DISABLED=1` for local runs.
- For CI triage use `$pr-status-triage` and `scripts/pr-status.js`, and mirror the failing job's env vars exactly (the workflow's `afterBuild:` block in `.github/workflows/build_and_test.yml` is the source of truth for things like `IS_WEBPACK_TEST=1`) before attempting local reproduction.
- Commit convention: no 'Generated with Claude Code' or co-author footers, and never run `gh pr ready` — PRs stay in draft until the user decides.