```html

Building Multi-Site Auto-Generated Technical Blog Infrastructure with Claude Code Hooks

This session focused on creating a fully automated technical blogging system across four domain properties: queenofsandiego.com, sailjada.com, dangerouscentaur.com, and burialsatseasandiego.com. The goal was to capture granular technical details from development sessions automatically and publish them to dedicated tech blogs without manual intervention.

What Was Done

We implemented an end-to-end system consisting of:

  • A Claude Code Stop hook that captures session transcripts when development work completes
  • A blog post generator that parses JSONL transcripts and transforms them into HTML articles
  • Infrastructure provisioning across AWS (S3, CloudFront, Route53) and DNS providers (Namecheap, GoDaddy)
  • Navigation menu integration into existing Ship's Papers sections on each domain
  • Real-time post publication triggered immediately upon session completion

Technical Architecture

The Hook System

We created /Users/cb/.claude/hooks/tech_blog_stop.sh, a Bash script executed by Claude Code when a session ends. The hook:

  • Reads the session transcript from $CLAUDE_SESSION_TRANSCRIPT_PATH (provided by Claude Code runtime)
  • Invokes tech_blog_generator.py with the transcript path and target domain
  • Routes the generated HTML to the appropriate S3 bucket and invalidates CloudFront cache
  • Logs execution details to /Users/cb/.claude/logs/tech_blog_hook.log for debugging

The hook is registered in /Users/cb/.claude/settings.json under hooks.on_session_stop, allowing it to run without user intervention.

Blog Generator (tech_blog_generator.py)

This Python script handles the core transformation logic:

  • Transcript Parsing: Reads JSONL-formatted Claude Code transcripts containing tool use entries, command outputs, and file operations
  • Content Extraction: Filters entries to exclude sensitive data (credentials, API keys, passwords) while preserving technical details
  • HTML Generation: Converts parsed data into semantic HTML with proper heading hierarchy (<h2>, <h3>), code blocks, and lists
  • AWS Integration: Uses boto3 to upload generated posts to S3 with appropriate path structure and CloudFront invalidation
  • Timestamping: Automatically generates post titles with ISO 8601 timestamps for chronological organization

The generator sanitizes file paths (replacing absolute paths with relative ones where appropriate) and formats commands in <pre><code> blocks for readability.

Infrastructure Initialization (tech_blog_init.py)

We created a comprehensive infrastructure setup script that:

  • S3 Buckets: Creates domain-specific buckets (qos-tech-blog, jada-tech-blog, dc-sites/tech-blog/, bats-tech-blog) with appropriate versioning and public read access policies
  • CloudFront Distributions: Provisions CDN distributions for tech.queenofsandiego.com, tech.sailjada.com, tech.dangerouscentaur.com with HTTP-to-HTTPS redirects
  • SSL/TLS Certificates: Validates existing wildcard certificates (*.queenofsandiego.com, *.sailjada.com) and provisions new ACM certificates where needed
  • DNS Configuration: Creates CNAME records at appropriate DNS providers:
    • Route53 for queenofsandiego.com and sailjada.com subdomains
    • Namecheap API for dangerouscentaur.com tech blog subdomain
    • GoDaddy API for burialsatseasandiego.com tech blog subdomain
  • Index Pages: Generates initial index.html with blog post listing capabilities

Key Infrastructure Decisions

DNS Provider Strategy

Rather than consolidating all domains under a single provider, we maintained each domain's existing DNS provider:

  • Route53: Used for queenofsandiego.com and sailjada.com (already AWS-native in Route53 hosted zones)
  • Namecheap: Used for dangerouscentaur.com via API integration
  • GoDaddy: Used for burialsatseasandiego.com via API integration

This approach avoided unnecessary DNS migrations and leveraged existing API credentials, reducing risk of propagation issues.

S3 Bucket Organization

For three domains we created dedicated S3 buckets (qos-tech-blog, jada-tech-blog, bats-tech-blog). For dangerouscentaur.com, which already had a wildcard CloudFront distribution pointing to the dc-sites S3 bucket, we created a /tech-blog/ prefix within that existing bucket. This preserved the existing infrastructure while avoiding bucket proliferation.

Certificate Strategy

We leveraged existing wildcard certificates for queenofsandiego.com and sailjada.com rather than provisioning individual certificates per subdomain. For domains without wildcards, we provisioned new ACM certificates and configured DNS validation via the appropriate provider's API.

Integration with Existing Sites

Navigation links were added to the Ship's Papers menu on each domain's index.html. This required:

  • Adding menu items that link to tech.{domain}.com
  • Maintaining consistency with existing navigation structure
  • Ensuring the tech blog links appear for users interested in infrastructure transparency

The menu updates were deployed via CloudFront invalidation to ensure immediate visibility.

Data Security & Sanitization

The blog generator implements strict filtering to prevent credential leakage:

  • Excludes environment variable expansions containing API keys
  • Redacts AWS credentials, database passwords, and authentication tokens
  • Removes sensitive file contents (e.g., credential references are replaced with [REDACTED])
  • Preserves file paths, function names, and technical architecture details

This allows complete transparency into technical implementation while maintaining security posture.

Operational Workflow

The system operates as follows:

  1. Developer works in a Claude Code session, making infrastructure changes or code modifications
  2. At session end, Claude Code runtime triggers the Stop hook automatically
  3. Hook script invokes tech_blog_generator.py with the session transcript
  4. Generator parses transcript, extracts technical details, and generates HTML
  5. HTML is uploaded to the appropriate S3 bucket (determined by session context)
  6. CloudFront cache is invalidated