DeepSeek Harness Plugin

lamost423/dsh-maze

Stars ★ 86 Downloads (30d) 1,888 Category Sessions & Messages Added 2026-08-31 npm dsh-maze

Execution maze for DSH sessions: the agent's real path — main advance, failed or dead-end detours, backtracks, request retries and subagent branches — drawn on one wall-clock timeline, with three tracks under each lane sharing that axis (tool-call density, token pulse, context pressure) and a deterministic analysis panel below it (tool result matrix, failure-recovery chains, duration distribution); watch it grow live in a session tab, or upload up to 5 session logs for a same-axis compare.

Install

# from npm (prebuilt)

dsh plugin --profile web add dsh-maze

# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)

dsh plugin --profile web add github:lamost423/dsh-maze

Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).

README

🔀 dsh-trace-compare is now dsh-maze (since v1.0.0). The old package stays installable but frozen — migration is two commands.

中文 | English

Also listed in: fendouai/awesome-deepseek-harness (dedicated intro page)· Zhiyuan-Fan/Awesome-DeepSeek-Harness-Plugins · ZeroPointRepo/awesome-dsh-plugins · cccakeee/awesome-dsh-plugins · diegosouzapw/awesome-omni-dsh-plugins · anbeime/skill · dsh-app built-in plugin market

The execution maze for DeepSeek Harness agents: see how the agent actually worked — drawn in full, and analyzed.

The maze, the data tracks and the execution analysis: one screen reads a real 8.6-hour session

  • The maze — main path, failed detours and backtracks on one timeline; idle stretches fold away, dense segments cluster into "×N" badges (click to zoom, labels refill progressively), and the seek bar carries a failure heatmap. An 8-hour session stays legible:

Dense session: cluster badges at full view → click to zoom → labels refill → open a failure

  • Data tracks — per-step tool-call density, token pulse (cache backdrop + uncached-input/reasoning/output bars), and context pressure (70%/90% threshold lines, compaction events marked "⌄−N%" with before/after on hover):

Hovering the tracks: token breakdown → context usage → compaction before/after

  • Execution analysis — failure recovery chains (identical retry / changed args / switched tool / not recovered), a per-tool result matrix, duration percentile scatter. Every conclusion is one click away from its evidence:

Click any failure chain row: zoom to that failure with the full command, error output and verdict rationale

  • Multi-session comparison — 2–5 runs of the same task on one axis: turn alignment, manual anchors, detour inventory.

Compare: two real runs of one task → per-turn detour inventory → click a row to zoom

  • Replay — up to 300× playback of the whole run:

Replay: an 8.6-hour session at 300×

House rules: every number is a deterministic aggregation over judged data — no LLM involved; every verdict carries its rationale and every conclusion traces back to evidence; missing data is labeled honestly (no tracks without usage, no guessed context windows), never invented.

Two entries: the Live Maze tab inside every session (grows with the running session), and Maze in the sidebar (upload session logs to inspect or compare).

What the maze shows

  • Solid line: the main path — steps whose tool calls succeeded, plus answer nodes.
  • Duration capsules: every step renders as a rounded bar spanning its start→end, verdict-colored — a 3-minute bash and a 0.2 s read are no longer the same dot; wide bars carry the duration inline.
  • Parallel tool-call rows (since v0.3.2): when a step fires ≥2 tool calls, each call renders as a thin waterfall bar under the capsule at its real start→end, colored by its own verdict — see at a glance which of the parallel calls dragged or failed; hover a bar for that call's command/result/rationale. Lane height adapts to the maximum concurrency; detour nodes keep their "+N" label (fixed lane slots; the panel lists everything).
  • Dashed arcs: exploration detours — steps whose tools failed (red ✗), searched and found nothing (gray ·), or blind-retried (gray ↻), with the return arc back to the branch point.
  • Subagent branches (since v0.4.0, live tab): dsh subagent child sessions spawned by the model render as aggregated detour nodes branching off the main path — anchored at the spawning step on the parent's clock, with the child's judged tool calls as sub-bars; running children grow live and read "still running". Hover cards and the detail panel carry the subagent identity and spawn/rejoin copy; clicking jumps back to the spawning row. Only real task subagents qualify (origin: 'subagent') — manual branch-offs and side chats stay out. From 0.1.6-alpha.2 the host requires retaining a child Session before reading it, so on those hosts the plugin holds children itself (reference source maze; never changes the selected Session): membership comes from the parent's subagent catalog, and children that finished before the maze opened are drawn in full; running children stay held, settled ones are read once, released and cached; at most 8 are expanded at once, the rest are noted on the lane. Older hosts (0.1.5 / 0.1.2) only draw children the host has already opened. Branch names use the task description given at spawn time; a running branch grows every second.
  • Hover any node or arc for a quick preview; click to pin a detail panel on the right — full command and result text (copy buttons; results keep their first 5000 chars), timings, verdict, reasoning summary. Close with Esc or ×.
  • Zoom navigation: wheel zooms horizontally around the cursor, drag pans, double-click (or the fit button) resets; axis ticks re-densify with the zoom window down to 1 s.
  • Jump to conversation (live tab only): the panel's locate button switches the host back to the Chat view and scroll-highlights the step's tool row. Rows older than the chat's loaded window degrade to the view switch alone.
  • Search & filter: a toolbar with a failures/retries-only toggle, per-tool filtering, and full-text search over commands and results (including the 5000-char panel text); non-matching nodes and arcs fade to 15% opacity with a live hit count. Filter state survives live-mode rebuilds.
  • Turn alignment lines (same-task compare kit, since v0.3.0, now up to 5 lanes): enabled only when the files are recognized as runs of one task (identical first user message). Each turn's answer nodes connect into a cross-lane chain labeled with every lane's per-turn time (turn start → answer done; inter-turn waits for user input are excluded, since v0.5.1); with exactly two lanes the label adds the delta and that turn's detour counts (e.g. "Turn 3 time: 1st 4m ↔ 2nd 6m (Δ2m) · detours 4↔0"). Only turns present in ≥2 lanes get a line — the old corpus-specific "model list result" regex milestone is retired.
  • Manual anchors (same-task compare kit): after "🔗 add anchor", click one node in each of any two lanes to pin a comparison line with its time delta; click the line to delete, Esc cancels picking. Useful for pinning semantically equivalent moments that sit in different turns.
  • Detour inventory (same-task compare kit): "📋 detour inventory" opens a per-turn table — every lane's detour step count, wall-clock time, and verdict breakdown (✗ failure / ↻ blind retry / · dead end), with a delta column at exactly two lanes (e.g. "session 2 wasted 48.4s more"); clicking a row zooms to that turn and keeps only its detours visible. A lane missing that turn shows "—" — the absence itself is signal. Files that are different tasks render side-by-side only, and none of these three appear (the legend says why).
  • Lane data tracks (v0.7, 📊 toggleable): three tracks under each lane band sharing the maze's time axis — tool-call density (one tick per call, colored by read/search/shell/edit/other), token pulse (per-step stacked bars: cached input / uncached input / reasoning / visible output, read from real usage), and context pressure (line+area with a data-adaptive y-axis; with a known model window it shows percentage plus 70%/90% threshold lines and compaction appears as sawtooth drops; an unknown or stale window falls back to absolute tokens — never a >100% reading). Tracks with no usage in the log are not drawn and take no height.
  • Execution analysis section (v0.7, rendered right below the maze in the main view): three summary cards (tool failures & recovery / time spent / context pressure), a duration scatter plot (one row per tool, global P50/P95 reference lines, failed calls highlighted, hover for the individual call), a per-tool result matrix (ok/failed/no-result/blind-retry/success rate plus P50/P95/max durations), and failure recovery chains — what happened after each failed call: identical retry / changed args / switched tool / not recovered, with honest recovery times; click a row to zoom to that failure and open its details. Scope note: chains cover failures (✗) only — no-result (·) and blind-retry (↻) calls count in their own matrix columns, not in the chains, and a blind retry never counts as recovery evidence. Every number is a deterministic aggregation — no LLM involved.
  • Outcome & evidence (diagnosis layer item 1; the first block of the analysis section): six cells — task / tests / build / lint / artifacts / human check — plus one overall badge (completed / partial / unverified), all read from log evidence rather than the agent's own claims. Tests/build/lint are recognized by command-position regexes (JS/TS, Python, Rust, Go, Swift in this first cut; an npm/pnpm/yarn check script counts as tests; cat vitest.config.ts or grep pytest do not count), one command can count for several kinds; passed = the call carried no error flag and the last line of its output has no non-zero exit code; each category is judged by its last run, with earlier commands that failed on their last run noted in small print ("the same command" is the matched segment — a different cd prefix, redirection or && echo PASS decoration does not make it a new one); a background job counts by the exit code on its later job_output last line and is left out (and noted) when none arrives; click a cell to locate the step of the last run and open that step's details. Artifacts = files touched by successful write/edit/patch calls, deduplicated (expand the list in the cell); task done = the last turn/end is not error/aborted/interrupted/blocked and the last step is an answer; the human check only asks whether a human message followed the final answer — content is never interpreted. With no verification command at all the badge reads a neutral "unverified"; code-mode sessions (real tool calls dispatched inside run_code scripts) are not recognized yet and the block says so. Rules live in ANALYSIS_RULES.VALIDATION in verdict.js.
  • Behavior signals (diagnosis layer item 2; the block beside the failure recovery chains): each row carries a severity (high / medium / low / info), a one-line rationale with the actual numbers, and the number of calls involved — identical retry after failure, same-turn repeats (with a repeated-reads sub-tag), loops, tool failures, slow calls (≥120 s), tool concentration (Herfindahl index), context jumps/drops (a drop next to a compaction event is tagged as such), context peak, compaction, stale todo reminders, adaptive recovery. Thresholds were calibrated on 202 local sessions ("medium" lands in the worst 15–20% of sessions, "high" in the worst 3–5%) and live in ANALYSIS_RULES.SIGNALS in verdict.js; signals count independently. Click a row to dim everything else and locate the first call of that stretch (click again or press Esc to clear; stacks with the other filters); with nothing fired the block says so instead of hiding. In this version code-mode sessions count only the outer run_code calls, as the method note says. Context use (the peak signal, the context-pressure track, summary card and header strip) is converted with the window of the model in use at each request: uploaded logs read request/context, the live tab looks per-request models up in the table; the track's axis is a percentage, and its caption notes mid-session window switches and samples skipped because their declared window was untrustworthy.
  • Agent graph (v0.7, a block inside the analysis section): a star overview of the main agent and its subagents — node size = tokens consumed per agent, edge width = tool-call count, running subagents dashed; click a subagent node to jump to its span on the timeline. Appears only when subagent data exists.
  • Export: one click saves the current view (zoom window and filter dimming included) as SVG or 2x PNG with styles inlined; exports are always light-background regardless of the page's current theme (built for sharing).
  • Bilingual UI (since v0.5.0): the whole page (upload area, legend, lane stats, alignment lines, detour inventory, hover cards, detail panel, errors) ships in Chinese and English, live-follows the dsh host's language setting when embedded, and falls back to the browser language when opened standalone; verdict rationales are structured keys rendered in the current language, so switching languages needs no re-upload.
  • Theme following (since v0.3.1): the page tracks the host dsh light/dark theme (the host components watch body[data-ds-dark-theme] and postMessage into the iframe); standalone opens follow the system preference.
  • Settings toggle (since v2.1.0): "Settings → Maze" can hide the sidebar entry — live-tab-only users can drop the persistent button; the flip applies immediately with no reload, persists per browser, and never affects the Live Maze tab or an open maze page.
  • Compact header (since v0.3.1): once data renders, the intro text hides, the upload zone collapses to a slim strip, the per-lane stat cards hide (the same info lives in the lane bands), and the legend fits one row — the maze gets nearly the whole viewport.
  • Playback replays the whole run at up to 300×.

Timeline honesty rules:

  • Idle folding: stretches with no step or tool activity for over 60 s (you thinking between turns) collapse into a thin ⏸ seam labeled with the skipped duration. Axis ticks keep wall-clock labels inside activity segments.
  • Step identity is turn-qualified (S15·47), so multi-turn sessions attach detours to the right nodes.
  • Durations, tool timings, and totals stay wall-clock; only the axis is compressed.
  • The live tab renders only the conversation's loaded event window (honestly labeled since v0.2.3): stale steps from earlier turns leaking into the window edge are dropped and noted as "⏮ N earlier steps not loaded" instead of piling at 0 s and inflating stats; for the whole session, download the log and use the upload view.
  • Tokens are real (since v0.2.2): reasoning/output tokens come from the session log's assistant/message usage (the old "reasoning N tok" counted streaming chunks, not tokens). Logs without usage fall back to an honest, self-explaining "reasoning N chunks (no token usage in log)" label — relay logs often omit reasoning-token fields, and side by side with official-API logs the differing units used to confuse (since v0.5.1).

Verdict honesty rules (since v0.2.1):

  • No output-length verdicts. Per-tool verdicts layer: error flag (isError) → failure signatures → per-tool-class rules (write tools succeed unless errored; search tools only dead-end on empty results; bash and unknown tools succeed with any output).
  • Failure signatures scan only the head and tail windows (since v0.2.3): real errors either lead the output or sit in the appended stderr section, while error-looking text QUOTED mid-output (git log, file reads, log dumps) is deliberately ignored — a command that prints "upstream returns HTTP 400" inside a commit message did not itself fail. Both render paths judge the same untruncated text.
  • Blind retries are behavioral: only consecutive same-tool, similar-args call clusters containing at least one failure are marked — following AgentLens-style deterministic waste detection for SWE-agent trajectories.
  • Every verdict carries a rationale string, visible in the hover tooltip and the detail panel.
  • All thresholds and tool classes live in VERDICT_RULES in src/client/verdict.js, tunable per corpus; the upload page and the live tab share this single implementation (spliced in at build time).

Session log support

Upload accepts DSH session logs in any of these forms, detected by content (the file name does not matter — macOS duplicates like session.jsonl 2 work):

  • plain .jsonl (session format v0 event streams)
  • .jsonl.zstd exactly as stored under ~/.dsh/sessions/ — decompressed in the browser (native DecompressionStream('zstd') when available, bundled fzstd otherwise)

Install

Check where your host came from first. Host 0.1.2 re-split its client packages (dsh-client-runtime became dsh-client-store and friends) and swapped the conversation snapshot model, so the two lines are not interchangeable:

Your host Version to install Command
0.1.2 and later — npm's @deepseek-ai/dsh (its latest is 0.2.0-rc.2 now), desktop apps on a 0.1.2+ kernel, or self-built master dsh-maze 2.x, tag latest dsh plugin --profile web add dsh-maze
Older hosts (0.1.0-rc.6 ~ 0.1.1-rc.2) dsh-maze 1.1.2, pinned manually dsh plugin --profile web add dsh-maze@1.1.2

Host 0.1.7 needs dsh-maze 2.3.0 or later: 0.1.7 renamed an icon and changed the subagent catalog API, so earlier 2.x builds show no sidebar entry and a blank Live Maze tab there. On hosts from 0.1.6-alpha.2, 2.2.0 does not crash but no longer closes the upload panel on a Session switch, so upgrading is recommended there too. Desktop apps (0.2.0-rc.2) should use 2.4.0: it widens the @deepseek-ai/dsh* peer ranges from <0.2.0 to <0.3.0 and tracks the built lib/ in git — without those, a GitHub install produces a shell with no lib/index.js and the plugin cannot load at all (which is exactly what happened on the desktop app on 2026-10-05). With pnpm 11's default settings, an unpinned install resolves to the previous version for 24 hours after a plugin release; pin the exact version meanwhile, e.g. dsh plugin --profile desktop add dsh-maze@2.4.0.

Compatibility: 2.4.0 builds against the npm 0.2.0-rc.2 package set, with typecheck also clean against the 0.1.2-rc.1 and 0.1.5-rc.3 sets and all 158 tests green; live acceptance was done on fresh 0.1.5-rc.3, 0.1.7-rc.2 and 0.2.0-rc.2 hosts for 2.3.0 (this release's package installed, sessions driven by a mock model, every on-screen number reconciled against the host's own accounting, and the upload page reading the format v3 and v4 logs those hosts wrote), and 2.4.0 was regression-tested in the 0.2.0-rc.2 desktop profile. 1.1.x is verified against official 0.1.0-rc.6 (build + full tests) and rc.8 (slot/type audit + live acceptance).

npm install --global @deepseek-ai/dsh
dsh plugin --profile web add dsh-maze
dsh web

After restarting dsh web, the sidebar gains a Maze entry and every session view gains a Live Maze tab.

From source:

git clone https://github.com/lamost423/dsh-maze.git
cd dsh-maze
corepack enable && pnpm install && pnpm build
dsh plugin --profile web add .
dsh web

You can also install straight from GitHub — the repository ships the build output, so nothing is built locally (unpinned installs take the default branch's latest commit):

dsh plugin --profile desktop add github:lamost423/dsh-maze

Migrating from dsh-trace-compare

dsh plugin --profile web remove dsh-trace-compare
dsh plugin --profile web add dsh-maze

The old package is frozen at v0.7.0 (feature-identical to dsh-maze 1.0.0); only dsh-maze moves forward. The old GitHub URL redirects here.

Version history

See CHANGELOG.md.

Development

pnpm install
pnpm check   # typecheck + vitest + build

The upload/visualization page is a self-contained HTML document (src/client/maze-upload.html) rendered inside a sandboxed <iframe srcDoc>; parsing and rendering run entirely in the browser, and nothing from an uploaded log reaches the host.

License

MIT. See NOTICE — this project contains code derived from DeepSeek Harness.

Content from the project README on GitHub ↗

Links

More in this category

View the whole category →

Community comments

Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.