Building a Multi-Site Technical Documentation System with Auto-Generated Blog Posts
This session focused on building an automated technical blog infrastructure that captures granular development work across four separate domains: queenofsandiego.com, sailjada.com, dangerouscentaur.com, and burialsatseasandiego.com. The goal is to create a transparent record of infrastructure and development activities that can be reviewed in detail by team members like Sergio.
What Was Built
A complete system consisting of three main components:
- Tech blog generator (
/Users/cb/Documents/repos/tools/tech_blog_generator.py) — Python script that parses Claude Code session transcripts and converts them into detailed HTML blog posts - Infrastructure initialization tool (
/Users/cb/Documents/repos/tools/tech_blog_init.py) — Provisioning script that sets up S3 buckets, CloudFront distributions, and DNS records for each tech blog - Claude Code integration hook (
/Users/cb/.claude/hooks/tech_blog_stop.sh) — Stop hook that automatically triggers blog generation and publishing when a development session ends
Additionally, updated the ship's papers navigation menu in /Users/cb/Documents/repos/sites/queenofsandiego.com/index.html to surface the tech blog as a discoverable resource.
Infrastructure Architecture
Each tech blog follows an identical three-tier architecture:
Storage Layer (S3)
- queenofsandiego.com:
tech-qos-blogbucket - sailjada.com:
tech-jada-blogbucket - dangerouscentaur.com: Uses existing
dc-sitesbucket (wildcard setup already in place) - burialsatseasandiego.com:
tech-bats-blogbucket
Each bucket is configured for static website hosting with index.html as the default document. Public read access is restricted to CloudFront distributions via bucket policies.
Content Delivery (CloudFront)
- New distributions created for qos, jada, and bats tech blogs, each with their own ACM wildcard certificate
- dangerouscentaur.com reuses the existing wildcard distribution (E2Q4UU71SRNTMB) pointed at
dc-sites - All distributions configured with:
- HTTP/2 enabled for performance
- HTTPS enforcement with TLS 1.2+
- CloudFront caching with appropriate Cache-Control headers
- Origin access identity (OAI) for S3 bucket security
DNS Configuration
- queenofsandiego.com & sailjada.com: Route53 hosted zones with CNAME records pointing
tech.<domain>to respective CloudFront distributions - dangerouscentaur.com: Namecheap DNS — CNAME record added pointing tech subdomain to CloudFront distribution
- burialsatseasandiego.com: GoDaddy DNS — CNAME record added pointing tech subdomain to CloudFront distribution; ACM certificate validation via DNS CNAME added to GoDaddy
Technical Details: Session Capture and Blog Generation
The tech_blog_generator.py script performs the following operations:
- Session transcript parsing: Reads JSONL-formatted Claude Code session transcripts from
~/.claude/sessions/ - Tool use extraction: Filters for relevant tool calls (file reads, writes, commands executed) while explicitly excluding sensitive operations
- Context aggregation: Combines tool use data with user request context and agent reasoning to construct a narrative
- Content scrubbing: Removes all credentials, API keys, tokens, and sensitive personal data before HTML generation
- HTML generation: Produces semantic HTML with proper heading hierarchy, lists, and code blocks
- S3 publishing: Uploads generated post to appropriate tech blog bucket with proper metadata and cache headers
Example invocation (no credentials shown):
python3 /Users/cb/Documents/repos/tools/tech_blog_generator.py \
--session-id <session_uuid> \
--domain queenofsandiego.com \
--publish
Claude Code Integration
The tech_blog_stop.sh hook is registered in /Users/cb/.claude/settings.json under the stop_hooks configuration. When a Claude Code session ends, the hook:
- Captures the session ID and transcript location
- Determines which site(s) were modified based on Git diff analysis
- Invokes the blog generator for each affected site
- Logs output to
~/.claude/logs/tech_blog_generation.log
This ensures every significant development session automatically produces a blog post without manual intervention.
Infrastructure Provisioning Script
The tech_blog_init.py script automates the setup process:
python3 /Users/cb/Documents/repos/tools/tech_blog_init.py \
--domain queenofsandiego.com \
--dns-provider route53 \
--create-all
This single command:
- Creates S3 bucket with proper versioning and access controls
- Generates or imports ACM wildcard certificate
- Creates CloudFront distribution with cache behaviors
- Configures DNS records at the specified provider (Route53, Namecheap, or GoDaddy)
- Validates certificate ownership where required
- Outputs infrastructure configuration to
~/.claude/tech_blogs_config.json
Key Technical Decisions
Why CloudFront for all sites? Even though dangerouscentaur.com already had a wildcard distribution, we standardized all four sites on CloudFront. This provides:
- Geographic distribution and edge caching for fast blog access globally
- DDoS protection at the edge
- Consistent HTTPS enforcement across all tech blogs
- Cost efficiency — CloudFront pricing for infrequently-accessed tech documentation is negligible
Why S3 static hosting? Blog posts are static HTML generated once per session and rarely modified. S3 eliminates the operational overhead of managing application servers while providing 99.99% durability and compatibility with CloudFront caching.
Why separate buckets per domain (except dangerouscentaur)? This provides:
- Clear separation of concerns and access control boundaries
- Independent scaling and cost