v0.2.6
Everything here landed after v0.2.5. The full
record is in CHANGELOGS/v0.2.6.md.
An actor has a type, and actors write to each other
An agent used to be one thing configured one way, and a sub-agent that same thing handed a task. An
actor now has a role: a settings type in roles/<name>.yaml beside the manifest, travelling in
git like any other project file. The manifest names the roles it accepts, so a role file that arrives
in a pull request and that nobody named does not act. The point of the type is that it withholds:
a named role governs the mode of the run and narrows the tools it is offered, and an unknown role is
refused with the available names listed rather than quietly falling back to the default. role_list
publishes who exists — name, mode, one-line description, and nothing else.
A spawned run is now an ordinary session: an id, a file on disk, an inbox, a progress tree, token
accounting. That is what makes it watchable mid-run instead of only reportable afterwards, and it is
what makes the rest possible — once a spawned run is a session, two actors can address each other.
agent_correspond opens an address to another role, and the chat grows its own reply tool for that
one correspondence: the tool name is the address. Calling it returns a delivery receipt, never the
answer — the correspondent's words arrive later as an ordinary message on this chat's own turn. Each
correspondent now has exactly one address owned by its chat, after a free-text topic turned out to
found a new correspondent on every typo and to collide outright in Cyrillic; agent_introduce
connects two other chats without either side spelling out a chat id.
Two actors who never run out of things to say would spend someone else's token budget forever, so the
exchange decays by construction: the wait before a reply wakes a turn doubles with how many
replies have crossed since a human last spoke, up to a ceiling past which a reply queues instead of
waking a turn of its own. The old blunt self_feeding_cap — a constant of 3 that killed an honest
ping-pong on the third turn — is now a setting, and off by default.
Seeing who is talking, and who is being ignored
The chat list is a tree: a spawned session hangs under the chat that gave it its errand. An incoming
reply renders as speech, "from <role>"; underneath it is still an ordinary turn on the wire. The
correspondence graph is drawn rather than listed — a role is a box with its totals, a pair of roles is
one arrow however many chats it covers, weighted by how much text actually crossed it — and it leads
with the imbalance: the role that only ever talks, the role nobody answers.
Archiving means it. Opening an archived chat used to bring it back to life in everything but name;
it is now refused, and refused legibly ("Chat is archived", not "Chat not found"). chat.read is the
way back in: history off disk, no runtime, no watch, and a window with no composer. A sub-agent's
window is read-only on the same principle, and there it is a server-side rule rather than a house
style a client could forget.
Settings you can reach, in the layer they belong to
Roles have an editor, showing both halves at once — the body is the file, whether the role acts is
the manifest naming it — because hiding either hides a real state. Connections moved out of the
manifest alone into three layers like secrets (shared, user, project), since an endpoint plus a
credential is a property of an account, not of a repository; a role can name which of them its chats
may resolve a model against. Models and roles can carry their own temperature and reasoning level,
between the project default and a chat's own choice.
Settings now open as an overlay inside the window instead of a frame that read as a separate program,
and every settings list finally uses the same card, caret, delete and add button, with the add button
after the items so a freshly added row is never below the fold.
The interface speaks your language, and the chat reads properly
The whole interface — shell, chat, dock, workspace, banners, plugin panels, the native window frame —
goes through one dictionary keyed by the English source text, so an untranslated string renders as
English rather than as debris. The choice now survives a restart: it was being saved correctly and
thrown away, because an ephemeral loopback port makes every launch a new origin with an empty
localStorage. It lives in the machine layer now — a language is a property of the reader, not of
the repository, and not something one person may broadcast onto a shared server.
Reading a chat: a draggable reading measure, a footer of knobs that folds away per window, and a log
that finally stays pinned to the bottom by measuring the view rather than polling until the turn ends.
Caching is stated explicitly at last — hashed assets immutable, the index that names them never
cached — which is what had been making a rebuilt client invisible in WebView2.
The architecture diagram editor — experimental, as-is
The diagram editor remains experimental and is shipped as-is. Its model contract is still moving,
and neither the file format nor the behaviour is stable between releases.
Routing was replaced rather than extended: the scene is one list of zones with a weight, cost is paid
per unit length inside one, and routes are searched on a sparse grid with bends priced for stability.
That single rule says what a pile of special cases used to — a line stops disappearing into a
container's frame without any rule about frames existing — and ports join the grid on their own
normal, so ends come out square by construction. Lines sharing a corridor are separated afterwards.
Shapes now state where their own inside is, so a diamond's controls and an actor's name stop landing
in empty space, and a hovered edge is lit from underneath instead of thickened.
Also in this release
A chat running as a role now resolves its model, temperature and reasoning through that role instead
of around it. A plugin's own settings keep their types when they cross between YAML and the settings
panel, so an unquoted true no longer reaches a plugin as the string "true". Any window can open
WebView2's devtools for itself (F12), renders at the DPI of the monitor it is actually on rather than
the one it launched on, drags by its whole title bar again, and clips a long project name instead of
pushing the buttons off the edge. Popups no longer hide behind the settings overlay.