# Pathrule Pattern: Astro (1.0.0)
# ::pathrule:package:astro

### [RULE] Hydrate islands intentionally, never by reflex  (path: /src/components)
<!-- scope: folder | priority: high | advisory -->

Astro renders UI framework components to static HTML by default and ships zero JavaScript for them. A `client:*` directive is a performance contract, not boilerplate. Default to no directive and add the lightest one only when interaction is actually required.

- Reserve `client:load` for above-the-fold controls that must be interactive immediately. Use `client:visible` for below-the-fold widgets and `client:idle` for low-priority ones.
- Treat `client:only` as a last resort. It skips server rendering, hurts SEO, and removes the static HTML fallback.
- Split large interactive components so only the truly dynamic part hydrates, keeping the rest as static `.astro` markup.
- Pass a `rootMargin` to `client:visible` for heavy components to hydrate them just before they scroll into view and reduce layout shift.

---

### [RULE] Define every collection with a loader and a Zod schema  (path: /src/content)
<!-- scope: folder | priority: high | strict -->

In Astro 5 content collections use the Content Layer API. Each collection is declared in `src/content.config.ts` with an explicit `loader` and a Zod `schema`, so frontmatter is validated at build time and queries are fully typed.

- Use the built-in `glob()` or `file()` loader for local Markdown, MDX, JSON, and YAML. Use a custom or community loader for CMS, API, or database sources.
- Always give the collection a `schema` so `getCollection()` and `getEntry()` return typed, validated data and bad frontmatter fails the build.
- Query content only through `getCollection()` / `getEntry()`. Do not read files with `fs` or `import.meta.glob`.
- For very large stores, set `retainBody: false` on the loader to shrink the deployed data store and avoid size limits.

---

### [MEMORY] Rendering modes: static by default, server islands for the dynamic bits  (path: /src/pages)

Astro pages are statically prerendered by default. Keep them that way so the shell can be cached aggressively, and push only the dynamic parts to the edges.

- Mark personalized or per-request fragments (avatar, cart, recommendations) with `server:defer` so they render in their own request without blocking the cached page.
- Provide a `slot="fallback"` for each server island so users see meaningful placeholder markup until the island resolves.
- Reach for full on-demand SSR (`export const prerender = false`) only when an entire route is dynamic. Prefer server islands on otherwise-static pages.
- Server islands need an SSR adapter configured, even when most of the site is static.

---

### [MEMORY] View Transitions and navigation polish without a framework  (path: /src)

Astro supports the native View Transitions API for animated, app-like navigation without adding a client-side framework. Add the `<ClientRouter />` component to a shared layout head to enable it site-wide.

- Persist stateful elements across navigations with `transition:persist` (for example a video player or audio element).
- Name matched elements with `transition:name` so Astro animates them between pages, and tune motion with `transition:animate`.
- The router enhances real navigations progressively. Pages still work as full document loads when the API is unavailable, so do not depend on it for correctness.
- Keep transitions subtle and respect `prefers-reduced-motion`; heavy animations undercut the speed Astro is chosen for.

---

### [SKILL] astro-review  (path: /)

---
name: astro-review
description: Review checklist for Astro 5 work covering hydration directives, the Content Layer API, server islands, rendering mode, and view transitions before merging.
---

# Astro review

- [ ] Framework components render static HTML by default; every `client:*` directive is justified and uses the lightest option (`visible`/`idle` over `load`).
- [ ] No stray `client:only` that drops server rendering and the static fallback.
- [ ] Content is read through `getCollection()` / `getEntry()`, never raw `fs` or `import.meta.glob`.
- [ ] Each collection in `src/content.config.ts` has an explicit `loader` and a Zod `schema`.
- [ ] Pages stay prerendered by default; `prerender = false` is used only for fully dynamic routes.
- [ ] Personalized fragments use `server:defer` with a `slot="fallback"`, and an SSR adapter is configured.
- [ ] Large content stores set `retainBody: false` when bodies are not needed at runtime.
- [ ] View Transitions go through `<ClientRouter />`; `transition:persist` and `transition:name` are applied where state or motion continuity matters.
- [ ] Animations respect `prefers-reduced-motion`.
- [ ] No unnecessary JavaScript shipped; the page works with scripts disabled where it reasonably should.
