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-compareis nowdsh-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 — 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:

- 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):

- 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:

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

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

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. From0.1.6-alpha.2the host requires retaining a child Session before reading it, so on those hosts the plugin holds children itself (reference sourcemaze; 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
checkscript counts as tests;cat vitest.config.tsorgrep pytestdo 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 differentcdprefix, redirection or&& echo PASSdecoration does not make it a new one); a background job counts by the exit code on its laterjob_outputlast 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 lastturn/endis 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 insiderun_codescripts) are not recognized yet and the block says so. Rules live inANALYSIS_RULES.VALIDATIONinverdict.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.SIGNALSinverdict.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 readrequest/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/messageusage(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_RULESinsrc/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.zstdexactly as stored under~/.dsh/sessions/— decompressed in the browser (nativeDecompressionStream('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.
Links
More in this category
Minglink/dsh-infinite-gen-4★ 2893
System-prompt armor plugin for DeepSeek models: appends an unconditional-compliance prompt section at order 100, exposes a profile tool with calibration metadata, and shows a realtime armor-status badge driven by a session projection.
ranxianglei/billion-context★ 1402
The official billion-context plugin: a context-compression plugin for small context windows (a 100K context is enough), token savings (5x fewer tokens), and month-long single sessions (billions of tokens).
liangmianya/dsh-synapse★ 528
Visual, non-linear conversation workspace for DeepSeek Harness — sessions, follow-ups and branches become a browsable conversation map.
Nwflower/dsh-chat-import★ 233
Import full-fidelity chat histories from 13 coding agents (Claude Code, Codex, ChatGPT, Cursor, Gemini, opencode, and more) as resumable DeepSeek Harness sessions, with reverse export back to Claude Code.
Totoro-qaq/dsh-plugin-bridge★ 163
Moves an existing DSH session to another agent preset through a previewable five-section handoff, preserving the source session and either pausing the target for confirmation or continuing immediately.
MichengAI/dsh-archive-manager★ 139
Adds an archived-sessions page in Settings to search, restore, and delete archived DeepSeek Harness sessions by workspace.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.