Six days in a row, my morning status check was green. publish OK. Every day, 09:30, right on schedule.
On day six I actually opened the blog. Nothing had gone out since day zero.
The launchd job had fired every morning. The Python script had exited 0 every morning. It had even written publish OK to the log — every morning. What it hadn't done was publish anything, because the publish step depended on a browser session that had quietly expired on day one. The script caught the auth error, logged a warning that scrolled off the top of the file, and exited 0 anyway — because the wrapper only checked "did the process run," never "did a post actually go live."
I had built an employee that clocks in, does nothing, and files a glowing self-review. And I had no idea, because I was reading its self-review instead of checking its work.
That week taught me the thing this whole post is about: when you run AI agents past one-off coding tasks, the hard part is not the agents. It's the management layer around them.
"12 agents" is not the problem anymore
You can find free packs of 100+ Claude Code subagents. Agents are commodities now. If your automation is failing, it is almost never because you're missing a code-reviewer.md or a researcher.md.
It's failing for boring management reasons:
- The agent reported success it didn't earn.
- Two agents fought over the same file.
- One agent invented a number and put it in a report you almost sent.
- A job died silently and nothing noticed for a week.
- You re-pasted the same context into every session because the agent had no memory.
None of that is an agent problem. It's a governance problem. Below are the five pieces I bolted on after the six-day incident, with the actual patterns. You can build all of this yourself — that's the point of writing it down.
1. Give every agent a charter, not a prompt
A prompt says what to do this once. A charter says what this role is allowed to be. It's the difference between a task and an employee. Mine are plain Markdown files that live next to the agent:
# Charter: publish-lead
Mandate: Publish 1 post/day to the blog queue.
Authority: May edit drafts in /drafts. May call the publish endpoint.
Boundaries: Never touches billing. Never publishes without a draft on disk.
Definition of done:
A live URL is returned AND written to
/published/YYYY-MM-DD.json
Escalate to human when:
- session auth is expired
- credit balance < threshold
- the same step fails twice in a row
Two lines here do all the work. Definition of done is an artifact on disk, not a feeling. Escalate when names the exact conditions the agent must not try to paper over. My six-day ghost happened precisely because "session auth expired" was a warning the agent swallowed instead of an escalation it raised.
2. Check the work live, never the log
This is the lesson that cost me the six days, so it gets the most space.
A log line is a claim the agent makes about itself. Treat it like one. The status check should look at reality instead:
# WRONG — trust the agent's self-report
tail -1 publish.log # "09:30 publish OK" ← this lied to me for a week
# RIGHT — verify three independent live signals
# 1) Did the real session file get touched today?
find ~/.sessions/publish.json -newermt "today" | grep -q . \
&& echo "session: fresh" || echo "session: STALE"
# 2) Did the source actually hit the publish endpoint today?
grep "$(date +%F)" access.log | grep -q "POST /articles" \
&& echo "endpoint: called" || echo "endpoint: NEVER CALLED"
# 3) Is there an artifact on disk dated today?
ls published/$(date +%F)*.json >/dev/null 2>&1 \
&& echo "artifact: exists" || echo "artifact: MISSING"
Rule I now enforce everywhere: a report is only allowed to say "done" if there is an artifact it can point to. "The job ran" and "the job worked" are different sentences, and your monitoring has to know the difference. If you only remember one thing from this post, make it this one.
3. Facts-only reporting: an empty field beats a confident guess
At some point an agent summarizing performance will want to write a number it doesn't actually have. Views, revenue, signups — whatever. It will produce a plausible one. That is the single most dangerous thing an agent can do, because a made-up number in a report is indistinguishable from a real one until it's too late.
The rule is absolute and it lives in the charter: any metric comes from a verified source or the field stays blank. No interpolation, no "roughly," no rounding a guess into a fact. A blank cell is honest. A hallucinated 1,240 views is a landmine you buried for future-you.
4. Memory has to be a file the agent re-reads
If you re-paste the same context into every session, you don't have memory — you have a chore. Persistent memory is just a durable index the agent reads at the start of every run and appends to at the end:
# MEMORY.md (agent reads this first, every session)
- [publish-pipeline] Naver session dies before Tistory session — regen
stats session first. (learned the hard way 07-06)
- [reporting] Money/metrics = verified source only. Never invent.
- [status] Judge automations live, not by last log line. (the six-day incident)
Each entry is a scar with a date. New sessions inherit the scars instead of re-earning them. This is the difference between an agent that gets better over weeks and one that repeats month-one mistakes forever.
5. Schedule with an escalation path, not just a cron line
The scheduling part is easy — launchd on macOS, cron on Linux:
<!-- ~/Library/LaunchAgents/com.me.publish.plist -->
<key>StartCalendarInterval</key>
<dict><key>Hour</key><integer>9</integer>
<key>Minute</key><integer>30</integer></dict>
<key>StandardErrorPath</key><string>/tmp/publish.err</string>
The part everyone skips: who gets told when it breaks. A scheduled job with no escalation channel is exactly how you get six silent days. Mine pings a Telegram bot the moment an agent hits one of its charter's "escalate when" conditions — expired auth, empty credits, a step that failed twice. The human (me) is a documented dependency of the system, not a person who happens to check in sometimes.
The lessons, condensed
The ones that cost me the most, in one screen:
- A process that exits 0 is not a task that got done.
- Trust artifacts, not logs. A report needs something to point at.
- Never let an agent invent a number. Blank > plausible.
- One template across every channel = zero results on every channel. Each surface gets its own strategy.
- Every agent needs an escalation path for the things only a human can fix — expired sessions, empty balances, a captcha.
- Memory is a file the agent re-reads, not context you re-paste.
- A charter (mandate + authority + boundaries + definition-of-done + escalation) turns a vague prompt into an accountable role.
If you want the shortcut
Everything above is enough to build your own management layer — genuinely, go do it, it's a good weekend.
If you'd rather not spend the week I spent getting scolded by my own status reports, I packaged it: the 12 subagents, the charter template, the facts-only reporting rules, the live-not-logs status-check recipes, the memory system, and the launchd/cron patterns — 21 files you drop into .claude/. It's a management layer for AI employees, not another agent pack.
It's on Gumroad for $19, and the price goes up $10 every time someone buys — the sale counter is public on the page, so it is provably cheaper now than it will be later. That's the only scarcity here; there's no fake countdown. → https://bluelove3.gumroad.com/l/ai-employee-company
Either way: go check your automations against reality today, not against their logs. Mine looked perfect right up until it wasn't.
What's the longest one of your jobs has been silently broken before you noticed? I'll go first — six days. Beat that in the comments.
Top comments (0)