For three weeks, my AI agent followed the most important rule in its prompt: never contact a customer without logging it first. Then one Tuesday I found an unlogged reply in my outbox — sent at 4:47 PM, in the middle of a long support triage session, in a tone so normal that I almost scrolled past it.
The agent hadn't gone rogue. It hadn't been prompt-injected. It had simply... forgotten. Not dramatically. Quietly. The way you forget a house rule after the fourth hour of a board game.
This is a post about context window pressure — the most common failure mode in agent ops, the hardest one to notice, and the one that took me an embarrassingly long time to diagnose because the symptoms looked like everything except a prompt problem.
The setup
I run a small support-and-ops agent on a Raspberry Pi. It triages incoming emails, drafts replies for my approval, updates a customer CRM, and logs everything it touches. The system prompt was about 2,400 tokens: role, tone, twelve hard rules (logging, escalation thresholds, "never promise refunds," etc.), and a pile of accumulated edge-case instructions I'd bolted on over months.
For short sessions it was flawless. The failures only showed up in long sessions — the kind where a support backlog piles up and the agent runs 40, 60, 90 turns without a restart.
What the autopsy actually showed
My first theory was model flakiness. My second was a bad prompt edit that I'd since reverted. Both wrong.
I dumped the full request payloads from the failing sessions and compared them to a healthy short session. The difference was obvious once I looked:
- In the short session, the system prompt was ~15% of total context.
- In the 4:47 PM session, the system prompt was under 4% of the context. The rest was 90+ turns of email threads, tool outputs, CRM dumps, and my own mid-session instructions.
Two things were working against me:
Lost in the middle. Models attend most reliably to the beginning and end of a context window. My twelve rules lived at the beginning — but by turn 70, "beginning" was 60,000 tokens ago, and the end was full of a noisy email thread about a shipping delay. The rules hadn't been deleted. They'd been buried.
Recency competition. My mid-session instructions ("handle this VIP first," "skip the survey emails today") were living in the same high-attention zone that the permanent rules deserved. The agent was weighting a throwaway 2 PM instruction roughly as heavily as a rule I'd written three months ago.
The unlogged reply wasn't malice. It was arithmetic. The logging rule lost the attention contest.
What I changed
1. Rule re-injection near the end
The single highest-leverage fix. Instead of trusting the system prompt to survive 90 turns, my orchestration code now appends a compact rules block to the last user-role message every N turns:
CRITICAL_RULES = (
"REMINDER — non-negotiable rules:\n"
"1. Log every customer contact to the outbox log BEFORE sending.\n"
"2. Never promise refunds or timelines.\n"
"3. Escalate anything mentioning legal, press, or churn.\n"
)
def maybe_reinject(messages, turn):
if turn % 15 == 0:
messages.append({"role": "user",
"content": CRITICAL_RULES + "\nContinue."})
return messages
Fifteen turns was empirical — shorter intervals burned tokens for no measurable gain, longer ones let drift creep back in. This one change eliminated the unlogged-send class of failure entirely in the six weeks since.
2. Aggressive history compaction
I stopped feeding raw tool output into history. CRM lookups, file reads, API responses — all get summarized to two or three lines before the next turn. A 900-token JSON blob becomes CRM: customer since 2023, plan=Pro, 2 open tickets. The agent doesn't need the blob; it needed the facts in it.
3. Session rotation with a handoff note
Every long-running session now ends deliberately instead of dying of context exhaustion. At turn ~60, the agent writes a structured handoff note (open threads, pending decisions, anything unusual), and a fresh session starts with just the system prompt + that note. Clean context, zero accumulated noise, and the handoff note is auditable — which matters more than I expected.
4. A post-hoc validator that doesn't trust the model
Belt and suspenders: a tiny script checks that every send in the outbox has a matching log entry. It doesn't use an LLM — it's about 20 lines of Python diffing two directories. When the model forgets a rule, the validator catches the consequence of the rule being forgotten.
# cron, every 10 minutes
diff <(ls ~/agent/outbox) <(ls ~/agent/logs/sends) && echo OK || notify-me
The honest failure part
I need to own how long this took. The unlogged reply was caught by luck, not by my systems — I happened to be cleaning out the outbox folder manually. If that email had contained a refund promise or a wrong shipping date, I'd have found out from an angry customer, not from my own monitoring.
Worse: after diagnosing it, my first fix was wrong. I doubled down on prompt engineering — rewrote the rules in ALL CAPS, moved the logging rule to position one, added "THIS IS CRITICAL" emphasis. It made no measurable difference, and I burned two days convincing myself it had. The problem was never the wording of the rules. It was their position in a 60k-token context. Shouting louder at someone who can't hear you doesn't help.
And one more: the re-injection snippet above is the version that works. The version I shipped first injected rules as a system-role message mid-conversation, which some providers deduplicate or deprioritize. It ran for four days doing nothing before I noticed the payloads in my logs didn't contain it at all. Test your fixes against the actual API payloads, not against your mental model of them.
What I'd tell myself three months ago
- Prompt length is not prompt strength. Twelve rules in 2,400 tokens is worse than four rules in 400 tokens re-injected every fifteen turns. Attention is a budget; spend it deliberately.
- Long sessions are a liability, not a feature. Anything that runs 60+ turns without a reset will drift. Plan the reset instead of discovering the drift.
- Validate consequences, not intentions. Don't ask the model "did you follow the rules?" — check the filesystem, the database, the outbox. Dumb deterministic checks beat smart probabilistic ones for guardrails.
- Keep your prompts modular. The compaction template, the re-injection block, the handoff-note format — these are small, reusable prompt artifacts. Mine live in a git repo now, versioned like code (after a different disaster involving an "improved" prompt that silently broke three days of work — that's another post).
The agent still runs on the same Pi, with the same model. The only thing that changed is how I manage the context around it. Six weeks, zero unlogged sends, and the handoff notes have become genuinely useful documentation of what the agent is doing — a side benefit I didn't plan for.
If you're running agents in production, grep your last week of API payloads and count what fraction of the context is your rules versus your noise. If the answer embarrasses you, it did me too.
All 100 prompts are in The Agent Prompt Vault — $3, lifetime updates. Steal the ones that fit your workflow.
Top comments (0)