feat(auth): allow passive terminal observation - #9791
Conversation
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: unavailable · PR result: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
1b83112 to
77bea7c
Compare
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — This PR adds a new read-only terminal capability across server, shared RPC contracts, web, and mobile clients, while changing terminal authorization and default pairing/session scopes. Its broad runtime surface and authentication-sensitive permission changes require human review. No code changes detected at You can add or adjust custom eligibility rules. Learn more. |
77bea7c to
755a0b0
Compare
755a0b0 to
a7693db
Compare
a7693db to
a9d5aa3
Compare
a9d5aa3 to
12ffc87
Compare
12ffc87 to
c391e46
Compare
c391e46 to
8cf3080
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
Bugbot Autofix is ON, but a cloud agent failed to start.
Reviewed by Cursor Bugbot for commit 8cf3080. Configure here.
8cf3080 to
6deb383
Compare
6deb383 to
43e5909
Compare
2644cae to
b2be98d
Compare
b2be98d to
2de375b
Compare
2de375b to
1e5fbea
Compare
2335ffb to
d975869
Compare
d975869 to
33d5b21
Compare

Watching terminal output currently requires
terminal:operate, which also allows starting shells, sending input, resizing, clearing, restarting, and closing sessions. A client cannot be granted terminal viewing without those controls.Add
terminal:readand a passiveterminal.observestream. Observation reads an existing session's history and live events without spawning, restarting, resizing, writing, or changing its working directory or environment. Retained exited sessions can be observed; missing sessions return an error.terminal.attachkeeps its existing behavior and still requiresterminal:operate.Web, desktop, and mobile use passive observation for read-only grants and disable terminal mutations. Native iOS and Android views guard software and hardware keyboard input, terminal-generated replies, and keyboard focus. Losing operate permission dismisses native input; client callbacks guard input and resize requests too.
Output and metadata subscriptions now require
terminal:read;terminal:operatealone no longer grants those subscriptions. New read-only, standard, and administrative grants include the read scope. Existing grants are unchanged, so clients must explicitly pair again to receive it.Terminal manager tests and ten focused server RPC tests pass. The integrated stack also passes 186 focused web tests and 20 contract, shared, and mobile tests. The manager cases cover history and live output without process changes, observing exited sessions without restarting, and rejecting missing sessions. The RPC cases verify that observers can subscribe while terminal mutations remain denied.
Android development APK builds successfully with the native read-only changes. Web, mobile, and server typechecks passed; Android emulator verification confirms live passive output, no keyboard on tap, and injected input absent from host terminal history.
Android client paired with only
orchestration:readandterminal:read:Model: GPT-6. Harness: Codex.
Note
Add
terminal:readscope for passive terminal observationterminal:readauthorization scope alongside the existingterminal:operatescope, and aterminal.observestreaming RPC backed byTerminalManager.observeStreamthat delivers an existing terminal's snapshot and live events without starting or mutating the processterminal:read, while attach, write, resize, clear, restart, and close still requireterminal:operateterminal:read: input, paste, resize, split, create, and close are disabled or guarded; project-script execution requiresterminal:operate; existing terminal sessions remain selectablereadOnlyview props to iOS and Android terminal modules, suppressing keyboard focus and input events when enabledRPC_REQUIRED_SCOPESin RpcAuthorization.ts moves terminal event and metadata subscriptions fromterminal:operatetoterminal:read; any existing client relying onterminal:read-only tokens for those streams will now succeed where they previously failed, and any client withoutterminal:readwill lose access to event/metadata streams they had underterminal:operatealoneMacroscope summarized 33d5b21.
Note
High Risk
Splits terminal RPC scopes so clients with operate-only tokens lose event/metadata subscriptions unless re-paired with terminal:read; auth and PTY observation paths are security-sensitive.
Overview
Introduces
terminal:readso clients can watch shells withoutterminal:operate. A newterminal.observestream (andTerminalManager.observeStream) returns an existing session’s snapshot plus live output without spawning, restarting, resizing, or writing to the PTY; missing sessions still error.Authorization now maps observe,
subscribeTerminalEvents, andsubscribeTerminalMetadatato read, while attach/open/write/resize/clear/restart/close stay on operate. Pairing adds a “View terminals” scope and includes it in the read-only preset;terminal:operatealone no longer covers event/metadata subscriptions.Web and mobile attach with
observewhen the user only has read scope, gate writes/resizes/opens/splits/scripts, and drivereadOnlyon native surfaces (keyboard, paste, resize RPCs suppressed). Android/iOS expo modules honorreadOnlyon software/hardware input and terminal-generated replies. Web Ghostty setsinput.readOnlyand canresendSizeonce a writable session exists.Reviewed by Cursor Bugbot for commit 33d5b21. Bugbot is set up for automated code reviews on this repo. Configure here.