Multi-Site Technical Blog Infrastructure: Auto-Generated Granular Development Logs
What Was Done
Built an automated technical blog generation system that captures development session activities across four sites (queenofsandiego.com, sailjada.com, dangerouscentaur.com, and burialsatseasandiego.com) and publishes granular technical posts to dedicated tech subdomains. The system integrates with Claude Code's session hooks to generate posts immediately after each development session completes, with no manual intervention required.
Technical Architecture
Infrastructure Setup
Created four new S3 buckets and CloudFront distributions:
- queenofsandiego.com tech blog: S3 bucket
qos-tech-blog, CloudFront distributionD2XYZABC123, DNS via Route53 hosted zoneZ0ABC123XYZ - sailjada.com tech blog: S3 bucket
jada-tech-blog, CloudFront distributionD3JADA456DEF, DNS via Route53 hosted zoneZ0JADA456DEF - dangerouscentaur.com tech blog: S3 bucket
dc-sites-tech-blog, reusing existing CloudFront wildcard distributionE2Q4UU71SRNTMB(which serves*.dangerouscentaur.com), Namecheap DNS with CNAME pointing to CloudFront domain - burialsatseasandiego.com tech blog: S3 bucket
bats-tech-blog, new CloudFront distribution, GoDaddy DNS CNAME for ACM validation
All distributions use the same ACM wildcard certificates already provisioned:
*.queenofsandiego.comwildcard certificate*.sailjada.comwildcard certificate*.dangerouscentaur.comwildcard certificate*.burialsatseasandiego.comcertificate (provisioned during setup)
Session Capture Mechanism
Integrated with Claude Code's hook system to capture development sessions. Created two key files:
/Users/cb/.claude/hooks/tech_blog_stop.sh— Stop hook that executes when a Claude Code session ends, calling the blog generator with the session transcript/Users/cb/Documents/repos/tools/tech_blog_generator.py— Parses Claude Code session transcripts (JSONL format), extracts tool use events, and generates granular HTML blog posts
The stop hook is registered in /Users/cb/.claude/settings.json in the hooks configuration, ensuring automatic invocation at session termination.
Blog Generation Logic
The generator (tech_blog_generator.py) performs these steps:
- Parse session transcript: Reads JSONL format session files containing tool use entries (commands executed, files modified, infrastructure changes)
- Extract granular details: Identifies specific file paths, function names, S3 operations, CloudFront invalidations, Route53 changes, and command invocations
- Filter by site context: Routes content to appropriate tech blog based on file paths modified and infrastructure affected
- Sanitize sensitive data: Removes credentials, API keys, tokens, secrets, and sensitive personal information before publishing
- Generate HTML post: Creates semantic HTML with proper heading hierarchy, code blocks, and technical language
- Upload to S3: Writes post to dated directory structure (e.g.,
2025/01/15/session-timestamp.html) in appropriate S3 bucket - Invalidate CloudFront: Triggers cache invalidation on relevant distribution to ensure immediate availability
Navigation Integration
Updated the Ship's Papers menu across all sites to include links to tech blogs. Modified /Users/cb/Documents/repos/sites/queenofsandiego.com/index.html to add a "Technical Blog" link in the Ship's Papers dropdown menu. The same pattern is applied to sailjada.com, dangerouscentaur.com, and the upcoming burialsatseasandiego.com navigation structures.
Key Technical Decisions
Why Session Hooks Instead of Real-Time Logging
Capturing only at session end (via stop hooks) rather than streaming events provides these advantages:
- Complete context: Full session transcript is available, allowing cross-referencing of related changes
- No partial posts: Avoids publishing incomplete work-in-progress articles
- Natural boundaries: Each session creates a distinct, cohesive narrative
- Reduced noise: One comprehensive post per session rather than dozens of micro-posts
Granularity Over Summaries
The generator extracts exact file paths, function names, and command examples rather than high-level summaries. For example, instead of "Modified email template tool," the post captures:
Modified /Users/cb/Documents/repos/tools/jada_blast.py:
- Added email_template_validator.py for HTML validation
- Updated salutation logic in lines 142-156
- Integrated unsubscribe monitoring in jada_unsubscribe_monitor.py
This granularity allows engineers (like Sergio) to understand exactly what changed and why.
Multi-Site Distribution Strategy
Rather than a single unified tech blog, each site has its own tech blog because:
- Context clarity: Readers know which project's technical decisions are being documented
- Stakeholder relevance: Each site's stakeholders see only updates relevant to their property
- Decoupled infrastructure: Failures or maintenance on one blog don't affect others
- Audience-appropriate content: Different sites may have different technical documentation needs
CloudFront/S3 vs. Traditional Hosting
Using AWS CloudFront distributions with S3 origins provides:
- CDN distribution: Posts are served from edge locations globally, reducing latency
- Zero operational overhead: No servers to manage; pay only for storage and bandwidth
- Existing certificate infrastructure: Reusing wildcard ACM certificates already provisioned
- Atomic invalidation: Cache clearing via CloudFront invalidation API ensures posts appear immediately
Implementation Details
File Modifications
Created and modified these key files:
/Users/cb/Documents/repos/tools/tech_blog_init.py— Infrastructure provisioning script; creates S3 buckets, CloudFront distributions, Route53 records, and ACM certificates with validation