astro-bootstrap
Skill4 starsChanged 3 months agoMITView on GitHub
Scaffold an Astro project (Tailwind v4, DaisyUI, landing page).
- Reads credentials
- Installs packages
In this repository53 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- llms.txtllms.txt
- actionableSkill
- astro-patternsSkill
- autopilotSkill
- axon-code-intelSkill
- brainstormingSkill
- commit-conventionsSkill
- cross-repo-contextSkill
- django-bootstrapSkill
- django-patternsSkill
- executeSkill
- find-sessionSkill
- flutter-bootstrapSkill
- flutter-patternsSkill
- full-featureSkill
- intelSkill
- nextjs-bootstrapSkill
- nextjs-fullstack-bootstrapSkill
- nextjs-fullstack-patternsSkill
- nextjs-mui-bootstrapSkill
- nextjs-patternsSkill
- nextjs-shadcn-bootstrapSkill
- orchestratorSkill
- phase-breakdownSkill
- plan-and-scopeSkill
- prdSkill
- reactSkill
- recallSkill
- reflectSkill
- relaySkill
- rememberSkill
- scaffoldSkill
- scratchSkill
- tailwindSkill
- ux-specSkill
- ux-to-promptsSkill
- verify-astroSkill
- verify-djangoSkill
- verify-flutterSkill
- verify-nextjs-fullstackSkill
- verify-nextjs-muiSkill
- verify-nextjs-shadcnSkill
- verify-nextjsSkill
- verifySkill
- visual-feedbackSkill
- work-disciplineSkill
- worktreesSkill
- wrapSkill
- write-as-friendSkill
- write-as-humanSkill
- writing-clearlySkill
- writing-skillsSkill
The file
We split this skill into the rules it gives an agent
8 rules. About 0 are common, 3 are distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 17
Ask the user for these values:
- Distinctive: line 124
If Agentation enabled: Import and add the React integration:
- Very specific: line 242
If Agentation enabled: Add the import to the frontmatter and the overlay inside <body>, after <Footer />:
- Distinctive: line 539
Only generate these files if the user opted into Agentation.
- Very specific: line 693
Verify Docker files exist: Dockerfile.dev, docker-compose.yml, Makefile
- Very specific: line 696
Verify page loads at http://localhost:{host_port}
- Very specific: line 698
If content collections: verify blog index renders at /blog
- Very specific: line 699
If Agentation: verify overlay renders in dev mode, check .mcp.json exists
≈ “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
Astro Bootstrap
On-demand command for scaffolding a new Astro site with Docker, Tailwind CSS v4, DaisyUI, and landing page conventions.
MANDATORY: This project runs entirely in Docker. Every Docker file below (Dockerfile.dev, docker-compose.yml, Makefile) MUST be generated. The Makefile is the sole interface — never run
npmdirectly on the host.
Before You Start
Ask the user for these values:
| Placeholder | Description | Example |
{site-name} | Project/directory name | acme-landing |
{compose-project} | Docker Compose project name (kebab-case) | acme-landing |
{host_port} | Host port for Astro (default: 4321) | 4321 |
{domain} | Production domain | acme.com |
{site-title} | Display name for metadata | Acme Inc |
{site-description} | Default meta description | Build better widgets with Acme |
| Content collections | Include content collections setup? | Yes / No |
| Include Agentation? | Browser annotation tool for visual feedback | Yes / No |
Directory Structure
{site-name}/
├── src/
│ ├── pages/
│ │ ├── index.astro
│ │ └── 404.astro
│ ├── components/
│ │ ├── layout/
│ │ │ ├── Header.astro
│ │ │ └── Footer.astro
│ │ ├── landing/
│ │ │ └── Hero.astro
│ │ ├── ui/
│ │ │ └── Button.astro
│ │ └── dev/ # If Agentation enabled
│ │ └── AgentationOverlay.tsx
│ ├── layouts/
│ │ └── BaseLayout.astro
│ ├── styles/
│ │ └── global.css
│ ├── content/ # If content collections enabled
│ │ └── blog/
│ │ └── first-post.md
│ └── content.config.ts # If content collections enabled
├── public/
│ ├── favicon.svg
│ └── robots.txt
├── package.json
├── astro.config.mjs
├── tsconfig.json
├── .env
├── .gitignore
├── Dockerfile.dev
├── docker-compose.yml
├── Makefile
└── .mcp.json # If Agentation enabledFile Templates
package.json
{
"name": "{site-name}",
"type": "module",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "astro dev --host",
"build": "astro build",
"preview": "astro preview --host",
"check": "astro check"
},
"dependencies": {
"astro": "^5",
"@astrojs/sitemap": "^3"
},
"devDependencies": {
"typescript": "^5",
"tailwindcss": "^4",
"@tailwindcss/vite": "^4",
"daisyui": "^5"
}
}If content collections enabled: Also add "zod": "^3" to dependencies.
If Agentation enabled: Also add "@astrojs/react": "^4", "react": "^19", "react-dom": "^19" to dependencies and "agentation": "^0" to devDependencies.
astro.config.mjs
import { defineConfig } from 'astro/config';
import tailwindcss from '@tailwindcss/vite';
import sitemap from '@astrojs/sitemap';
export default defineConfig({
site: 'https://{domain}',
output: 'static',
integrations: [sitemap()],
vite: {
plugins: [tailwindcss()],
},
});If Agentation enabled: Import and add the React integration:
import react from '@astrojs/react';
// Add to integrations array:
integrations: [sitemap(), react()],tsconfig.json
{
"extends": "astro/tsconfigs/strict",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}.env
PUBLIC_SITE_URL=https://{domain}.gitignore
# astro
dist/
.astro/
# dependencies
node_modules/
# environment
.env*.local
# editor
.DS_Store
*.swp
# docker
docker-compose.override.ymlsrc/styles/global.css
@import "tailwindcss";
@plugin "daisyui" {
themes: light, dark;
}src/layouts/BaseLayout.astro
---
import { ViewTransitions } from 'astro:transitions';
import Header from '@/components/layout/Header.astro';
import Footer from '@/components/layout/Footer.astro';
import '@/styles/global.css';
interface Props {
title: string;
description?: string;
ogImage?: string;
}
const {
title,
description = '{site-description}',
ogImage = '/og.jpg',
} = Astro.props;
const canonicalURL = new URL(Astro.url.pathname, Astro.site);
---
<!doctype html>
<html lang="en" data-theme="dark">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<title>{title} | {site-title}</title>
<meta name="description" content={description} />
<link rel="canonical" href={canonicalURL} />
<meta property="og:type" content="website" />
<meta property="og:url" content={canonicalURL} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:image" content={new URL(ogImage, Astro.site)} />
<meta property="og:site_name" content="{site-title}" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content={description} />
<meta name="twitter:image" content={new URL(ogImage, Astro.site)} />
<ViewTransitions />
</head>
<body class="min-h-screen bg-base-100 text-base-content flex flex-col">
<Header />
<main class="flex-1">
<slot />
</main>
<Footer />
</body>
</html>If Agentation enabled: Add the import to the frontmatter and the overlay inside <body>, after <Footer />:
---
import AgentationOverlay from '@/components/dev/AgentationOverlay.tsx';
---
<!-- Add after <Footer />, before </body>: -->
{import.meta.env.DEV && <AgentationOverlay client:only="react" />}src/components/layout/Header.astro
---
const navItems = [
{ label: 'Home', href: '/' },
{ label: 'About', href: '/about' },
];
---
<header class="navbar bg-base-200 border-b border-base-300">
<div class="container mx-auto max-w-5xl">
<div class="flex-1">
<a href="/" class="text-xl font-bold text-primary">{site-title}</a>
</div>
<nav class="flex-none">
<ul class="menu menu-horizontal px-1">
{navItems.map((item) => (
<li><a href={item.href}>{item.label}</a></li>
))}
</ul>
</nav>
</div>
</header>src/components/layout/Footer.astro
---
const year = new Date().getFullYear();
---
<footer class="footer footer-center p-6 bg-base-200 text-base-content/70 border-t border-base-300">
<p>© {year} {site-title}. All rights reserved.</p>
</footer>src/components/landing/Hero.astro
---
interface Props {
title: string;
subtitle?: string;
ctaText?: string;
ctaHref?: string;
}
const {
title,
subtitle,
ctaText = 'Get Started',
ctaHref = '#features',
} = Astro.props;
---
<section class="hero min-h-[60vh] bg-base-200">
<div class="hero-content text-center">
<div class="max-w-2xl">
<h1 class="text-5xl font-bold">{title}</h1>
{subtitle && <p class="py-6 text-lg text-base-content/70">{subtitle}</p>}
<a href={ctaHref} class="btn btn-primary btn-lg">{ctaText}</a>
</div>
</div>
</section>src/components/ui/Button.astro
---
interface Props {
variant?: 'primary' | 'ghost' | 'outline';
size?: 'sm' | 'md' | 'lg';
href?: string;
}
const { variant = 'primary', size = 'md', href } = Astro.props;
const Tag = href ? 'a' : 'button';
const classes = `btn btn-${variant} btn-${size}`;
---
<Tag href={href} class={classes}>
<slot />
</Tag>src/pages/index.astro
---
import BaseLayout from '@/layouts/BaseLayout.astro';
import Hero from '@/components/landing/Hero.astro';
---
<BaseLayout title="Home" description="{site-description}">
<Hero
title="Welcome to {site-title}"
subtitle="{site-description}"
ctaText="Get Started"
ctaHref="#features"
/>
<section id="features" class="container mx-auto max-w-5xl px-4 py-16">
<h2 class="text-3xl font-bold text-center mb-12">Features</h2>
<div class="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
<div class="card bg-base-200 shadow-md">
<div class="card-body">
<h3 class="card-title">Feature One</h3>
<p class="text-base-content/70">Description of the first feature.</p>
</div>
</div>
<div class="card bg-base-200 shadow-md">
<div class="card-body">
<h3 class="card-title">Feature Two</h3>
<p class="text-base-content/70">Description of the second feature.</p>
</div>
</div>
<div class="card bg-base-200 shadow-md">
<div class="card-body">
<h3 class="card-title">Feature Three</h3>
<p class="text-base-content/70">Description of the third feature.</p>
</div>
</div>
</div>
</section>
<section class="bg-base-200 py-16">
<div class="container mx-auto max-w-5xl px-4 text-center">
<h2 class="text-3xl font-bold mb-4">Ready to get started?</h2>
<p class="text-base-content/70 mb-8 max-w-lg mx-auto">
Join thousands of users building with {site-title}.
</p>
<a href="/signup" class="btn btn-primary btn-lg">Sign Up Free</a>
</div>
</section>
</BaseLayout>src/pages/404.astro
---
import BaseLayout from '@/layouts/BaseLayout.astro';
---
<BaseLayout title="Page Not Found">
<div class="min-h-[60vh] flex flex-col items-center justify-center px-4">
<h1 class="text-6xl font-bold text-base-content/20 mb-4">404</h1>
<p class="text-xl mb-8">Page not found.</p>
<a href="/" class="btn btn-primary">Back to Home</a>
</div>
</BaseLayout>public/robots.txt
User-agent: *
Allow: /
Sitemap: https://{domain}/sitemap-index.xmlpublic/favicon.svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36" fill="none">
<rect width="36" height="36" rx="8" fill="#570DF8"/>
<text x="50%" y="55%" dominant-baseline="middle" text-anchor="middle" font-size="20" fill="white" font-family="system-ui">A</text>
</svg>Content Collections (if enabled)
src/content.config.ts
import { defineCollection, z } from 'astro:content';
const blog = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
description: z.string(),
pubDate: z.coerce.date(),
updatedDate: z.coerce.date().optional(),
heroImage: z.string().optional(),
draft: z.boolean().default(false),
}),
});
export const collections = { blog };src/content/blog/first-post.md
---
title: "First Post"
description: "Welcome to the blog."
pubDate: 2025-01-01
---
This is the first blog post. Edit or delete this file to get started.src/pages/blog/index.astro
---
import { getCollection } from 'astro:content';
import BaseLayout from '@/layouts/BaseLayout.astro';
const posts = (await getCollection('blog'))
.filter((post) => !post.data.draft)
.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
---
<BaseLayout title="Blog" description="Latest posts from {site-title}">
<div class="container mx-auto max-w-3xl px-4 py-16">
<h1 class="text-3xl font-bold mb-8">Blog</h1>
{posts.length === 0 ? (
<p class="text-base-content/70">No posts yet.</p>
) : (
<ul class="space-y-6">
{posts.map((post) => (
<li>
<a href={`/blog/${post.id}`} class="card bg-base-200 shadow-md hover:shadow-lg transition-shadow">
<div class="card-body">
<h2 class="card-title">{post.data.title}</h2>
<p class="text-base-content/70 text-sm">{post.data.description}</p>
<time class="text-xs text-base-content/50">
{post.data.pubDate.toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' })}
</time>
</div>
</a>
</li>
))}
</ul>
)}
</div>
</BaseLayout>src/pages/blog/[id].astro
---
import { getCollection, render } from 'astro:content';
import BaseLayout from '@/layouts/BaseLayout.astro';
export async function getStaticPaths() {
const posts = await getCollection('blog');
return posts.map((post) => ({
params: { id: post.id },
props: { post },
}));
}
const { post } = Astro.props;
const { Content } = await render(post);
---
<BaseLayout title={post.data.title} description={post.data.description}>
<article class="container mx-auto max-w-3xl px-4 py-16">
<header class="mb-8">
<h1 class="text-4xl font-bold mb-2">{post.data.title}</h1>
<time class="text-sm text-base-content/50">
{post.data.pubDate.toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' })}
</time>
</header>
<div class="prose prose-lg max-w-none">
<Content />
</div>
</article>
</BaseLayout>Agentation (if enabled)
Only generate these files if the user opted into Agentation.
src/components/dev/AgentationOverlay.tsx
import { Agentation } from "agentation";
export default function AgentationOverlay() {
return <Agentation />;
}.mcp.json
{
"mcpServers": {
"agentation": {
"command": "npx",
"args": ["agentation-mcp", "server"]
}
}
}Docker (REQUIRED — do not skip)
Dockerfile.dev
FROM node:22-alpine
WORKDIR /app
# Install dependencies first for layer caching
COPY package.json package-lock.json* ./
RUN npm install
# Copy application code
COPY . .
EXPOSE 4321
CMD ["npm", "run", "dev"]docker-compose.yml
name: {compose-project}
services:
site:
build:
context: .
dockerfile: Dockerfile.dev
volumes:
- .:/app
- /app/node_modules
ports:
- "{host_port}:4321"
env_file:
- .envMakefile
# {compose-project} - Makefile
PROJECT_NAME = {compose-project}
DOCKER_COMPOSE = docker compose --project-name $(PROJECT_NAME)
# ============================================================================
# Docker
# ============================================================================
.PHONY: build up down restart stop ps logs bash wipe
build:
$(DOCKER_COMPOSE) build
up:
$(DOCKER_COMPOSE) up --detach
down:
$(DOCKER_COMPOSE) down
restart: down up
stop:
$(DOCKER_COMPOSE) stop
ps:
$(DOCKER_COMPOSE) ps
logs:
$(DOCKER_COMPOSE) logs -f site
bash:
$(DOCKER_COMPOSE) exec site sh
wipe:
@echo "WARNING: This will delete all containers and volumes!"
@read -p "Are you sure? [y/N] " confirm && [ "$$confirm" = "y" ]
$(DOCKER_COMPOSE) down -v --remove-orphans
# ============================================================================
# Development
# ============================================================================
.PHONY: dev preview astro-check
dev: up logs
preview:
$(DOCKER_COMPOSE) exec site npm run preview
astro-check:
$(DOCKER_COMPOSE) exec site npm run check
# ============================================================================
# Dependencies
# ============================================================================
.PHONY: install add
install:
$(DOCKER_COMPOSE) exec site npm install
add:
$(DOCKER_COMPOSE) exec site npm install $(filter-out $@,$(MAKECMDGOALS))
# ============================================================================
# Build
# ============================================================================
.PHONY: build-site
build-site:
$(DOCKER_COMPOSE) exec site npm run build
# Catch-all for npm commands
%:
@:Post-Bootstrap Checklist
- Create project directory
- Generate all files from templates above (replace placeholders)
- Verify Docker files exist:
Dockerfile.dev,docker-compose.yml,Makefile - Copy
.envfrom template above make build && make up- Verify page loads at
http://localhost:{host_port} make astro-check— should pass cleanly- If content collections: verify blog index renders at
/blog - If Agentation: verify overlay renders in dev mode, check
.mcp.jsonexists - Commit initial scaffold
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.

