소스 정보
- 저장소
- theyoungastronauts/polaris
- 최근 소스 활동
- 2026년 7월 3일 23:05
- 감지된 SKILL.md 언어
- 영어
- 스타
- 4
- 포크
- 1
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/theyoungastronauts/polaris --skill astro-bootstrap명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SKILL.md 표시 중
SOC 직업 분류 기준
| name | astro-bootstrap |
| description | Scaffold an Astro project (Tailwind v4, DaisyUI, landing page). |
| disable-model-invocation | true |
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.
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 |
{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 enabled
{
"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"
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.
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()],
{
"extends": "astro/tsconfigs/strict",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}
PUBLIC_SITE_URL=https://{domain}
# astro
dist/
.astro/
# dependencies
node_modules/
# environment
.env*.local
# editor
.DS_Store
*.swp
# docker
docker-compose.override.yml
@import "tailwindcss";
@plugin "daisyui" {
themes: light, dark;
}
---
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" />}
---
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>
---
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>
---
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>
---
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>
---
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>
---
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>
User-agent: *
Allow: /
Sitemap: https://{domain}/sitemap-index.xml
<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>
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 };
---
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.
---
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>
---
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>
Only generate these files if the user opted into Agentation.
import { Agentation } from "agentation";
export default function AgentationOverlay() {
return <Agentation />;
}
{
"mcpServers": {
"agentation": {
"command": "npx",
"args": ["agentation-mcp", "server"]
}
}
}
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"]
name: {compose-project}
services:
site:
build:
context: .
dockerfile: Dockerfile.dev
volumes:
- .:/app
- /app/node_modules
ports:
- "{host_port}:4321"
env_file:
- .env
# {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
# ============================================================================
exec site npm install
exec site npm install
exec site npm run build
@:
Dockerfile.dev, docker-compose.yml, Makefile.env from template abovemake build && make uphttp://localhost:{host_port}make astro-check — should pass cleanly/blog.mcp.json exists