Building an Auto-Generating Technical Blog System Across Four Sailing Sites
This session focused on creating a comprehensive technical documentation system that automatically generates blog posts across four separate sailing and charter websites. The goal is to provide transparency into development work—specifically for stakeholders like Sergio—by capturing detailed, granular technical changes in real-time across queenofsandiego.com, dangerouscentaur.com, sailjada.com, and burialsatseasandiego.com.
What Was Done
Built a multi-site technical blog infrastructure with three core components:
- Blog Generator Script (
/Users/cb/Documents/repos/tools/tech_blog_generator.py): Parses Claude session transcripts in JSONL format, extracts tool use entries, filters out sensitive data, and generates HTML blog posts - Infrastructure Initialization Script (
/Users/cb/Documents/repos/tools/tech_blog_init.py): Provisions S3 buckets, CloudFront distributions, DNS records, and ACM certificates for each tech blog domain - Claude Code Stop Hook (
/Users/cb/.claude/hooks/tech_blog_stop.sh): Automatically triggers blog generation when a session ends, uploading posts to the appropriate site
Additionally, updated navigation menus on all four sites to include links to their respective tech blogs, accessible from the "Ship's Papers" menu for easy stakeholder access.
Technical Architecture
Session Transcript Processing Pipeline
The blog generator reads Claude session transcripts—stored as JSONL files in ~/.claude/projects—and extracts meaningful work data. The JSONL format contains structured entries like:
{"type": "tool_use", "id": "...", "name": "...", "input": {...}}
{"type": "tool_result", "id": "...", "content": "..."}
The script identifies work patterns: file modifications, command executions, infrastructure changes, and deployment operations. It filters output to remove any API keys, credentials, or sensitive data patterns (GoDaddy credentials, AWS access keys, etc.) before writing to the blog post.
Infrastructure per Tech Blog
Each tech blog follows this pattern:
- S3 Bucket: Named
tech-{site}-blog(e.g.,tech-queenofsandiego-blog). Stores HTML post files with structure/YYYY/MM/DD/post-slug.html - CloudFront Distribution: Points to the S3 bucket as origin with index.html fallback to enable pretty URLs
- DNS Records: Created via appropriate nameserver provider (Route53 for sailjada.com/queenofsandiego.com, Namecheap for dangerouscentaur.com, GoDaddy for burialsatseasandiego.com)
- ACM Certificates: Leveraged existing wildcard certs where available (
*.queenofsandiego.com,*.sailjada.com) or created new ones with DNS validation
Domain-Specific Handling
sailjada.com, queenofsandiego.com: Both have wildcard ACM certificates and Route53 hosted zones. The init script created CNAME records pointing to CloudFront distribution domain names in Route53.
dangerouscentaur.com: Uses existing wildcard CloudFront distribution (E2Q4UU71SRNTMB) pointing to dc-sites S3 bucket. Created a new S3 bucket for the tech blog with separate CloudFront distribution. Added CNAME via Namecheap DNS API pointing to the new distribution.
burialsatseasandiego.com: Registered at GoDaddy with manual DNS management. Created new S3 bucket and CloudFront distribution, then added ACM certificate with DNS validation CNAME record via GoDaddy API (using stored credentials from project memory).
Key Decisions
Why Session Transcripts Instead of Git Logs
Claude sessions capture intent and reasoning, not just code diffs. A git log shows "edited file X" but a session transcript explains "why did we edit file X, what command did we run, what was the output?" This granularity is crucial for stakeholder understanding.
Why Automatic Trigger on Session Stop
Manual blog posting would be forgotten or delayed. A bash hook in Claude Code's settings ensures every session automatically generates a post. The hook:
- Reads the session transcript from
~/.claude/sessions/{session_id}/transcript.jsonl - Runs the blog generator
- Uploads the resulting HTML to the site's S3 bucket
- Invalidates the CloudFront distribution to ensure fresh content
- Logs activity to
~/.claude/logs/tech_blog_hook.log
Why Filter Sensitive Data Aggressively
The generator uses regex patterns to scrub credentials before publishing. Patterns include:
aws_access_key_id.*?=.*?[\w/+=]{40,}(AWS credentials)Authorization.*?Bearer\s+[\w.-]+(API tokens)(?:password|passwd|pwd).*?[:=]\s*['"]?[^'"\s]+(Passwords)- GoDaddy API key patterns from stored reference memory
Infrastructure Changes Made
S3 Buckets Created:
tech-queenofsandiego-blogtech-sailjada-blogtech-dangerouscentaur-blogtech-burialsatseasandiego-blog
CloudFront Distributions Created: Four distributions, one per tech blog, with origin pointing to respective S3 bucket and custom domain names.
DNS Records Created:
- Route53:
tech.queenofsandiego.comCNAME to CloudFront distribution - Route53:
tech.sailjada.comCNAME to CloudFront distribution - Namecheap:
tech.dangerouscentaur.comCNAME to CloudFront distribution - GoDaddy:
tech.burialsatseasandiego.comCNAME to CloudFront distribution
Navigation Updates: Modified the "Ship's Papers" dropdown menu on all four sites to include a "Technical Blog" link pointing to the appropriate tech blog domain.
Configuration & Deployment
The init script creates an infrastructure config JSON file at ~/.claude/projects/memory/tech_blogs_infrastructure.json containing all bucket names, distribution IDs, hosted zone IDs, and domain details.