a chat, not a terminal
Talk to one agent.
It runs the fleet.
The agent-fleets pattern needs a coordinator, and until now the coordinator was a terminal: you opened one, typed instructions into a CLI agent, and that agent used kolu’s commands to drive the others. It works — kolu was built that way — but the thing you talk to all day was a PTY, with a PTY’s shape: scrollback you scroll, output you read, no idea which of its questions were waiting for you.
The Conductor is that coordinator as a chat. One of them, covering every machine you have. You talk to it; it creates, briefs, watches and answers the agents in your terminals, wherever those terminals are.
What it is
A single conversation with Claude, held by kolu-server — the process your browser is already talking to — and spoken over the Agent Client Protocol. Its working directory is the $HOME of the machine kolu-server runs on. Its hands are kolu’s own MCP face: the same tool table you can point any agent at, lifted over every host kolu knows about. So it opens terminals, types into them, waits for them to settle, reads their screens and kills them — on whichever machine the work belongs on — through exactly the tools documented on the MCP page: nothing special, nothing private.
A terminal’s name on that wire carries its host: local/3f29…, remote:nix@prod/9a1b…. A live hosts roster tells the agent which machines are there and which are reachable right now, and it changes while the conversation runs. Add a host mid-turn and its terminals start arriving in the watch the agent already has open; take one away and the terminals it was carrying report themselves gone, then the host leaves the roster. Nothing is reopened and nothing is re-taught — the conversation is opened against one tool endpoint and keeps exactly that one for its whole life.
Its own entry in the chrome bar
The chrome bar’s tab row is a row of machines: one tab per host, each with its connection dot and its own hue. The Conductor sits in that row and is deliberately not one of them — a ◆ Conductor entry, set apart, with none of the host-tab chrome: no tab shape, no connection dot, no host colour. It is not a host and kolu does not model it as one; it is the one conversation, and the thing it is about is all of those machines at once.
Selecting it opens the conversation; selecting any host tab leaves it for that machine. ⌘⇧O (Super+Shift+O off a Mac) jumps to it, and again to come back to the host tab you were on. Which of the two you had open persists the way the active host does, per device. The ▦ canvas · ▢ maximized control stays what it always was — a posture for a host tab — and has no conductor segment, because the entry in the tab row is how you get here.
Its badge is a violet count: how many of its questions are waiting for you, summed across every host. Those questions are a needs-you source like any other, so they chime, raise a system notification and count toward the app badge through the same machinery a blocked terminal does. A turn merely ending is silent; being asked something is not.
The view is the chat, and for now nothing else — header, strip, transcript, composer, filling the window. No dock, no canvas, no second pane holding a terminal: the terminals are on the host tabs, one keystroke away, and a half-width copy of one here would be a second place to look at the same thing. The way to a terminal from the conversation is open tile on the agent’s own tool card, which takes you to that terminal’s host tab with the tile focused.
On mobile the Conductor appears in the host sheet beside the hosts, and opens the chat full-screen.
The conversation
The header
The agent’s name, and then the facts you steer by:
- a state chip — rust while it is working, violet when it is asking you something, quiet otherwise;
- who it is signed in as, when the agent says — “Claude Max”, an API key, a gateway. Silence here is not the same as logged out: an agent that does not report its identity shows nothing, and one that reports it is logged out says so;
- the model, pressable for the session settings;
- a context meter,
148k/1M. A fraction rather than a percentage, because the window is not a constant — 200k and 1M are both ordinary, and “2%” would read identically in both and mean quite different amounts of work left; - a ⋯ menu, which performs nothing by itself.
Session settings
Pressing the model opens the adapter’s own settings: the models it offers (with their window sizes), reasoning effort, permission mode, and whatever else it advertises. The controls use the adapter’s names and values — kolu composes none of them. A change the agent refuses leaves the confirmed value where it was, and says why.
The model you choose survives a restart. That is a fix rather than a given: the agent re-asserts its own default over a resumed conversation, so kolu records the switch and re-applies it when the conversation comes back.
The ⋯ menu
Everything kolu can do to the conversation itself, as opposed to the options the agent advertises:
- New session — a fresh conversation, and an empty one. The messages go, the files attached to them are deleted from the machine running kolu, and the terminals the conversation remembered are forgotten; what is left is a blank chat, and the next thing you say teaches the agent its standing prompt again. There is no undo, so it asks once before it does any of it.
- Stop, while a turn is running.
- Sign in…, while the agent is not signed in.
- Copy transcript, always — the conversation as plain text, on the clipboard.
A conversation kolu could not resume after a restart is the one case where a — new session — rule is drawn across the transcript: the scroll above it is the conversation you were having, and the line says where the agent’s memory stops. A new session you ask for yourself leaves no such line, because there is nothing above it to divide from.
The strip
Above the scroll, and never carried away by it:
- the tool servers this conversation has.
kolu ✓when the agent has reported the server attached, the agent’s own sentence beside the name when it says it is not, and a note that the agent brought its own servers besides. There is no “kolu is missing” row: the fleet endpoint is proved to be answering before the conversation is opened, so an endpoint that is not gets a refusal naming it rather than a chat window that can see nothing; - background tasks still running — a
run_in_backgroundshell, a monitor, an async subagent — with a live clock. These outlive the turn that started them, which is the whole point of them; - subagents out, pressable to open their shelf.
The transcript
What you typed sits quoted. What the agent answers is rendered as markdown. Between them:
- a plan card when the agent sends one, replaced whole on each update;
- tool cards. Anything kolu cannot name gets a generic card. Anything that is one of kolu’s own tools gets a card that knows what it means, and each one that is about a terminal names the host it acted on, since an id alone no longer says which machine:
lifecycle_createshows the terminal’s label (or its worktree branch), the directory and the command it started, and — once the call has answered with the terminal it made, not while it is still running — that terminal’s host and an open tile that takes you to that host’s tab with the tile focused;lifecycle_sendInputshows the target and what was sent; the three ways of waiting show the state, how long it took, and the last lines of the screen folded underneath — awatch_nextis about a terminal only when everything it caught was about that one, and otherwise shows just how the wait ended;screen_textshows the snapshot. A call that is still running carries a clock; - file diffs, trimmed, one box per hunk, click to expand;
- asks — a permission request the agent was not allowed to answer for itself, a question it needs you to settle, a page it needs you to visit — as a form in the flow. Nothing times out. Dismissing one is an answer too: the agent is told you would not say, never handed a choice you did not make.
The composer
It never locks. @ completes terminals from every host into a chip — the host is shown as you pick, and the message that goes out carries a structured reference to each one, so the agent gets the terminal’s host/id and intent rather than a name it has to guess at. / completes the agent’s own commands. ⇧⏎ is a newline, ⏎ sends, Stop cancels the turn in flight.
Sending while it works is fine: the message goes out immediately and waits at the agent, marked queued until it is picked up. Nothing is held on kolu’s side, which is also why Stop has nothing to throw away — anything queued behind the turn you stopped survives and runs next.
A tile action, Ask the Conductor about this, opens the conversation with that terminal already mentioned.
Attachments
Paste an image into the composer, or drop a file onto the pane, and it goes up with your message — a chip appears above the box first, so you can see what is attached and take it off again. A screenshot is the obvious case: the agent reads the picture rather than your description of it.
What travels depends on what the agent said it could take. An image goes as an image. A text-like file goes as its text, embedded. Anything else goes as a link to the path kolu wrote it to, which the agent reads itself — so a 40 MB binary is a filename on the wire, not forty megabytes. An agent that never advertised the kind you attached gets told no, out loud, rather than quietly handed nothing.
There are two limits — 10 MiB per file, 20 MiB per message — and crossing either is a sentence in the composer before anything is sent.
A file goes up as it is attached, in pieces, and the message that follows carries only its name and where it landed — the bytes never ride the message itself, because one oversized message would take the whole tab’s connection down with it. Nothing is kept in the conversation’s record either: kolu writes the file into kolu-server’s own state directory and remembers where, so the thumbnail stays on screen in the tab that sent it and a conversation reopened tomorrow shows the chip with the file’s name and size. A transcript is a thing you scroll through for months, and a base64 screenshot in it is a conversation you cannot load.
Signing in
An agent with no credential cannot open a conversation or run a turn, and the protocol has one way of saying so. kolu reads it as its own refusal rather than a generic no, because it is the one refusal with something to do about it: the panel puts the agent’s own ways of signing in on screen.
Claude hands over a command for kolu to run. kolu spawns it in the session’s directory, streams its output with the URLs clickable, and gives you one line to type the code into; exit 0 is the whole of success. A message that was refused for want of a signature comes back to the composer and is sent again once you are in.
There is deliberately no API-key box. Where a credential typed into a form would live, how it would be stored and whether it would ever be shown again is a feature with its own argument to make; until it is made, the button is not drawn.
What it knows how to do
Every new conversation starts with one standing instruction — visible in the transcript, because the protocol has no system prompt and kolu would rather you could read what your agent was told than not. It says, in short: you are kolu’s conductor, and one conversation covers every host; a terminal is named host/id; the hosts resource is the live roster of machines and it changes under you; create a terminal on the host the repo lives on; the loop is create → send the text → let it settle → press Enter → debrief; supervise several at once with a standing watch; the agents’ questions come up to you, and you bring the human only the decisions that are theirs; briefs go through files rather than long pastes.
It is re-taught on every new session, and it is versioned with the binary — so the law never drifts from the tools it describes.
When it comes back
kolu-server restarts routinely — an upgrade does it — so a restart is the normal path rather than a crash. The conversation comes back: the session is resumed by its own id, the transcript is what it was, and the model you put it on is re-applied. What does not come back is anything that was a fact about a subprocess that no longer exists — a turn in flight, a sign-in half done — because a restored one would be a lie with a timestamp on it. A host that was away while kolu-server was down needs nothing either: it rejoins the hosts roster when it reconnects, and its terminals flow back into the conversation that is already open.