Cursor plugin for Astro 6 (Server Islands, Content Layer, Actions, Sessions, astro:env). Pinned to astro ^6.3.3. Teaches the APIs that LLMs trained pre-October 2024 do not know (astro:env typed env, Server Islands with server:defer, the Content Layer with loader: glob() / loader: file(), server actions with astro:schema, Astro Sessions, the ClientRouter rename, the output: 'hybrid' removal). Catches 48 LLM regressions with BAD / GOOD .astro + TypeScript pairs.
Astro 6.3.3 shipped on 2026-05-14. Astro 5.0 shipped on 2024-11-06. Most LLMs in production today were trained before either landed; they emit code that looks like Astro 4. The biggest regressions:
getEntryBySlug,Astro.glob,entry.render(),entry.slug: all removed in Astro 5 when the Content Layer became the only collection API.type: 'content'/type: 'data': replaced byloader: glob(...)/loader: file(...)fromastro/loaders.<ViewTransitions />: renamed<ClientRouter />in Astro 5.0.output: 'hybrid': removed in Astro 5; pick'static'or'server'and useexport const prerender = true/falseper page.@astrojs/tailwind: only works with Tailwind 3. Tailwind 4 ships as@tailwindcss/vite; you put it invite.plugins, not inintegrations.import.meta.env.SECRET_*: leaks into the client bundle when the variable is referenced from aclient:*island. Useastro:env/serverwithaccess: 'secret', which the build refuses to expose.defineActionwithoutinput: handler receivesunknown, no validation.import { z } from 'zod'insidesrc/actions/: produces two parallel Zod runtimes whoseinstanceofchecks disagree. Useastro:schema.src/content/config.ts: legacy path; Astro 6 removed the fallback. Move tosrc/content.config.tsat thesrc/root.- Lucia auth: archived March 2025. Use
better-auth. - Node 18 in
engines: Astro 6 requires Node 22.12.
This plugin is the 16th in the RoninForge series. It ships:
- 10 MDC rules with proper
globs - 48 documented anti-patterns with BAD / GOOD pairs and source URLs
- 5 skills
- 1 reviewer agent with severity grouping
- 2 fixture projects (correct + anti-pattern)
- 1 validator script
git clone https://github.com/RoninForge/roninforge-astro.git
# -n preserves any existing rule of the same name.
cp -rn roninforge-astro/rules/* your-project/.cursor/rules/
cp -rn roninforge-astro/skills/* your-project/.cursor/skills/
cp -rn roninforge-astro/agents/* your-project/.cursor/agents/Or vendor the whole repo as a git submodule under your-project/.cursor/plugins/.
| Rule | Scope (globs) | What it does |
|---|---|---|
astro-anti-patterns |
**/*.astro,**/*.ts,**/*.tsx,**/*.mdx,astro.config.{mjs,ts},src/content.config.ts,src/content/config.ts |
48 LLM regressions with BAD / GOOD pairs and source URLs |
astro-content-layer |
src/content.config.ts,src/content/**/* |
defineCollection + glob() / file() loaders, schema with image() and reference(), getEntry / render() |
astro-env-and-secrets |
astro.config.{mjs,ts},src/env.d.ts,**/*.astro,**/*.ts |
envField schema, the four context x access combinations, astro:env/server vs astro:env/client |
astro-server-islands |
**/*.astro,astro.config.{mjs,ts} |
server:defer, fallback slot, JSON-only props, adapter requirement, Astro.url limitation |
astro-actions-and-forms |
src/actions/**,**/*.astro,**/*.ts |
defineAction, astro:schema zod, accept: 'form', Astro.callAction, multipart enctype |
astro-sessions |
astro.config.{mjs,ts},**/*.astro,src/middleware.ts,src/actions/** |
Astro.session.get/set/regenerate, drivers, secure cookie flags |
astro-images-and-assets |
**/*.astro,**/*.mdx |
<Image>, <Picture>, getImage(), image.domains / image.remotePatterns, responsive layout |
astro-output-and-prerender |
astro.config.{mjs,ts},**/*.astro,src/pages/** |
'static' vs 'server', per-route prerender flag, hybrid removal |
astro-routing-and-endpoints |
src/pages/** |
File-based routes, dynamic [id] and rest [...slug], uppercase APIRoute exports |
astro-middleware-and-locals |
src/middleware.{ts,js},src/middleware/**,src/env.d.ts |
defineMiddleware, sequence, App.Locals typing |
| Skill | Command | What it does |
|---|---|---|
| New page | /astro-new-page |
Scaffold a .astro page or endpoint with optional [param] and prerender flag |
| New collection | /astro-new-content-collection |
Scaffold a defineCollection in src/content.config.ts with glob() / file() loader and zod schema |
| New action | /astro-new-action |
Scaffold a defineAction in src/actions/index.ts with astro:schema zod input and form / file examples |
| Migrate to Content Layer | /astro-migrate-to-content-layer |
Stage-by-stage diff for moving from Astro 4 (type:'content', entry.render(), getEntryBySlug, Astro.glob) to Astro 6 |
| Validate | /astro-validate |
Run validate-plugin.sh + astro check + vitest + grep audit for tracked anti-patterns |
| Agent | What it does |
|---|---|
astro-reviewer |
Reviews Astro 6 code by severity. CRIT: secret in client bundle, client+secret astro:env, action without zod input, insecure session cookie flags, Lucia still imported. ERR: getEntryBySlug, Astro.glob, entry.render, type:'content', entry.slug, output:'hybrid', lowercase endpoint exports, getStaticPaths in SSR, raw img for local, remote without domains config, @astrojs/tailwind with v4, server-island without adapter, non-serializable island props, server-island uses Astro.url, Cloudflare bare node import, middleware no return next, untyped locals, ViewTransitions import, client:only without name, integration+vite tailwind mix, node 18, zod imported directly in actions, content config old path. WARN: client:load everywhere, client:visible above-fold, fetch waterfall, top-level awaits, action without callAction, file form wrong enctype, getRelativeLocaleUrl on current path, manual i18n routing, MDX missing charset, MDX component missing import, partytown + view transitions, prefetch on everything, missing prerender flag, server-island on prerendered page, mixed zod imports across actions, no astro check in CI. NIT: tsconfig not strict, missing .astro/types.d.ts include, Image missing alt, action named apply outside index |
| Severity | Count |
|---|---|
| CRIT | 5 |
| ERR | 23 |
| WARN | 16 |
| NIT | 4 |
| Total | 48 |
See rules/astro-anti-patterns.mdc for the full catalogue with BAD / GOOD pairs and source URLs.
| Package | Version |
|---|---|
astro |
^6.3.3 |
@astrojs/check |
^0.9.9 |
@astrojs/node |
^10.1.1 |
@astrojs/mdx |
^5.0.6 |
@astrojs/sitemap |
^3.7.2 |
@astrojs/rss |
^4.0.18 |
@tailwindcss/vite |
^4.3.0 |
tailwindcss |
^4.3.0 |
typescript |
^6.0.3 |
vitest |
^4.1.6 |
zod |
^4.4.3 |
| Node | >=22.12.0 |
The tests/fixtures/anti-pattern-sample/ project deliberately pins Astro 4 era versions (astro@^4.16.19, @astrojs/tailwind@^5, zod@^3, node@>=18) so the contrast against the correct sample is obvious and the validator can confirm each tracked violation is present.
bash tests/validation/validate-plugin.shValidates:
.cursor-plugin/plugin.jsonis valid JSON with the required fields.- Every
rules/*.mdcopens with YAML frontmatter and hasdescription+globs. - Every
skills/*/SKILL.mdhas frontmatter withname(matching the directory) +description. - Every
agents/*.mdhas frontmatter withname+description. correct-sampleis FREE of:output: 'hybrid',<ViewTransitions,getEntryBySlug,Astro.glob(,type: 'content',@astrojs/tailwind,process.env.,.render()method calls,client:onlywithout a framework name,from 'zod'insidesrc/actions/,import.meta.envreads of secret-shaped keys (STRIPE / SECRET / API_KEY / TOKEN / PRIVATE), and raw<img src="/src/...">references to local images.anti-pattern-sampleCONTAINS each of those patterns (negative test confirms fixtures are realistic).correct-sample/package.jsonpinsastro ^6.3andnode >=22.12.- No em dashes (U+2014) anywhere in
rules/,skills/,agents/,README.md. - No emojis in
rules/,skills/,agents/,README.md.
Exit 0 with the line ALL CHECKS PASSED on success.
MIT - see LICENSE