Written 2026-09-22 at the end of the session that de-forked this plugin, added human approval, containerised it, and verified it end to end in a browser.
Updated 2026-10-03. The 0→1 product loop landed on dsh/zero-to-one: five
phases (research → PRD → implement → test → ship), per-phase budgets, a YOLO
envelope with a worktree sandbox and a kill switch, an evidence bundle per run,
and make install. Design: docs/PRD-0to1.md.
Read docs/PRD-0to1.md §10 and the README's Known
limits → The 0→1 pipeline before trusting any of it. Every part exists and is
tested, and three call sites do not exist yet:
- nothing calls
transition()— a run stays inresearch; - nothing fills a
PhaseObservation, so no gate can pass; - nothing calls
ship()orcreateSandbox().
That last one matters for safety, not just completeness: with no worktree,
gateMode: auto denies every write, which is the correct fail-closed
direction but means YOLO is not yet usable end to end. The next session's first
job is the gate evaluator and the phase transition; the second is the evidence
writer wired into the turn-end seam; the third is a real five-phase run recorded
in docs/evidence/.
Everything below is true on this machine and on no other. Read "State of the repo" before you do anything.
Two sessions of work sit on an open PR; the newest session's work sits uncommitted in the working tree.
origin/mainis atea48b03(PR #8, the de-fork) — nothing after it is merged.- Branch
feat/human-approval-and-dockerholds the approval + Docker session's work, committed and pushed (04326cd,2f93906) as PR #9 (open). - The approval dashboard work is UNCOMMITTED: 13 paths (9 modified + 4 new)
—
src/dashboard.ts,src/dashboard-page.ts,test/dashboard.test.ts,docs/VERIFY-DASHBOARD.md, plus wiring insrc/plugin.ts/src/index.ts, deployment config (compose, profile patch, cordis patch, Makefile, ci.yml) and doc updates. If this machine is lost, so is the dashboard.
cd dsh-feature-loop
git log --oneline origin/main -1 # ea48b03
git status --short | wc -l # 13On a fresh clone of origin/main you would get none of it: no approval
panel, no Docker path, no dashboard, no runbook, and pnpm install would still
fail on the unpublished @deepseek-ai/cordis@0.4.0.
Commit/PR plan for the uncommitted dashboard set: todo.md §"Not yet
committed".
Start with whichever question you have; every file below is in this repo.
| Question | Read |
|---|---|
| How do I run this? | docker/README.md — one command; no toolchain, no monorepo build |
| How do I install it by hand into a DSH profile? | docs/SETUP.md |
| It is running — how do I know it works? | docs/RUNBOOK-SERVER.md §0 acceptance checklist |
| Why is the approval panel not appearing? | docs/RUNBOOK-SERVER.md §2.5-2.6 — the permission preset; this is the cause in almost every case |
| What is the design and why? | docs/PRD.md |
| What is proven, and how? | the docs/VERIFY-*.md files, table below |
| What is still broken or unproven? | todo.md and §5 below |
| Doc | Proves |
|---|---|
VERIFY-E2E-APPROVAL.md |
A real browser: the panel renders this plugin's reason; Allow once writes the file; Reject writes nothing |
VERIFY-DASHBOARD.md |
The approval dashboard on assistant-ui: 194 unit + 11/11 integration green, live HTTP transcript, and the browser click verified via make e2e-dashboard |
VERIFY-INTEGRATION.md |
5/5 in a real cordis context — approve, reject, fail-closed, deny mode, auto |
VERIFY-SDK-RUN.md |
A real model-driven run via the SDK reached the gate; session log quoted |
VERIFY-HEADLESS-RUN.md |
A real model-driven run via the CLI reached the gate |
VERIFY-APPROVAL.md |
The five outcomes, with harness file:line |
VERIFY-PANEL-EVIDENCE.md |
The harness already covers panel rendering (15/15 component tests + a committed browser snapshot) |
QA-FINAL.md |
Independent QA of the guide — 39 PASS / 9 FAIL, all 9 since fixed |
QA-SETUP.md |
The earlier QA pass; its findings were the 9 that got fixed. Historical |
E2E-BROWSER-PLAN.md |
Browser-launch and selector patterns to reuse for UI automation |
docs/INTEGRATION-PLAN.md is a planning note, not a result.
cd dsh-feature-loop
make verify # compose-check + 194 tests + typecheck + the 11/11 integration specOr individually:
make test # 194 pass, 0 fail
make typecheck # mirrors the CI file list (now incl. src/dashboard*.ts)
make integration # 9 pass (needs a harness checkout; set DSH_HARNESS to move it)
make compose-check # the compose file is validtest/integration/run.sh stages a spec into $DSH/packages/core/tools/tests/,
runs it, and removes it. It needs the harness checkout; pass the path as $1 or
set DSH_HARNESS. It cleans up after itself — if you kill it mid-run, delete
$DSH/packages/core/tools/tests/zz-feature-loop-gate.spec.ts by hand.
cd dsh-feature-loop
make up # build, start, wait for the UI, print the URL + token
make help # every targetmake up reads the gateway key from ~/.dsh/.credentials.yaml when it is not in
the environment, so it usually needs no arguments. make url, make dashboard
(the approval dashboard's URL + token), make health, make logs, make down
(keeps the volume) and make clean (removes it, asks first) cover the rest.
make ports shows which of 3081/3097/3099/3090/3092 are in use without
touching them.
There is one service and one compose file: docker/docker-compose.yml,
service dsh-feature-loop, volume dsh-fl-data (pinned — compose would
otherwise prefix it with the directory name).
The image is already built locally as dsh-feature-loop:local, and a container
named dsh-feature-loop may still be running on host port 3090. Check
docker ps before starting another.
Each of these was hit and diagnosed. Do not re-derive them.
-
@deepseek-ai/dsh@latestis broken. It pins@deepseek-ai/dsh-client-ui-sidebar-documentpreview@^0.1.5-rc.3, which was never published → ETARGET. Use0.1.7-alpha.1(what the image pins). -
The approval panel needs
permission.defaultPreset: workspace-write.permission-presetsapplies the default preset's approval policy directly on a fresh session, after every config default, and it is a settings section — so a profile'scordis.patch.ymlcannot override it. Underdanger-full-accessthe policy isneverand a feature-loopaskbecomesError: the user rejected tool "X"with no panel.DSH_PERMISSION_MODEdoes not help; it only sets the sandbox mode and theapprovalbundle's ownpolicy. Full mechanism:docs/RUNBOOK-SERVER.md§2.5. -
DSH refuses two binds.
--host 0.0.0.0is rejected by the CLI ("would expose remote code execution"), and the webserver schema accepts only127.0.0.1or0.0.0.0— so binding the container's own IP fails too. The image binds127.0.0.1and relays; seedocker/entrypoint.sh. -
Use the harness's real tool names.
read,write,edit,bash,glob,grep. The namesread_file/write_file/edit_file/run_testsbelong to this repo's standalone runner (src/tools.ts) and match nothing in a DSH session. A non-matching name is not an error — the tool falls through to the unclassifiedirreversibledefault, so the gate still fires but withalways-approveinstead of your configured policy. That is the "working for the wrong reason" trap. -
A composer element exists before a workspace is chosen, but is inert. A UI script keying off "is the composer present?" will type into it, submit nothing, and then wait forever for a panel that was never requested. Key off the UI's own
Choose a workspace to startprompt. -
The harness cannot launch its own browser specs here. They expect
chromium_headless_shell-1228; the cachedchromium-1228is a stub.chromium.launch({ channel: 'chrome' })withlocale: 'en-US'works. -
pnpm installwas impossible until this session — the manifest pinned harness-monorepo workspace versions (cordis@0.4.0,schemastery@0.1.5) that were never published. Now fixed; harness packages are optional peers and.npmrcdisables peer auto-install (some transitive peers are unpublished).
Stated plainly so nobody inherits a false belief. These are also in
todo.md.
costBudgetUSDmeasures zero.LoopBudget.spend()is never called with real usage, so the cost ceiling is decorative.maxStepsis the only trustworthy ceiling. This is the largest correctness gap.src/plugin.tshad no automated test until this session, and the two new test files cover the decisions and a real cordis context — but the wiring is still thin. Two bugs already shipped past reading-only review (detectors that never saw history; a gate that failed open for an agent-less call).- Nobody has clicked the panel by hand. Both buttons were exercised by an automated browser script. That proves the mechanism, not that a person finds the UI usable — and the flow needs three gates (testing notice, API-key prompt, workspace chooser) before the composer is usable.
- Session-log persistence through the web path was not confirmed on the container volume. The approved file is the evidence instead.
routing.tsoverlapsmodel-selectionin the harness. Retained deliberately (it drives the standalone runner and carries spec-level escalation), but unresolved.- Branch drift risk: PRs #3-#7 (Dependabot) are still open. #5 (tsdown 0.5 →
0.23), #6 (zod 3 → 4) and #7 (typescript 5.9 → 7) are major jumps; CI green
on them does not prove the plugin still typechecks, because
src/plugin.tsis excluded from the CI typecheck job.
- No vendored harness code. If you find yourself copying a file out of
deepseek-harness, stop and register a listener on a harness event instead. The fork was removed on purpose;CONTRIBUTING.md§"The de-fork" says why. - Report only what you observed. "UNVERIFIED", "did not work", and "I could
not test this" are expected answers and appear throughout
docs/. Do not upgrade an inference into an observation. - Thresholds cite provenance. Every detector threshold is quoted in
BOOK_THRESHOLDS(src/signals.ts) from the source playbook. - Do not edit
~/.dsh/settings.yamlwithout asking. Use a privateDSH_HOMEinstead — the recipe isdocs/RUNBOOK-SERVER.md§2.6.
This session was run with an Agent Teams setup. For continuity, the shared task board used these ids:
| Task | Subject | Outcome |
|---|---|---|
| task-1 | Wire the gate to ask |
done |
| task-2 | Verify the approval paths | done → VERIFY-APPROVAL.md |
| task-3 | Run the DSH web server | done → RUNBOOK-SERVER.md |
| task-4 | Model-driven run reaches the gate (headless) | done → VERIFY-HEADLESS-RUN.md |
| task-5 | Same via the SDK | done → VERIFY-SDK-RUN.md |
| task-6 | QA the setup guide | done → QA-SETUP.md |
| task-7 | Re-verify the fixed guide + Docker path | done → QA-FINAL.md |
| task-8 | Strongest non-browser panel evidence | done → VERIFY-PANEL-EVIDENCE.md |
| task-9 | Browser-e2e patterns | done → E2E-BROWSER-PLAN.md |
The board does not persist across sessions; this table is the record.
If you have 5 minutes: run the four verification commands in §3.
If you have half an hour: commit and push the dashboard work so PR #9 carries
it (§1 of todo.md has the plan) — leaving it uncommitted is the biggest risk
to it.
If you have a browser: click the dashboard's Allow once by hand — the
single UNVERIFIED item, and docs/VERIFY-DASHBOARD.md §"NOT verified" has the
two-minute script.
If you want to improve the product: fix the cost ceiling (§5, first bullet).