Repository navigation
feat(crews): answer a Crew thread's provider approvals and questions from the Inbox - #309
Conversation
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Repository: Jacksondr5/j5code/.coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: Comment |
879b80d to
966519e
Compare
…from the Inbox A Captain's or seat's tool approvals and questions rendered inline in that thread's composer, where the person only saw them by opening the thread, so a Crew stalled unseen. The Inbox gets a Crew agent requests section, read from #263's route on every connected environment: each item names its Crew and seat (or the Captain), links to the thread, and is answered in place with the provider's approval choices or the question form. The bell counts them. On a live Crew thread, one appended J5 hook in ChatView (FORK.md case 44) hands the composer only the requests the Inbox does not hold, and CrewRosterGate shows a note pointing to the Inbox; a request the Inbox has not read yet stays inline, so nothing is hidden from both places. The roster gate still renders inline, non-Crew threads are unchanged, and mobile keeps its inline cards until it has an Inbox. Closes #264 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ead note aligns Found in the seeded dev-server pass: with no provider options the Inbox offered only Approve and Decline while the composer offers Cancel, Decline, Always allow this session, and Approve; the note sat on the composer's edge. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
966519e to
bcef305
Compare
Conflicts in crews.md and personas.md: took the sync's handoff artifact wording and kept this branch's Inbox rule. FORK.md: this branch's case is renumbered 44 → 49, since the sync took 44 and 45 and the Captains stack takes 46–48; the inventory count line is left to the Captains stack so the two land without conflicting. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The upstream sync's Badge lint (shadcn/no-restyle) refuses spacing and typography classes on <Badge>; the Crew agent request row's seat badge now uses size="sm" like the other Crew badges. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…rest inline With #308's selector matching the composer, a request can be listed that the Inbox cannot answer: a question answered by sending a message, or one that is no longer resumable. The Inbox now offers answers only for live requests and points to the thread for the rest, and the composer keeps those requests inline instead of handing them to an Inbox that cannot answer them. FORK.md case 46 records the shared selector and the client-runtime test that holds it to derivePendingThreadRequests. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
[Review panel: Opus 5.5 + Astra] Live test evidence for #308 and #309, run by Astra against real provider turns on an isolated dev server. This fills the PR's "Not verified: a real provider turn resuming after an Inbox answer".
Not tested: the "waiting in your Inbox" note on a seat thread (only the Captain's note was checked), the native desktop shell, mobile, and a disconnect in the middle of a flow. Bryant's before-images in the PR description cover the baseline. Captain resumed after the Inbox answer: Seat resumed after the Inbox approval: Stale Inbox answer refused with 409: |
|
Decision (Jackson, 2026-09-26): slim #308/#309 to seat approvals only. See the matching comment on #308 for why. For #309 that means:
|
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…wn approval UI The Inbox now lists only Crew seat approvals, and nothing is hidden from a thread: ChatView.tsx is back to upstream's, its FORK.md case and file row are gone, and the roster gate no longer points to the Inbox. CrewRuntimeRequestsSection renders each approval with upstream's ComposerPendingApprovalPanel and ComposerPendingApprovalActions, so provider option warnings and every request kind label match the composer. The question UI and the copied approval choices are removed. An environment is read only while one of its thread shells has hasPendingApprovals: the source atom answers empty for the rest, the 7.5s poll runs only while some approval is pending, and a flag turning on or off triggers an immediate re-read. crewApprovalPollPlan holds that decision and is unit tested. Docs describe seat approvals in the Inbox and the Captain's requests staying in its thread. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
@Jacksondr5 #309 is slimmed to match (746a720):
The docs describe the slimmed behavior, and the PR description has a current-scope summary. CI is running. |
Jacksondr5
left a comment
There was a problem hiding this comment.
Posted by an AI agent on Jackson's behalf.
Approved. Verified by the review panel (Opus 5.5 + Astra), with a live pass on 3c3bee9:
- a real seat approval shows in the Inbox and inline, and answering from the Inbox resumes the seat;
- a stale answer gets 409 with nothing dispatched;
- the Captain's approvals and seat questions stay inline only;
- the poll makes zero calls when nothing is pending;
- upstream's approval panel shows warnings and the permission label.
No upstream files change.
- Known limitation, not a blocker: a thread reports only its newest pending request, so a newer question on a seat hides an older approval from the Inbox until the question resolves. The approval can still be answered inline, and this gets rarer once seats lose their question tools (#325).
- The polling simplification (r4124053858) is optional.
- Merge order: #308 first, then this PR.
|
[Review panel: Opus 5.5 + Astra] Round-two live verification of the seat-approvals-only scope.
The real Crew used a Claude Haiku Captain and seat, both Supervised, against a fresh snapshot of real data. The base and head web clients used the same isolated backend, 1440×1000 viewport and light theme. All 10 focused tests pass. Live permission-kind requests and native provider warnings were NOT RUN: Claude emitted command approvals without these fields. A separately labelled response fixture verified the upstream permission label, warning icon, tooltip and accessible description. Native desktop and mobile were not run. Pending seat approval: base → head. Empty Inbox: base → head. Read held pending; there is no dedicated Crew-request loading indicator: base → head. Stale-answer error: base → head. The seat approval remains inline. The real seat turn resumes after the Inbox approval. Captain approval stays inline. Seat question stays inline. Supplemental UI fixture: permission label and provider warning. The turn resumes after the Inbox approval. |
|
@Jacksondr5 Thanks. #308 and #309 are merged. About the known limitation, where a newer question on a seat hides an older approval: #348, one PR up this stack, already removes seats' native question tools (Claude seats lose |





















Important
#309 is based on #308, so #308 merges first. Neither has migrations or ordering against the other Crews PRs.
Scope now: seat approvals only (Jackson, 2026-09-26)
The sections below describe the original scope and have been narrowed; this summary is current.
ChatView.tsxchange, its FORK.md case,useJ5CrewRoutedRequests/withoutInboxRequests, and the "waiting in your Inbox" note are gone. A seat approval shows both inline and in the Inbox, and a stale Inbox answer gets a 409.ComposerPendingApprovalPanelandComposerPendingApprovalActions, so provider warnings and the "permission" label show.hasPendingApprovals, so there are zero requests when nothing is pending.Problem
A Captain's or seat's provider approvals and questions render only inline in that thread's composer (
ChatViewfeeds every pending request toChatComposer), so I only see them if I open that thread, and the Crew stalls (#264). The Inbox and bell showed agent asks and Crew seat requests only.What I changed
packages/client-runtime/src/j5/http.tsandstate.ts:listCrewRuntimeRequestsandrespondCrewRuntimeRequest, plus a query atom family and a command, polled every 7.5 seconds like Crew gates.apps/web/src/j5/state.ts:crewRuntimeRequestSourcesAtom, read on every connected environment.apps/web/src/j5/crew/crewRuntimeRequests.logic.ts(new):mergeCrewRuntimeRequestSources,inboxRequestIdsForThread,withoutInboxRequests, andinboxBadgeCount.apps/web/src/j5/crew/crewRuntimeRequestsClient.ts(new): the answer call, the forced refresh, the shared poll, anduseJ5CrewRoutedRequests.apps/web/src/j5/crew/CrewRuntimeRequestsSection.tsx(new): the Inbox's "Crew agent requests" section. Each item names its Crew and seat (or Captain) and links to the thread. Approvals show the provider's choices, or Approve and Decline by default; questions reuse upstream'spendingUserInput.tshelpers so answers have the composer's shape.HumanInboxPage.tsxmounts the section and counts it;HumanInboxBell.tsxcounts it throughinboxBadgeCount.apps/web/src/components/ChatView.tsx(upstream, FORK.md case 46): the derived memo is renamedproviderPendingRequestsand passed throughuseJ5CrewRoutedRequests, whose result keeps the namependingRequests.CrewRosterGate.tsx: shows "A request from this agent is waiting in your Inbox" with a link when the Inbox holds requests for the thread; the roster card is unchanged.Screenshots are from an isolated dev server on a copy of my data. The fixture Crew "Release Crew" has the Captain's thread holding a pending question and a builder seat holding a pending command approval. Every thread in the copy points at a provider instance that doesn't exist, so nothing could start a turn.
Seat thread, before (the approval inline) → after (the note):
Captain thread, before (the question inline) → after:
Inbox, before → after (bell: "2 open"):
Answering with no live provider session is refused, and the request stays listed:
The pass turned up two fixes, both in
bcef3054c1: with no provider options, the Inbox offered only Approve and Decline while the composer offers four choices, so it now uses the composer's defaults; and the thread note sat on the composer's edge.Why this shape
The thread hides exactly the request ids the Inbox currently lists for that thread on that environment. So a request the Inbox hasn't read yet, or can't read on a server without #263's route, stays inline. A prompt is never hidden from both places, and the thread doesn't need its own "is this a Crew thread" check. Putting the note in
CrewRosterGate, which ChatView already mounts, keeps the upstream touch to one hook. The upstream approval and question panels are untouched.Invariants
withoutInboxRequestsreturns the same object when no ids match).rosterGatesForThreadis unchanged.Surfaces
packages/contracts)ChatView.tsx, recorded as FORK.md case 44.docs/user/personas.md.Out of scope
j5/main.Upgrade and data
None.
Verification
crewRuntimeRequests.logic.test.tscovers:vp test run apps/web/src/j5/crew apps/web/src/j5/a2a: 245 passed.ChatView.logic.test.ts: 125 passed.set-state-in-effectwarning inHumanInboxPage.tsx.Review focus
useJ5CrewRoutedRequestsinChatView:activeThreadIdis passed even for drafts, which have no Inbox requests. Confirm nothing downstream depends onpendingRequestsidentity changing only with the projection.CrewRuntimeRequestsSectionhandles multi-question requests all at once; check it against the composer panel's behavior.Closes #264
Claude Opus 5.5 via Claude Code
🤖 Generated with Claude Code