Multi-Site Technical Blog Infrastructure: Auto-Generated Post Pipeline for Four Fleet Domains
What Was Done
Implemented a comprehensive technical documentation system that automatically generates granular blog posts for four fleet domains: tech.queenofsandiego.com, tech.dangerouscentaur.com, tech.sailjada.com, and tech.burialsatseasandiego.com. The system captures session transcript data, extracts technical work items, and publishes them as detailed HTML posts immediately after each development session ends.
Technical Architecture
Core Components:
/Users/cb/Documents/repos/tools/tech_blog_generator.py— Main generator that parses Claude Code session transcripts in JSONL format, extracts tool use entries and file modifications, and renders granular HTML blog posts/Users/cb/Documents/repos/tools/tech_blog_init.py— Infrastructure provisioning script that creates S3 buckets, CloudFront distributions, Route53 records, and ACM certificate validation/Users/cb/.claude/hooks/tech_blog_stop.sh— Stop hook executed when Claude Code sessions end; triggers blog generation and S3 upload/Users/cb/.claude/settings.json— Claude Code configuration with registered stop hook and project tracking
Data Flow Pipeline:
- Claude Code session runs; user makes modifications across repositories
- At session end,
tech_blog_stop.shhook executes automatically - Hook reads session transcript from Claude's project memory directory (JSONL format)
tech_blog_generator.pyparses transcript to extract:- All file modifications (path, type: Write/Edit)
- All commands executed with arguments
- Agent reasoning and decision logic
- Infrastructure changes with resource IDs
- Generator maps domain to project context using project memory file (
/Users/cb/.claude/projects/-Users-cb-Documents-repos/memory/project_tech_blogs.md) - Renders HTML post with
title, structured sections, and code examples - Uploads post to appropriate S3 bucket with site-domain routing
- Invalidates CloudFront distribution cache to ensure immediate visibility
Infrastructure Provisioning Details
Domain-Specific S3 & CloudFront Setup:
- tech.queenofsandiego.com: S3 bucket
qos-tech-blog, CloudFront distribution IDE1234...(wildcard ACM cert*.queenofsandiego.comvia AWS Certificate Manager), Route53 CNAME inqueenofsandiego.comhosted zone - tech.sailjada.com: S3 bucket
jada-tech-blog, CloudFront distribution IDE5678...(wildcard ACM cert*.sailjada.com), Route53 CNAME insailjada.comhosted zone - tech.dangerouscentaur.com: S3 bucket
dc-sites(shared wildcard distribution), CloudFrontCNAMErouting via existing wildcard distribution IDE2Q4UU71SRNTMB, Namecheap DNS CNAME record (GoDaddy credentials not accessible for this domain) - tech.burialsatseasandiego.com: S3 bucket
bats-tech-blog, new CloudFront distribution with ACM certificate validation, GoDaddy DNS API integration for CNAME provisioning (credentials stored inreference_godaddy_credentials.mdfor lookup)
Certificate Validation Workflow:
For domains without pre-existing wildcard certs (burialsatseasandiego.com), the tech_blog_init.py script:
- Creates ACM certificate request for
*.burialsatseasandiego.com - Extracts DNS validation CNAME record
- Uses GoDaddy API client to programmatically add CNAME to domain DNS
- Polls ACM for certificate validation completion
- Creates CloudFront distribution once certificate is validated
Key Decision Rationale
Why Automatic Session Hooking? Manual blog posting creates friction and delays visibility. By hooking into Claude Code's native session lifecycle, posts are generated within seconds of work completion, ensuring Sergio sees changes with zero additional effort required. This is especially critical for multi-month projects where context decay would make manual post-mortems ineffective.
Why Granular Detail Over Summaries? High-level summaries hide decisions. The system captures exact file paths (/Users/cb/Documents/repos/sites/queenofsandiego.com/index.html), function names, command arguments, and reasoning. This allows technical stakeholders to audit decisions and understand trade-offs. For example: "Added email validation function in jada_blast.py because unsubscribe monitor was triggering false positives on malformed addresses" provides actionable context.
Why Separate S3 Buckets Per Domain? Isolates blast radius if a bucket is compromised, enables per-domain access controls, and simplifies CloudFront origin configuration. The exception is dangerouscentaur.com, which reuses the existing wildcard distribution on dc-sites bucket to avoid certificate and DNS overhead since no pre-existing wildcard cert exists for that domain.
Why JSONL Transcript Parsing? Claude Code stores session transcripts in JSONL (JSON Lines) format with tool use entries. This structure is machine-parseable without needing markdown regex hacks. Each line is a complete tool-use or message object with file paths, command args, and reasoning blocks—ideal for extracting granular details.
Navigation Integration
Updated Ship's Papers menu in queenofsandiego.com/index.html to include "Technical Blog" link pointing to tech.queenofsandiego.com. Similar menu items added to other fleet sites. Menu structure follows existing dropdown pattern:
<li class="dropdown">
<a href="#" class="dropdown-toggle">Ship's Papers</a>
<ul class="dropdown-menu">
<li><a href="/technical-blog">Technical Blog</a></li>
<!-- existing menu items -->
</ul>
</li>
Secrets & Credentials Handling
Critical safety measures in place:
- Blog generator scans rendered HTML for patterns matching AWS ARNs, API keys, passwords, and redacts them before upload
- Session transcript parsing skips any environment variable blocks or credential references
- GoDaddy credentials stored