Permission UI Redesign Plan (Inline, Contextual Approval)¶
Objective¶
Redesign permission UX from a standalone full-screen selector to an inline, contextual approval card rendered directly in the normal output stream below tool activity.
This should make it easier to understand what the LLM is trying to do in context, while preserving existing permission safety and blocking semantics.
This plan does not implement edit_file now. It prepares the permission UI architecture so a future edit_file tool can integrate diff-first review without additional UI redesign.
Current Problem¶
Today, permission requests switch the REPL into a dedicated permission mode with a separate screen. This causes:
- Context switch away from tool output/transcript
- Lower visibility of what operation triggered the prompt
- No room for richer inline context (for example edit diff)
- Session-approved fast path bypasses the permission UI entirely
Desired UX¶
Baseline behavior¶
- Tool emits start/output as usual
- If permission is needed, show an inline approval card right below relevant tool output
- User approves/denies directly in that inline card using keyboard controls
- Decision status appears inline under the same card
- Tool continues or aborts based on user decision
Session-approved behavior¶
For existing tools, keep current behavior by default.
The redesign should support an optional future mode where a tool can request a visible inline review card even when session-approved (needed later for edit_file diff previews).
Scope¶
In scope¶
- Inline permission-card rendering in transcript/viewport
- Keyboard interaction for pending permission card
- Card structure that can carry optional preview payloads (for future diff or other previews)
- Tests for ordering, interaction, and resolution flow
Out of scope (for this phase)¶
- Mouse-driven selection UI for permission cards
- Multi-card simultaneous approval UI (we can queue requests)
- Fancy collapse/expand animations
- Rich side-by-side diff layout
- Implementing
edit_filetool behavior
High-Level Design¶
1. Event-driven permission rendering¶
Treat permission requests like stream events, similar to tool start/end.
Introduce UI event concepts:
permission_request_startpermission_request_update(optional, future)permission_request_resolved
Each request has a stable request_id and references:
- tool name
- operation
- path/resolved path
- dangerous flag
- optional
previewpayload (e.g. diff text in future) - status (
pending,allowed,allowed_session,denied,auto_allowed_session)
2. Inline permission card segment¶
Render permission request as a stream segment in normal viewport flow:
- Header: "Permission required" (or "Edit review")
- Metadata: tool, operation, path, resolved path
- Optional diff preview (truncated)
- Choice rows:
Allow,Allow for this session,Deny(dangerous =>Allow,Deny) - Hint row with keyboard controls
Resolved cards remain in transcript with final status line.
3. Input routing model¶
Keep normal REPL view active; no separate permission mode.
When there is a pending permission request:
- Route
up/down/enter/escto card selector - Keep
pgup/pgdown/home/endfor transcript scrolling - Ignore standard input submission (
enter) until request is resolved
When no pending request exists, normal key behavior applies.
4. Blocking semantics remain unchanged¶
Tool execution still blocks on permission requester response channel. UI redesign should not change safety semantics.
Flow:
- Tool requests permission
- Requester publishes request event for rendering
- Tool waits for response
- User decision resolves request
- Requester returns decision to tool
5. Future compatibility flow (for edit_file later)¶
Design the requester/rendering contract so a future tool can opt into one of two behaviors when session-approved:
- Silent fast path (current behavior)
- Visible auto-approved card (future
edit_filerequirement)
The UI layer should support both without structural changes.
Data Model Changes¶
Permission request model¶
Extend request payload (or introduce a UI-facing wrapper) with:
RequestID stringPreview string(optional, tool-defined)PreviewKind string(optional, examplediff)AutoApproved boolStatus PermissionStatus
PermissionStatus enum:
pendingallowedallowed_sessiondeniedauto_allowed_session
Stream segment model¶
Add segment types:
segmentPermission
Segment stores:
- request metadata
- selector cursor (if pending and interactive)
- resolved status
Implementation Phases¶
Phase 1: Inline rendering foundation¶
- Add permission segment type in streaming/output pipeline
- Add permission card formatter (
formatPermissionCard) - Emit card when permission request is consumed
- Keep existing modal selector temporarily as fallback behind a feature flag
Deliverable: permission requests can be displayed inline in transcript.
Phase 2: Interaction handoff¶
- Remove/disable
permissionSelectormodal path - Route approval keys to pending inline permission card state
- On
enter, send selected choice through requester - On
esc, resolve as deny - Persist resolved card output in transcript
Deliverable: fully functional inline approval interaction.
Phase 3: Edit diff integration¶
- Add generic preview rendering capability in card (type-aware by
PreviewKind) - Add preview truncation rules for long payloads (see limits below)
- Keep styling conservative until a concrete tool integration is implemented
Deliverable: preview-capable inline approval UI ready for future edit_file integration.
Phase 4: Session-approved visibility option¶
- Add an explicit request flag to allow visible auto-approved cards
- Mark status
auto_allowed_session - Do not block for input in this path
Deliverable: optional visible auto-approved path available for future tools.
Phase 5: Cleanup and hardening¶
- Remove obsolete modal permission code paths if unused
- Add regression tests (see test plan)
- Validate keyboard handling with active stream + pending approval
Deliverable: stable, maintainable permission UI architecture.
Preview Rendering Rules¶
To prevent output overload:
- Show max first 120 preview lines by default
- If truncated, append line:
... N more preview lines omitted - Preserve raw preview text model-level and apply styling in view layer
- If
PreviewKindis known (for examplediff), apply kind-specific styling rules
Optional future enhancement: keybinding to expand/collapse full preview.
Error Handling & Edge Cases¶
- Request canceled via context timeout => card resolves as denied/canceled
esckey on pending card => explicit deny- Multiple permission requests arriving quickly => queue and display one active pending card at a time
- If permission request has no resolved path, still render safely with available metadata
- If preview is empty, still render card with metadata and choices
Testing Strategy¶
Unit tests¶
- Permission card rendering (pending vs resolved statuses)
- Preview rendering styles and truncation behavior
- Choice mapping for dangerous vs non-dangerous operations
- Key handling while pending request exists
- Auto-approved card behavior when explicitly requested by tool metadata
Integration/repl tests¶
- Tool output followed by inline permission card appears in correct order
- Selecting allow/deny updates card and unblocks tool execution
- Session-approved visible-card path shows card and continues without extra input
- Existing non-permission interaction still works when no pending request
Regression tests¶
- Existing tools still request permission correctly
- No deadlocks in requester/response channels
- Transcript remains readable with long preview payloads
Migration Notes¶
- Implement behind a temporary feature flag if needed (
inlinePermissionUI) - Run both code paths in tests during transition
- Remove modal path once parity is confirmed and tests are green
Risks and Mitigations¶
-
Risk: Keybinding conflicts with normal input Mitigation: explicit pending-request gate in key router
-
Risk: Transcript clutter from long diffs Mitigation: line cap + truncation message
-
Risk: Request ordering/race issues Mitigation: single active pending request + deterministic queue
-
Risk: Behavior drift for dangerous operations Mitigation: preserve current dangerous-choice set (
Allow,Deny)
Acceptance Criteria¶
- Permission prompts appear inline beneath tool outputs (no standalone permission screen)
- User can approve/deny using keyboard without leaving normal transcript view
- Permission card supports optional tool-provided preview payload without new UI redesign
- Architecture supports optional visible auto-approved cards for session-approved operations
- Tool execution remains blocked until explicit decision except explicit auto-approved path
- Existing tools continue to function with permission system unchanged in behavior
Suggested Follow-up (Optional)¶
After this redesign lands, we can decide whether to standardize informational cards for all session-approved tools (not only edit_file) for complete UX consistency.