Skip to content

Add instant-navs skill#94152

Draft
feedthejim wants to merge 10 commits into
canaryfrom
feedthejim/builtin-skill-instant-navs
Draft

Add instant-navs skill#94152
feedthejim wants to merge 10 commits into
canaryfrom
feedthejim/builtin-skill-instant-navs

Conversation

@feedthejim
Copy link
Copy Markdown
Contributor

@feedthejim feedthejim commented May 27, 2026

What

Adds a built-in skill, instant-navs, that teaches App Router Instant
Navigation and PPR shell-capture patterns, fact-checked against Next.js
16.3 source. Two entry points:

  • Diagnose Slow Navigations (primary): 6-step diagnostic loop for
    the common trigger "client navigations to this route feel slow." Flip
    instantInsights: { validationLevel: 'warning' }, navigate, read the
    panel or stdout diagnostic, apply one boundary move, loop, exit on
    fast second nav + clean stdout. No route marker, Playwright test, or
    build required.
  • Quickstart (lock-in path): 5-minute recipe to add a route marker,
    write the focused `@next/playwright` `instant()` test, and
    optionally promote the route to `unstable_instant = { level:
    'experimental-error' }` once the regression test exists.

Files:

  • `skills/instant-navs/SKILL.md` — workflows, flag requirements,
    composition rules, marker convention, acceptance criteria.
  • `skills/instant-navs/references/playwright-verification.md` —
    writing and auditing `@next/playwright` Instant tests.
  • `skills/instant-navs/references/diagnostic-loop.md` — Debug Ladder,
    Boundary Decision Table, Known Diagnostic Signatures, escape hatches.
  • `skills/instant-navs/references/react-suspense-composition.md` —
    layout, provider, fallback, shell-capture ownership patterns.

Also separates the published skill surface from the repo-local one
(`skills/README.md` declares `skills/` as the externally distributed
bundle; `.agents/skills/authoring-skills/SKILL.md` is scoped to
repo-local `.agents/skills/` only).

Why

App authors today reverse-engineer Instant Navigation from docs
scattered across PPR, Cache Components, `next/root-params`,
`generateStaticParams`, and `@next/playwright`. The skill
consolidates the composition rules and validation workflow in one
invocable artifact.

Most users arrive from "my page feels slow," not from a greenfield
adoption decision. Diagnose Slow Navigations is the headline so the
skill activates from the real trigger and offers a low-commitment fix
path before pushing toward the heavier test-and-lock-in flow.

Fact-Checked Against Source

  • Route segment config name is `unstable_instant`, not
    `instant`. The zod schema is non-strict, so `instant` typos
    compile to no-ops. The dev runtime sometimes suggests the wrong key
    in blocking-route diagnostics; the skill calls this trap out at step
    4 of Diagnose Slow Navigations.
  • Default `instantInsights.validationLevel` is `'manual-warning'`
    (`packages/next/src/server/config.ts:1621`), applied unconditionally
    even with no `experimental.instantInsights` block.
  • Validation is segment-scoped because navigations are
    segment-scoped
    . A parent layout's `` around
    `{children}` and a parent segment's `loading.tsx` both fail to
    silence `blocking-route` for a child page's suspending data, even
    though React's runtime fallback inheritance renders them correctly.
    Sibling navigations within a shared layout re-render only the
    changing leaf, so the boundary has to live in the suspending segment
    for every navigation source to land on an instant shell.
  • `next/root-params` exports named per-param getters (e.g.
    `import { locale } from 'next/root-params'`), not an aggregate
    `rootParams()` function.

Test plan

  • Skill auto-activates from "slow client navigations" triggers and
    from explicit Instant Navigation / `@next/playwright` mentions.
  • `pnpm --filter next build` includes `skills/instant-navs/**`
    in the `next/dist/skills/` bundle output.
  • Diagnose Slow Navigations loop runs end-to-end against a fresh
    App Router app with a planted blocker (cookies-above-shell,
    uncached fetch, or useSearchParams-without-Suspense).
  • Quickstart locks in the fix with a Playwright test in <5 min.

Follow-ups (not in this PR)

  • The dev runtime's "outside of ``" diagnostic wording is
    misleading when a parent layout has a Suspense whose fallback streams
    correctly. The skill explains the actual rule (validation is
    segment-scoped); the runtime message itself should be made more
    precise in a separate framework PR.
  • The eval harness in `evals/` doesn't yet copy `dist/skills/` into
    agent sandboxes; a separate PR can wire that up.

Adds a user-facing built-in skill that teaches App Router Instant Navigation and PPR shell-capture patterns. Covers the Playwright-first validation ladder, ten composition rules, shell-capture rules, test-oracle traps, a debug ladder, and a boundary decision table. Includes three references (diagnostic-loop, playwright-verification, react-suspense-composition) and a diagnostic-extraction script.

Bundled into next/dist/skills/instant-navs/ via packages/next/taskfile.js copy_skills.

Signed-off-by: Jimmy Lai <laijimmy0@gmail.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 27, 2026

Failing CI jobs

Commit: fda9e8a | About building and testing Next.js

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 27, 2026

Stats from current PR

🟢 1 improvement

Metric Canary PR Change Trend
Webpack Cold (First Request) 3.309s 3.204s 🟢 105ms (-3%) ▄▆▆▆▄
📊 All Metrics
📖 Metrics Glossary

Dev Server Metrics:

  • Listen = TCP port starts accepting connections
  • First Request = HTTP server returns successful response
  • Cold = Fresh build (no cache)
  • Warm = With cached build artifacts

Build Metrics:

  • Fresh = Clean build (no .next directory)
  • Cached = With existing .next directory

Change Thresholds:

  • Time: Changes < 50ms AND < 10%, OR < 2% are insignificant
  • Size: Changes < 1KB AND < 1% are insignificant
  • All other changes are flagged to catch regressions

⚡ Dev Server

Metric Canary PR Change Trend
Cold (Listen) 812ms 811ms █████
Cold (Ready in log) 778ms 781ms ██▇▆▆
Cold (First Request) 1.192s 1.190s ██▃▂▃
Warm (Listen) 812ms 812ms ▆█▆▆▆
Warm (Ready in log) 778ms 778ms ▇█▆▆▆
Warm (First Request) 583ms 581ms █▆▅▅▅
📦 Dev Server (Webpack) (Legacy)

📦 Dev Server (Webpack)

Metric Canary PR Change Trend
Cold (Listen) 814ms 813ms █████
Cold (Ready in log) 785ms 780ms ▇▇███
Cold (First Request) 3.309s 3.204s 🟢 105ms (-3%) ▄▆▆▆▄
Warm (Listen) 812ms 812ms █████
Warm (Ready in log) 787ms 788ms ▇▇███
Warm (First Request) 3.271s 3.243s ▅▆▆▇▅

⚡ Production Builds

Metric Canary PR Change Trend
Fresh Build 4.676s 4.705s █▄▅▅▆
Cached Build 4.707s 4.715s █▆▆▅▆
📦 Production Builds (Webpack) (Legacy)

📦 Production Builds (Webpack)

Metric Canary PR Change Trend
Fresh Build 24.467s 24.613s ▇█▆█▆
Cached Build 24.412s 24.289s ▇███▆
node_modules Size 507 MB 507 MB █████
📦 Bundle Sizes

Bundle Sizes

⚡ Turbopack

Client

Main Bundles
Canary PR Change
008ypkwxhzol9.js gzip 151 B N/A -
04hm05ar7kldw.js gzip 5.73 kB N/A -
05pjmzkb6_bx2.js gzip 155 B N/A -
0cz1d0mv5g_q7.js gzip 39.4 kB 39.4 kB
0dj46kukqg96u.js gzip 13.9 kB N/A -
0dvitrl5zg37g.js gzip 8.82 kB N/A -
0gn57unzp9cj7.js gzip 156 B N/A -
0hgh7weswzeyc.js gzip 154 B N/A -
0n_jt34y59ek-.js gzip 156 B N/A -
0q8_3dusot1rk.js gzip 65.6 kB N/A -
0sf7ysou-72zd.js gzip 8.71 kB N/A -
0zt2vt-9glw4j.js gzip 156 B N/A -
13yi-ex_n8ps5.js gzip 156 B N/A -
157abun3hwc_s.js gzip 10.3 kB N/A -
1elt1qium-r2m.css gzip 115 B 115 B
1jpaub6y8xlfr.js gzip 2.3 kB N/A -
1jzb4w8d2wg2h.js gzip 50.7 kB N/A -
1ot0mvscrc_uf.js gzip 233 B N/A -
1vwk0543z0fpb.js gzip 7.61 kB N/A -
2_m3xv2uq3sjc.js gzip 1.46 kB N/A -
21fdvwgh64eqz.js gzip 153 B N/A -
22qvit7es5csn.js gzip 159 B N/A -
24y34mwgrkqp4.js gzip 8.78 kB N/A -
2c-fd4y1zozz8.js gzip 8.79 kB N/A -
2d7416h_xd36x.js gzip 8.71 kB N/A -
2ifho6101i9bz.js gzip 71 kB N/A -
2jjk__fiybm3z.js gzip 169 B N/A -
2lyuhit6rn8fy.js gzip 9.44 kB N/A -
2q0gr8wfr3jwl.js gzip 8.77 kB N/A -
2t9e75oz6r0zp.js gzip 8.76 kB N/A -
2uku_olcn15b7.js gzip 8.79 kB N/A -
30r8mm-46bdqy.js gzip 220 B 220 B
324onewq6pt5f.js gzip 155 B N/A -
3c1jdxkzlb8oq.js gzip 12.9 kB N/A -
3inab2jybr4k9.js gzip 450 B N/A -
3jkm5tdjvaf_q.js gzip 13.1 kB N/A -
3kw5ih-u7m6yu.js gzip 154 B N/A -
3mt67agm5wp40.js gzip 10.6 kB N/A -
3oabm6bz3ucna.js gzip 159 B N/A -
3saabek4kohwi.js gzip 10 kB N/A -
4189xmby9yu1p.js gzip 13.6 kB N/A -
turbopack-01..n95f.js gzip 4.2 kB N/A -
turbopack-03..08mv.js gzip 4.2 kB N/A -
turbopack-0l..d4yd.js gzip 4.2 kB N/A -
turbopack-0t..tddl.js gzip 4.2 kB N/A -
turbopack-15.._7z6.js gzip 4.21 kB N/A -
turbopack-1i..twe9.js gzip 4.2 kB N/A -
turbopack-2h..pd3z.js gzip 4.2 kB N/A -
turbopack-2m..tjab.js gzip 4.2 kB N/A -
turbopack-2r..gkc3.js gzip 4.18 kB N/A -
turbopack-30..4f3f.js gzip 4.2 kB N/A -
turbopack-38..xmc_.js gzip 4.2 kB N/A -
turbopack-3c..zl6e.js gzip 4.2 kB N/A -
turbopack-3s..8uk3.js gzip 4.2 kB N/A -
turbopack-44..84hz.js gzip 4.2 kB N/A -
0_i7nqgx23st7.js gzip N/A 10 kB -
06puhytyxk31p.js gzip N/A 8.82 kB -
0j_9aszpra-qr.js gzip N/A 13.9 kB -
0j42f9zonj0wd.js gzip N/A 13 kB -
0j55buqga5ouy.js gzip N/A 156 B -
0m34gln_kt4fg.js gzip N/A 5.73 kB -
0ovx4f5ps03mz.js gzip N/A 155 B -
0zc_suxa7omv0.js gzip N/A 155 B -
11aw0-ta6iat3.js gzip N/A 50.7 kB -
19n2l-u3kwvi0.js gzip N/A 169 B -
1g3q1ww01thnl.js gzip N/A 2.3 kB -
1hraqxuiymq6v.js gzip N/A 8.79 kB -
1l9un1sl77287.js gzip N/A 1.46 kB -
1ordt6-2yc6pp.js gzip N/A 156 B -
2_zvio6m3evby.js gzip N/A 156 B -
2147zgtf14z-q.js gzip N/A 234 B -
23bz3xsg-5-1s.js gzip N/A 8.71 kB -
26h439qd-h8yt.js gzip N/A 7.61 kB -
27441mytv7pbm.js gzip N/A 9.43 kB -
2cjkwjgm1zcfs.js gzip N/A 8.71 kB -
2m0wbqccqkvo6.js gzip N/A 155 B -
2n4h-6od35r3u.js gzip N/A 71 kB -
2qtvsrfha8he-.js gzip N/A 152 B -
2scd8zaoyb8md.js gzip N/A 8.79 kB -
2st_qs6p_9us0.js gzip N/A 13.1 kB -
2zo2exm1d8qj1.js gzip N/A 13.6 kB -
3-qwg5kfnixmo.js gzip N/A 162 B -
34bebob8ux4vr.js gzip N/A 157 B -
34h7rhzpjm191.js gzip N/A 160 B -
3g-6cp5tfmp65.js gzip N/A 157 B -
3hn75zuxly9az.js gzip N/A 10.3 kB -
3hqh7m128tvsn.js gzip N/A 8.77 kB -
3hqti_t-zy1x4.js gzip N/A 449 B -
3mnawenie1flm.js gzip N/A 8.76 kB -
3ubsozlu6zs38.js gzip N/A 10.6 kB -
3w0o1l32pu9eg.js gzip N/A 65.6 kB -
43iwfqjnx1cy_.js gzip N/A 8.78 kB -
43xpw4h0vletp.js gzip N/A 156 B -
turbopack-0h..-i0f.js gzip N/A 4.2 kB -
turbopack-0i..0qps.js gzip N/A 4.18 kB -
turbopack-0y..2uvo.js gzip N/A 4.21 kB -
turbopack-14..opn5.js gzip N/A 4.2 kB -
turbopack-15..7l0b.js gzip N/A 4.2 kB -
turbopack-15..08rq.js gzip N/A 4.2 kB -
turbopack-1f..qb43.js gzip N/A 4.2 kB -
turbopack-1m..-co8.js gzip N/A 4.2 kB -
turbopack-24..k9f9.js gzip N/A 4.2 kB -
turbopack-2o..2sqn.js gzip N/A 4.2 kB -
turbopack-2y..9e-y.js gzip N/A 4.2 kB -
turbopack-34..wltk.js gzip N/A 4.2 kB -
turbopack-3z..rfcm.js gzip N/A 4.2 kB -
turbopack-43..o0mr.js gzip N/A 4.2 kB -
Total 469 kB 470 kB ⚠️ +69 B

Server

Middleware
Canary PR Change
middleware-b..fest.js gzip 723 B 719 B
Total 723 B 719 B ✅ -4 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 434 B 437 B
Total 434 B 437 B ⚠️ +3 B

📦 Webpack

Client

Main Bundles
Canary PR Change
2258-HASH.js gzip 61.7 kB N/A -
2266-HASH.js gzip 4.69 kB N/A -
3317.HASH.js gzip 169 B N/A -
4866-HASH.js gzip 5.64 kB N/A -
9e302639-HASH.js gzip 62.8 kB N/A -
framework-HASH.js gzip 59.5 kB 59.5 kB
main-app-HASH.js gzip 255 B 255 B
main-HASH.js gzip 39.9 kB 39.9 kB
webpack-HASH.js gzip 1.68 kB 1.68 kB
175fd0fd-HASH.js gzip N/A 62.8 kB -
2596-HASH.js gzip N/A 5.63 kB -
34-HASH.js gzip N/A 61.7 kB -
5691.HASH.js gzip N/A 169 B -
9156-HASH.js gzip N/A 4.68 kB -
Total 236 kB 236 kB ✅ -48 B
Polyfills
Canary PR Change
polyfills-HASH.js gzip 39.4 kB 39.4 kB
Total 39.4 kB 39.4 kB
Pages
Canary PR Change
_app-HASH.js gzip 193 B 193 B
_error-HASH.js gzip 181 B 182 B
css-HASH.js gzip 334 B 332 B
dynamic-HASH.js gzip 1.79 kB 1.81 kB
edge-ssr-HASH.js gzip 255 B 255 B
head-HASH.js gzip 351 B 348 B
hooks-HASH.js gzip 385 B 384 B
image-HASH.js gzip 580 B 580 B
index-HASH.js gzip 257 B 259 B
link-HASH.js gzip 2.51 kB 2.52 kB
routerDirect..HASH.js gzip 318 B 319 B
script-HASH.js gzip 387 B 386 B
withRouter-HASH.js gzip 316 B 316 B
1afbb74e6ecf..834.css gzip 106 B 106 B
Total 7.97 kB 7.99 kB ⚠️ +19 B

Server

Edge SSR
Canary PR Change
edge-ssr.js gzip 126 kB 126 kB
page.js gzip 277 kB 272 kB 🟢 5.31 kB (-2%)
Total 403 kB 398 kB ✅ -5.52 kB
Middleware
Canary PR Change
middleware-b..fest.js gzip 618 B 615 B
middleware-r..fest.js gzip 155 B 155 B
middleware.js gzip 44.3 kB 44.9 kB 🔴 +561 B (+1%)
edge-runtime..pack.js gzip 842 B 842 B
Total 46 kB 46.5 kB ⚠️ +558 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 719 B 717 B
Total 719 B 717 B ✅ -2 B
Build Cache
Canary PR Change
0.pack gzip 4.51 MB 4.51 MB
index.pack gzip 114 kB 114 kB
index.pack.old gzip 113 kB 113 kB
Total 4.74 MB 4.73 MB ✅ -3.77 kB

🔄 Shared (bundler-independent)

Runtimes
Canary PR Change
app-page-exp...dev.js gzip 352 kB 352 kB
app-page-exp..prod.js gzip 196 kB 196 kB
app-page-tur...dev.js gzip 351 kB 351 kB
app-page-tur..prod.js gzip 195 kB 195 kB
app-page-tur...dev.js gzip 348 kB 348 kB
app-page-tur..prod.js gzip 193 kB 193 kB
app-page.run...dev.js gzip 348 kB 348 kB
app-page.run..prod.js gzip 194 kB 194 kB
app-route-ex...dev.js gzip 77.6 kB 77.6 kB
app-route-ex..prod.js gzip 52.9 kB 52.9 kB
app-route-tu...dev.js gzip 77.6 kB 77.6 kB
app-route-tu..prod.js gzip 52.9 kB 52.9 kB
app-route-tu...dev.js gzip 77.2 kB 77.2 kB
app-route-tu..prod.js gzip 52.7 kB 52.7 kB
app-route.ru...dev.js gzip 77.2 kB 77.2 kB
app-route.ru..prod.js gzip 52.7 kB 52.7 kB
dist_client_...dev.js gzip 324 B 324 B
dist_client_...dev.js gzip 326 B 326 B
dist_client_...dev.js gzip 318 B 318 B
dist_client_...dev.js gzip 317 B 317 B
pages-api-tu...dev.js gzip 44.3 kB 44.3 kB
pages-api-tu..prod.js gzip 33.8 kB 33.8 kB
pages-api.ru...dev.js gzip 44.3 kB 44.3 kB
pages-api.ru..prod.js gzip 33.7 kB 33.7 kB
pages-turbo....dev.js gzip 53.7 kB 53.7 kB
pages-turbo...prod.js gzip 39.4 kB 39.4 kB
pages.runtim...dev.js gzip 53.6 kB 53.6 kB
pages.runtim..prod.js gzip 39.4 kB 39.4 kB
server.runti..prod.js gzip 63.1 kB 63.1 kB
use-cache-pr...dev.js gzip 69.9 kB 69.9 kB
use-cache-pr...dev.js gzip 69.9 kB 69.9 kB
use-cache-pr...dev.js gzip 68.3 kB 68.3 kB
use-cache-pr...dev.js gzip 68.2 kB 68.2 kB
Total 3.38 MB 3.38 MB
📎 Tarball URL
https://vercel-packages.vercel.app/next/commits/fda9e8a07b2cdf061ea00b3a6a75fb85837b3671/next

Commit: fda9e8a

Replaces internal Vercel/v0-team jargon with terms a vanilla Next.js user will understand on first read.

Translations: oracle → (focused) test, geometry → layout dimensions / box model, locked shell → captured shell, released route/UI → loaded route/UI, chrome → shared layout, persistent chrome → persistent shared layout, Instant lock → shell capture / while the shell is captured.

Per-file edits are pure language; no rule count or substantive guidance changed.

Signed-off-by: Jimmy Lai <laijimmy0@gmail.com>
- Rename route segment config from `instant` to `unstable_instant` to
  match the actual zod schema (the schema strips unknown keys silently,
  so the old name compiled to a no-op).
- Drop `rootParams()` framing; `next/root-params` exports named
  per-param getters, not an aggregate function.
- Add a Version And Flag Requirements section with the minimum Next.js
  version, `cacheComponents`, `experimental.instantInsights`,
  `experimental.exposeTestingApiInProductionBuild`, and the test deps.
- Tighten extract-instant-diagnostics.mjs regexes to match the actual
  backtick-wrapped `Could not validate \`unstable_instant\`` and
  `\`cookies()\` was called outside a request scope` strings.
- Drop the stale "error does not point at the call site" note for
  `headers()` inside `after()`; the error names the route and remediation.
… panel

- Expand the per-route `unstable_instant` config example with the
  granular escape hatches (`unstable_disableDevValidation`,
  `unstable_disableBuildValidation`, `unstable_disableValidation`)
  and the per-route `level` override.
- Reorder the diagnostic-loop Escape Hatches as a ladder from smallest
  to largest opt-out so readers pick the least disruptive one first.
- Point Source Priority at the dev overlay's Instant Navigation panel
  by name; it is the canonical surface for blocking-route diagnostics.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant