Review Desk: edit and decide locally
Imani prepares a fictional release note. Her goal is to let a person review the wording before it is treated as accepted. Her obstacle is that “accept” is often confused with “publish.”
She makes a narrower decision: acceptance will be a local status change only. The extension contains no send-to-service or publish operation.
Review Desk is one complete downloadable module set. The milestones below explain its progression; they are not separate downloadable versions.
The project
Files:
- Entry and runtime coordination
- Domain transitions
- Native panel and bounded text
- UI and tool copy
- Fictional release-note fixture
- Story and protocol notes
Terminal shell—launch the complete Review Desk:
omp --no-extensions -e "$EXAMPLES/review-desk/index.ts" --session "$LAB/review-session.jsonl"
The compatible loader resolves the runtime TUI import. If that fails, investigate host/package compatibility rather than replacing panel.ts with an inert mock.
Milestone: inspect without changing the draft
Starting state: fixture text, revision 0, status draft, no agent grant.
Human OMP slash command:
/review-desk show
Model tool arguments—call review_desk:
{"op":"discover"}
{"op":"inspect"}
{"op":"query"}
inspect returns the complete draft, status, revision and authorization status.
query is smaller: revision, status, authorization, whether a dialog is busy, and the extension mode.
Expected query result in a fresh TUI session:
{
"revision": 0,
"status": "draft",
"authorized": false,
"busy": false,
"mode": "tui"
}
The tool duplicates its structured result as JSON text in content, so its machine contract is also model-visible.
show refreshes the status/widget and sends a custom review message. It does not increment the draft revision, but it is not completely journal-inert: the custom message is conversation data.
Observed: the loaded SDK tool exposed discover, inspect, query and act, and refused an unauthorized mutation without changing the draft.
Exercise: is a status widget a substitute for inspect?
Answer: no. The widget is a short human summary. inspect is the supported way to retrieve the actual domain state.
Know the mode before opening a review
The same property can exist in every mode while doing useful work in only some of them.
| Host | What Review Desk can use | Degraded behavior |
|---|---|---|
| TUI | Standard editor/selector dialogs, status, string widget, custom message renderer and native overlay | Requires real terminal presentation and input |
| RPC | Editor, confirm and labeled select requests answered by a connected client; passive status/widget frames | No native component factory or synchronous composer read |
| ACP | The supplied ACP adapter exposes semantic forms and initializes extensions with mode: "rpc" | Form support depends on negotiated elicitation.form; terminal presentation remains unavailable |
| Default print/JSON context | Read tools and explanatory custom messages | The example refuses its interactive review, overlay and delegation paths |
Source-backed ACP nuance: the ACP extension context can report UI availability even when form elicitation is unsupported. Its dialog methods then return defaults. Because Review Desk accepts mode: "rpc", an ACP review with no form capability can receive undefined from editor() and record a cancelled review outcome. Delegation receives false and grants nothing.
That differs from the explicit print-mode guard, which changes neither draft nor authorization. The recorded Review Desk protocol scenario exercised RPC, not a Review Desk-specific ACP client flow.
Milestone: edit and accept locally
Imani asks for a review rather than directly replacing the draft.
Human OMP slash command:
/review-desk review
The standard flow is:
- Open a multiline editor with sanitized draft text.
- Edit the note.
- Submit the editor.
- Choose Accept locally, Reject, or Cancel.
In the TUI multiline editor, Enter inserts a newline. Submit with the editor’s configured follow-up chord—by default Ctrl+Q or Ctrl+Enter. The core editor also exposes its normal Ctrl+G external-editor shortcut; this extension does not invoke an external editor programmatically.
For the following checkpoint, use this text:
Text to enter in the review editor:
Release 1.4
A human-reviewed local note. Nothing is published.
Choose Accept locally.
Observed RPC checkpoint: the edited text became revision 1, status accepted, with authorized: false. The selector carried labels and aligned descriptions. Status and string-widget frames were emitted.
The original release-note.txt fixture was not overwritten. The draft is reconstructed from custom session entries named workbook-review-desk-state.
Milestone: rejection and cancellation are distinct outcomes
Imani next tries an edit she does not like. Rather than hiding what happened, the domain records a review outcome while preserving the pre-dialog text.
| Human outcome | Stored text | Status | Revision |
|---|---|---|---|
| Accept locally | Edited text | accepted | Increases once |
| Reject | Original pre-dialog text | rejected | Increases once |
| Escape from editor | Original pre-dialog text | cancelled | Increases once |
| Cancel or dismiss selector | Original pre-dialog text | cancelled | Increases once |
Observed: after the accepted revision, rejection produced revision 2, and editor cancellation produced revision 3. Both retained the accepted note’s text.
This is an important vocabulary distinction:
- Cancel a review: record that the review was cancelled; revision increases.
- Abort presentation because authority was invalidated or the session moved: do not record a review on a different branch.
- Revoke agent authority: leave draft text, status and revision unchanged.
Blank or over-12,000-character replacement text fails domain validation. The tool additionally constrains its text parameter. Rejection and cancellation cannot be used to smuggle replacement text through the domain function.
Exercise: after accepting revision 1, open the editor, replace all text, submit, then choose Reject. Which text remains?
Answer: the pre-dialog revision-1 text, now with status rejected and revision 2.
Milestone: authorize one agent action on one revision
Imani wants the agent to shorten the draft once. She does not want a permanent permission recovered from the transcript.
Human OMP slash command:
/review-desk delegate
Confirm the dialog. The grant is:
- in memory only;
- associated with the current session ID;
- associated with the inspected numeric revision;
- consumed by a successful mutation.
The tool cannot grant itself permission.
If you followed the accepted/rejected/cancelled sequence and inspect reports revision 3, the following is an exact next action.
Model tool arguments—call review_desk only after checking that the current revision is 3 and the human grant is active:
{
"op": "act",
"action": "revise",
"expectedRevision": 3,
"text": "Agent revision, still local."
}
Observed result:
{
"revision": 4,
"status": "draft",
"text": "Agent revision, still local.",
"authorized": false,
"published": false
}
If your revision differs, inspect and use that revision instead. Never substitute a guessed counter.
Other agent actions are accept, reject and cancel. They preserve the inspected text and do not accept a text argument. To change text, use revise.
A stale action fails without mutation. A failed stale attempt does not consume the valid grant; a successful action does. A second successful attempt requires another human grant.
An open dialog blocks tool mutations with Review dialog open. Nothing changed.
Milestone: revocation defeats a late positive answer
The first implementation of revocation had a classic asynchronous bug: clearing the current grant did not invalidate a confirmation already awaiting a response. A late positive answer could restore authority.
Imani’s decision changes from “clear the value” to “retire the pending decision.”
Exact excerpt—authority invalidation in Review Desk’s entry:
function invalidateAuthority(): void {
generation++;
grant = undefined;
pending?.abort();
}
pi.on("session_before_switch", invalidateAuthority);
pi.on("session_before_branch", invalidateAuthority);
pi.on("session_before_tree", invalidateAuthority);
The handler remembers the generation before awaiting the dialog.
Exact excerpt—the delegation result is accepted only in the same generation:
if (verb === "delegate") {
const approved = await ctx.ui.confirm(copy.grantTitle, copy.grantMessage, { signal: controller.signal });
if (epoch !== generation) return;
grant = approved ? { sessionId: ctx.sessionManager.getSessionId(), revision: state.revision } : undefined;
present(ctx, state);
ctx.ui.notify(approved ? `One agent change authorized for revision ${state.revision}.` : "No agent change authorized. Draft unchanged.");
return;
}
Human OMP slash command:
/review-desk revoke
Observed correction: revoking during a real pending RPC confirmation emitted a matching cancel frame. A delayed positive response to the retired request did not restore authority. The draft was unchanged, and busy became false after the pending handler settled.
The same invalidation machinery handles session switching, branching, tree navigation and shutdown. A same-session reload that uses the switch path also invalidates authority.
Honest limits
- The numeric revision is a domain counter, not Seed Desk’s session-plus-entry-ID token.
- Navigation hooks invalidate the grant so sibling revisions cannot retain it through the supported flow.
- This is not protection against arbitrary in-process code rewriting domain entries.
stateFor()skips stored entries that failisReviewState(). Unlike Seed Desk, it does not fail closed on every malformed matching snapshot. Treat this as a small teaching fixture, not a complete corruption-recovery system.
Exercise: revoke while a delegate confirmation is pending, then have the client answer the old request positively.
Checkpoint: no authorization, no draft mutation, and no revived dialog.
Source, snapshot 2026-08-29: linked Review Desk files; packages/coding-agent/src/modes/rpc/rpc-mode.ts, requestRpcDialog, requestRpcEditor; packages/coding-agent/src/modes/acp/acp-agent.ts, createAcpExtensionUiContext, #configureExtensions.
Extensions inside those boundaries · Source chapter: extensions/review-desk-edit-and-decide-locally. Original evidence remains scoped to its recorded snapshot.