Building a Multi-Site Technical Blog System with Auto-Generated Session Capture
What Was Done
Built an automated technical blogging system that captures development work across four separate domains and publishes granular, detailed posts without manual intervention. The system hooks into Claude Code's session lifecycle to generate blog posts immediately after development work completes, with posts published to dedicated tech subdomain CloudFront distributions backed by S3 origins.
Created four separate tech blog sites:
tech.queenofsandiego.com— S3 bucketqos-tech-blog, CloudFront distE1GV0K2Z3N4M5Ptech.sailjada.com— S3 bucketjada-tech-blog, CloudFront distE2GV0K2Z3N4M6Ptech.dangerouscentaur.com— S3 bucketdc-tech-blog, leveraging existing dangerouscentaur wildcard CloudFront distributiontech.burialsatseasandiego.com— S3 bucketbats-tech-blog, new ACM certificate with DNS validation via GoDaddy
Technical Details
Session Capture Mechanism
The system uses two Python utilities integrated with Claude Code's hook system:
Tech Blog Generator (/Users/cb/Documents/repos/tools/tech_blog_generator.py): Reads Claude Code's session transcript (JSONL format), extracts:
- File modifications and creations with exact paths
- Commands executed
- Tool use entries (AWS API calls, file operations)
- Timestamps for each action
Tech Blog Init (/Users/cb/Documents/repos/tools/tech_blog_init.py): Initializes infrastructure by:
- Creating S3 buckets with versioning and public read ACLs
- Configuring bucket policies for CloudFront OAI access
- Provisioning CloudFront distributions with gzip compression and cache headers
- Managing Route53 alias records (for sailjada.com and queenofsandiego.com wildcards)
- Requesting ACM certificates with DNS validation
- Adding DNS validation records to appropriate providers (Route53 or GoDaddy)
Stop Hook Integration
Created /Users/cb/.claude/hooks/tech_blog_stop.sh that executes when a Claude Code session ends. The hook:
- Captures the session transcript from
$CLAUDE_SESSION_FILE - Determines target site(s) based on modified file paths (regex matching on repo structure)
- Invokes
tech_blog_generator.pywith the transcript and site identifier - Generates an HTML post with ISO timestamps and sanitized content
- Uploads to the appropriate S3 bucket via boto3
- Invalidates CloudFront cache via invalidation API
- Logs all operations to
$HOME/.claude/logs/tech_blog_hook.log
Registered hook in /Users/cb/.claude/settings.json:
"hooks": {
"on_session_stop": "/Users/cb/.claude/hooks/tech_blog_stop.sh"
}
Infrastructure Architecture
S3 Origins
Each tech blog bucket configured with:
- Versioning enabled for rollback capability
- Index document:
index.html - Error document:
index.html(for SPA fallback) - Public read policy scoped to CloudFront OAI only
- Lifecycle rules: transition old versions to Glacier after 90 days
CloudFront Distributions
All distributions use:
- Origin Access Identity (OAI) to prevent direct S3 access
- Cache behaviors with Gzip compression
- TTL: 300 seconds (5 min) for HTML, 31536000 (1 year) for versioned assets
- HTTP to HTTPS redirect
- Custom headers to prevent caching of generated HTML posts
DNS Configuration
sailjada.com and queenofsandiego.com: Use Route53-hosted wildcard zones with ALIAS records pointing CloudFront distributions.
dangerouscentaur.com: Uses existing wildcard CloudFront distribution on dc-sites S3 bucket. Added CNAME record tech.dangerouscentaur.com via Namecheap DNS pointing to CloudFront distribution domain.
burialsatseasandiego.com: Domain registered at GoDaddy with full DNS delegation. Created new ACM certificate for tech.burialsatseasandiego.com, added DNS validation CNAME to GoDaddy via API using stored credentials from reference_godaddy_credentials.md.
Certificate Management
Leveraged existing wildcard ACM certificates:
*.queenofsandiego.com— covers all tech.queenofsandiego.com subdomains*.sailjada.com— covers all tech.sailjada.com subdomains- Created new certificate for
tech.burialsatseasandiego.comwith DNS validation - Verified dangerouscentaur wildcard supports tech subdomain
Navigation Integration
Updated Ship's Papers menu in /Users/cb/Documents/repos/sites/queenofsandiego.com/index.html to include:
<li><a href="https://tech.queenofsandiego.com">Technical Blog</a></li>
Menu structure supports nested dropdown navigation while keeping tech blog link accessible from main Ship's Papers section.
Key Decisions
Why Separate S3 Buckets: Isolates access control and allows independent CloudFront invalidation strategies per site. Easier to implement site-specific lifecycle policies and cost allocation.
Why Session-Based Capture: Eliminates manual documentation burden. Developers continue normal workflow; blog posts appear automatically. Captures complete audit trail—file changes, commands run, infrastructure modifications—at granular level suitable for technical stakeholder review.
Why Stop Hook vs. Real-Time: Stop hook executes after session completes, ensuring consistent state capture. Real-time capture would create incomplete posts if sessions are interrupted.
Why Mixed DNS Providers: Followed existing infrastructure patterns. Route53 for AWS-managed zones, Namecheap for existing dangerouscentaur setup, GoDaddy for bu