Orchestrating Multi-Site CI/CD Deployments with Daemon Health Monitoring and OAuth Token Lifecycle Management
Over the past development session, we executed a complex multi-site deployment pipeline while simultaneously diagnosing and remediating daemon health issues on our Lightsail orchestrator instance. This post details the architectural decisions, infrastructure changes, and tooling patterns we implemented to maintain reliable service deployments across multiple domains.
What Was Done
- Created and iterated on authentication tooling for Google Analytics Data API integration
- Deployed new content and fixed templating bugs across three separate sites (86from.com, sailjada.com, queenofsandiego.com)
- Diagnosed and verified daemon health on the jada-agent orchestrator (34.239.233.28) via AWS Lightsail API and SSH
- Identified a broken OAuth token in the port_sheet_sync routine affecting scheduled sync operations
- Implemented versioning and cache invalidation patterns for CloudFront distributions
Authentication and Tooling: GA Data API Integration
We created /Users/cb/Documents/repos/tools/auth_ga.py to handle Google Analytics 4 authentication and data retrieval. The tool manages OAuth credential reuse—specifically leveraging existing dangerouscentaur@gmail.com credentials (client_id and client_secret pairs) to avoid redundant authentication flows.
Why this approach: Rather than storing separate OAuth tokens for each analytics property, we store one validated credential set and use it to enumerate all accessible GA4 accounts and properties. This reduces credential sprawl and simplifies rotation procedures.
The tool queries the Google Analytics Admin API to list all properties under the authenticated account, then pulls 7-day reporting windows for specific domains. We ran this against 86dfrom.com (later renamed to 86from.com) to validate traffic patterns and user engagement metrics.
Key technical decision: We verified that the google-auth-oauthlib library was available in the environment before attempting authentication, and we locked down the secrets file with restrictive permissions to prevent accidental exposure.
Multi-Site Deployment Pipeline
86from.com Restructuring and SEO Content
We renamed the project directory from 86dfrom.com to 86from.com to match the actual domain. The site structure lives at /Users/cb/Documents/repos/sites/86from.com/site/.
Key changes:
- Updated
index.htmlwith navigation and structural improvements - Created new SEO-focused page at
/Users/cb/Documents/repos/sites/86from.com/site/what-does-86d-meanto capture long-tail search intent - Deployed to S3 with CloudFront cache invalidation to ensure immediate content availability
Why: SEO content expansion targets informational queries about "86d" terminology, improving organic discoverability while maintaining the site's primary booking functionality.
sailjada.com Index Refinement
We performed extensive iteration on /Users/cb/Documents/repos/sites/sailjada.com/index.html—16 edits across the session as we refined layout, responsive behavior, and booking widget integration.
The booking widget integration required careful template syntax handling. Double-brace syntax ({{ }}) is ambiguous in JavaScript context, so we conducted a thorough audit:
grep -r "{{" /Users/cb/Documents/repos/sites/sailjada.com/
After confirming that double-brace occurrences only appeared within the booking widget section (a Vue.js or similar framework component), we replaced internal occurrences with single-brace syntax to prevent template collision during HTML generation. This required extracting the ~1500-character JavaScript block, syntax-validating it independently, and redeploying to staging before production push.
Deployment pattern: We used a staging S3 bucket separate from production, invalidated the staging CloudFront distribution first to validate rendering, then promoted to production distribution.
queenofsandiego.com Booking Automation
We edited /Users/cb/Documents/repos/sites/queenofsandiego.com/BookingAutomation.gs twice during this session. This is a Google Apps Script file, indicating that booking automation logic is managed via Google Sheets integration.
Why Apps Script: Allows non-deployed logic (Google Sheets formulas, triggers, and custom functions) to orchestrate booking workflows without requiring backend infrastructure changes or new deployments. The script is versioned in Git alongside site source, enabling collaborative review and rollback capability.
Daemon Health Diagnostics and Infrastructure
The jada-agent orchestrator daemon runs on a Lightsail instance at 34.239.233.28. We performed a comprehensive health check via AWS Lightsail API since the SSH private key (jada-key) was not stored locally.
Access Pattern: Lightsail API + Temporary Credentials
Rather than struggle with missing SSH keys, we used the AWS Lightsail GetInstanceAccessDetails API to obtain temporary SSH credentials, avoiding the need to manage static key pairs:
aws lightsail get-instance-access-details \
--instance-name jada-agent \
--region us-east-1
This returned a temporary private key and default username, valid for a limited window. After use, we immediately removed the temporary key file from the local filesystem.
Daemon Health Findings
- Service Status:
jada-agent.serviceis active and running with 3 days uptime (since May 10) - Resource Utilization: CPU 0.65% average, Memory 144MB / 914MB, Disk 6.2GB / 39GB—all nominal
- Session Activity (May 13): 3 of 5 daily sessions consumed; 2 hit the 30-turn Claude conversation limit (exit code 1), 1 completed successfully and created a needs-you task for blocking issues
- Status Checks: 0 failures in the last 2 hours; Lightsail health checks passing
Key observation: Max-turn exits are not daemon crashes—they're expected behavior when complex tasks exceed the conversation turn budget. Session 2 (which completed normally) did meaningful work, creating blocking-issue escalation tasks. The pattern suggests task complexity is appropriate but may occasionally require split execution.
Critical Issue: OAuth Token Lifecycle Failure
We discovered that the port_sheet_sync.py script's Google OAuth token is broken:
[port-sheet] token error: HTTP Error 400: Bad Request
Every 30-minute sync attempt has failed since at least this afternoon. The token is expired or revoked, preventing synced data from flowing into the port sheet.
Remediation required: Re-authenticate the Google OAuth flow for port_sheet_sync.py, similar to the pattern used in auth_ga.py. The script needs a fresh token or refresh token rotation before the next scheduled sync window.
Key Architecture Decisions
- Credential Reuse: Storing a single validated GA credential set and