Sitemap
Thomas Pierrain. (υѕe caѕe drιven)

Thomas Pierrain. (υѕe caѕe drιven)

Change Agent (powered by software). Symmathecist & VP of Tech @Shodo . Organizer of #DDDFR meetup #lowLatency #XP #NFluent creatr @tpierrain.bsky.social

My agents run /clear on their own

--

TL;DR: what if your agent ran its own /clear? Not auto-compaction, which summarizes more or less at random. A real relay: it writes down what matters, empties its conversation and starts again fresh, without you. Forty lines of code, three traps avoided, and no need to sit in front of your screen for it.

A short follow-up to my series on context engineering: the diagnosis (long sessions produce bugs), the harness that makes /clear free, then the question of no longer having to type it. Here, the harness types it by itself.

Press enter or click to view image in full size

Don’t block for no reason

Right now, I am working on an agentic software factory. My guiding principle: humans should only have to step in on tasks that add value, and everyone should be as efficient as possible. Every manual intervention costs twice: the time to do it, and all the time the agent stays blocked, waiting for a human to unblock it.

For a few months now, I have been hunting these interventions one by one, to make them disappear. One stubborn one was left: the /clear. In a previous article, I explained how to make it free: the state of the work lives in a plan, not in the conversation, so you can empty the conversation and resume without losing anything. It works very well. But a human still has to think about it, type /clear, then “let’s resume”.

“What about auto-compaction?” It does avoid the intervention, but it does not give good results. It starts at the worst moment, when the agent is the most tired, sometimes in the middle of a task. Its summary is generic, and you do not choose what survives: a decision forgotten along the way comes back later as a bug. Reducing the window size (article in French) makes it start earlier, but then you just get it more often, and each run blocks the agent and costs one more call to the model.

So the choice was: stay in front of the screen to type /clear at the right moment, or let the agent degrade. I wanted neither.

Greg’s idea: a “relay” mod that types for you

I like to run my experiments at home, in the evening. Tonight, I tried an idea from Grégory, our QA lead, who is passionate about AI and further ahead on the subject than most people: use a Claude mod to trigger the /clear from outside the conversation, instead of waiting for a human to type it. What follows is my own experiment of the evening: a mod written from the official documentation, measured, and the traps I found along the way.

A mod is a plugin that contains TypeScript code run by Claude Code itself. It can listen to what happens (the end of an answer, for example) and do what you would do at the keyboard: read the size of the conversation, send a message, run a command… like /clear.

Get Thomas Pierrain. (υѕe caѕe drιven)’s stories in your inbox

Join Medium for free to get updates from this writer.

The relay takes four steps:

  1. at the end of each answer, the mod reads the size of the conversation;
  2. above the threshold, it asks Claude to update `state.md`: what is settled, what was tried and failed, and the next step;
  3. when that turn is over, it runs /clear;
  4. then it sends “let’s resume”, and the fresh conversation reads state.md again (one line in CLAUDE.md tells it to).

The mod fits in three files:

  • .claude-plugin/plugin.json: its name;
  • hooks/hooks.json: { "modules": ["./register.ts"] }, which tells Claude Code which code to load;
  • hooks/register.ts: the code, below.
import type { Register } from 'claude-code'

const MARGIN = 40_000 // relay once the conversation grew 40k tokens past its starting size
type State = { phase: 'armed' | 'writing' | 'clearing' | 'resumed'; base?: number; held?: string[] }

const HANDOVER =
'The conversation is getting long. Update state.md in ten lines at most: ' +
'what is settled, what was tried and failed, and the exact next step. ' +
'Then answer "state.md updated" and nothing else.'

export const register: Register = on => {
on('turn.complete', async ($, e, next) => {
const result = await next(e)
if (e.agentId) return result // main conversation only, not subagents
const key = `relay:${await $.session.root()}`
const s = ((await $.store.get(key)) as State | undefined) ?? { phase: 'armed' }
const tokens = (await $.session.usage()).context.tokens ?? 0

if (s.phase === 'writing') {
// state.md is written: clear, then resume, right after this hook returns
await $.store.set(key, { ...s, phase: 'clearing' })
$.clock.after(0, async () => {
await $.command.run({ command: 'clear' })
await $.store.set(key, { ...s, phase: 'resumed' })
await $.prompt.submit({ text: "let's resume", asUser: true })
})
} else if (s.phase === 'resumed' || s.base === undefined) {
// first turn of a conversation: measure its starting size, then send back what was held
await $.store.set(key, { phase: 'armed', base: tokens })
for (const text of s.held ?? []) $.clock.after(0, () => void $.prompt.submit({ text, asUser: true }))
} else if (s.phase === 'armed' && tokens >= s.base + MARGIN) {
await $.store.set(key, { ...s, phase: 'writing' })
$.clock.after(0, () => void $.prompt.submit({ text: HANDOVER }))
}
return result
})

// While the relay runs, hold what the person types, and send it again after the resume
on('prompt.submit', async ($, e, next) => {
if (e.origin.kind === 'plugin' || e.command) return next(e)
const key = `relay:${await $.session.root()}`
const s = ((await $.store.get(key)) as State | undefined) ?? { phase: 'armed' }
if (s.phase !== 'writing' && s.phase !== 'clearing') return next(e)
await $.store.set(key, { ...s, held: [...(s.held ?? []), e.text] })
return { drop: 'Relay in progress: your message will be sent again right after the resume.' }
})
}

To try it: claude --plugin-dir ./relay. And claude plugin validate ./relay tells you what the mod listens to and calls.

The three traps

  1. Don’t set the threshold too low, to avoid livelocks. Before the first message, a conversation already weighs a few tens of thousands of tokens, more depending on the plugins you have loaded, and even more in Claude Desktop. If your threshold for relaying to a new session is below this starting base, the conversation is still too big right after the /clear, and the answer to “let’s resume” immediately starts another relay, then another, then another… The mod then runs on its own, forever, and the work stops moving: that is a livelock (everyone is busy, nobody makes progress). This is why the mod measures the size at the first turn of each conversation, and adds a margin.
  2. Don’t run /clear from inside the hook. The documentation of $.command.run says so: the command is refused if it comes from a hook that the turn is waiting on. So the mod hands it to $.clock.after, to run once the hook is finished. This is not a bad Thread.Sleep that bets on a delay: the duration plays no role, it is just a way to get out of the hook. Claude Code guarantees the order, because it queues /clear and "let's resume" and only runs them when the session is idle.
  3. Let nothing through during the relay. A message typed while Claude writes state.md would go in just before the /clear, and its answer would be wiped out with the rest. So the mod also listens to prompt.submit: during the relay, it puts aside what the person types, shows "relay in progress", then sends it again, unchanged, once the fresh conversation has started. Nothing is lost.

What a good handoff note keeps

The prompt in the mod is short on purpose. But the whole relay depends on this note. Here are the rules that work:

  • One line per entry, as few words as possible. The note is read by a fresh agent, not by a human.
  • Keep what is still open: each goal not met yet, with its next step; the branch, and whether it is committed; each dead end, with what was tried and what happened; the human’s instructions that still apply.
  • Keep only what is verified. A claim that no run has confirmed goes on its own line, with the check that will settle it. Anything vague is removed.
  • Remove what is done: goals met, dead ends solved, claims verified, instructions that no longer apply.
  • Leave out what can be found elsewhere: reasoning, finished work, numbers, quotes, tips. The code, the plan and git already hold them.
  • Keep a question for the human only if no run can answer it.

Free, then automatic

It works, in Claude CLI as well as in Claude Desktop, including on a TEAM account. The first episode made /clear free. This one makes it automatic. One interruption less, and nobody will miss it.

This relay is only one piece of a bigger whole. My next article, the third and last of my series on the agentic software factory, will tell the story of this software factory itself: the factory in which this small mod is just one small part.

Going further

--

--

Thomas Pierrain. (υѕe caѕe drιven)
Thomas Pierrain. (υѕe caѕe drιven)

Change Agent (powered by software). Symmathecist & VP of Tech @Shodo . Organizer of #DDDFR meetup #lowLatency #XP #NFluent creatr @tpierrain.bsky.social