Building an Automated Technical Blog System Across Four Domains with Session-Based Post Generation
What Was Done
Implemented an end-to-end automated technical documentation system that captures development work across four separate domains—tech.queenofsandiego.com, tech.sailjada.com, tech.dangerouscentaur.com, and tech.burialsatseasandiego.com—and automatically generates granular technical blog posts immediately after each development session completes. The system integrates with Claude Code's session management to extract detailed session transcripts, parse tool usage and file modifications, and publish semantically rich HTML posts to the appropriate domain's CloudFront distribution.
Technical Architecture
Core Components
The system consists of three primary Python modules:
/Users/cb/Documents/repos/tools/tech_blog_init.py— Infrastructure provisioning script that creates S3 buckets, CloudFront distributions, Route53 DNS records, and ACM certificate validation for each tech blog domain/Users/cb/Documents/repos/tools/tech_blog_generator.py— Post generation engine that reads Claude Code session transcripts, extracts structured data about modifications and commands, and renders HTML articles/Users/cb/.claude/hooks/tech_blog_stop.sh— Stop hook executed by Claude Code when a session ends, triggering post generation and deployment
Session Data Capture
Claude Code maintains session metadata in JSONL format within /Users/cb/.claude/projects/-Users-cb-Documents-repos. Each session transcript contains:
- Tool use entries (with exact tool names, parameters, and outputs)
- File modification events (paths, operation type: write/edit, timestamps)
- Command execution records (exact shell commands run, output summaries)
The tech_blog_generator.py parses these JSONL transcripts to extract:
Files modified/created (with full paths)
Commands executed (command name and arguments)
Tool invocations (function names, parameters)
Temporal sequence of work
Post Generation Logic
The generator applies heuristics to determine which domain(s) a session targets based on file paths. For example:
- Modifications to
/Users/cb/Documents/repos/sites/queenofsandiego.com/→ post published totech.queenofsandiego.com - Modifications to
/Users/cb/Documents/repos/tools/jada_*.py→ post published totech.sailjada.com - Modifications to
/Users/cb/.claude/settings or infrastructure code → post published to all four domains (cross-cutting concerns)
Each generated post includes:
- Specific file paths and function names modified
- Exact S3 bucket names and CloudFront distribution IDs affected
- Why decisions were made (architectural rationale)
- Command examples (sanitized of credentials)
- Infrastructure resource names and configuration changes
Infrastructure Implementation
Domain-Specific Setup
For each domain, the init script provisions:
- S3 bucket: Named following pattern
tech-{domain}-blog(e.g.,tech-queenofsandiego-blog) in us-west-2 region, with public read access policy and static website hosting enabled onindex.html - CloudFront distribution: Origin pointing to S3 bucket, with ACM wildcard certificate for the parent domain (
*.queenofsandiego.com,*.sailjada.com, etc.), and cache invalidation support - DNS routing: Route53 (for
queenofsandiego.comandsailjada.com) or third-party DNS (GoDaddy forburialsatseasandiego.com, Namecheap fordangerouscentaur.com) - ACM certificates: Existing wildcard certs reused where available; new certificates requested and validated via DNS CNAME records
DNS Provider Differences
The system handles three different DNS providers:
- Route53:
queenofsandiego.comandsailjada.com` — A records created automatically via boto3 CloudFormation integration - GoDaddy:
burialsatseasandiego.com— CNAME record added via GoDaddy API (credentials stored in environment, never logged) - Namecheap:
dangerouscentaur.com— CNAME record added via Namecheap API or manual UI entry; domain points to wildcard CloudFront distribution ondc-sitesS3 bucket
Certificate Validation
ACM certificate validation follows DNS validation pattern. For burialsatseasandiego.com, the script:
- Requests wildcard certificate for
*.burialsatseasandiego.com - Extracts DNS validation CNAME record (e.g.,
_xyz123.burialsatseasandiego.com→_abc456.acm-validations.aws.com) - Adds CNAME via GoDaddy API
- Polls ACM until certificate status transitions to ISSUED
Stop Hook Integration
The tech_blog_stop.sh hook is registered in Claude Code settings at /Users/cb/.claude/settings.json under hooks.on_session_end. When a session terminates, the hook:
- Waits for the session transcript to be written to disk (checks for file existence and size stability)
- Invokes
tech_blog_generator.pywith the session ID and transcript path - Generator parses transcript, determines affected domains, renders HTML
- Uses boto3 to upload HTML to appropriate S3 bucket(s)
- Invokes CloudFront cache invalidation on distribution(s) to ensure immediate visibility
- Logs all operations to
/Users/cb/.claude/logs/tech_blog_generation.log
Key Design Decisions
JSONL Session Parsing Over API
Rather than querying Claude Code via REST API, the system directly reads JSONL transcript files. This decision prioritizes:
- Reliability: No dependency on API availability or rate limits
- Granularity: Access to full tool use and file modification details without filtering
- Latency: Immediate local file access vs. network round-trips