Making AI Agents Proactive: Rush Hour When I'm Here, Away Mode When I'm Not
In the previous post I described the org chart behind Klooboo: me, an AI head of product called Scout, a design director, sixteen game directors, builders that live for one job, and a marketing team. All of it meets me on one board, the desk.
The structure worked. The speed didn’t. On 2 November I wrote this to Scout:
“I feel like every reply is going to a queue that I need to push forward.”
I was right, and the numbers were worse than it felt. That morning 38 cards sat “with the team”, meaning I had answered and the agents hadn’t acted yet. Each answer of mine waited up to about 20 minutes before anything happened: a 10-minute timer to notice the reply, then a 10-minute quiet wait in case I was about to answer something else. Merges waited for my click. The team was proactive on paper and reactive in practice.
This post is what we changed.
The old loop, and why it was slow
The reply loop had been designed to be careful with usage:
- A scheduled check every 10 minutes looked for desk cards I’d answered.
- If it found one, it waited until I had been quiet for 10 minutes, so it could batch my answers into one run.
- It allowed a fixed number of reply runs per day, and none overnight.
- The run did the work and then, often, put a merge card back in front of me.
Every one of those rules made sense alone. Together they meant that the moment I was most available, sitting in front of the desk, clicking through cards, was the moment the team was guaranteed to be slowest. It waited for me to stop before it started.
The fix was to stop treating “Itay answered something” and “Itay is here” as the same signal.
Presence: is Itay actually around?
Presence comes from two timestamps. Either one counts:
- Typing in a Claude Code session. A
UserPromptSubmithook runs on every prompt I send and touches the presence file. - Clicking on the desk. Every reply, decision or Go live click lands in the desk’s event log, and presence reads the newest one.
If the timestamp is less than 45 minutes old, I’m present. Otherwise I’m away. The hook is a few lines (simplified here; the real one calls a small script):
{
"hooks": {
"UserPromptSubmit": [
{ "hooks": [{ "type": "command", "command": "touch \"$HOME/.team/present\"" }] }
]
}
}
That’s the whole sensor. It’s crude and it’s enough. The useful part is what the team does differently with it.
Rush hour: when I’m present
While I’m present, the reply loop drops almost every rule that made it wait (overnight quiet hours stay):
- A desk click starts the reply run at once. The desk server kicks the trigger directly when I answer, instead of waiting for the next 10-minute tick. After a run finishes, the trigger checks once more in case I answered something while it was working.
- No daily cap. The limit on reply runs per day does not apply while I’m here.
- No quiet wait. It doesn’t wait for me to stop clicking.
- Answers before code. If my reply asked a question, the run answers it on the card first, then builds. A two-line answer in a minute is worth more to me than a PR in twenty.
- Idle areas get a pitch. If nothing is waiting, the directors of up to two idle areas pitch something, at most once an hour. Being present should produce new options, not an empty board.
There is still a floor. A real reply takes one to three minutes: the agent starting, reading the card and its context, writing the answer. For anything faster than that, I talk to Scout directly in the session. That is the instant layer; the desk is the durable one.
Away mode: when I’m not
When I’ve been gone for 45 minutes, the team switches to finishing things.
Every 3 hours during the day, an “away” run works the approved queue, the work I’ve already said yes to, and pushes it toward live:
- fixes Lens (the design director) asked for after its review;
- my “Not yet” notes on Go live cards;
- cards I pressed ▶ Start on;
- PRs that went into conflict with main and need their branch brought up to date.
Each away run can start up to 4 builders. Green PRs behind an off feature flag get merged through the one narrow merge script the team is allowed to use (the next post is about that script and why it exists).
Away mode does not start new ideas on its own budget. Its job is to make sure that when I come back, the things I approved are closer to live than when I left, and the Go live list has new items on it for me to review.
Opening a session with decisions, not a blank prompt
The other half of “proactive” was the first minute of every session. I used to open a session and type what I wanted. That made me the source of every next step, which is exactly the bottleneck I was trying to remove. On 2 November I put it this way:
“I also want to open the session with suggestions that I can approve and stop being the bottleneck … the real challenge is to know on what to work and we as a team needs to see where this product is going by suggesting the next steps.”
Now every session opens the same way:
- A short brief. What shipped since I was last here, what’s live, what’s stuck and why. A few lines, not a report.
- My approvals, as multiple-choice questions. Each decision that needs me comes as a question with up to four options, and the team’s pick first, marked as recommended. Most of the time I take the recommendation. Each answer is applied through the desk, so the scheduled runs see it exactly as if I’d clicked the card.
- Three bets. Three suggestions for where the product should go next week, each with the player-facing words, why now, the first day’s step, and the number that would show it worked. A chosen bet becomes a project card. An unchosen one is dropped, not parked forever.
One thing stays out of the opening on purpose: Go live never happens in chat. I tried a batched “approve these Go live cards” question once and turned it down: “it’s better if I review them, they are open since I have comments I don’t want to go live with them yet.” A Go live card usually waits because I have notes, not because I’m slow. That review stays on the desk, with the frames in front of me.
Two buttons that skip the line
Two desk buttons exist for the cases the rules don’t cover:
- ▶ Start — “I want this one now.” It starts work on a card even when the day’s budget is used up. Without it, the only way to jump the queue was to ask in chat, which split the conversation again.
- ✅ Merge — for a PR the team flagged as risky (no flag on a player-visible change, a data migration, anything touching auth, money or the deploy pipeline). The team doesn’t merge those alone. One click from me, and the next run merges it.
The usage gate: two teams, one account
Faster runs have a cost: usage. Scout’s product team and Atlas’s marketing team run on the same account. On 1 November we had already used half the week’s allowance, and running out would stop both teams at once, not just the busy one.
So every scheduled job, from either team, passes through the same gate before it starts:
- A pause file. If it exists, nothing scheduled runs. One
touchstops everything; deleting it resumes. - A recent limit message. If any run hit a usage-limit message in the last 5 hours, scheduled jobs skip their turn instead of failing one after another.
- A minutes ledger. Each run writes how long it ran, so either team can see who used what this week. The agreed default is that scheduled jobs stay under about 70% of the week, leaving the rest for my live sessions, with product taking about 60% of that share and marketing about 40%. The ledger shows the split; it doesn’t enforce it yet.
# shape of the check every scheduled job runs first
[ -f "$PAUSE_FILE" ] && exit 0
recent_limit_message --within 5h && exit 0
# then: run the job, and log its minutes to the shared ledger
The split matters more than the total. Before the ledger, a busy day on the product side could use up the marketing team’s week without anyone noticing, let alone deciding it.
The numbers, honestly
Here is every merged pull request in the main repo from 20 October to 3 November, by day (UTC). These are PR counts, not features. One feature is often several PRs, and some PRs are a one-line fix or a docs change.
| Day | Merged PRs |
|---|---|
| Tue 20 Oct | 18 |
| Wed 21 Oct | 10 |
| Thu 22 Oct | 20 |
| Fri 23 Oct | 8 |
| Sat 24 Oct | 11 |
| Sun 25 Oct | 9 |
| Mon 26 Oct | 3 |
| Tue 27 Oct | 10 |
| Wed 28 Oct | 1 |
| Thu 29 Oct | 17 |
| Fri 30 Oct | 70 |
| Sat 31 Oct | 29 |
| Sun 1 Nov | 15 |
| Mon 2 Nov | 41 |
| Tue 3 Nov (so far) | 3 |
That’s 265 merged PRs in 15 days, and 44 on 2–3 November.
What I read in it:
- The first week and a half was me. Up to twenty merges a day and some days one or three, each waiting for my click.
- 29–30 October was the rule change. On 29 October I wrote down the four kinds of decision that are mine and let the team merge green flag-off work. On 30 October the morning team run was allowed six builders, and Scout started clearing a merge queue. Seventy merges in a day was mostly a backlog draining, not a new normal.
- 1 November was the usage scare. Budget mode cut the scheduled runs back, and merges dropped.
- 2 November was the two modes. Presence, rush hour, away mode and the merge script all went in that day, and the merges came back up.
A merge count is the easiest number to make go up, and not the one I care about. What I watch is whether work I approved reaches the Go live list, and whether the time between my answer and the team’s next step is now minutes instead of twenty.
What I’d take from it
- “The human answered” and “the human is here” are different signals. Treat them the same and the team is slowest exactly when you’re most available.
- Make presence cheap to detect. A hook on every prompt and a touch on every click was enough.
- When nobody’s watching, finish things. Away time is for moving approved work to done, not for starting new ideas.
- Open with decisions. A brief, multiple-choice approvals with the team’s pick first, and three bets. The team proposes; I choose.
- Keep an escape hatch both ways. ▶ Start to skip the budget, ✅ Merge for the risky ones.
- Put a shared gate in front of shared usage. A pause file, a back-off after a limit message, and a ledger with an agreed split.
The next post is about the thing that made all of this safe enough to try: every change ships behind a feature flag that is off.