OMP Workbook

Read the source. Follow the evidence.

Review Desk: a native panel and portable dialogs

Imani’s standard editor works in both terminal and RPC review flows. Now she wants a compact local panel for quickly accepting or rejecting a long note.

Her obstacle is portability. A terminal component is not automatically a remotely inspectable form.

She keeps the domain tool and standard dialogs, then adds the panel as an optional TUI presentation.

Milestone: open a focused native overlay

Human OMP slash command—TUI only:

Review Desk: a native panel and portable dialogs · source excerpt 1; read surrounding instructions
/review-desk overlay

The supplied ReviewPanel supports:

  • Up/Down to scroll;
  • a to accept locally;
  • r to reject;
  • Escape to cancel.

The overlay does not edit the note. Accepting from it retains the existing text.

The body shows an eight-line scrolling window. Text rows are bounded to the smaller of the available width and 100 columns.

Exact excerpt—untrusted text handling in panel.ts:

Review Desk: a native panel and portable dialogs · source excerpt 2; read surrounding instructions
export function safeText(text: string): string {
  return replaceTabs(Bun.stripANSI(text)).replace(/[\u0000-\u0008\u000b-\u001f\u007f-\u009f\u202a-\u202e\u2066-\u2069]/g, "");
}

The note is data. It is not trusted ANSI styling, terminal control, clipboard control or bidirectional layout instruction.

Inspect progress

Observed:

  • The loader-registered expanded custom renderer was checked at widths 0, 1, 4, 24, 80 and 160.
  • Every rendered row stayed within the applicable bound.
  • Injected control sequences were removed.
  • Real controller/TUI focus dispatch through a terminal emulator accepted the overlay.
  • Cleanup hid and disposed it.
  • The surrounding composer text remained unchanged.
  • Aborting a custom UI signal rejected the promise and removed the overlay.

This was real controller and terminal-emulator behavior with a surrounding mode fixture. It was not a physical-terminal visual audit or a full Seed Desk composer smoke.

Exercise: open the overlay, scroll, then Escape.

Checkpoint: the panel closes; the domain records a cancelled review. An externally aborted presentation caused by revocation/navigation instead must not commit to another branch.

Choose semantic dialogs before custom controls

The portable baseline is:

MethodResultCancellation distinction
select(title, options, dialogOptions?)Selected label, even for an option objectundefined on dismissal/cancellation
confirm(title, message, dialogOptions?)BooleanDecline and cancellation both resolve false
input(title, placeholder?, dialogOptions?)Textundefined means no answer; an empty string is a separate value
editor(title, prefill?, dialogOptions?, editorOptions?)Multiline textundefined means cancelled
Optional askDialog(questions, dialogOptions?)A structured ask resultCan be cancelled, submitted, or redirected to chat

input’s second argument is a placeholder, not an initial document. editor’s second argument is the prefill. Its fourth argument may set promptStyle.

Feature-detect askDialog; do not assume it exists because hasUI is true.

Rich ask data

A rich ask question contains:

  • id: stable question identity;
  • question: full question text;
  • optional header;
  • options;
  • optional multi;
  • optional zero-based recommended.

Each option has label, optional description, and optional preview.

A submitted result has kind: "submit" and ordered results. Each result item contains:

  • id, question;
  • options as labels;
  • multi;
  • selectedOptions;
  • optional customInput, note, timedOut.

kind: "chat" means the user chose to discuss the question. It is not cancellation and it is not an answer.

ACP’s rich ask adapter can produce recommended fallback answers marked timedOut: true. A permission system must not interpret such a fallback as explicit consent.

Descriptions and previews are presentation capabilities, not a guarantee that every protocol adapter transmits them. For example, the supplied ACP basic select translates labels to an enum; its rich ask path carries richer descriptions.

Dialog options are not universally portable

ExtensionUIDialogOptions includes all of the following:

FamilyMembersUse
Cancellation and timingsignal, timeout, onTimeout, onTimeoutStart, onTimeoutResetCancel work and observe a host-managed timeout
Initial selector presentationinitialIndex, outline, helpTextPosition and explain a TUI selector
Selector actionsonLeft, onRight, onExternalEditorTUI-specific callbacks
Selection markersselectionMarker, checkedIndices, markableCountRadio/checkbox presentation for leading options

Timeouts are milliseconds. timeoutStartsOnPresentation is an optional UI capability: the TUI sets it true so a queued selector’s timeout need not expire before it appears.

Do not infer that every option applies to every method. In particular, the supplied standard multiline editor path honors cancellation but does not implement the same dialog timeout plumbing as the selector/input paths.

RPC is semantic UI, not a terminal

The current wired RPC extension context reports hasUI: true and mode: "rpc". This outranks the stale type comment saying RPC has no UI.

The protocol uses requests and correlated responses.

RPC client input—request the human review command:

Review Desk: a native panel and portable dialogs · source excerpt 3; read surrounding instructions
{"type":"prompt","id":"review-1","message":"/review-desk review"}

The client must continue reading output, present the emitted editor/selector requests, and reply using each request’s actual ID. It must not wait for the review to finish before processing the dialog requests needed to finish it.

Illustrative RPC response shapes—dialog-1 represents an ID received from the server, not a reusable workbook ID:

Review Desk: a native panel and portable dialogs · source excerpt 4; read surrounding instructions
{"type":"extension_ui_response","id":"dialog-1","value":"Accept locally"}
Review Desk: a native panel and portable dialogs · source excerpt 5; read surrounding instructions
{"type":"extension_ui_response","id":"dialog-1","confirmed":true}
Review Desk: a native panel and portable dialogs · source excerpt 6; read surrounding instructions
{"type":"extension_ui_response","id":"dialog-1","cancelled":true}

Use the appropriate variant, not all three.

RPC specifics:

  • Select sends string options; optional optionDetails align descriptions by position.
  • Select returns a label, not an index.
  • Select, confirm and input transmit timeout information.
  • Editor transmits title, prefill and optional promptStyle; it has no timeout field or local editor timeout scheduler in this adapter.
  • Aborting an active dialog emits method: "cancel" with targetId equal to the original request ID.
  • Pre-aborted signals suppress presentation.
  • Disconnect rejects pending and future requests.
  • Local select/confirm/input timer expiry can settle without a cancel frame, so clients must honor the transmitted timeout too.

RPC supports fire-and-forget notifications, status, string-array widgets and editor-text requests. Title emission is opt-in through PI_RPC_EMIT_TITLE=1.

It does not serialize TUI component factories. custom() returns without invoking the factory. Component widgets, terminal listeners, custom editor replacement and autocomplete factories are unsupported there.

Passive presentation is not persistence

UI methodUseful roleCurrent implementation boundary
notifyBrief result or warningNot a durable domain record
setStatus(key, text)Small named status indicatorClear with undefined
setWorkingMessage(message?)Streaming activity wordingTUI support; RPC/ACP inert
setWidget(key, content, options?)Summary above/below editorTUI supports strings or factories; RPC supports strings only
setTitleTerminal/window titleNot the persisted session name
setFooter, setHeaderAdvertised component replacement surfacesNo-op in the supplied TUI controller, as well as RPC/ACP
custom(factory, options?)Focused terminal componentGuard with ctx.mode === "tui"

For string widgets, the TUI takes the first ten supplied strings and adds a truncation notice when necessary. This is not a promise that arbitrary long strings wrap into only ten terminal rows.

ExtensionCustomOptions contains:

  • overlay;
  • static or lazy overlayOptions;
  • onHandle, receiving an overlay handle;
  • signal.

A component should implement render(width) and invalidate(), optionally input handling and dispose(). Cleanup must be idempotent. Review Desk’s panel becomes inert after disposal.

What changes next?

If Imani needs screen-reader-friendly or remotely operated review controls, she should extend the semantic domain interface or use host-supported forms. A custom terminal drawing does not become accessible merely because it is visible.

review_desk inspect/query/act is the agent-facing interface. The panel is one human-facing view of that interface.

Source, snapshot 2026-08-29: packages/coding-agent/src/extensibility/extensions/types.ts, UI interfaces; packages/coding-agent/src/modes/controllers/extension-ui-controller.ts, showHookCustom, #presentDialog; packages/coding-agent/src/modes/rpc/rpc-mode.ts; linked Review Desk panel.

Extensions inside those boundaries · Source chapter: extensions/review-desk-a-native-panel-and-portable-dialogs. Original evidence remains scoped to its recorded snapshot.

Read this chapter as Markdown

Your lesson ticks

A self-reported reading checklist, not proof of real OMP behavior. Only these ticks are saved in this browser. Reading a milestone does not resume, fork, reset or export a session.

Chapters I have worked through
Start here 1
Sessions, resets, and reviewable history 19
Memory and reusable knowledge 14
Tangent work and live control 17
Tool permissions and approvals 15
Extensions inside those boundaries 23
Connections and next steps 8
0 of 97 checked

Checklist saving needs JavaScript and available browser storage.