feat(service,features,desktop): tell Inbox items apart by whose agent asks them

Merged
DA
4d ago
+542-68

Implements the plan "Is there a way to distinguish between Inbox items per person?" (https://tryluke.dev/stage/plan/d4c1b75b-9298-4197-82c9-1a607d2cf91b), where the developer chose options A + B + C.

Summary

Before this change, notifications, the Dock badge, and the sidebar's Inbox count included only items from agents you started. The Inbox list, Home, and a task's Inbox tab drew every member's items the same way, blue dot included. You could only see whose agent was asking by hovering over its tile.

  • The item says whose it is. Each inbox item now carries startedBy (a member reference), read from the user_id the row was already written under. No migration is needed. An item from an older service with no startedBy counts as the reader's own, the same rule agent-notices.ts already uses.
  • A. Faces on teammates' rows. A teammate's item shows their face beside its time, the way the sidebar marks a teammate's task. Your own rows show no face.
  • B. Needs you means yours. The blue dot, the Needs you filter and its dot, group counts, the item chosen first, Next / J, a task's own Inbox tab, and Home's Inbox section now count only your own agents' open items, which matches the Dock badge. A teammate's open item gets a hollow ring, labelled "Waiting on " for screen readers. Any member can still answer it.
  • C. Group by person is a new View options choice. Your items come first as You, then each teammate's, the one with the most recently changed item first. Rows there name their task instead of showing a face. Each person's group folds like a task group, and the choice is kept across launches like the other groupings.

Left unchanged on purpose:

  • Factory still counts every open question, because it shows what is holding a task up, whoever is asked.
  • A person's page still lists everything waiting on that person.

Evidence

  • pnpm check:affected: typecheck, lint, knip, and discarded-effect pass. Every test package passes except one desktop file, src/main/app-menu.test.ts, which fails in my sandbox because the Electron binary isn't installed ("Electron failed to install correctly"). That file is unrelated to this change, and CI installs Electron.
  • pnpm exec vitest run packages/service/src/agents/coder-host/inbox-store.test.ts: 7 passed, on PGlite. A teammate and the starter both read startedBy as the agent's starter.
  • pnpm exec vitest run apps/desktop/src/renderer/tasks/inbox-model.test.ts: 18 passed (+4).
  • Screenshots: I rendered the real InboxList in jsdom with the desktop stylesheet and captured it with Playwright. Images follow below.
Group by taskNeeds you onGroup by person
Inbox grouped by task: your open item has a blue dot, while Dana's and Lee's open items show their faces and hollow ringsNeeds you filter on: only your own open item is listedInbox grouped by person: You first, then Dana Reyes, then Lee Park, each row naming its task

Invariants

  • ./scripts/check.sh green. (CI)
  • JSON Schema goldens changed under LUKE_UPDATE_FIXTURES=1. Each of the five inbox answer schemas (inbox-wire-inboxItemSchema, -inboxAnswerSchema, -inboxAnsweredSchema, coding-agent-view-codingAgentInboxAnswerViewSchema, -codingAgentInboxAnsweredViewSchema) gains one optional startedBy property, a member reference (userId and name strings), and nothing else.
  • Every behavior change has a test that fails without it: four new model tests (only your open items need you; first choice and Next skip a teammate's item; Group by person order and holders; folding a person's group) and the store assertion on startedBy. No change-detector tests.
  • Gateway envelope goldens unchanged.
  • No new as type assertion.
  • No Effect.run* outside the edges.
  • No new raw async primitives.
  • No discarded Effect.
  • Test count: +4 desktop model tests. The store test file's count is unchanged (one test gains assertions and a new name).
  • Replaces no hand-rolled file.
  • No CLAUDE.md/AGENTS.md sentence names these parts.
  • PRIVACY.md unchanged. A member could already see who started any agent on its card, so the starter's name reaches nobody new.
  • No dependency changes.
  • Barrel/door rule unaffected.

Notes

  • Blockers or follow-up verification: I haven't seen this on the Mac. A quick look at the window Inbox in a team workspace with a teammate's open item would confirm the face, the hollow dot, and Group by person.

Made with Luke


Devin Review


Summary by cubic

Lets you tell Inbox items apart by whose agent asks them, so needs-you signals match the Dock badge and sidebar count.

  • Each item now carries startedBy, the member who started the agent, read from the user_id the row was already written under; no migration needed. Items without it count as the reader's own.
  • A teammate's rows show their face beside the time, and their open items get a hollow ring labeled "Waiting on " for screen readers; any member can still answer them.
  • The blue dot, Needs-you filter, group counts, first choice, Next/J, a task's Inbox tab, and Home's Inbox now count only your own open items.
  • Group by person is a new View-options choice, kept across launches: yours first as You, then each teammate's, most recently changed first.
  • Factory still counts every open question, and a person's page still lists everything waiting on them.