Around the middle of a long work session, I rewrote the shared rulebook that my agent fleet runs on — and about half of them never found out.
Here’s the setup, plainly: I run a coordinator agent that hands work to roughly nine long-lived worker agents, each a separate Claude session. They all share what I call doctrine — the principles, hard rules, and skill definitions that tell them how to reply, when to escalate a problem up to me, and how to classify their own work. Think of it as the employee handbook every agent carries a copy of. Mid-session I refactored one of the core skills and added four new principles to that handbook.
Then I kept working. And the fleet quietly split into two personalities.
The workers I’d already interacted with kept behaving on the old doctrine. The ones I triggered fresh, after the edit, used the new one. Same fleet, same coordinator, two different sets of rules running side by side — and nothing crashed, nothing errored, so I didn’t notice for a while. It only surfaced when I told the coordinator, almost offhand, “check in with all the agents again,” and their answers suddenly disagreed with each other in a way they shouldn’t have.
The mistake was assuming an in-place edit is a live update. It isn’t. An agent that’s mid-session doesn’t re-read its handbook until its next trigger — the same way your browser keeps serving an old page until something tells it the cached copy is stale. I’d changed the file on disk. I hadn’t changed what was in each agent’s head.
The fix is to treat a load-bearing config change like a cache-invalidation event. The moment I land one, I fan out a re-sync to every currently-active agent instead of waiting for them to bump into the change organically. Push, don’t hope.
But blasting all nine on every trivial edit is its own kind of noise — and it burns session budget I’d rather spend on actual work. So I gate it with one cheap question: would this agent behave differently on its next reply under the new rules? If yes, sync it, customized to what that specific agent is in the middle of. If no — I fixed a typo, reworded a comment — leave it alone.
Fanning out a gated re-sync to live agent sessions give me the detail
Each worker is a resumable Claude Code session (claude --resume <id>) living in its own tmux window. When the coordinator lands a doctrine change, it doesn’t broadcast blindly — it runs the gate per agent first:
for id in $(active_agent_ids); do
# cheap classifier: does the diff touch rules THIS agent acts on?
affects=$(gate_check --agent "$id" --diff doctrine.diff)
if [ "$affects" = "yes" ]; then
tmux send-keys -t "$id" \
"Doctrine updated. Re-read skill X; new principles 5-8 apply. Your open task: $(task_for $id)" Enter
fi
doneThe gate_check is a one-shot prompt asking whether the diff changes this agent’s next action given its current task — a few cents versus re-briefing the whole fleet. The customization matters: a generic “re-sync now” makes each agent re-derive its own context; handing it the delta plus its live task means one clean turn instead of three confused ones.
The general principle: any time long-lived agents share a prompt, config, or rulebook, editing the source is not the same as updating the runtime. State lives in the running session, not the file. So when you change something load-bearing, push it — proactively, per-agent, and gated by whether it actually changes behavior. Otherwise you don’t have one fleet. You have two, and you won’t find out which is which until they contradict each other.