agentleFS
casooncasoon/ai-agent-config/skills/astro-architecture/SKILL.md

astro-architecture

Skill1 starsChanged 47 days agoMITView on GitHub

Astro v6 architecture — rendering modes (SSG/SSR/hybrid), routing, Content Collections Loader API, Zod v4 schemas, hydration directives, API routes, and Node 22+ setup. Use when creating or modifying .astro pages and layouts, configuring astro.config.mjs, setting up or querying content collections, choosing rendering strategy, or hitting v5→v6 migration errors (`entry.slug`, `entry.render()`, `getEntryBySlug`, `src/content/config.ts` all changed in v6). Load this skill before touching any .astro file or astro config.

The file

We split this skill into the rules it gives an agent

4 rules. About 0 are common, 2 are distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈2

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Use islands intentionally, not by default.

    line 12
  2. Very specific:

    Prefer .astro components for presentational UI.

    line 25
  3. Distinctive:

    Use framework components (Svelte, React, Vue) only where client-side interaction is actually needed.

    line 26
  4. Very specific:

    When fallbackType: 'rewrite' is set, integrations can read fallback routes via the astro:routes:resolved hook:

    line 215

≈ “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.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Astro architecture

Goals

  • Server-first, static-friendly by default.
  • Minimize shipped client-side JavaScript.
  • Use islands intentionally, not by default.
  • Be explicit about SSG vs SSR vs hybrid per route.

Structure

  • src/pages for route entry points — keep files slim.
  • src/layouts for page shells.
  • src/components for reusable UI.
  • src/content for structured editorial content.
  • public for static assets that skip the module graph.

Rules

  • Prefer .astro components for presentational UI.
  • Use framework components (Svelte, React, Vue) only where client-side interaction is actually needed.
  • Move logic into utilities or domain modules — keep route files thin.
  • Reuse layouts and content schemas instead of duplicating page logic.
  • Cover SEO-critical metadata on every public page.

Astro v6 API

Content Collections — Loader API

// src/content.config.ts  (NOT src/content/config.ts)
import { defineCollection } from 'astro:content';
import { glob } from 'astro/loaders';
import { z } from 'astro/zod';

const blog = defineCollection({
  loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/blog' }),
  schema: z.object({
    title: z.string(),
    date: z.coerce.date(),
    // Zod v4 top-level validators
    email: z.email(),   // not z.string().email()
    website: z.url(),   // not z.string().url()
  }),
});

export const collections = { blog };

Rendering content

---
import { getCollection, render } from 'astro:content';

const posts = await getCollection('blog');
const { Content } = await render(post);  // not post.render()
---

<a href={`/blog/${post.id}`}>{post.data.title}</a>  <!-- id, not slug -->

Zod v4 syntax

import { z } from 'astro/zod';  // not from 'astro:content' or 'astro:schema'

z.email()   // instead of z.string().email()
z.url()     // instead of z.string().url()
z.uuid()    // instead of z.string().uuid()

z.string().min(5, { error: 'Too short.' });      // 'error', not 'message'
z.string().transform(Number).default(0);         // default matches output type

Removed / renamed APIs (v5 → v6)

OldNew
Astro.glob()import.meta.glob()
ViewTransitionsClientRouter
getEntryBySlug()getEntry()
post.render()render(post)
entry.slugentry.id
emitESMImageemitImageMetadata
src/content/config.tssrc/content.config.ts
handleForms prop on ClientRouterdefault behavior

Component patterns

Astro component

---
export interface Props {
  title: string;
  variant?: 'default' | 'primary';
}

const { title, variant = 'default' } = Astro.props;
---

<section>
  <h2>{title}</h2>
  <slot />
</section>

Hydration directives

  • client:load — immediate (navbar, theme toggle).
  • client:idle — browser idle (secondary features).
  • client:visible — in viewport (footer widgets, comments).
  • omit directive — static render only.

API route

import type { APIRoute } from 'astro';
import { z } from 'astro/zod';

const schema = z.object({
  email: z.email(),
  name: z.string().min(1),
});

export const POST: APIRoute = async ({ request }) => {
  try {
    const data = await request.json();
    const parsed = schema.safeParse(data);
    if (!parsed.success) {
      return new Response(JSON.stringify({ error: parsed.error.flatten() }), { status: 400 });
    }
    return new Response(JSON.stringify({ ok: true }), { status: 200 });
  } catch {
    return new Response('Invalid request', { status: 400 });
  }
};

Configuration

astro.config.mjs

import { defineConfig } from 'astro/config';
import svelte from '@astrojs/svelte';
import tailwindcss from '@tailwindcss/vite';

export default defineConfig({
  site: 'https://example.com',
  integrations: [
    svelte({ compilerOptions: { runes: true } }),
  ],
  vite: {
    plugins: [tailwindcss()],
    ssr: { noExternal: ['@fontsource/*'] },
  },
  build: { inlineStylesheets: 'auto' },
});

Node requirement

Astro v6 requires Node >= 22.12.0. Older versions are not supported.

New stable features (promoted from experimental)

  • Live Content Collections — real-time data without rebuild.
  • Content Security Policy — automatic CSP headers.
  • Vite Environment API — dev server matches production runtime.

Astro 6.1 additions

Sharp image service config

Codec-specific encoder options (only for astro/assets/services/sharp, not noop):

image: {
  service: {
    entrypoint: 'astro/assets/services/sharp',
    config: {
      webp: { effort: 6, alphaQuality: 90 },
      avif: { effort: 4, chromaSubsampling: '4:2:0' },
      jpeg: { mozjpeg: true },
      png:  { compressionLevel: 8 },
    },
  },
},

Per-image quality prop still takes precedence over config defaults. Cloudflare Workers does not support Sharp — use noop there.

SmartyPants options object

markdown: {
  smartypants: {
    dashes: 'oldschool', // -- → en-dash, --- → em-dash
    ellipses: true,      // ... → …
    backticks: false,
    quotes: true,        // "hello" → curly quotes
  },
},

i18n fallbackRoutes in integrations

When fallbackType: 'rewrite' is set, integrations can read fallback routes via the astro:routes:resolved hook:

{
  name: 'my-integration',
  hooks: {
    'astro:routes:resolved': ({ routes }) => {
      const fallbacks = routes.filter((r) => r.fallbackRoutes?.length);
    },
  },
}

Notable 6.1 bugfixes

  • CSRF checkOrigin reads X-Forwarded-Proto behind reverse proxies.
  • Cloudflare server:defer dev crash fixed.
  • Middleware HMR: changes detected in dev server.
  • Warning when Vite 8 is hoisted (Astro requires Vite 7).
  • ClientRouter skips animations when the browser supplies a native transition.

Review checklist

  • Is hydration avoidable for this component?
  • Is content modeled as a collection with a schema, not ad-hoc?
  • Is the component boundary clear (server-rendered vs island)?
  • Are SEO basics covered — title, description, canonical, OG?
  • Is the rendering mode of the page explicit (static vs on-demand)?

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.