You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The agent-driven policy approval loop landing in #1097 / #1528 ships a single-sandbox CLI/TUI review flow as the locked MVP. Reviewers operating across multiple sandboxes today must either watch the TUI per-sandbox or poll GetDraftPolicy per sandbox via gRPC.
This is workable for a developer running one or two sandboxes, but blocks two patterns we are already seeing from real customer adoption:
Platform teams running cohorts of agents (e.g., 20-team rollouts) where a small reviewer pool needs a single inbox view across the fleet instead of N tabs.
Web/Slack approval adapters built on top of the gRPC contract — without a streaming or aggregated surface they have to long-poll per sandbox to keep an inbox UI live.
The #1062 umbrella explicitly lists "Multi-sandbox approval inbox" under Follow-Up Themes and "Multi-sandbox push inbox / WatchProposals" as an MVP non-goal. This issue promotes that follow-up theme into a discrete tracking item.
Proposed Design
Add an aggregated proposal inbox surface to the existing gRPC service so reviewers see one prioritized stream across all sandboxes they have access to.
Two surfaces:
ListProposalInbox — unary RPC. Aggregates pending (and optionally approved/rejected) draft chunks across sandboxes the caller has config:read for, with pagination and filtering (sandbox label selector, status, age, has-finding). Returns the same DraftChunk shape used by GetDraftPolicy plus a sandbox_ref field so the client can disambiguate.
WatchProposalInbox — server-streaming RPC. Emits inbox-level deltas (chunk added, status changed, reloaded) so a long-lived UI does not have to poll. Resumable via an opaque cursor so disconnects do not require a full re-list.
Both RPCs reuse the existing RBAC model (caller's config:read set defines visibility; admin role required for write RPCs which remain per-chunk and per-sandbox). Both reuse the existing DraftChunk, validation_result, and audit shapes — no new schema beyond the inbox envelope and the cursor.
CLI surface: extend openshell rule get with --all-sandboxes and add openshell rule watch as a stream consumer for terminal use. TUI: extend the existing SandboxDraft pane into a Dashboard-scope inbox tab as a follow-up; out of scope for this issue beyond defining the contract.
Alternatives Considered
Per-sandbox long-polling from clients. Workable for small N but does not scale to fleet review and produces N times the gateway load. Forces every partner-built approval UI to reinvent aggregation.
Push to external webhook/Slack from the gateway. Couples the gateway to specific transport adapters and pushes auth/retry concerns into the core. Better implemented as a partner adapter on top of WatchProposalInbox.
In-place expansion of GetDraftPolicy to accept sandbox_id=*. Conflates the per-sandbox and fleet shapes, weakens RBAC scoping in a single RPC, and gives no path to streaming.
Agent Investigation
Confirmed the loop is single-sandbox by design today: `crates/openshell-server/src/grpc/policy.rs` exposes `GetDraftPolicy`, `ApproveDraftChunk`, etc., all scoped to one sandbox.
Confirmed in OpenShell Agent-Driven Policy Management #1062: "Multi-sandbox push inbox / `WatchProposals`" is an explicit MVP non-goal and "Multi-sandbox approval inbox" is listed under Follow-Up Themes.
TUI (`crates/openshell-tui/src/sandbox_draft.rs`) ties inbox state to a specific sandbox screen; no Dashboard-scope inbox exists.
gRPC service contract (`proto/openshell.proto`) is the natural extension point; streaming RPCs are already used elsewhere in the service.
Problem Statement
The agent-driven policy approval loop landing in #1097 / #1528 ships a single-sandbox CLI/TUI review flow as the locked MVP. Reviewers operating across multiple sandboxes today must either watch the TUI per-sandbox or poll
GetDraftPolicyper sandbox via gRPC.This is workable for a developer running one or two sandboxes, but blocks two patterns we are already seeing from real customer adoption:
The
#1062umbrella explicitly lists "Multi-sandbox approval inbox" under Follow-Up Themes and "Multi-sandbox push inbox /WatchProposals" as an MVP non-goal. This issue promotes that follow-up theme into a discrete tracking item.Proposed Design
Add an aggregated proposal inbox surface to the existing gRPC service so reviewers see one prioritized stream across all sandboxes they have access to.
Two surfaces:
ListProposalInbox— unary RPC. Aggregates pending (and optionally approved/rejected) draft chunks across sandboxes the caller hasconfig:readfor, with pagination and filtering (sandbox label selector, status, age, has-finding). Returns the sameDraftChunkshape used byGetDraftPolicyplus asandbox_reffield so the client can disambiguate.WatchProposalInbox— server-streaming RPC. Emits inbox-level deltas (chunk added, status changed, reloaded) so a long-lived UI does not have to poll. Resumable via an opaque cursor so disconnects do not require a full re-list.Both RPCs reuse the existing RBAC model (caller's
config:readset defines visibility; admin role required for write RPCs which remain per-chunk and per-sandbox). Both reuse the existingDraftChunk,validation_result, and audit shapes — no new schema beyond the inbox envelope and the cursor.CLI surface: extend
openshell rule getwith--all-sandboxesand addopenshell rule watchas a stream consumer for terminal use. TUI: extend the existingSandboxDraftpane into a Dashboard-scope inbox tab as a follow-up; out of scope for this issue beyond defining the contract.Alternatives Considered
WatchProposalInbox.GetDraftPolicyto acceptsandbox_id=*. Conflates the per-sandbox and fleet shapes, weakens RBAC scoping in a single RPC, and gives no path to streaming.Agent Investigation
Related