---
name: astro
description: Manage the Astro static site that powers clawdie.si. Use when building pages, configuring Strapi integration, deploying to nginx webroot, or managing the frontend project. Triggers on "astro", "frontend", "build site", "static site", "clawdie.si build".
---

# Astro

Use this skill for the static site generator that builds clawdie.si from Strapi content.

## Scope

This skill covers:

- Astro project setup and configuration
- Strapi content integration (REST API)
- Page and layout creation
- Build and deployment to nginx webroot
- Design system porting from current static HTML
- Skill page generation from SKILL.md files
- Build automation and webhooks

This skill does not replace:

- `strapi` for content management
- `nginx` for web server configuration
- `nginx-glasspane` for the ai.clawdie.si operator surface

## Architecture

```
cms jail (192.168.100.3)
  ├── Astro project at /home/clawdie/clawdie-site/
  │     ├── fetches from Strapi API (localhost:1337)
  │     └── reads SKILL.md files via nullfs mount
  │
  ├── Strapi at /home/clawdie/strapi/
  │     └── connects to PostgreSQL in db jail (192.168.100.2:5432)
  │
  └── build output → synced to host /usr/local/www/clawdie/ → nginx
```

Astro and Strapi run together in the `cms` jail. Astro pulls content from two sources:
1. **Strapi REST API** (localhost:1337, same jail) — pages, guides, blog posts
2. **SKILL.md files** via nullfs mount from host — skill documentation (build-time)

Output is pure static HTML/CSS/JS. No server-side rendering needed.

## Canonical paths

- Astro project: `/home/clawdie/clawdie-site/` (inside cms jail)
- Build output: `/home/clawdie/clawdie-site/dist/` (inside cms jail)
- Deploy target: `/usr/local/www/clawdie/` (host, via nullfs mount or rsync)
- Strapi endpoint: `http://localhost:1337/api` (same jail)
- SKILL.md source: `/mnt/skills/` (nullfs mount of host `.agent/skills/`)
- Memory budget: 1 GB shared with Strapi (see `freebsd-admin/references/memory-budget.md`)
- Build Node.js limit: `NODE_OPTIONS="--max-old-space-size=512"`

## Design system

Port the existing clawdie.si visual identity:

### Fonts
- Headings: `Cormorant Garamond` (300, 400, 600 weights)
- Monospace: `DM Mono` (300, 400 weights)

### Colors (dark theme)
```css
--cream: #0d1117;        /* page background */
--amber: #00b4d8;        /* accent / links */
--amber-dark: #0096b7;   /* hover states */
--charcoal: #e2e8f0;     /* headings */
--grey: #8b949e;         /* secondary text */
--grey-light: #21262d;   /* borders / dividers */
--paper: #161b22;        /* card backgrounds */
--ink: #c9d1d9;          /* body text */
```

### Components to port
- Hero statement block (dark background, accent text)
- Status note (left border, label)
- Comparison grid (two-column, cloud vs clawdie)
- Ecosystem cards (grid, featured variant)
- Principle rows (numbered, icon + text)
- CTA block (centered, button row)
- Divider (gradient line)
- Top nav (monospace, uppercase)

## Workflow

### Phase 1: Project setup

1. Read `references/setup.md`
2. Create Astro project with Strapi integration
3. Port design system CSS
4. Create base layout matching current site

### Phase 2: Page templates

Create Astro page templates:

| Template | Source | Route |
| --- | --- | --- |
| `pages/index.astro` | Strapi: Page (home) | `/` |
| `pages/docs/index.astro` | Strapi: Page (docs) | `/docs/` |
| `pages/guides/[slug].astro` | Strapi: Guide collection | `/guides/{slug}` |
| `pages/skills/[slug].astro` | Local SKILL.md files | `/skills/{slug}` |
| `pages/skills/index.astro` | Generated from skills list | `/skills/` |
| `pages/blog/[slug].astro` | Strapi: BlogPost collection | `/blog/{slug}` |

### Phase 3: Skill page generation

Skills are imported at build time from the local filesystem:

```astro
// src/pages/skills/[slug].astro
import { getCollection } from 'astro:content';

// Read .agent/skills/*/SKILL.md files
// Parse YAML frontmatter for metadata
// Render markdown body as HTML
```

This keeps skills in sync with code — no manual CMS updates needed.

### Phase 4: Build and deploy

```sh
cd /home/clawdie/clawdie-site

# build
npm run build

# deploy — sync to nginx webroot
rsync -av --delete dist/ /usr/local/www/clawdie/
```

### Phase 5: Automation

Build triggers (choose one):

**Option A: Strapi webhook**
- Strapi fires webhook on content publish
- Host script receives webhook and runs build
- Best for content-driven updates

**Option B: Cron rebuild**
- `cron` runs `astro build && rsync` every 15 minutes
- Simple, no webhook infrastructure needed
- Good enough for low-frequency updates

**Option C: Manual build**
- Operator or agent runs `npm run build` when needed
- Simplest, full control

Recommended: Start with Option C, move to B, then A as needed.

## Safe defaults

- Always ZFS snapshot before deploying a new build
- Keep the previous build in `/usr/local/www/clawdie.bak/` as fallback
- Test build locally before deploying: `npm run preview`
- Never delete the Astro project source — only the `dist/` output is expendable
- Run `nginx -t` after any nginx config changes (not needed for content-only updates)

## Build commands

```sh
cd /home/clawdie/clawdie-site

# development server (hot reload)
npm run dev

# production build
npm run build

# preview production build locally
npm run preview

# deploy to webroot
npm run deploy   # custom script: build + rsync
```

## Troubleshooting

### Build fails with Strapi fetch error

- Check Strapi is running: `curl -s http://192.168.100.2:1337/api`
- Check network: can host reach jail IP?
- Check API permissions in Strapi admin
- Astro can build with fallback content if Strapi is down (graceful degradation)

### Styles look wrong after build

- Check CSS variables are ported correctly
- Compare with current `/usr/local/www/clawdie/index.html`
- Check Google Fonts imports in layout

### Skill pages missing or stale

- Skills are read at build time from `.agent/skills/*/SKILL.md`
- Rebuild to pick up new or updated skills
- Check file path pattern matches in Astro config

### Deploy doesn't update site

- Static files served immediately by nginx — hard refresh browser
- Check rsync output for errors
- Verify files landed in `/usr/local/www/clawdie/`
- Check file permissions: `ls -la /usr/local/www/clawdie/`
