configure-isg
Skill106 starsChanged 7 months agoMITView on GitHub
Set up ISG revalidation for the project's adapter: `timeRevalidate`/`webhookRevalidate`, the `/__pracht/revalidate` webhook, Cloudflare and Vercel caching, and local verification. Use for "set up ISG", "configure revalidation", "add a revalidation webhook", "my ISG page never updates".
- Sends data out
In this repository33 other files it gives its agents.
- AGENTS.mdAGENTS.md
- add-authSkill
- add-capabilitiesSkill
- add-contentSkill
- add-dbSkill
- add-i18nSkill
- add-imagesSkill
- add-observabilitySkill
- add-openapiSkill
- audit-a11ySkill
- audit-agent-surfaceSkill
- audit-authSkill
- audit-bundlesSkill
- audit-csrfSkill
- audit-depsSkill
- audit-headersSkill
- audit-islandsSkill
- audit-loadersSkill
- audit-redirectsSkill
- audit-secretsSkill
- audit-seoSkill
- audit-shellsSkill
- migrate-nextjsSkill
- pracht-debugSkill
- pracht-deploySkill
- pracht-scaffoldSkill
- pracht-test-apiSkill
- pre-deploySkill
- scaffold-e2eSkill
- scaffold-testsSkill
- tune-render-modeSkill
- typed-routesSkill
- upgrade-prachtSkill
The file
We split this skill into the rules it gives an agent
6 rules. About 0 are common, 0 are distinctive, and 6 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
6
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 80
All adapters expose POST <base>/__pracht/revalidate (PRACHT_REVALIDATE_ENDPOINT from @pracht/core).
- Very specific: line 139
Before enabling cache: true, canonicalize or reject stray query params (the docs describe an uncached-gateway pattern), and note that …
- Very specific: line 158
Vercel: no faithful local production runtime — pracht preview points at vercel build/vercel dev.
- Very specific: line 171
Never overwrite wrangler.jsonc/wrangler.toml or vercel.json — diff and merge, confirming collisions with AskUserQuestion.
- Very specific: line 173
Never propose ISG for personalized responses.
- Very specific: line 182
Always pair render: "isg" with an explicit revalidate policy — without one the route silently behaves like SSG.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Pracht Configure ISG
ISG renders at build time and regenerates after a time window or an
authenticated webhook (https://pracht.resynapse.dev/docs/rendering#isg--incremental-static-generation, https://pracht.resynapse.dev/docs/adapters). The
mechanics differ per adapter, and a route with render: "isg" but no
revalidate policy never regenerates — the prerenderer only writes an ISG
manifest entry when a policy exists. This skill wires the policy, the
webhook, and the adapter-specific cache correctly.
Step 1: Identify adapter and candidate routes
MCP: if pracht dev-mcp is registered, prefer its inspect_*, doctor, and verify tools to the CLI.
pracht inspect routes --json # render + revalidate per route
pracht inspect build --json # adapterTarget (requires a prior `pracht build`)Prerequisite: pracht inspect needs a vite config with the pracht plugin
wired up. If unsure which routes deserve ISG at all, run
/tune-render-mode first — this skill assumes the mode choice is made.
Step 2: Wire the revalidate policy (manifest router)
// src/routes.ts
import { timeRevalidate, webhookRevalidate } from "@pracht/core";
route("/pricing", () => import("./routes/pricing.tsx"), {
render: "isg",
revalidate: [timeRevalidate(3600), webhookRevalidate()],
});timeRevalidate(seconds)— requires a positive integer; anything else throws at manifest evaluation.webhookRevalidate()— no arguments; opts the route into the webhook endpoint.revalidateaccepts one policy or an array (RouteRevalidate); the array above means "hourly, or sooner when a webhook names this path".
Pages router: time-based ISG is expressed with two static page exports:
export const RENDER_MODE = "isg";
export const REVALIDATE = 3600;REVALIDATE must be a positive integer literal number of seconds. Build,
doctor, and verify reject a missing or misplaced policy. Pages mode does
not accept policies on _app or 404, and fenced Markdown/MDX examples are
ignored. It does not support webhook or combined policies; eject with generateRoutesFile
from @pracht/vite-plugin/pages-router for those.
For dynamic routes, getStaticPaths() enumerates the prerendered params.
Paths it did not enumerate render per-request without a cached copy, and
webhooks naming them are skipped on Node/Cloudflare (nothing to refresh).
Step 3: The revalidation webhook
All adapters expose POST <base>/__pracht/revalidate
(PRACHT_REVALIDATE_ENDPOINT from @pracht/core). For example, an app with
base: "/app/" uses:
curl -X POST https://example.com/app/__pracht/revalidate \
-H "Authorization: Bearer $PRACHT_REVALIDATE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"paths":["/pricing"]}'At the default base: "/", omit /app. Keep request-body paths base-free;
they identify manifest routes rather than public deployment URLs.
- Auth:
PRACHT_REVALIDATE_TOKENenv var; fails closed with401when unset or wrong. Providers that can't send bearer auth may use thex-pracht-revalidate-tokenheader instead. - Body:
pathsarray, max 64 entries (else400). Response reportsrevalidated/skipped/failedarrays plus adetailsarray naming why each path was skipped (not_a_route,not_isg,not_prerendered,no_webhook_policy) or failed — checkdetailsfirst when a webhook appears to do nothing.scopesays how far a refresh reached:instance(Node: that server only),colo(Cloudflare Cache API: that data center only), orglobal(Netlify, Vercel, Cloudflare routes purged viacache: true). Failed paths keep serving the previous copy. Regeneration is single-flighted per path and never replays the caller's cookies/auth headers.
Step 4: Adapter mechanics
| Adapter | Time revalidation | Webhook revalidation |
| Node | File mtime vs window, per server; serves stale, refreshes in background | Regenerates the on-disk HTML synchronously on the receiving replica only — serve ISG routes from a single instance |
| Cloudflare (default) | Worker-managed Cache API timestamp, env.ASSETS fallback — per colo | Overwrites the Cache API entry in the receiving colo only (scope: "colo"); a colo with no cached copy serves the build snapshot as stale and re-renders, a colo holding a copy keeps it until eviction |
Cloudflare (cache: true) | Edge-tier Workers Caching in front of the Worker for time-revalidated routes | Webhook-only routes keep the worker-managed path; time+webhook routes also get their edge entry purged |
| Vercel | Build Output prerender functions: .prerender-config.json with expiration from the time policy and build HTML as fallback, next to a Node Serverless Function per ISG route (Vercel rejects ISR on an Edge Function) | For webhook revalidation, x-vercel-cache verifies the bypass; PRACHT_REVALIDATE_TOKEN becomes the bypassToken and must be set at build time (runtime-only setting → webhook paths report failed until you rebuild). Time-only ISR does not require the token. |
Cloudflare specifics (https://pracht.resynapse.dev/docs/adapters/cloudflare#isg-and-workers-caching):
- The default per-colo path needs no extra config. The
cache: trueupgrade needs bothcloudflareAdapter({ cache: true })in vite config (optionally{ cache: { staleWhileRevalidate: <seconds> } }) and{ "cache": { "enabled": true } }in wrangler config. - With it on, time-revalidated pages are no longer emitted as build-time snapshots (first request after deploy renders cold); webhook-only routes keep their snapshots.
- Programmatic purge:
purgeCache/routeCacheTagfrom@pracht/adapter-cloudflare/cache— protect any purge API route with a secret. - Cache safety: responses with
Set-Cookie,Cache-Control: private/no-store, orVary: Cookie/Authorization/*are never stored in the shared edge cache.
Step 5: Cache-key cardinality caveats
See https://pracht.resynapse.dev/docs/adapters/cloudflare#isg-and-workers-caching. Node and worker-managed
Cloudflare ISG key generated pages by pathname. Workers Caching keys by
exact path plus query string (param order and trailing slash included), so
/pricing?ref=a and /pricing?ref=b are independent entries with independent
revalidation — and attacker-chosen query values create unbounded cold entries.
Before enabling cache: true, canonicalize or reject stray query params (the
docs describe an uncached-gateway pattern), and note that routes exporting
markdown or declaring middleware-owned markdown: true carry Vary: Accept,
which multiplies variants per Accept string. Vercel prerender functions are
generated with allowQuery: [], so
query strings do not fragment that cache. Middleware never runs for cached ISG
hits on any adapter — keep per-visitor logic on SSR routes.
Step 6: Verify locally
- Node:
PRACHT_REVALIDATE_TOKEN=dev-secret pracht preview --port 3000(builds, then runsdist/server/server.jswith inherited env;--skip-buildreuses a build). Then curl the Step 3 command againstlocalhost:3000and check the JSON reports your path underrevalidated; re-fetch the page and confirm the change. For time policies, use a short window (e.g.timeRevalidate(5)), request after expiry — first response is the stale copy, the next one is fresh. - Cloudflare:
pracht previewdelegates towrangler dev; putPRACHT_REVALIDATE_TOKENin.dev.varsso the worker sees it. - Vercel: no faithful local production runtime —
pracht previewpoints atvercel build/vercel dev; verify webhook behavior on a real deployment built withPRACHT_REVALIDATE_TOKENset.
Finish with the standard gate — and run /pre-deploy before shipping:
pracht verify --json
pracht typegen # if src/routes.ts changedRules
- Never overwrite
wrangler.jsonc/wrangler.tomlorvercel.json— diff and merge, confirming collisions withAskUserQuestion. - Never propose ISG for personalized responses. ISG HTML renders always run
on a sanitized request (
GET,Accept: text/html, path only — no cookies, credentials, query, or body); Cloudflare Workers Caching uses the same isolation withAccept: text/markdownfor its markdown cache variant. A loader that reads the session therefore sees an anonymous visitor. On top of that,Set-CookieorCache-Control: private/no-storeoutput fails regeneration on every adapter (Vercel answers it with a503so its prerender cache keeps the previous page), andVary: Cookie/Authorization/*is kept out of shared caches by design. - Always pair
render: "isg"with an explicitrevalidatepolicy — without one the route silently behaves like SSG. - On Vercel, set
PRACHT_REVALIDATE_TOKENin the build environment, not just at runtime. - Webhook invalidation is per-colo on Cloudflare's default path and
per-instance on Node (the response's
scopesays which);pracht buildwarns about Cloudflare webhook routes. A webhook-only route never goes stale by time, so pair it withtimeRevalidate()to bound the lag, pluscache: trueon Cloudflare so the webhook purges every colo.
$ARGUMENTS
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

