All case studies

Case study 03

Running agents in production — the platform story

Anyone can demo an agent. The hard part is the boring part: keeping it alive, safe, and honest for weeks without a human watching. This is how the estate actually runs — and what I set up for clients.

Docker ComposeCaddyIAM rolesOAuth refreshwatchdogbackups

Topology

InternetHTTPS · real domainCaddy TLS ingressone VMdocker compose up -d --buildCost RCA servicerestart · healthcheckIncident RCA servicerestart · healthcheckEC2 IAM roleread-only · IMDS hop 2Watchdog + backups15-min cron · git-bundle

Two agent services in one Docker Compose stack behind Caddy TLS ingress on a real domain, on a single cloud VM. Restart policies, health endpoints, a shared network. One docker compose up -d --build deploys everything.

Identity & secrets

No static cloud keys anywhere — the EC2 IAM role is read via instance metadata, including the non-obvious container fix: IMDS hop limit 2. LLM access is via OAuth kept alive by a 4-hourly refresh job, with credentials mounted read-only into the containers. Slack webhooks are verified by HMAC with a replay window.

Self-monitoring

A watchdog cron runs every 15 minutes with a zero-noise contract:

prints NOTHING and exits 0 when everything is healthyfrom my runbooks

When something breaks, it posts the failure — plus the exact fix command — to Slack.

Backups that restore

Daily git-bundle backups of all agent code and runbooks. The restore path is actually verified, not assumed:

restore verification
$ git clone agents-2026-07-05.bundle restore-check
Cloning into 'restore-check'...
Receiving objects: 100% (483/483), done.
# 483 files recovered intact

Change control

Live code is mirrored into a PR-protected GitHub repo via git subtrees, with a full docs suite — architecture, operations, troubleshooting, regression testing. A written hardening review opens with a line worth quoting:

All changes verified with real tool output — nothing here is aspirational.from the hardening review

Honest failure handling

Timeouts tuned from real incidents

Timeout tuning is documented as a changelog with the incidents that motivated each bump — 180s → 300s → 500s — rather than a magic number nobody can explain.

Backoff and captured surprises

Exponential backoff on rate limits; and every operational surprise — container env traps, Python-in-Docker mount gotchas, Slack's single-consumer event queues — captured in the runbook library so it's never debugged twice.

Outcome

[[5–13 day]]
observed unattended stretches
483
files restored, verified
0
static cloud keys

Weeks of unattended operation. [[UPTIME/DURATION METRIC — source material says 5–13 day observed uninterrupted stretches; confirm current figure]]

[[SCREENSHOT: watchdog Slack message / compose ps output]]

Want this for your on-call?

The first call is a technical conversation. Bring an alert channel you hate.