Building Multi-Site Auto-Generated Technical Blog Infrastructure with Claude Hooks and S3/CloudFront
What Was Done
Implemented a comprehensive technical blogging system across four domains (queenofsandiego.com, sailjada.com, dangerouscentaur.com, burialsatseasandiego.com) that automatically generates granular technical posts from Claude development session transcripts. The system captures detailed work logs—file modifications, infrastructure changes, command execution—and publishes them immediately to dedicated tech subdomains without exposing credentials or sensitive data.
Architecture Overview
The solution consists of three primary components:
- Claude Code Stop Hook (
/Users/cb/.claude/hooks/tech_blog_stop.sh) — Executes at session end to trigger blog generation - Blog Generator (
/Users/cb/Documents/repos/tools/tech_blog_generator.py) — Parses JSONL session transcripts and generates HTML posts - Infrastructure Initializer (
/Users/cb/Documents/repos/tools/tech_blog_init.py) — Provisions S3 buckets, CloudFront distributions, and DNS records for each tech blog
Technical Implementation Details
Session Transcript Processing
Claude Code stores session transcripts in JSONL format at /Users/cb/.claude/projects/-Users-cb-Documents-repos/. Each line contains a timestamped event with type, content, and metadata. The blog generator:
- Reads the current session's JSONL transcript file
- Extracts
"type": "tool_use"entries for command execution - Parses file modification events (reads, writes, edits)
- Filters sensitive data: redacts API keys, passwords, credentials from output
- Generates chronological HTML post with exact file paths, bucket names, distribution IDs
- Uploads to appropriate S3 bucket and invalidates CloudFront cache
Example extraction: A file modification event contains the absolute path /Users/cb/Documents/repos/tools/tech_blog_generator.py with operation type "Write" and timestamp. This becomes a detailed line item in the post explaining what code was created and why.
Infrastructure Provisioning
The tech_blog_init.py script provisions identical infrastructure for each site:
- S3 Bucket:
qos-sites,jada-sites,dc-sites,bats-sites— hosts static HTML blog posts - CloudFront Distribution: Creates distribution for each bucket with origin access control (OAC) for security
- ACM Certificate: Uses existing wildcard certificates (
*.queenofsandiego.com,*.sailjada.com) or provisions new ones - DNS Records: Creates CNAME entries via appropriate DNS provider (Route53 for AWS-hosted zones, GoDaddy API for external domains)
For dangerouscentaur.com (external DNS at Namecheap), infrastructure reuses existing wildcard CloudFront distribution E2Q4UU71SRNTMB on dc-sites bucket, adding Namecheap CNAME pointing to CloudFront domain.
For burialsatseasandiego.com (GoDaddy DNS), the initializer:
- Reads GoDaddy API credentials from secure environment configuration
- Creates ACM certificate for
tech.burialsatseasandiego.com - Retrieves DNS validation CNAME record from ACM
- Adds validation record to GoDaddy DNS via API
- Waits for certificate validation
- Creates CloudFront distribution with validated certificate
Hook Integration with Claude Code
The Stop hook registered in /Users/cb/.claude/settings.json triggers on session completion. The hook script tech_blog_stop.sh:
#!/bin/bash
# Executes at end of Claude Code session
# Determines which site(s) were modified during session
# Invokes blog generator with current transcript
# Handles errors and logs to ~/.claude/logs/tech_blog.log
Hook detects which domains were modified by parsing file paths in the transcript. If modifications target queenofsandiego.com files, it generates posts for tech.queenofsandiego.com. Multiple domains in one session generate posts to all relevant tech blogs.
Navigation Integration
Updated queenofsandiego.com/index.html ship's papers menu to include "Tech Blog" link to tech.queenofsandiego.com. Similar updates pending for other main sites. Navigation structure uses consistent dropdown pattern for discoverability.
Credential Protection
Critical security measures implemented:
- Transcript parser includes blocklist of sensitive patterns (AWS keys, GoDaddy tokens, email credentials)
- Redaction function strips values matching patterns like
AKIA[0-9A-Z]{16}(AWS keys), email auth tokens - GoDaddy and other API credentials stored in
/Users/cb/.claude/projects/-Users-cb-Documents-repos/memory/reference_godaddy_credentials.md— file excluded from blog generation entirely - Blog post filenames use timestamps only; no domain names in paths to prevent information leakage
- S3 buckets configured with private ACLs; only CloudFront can serve content via OAC
Infrastructure Details by Domain
queenofsandiego.com: S3 bucket qos-sites, CloudFront distribution ID varies per run, uses Route53 hosted zone. Certificate: wildcard *.queenofsandiego.com pre-existing in ACM.
sailjada.com: S3 bucket jada-sites, CloudFront distribution, Route53 DNS. Uses wildcard certificate *.sailjada.com.
dangerouscentaur.com: Reuses CloudFront distribution E2Q4UU71SRNTMB (wildcard *.dangerouscentaur.com` pre-existing), adds tech.dangerouscentaur.com CNAME at Namecheap.
burialsatseasandiego.com: New ACM certificate, new CloudFront distribution, GoDaddy DNS integration via API for CNAME records.
Key Decision Rationale
Why S3 + CloudFront? Static HTML posts serve rapidly to any viewer without compute costs. CloudFront edge caching ensures sub-100ms delivery globally. OAC prevents direct S3 access, enforcing CloudFront routing.
Why Hook-Based Generation? Automatic post creation at session end captures context immediately. No