Preface

In DSH (DeepSeek Harness), as long sessions run, the context window gradually fills up. The common approach is manually copying summaries, starting a new session and pasting, or relying on external notes to continue. dsh-auto-handoff turns “reach threshold → assemble a length-limited handoff package → ask the session side to create a new session and deliver the first message” into a pluggable flow; since 2026-09-28 it also merges the original dsh-session-switch session switching logic into this package (switch-session.js / switch-store.js).

One thing to note upfront: as of 2026-10-17, the plugin description marks “session switching retired entirely” — long-conversation endurance is better left to DSH’s official context compression, and cross-restart continuation is left to dsh-memory-board. The following text still describes its design and configuration as in the repository README, to help understand historical workflows or maintain existing installations.

What This Is

In one sentence: when context usage reaches the configured ratio, it generates a handoff package with a default limit of 1200 characters, and via the merged session-switching module creates a new session and sends the handoff package as the first message of the new session; meanwhile, idempotent fingerprints prevent duplicate handoffs. Memory viewing/editing/importing/exporting is not handled by this plugin.

Core Features

Actions on Threshold Trigger

Usage rate resolution order (per README convention):

  1. Prefer the session projection contextPressure (same source as the page percentage)
  2. Otherwise ctx.tokenMeter.measure() ÷ request/context().contextWindow
  3. If neither is available, no action

When the threshold is reached and minTurns, cooldown, and other conditions are satisfied:

  1. Assemble a length-limited handoff package (default handoffMaxChars: 1200, only this enters the new session)
  2. Call the session-switching side logic (internally runSwitchDirect(), while still keeping /api/session/switch and other HTTP routes for self-checks and compatibility)
  3. Write an idempotent fingerprint handoff-fingerprints.json to the state directory (persisted across restarts, up to 50 entries)

This plugin does not create sessions itself; session creation, UI switching, and archiving the original session are handled by the merged switch-session.js; a handshake failure degrades gracefully (the complete pending handoff is written to an agreed location, and the browser side switches on its own).

Default Behavior Change Since 2026-10-16

  • archiveOnHandoff defaults to false: handoff does not write diary, status, or growth records; fingerprints land in ~/.dsh/session-switch/handoff-fingerprints.json
  • When autoTrigger: true, reaching the threshold does not automatically switch sessions, but instead injects 【自动收尾提示】 (Auto Wrap-up Prompt) into the AI; after wrap-up completes, it raises its hand via a fire-now file to switch sessions (see below)

Responsibility Boundaries

Dimension This Plugin Merged Session Switching
What it manages Handoff package + pending handoff records (only writes archives when archiveOnHandoff: true) Sessions: create, switch, archive
Trigger Context reaches threshold; or a full-sentence match of drill keywords in user messages Only acts when receiving switch-related API calls

The state directory defaults to ~/.dsh/session-switch/ and can be overridden via the environment variable DSH_SESSION_SWITCH_DIR.

Host API (prefix /api/handoff/)

The client client.js only handles polling and navigation/archiving; it does not register slots or write DOM. Common routes include: pending / take (pending handoff), ack, health, status, draft-report, fire, fire-ack. requestBody must be buffered, otherwise it may fail silently.

Raising Hand to Switch Session After Wrap-up (File Signaling)

POST /api/handoff/fire requires host authentication; on the AI side, writing a file is recommended:

: > ~/.dsh/session-switch/fire-now

The plugin checks and deletes this file roughly once per second; after the client polls fire, it sends “Switch Session” on behalf of the user, still subject to limits of ≤2 per hour and ≤8 per day.

Manual Drill

Match the default keyword #交接演练 as a full sentence in user messages:

  • Only writes to the drill copy root sandboxRoot, not touching real archives
  • If sandboxRoot is not configured, runs dry and logs
  • If sandboxRoot falls inside the real archive root, it is rejected

Installation and Activation

Installation steps come from the repository README (no dsh plugin add github:... one-liner):

  1. Place the plugin directory into the DSH plugin source directory (example: ~/.dsh/plugin-src/dsh-auto-handoff)
  2. Modify the entries in cordis.patch.example.yml according to your machine’s situation, and write them into the profile’s cordis.patch.yml; or install via Plugin Manager’s install_bundle using a bundle
  3. Restart the host (changing bundles or config both take effect on restart; HMR is unreliable)

The archive root root is required logic: when left empty, it tries in order config.root → environment variable DSH_MEMORY_ROOT → ~/.dsh/memory → searching upward from the current directory. Recognizing the root requires the simultaneous presence of 身份.md, 日记.md, and 生长\状态.md; if not recognized, no action.

Configuration Highlights

Key Default Description
root '' Archive root
triggerRatio 0.65 Trigger on usage ratio
minTurns 3 Too-short sessions do not trigger
cooldownMs 180000 3-minute cooldown, after which handoff can occur again
handoffMaxChars 1200 Handoff package character limit
dryRun true First startup only calculates without writing, no persistence
archiveOnHandoff false Whether to write archives during handoff
autoTrigger false When true, injects a wrap-up prompt instead of directly switching sessions
drillKeyword #交接演练 Manual drill
gatewayBase http://127.0.0.1:3080 Session switching gateway address

When archiveOnHandoff: true, there are four guards for writing to disk (backup before modifying, only modify at located points, verify after writing, reject writes on external modification), and it enforces CRLF, UTF-8 without BOM.

Typical Usage and Self-Checks

Drill handoff (send in the conversation, as a full sentence):

#交接演练

Module self-check (run in the plugin directory):

node index.js --selftest
node test-handoff-sandbox.mjs
node test-handoff-sandbox.mjs --verbose

Session switching self-check (README example):

DSH_SESSION_SWITCH_DIR=/tmp/ss node index.js --switch-selftest

Use Cases and Notes

Once suitable for: local DSH long sessions, workflows that want automatic handoff package generation and session switching when context reaches about 65%; teams that need alignment with the archive directory (memory panel system) and accept host restarts for changes to take effect.

Current ecosystem: the plugin description now marks that since 2026-10-17 the session switching capability is retired; new deployments should prioritize evaluating DSH’s official context compression and dsh-memory-board, then decide whether to keep this plugin solely for handoff package or archive writing logic.

Boundaries (README original text):

  • The handoff package is a compressed starting point for taking over, not a full-text copy
  • Cross-device does not cover the same Web client scenario
  • The plugin runs with the current DSH process permissions; please read the source code and MIT license before installation

Conclusion

dsh-auto-handoff strings together “context pressure → length-limited handoff package → session switching” into a configurable pipeline, and adjusted its default policies multiple times in 2026 (merging session switching, defaulting to no archive writes, raising hand to switch sessions after wrap-up). Whether or not you continue using the session switching capability, the repository README remains the authoritative explanation for understanding thresholds, cooldowns, fingerprints, and APIs.