- Framework: Astro 5.x (SSG)
- Styling: Tailwind CSS 3.x + One Dark Pro theme
- Language: TypeScript (strict mode)
- Content: Markdown with Astro Content Collections
- Icons: Lucide (@lucide/astro, local)
- Fonts: Inter + JetBrains Mono (@fontsource, local)
npm run dev # Dev server at localhost:4321
npm run build # Build to ./dist/
npm run preview # Preview production build
npm run astro -- check # Type check content + TSNo lint/test framework - verify changes via npm run build or npm run astro -- check.
- There is no test runner or lint script. Use
npm run astro -- checkfor type/content validation. - For component-level changes, run
npm run buildto validate SSG output.
---
// 1. External imports
import { getCollection } from 'astro:content';
import { IconName } from '@lucide/astro';
// 2. Internal imports
import BaseLayout from '../layouts/BaseLayout.astro';
import { formatDate } from '../utils/date';
// 3. Props interface (always define)
interface Props {
title: string;
optional?: boolean;
}
// 4. Destructure with defaults
const { title, optional = false } = Astro.props;
// 5. Logic
const data = await getCollection('til');
---
<BaseLayout title={title}>
<slot />
</BaseLayout>export type Category = 'AI/ML' | 'DevOps' | 'Systems' | 'Web' | 'Infra';
export function functionName(param: ParamType): ReturnType {
// Implementation
}
const map: Record<Category, string> = { ... };- Order: external → internal → local assets
- One blank line between groups
- Use relative paths for local modules; no absolute aliases
- Use single quotes in TS/Astro unless the file already uses double quotes
- 2 spaces for indentation, no tabs
- Keep JSX/Astro props in a single line unless it hurts readability
- Favor small, composable blocks over nested logic
- Prefer explicit return types for exported functions
- Avoid type assertions (
as) unless required by API contracts - Keep unions and enums in a shared util when reused
- Prefer safe fallbacks for content data (see category/icon helpers)
- Throw only when a failure is unrecoverable or should break the build
- Avoid silent failures; log in build-time only if necessary
| Type | Convention | Example |
|---|---|---|
| Components | PascalCase | Header.astro |
| Pages | kebab-case | [...slug].astro |
| Utilities | camelCase | formatDate |
| CSS classes | kebab-case | bg-main |
| Types | PascalCase | Category |
---
title: "Article Title"
description: "Brief description"
pubDate: 2026-01-24
updatedDate: 2026-01-25 # optional
category: "AI/ML" # AI/ML | DevOps | Systems | Web | Infra
tags: ["tag1", "tag2"]
draft: false # optional
---- Use
class:listfor conditional classes - Use inline boolean render (
condition && <Component />) or.mapfor lists - Use
formatDate()for ISO andformatDateDisplay()for display - Avoid
getRelativeTime()for SSG (freezes at build)
- Schema is enforced in
src/content.config.ts - Use
z.coerce.date()for date fields - Keep
draftandtagsdefaults aligned with schema
- No External Requests - All assets local (GDPR)
- No Type Suppression - Never
@ts-ignoreoras any - TypeScript Strict - Uses
astro/tsconfigs/strict - SSG Only - Static generation at build time
- No
.cursor/rules,.cursorrules, or.github/copilot-instructions.mdfound in this repo.
npm run buildmust succeed- No TypeScript errors
- Imports correctly organized
- Update
astro.config.mjssite URL before deploy
- Edit existing components before creating new
- Prefer Tailwind utilities over custom CSS
- Follow frontmatter schema exactly
- Keep all assets local (fonts, icons, images)