Install
$ agentstack add skill-0xdarkmatter-claude-mods-astro-ops ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Astro Operations
Comprehensive patterns for Astro framework development: islands architecture, content collections, rendering strategies, view transitions, and multi-platform deployment.
Rendering Strategy Decision Tree
Which rendering strategy?
│
├─ Is content mostly static (blog, docs, marketing)?
│ ├─ YES → Does it change less than daily?
│ │ ├─ YES → SSG (output: 'static')
│ │ │ Fastest TTFB, CDN-cacheable, zero runtime cost
│ │ └─ NO → Hybrid (output: 'hybrid')
│ │ Default static + opt-in SSR per route
│ └─ NO → Does every page need personalization?
│ ├─ YES → SSR (output: 'server')
│ │ Dynamic per-request, auth-aware, real-time data
│ └─ NO → Hybrid (output: 'hybrid')
│ Static shell + server islands for dynamic parts
│
├─ Does the app need real-time interactivity (dashboard, SPA)?
│ ├─ YES → Is it a full SPA with client-side routing?
│ │ ├─ YES → Consider React/Vue SPA instead, or Astro + client:only
│ │ └─ NO → Hybrid + islands architecture
│ │ Interactive islands in static pages
│ └─ NO → SSG (output: 'static')
│
├─ Build time concerns (>10k pages)?
│ ├─ YES → Hybrid with on-demand rendering
│ │ Prerender popular pages, SSR the long tail
│ └─ NO → SSG handles it fine
│
└─ Need edge computing (low latency globally)?
├─ YES → SSR + Cloudflare/Vercel Edge adapter
└─ NO → SSR + Node adapter or SSG
Configuration
// astro.config.mjs
import { defineConfig } from 'astro/config';
// SSG (default) - all pages prerendered at build time
export default defineConfig({
output: 'static',
});
// SSR - all pages rendered on request
export default defineConfig({
output: 'server',
adapter: cloudflare(), // or vercel(), netlify(), node()
});
// Hybrid - static default, opt-in SSR per page
export default defineConfig({
output: 'hybrid',
adapter: cloudflare(),
});
---
// In hybrid mode, opt OUT of prerendering for specific pages:
export const prerender = false;
// In SSR mode, opt IN to prerendering:
export const prerender = true;
---
Islands Architecture Quick Reference
| Directive | Hydrates When | JS Shipped | Use Case | |-----------|--------------|------------|----------| | client:load | Immediately on page load | Full bundle | Above-fold interactive (nav, hero CTA) | | client:idle | After page is idle (requestIdleCallback) | Full bundle | Below-fold interactive (comment form, chat) | | client:visible | When scrolled into viewport | Full bundle | Far-down-page (footer widget, carousel) | | client:media | When media query matches | Full bundle | Mobile-only nav, responsive components | | client:only="react" | Immediately, skip SSR entirely | Full bundle | Components that can't SSR (canvas, WebGL) | | (none) | Never - static HTML only | Zero JS | Static content, cards, headers |
---
import NavBar from '../components/NavBar.tsx';
import CommentForm from '../components/CommentForm.tsx';
import ImageCarousel from '../components/ImageCarousel.svelte';
import MobileMenu from '../components/MobileMenu.vue';
import ThreeScene from '../components/ThreeScene.tsx';
---
Content Collections Quick Start
Define Schema
// src/content.config.ts (Astro 5) or src/content/config.ts (Astro 4)
import { defineCollection, z, reference } from 'astro:content';
import { glob } from 'astro/loaders';
const blog = defineCollection({
loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/blog' }),
schema: z.object({
title: z.string(),
description: z.string().max(160),
pubDate: z.coerce.date(),
updatedDate: z.coerce.date().optional(),
heroImage: z.string().optional(),
tags: z.array(z.string()).default([]),
draft: z.boolean().default(false),
author: reference('authors'), // Reference another collection
}),
});
const authors = defineCollection({
loader: glob({ pattern: '**/*.json', base: './src/content/authors' }),
schema: z.object({
name: z.string(),
avatar: z.string(),
bio: z.string(),
socials: z.object({
twitter: z.string().optional(),
github: z.string().optional(),
}).optional(),
}),
});
export const collections = { blog, authors };
Query Collections
---
import { getCollection, getEntry } from 'astro:content';
// Get all non-draft blog posts, sorted by date
const posts = (await getCollection('blog', ({ data }) => !data.draft))
.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
// Get a single entry
const post = await getEntry('blog', 'my-first-post');
// Resolve a reference
const author = await getEntry(post.data.author);
// Render content
const { Content, headings } = await post.render();
---
Content Collections vs External CMS
| Criterion | Content Collections | External CMS (Payload, etc.) | |-----------|--------------------|-----------------------------| | Content type | Local markdown/MDX, docs, blogs | Relational data models | | Authors | Developers (version-controlled) | Editors (admin UI, multi-user auth) | | Validation | Type-safe via Zod at build time | CMS-side schemas + API contracts | | Update cadence | Deploys with the site | Independent of deployments | | API needs | None (build-time queries) | REST/GraphQL for other consumers | | Workflow | Git PRs, simple review | Editorial workflows, drafts, roles |
Rule of thumb: start with Content Collections; reach for a CMS only when non-developers need to publish without a deploy, or when content is genuinely relational.
Project Structure Reference
project-root/
├── astro.config.mjs # Astro configuration
├── tsconfig.json # TypeScript config (extends astro/tsconfigs)
├── package.json
├── public/ # Static assets (copied as-is)
│ ├── favicon.svg
│ ├── robots.txt
│ └── og-image.png
├── src/
│ ├── pages/ # File-based routing
│ │ ├── index.astro # → /
│ │ ├── about.astro # → /about
│ │ ├── blog/
│ │ │ ├── index.astro # → /blog
│ │ │ └── [slug].astro # → /blog/:slug (dynamic)
│ │ ├── api/
│ │ │ └── search.ts # → /api/search (API endpoint)
│ │ └── [...slug].astro # → catch-all/404
│ ├── layouts/
│ │ ├── BaseLayout.astro # HTML shell, , global styles
│ │ └── BlogPost.astro # Blog post layout
│ ├── components/
│ │ ├── Header.astro # Static Astro component
│ │ ├── Footer.astro
│ │ ├── NavBar.tsx # React island
│ │ └── Counter.svelte # Svelte island
│ ├── content/ # Content collections source files
│ │ ├── blog/
│ │ │ ├── post-one.md
│ │ │ └── post-two.mdx
│ │ └── authors/
│ │ └── jane.json
│ ├── content.config.ts # Collection schemas (Astro 5)
│ ├── middleware.ts # Request/response middleware
│ ├── styles/
│ │ └── global.css
│ └── lib/ # Shared utilities
│ ├── utils.ts
│ └── constants.ts
└── .env # Environment variables
View Transitions Quick Reference
---
// src/layouts/BaseLayout.astro
import { ViewTransitions } from 'astro:transitions';
---
Transition Directives
Content
Content
No animation
Lifecycle Events
document.addEventListener('astro:before-preparation', (e) => {
// Before new page is fetched - cancel navigation, show loading
});
document.addEventListener('astro:after-preparation', (e) => {
// New page fetched, before swap
});
document.addEventListener('astro:before-swap', (e) => {
// Customize DOM swap behavior
});
document.addEventListener('astro:after-swap', () => {
// DOM updated - reinitialize scripts
});
document.addEventListener('astro:page-load', () => {
// Page fully loaded (fires on initial + every navigation)
// Use this instead of DOMContentLoaded with View Transitions
});
Back/Forward Handling
// astro.config.mjs
export default defineConfig({
prefetch: {
prefetchAll: true, // Prefetch all links on hover
defaultStrategy: 'hover', // 'hover' | 'tap' | 'viewport' | 'load'
},
});
Prefetch on hover (default)
Prefetch when visible
Prefetch immediately
No prefetch
Deployment Decision Tree
Where to deploy?
│
├─ Need edge computing + Cloudflare ecosystem (KV, D1, R2)?
│ └─ Cloudflare Pages/Workers
│ Adapter: @astrojs/cloudflare
│ Best for: Global edge, Workers bindings, cost-effective
│
├─ Need serverless + Vercel ecosystem (ISR, analytics)?
│ └─ Vercel
│ Adapter: @astrojs/vercel
│ Best for: Next.js migration, image optimization, ISR
│
├─ Need serverless + Netlify ecosystem (forms, identity)?
│ └─ Netlify
│ Adapter: @astrojs/netlify
│ Best for: JAMstack, built-in forms, split testing
│
├─ Need full server control (Docker, custom runtime)?
│ └─ Node.js (standalone or Express/Fastify)
│ Adapter: @astrojs/node
│ Best for: Self-hosted, WebSocket, long-running processes
│
└─ Pure static site (no SSR needed)?
└─ Any static host (GitHub Pages, S3, Cloudflare Pages)
No adapter needed, output: 'static'
Best for: Blogs, docs, marketing sites
Adapter Installation
# Cloudflare
npx astro add cloudflare
# Vercel
npx astro add vercel
# Netlify
npx astro add netlify
# Node.js
npx astro add node
Common Gotchas
| Gotcha | Why | Fix | |--------|-----|-----| | Hydration mismatch errors | Server HTML differs from client render (dates, random IDs, browser APIs) | Use client:only for browser-dependent components, or ensure deterministic rendering | | import.meta.env undefined in client | Only PUBLIC_ prefixed vars are exposed to client-side code | Rename to PUBLIC_MY_VAR or pass via props from server | | Dynamic routes 404 in SSG | getStaticPaths() not returning all possible params | Ensure getStaticPaths() returns every valid path, or switch to hybrid/SSR | | Images not optimizing | Using ` instead of Astro's component | Import from astro:assets: import { Image } from 'astro:assets' and use local imports for src | | SSR fails without adapter | output: 'server' or 'hybrid' requires a deployment adapter | Install adapter: npx astro add cloudflare (or vercel, netlify, node) | | MDX components not rendering | Custom components not passed to MDX content | Pass components via or use astro.config.mjs MDX config | | Content collection schema changes not reflected | Type generation is cached, stale .astro types | Run astro sync to regenerate types, restart dev server | | client:* on Astro components | Client directives only work on framework components (React, Vue, Svelte) | Astro components are static-only; extract interactive parts to a framework component | | document / window is not defined | Server-side code cannot access browser globals | Guard with if (typeof window !== 'undefined') or move to client:only | | Styles leaking between components | Using global CSS instead of scoped styles | Use (scoped by default in .astro) or intentionally | | View Transitions break scripts | DOMContentLoaded only fires once with View Transitions | Use astro:page-load event instead, which fires on every navigation | | Env vars missing in production | .env not loaded or platform env vars not configured | Use envField` in astro.config.mjs for validation; set vars in platform dashboard |
Production Security Checklist
For every production deployment, address:
- CSP headers - configure a restrictive
Content-Security-Policy(see middleware patterns inreferences/deployment.md) - Remote image restrictions - enforce explicit
image.domains/remotePatternsallow-lists; never derive image URLs from user input (SSRF risk) - Host header validation - verify the request host matches expected domains in middleware (SSR/hybrid only)
- Secrets management - on Cloudflare, use Workers Bindings (
wrangler secret put), not env vars baked into code; elsewhere use platform secret stores - HTTPS only - ensure all external resources (scripts, images, fonts) load over HTTPS
- Input validation - sanitize all user input in SSR contexts (query params, form bodies, cookies)
Reference Files
| File | Contents | Lines | |------|----------|-------| | references/content-collections.md | Schema patterns, Zod types, querying, MDX, content layer API, migrations | ~500 | | references/islands-rendering.md | Islands deep dive, client directives, framework integration, server islands | ~550 | | references/deployment.md | Cloudflare/Vercel/Netlify/Node adapters, env vars, optimization | ~500 |
See Also
- typescript-ops - TypeScript patterns used throughout Astro projects
- tailwind-ops - Tailwind CSS integration with Astro (
@astrojs/tailwind) - javascript-ops - Core JS patterns for client-side island code
- container-orchestration - Docker patterns for self-hosted Astro (Node adapter)
- Astro Documentation
- Astro Integration Guide
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: 0xDarkMatter
- Source: 0xDarkMatter/claude-mods
- License: MIT
- Homepage: https://github.com/0xDarkMatter/claude-mods#readme
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.