Preface

When running coding agents with DeepSeek Harness (dsh), a common scenario occurs: you write a prompt incorrectly in a certain round, the Agent has already modified a bunch of files, and the conversation context has drifted far away. At this point, just looking at Git diffs is not enough — diff can tell you what has been changed now, but it cannot roll back both the workspace and the conversation according to “before a certain user message was sent”. The native “new conversation branch” of dsh only separates conversations without touching project files, making it easy for the two sides to get out of sync.

What dsh-turn-rewind does is exactly this: it attaches a rollback entry to each user message, restores the project files to the state before that message was sent according to the Turn, and optionally restarts the conversation from that round. This article is organized after cross-checking with the community directory page, GitHub repository README / README.zh.md, package.json and the official Harness repository.

The official positioning of DeepSeek Harness is “everything is a plugin”, and its source code is at deepseek-ai/deepseek-harness. The community plugin directory introduced below (deepseek-harness-plugin.com) is an independent site and has no official affiliation with DeepSeek / HyperMind. Do not treat it as an official app store.

What is this

dsh-turn-rewind is a conversation and message type plugin maintained by Anionex, with the repository at Anionex/dsh-turn-rewind. The npm package name is @anionex/dsh-turn-rewind, the current package.json version is 0.1.1, and the license is BSD-3-Clause. As of 2026-08-17, both GitHub and the directory page show 65 stars.

The problem it solves can be summarized in one sentence: add a security boundary around workspace changes to DSH Sessions — first create recovery points, after the Agent / user / external program modifies the worktree, preview the differences by path, and only truly restore when a user presses the final confirmation button.

The repository clearly distinguishes two layers of names:
- Turn Rewind: The function name seen by users, the repository name, and the Profile Bundle name.
- Change Ledger: The underlying persistent recovery engine. The ctx.changeLedger service, disk format, and storage path still use this name, because it describes a reusable snapshot and recovery layer, not just a web rollback button.

This repository is a standard DSH Profile Bundle: package.json declares dsh.bundle.patch, and cordis.patch.yml directly mounts @anionex/dsh-turn-rewind without modifying the main DSH repository.

Core Features

Anchor recovery points by user messages

When the Profile also provides the DSH Agent service, the plugin saves a hidden file state before each first agent/pre-step, before the Agent starts processing user messages. A save failure will only make that message impossible to roll back, and will not block the user’s current round.

In the Web Profile, a pure “rollback” icon will appear below each user message, right after the timestamp and the native “copy” button, with the tooltip “Restore before sending this message”. After opening it, it will first check the saved file status, provide a paginated preview, and then let you choose the recovery method.

Two recovery modes

Mode Project Files Conversation
Restore files and continue from here (default) Automatically back up the current state first, then restore project files Create and open a new Session that ends before the selected message, and fill the original text of that message back into the input box
Restore files only Also back up first before restoring Keep the current Session in place, with unchanged content

DSH Session logs are only appended and not rewritten, so “continue from here” will create a new Session instead of truncating the original conversation. When selecting the first message, the Host will create an empty Session in the same working directory; when selecting subsequent messages, it will fork at the last completed turn/end. The original Session is always retained.

If the project files are already in the state before the selected message was sent, Turn Rewind will not degenerate into “only open a conversation branch”, but will prompt that no recovery is needed, and guide you to use dsh’s native new conversation branch. The repository clearly distinguishes the two: new conversation branch only separates conversations and keeps project files unchanged; Turn Rewind will definitely restore project files, and then let you decide whether to start a new conversation.

Review first, write later

The recovery lifecycle follows the warehouse description as follows:

Create recovery point
        ↓
agent / user / external program modifies worktree
        ↓
Preview changes path by path
        ↓
Review all or part of the recovery plan
        ↓
Press the final recovery button in the rollback popup
        ↓
Create rescue point first → Restore → Hash verification

The popup preview will generate a short-term, session-bound recovery plan based on the current worktree, and this step does not modify any files. Before actually making changes, it will recheck the selected paths and repository status, and first create an automatic backup. Relevant changes that appear after the preview will invalidate the plan. Recovery will be blocked as long as there are still running Agents on the same worktree (including the current source Session); idle Sessions will not block recovery.

The plugin will not automatically commit, stash, reset, switch branches, modify the Git index, or judge for you which changes “should be rolled back”. The restored content may appear as uncommitted changes on the current HEAD, because commits, branches, HEAD, and the index remain unchanged. Recovery will still be blocked when Git is performing merge, rebase and other operations.

What Change Ledger is responsible for

The regular Git panel can display the current diff, but does not have a complete and persistent recovery lifecycle. Change Ledger is independently responsible for:
- Content-addressed recovery point manifest
- Status fencing for Git worktree, HEAD, branches and in-progress Git operations
- Stale plan detection between review and execution
- Dual thresholds of short-term confirmation code and DSH manual approval
- Automatic rescue point creation before each recovery
- Content hash verification after recovery
- Automatic rollback after recovery failure
- Reconciliation of unfinished operation logs when DSH restarts
- ctx.changeLedger public service that can be depended on by other plugins

The persistent format is available in the repository’s docs/FORMAT.md, and the security and failure model is in SECURITY.md.

Installation and Activation

The installation command given on the community directory page can be run in the DeepSeek Harness terminal:

dsh plugin add github:Anionex/dsh-turn-rewind

The dsh CLI will parse the plugin from GitHub and install it to the current configuration. For reproducible installations, the directory page recommends pinning the commit hash:

dsh plugin add github:Anionex/dsh-turn-rewind#<commit>

Replace <commit> with the actual commit hash from the repository. The directory page also reminds you that the plugin runs with the permissions of the current dsh process, and may execute code during installation. Please check the source code repository and license before installing.

The repository README also gives the mounting method by Profile. First build in the checked-out plugin directory, then add it to the Profiles that need to expose this service separately:

pnpm install --frozen-lockfile
pnpm run check

dsh plugin --profile web add @anionex/dsh-turn-rewind
dsh plugin --profile headless add @anionex/dsh-turn-rewind

dsh --profile web --dump-config | grep turn-rewind

You need to restart the corresponding DSH process after modifying the Profile Bundle. The Node engine declared in package.json is ^22.19.0 || >=24.0.0.

The default configuration can be overridden in the Profile’s patch layer. The fields given by the repository are as follows:

- id: turn-rewind
  config:
    storageDir: ~/.dsh/change-ledger/v1
    maxRestorePoints: 50
    maxTurnCheckpointsPerSession: 30
    maxFiles: 20000
    maxFileBytes: 16777216
    maxSnapshotBytes: 536870912
    planTtlMs: 900000
    staleLockMs: 30000

When not configured, storageDir uses $DSH_HOME/change-ledger/v1, and falls back to ~/.dsh/change-ledger/v1 when DSH_HOME is not set. The repository requires that it must not overlap with the managed worktree. Both the capacity and user recovery point limit are fail loud: exceeding the limit will directly fail instead of silently discarding files. The automatic Turn checkpoints have an independent per-session retention window, and only clean up their oldest checkpoints; user and rescue recovery points will not be silently deleted.

Typical Usage

Rollback via Web UI

  1. Confirm that the current Profile has mounted @anionex/dsh-turn-rewind and provides the DSH Agent service, so that available recovery points will be left before each round starts.
  2. Find a certain user message in the web interface, and click the rollback icon after the timestamp and “copy”.
  3. The popup will list the affected files, and you can expand “View all files”. The files will be displayed as “Restore previous version”, “Recover file”, “Remove newly added files”, “Restore file permissions” or “Restore previous file type” according to the actual result.
  4. Select “Restore files and continue from here” or “Restore files only”, review and press the final recovery button. The popup itself is the confirmation process, and no repeated check is required.
  5. If you choose “continue from here” and the new Session creation fails, Change Ledger will automatically restore the files to the pre-operation state from the backup.

The Web Profile provides the same-origin /turn-rewind interface: find the corresponding status according to the selected user/message serial number, return file previews in pages, generate short-term, session-bound recovery authorization, and hand over the new conversation creation to the create / fork lifecycle of the dsh official Host. The plugin will never restore files automatically.

Call Change Ledger for other plugins

Other Cordis plugins can inject changeLedger and use the same structured API. The repository example:

export const inject = ['changeLedger']

export async function apply(ctx: Context) {
  const point = await ctx.changeLedger.create({
    cwd: '/absolute/git/worktree',
    sessionId: 'session-id',
    label: 'before refactor',
  })
  // point.id is the persistent recovery point ID.
}

The complete format types are exported from @anionex/dsh-turn-rewind/format; trusted integrations and tests can use the independent Engine from @anionex/dsh-turn-rewind/core.

In case of a crash, recovery also uses the same API: use listRecovery to find the rescuePointId of the operation, use inspect to review the rescue point, and then run planRestore / applyRestore on the relevant paths. Before writing any path, the plugin will first create a rescue point and a persistent operation journal. If dsh exits during a non-final operation, the next startup will mark the operation as interrupted; another surviving dsh process holding the worktree lock will not misjudge its operation.

Applicable Scenarios and Notes

It is suitable for these situations:
- The coding agent has broken the workspace, and you want to go back to before a certain prompt was sent, instead of just opening a new conversation
- You just want to revert the files, and keep the current conversation for reference
- You need to provide inspectable and rollbackable workspace recovery points for other plugins

The 0.1 series only supports regular Git worktrees, including: tracked files (including tracked paths that were missing when the recovery point was created), untracked files not ignored by .gitignore or Git standard excludes, text and binary regular files, symbolic links, and portable permission bits such as executable bits.

Objects that are explicitly not supported or will be directly rejected include: sparse checkout, submodule gitlink (you should create recovery points in each submodule respectively), ignored files, special files such as sockets / devices / FIFOs, extended attributes / ACLs / owners / timestamps / hard-link topologies, Git index and repository metadata, non-Git directories. If ignored or other unmanaged files occupy the path to be restored, the plugin will reject recovery and will not recursively delete them.

Please also note:
- The plugin runs with the permissions of the current dsh process, so you should check the source code and license before installing.
- It does not sandbox other processes, and cannot prevent external programs from modifying files at the same time.
- It does not provide confidentiality or tamper-proof guarantees for the same OS user; the status files are readable and writable only by the owner by default, but the host user is still regarded as a trusted party.
- “Continue from here” has a seedLength fence when creating child Sessions: only when both the selected user/message and the corresponding exact turn/start are lower than each layer of persistent fence, can the ancestor saved state be reused; the child Session’s own state takes precedence, and sibling branches will never be mixed.

Summary

Modifying files by agents is an irreversible operation unless verifiable recovery points are left in advance. dsh-turn-rewind turns this into a Turn-level explicit rollback: attach an entry to the message, Change Ledger manages snapshots, reviews, rescues and failure rollbacks, and Git’s commits / branches / index remain unchanged. The current version limits the scope to regular Git worktrees, and automatic recovery is explicitly excluded.

Directory page: https://deepseek-harness-plugin.com/zh-CN/plugins/dsh-turn-rewind/

GitHub: https://github.com/Anionex/dsh-turn-rewind