Repository navigation
Suggest the room: a department offers, the founder convenes - #250
Merged
Merged
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A department in Ask was told to say 'this one needs Marketing too' and the founder had no way to act on it. suggest_room is offered only on a turn that answers as a known department; coerceRoomOffer keeps 2-4 known keys (deduped, capped), clips question/why, and drops a bad offer rather than failing the turn. It resolves beside remember_fact and rides the done frame as room_offer. An offer costs nothing until the founder presses it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pressing 'Bring Finance + Sales in' must give that room; otherwise the router could still answer single_agent and the escape hatch would discard it, so the button would visibly do nothing. applyRequestedAgents runs after intake: 2-4 routable departments (not chief_of_staff, the red team or product) force multi_agent with exactly those, keeping devils_advocate if the router named it and the router's real_question. Fewer than two, or no field, returns the routing object untouched. validateRunPayload 400s a non-string-array. The SSE contract (the authority) records both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ChatDoneAction.roomOffer decodes the done frame's room_offer; the room request gains an optional agents list that is not encoded when nil, so every existing run is byte-identical on the wire. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A department's room_offer lands on its reply under the Noted chip as 'Bring Finance + Sales in ->' with its reason. acceptRoomOffer maps the native keys to room agent ids (RoomInvite, pinned key-for-key against ROOM_AGENT_FOR) and convenes through sendChat(convenesRoom:requestedAgents:) -> startVirtualCompanyRun -> VirtualCompanyRequest.agents. It sets its own used flag before the await so it convenes once, and is disabled while a turn is in flight. Named RoomInvite because RoomOffer is already the composer's convene control. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review finding: applyRequestedAgents overrode only decision and agents, so
the panel showed '✗ Sales — not a pricing question' under NOT IN THE ROOM
while Sales sat in the room, gave Sales no ✓ line, and kept a 'Missing:'
ask on a room that was running. Picked agents now leave excluded, get a
reason ('Asked for by the founder.') when the router gave none, and
missing_info is cleared.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In the app no card ever appeared. Traced layer by layer: the app sent dept_key=fin, the bundled sidecar had the tool, claude's init listed mcp__codepet__suggest_room with the MCP server connected — and the model never called it. Replaying the app's exact request: 3/3 offers without a linked folder, 0/3 with one (Read/Glob/Grep on). The role framing told it to SAY 'this one needs Marketing too', so with the folder attached it did exactly that, in prose. The role block now says to give its own answer AND call suggest_room when another department's interest pulls the other way. Same request, folder linked: 4/4 offers (fin+mkt+sales). A one-department question (runway from burn and cash): 0/3 offers — it does not over-trigger. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In the app the reply said 'press the room button above'; the card draws below the reply, the same slip the draft cards had on build 10. Both the tool description and the role block now say it appears below. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Collaborator
Author
|
Checked in the running app at
What testing found, and fixed:
jest 1089/1089. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Step 3 of "one founder runs the whole company", after #247 (a department answers as itself) and #248 (it keeps a notebook).
What
Since #247, a department answering in Ask is told to say "this one needs Marketing too", but the founder had no way to act on that. Now the department can offer to bring the others in, and one press convenes that room.
suggest_room. It is offered only on a turn that answers as a known department.coerceRoomOfferkeeps 2–4 known keys, removes duplicates and caps the list, and clipsquestion/why. An invalid offer is dropped without failing the turn. The offer rides the done frame asroom_offerand costs nothing until the founder presses it.sendChat(convenesRoom:requestedAgents:), which setsVirtualCompanyRequest.agents. The card is disabled while a turn is in flight and cannot be used twice.applyRequestedAgents). With 2–4 valid departments the routing is forced tomulti_agentwith exactly those, so the room never takes the escape hatch.chief_of_staff, the red team and Product can't be requested. The router'sreal_questionis kept, and so isdevils_advocateif the router named it. The routing panel is made consistent with the forced room: picked departments leave "not in the room", each gets a ✓ reason, and there is no "Missing:" line. Withoutagents, behaviour is unchanged.agentsfield and the rule that a founder-picked room never escapes.Spec:
docs/superpowers/specs/2026-10-09-suggest-room-design.md· Plan:docs/superpowers/plans/2026-10-09-suggest-room.mdVerified
room_offeron the done frame,validateRunPayload, andapplyRequestedAgents, including a run whose router returnssingle_agentbut which still convenes the requested room.RoomOfferWireTests(decode, andagentsomitted when nil) andRoomInviteTests(the offer lands on the reply; one press convenes exactlyfinance+saleson the offer's question, and a second press does nothing). The existingRoomOfferTests,CompanyStoreChatTests,CompanyStoreVirtualCompanyTestsandApprovalParityTestspass.Deferred minors
toString) get pastin ROOM_AGENT_FOR. A model would have to emit one.ChatTailActionwas not updated (harmless).🤖 Generated with Claude Code