Skip to content

feat(desktop,host,features): an Inbox thread draws its messages, and every item keeps its box - #3486

Merged
luke-agent[bot] merged 2 commits into
mainfrom
luke/inbox-thread-composer
Oct 17, 2026
Merged

luke-agent[bot] merged 2 commits into
mainfrom
luke/inbox-thread-composer

Conversation

@dastratakos

@dastratakos dastratakos commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This is the desktop half of "a message on an Inbox thread at any point". It stacks on #3469 (the thread's wire and service).

  • The thread draws its messages. Messages show as Comments, mixed in by time with the question (at postedAt) and the answer or withdrawal (at settledAt, falling back to updatedAt on an older service). A message written while the item was open therefore shows before the answer that came after it.
    • A member's message shows their face and name (personActor), and "You" for your own. A member whose account is gone shows as someone unnamed.
    • The agent's message shows its tile and name.
    • Words go through SentWords, so mentions show as chips. Files show the way an answer's do. A message with files and no words shows the files alone.
    • When the thread holds MAX_MESSAGES_READ (50) messages, a line says earlier messages are in the agent's tab. Pressing the agent's name opens that tab.
    • The answer's and withdrawal's times now read settledAt, so a later message no longer moves them.
  • The box is on every item.
    • While the item is open, nothing changes: presses, choice, form, and the quiet line work as before, and a free note is still the answer.
    • Once the item is settled, the same composer posts a message: placeholder "Message …", Send or Enter, files by picker, paste, or drop, up to 8,000 characters.
    • InboxNextUp now sits above the box.
  • Posting. This adds a new codingAgents.inboxMessage act: an ACT_KIND entry with its payload schema (codingAgentInboxMessageParamsSchema) and result guard, a router row, a gateway method, a HostOperator method, and a composer row that calls HostedCodingAgentClient.messageInbox.
    • The returned item replaces the one held, and the item keeps its status.
    • Your own new comment scrolls into view inside the board's own scroller, not with scrollIntoView.
    • The draft is kept per item. A settled item now keeps its draft until the item changes revision.
    • A refusal shows under the card.
    • The send key is reused only for a retry of the same words and is dropped once the message lands, because feat(database,features,service): an Inbox item holds a thread of messages #3469 now refuses a reused key.
    • The agents are read again afterwards, since a message may wake a stopped agent.
  • reply_inbox row. The agent's reply_inbox call (feat(features,service,dev): the agent reads and replies on its Inbox threads #3482) gets its own collapsed row, CALL_KIND.INBOX_REPLY ("Replied in your inbox:"). The row names the item's key and lists the reply's words and image paths. The tool name is matched as a string, so this PR doesn't depend on feat(features,service,dev): the agent reads and replies on its Inbox threads #3482.

Screenshots

A settled item's thread: a teammate's message before the answer, the agent's reply and your own message after it, Next over the message box
The same, in light, with a message typed into the box

Both were rendered from the jsdom fixtures' DOM with the built styles.css and captured with Playwright.

Evidence

  • Platform-independent checks:
    • The affected vitest runs pass: desktop-inbox, composer-drafts, tool-call-model, inbox-model, all of host, features, and gateway.
    • tsc passes for desktop, host, and service. Biome and oxlint are clean.
    • A whole check:affected run had its @luke/service#typecheck OOM-killed (exit 137) in the sandbox. Run alone, that typecheck passes.
  • New tests in desktop-inbox.test.ts:
    • Member and agent messages drawn in order with their faces, including one written while the item was open, which draws before the answer.
    • A message on a settled item: the act's payload, no answer sent, the item replaced, the status still "Answered", the box emptied, and the board scrolled.
    • A refusal.
    • Files alone, both sent and drawn.
    • An open item still answers and sends no message.
    • The 50-message cut line, which opens the agent's tab.
  • Other new tests:
    • A router row for the act.
    • The composer relaying the message.
    • The reply_inbox row.
  • One existing assertion changed: "a settled item takes no answer" now checks that the box asks to message the agent.

Invariants

  • ./scripts/check.sh green. (CI)
  • JSON Schema goldens unchanged (LUKE_UPDATE_FIXTURES not run, or diff explained line by line). (CI) One golden was added: coding-agent-view-codingAgentInboxMessageParamsSchema.json, for the new act's params, which are itemId plus inboxMessageRequestSchema's fields.
  • Every behavior change has, in this PR, the test that fails without it; no change-detector test added. (manual; root AGENTS.md "Testing")
  • Gateway envelope goldens unchanged. (CI)
  • No new as type assertion outside the allowlisted files. (CI via anti-slop)
  • No Effect.runPromise/runSync/runFork outside the runtime edges and the shims tools/anti-slop/effect-edges.json records. (CI via anti-slop/no-run-promise-outside-edges)
  • No new setTimeout/setInterval/new Promise/AbortController/fs.watch outside the files tools/anti-slop/effect-edges.json records. (CI via anti-slop/no-raw-async-primitives)
  • No Effect, Stream, or Layer written as a statement and dropped; a description a caller walks past runs nothing. (CI via pnpm discarded-effect)
  • Test count equals the pre-PR count or the delta is listed. (+6 in desktop-inbox.test.ts, +1 in coding-agent-acts.test.ts, +1 in tool-call-model.test.ts)
  • Each hand-rolled file the PR replaces is deleted, or the part that remains is a permanent adaptor named in root AGENTS.md's "The permanent adaptors" with the reason it stays.
  • Every CLAUDE.md/AGENTS.md sentence naming a changed part is edited; root pair stays byte-identical. (CI for pair existence; manual for wording)
  • PRIVACY.md unchanged, or the change is a product decision called out in the PR body.
  • Package package.json deps match what the sources import by bare specifier; effect via catalog:. (CI)
  • Barrel/door rule: no Node-reaching Effect module (@effect/platform-node, effect/sql) behind a barrel the renderer or a web function opens. (CI: existing renderer node: grep plus a new grep for those specifiers in renderer bundles)

Notes

Made with Luke


Devin Review


Summary by cubic

Lets an Inbox thread draw its messages and keeps the message box docked on every item, so a settled item can still be discussed without changing its status.

New Features

  • The thread now interleaves member and agent messages with the question (at postedAt) and the answer or withdrawal (at settledAt, falling back to updatedAt on older services), so a message written while the item was open shows before the answer that followed it; the answer's and withdrawal's times no longer move when a later message lands.
  • When a thread read holds 50 messages, a line says the earlier ones are in the agent's tab, and pressing the agent's name opens that tab.
  • Once an item is settled, the same composer writes a message instead of an answer: "Message <agent>…", Send or Enter, files by picker, paste, or drop, up to 8,000 characters, while the next item that needs you stays offered above the box.
  • Adds a codingAgents.inboxMessage act and matching gateway method and host operator; a refusal is shown under the card, and the send key is reused only for a retry of the same words, because the service now refuses a reused key.
  • An agent's reply_inbox call draws as its own collapsed row naming the item's key and listing the reply's words and image paths.
  • Drafts now know whether they are an answer or a thread's message: an answer left unsent on an item a teammate settled in the meanwhile is let go rather than sent as a message, and a message being written on a settled item outlasts the reads after it.

Written for commit bfc6362. Summary will update on new commits.

View guided diff Turn on auto-fix

@vercel

vercel Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
luke-web Ready Ready Preview Oct 17, 2026 2:13pm UTC

Request Review

luke-agent Bot added a commit that referenced this pull request Oct 17, 2026
Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
devin-ai-integration[bot]

This comment was marked as resolved.

Base automatically changed from luke/inbox-thread-messages to main October 17, 2026 14:07
dastratakos and others added 2 commits October 17, 2026 14:09
…every item keeps its box

An item's thread now draws its messages as comments among the question and
the answer or withdrawal, in the order they were written (`settledAt` for
the settlement): a member's by their face and name, the reader's own as
You, the agent's by its tile and name, their words through SentWords so
mentions are chips, and their files drawn as an answer's are. A thread
read cut to its latest 50 says the earlier ones are in the agent's tab.

The box is docked on every item. While an item waits it answers it exactly
as before; once settled, the same composer writes a message on the thread,
"Message <agent>…", Send, files allowed, over a new
`codingAgents.inboxMessage` act through the host to
`HostedCodingAgentClient.messageInbox`. The returned item replaces the one
held, the reader's own new comment is scrolled into view inside the board,
the draft is kept per item, and a refusal is said under the card. Next
stays offered over the box.

The agent's `reply_inbox` call draws as its own collapsed row naming the
item's key.

Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
An answer typed on an open item that another member answered meanwhile
stayed as the settled item's draft, since settling leaves the revision as
it was, so its note stood ready to send as a message and its picks were
stuck. A draft now says whether it is a thread's, and a read lets go of an
answer's once its item is settled.

Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
@luke-agent
luke-agent Bot force-pushed the luke/inbox-thread-composer branch from 11197ee to bfc6362 Compare October 17, 2026 14:10
@luke-agent
luke-agent Bot added this pull request to the merge queue Oct 17, 2026
Merged via the queue into main with commit 981d97d Oct 17, 2026
12 checks passed
@luke-agent
luke-agent Bot deleted the luke/inbox-thread-composer branch October 17, 2026 14:26

This branch was successfully deployed

1 active deployment
Preview — bfc6362b Deployed Oct 17, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant