dsh-session-export
Human-readable session transcript export for DeepSeek Harness — /transcript writes Markdown/JSON to a host path via ctx.sessionQuery (dsh-plugin)
- Stars
- 0
- Language
- TypeScript
- Created
- Aug 22, 2026
- Updated
- Oct 3, 2026
Introduction
dsh-session-export
English | 中文
Deterministic session evidence reports for DeepSeek Harness: /transcript writes a styled single-file HTML report or Markdown/JSON transcript, /stats prints a terminal stats card, and /archive writes raw session logs as per-session ZIPs — all to a host path, on any persistence backend (JSONL or SQLite).
Reads the session log itself through ctx.sessionQuery — no recorder, no resident memory, no drift. Sessions that existed before the plugin was installed export just as well as live ones.
Install
Requirements: Node.js 20 or 22 · a DeepSeek Harness profile that mounts the commands and sessionQuery services (the shipped web / agent profiles qualify).
dsh plugin --profile web add dsh-session-export
Try it once
Inside any session:
/transcript --html
Exported 23 messages (41 tool calls, 128450 tokens) → /path/to/cwd/dsh-transcripts/transcript-a1b2c3d4-20260929T101530.html
One self-contained HTML file — KPI cards, turn timeline, tool ranking, error highlighting, dark/light theme — opens offline, prints to PDF.
The session toolchain
| Plugin | Layer | Answers |
|---|---|---|
dsh-session-export | Evidence | "What exactly happened in this session?" |
dsh-session-recall | Memory | "What did I do before, and where is it?" |
dsh-session-eval | Measurement | "Was that session good? Is the trend improving?" |
All three read through the same trusted ctx.sessionQuery seam.
Contributing
- Local dev:
npm ci && npm run doctor && npm run typecheck && npm test && npm run bundle(Node 20 or 22;npm run doctorfixes the unpublished peer dep — see CONTRIBUTING.md Step 0). - Start in the source:
src/render/html.ts,src/render/markdown.ts,src/mask.ts— the full source map is in CONTRIBUTING.md. - Open gaps: #5, #6, #7 — or browse issues labeled
good first issue. - Rules: behavior changes need tests; doc changes must update
README.mdandREADME.zh.mdin sync; releases belong to the maintainer. Details: CONTRIBUTING.md.
Commands
| Input | Result |
|---|---|
/transcript | Export the current session → <session cwd>/dsh-transcripts/transcript-<id8>-<timestamp>.md |
/transcript --html | Single-file HTML report: KPI cards, turn timeline, tool ranking, error highlighting, dark/light theme, print-to-PDF |
/transcript --json / --md / --html | Pick any combination of formats |
/transcript <path> / --out <path> | Write to the given path (spaces allowed after --out) |
/transcript --id <sessionId> | Export another session |
/transcript --last 30m | Partial export: entries from the last 30 minutes (7d/12h/30m/90s) |
/transcript --errors-only | Debug view: failed tool results with a two-entry context window |
/transcript --mask | Redact likely secrets (API keys, bearer tokens, private keys, emails) from the output |
/transcript --mask-hash | Deterministic redaction: secrets become #xxxxxxxx digests — same secret → same marker, equality survives redaction |
/transcript --manifest | Evidence manifest: write a .manifest.json sidecar with byte size + SHA-256 for every artifact of this run |
/transcript --full | Append log-only events + Mermaid turn timeline |
/stats | Terminal stats card: messages, turns, duration, tool calls (with failures), tokens, cost, per-tool ranking, sparkline — no files written |
/bundle | Review ZIP: transcript report(s) + raw JSONL archive + sha256 evidence manifest — one command for audit/review workflows |
/bundle --mask --manifest | Redacted transcript + evidence manifest |
/bundle --no-archive | Transcript-only review pack |
/archive | Archive the current session (incl. subagent descendants) → per-session ZIP |
/archive --all --since 7d | Batch-archive every session from the last 7 days |
/diff <id1> <id2> | Session diff: compare two sessions — common prefix, unique tails, stats delta (terminal or --html report) |
Like every ctx.commands command, all five run on the human-command plane: results never enter model history and cost zero tokens.
Positioning
dsh-session-export is a session evidence layer, not a memory optimizer.
- It focuses on auditability (what happened, in which order, with what failures).
- It focuses on reproducibility (stable outputs, portable files, deterministic render).
- It focuses on operations (batch archive, host-path artifacts, print-ready reports).
If your primary goal is context compression or long-term semantic memory, use a memory framework; if your primary goal is evidence, review, and postmortem quality, use this plugin.
Why
The shipped @deepseek-ai/dsh-session-log-export downloads a raw JSONL/zstd ZIP through the browser and supports the JSONL backend only. This plugin covers what it explicitly defers (see the competitive table below).
Transcript semantics follow @deepseek-ai/dsh-session/surface: the plugin renders append-origin surface events — everything the user actually saw — instead of the model-visible surface, whose compaction replacements would erase conversation the user already read.
Competitive context
| Capability focus | Official /export | Recorder-style exporter | Memory frameworks | dsh-session-export |
|---|---|---|---|---|
| Primary outcome | Raw artifact download | Human-readable transcript | Context/memory optimization | Evidence-grade replay report |
| Data source | Raw log package | Side-channel listener | Derived memory structures | Canonical session log (sessionQuery) |
| Historical coverage | Backend-limited | Often partial without backfill | Usually selective recall | Full history (incl. pre-install sessions) |
| Persistence backends | JSONL only | What the listener saw | Framework-specific | Any backend (JSONL, SQLite, …) |
| Stats | — | In-panel counters | Framework-specific | /stats card + cost estimate + tool ranking |
| Lineage / diffs / timeline | — | — | — | Mermaid lineage, editor diffs, turn timeline |
| Batch | — | — | — | /archive --all --since |
| Operational artifacts | Browser ZIP | Usually one-off exports | Memory state / indexes | HTML/MD/JSON + /stats + /archive ZIPs |
Official ecosystem note (2026-09): the official @deepseek-ai/dsh-session-log-export (browser download of raw JSONL/zstd ZIP, JSONL backend only) and @deepseek-ai/dsh-session-stats (base stats projection) are the raw-utility layer; this plugin is the evidence layer built on top — deterministic replay reports, SHA-256 manifests, redaction, policy packs, output contracts, /diff and /bundle.
Model-facing tool (v1.3)
Set exposeTool: true to register transcript_export — the same export kernel as a typed tool the model can call. The intended bridge: a dsh-session-recall hit returns a sessionId; the model hands it to transcript_export and the user gets a full evidence report on disk. One format per call (html default, md / json), optional mask / manifest / last; files always land in the standard dsh-transcripts directory (or defaultDir), with timestamped names that never overwrite. The tool is opt-in because it puts a host-file write in the model's hands.
The HTML report

/transcript --html writes one self-contained file — no external CSS/JS, opens offline:
- KPI cards: messages, tool calls (failed highlighted), tokens in/out, duration, turns, cost
- Turn timeline: one colored bar per turn, proportional to wall-clock share
- Tool ranking: horizontal bars with per-tool failure counts
- Token sparkline: inline SVG, output tokens per assistant message
- Error focus: failed tool results get a red border, banner, and auto-open; a header link jumps straight to the first failure
- JSON syntax highlighting: tool arguments and JSON results get token colors (keys blue, strings green, numbers amber) — no external highlighter
- Bilingual labels:
lang: zhrenders the entire report in Chinese; default is English - Native tooltips: hover KPI cards, timeline bars, and sparkline bars for details
- Native folding: tool arguments/results and reasoning in
<details> - Per-turn folding: the transcript groups into collapsible turns (duration · entry count · ⚠ flag); the sticky toolbar gives TOC chips + live search (
/to focus) for long reports - Copy buttons: one click to copy any tool argument/result/diff/reasoning block
- Dark/light theme: follows
prefers-color-scheme, toggle button, remembered - Print → PDF:
@media printrules; printing auto-expands all folds — archival copies in one Cmd+P
Markdown output gains a Mermaid lineage graph (GitHub/VSCode render it natively) and a Mermaid turn-timeline gantt with --full.
Cost estimation
Set a price table once and every export/stats run shows the estimated cost:
- id: session-export
name: 'dsh-session-export'
config:
pricing:
inputPerMillion: 0.27 # your per-1M-input-token price
outputPerMillion: 1.10 # your per-1M-output-token price
currency: '$' # label rendered next to the estimate
Install (out-of-tree plugin)
From npm:
dsh plugin --profile web add dsh-session-export
Or from GitHub:
dsh plugin --profile web add github:kittimzhe/dsh-session-export
Then add to the profile's cordis.patch.yml (the row requires commands and sessionQuery services, which the shipped profiles already mount):
- id: session-export
name: 'dsh-session-export'
Configuration
Plugin row config (all optional):
- id: session-export
name: 'dsh-session-export'
config:
preset: compliance # one-line policy pack: 'baseline' (default), 'compliance', 'full'
defaultDir: /absolute/output/dir # default: session cwd + dsh-transcripts/
argCharLimit: 512 # rendered tool-argument cap
resultCharLimit: 2048 # rendered tool-result cap
lang: zh # HTML report labels: 'en' (default) or 'zh'
mask: true # redact secrets by default (--mask per run)
maskMode: hash # replacement mode: 'mask' (placeholders, default) or 'hash' (deterministic digests)
maskPatterns: ['OPS-\d+'] # extra masking regexes
manifest: true # write a .manifest.json sidecar by default (--manifest per run)
exposeTool: true # register the model-facing transcript_export tool (default false)
pricing: { inputPerMillion: 0.27, outputPerMillion: 1.10, currency: '$' }
archiveDir: /absolute/output/dir # default: session cwd + .dsh-archives/
includeDescendants: true # /archive --id default
maxSessionsPerRun: 100 # safety cap on /archive --all
What the Markdown contains
- Header table: session id, project, created, agent preset, message/tool-call counts (failures), token totals, duration, cost, generator
- Lineage: Mermaid graph + ancestor chain and recursive subagent descendant tree
- Transcript in log order: user messages, assistant messages (provider/model provenance, token usage, collapsible reasoning), tool calls (arguments truncated;
str_replace_editorrendered as ```diff blocks), tool results (error-aware) --full: Mermaid turn timeline + log-only events appendix
Current gaps
Shipped roadmap items live in the CHANGELOG. Open work is tracked in issues:
- #5 — Markdown: content lines starting with
+/-must not widen diff blocks - #6 — Redaction: connection-string pattern (postgres/redis/mysql URLs with credentials)
- #7 — HTML report: tool-ranking bars link to the first call of that tool
Known limitations
- Exports run through the trusted
ctx.sessionQueryseam; a composition without it cannot mount this plugin. - Report bytes are not reproducible (embedded generation timestamps);
--manifestprovides integrity (SHA-256 per artifact), not reproducibility. - Token totals sum per-assistant-message
usagerecords; steps whose adapter reported no usage contribute zero. - Cost is an estimate from list prices; cache-hit discounts are not modeled (
cacheReadTokensis not priced separately). - Masking is pattern-based and best-effort: it redacts common credential shapes, not all possible secrets.
- Markdown escapes nothing inside fenced blocks; a diff whose own lines start with
+/-renders as additional diff lines (see #5). /archiveis export-only: there is no restore/import because DSH exposes no write-side session seam, so the ZIP is a backup, not a round-trip.
Development
npm ci
npm run doctor # peer-dep self-check — see CONTRIBUTING.md Step 0
npm run typecheck # tsc --noEmit
npm test # vitest run
npm run bundle # tsdown -> lib/