feat(chat): agents read and address members by their mention links
PR 2 of 3 in replacing chat handles. It is stacked on #4004. Coding agents and Luke now read and write chat members as the app's mention links instead of @handles. Per the developer's decision there is no fallback for @handle text already posted.
What changes
Agents read members as links
read_chatnow names members by link:you,members[]({ mention, kind, left? }replaceshandle), each message'sfrom, a DM'sin, an ask'sansweredBy, and a post's receipt (told/held/left).unresolvedholds the labels, as written, of links that name no member.- The new
coder-host/chat-names.tsbuilds each member's link the waylist_agentsdoes (workspaceStepOf+writtenMention). A person's link uses their account name, an agent's its title or else its model, and Luke's is…/plan/<taskId>/luke. - A member no link can be built for gets a plain label (
CHAT_MEMBER_LABEL): "Former agent", "Former member", or "Luke". - Message words reach agents as written.
chatWordsForAgents,handlesIn,HandleOfandnamesMemberare deleted.
Agents address members by link
chatTargetSchemaaccepts#name, or a member link written whole ([@Name](url)) or as the bare URL.@handleis refused.CHAT_BOUNDS.MAX_TARGET_CHARSis 512, and the schema checks only the shape.- New
chatTargetMember(target)inchat-mentions.ts. - New
memberOfSubject(userId, organizationId, subject)inchat-store.ts. It wrapssubjectMemberwithisWorkspaceMember, andsubjectOfinchat-ask.tsis now exported. - These handle
post_chat'sto(dmWith),read_chat'schannel(a DM is matched by what the other member stands for, not by spelling), and the window'stoinworkspace-chat.ts. memberNamed,namedMember,findMemberByHandle,taskOfContextandfindAgentTaskare removed.
Only links notify
- Removed:
mentionedHandles, theMENTIONregex,ChatMentions.handles,ChatPost.mentions, and the handle half ofnamedIn/placePost. @luketyped as a word means nothing and mints no Luke.
Notices, senders, inbox entries
- A notice's head is
Chat · [@Name](link) in #x (m N):.chatNoticeWordsnow matches that head in full. - These are now display names, not links: notice metadata
from, the inbox'saccountChatEntry.from(in both the held read and the Neon live statement, which joins the author's account and agent), and an agent'sLineSender.name. - The
@prefix is gone fromchat-notice.tsx,agent-notices.tsand the transcript copy's heading.
One change beyond the brief: a chat notice no longer carries "Mentioned in this message" notes (steer.ts). Those notes are written as "The developer pointed you at…". Now that a notice carries member links, a teammate's message would otherwise be described as the developer pointing at people. This also drops notes for task or file links in chat messages. The servers a notice hands are unchanged.
Prompts: the coder's chat section tells the agent to name members by the links read_chat lists, and writes its task's Luke as [@Luke](<taskLink>/luke). "as @luke" is gone from Luke's prompt and the tool descriptions and refusals.
Kept for PR 3
The handle column is still minted and written (mintHandle, SPOKEN_FOR, LUKE_HANDLE, chatHandleSchema, MAX_HANDLE_CHARS), and the window's wire still sends handle. CHAT_TARGET_SIGIL.MEMBER is still used by the composer.
Tests
- Handle-pinned tests are rewritten to links in:
coding-agents-app.test.ts,coder-host.test.ts,brain-host-tools.test.ts,brain.test.ts,inbox-store.test.ts,chat-store.test.ts(the minting tests are kept),chat-wire.test.ts,chat-mentions.test.ts, and the desktop notice tests. - New tests cover:
post_chatto a member link, whole or bare, opens the DMread_chatlists members andyouas links- a link in the words tells a member, and one naming no member comes back unresolved by its label
@wordtext tells no one and mints no Luke@handleastoorchannelis refused- the window's DM goes by link
- a notice names its sender by link and carries no mention notes
- the coder prompt's Luke link decodes as a Luke mention
- JSON Schema goldens were regenerated with
LUKE_UPDATE_FIXTURES=1. The 7 changed fixtures differ only inchatTargetSchema's pattern and max length. - Run locally: per-package
tsc --noEmit,oxlint,biome,knip,repository-checks.sh, and vitest across features, ui, host, panel/tasks, wire, apps, the database store models, and the service agents, live and inbox suites.
Made with Luke