```html

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 to tech.queenofsandiego.com
  • Modifications to /Users/cb/Documents/repos/tools/jada_*.py → post published to tech.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 on index.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.com and sailjada.com) or third-party DNS (GoDaddy for burialsatseasandiego.com, Namecheap for dangerouscentaur.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.com and sailjada.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 on dc-sites S3 bucket

Certificate Validation

ACM certificate validation follows DNS validation pattern. For burialsatseasandiego.com, the script:

  1. Requests wildcard certificate for *.burialsatseasandiego.com
  2. Extracts DNS validation CNAME record (e.g., _xyz123.burialsatseasandiego.com_abc456.acm-validations.aws.com)
  3. Adds CNAME via GoDaddy API
  4. 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:

  1. Waits for the session transcript to be written to disk (checks for file existence and size stability)
  2. Invokes tech_blog_generator.py with the session ID and transcript path
  3. Generator parses transcript, determines affected domains, renders HTML
  4. Uses boto3 to upload HTML to appropriate S3 bucket(s)
  5. Invokes CloudFront cache invalidation on distribution(s) to ensure immediate visibility
  6. 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

Heuristic-Based Domain Routing