DeepSeek Harness plugin

dsh-turn-fork

Turn-atomic message editing, retry, reroll and version-tree navigation for DeepSeek Harness conversations

Jump to install

Source facts

Repository
ruby1304/dsh-turn-fork
Latest update
Aug 20, 2026
Category
Tools & Capabilities
GitHub stars
2
Format
plugin
Catalog evidence
Upstream dsh.bundle evidence
Evidence path
package.json#dsh.bundle
Checked against
0.1.0-rc.8
Upstream check date
2026-08-20

This evidence comes from the upstream catalog. This site has not installed, run, or security-reviewed the plugin.

Install

Start with a prompt that asks an agent to review the GitHub repository and source. Switch to the command if you want to install it yourself.

Copy this prompt into DSH, Codex, or another agent and ask it to review the GitHub repository and source first.

Do not install or run any commands yet. Read this plugin's GitHub repository, README, and relevant source code. Then answer the questions below clearly and directly so I can decide whether it fits my needs:

1. What is this plugin, and what problem does it solve?
2. Who is it for, and what are its typical use cases?
3. How is it used after installation? Include one minimal example.
4. What known limitations or privacy, security, compatibility, or maintenance risks does it have?
5. Give a clear recommendation: recommend, conditionally recommend, or do not recommend, with reasons.

Distinguish statements documented by the repository, inferences from source code, and unknowns. If evidence is insufficient, say so explicitly. Do not guess or simply repeat the README.

GitHub: https://github.com/ruby1304/dsh-turn-fork
Plugin: dsh-turn-fork
Author: ruby1304

Check the source files

Read the README and other files from this plugin directory before installing.

File explorer4 files
README.mdSource · read only
README language

dsh-turn-fork

Turn-atomic message editing, retry, reroll, and version-tree navigation for DeepSeek Harness conversations.

简体中文

  • Edit any settled user message and re-run the conversation from that turn

(truncate or preserve downstream turns).

  • Retry any historical turn; regenerate the latest reply.
  • Version tree Timeline with undo/redo navigation across branches.
  • Branch logs survive a dsh process restart — the P0 durability guarantee

the community plugin dsh-message-edit fails (see below).

  • Official slots only: Timeline tab, session-header actions, and per-message

assistant actions. No DOM injection, no text guessing.

  • Bilingual UI (zh / en) through the dsh-client-locale service.

Install

dsh plugin add dsh-turn-fork

Then restart dsh. The plugin registers a Turn Fork tab (between Trajectory and Prompt Studio), compact undo/redo/regenerate buttons in the session header, and retry/regenerate buttons on each finalized assistant message.

Why this plugin exists

dsh-message-edit (v0.2.3) has a P0 defect: its durable provenance event message-edit/version is written without the ignorable marker. The live write path accepts it, but after a dsh restart the persistence layer's cold-read vocabulary guard (assertEventsSupported) rejects the whole log with SessionFormatUnsupportedError — every branch session becomes unreadable. See tests/p0-persistence.test.mjs for a reproduction (live write OK → restart → cold read REJECTED) and this plugin's regression test (ignorable marker → restart → cold read PASSES), run against the real dsh-session + dsh-session-persistence-jsonl packages in a fresh child process.

dsh-turn-fork also fixes the design gaps the review found in the community plugin:

GapThis plugin
Custom events must be ignorable: trueturn-fork/version is always ignorable; schema-versioned for future migration
HTTP route without trust fence (CSRF / DNS rebinding, quota burning)Origin/Host loopback fence + content-type check + 64 KiB body cap
Message targeting by DOM text guessingOfficial slots only (conversation.view, conversation.session.header.actions, conversation.chat.assistant-actions)
reasoningEffort / config lost on forkprovider/model/maxTokens derive from the last request/header; reasoningEffort and adapterDefaults ride the inherited header inside the seed
Steering messages dropped on replayEvery user input of a turn is preserved and replayed in order
Assistant edits forge source: {kind:'model'} and drop tool callsNot supported (honest limitation, see below)
Undo navigation leaves branches running silentlyRunning branches are reported; each has an explicit Stop control
preserve replays N turns with no confirmationCost hint and explicit cascade choice before saving
No tests, no i18nnode:test suite + P0 regression + dsh-testkit lifecycle gate; zh/en dictionaries

Usage

  • Edit a user message — open the Turn Fork tab, pick a message, correct

the text, choose the downstream policy and save. A new branch session is created from the completed prefix and the corrected turn re-runs.

  • Retry / regenerate — per-turn buttons in the tab, per-message buttons on

assistant replies, or the header regenerate button for the latest reply.

  • Version tree — the tab lists every branch with its operation summary

(from "…" to "…"), marks the current version, and offers Undo/Redo navigation plus Open for any branch. Branches with a running agent show a warning and a Stop control.

  • Cascade policytruncate drops everything after the edited turn;

preserve replays the edited turn and every later turn (each replayed input becomes its own turn, with inputs of the same original turn kept in order). The editor shows how many turns preserve will replay before you confirm.

Design notes

  • Fork semantics. The official session.fork(atSeq) RPC cuts including

the anchored turn, which cannot express "edit turn N and re-run it". This plugin therefore uses the same underlying transaction seam the official fork uses internally — ctx.agents.create — with the seed cut before the target turn, official lineage meta (parentSession, seedLength, cwd, agentPreset), the source's preset re-mounted, and durability flushed before the branch is announced.

  • Workspace. The fork inherits the source's workspace attachment exactly

like the official fork does (re-attach, no filesystem snapshot). Re-running a task that rewrites files can therefore leave the working tree at the new branch's state. Pair with a checkpointing plugin (e.g. dsh-checkpoint-rewind) when you need workspace state rewind.

  • Branch deletion / GC. The platform currently exposes no session-delete

API, so branches cannot be garbage-collected yet; the version tree is a plain disclosure of this lineage.

  • Migration from dsh-message-edit. Logs written by the broken event

format are refused by the persistence layer itself, so no reader — this plugin included — can repair them in place. The Timeline detects the refusal and reports it explicitly. To recover old transcripts, use the official export flow before upgrading, or wait for the upstream fix.

HTTP trust fence

The host route /turn-fork is served by the dsh web server, which performs no origin checks of its own. Every request must pass the plugin's fence: a

browser Origin must be http(s)://localhost|127.0.0.1|[::1] with the

server's exact port (relaxed only when the server listens on 0.0.0.0, the operator's explicit remote-exposure opt-in); requests without an Origin must carry a loopback Host. POST bodies must be application/json and at most 64 KiB.

Development

npm install
npm run build      # tsc typecheck + tsdown host/client bundles
npm test           # build + node:test (core, lineage, P0 persistence regression)

Tests

  • tests/p0-persistence.test.mjs — the P0 regression: the plugin's real fork

seed is written through a real dsh-session store and dsh-session-persistence-jsonl backend, flushed to disk, then cold-read in a fresh child process ("restart"). A negative control proves the guard rejects the same log with the marker stripped.

  • tests/core.test.mjs — steering fidelity, plan boundaries, seed

construction, model-config derivation, trust-fence matrix, body cap, operation decoding.

  • tests/lineage.test.mjs — version projection, undo/redo stacks, running

flags.

  • dsh-testkit.yaml — real-host lifecycle gate (install → boot → register →

uninstall → reboot → residue) via the community dsh-testkit, plus the generated .github/workflows/dsh-lifecycle.yml CI workflow.

Testkit notes

dsh-test --suite full reports flaky under --runner local: every attempt passes every stage with identical assertions, but the repeatability digest includes attempt-scoped absolute paths and timestamps, which necessarily differ between attempts (the Docker default runner keeps the run-root path stable). The quick suite is the authoritative lifecycle gate here; the CI workflow runs it under Docker.

License

MIT. The client bundle preset under scripts/dsh-client-preset.ts is vendored from the DeepSeek Harness repository (MIT, © DeepSeek).