← ~/articles

You Can Just Interrupt It

Lion Hummer/

I added Discord as an external channel for Kit. This changed more than I expected.

Before Discord, every interaction was through the TUI on my laptop. Strict turns: I send a message, Kit responds, I send another. If Kit is busy, I wait. That's fine when you're sitting at your desk watching it work. It's not fine when you're on your phone and Kit is three tool calls into something you asked for twenty minutes ago.

With Discord, messages arrive whenever. I'm on the bus, I remember something, I send it. Kit might be idle or it might be mid-task. Queueing ("hold that thought until I'm done") doesn't work here because the UX is a chat thread, not a terminal. If I send a message and nothing happens for two minutes while Kit finishes something in the background, it feels broken.

So I built interjection.

Mid-turn messages

When a message arrives while Kit is working, it gets injected into the current tool loop via a MidTurnEventCollector. After each batch of tool calls, the agent drains the collector. If there's a new message, Kit sees it with three options:

  1. Incorporate — the message is relevant to what it's already doing. Fold it in, keep going.
  2. Switch — the new message is more important. Create a todo to resume the current work, then handle the new thing.
  3. Defer — the new message is less urgent. Create a todo for it, continue current work.

Kit picks one and acts on it. The key is that all three are real actions, not just acknowledgments. If Kit incorporates, the current work adjusts. If it switches, the old task is saved as a todo with enough context to resume. If it defers, the new message becomes a todo that'll get picked up next cycle.

This builds on multithreading

The reason interjection works smoothly is that Kit is usually already fast. Because the main thread delegates heavy work to background threads, most of the time when a message arrives the orchestrator is idle. It just responds. No interjection needed.

But when Kit is mid-task and a message lands, the transition is seamless. "I'm working on the research you asked for. What's up?" It doesn't feel like an interruption because Kit already thinks of itself as doing multiple things. One more input to incorporate or defer is natural.

The switch path is the most interesting. Kit is halfway through task A, I send something more urgent, and Kit creates a todo for "resume task A from step 3" and pivots. Next delivery cycle, it picks task A back up. I didn't have to manage any of that. Kit context-switched for me, preserved the state, and came back to it.

What changed

Before this, talking to Kit felt like submitting requests. After this, it feels like texting someone who's working. I can say "oh also" and "actually wait" and "never mind, do this instead" and Kit handles all of it. The conversation doesn't have a lock on it.

Most agent interfaces enforce strict turns because it's simpler to build. But it's an artificial constraint. The model doesn't care. It's just more context. The interfaces are the bottleneck, not the models.

You Can Just Interrupt It — Lion Hummer