Handoff — 2026-09-15 — / commands and @ mentions in agent windows
State
Done, tested, gate green, documented, not committed. Working tree on main (v0.7.0 + this), 12 files changed and 9 new, nothing staged. The five editors carry the documentation and the starter-file change, also uncommitted; their code is unchanged and their suites pass.
What was built: typing / as the first character of an agent window's box lists the agent's available_commands_update commands with descriptions and hints; typing @ anywhere lists the project's files. ↑↓ move, Tab completes, Enter completes-or-sends, Esc closes until the text changes, a click takes a line. A command is sent as text (/web query); a mention is sent as an embedded resource when the agent declared promptCapabilities.embeddedContext, a resource_link otherwise, in place of the name, with text blocks either side.
In flight
Why does mini-me's command list not show? (2026-09-16.) The user typed / in a window on mini-me and saw nothing. Their binary has the feature (checked: go version -m shows turbo-core (devel), the label string is in it). Added TURBO_ACP_TRACE and the unreadable-update line in Agent status so the next step is possible. Next step is theirs: run TURBO_ACP_TRACE=/tmp/acp.log ./bin/turbo-go, open mini-me, type a prompt, then open Agent ▸ Agent status and send the log. Three outcomes: (1) no available_commands_update in the trace → mini-me does not send it over ACP and the question moves to mini-me; (2) it is there and the status says it could not be read → fix the decoding to that shape, and replay it in fakeagent_test.go; (3) it is there and decoded → the picker itself, Session.Commands() non-empty but choices() returning nothing; check onInput, cursor == 0, single line.
Next steps
- Read the diff —
acp/picker.go,acp/picker_draw.go,acp/mention.goare new and small; the rest is threading. - Try it against a real agent that announces commands. The user's
mini-me(mm -acp,AGENT_CONFIG=…/agent.llamacpp.yaml) is the obvious one — an[[agent]]block for it iscommand = "mm",args = ["-acp"],env = { AGENT_CONFIG = "…" }. Watch for: does itsavailable_commands_updatearrive beforesession/newreturns (the client stores it either way, but the rule label only updates on the next frame), and does it declareembeddedContext. - Then the release order: turbo-core tag → each editor
go get→GOWORK=off make check→ tag. The editors' docs already describe the new behaviour, so they are ahead of the binary until then. - Decide about a branch. Previous cycles used
feature/acp; this one sits onmainbecause nobody was there to ask.
Open questions
- Should
Enteron a command that takes input but has none typed send anyway? It does now (/web+Entersends/web). Zed inserts and waits. The hint in the popup is the only nudge. - Should the popup also list files when
@is typed with the transcript focused? No — the picker is the box's. Nobody has asked. - Is 5 000 files / 200 shown the right cap? Guessed, not measured. A monorepo will tell.
Watch out for
- The picker's list is recomputed on every key and every frame —
refresh()is the single entry point and bothhandlePickerKeyanddrawPickergo through it, so the highlighted index can never refer to a different list than the one drawn. If you add a stored list, you will reintroduce exactly the desynchronisation this avoids. Files()is called once per opening of the@list, and the answer cached inpicker.fileswhile the word keeps its@. Calling it per frame walks the project sixty times a second.refresh()drops the cache when the word stops being an@word.HandleKeywraps everything in a before/afterInput()comparison to liftEsc's dismissal. It is cheap (onestrings.Join) but it runs on every key.mentions()onSendconsultsfileList(), which walks the project if the list is not cached — so a prompt with an@word sent without the popup having opened costs one walk. Acceptable; noted.cpis still corrupt for fresh inodes in this sandbox, and this time recreating the files did not help.release_test.gofails on it; nothing else does. Do not chase it as a code defect. Usecat a > b, nevercp.drawLinehas seven parameters and the gate did not flag it;drawChoicehad six and was flagged. The rule is not simply "> 5" — do not reason from the count alone, run the measurement.
Never touched by a human
Everything: the popup on a real terminal, its colours under the eight themes, Tab vs Enter on a real keyboard, a mention of a file with unsaved changes reaching a real agent, a command actually being answered by an agent.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|