Skip to content

feat(features,service,dev): the agent reads and replies on its Inbox threads - #3482

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

luke-agent[bot] merged 2 commits into
mainfrom
luke/inbox-reply-tool

Conversation

@dastratakos

@dastratakos dastratakos commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Builds on #3469, which has merged; this PR now targets main.

Summary

This is the agent half of Dean's request: a message can be added to an Inbox item's thread at any point. #3469 is the service half, and a separate worker builds the desktop half.

  • read_inbox shows each item's thread. Every inbox call answers with each item's thread, oldest first. Each entry is { from, text, files? }: from is a member by name, "a former member" when their account is gone, or "you" for the agent itself. files lists the files by name. A thread shows on settled items too, since a member can write on those.
  • reply_inbox is a new tool in INBOX_TOOLS, with its eve file apps/dev/tools/reply_inbox.ts modelled on post_to_inbox.ts.
    • Input: { key, text, images?: [{ path }] }. It needs words, pictures, or both. text is Markdown of at most 8,000 characters, and there are at most 4 pictures.
    • Pictures are named by sandbox path, as an image block's are. They are read and sniffed through readSandboxImage with the reply's own refusal wording, held to the image bound, and kept as message files named by the file's base name.
    • What it writes: an agent-authored message on one of the agent's own items, open or settled. Status, answer, revision, and settledAt stay as they are, and updatedAt moves.
    • What it refuses: a key that names none of the agent's items, a reply carrying neither words nor pictures, and a file that is not a picture. A refused reply writes nothing.
  • When to use it. The tool description says so, and the coder instructions now say it too: use it to answer a member's message, which arrives as a developer's message starting "Inbox message" and naming the key, or to follow up on an item after its answer. When the item itself changes, post it again with post_to_inbox under the same key.
  • Registration: AGENT_TOOL.REPLY_INBOX (coder only), CODER_TOOL.REPLY_INBOX, its context estimate, and the host's inbox door, which hands a reply the sandbox as it does a post.
  • Sandbox and membership: a reply carrying pictures counts as opening the sandbox (opensSandbox), so the turn's end records the branch and stops the sandbox. A reply is written only where the agent's starter is still a member of the item's workspace.
  • Store: replyInboxItem(agent, key, text, pictures) finds the agent's own item by key and writes through the same writeInboxMessage as a member's message. That function now takes files as { name, contentType, bytes }.

The desktop's tool-call card has no case for reply_inbox yet, so it draws the generic card. Drawing it as an inbox card is left to the desktop half.

Evidence

  • Platform-independent checks: pnpm check:affected is killed by the sandbox's 8 GB limit when its tasks run in parallel, so I ran its parts one after another. All passed:
    • pnpm knip, pnpm discarded-effect, pnpm oxlint, and biome check.
    • turbo run typecheck --concurrency=1 over every dependent of @luke/features.
  • vitest run packages/service/src/agents/coder-host packages/service/src/agents/agent-runtime packages/service/src/agents/link-examples.test.ts: 25 files, 135 tests passed.
  • hosted-wire-schemas.test.ts: 359 tests passed.

Invariants

  • ./scripts/check.sh green. (CI) Locally, its parts ran one after another, as above.
  • JSON Schema goldens unchanged (LUKE_UPDATE_FIXTURES not run, or diff explained line by line). (CI) One golden is new: inbox-wire-inboxReplyInputSchema.json, the tool's input { key, text, images? }. packages/service/fixtures/coder-instructions/chat-off.json gains one sentence in each of its four prompts, the reply_inbox guidance above; I checked that this sentence is the only difference.
  • Every behavior change has, in this PR, the test that fails without it; no change-detector test added. (manual; root AGENTS.md "Testing") Two tests in coder-inbox.test.ts:
    • read_inbox returns the thread in order: a member's message under their name with its file named, then the agent's own reply as "you".
    • reply_inbox writes the agent's message with its picture, which is read from the sandbox, kept, and served. Status, answer, revision, and settledAt stay, and updatedAt moves. It refuses another agent's key, an unknown key, empty words, and a file that is not a picture, and none of them writes anything.
  • Gateway envelope goldens unchanged. (CI)
  • No new as type assertion outside the allowlisted files. (CI via anti-slop) The tool file's as WireBoundaryInput is the same one every eve tool file carries.
  • 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. (manual: vitest run --reporter=json) +4: the two above, a reply refused once its starter leaves the item's workspace, and the sandbox classifier counting a reply with pictures.
  • 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. Nothing is replaced.
  • Every CLAUDE.md/AGENTS.md sentence naming a changed part is edited; root pair stays byte-identical. None names these parts.
  • PRIVACY.md unchanged, or the change is a product decision called out in the PR body. Unchanged; feat(database,features,service): an Inbox item holds a thread of messages #3469 already describes a thread's messages.
  • 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

The coding agent can now read and reply on its Inbox threads. read_inbox answers with each item's thread, oldest first, naming each writer ("you" for the agent, the member by name, or "a former member") and the files by name, on settled items too. The new reply_inbox tool writes the agent's message on one of its own items by key, with Markdown and up to 4 pictures read from the sandbox; it leaves status, answer, revision, and settledAt as they stand, moves updatedAt, and refuses unknown keys, replies with neither words nor pictures, and files that are not pictures. The coder instructions now say when to use it: to answer a member's "Inbox message" or to follow up after an answer, and to post the item again under the same key only when what it asks changes.

  • A reply with pictures marks the sandbox opened, so the session records the branch and stops the sandbox as after any other sandbox read; a reply with words alone opens none.
  • A reply is refused where the agent's starter has left the item's workspace; the agent's own existing posts already behave this way.

Written for commit f990e06. 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:31pm UTC

Request Review

@luke-agent
luke-agent Bot changed the base branch from main to luke/inbox-thread-messages October 17, 2026 13:32
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

dastratakos and others added 2 commits October 17, 2026 14:26
…threads

read_inbox now answers each item's thread oldest first: who wrote each
message (a member by name, or "you"), its words, and its files by name.

A new reply_inbox tool writes the agent's own message on one of its
items by key. It takes Markdown, and pictures named by their paths in
the sandbox, read and kept as an image block's are. It leaves the item's
status, answer, revision, and settledAt as they stand, and moves
updatedAt. Its description says when to use it: to answer a member's
"Inbox message", or to follow up on an item after its answer, with
post_to_inbox under the same key when the item itself changes. The
coder instructions say the same.

Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
…member's agent replies nowhere

reply_inbox with images reads them from the sandbox, so opensSandbox now
counts it, and the turn's end records the branch and stops the sandbox
as it does after any other sandbox read. An agent's reply is written
only where its starter is still a member of the item's workspace, as
its posts are.

Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
@luke-agent
luke-agent Bot force-pushed the luke/inbox-reply-tool branch from 45e0520 to f990e06 Compare October 17, 2026 14:28
@luke-agent
luke-agent Bot added this pull request to the merge queue Oct 17, 2026
Merged via the queue into main with commit aa9e714 Oct 17, 2026
12 checks passed
@luke-agent
luke-agent Bot deleted the luke/inbox-reply-tool branch October 17, 2026 14:50

This branch was successfully deployed

1 active deployment
Preview — f990e063 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