Skip to content

Invite an agent into the room: one checkbox, read-only or full - #42

Merged
udaychandra merged 1 commit into
mainfrom
agent/sail-room-invite
Aug 17, 2026
Merged

Invite an agent into the room: one checkbox, read-only or full#42
udaychandra merged 1 commit into
mainfrom
agent/sail-room-invite

Conversation

@udaychandra

Copy link
Copy Markdown
Contributor

Spec: sail-room-invite. Sail counterpart: standardapplied/sail#194 (the API, roles, and launch lanes).

The room header gains an Invite action (wide button row and the compact Actions menu, every status — a draft room is exactly where brainstorming happens). The dialog asks for agent, optional model, and the one Full checkbox:

  • The server declares each agent's mode support (GET /v1/agents) and the dialog renders exactly that: with Full unchecked, an agent without a harness-enforced read-only session is greyed with the server's reason as the option description; checking Full lifts it. No client-side guessing — the reason string is the seam-declared one the launch gate also refuses with.
  • Version skew: if the agents endpoint is missing (older sail), the agent field falls back to free text and the server rules on submit.
  • Refusals hold the dialog open and render the server's words verbatim through a pure mapInviteOutcome (message — action): the reservation vocabulary on 409, the mode refusal on 400, policy refusals on 403. A launch closes and toasts the invited principal — and, for a full invite, the snapshot label it paid with.
  • snapshot_created joins EVENT_REGISTRY as a lifecycle row and eventNarration learns data.label, so the full invite's pre-launch snapshot renders in the room timeline the moment it is taken (it arrives with the spec id over SSE). The invite run's presence rides the existing per-spec presence chip.

No new dependencies. bun test (474) and bun run typecheck green. Behavior tests: InviteDialog.test.tsx (reported modes + greyed reason, Full lifting the greying, submit payloads, 409 held-open verbatim refusal, endpoint-missing fallback, read-only credential gate), inviteOutcome.test.ts, specTimeline.test.ts (snapshot row + label narration), SpecRoom.test.tsx (live snapshot_created renders as a system row naming the label).

The room header gains an Invite action (wide row and compact menu, every
status — a draft room is exactly where brainstorming happens). The dialog
asks for agent, optional model, and the one Full checkbox; the server
declares each agent's mode support via GET /v1/agents and the dialog
renders exactly that — an unsupported read-only combination is greyed
with the server's reason, lifted when Full is checked. When the agents
endpoint is missing (an older sail), the agent field falls back to free
text and the server rules on submit.

Refusals hold the dialog open and render the server's words verbatim
(the reservation vocabulary on 409, the mode refusal on 400) through a
pure mapInviteOutcome; a launch toasts the invited principal and, for a
full invite, the snapshot label it paid with.

snapshot_created joins EVENT_REGISTRY as a lifecycle row and
eventNarration learns data.label, so the full invite's pre-launch
snapshot renders in the room timeline the moment it is taken — rollback
is one visible step.
@udaychandra
udaychandra merged commit 2d8e9aa into main Aug 17, 2026
2 checks passed
@udaychandra
udaychandra deleted the agent/sail-room-invite branch August 17, 2026 16:48
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