@andrewhmir/dsh-plan-review — read the whole plan before you approve it
An unofficial community plugin for DeepSeek Harness (DSH). Repository: https://github.com/andrewhmir/dsh-plan-review. It removes one specific piece of friction in the superpowers workflow:
The agent asks you to approve a plan. The question card shows
path: C:\ws\.superpowers\plans\feature.mdand two buttons — so you open the markdown file by hand just to find out what you are approving.
With this plugin installed, that question takes over the composer and renders
the complete plan inline, with Accept plan / Revise plan at the top and
highlight → comment on any passage. You decide with the plan on screen.
What it does
| property | behavior |
|---|---|
| trigger | an ask_user_question request whose single question header starts with [plan-review] |
| presentation | composer takeover: sticky decision header, full plan markdown, scrollable body, comment rail |
| plan source | path: <absolute .md> on the question's first line, read through the plugin's own host route; without a path, the question text itself is the plan |
| comments | select text in the plan → Add comment; each comment anchors to the quoted passage, is editable/deletable, and can be located again |
| accept | answers with the question's own accept label; refused while comments or an overall note exist, so feedback is never silently dropped |
| revise | sends {decision, comments, note} back in the answer's custom field; refuses locally when there is no feedback yet |
| drafts | comments and the overall note are kept in this browser tab's session storage, so closing and reopening the review does not lose them; answering clears the draft |
| fallback | unreadable plan or an unclaimed question shows the shipped card / an inline error; the review stays answerable |
| keyboard | Ctrl/Cmd+Enter accepts; Escape clears a pending comment selection |
| dismissal | Close dismisses the review without answering (same as the shipped card's discuss action) |
| locale | panel chrome is English; package metadata ships en + zh |
Requirements
- DSH
>= 0.2.1-rc.2with the Web GUI (dsh web). - The superpowers workflow's
superpowers-uiskill (installed under$DSH_HOME/skills/) emits the[plan-review]protocol this plugin renders. - Node.js 22 or newer only for the tests and the client build; the plugin itself runs inside the harness process.
Install
The package is a DSH bundle: it declares dsh.bundle.patch and one
client+host plugin row (id: plan-review). Install it into the profile you run,
then restart dsh web.
From a plugin market
Enable DSH's custom plugin market, add a community index that lists this package
(the repository carries the dsh-plugin GitHub topic so indexes can discover
it), and install @andrewhmir/dsh-plan-review from the Discover tab.
With the agent
plugin_manager install_bundle target: @andrewhmir/dsh-plan-review@0.1.0
From a local checkout
plugin_manager install_bundle target: /absolute/path/to/dsh-plan-review
After installing
Restart dsh web. The running process holds its pre-install module graph; a
restart loads the new host half and the client bundle. Then confirm the
composition:
dsh --profile web --dump-config
Expected: exit code 0 and a row id: plan-review / name: @andrewhmir/dsh-plan-review
with no not found, unknown key, or cannot resolve lines.
How it works
- Claim. The plugin's client half registers into the
conversation.composerchain slot atpriority: -20— ahead of the shipped question composer (0), the approval panel (1) and the subagent read-only composer (-10). Its selector returns a claim only for a single generic question whose header starts with[plan-review]; every other interaction getsnull, so the shipped card is untouched. (A question must carry at most two options and not be multi-select; anything else also falls back.) - Protocol. The question text is
path: <absolute markdown file>on line one, followed by the review heading. Without apath:line the whole text is the plan. The option labels are the authority for the decision buttons; accept-like and revise-like labels are matched by pattern and sent back verbatim. - Host half.
GET /plan-review/file?path=…(loopback-only, read-only) reads the plan as UTF-8. Reads are confined to the profile's registered workspace roots plus the sandbox policy'sworkspaceRoot; binary extensions, oversized files, and paths outside those roots are refused with stable error codes.GET /plan-review/pingis the liveness probe. - Rendering. The plan markdown is rendered by the plugin's own renderer
(
src/client/markdown.mjs): ATX headings, paragraphs, fenced code, inline code, bold/italic/strikethrough, links (http/https/mailto/#/relative only), ordered and unordered lists, blockquotes, GFM tables, and rules. Raw HTML is shown as text. Nothing is fetched from the network, and rendering does not depend on a module-table primitive the shell might not expose. - Comments. Highlighting is anchored by the quoted text plus character
offsets over the rendered document; offsets are repaired against the document
as it renders, so a re-render never leaves a comment pointing at the wrong
passage. Anchored comments are painted with the browser's CSS Custom Highlight
API, so the markdown renderer's DOM is never mutated. A comment whose quote
disappeared is marked
passage not foundbut keeps its note. - Answers.
Acceptsends{ id, selected: [<accept label>] }.Reviseneeds at least one comment or an overall note, then sends{ id, selected: [], custom: "{\"decision\":…,\"comments\":[{\"quote\":…,\"note\":…}],\"note\":…}" }— the shape thesuperpowers-uiskill documents. The panel only renders; it never edits plan files.
The protocol (agent-facing)
{
"id": "plan-review",
"header": "[plan-review]",
"question": "path: C:\\ws\\.superpowers\\plans\\feature.md\nReview the plan below.",
"options": [
{ "label": "Accept plan", "description": "Start executing the plan as written." },
{ "label": "Revise plan", "description": "Incorporate my comments and show me the updated plan." }
]
}
Answers arrive in the ask_user_question result. A plain decision is
selected: ["Accept plan"]. A comment-bearing decision instead has
selected: [] and custom holding
{"decision": "<label>", "comments": [{"quote": "<passage>", "note": "<what to change>"}], "note": "<overall note>"}.
note is this plugin's additive field for an overall remark (the skill documents
decision + comments); a body that had to be shortened to fit one tool result
also carries "truncated": true. Locate each quoted passage in the plan file,
apply every note (never drop one), rewrite the plan, and ask again.
The plugin refuses to send an accept answer while comments or an overall note
exist: a label decision has no field for them, so it asks for
Request changes (or for the comments to be deleted) instead.
Configure
The plugin row accepts one optional value; it is read without a Config schema:
- insert:
- id: plan-review
name: '@andrewhmir/dsh-plan-review'
config:
maxPlanBytes: 2000000 # read cap for one plan file (default 2 MB)
Known limitations
- The
[plan-review]protocol only. The harness's native plan-mode review (exit_plan_mode, architect preset) is a separate, shipped surface and is deliberately not touched — this plugin exists to render superpowers plan files. - Plan files must live under a workspace root. A plan outside every
registered root is refused by design (the error names the path so it can be
fixed). The route only serves markdown/text plan files (
.md,.markdown,.mdown,.mkd,.mdx,.txt), never arbitrary workspace files. - Drafts are per browser tab. Comments survive closing and reopening the
review in the same tab (
sessionStorage); they are not synced to another tab or device, and answering the review clears them. - Malformed answers are capped. The encoded answer stays under the profile's
tool-result pruner budget; if it had to shrink, the payload says
"truncated": trueso the agent can ask rather than silently missing notes. - English panel copy. Package metadata is bilingual; in-panel strings are English in this version.
- Web GUI only. The host route is generic, but the takeover and comments are Web-client features.
- The composer is occupied while reviewing. That is the same seat the shipped question card takes; dismissing the review returns the composer.
- Quote-based anchoring. A comment is tied to the exact text the user
selected; if a plan is rewritten mid-review (it is not, by this plugin), the
comment shows
passage not found. - A future host protocol change can shadow this plugin. Claiming depends on
the documented
conversation.composerchain and the[plan-review]header; if a future harness ships its own renderer for that header, its composer entry may win.
Compatibility
engines.dsh declares >=0.2.1-rc.2. The composer chain, the question answer
wire schema, the loopback web route and the seeded React module were implemented
against the 0.2.1-rc.2 packages on this machine and are covered by a
unit/integration suite with fake React, fake storage and fake fetch (no live
browser is driven by the tests). Plan rendering is self-contained and does not
depend on the shell's markdown primitive. Live install + smoke-test evidence is
recorded in MOUNT.md once performed.
Verify
From this directory:
node --test "test/*.test.mjs"
node tools/build-client.mjs --check
node --check client.js
In a confined Windows sandbox the test runner's child-process spawn is blocked;
run node --test --test-isolation=none "test/*.test.mjs" there instead.
Development
node tools/build-client.mjs # regenerate client.js from src/client/*.mjs
node tools/build-client.mjs --check # fail when client.js is stale
node --test "test/*.test.mjs"
client.js is a generated classic script that registers itself with the
harness's module loader under the package name. Source modules under
src/client/ are plain ESM with relative .mjs imports only; the host half
lives in src/host/ and is injected with webServer (optional
workspaceRegistry / sandboxPolicy).
After editing only the client half, the harness's client HMR stat-polls the
built bundle and hot-swaps it in the open page. Host-half edits need a
dsh web restart.
Independence and license
This is an unofficial community plugin, not affiliated with DeepSeek. It is an
independent implementation of the inline plan-review idea for the superpowers
protocol; its predecessor on this machine was the private dsh-superpowers-ui
plugin (0.1.x API, retired in the 0.2.x upgrade). Upstream DSH does not accept
external pull requests at the moment, so distribution is a standalone package;
the repository carries the dsh-plugin topic so community plugin indexes can
discover it.
MIT. See LICENSE.
No comments yet. Be the first to write one.