How We Built This Publication With Claude Code and an Agentic Pipeline
This site is itself the project. Here’s exactly how it was built — infrastructure, design, and the agentic pipeline that will drive it going forward.
The Stack Decision
Static site on a VPS. No Vercel, no Netlify, no managed headless CMS. The reasons:
- Cost: $6/month DigitalOcean Basic droplet vs. paid tiers on managed platforms once you hit traffic
- Control: Nginx config, caching headers, full server access
- Agentic pipeline: an rsync deploy from a local build script fits naturally into an automated publish workflow
The framework choice was Astro. No JavaScript framework overhead for what is fundamentally a content-driven site. Tailwind CSS v4 with a custom navy/electric-blue theme defined in CSS custom properties.
Infrastructure Setup
The droplet runs Ubuntu 24.04 with a LEMP stack: Nginx 1.24, MySQL 8.0.46 (for the WordPress sites also on this server), PHP-FPM 8.3.
Server hardening was scripted in Python using pexpect — an SSH automation library that handles interactive prompts including key passphrases. The setup sequence:
- Deploy user created, root login disabled
- UFW firewall: ports 22, 80, 443 only
- fail2ban installed for SSH protection
- Nginx virtual hosts for all domains
- Certbot SSL certificates (4 certs issued)
- Uptime Kuma in Docker behind an Nginx reverse proxy
The pexpect approach over raw subprocess was the right call. Server setup involves interactive prompts — dpkg --configure, certbot --nginx, package installation confirmations. pexpect handles all of these without brittle shell heredocs.
The Design Process
The homepage went through three major iterations in a single session with Claude Code:
Version 1: Generic blog layout. Too sparse, too much whitespace, no personality.
Version 2: Card grid with topic-colored image placeholders on every card. Looked cluttered — too many colored boxes fighting for attention.
Version 3 (current): Dense magazine layout. Only the hero card has an image (topic gradient). Everything else is text-only with a strict hierarchy: hero → secondary stack → latest grid → sidebar → topic strips. The rule “images only where they add information” cleaned up the design immediately.
The design system lives entirely in src/styles/global.css as CSS custom properties under Tailwind v4’s @theme {} block. No tailwind.config.* file.
Claude Code as the Primary Tool
Every file in this repository was written with Claude Code. A few patterns that emerged:
CLAUDE.md is load-bearing. Rules about which card sizes should have images, which Tailwind classes encode the layout invariants, the 4-location requirement for adding a new topic — these live in CLAUDE.md. Without it, a new session starts cold.
The first:pt-0 trick. When medium cards in a grid column share py-4, the top card in each column has extra space above it. Adding first:pt-0 to the card class removes it. Small thing, looks much better.
Sidebar overflow. The original layout had Latest articles and the topic strips in separate grid containers, with the sidebar only alongside Latest. The sidebar was shorter than the topic strips below it, creating dead space. The fix: pull both Latest and topic strips into a single lg:col-span-3 column, keeping the sidebar in the same 4-column grid row throughout.
The Content Pipeline (In Progress)
The publishing workflow we’re building:
Prompt (topic + angle)
→ write_article.py (Claude API) → markdown with frontmatter
→ image_gen.py (Gemini 2.0 Flash) → PNG → Sharp → WebP
→ dropped into src/content/{section}/
→ npm run build
→ deploy.sh (rsync to droplet)
The writing agent uses Claude Sonnet with a voice guide in the system prompt: direct, technically credible, first-person plural where appropriate, H2 sections, 3–4 sentence paragraphs, concrete takeaway at the end.
Image generation uses Gemini 2.0 Flash. We already use it for the Stonks agent (stock chart analysis), so the API key is in place. The pipeline generates hero images at 1200×630 (OG dimensions), resizes to WebP via Sharp, and drops them in public/images/.
Claude Code skills (~/.claude/commands/) will wrap the full pipeline into /publish — a single command that takes a topic and angle and handles everything through to live.
What’s Next
Content collections and article templates are live. The writing and image generation scripts (write_article.py, image_gen.py) are the next build. After that: mjelitecontractors.com as a static Astro + Keystatic site, and Stonks Agent v2 as a proper Python + Claude API pipeline replacing the original n8n workflow.
All of it gets documented here as it ships.