Back to home@savageops

dsh-rich-questions

Rich branching survey system for DeepSeek Harness (DSH) Web GUI — ask_survey tool with branch graphs, delayed hover insights, Mermaid diagrams, quick mode, reroll/push/discuss actions

Stars
0
Language
JavaScript
Created
Aug 26, 2026
Updated
Aug 26, 2026
GitHub repo

Introduction

dsh-rich-questions

Branching surveys for DeepSeek Harness — authored live by your agent, answered in your chat.

Your agent doesn't just send a questionnaire — it composes one from the conversation's context: a directed graph of questions where each answer decides what gets asked next, every option carries its own reasoning, and the whole thing renders in the same composer seat you're already looking at. One tool call. No forms product, no account, no copy-paste.

富问题/问卷系统 — 由 agent 现场编写的分支问卷:每个答案决定下一题,每个选项自带洞察与流程图,直接在聊天输入框位置作答。

MIT · zero runtime dependencies · DSH ≥ 0.1.1-rc.1 · Node ≥ 20

flowchart LR
    A[Agent composes survey] --> B{Quick mode?}
    B -- pick a template --> Q[All answers applied<br>one click, submitted]
    B -- walk it --> C[Question 1]
    C -- option a --> D[Branch A]
    C -- option b --> E[Branch B]
    D --> F[Paths converge]
    E --> F
    F --> G[Banked along the way<br>survives any reload]
    G --> R[Structured result<br>back to the agent]
    Q --> R

Install

dsh plugin --profile web add dsh-rich-questions

Restart the dsh web process, refresh the tab — done. The ask_survey tool is now visible to every agent preset. (From a fork: dsh plugin --profile web add file:/path/to/dsh-rich-questions.)

What you get

Branching pathsEvery option declares what follows it (next). Choose C, get a different range of questions than A. Multi-select fans out depth-first; skipped/free-text fall through cleanly; the host re-derives the path independently so claimed paths are always verifiable.
Per-option intelligenceInsights (~6 lines: what great looks like / the tradeoff / "(today)"), sources and citations, and compact Mermaid diagrams — revealed through a 3-second-delayed tooltip and click-to-expand, never a hover ambush.
Quick modeUp to six whole-survey decision templates (af) next to Start — "Ship like Vercel/Railway: polish + DX first" vs "Lean internal tool: ship fast". One click applies a complete, coherent answer map and submits. A 20-question alignment exercise becomes a single decision.
Bank & continuePer-step commit for long surveys: answers-so-far go to the host in the background while you advance immediately. Banked answers lock (view-only forever after), survive reloads, and follow you to any browser. A {n} banked chip tracks them.
Durable progressDrafts autosave per survey — reload, switch tabs, come back tomorrow: same question, same answers, same position. Nothing to press.
Pre-flight steeringReroll (rewrite it cleaner), Push (research competitors, come back deeper), Discuss (drop the form, talk it through) — one click each, before the first question.
Language follows youEnglish chat → English survey. 中文 → 中文. Any language → that language, consistently.
Host-authoritativeThe pending survey lives on the host — close the browser, kill the tab, the tool keeps waiting and the wizard rehydrates on reconnect.

Why it exists

ask_user_question is perfect for 1–3 flat questions and nothing more. Real work — expectation gathering, acceptance criteria, scoping a build across a dozen interacting dimensions — needs paths (one answer changes what matters next), depth (a one-line label is not enough to choose well), and speed (sometimes you already know the destination). ask_survey is that system, and it leaves the simple flow untouched.

How it compares

Researched against the major survey platforms and wizard-commit patterns:

Capabilitydsh-rich-questionsTypeformSurveyMonkeyGoogle FormsMS Forms
Survey composed live from conversation context
Graph branching (per-option next)✅ nativelogic jumps (paid)sections onlybasic
Reload resumes progress✅ autosavesame browservia resume linksame browser + login
Committed answers survive browser loss✅ bank, any browserpartial (paid)
Answers lock once committed
One-click whole-survey decision templates
Rewrite / deep-research / discuss redirection
Per-option insights + sources + diagramsdescriptionsdescriptionsdescriptionsdescriptions
LicenseMITcommercialcommercialfree (account)free (account)

Also studied: Qualtrics, Jotform, Tally, Fillout, SurveySparrow partial-submission behavior, and Stripe/TurboTax-style per-step wizard commits — banking follows the wizard pattern, which none of the survey tools implement.

The wizard

Renders in the composer seat, one question per page over the live branch path:

  • Progress bar + answered/total against the current path; back re-evaluates branches from saved answers
  • Multi-select with checkboxes, free-text other row, per-question skippable
  • Every button explained by a delayed tooltip — Start/Next/Submit (contextual), Skip, Bank, Quick, Reroll, Push, Discuss, back, minimize, cancel
  • Keyboard-operable rows, aria-labelled controls; UI chrome localizes (EN / 简体中文, graceful fallback elsewhere)
  • Host-authoritative pending state, loopback-fenced routes, SSE + poll rehydration

Authoring guide

One spec, every capability:

{
  "survey": {
    "title": "Expectation alignment",
    "intro": "Short markdown preamble — the first page.",
    "entry": "q1",
    "questions": {
      "q1": {
        "prompt": "Which direction fits this release?",
        "header": "Scope",
        "detail": "Optional markdown context.",
        "options": [
          {
            "key": "a",
            "label": "Ship the public surface",
            "description": "One-line tradeoff, always visible.",
            "insight": "**What great looks like** — …\n**Tradeoff** — …\n**(today)** — …",
            "diagram": "flowchart TD; ship-->polish; polish-->latency; latency-->done",
            "sources": ["https://example.com/rfc-1"],
            "recommended": true,
            "next": "q2a"
          },
          { "key": "b", "label": "Rework the core first", "next": "q2b" },
          { "key": "other", "label": "Something else" }
        ],
        "next": "q2b"
      },
      "q2a": { "prompt": "…", "next": "q3" },
      "q2b": { "prompt": "…", "next": "q3" },
      "q3":  { "prompt": "…", "multiSelect": true }
    },
    "quick": [
      { "key": "a", "label": "Highest standard: Vercel/Railway grade", "recommended": true,
        "insight": "Who this is for, what it optimizes, the tradeoff.",
        "answers": { "q1": { "selected": ["a"] }, "q2a": { "selected": ["b"] }, "q3": { "selected": ["a", "c"] } } },
      { "key": "b", "label": "Lean internal tool", "answers": { "q1": { "selected": ["b"] } } }
    ]
  }
}

Edge semantics — exactly enforced:

SituationFollows
Single-select, option has nextthat option's next (id, list, or null = end)
Single-select, option has no nextthe question-level next
Multi-selectevery selected option's branch, depth-first, in option order
Skipped / free-text-onlythe question-level next
Nothing left / next: nullthe survey finishes

Validation is self-repairing. Every rule is checked host-side at authoring time: entry exists, every next names a real question (question-level null = no follow-up), no cycles, option keys unique, quick templates reference only reachable questions with real option keys, size caps hold (150 questions / 40 options / 1500-char insights / 1200-char diagrams / 8 sources / 6 templates). Rejected specs get the exact offending spot, the nearest defined id for dangling references, and the full id roster — one retry fixes it.

Result shapes

Completed (manual walk, quick template, or a mix — indistinguishable):

{
  "outcome": "answered",
  "path": ["q1", "q2a", "q3"],
  "answers": [
    { "id": "q1", "selected": [{ "key": "a", "label": "Ship the public surface" }] },
    { "id": "q3", "selected": [{ "key": "a", "label": "…" }, { "key": "c", "label": "…" }] }
  ],
  "skipped": []
}

Pre-flight redirect:

{
  "outcome": "push",
  "instruction": "The user hit \"Push\" before starting: … run aggressive web research … Call ask_survey again with the expanded, better-informed spec; do not ask the user anything first."
}

Banking never changes the result shape — banked answers simply are answers, committed earlier and locked along the way.

Architecture

src/host.js            Node half — ask_survey tool, pending-survey registry with
                       write-ahead banking, /api/rich-questions/{state,action,events}
                       routes, bilingual system-prompt announcement. Node builtins only.
src/survey-engine.js   Pure engine — branch-path computation + self-repairing
                       spec/answer validation. Imported by the host AND inlined
                       verbatim into the client bundle (keep the two in sync).
src/client.bundle.js   Browser half — the composer-seat wizard (draft autosave,
                       banking, quick mode, diagrams, tooltips). React + client
                       primitives only.
cordis.patch.yml       Bundle patch inserting the plugin row.

The Mermaid engine lazy-loads from CDN on first diagram expand and caches after — everything else is fully offline.

License

MIT