Building a Multi-Site Technical Blog Infrastructure with Auto-Generated Session Transcripts
What Was Done
Implemented a comprehensive technical blogging system across four domains (tech.queenofsandiego.com, tech.sailjada.com, tech.dangerouscentaur.com, and tech.burialsatseasandiego.com) that automatically generates detailed, granular blog posts from Claude Code session transcripts. This system captures the "weeds" of development work—exact file paths, infrastructure changes, architectural decisions—making it possible to audit and review technical decisions with complete transparency.
Technical Details
Architecture Overview
The system consists of three primary components:
- Tech Blog Generator (
/Users/cb/Documents/repos/tools/tech_blog_generator.py): Parses Claude Code session transcripts in JSONL format, extracts meaningful technical work from tool use entries (file modifications, AWS commands, diagnostics), and generates HTML blog posts following a strict format with no credential leakage. - Infrastructure Initialization (
/Users/cb/Documents/repos/tools/tech_blog_init.py): Provisions S3 buckets, CloudFront distributions, and DNS records for each tech blog domain using the AWS CLI and domain-specific APIs. - Stop Hook (
/Users/cb/.claude/hooks/tech_blog_stop.sh): Triggered when a Claude Code session ends, automatically collecting the session transcript, running the generator, and deploying the resulting HTML post to the appropriate S3 bucket and invalidating CloudFront cache.
Session Transcript Processing
Claude Code sessions store transcripts in ~/.claude/projects/ with a JSONL format containing rich metadata about each interaction. The generator parses entries with "type": "tool_use", extracting:
- File modifications and creations with full paths (e.g.,
/Users/cb/Documents/repos/sites/queenofsandiego.com/index.html) - AWS CLI commands executed (S3 uploads, CloudFront invalidations, Route53 changes)
- Shell commands run with their purposes
- File content reads that inform decisions
The generator respects a strict sanitization layer: any environment variable references, credential patterns, API keys, or sensitive identifiers are stripped before rendering. The output focuses on what changed and why, making it safe for external review while maintaining technical depth.
Infrastructure Provisioning
The init script handles four distinct domain configurations:
- queenofsandiego.com and sailjada.com: Both had existing wildcard SSL certificates (
*.queenofsandiego.comand*.sailjada.com) in AWS ACM. The script created S3 buckets (qos-tech-blog,jada-tech-blog) and CloudFront distributions pointing to these origins, reusing the existing certificates. - dangerouscentaur.com: This domain uses a wildcard Namecheap DNS provider and has an existing CloudFront distribution (ID:
E2Q4UU71SRNTMB) pointing to thedc-sitesS3 bucket. The tech blog was configured as a path-based distribution, using CNAME routing at Namecheap fortech.dangerouscentaur.com. - burialsatseasandiego.com: This domain uses GoDaddy DNS. The script provisioned an S3 bucket (
bats-tech-blog), created a new CloudFront distribution, and added the required DNS validation CNAME to GoDaddy's API, handling the validation workflow automatically.
Route53 was used for domains managed in AWS; external DNS providers (Namecheap, GoDaddy) were integrated via their respective APIs or manual DNS record updates.
Stop Hook Integration
The stop hook is registered in Claude Code settings (~/.claude/settings.json) under the hooks.session_stop key. When a session ends, the hook:
- Locates the session transcript file in the project's memory directory
- Determines the target domain by reading a configuration map (stored in
/Users/cb/.claude/projects/-Users-cb-Documents-repos/memory/project_tech_blogs.md) - Runs the blog generator against the transcript
- Uploads the generated HTML to the appropriate S3 bucket using a timestamped filename
- Invalidates the CloudFront distribution cache with path
/*to ensure immediate visibility - Logs success/failure to
~/.claude/logs/tech_blog_hook.log
Key Decisions
- JSONL Transcript Format: Claude Code stores sessions in JSONL (JSON Lines), allowing streaming parsing and easy extraction of discrete tool use events without loading entire transcripts into memory.
- HTML-First Output: Generated posts are plain HTML with semantic tags (
<h2>,<h3>,<ul>,<code>,<pre>) for direct browser rendering and SEO-friendly indexing. No templating engine overhead. - Sanitization at Generation Time: Rather than stripping secrets at upload, the generator redacts sensitive patterns during parsing. This prevents accidental commits of partial credentials to version control.
- Distributed DNS Strategy: Different domains use different providers (Route53, Namecheap, GoDaddy), so the init script abstracts provider-specific logic. This prevents lock-in while maintaining automation.
- Granular Audit Trail: Posts capture individual file edits, not sessions-level summaries. This allows drilling into specific decisions (e.g., "Why was Route53 chosen over Namecheap for burialsatseasandiego?") by reading the associated post.
Integration with Ship's Papers Navigation
The main site's navigation (/Users/cb/Documents/repos/sites/queenofsandiego.com/index.html) includes a "Ship's Papers" menu. A new dropdown entry, "Technical Blog," links to tech.queenofsandiego.com. This pattern is replicated across all four sites, making the tech blog discoverable without cluttering the main navigation.
What's Next
- Index Generation: Create an automated index page listing all posts by date, with full-text search capability.
- Credential Pattern Enhancement: Expand the sanitization regex to catch additional credential formats (AWS SigV4 signatures, JWT tokens, etc.).
- Cross-Domain Search: Implement a meta-blog aggregating posts from all four tech sites with filtering by domain.
- Validation Testing: Add CI/CD checks to ensure no credentials leak into generated posts before CloudFront deployment.
This infrastructure ensures that every technical decision—from infrastructure provisioning to file edits—is captured, auditable, and visible to stakeholders like Sergio without exposing sensitive credentials.
```