shared-handoff-dsh
A DeepSeek Harness (dsh) skill plugin that ports the shared-handoff-kit's
handoff workflow: it packages the handoff and task-id-bootstrap skills
with zero dependencies and no build step, adapted for macOS, Linux, and
Windows (including Windows 10 vs Windows 11 Python environment differences).
Skills
| Skill | What it does | Requires |
|---|---|---|
handoff |
Evidence-driven session handoff: export/resume, interoperable across Codex, Claude, and dsh | Nothing (pure instructions) |
task-id-bootstrap |
Repo-local task state under .agents/state/tasks/<task-id>/, binding the current dsh session (DSH_SESSION_JSONL) to the task |
Python 3.9+ |
Install
dsh plugin --profile web add shared-handoff-dsh
After restarting dsh web, both skills join the skill catalog and the model
loads them through the skill tool.
Usage
Once installed there is no command to remember — the skills are triggered conversationally and the model loads the right SKILL.md itself.
task-id-bootstrap: open a task
Just say in a dsh chat (adjacent Chinese/English punctuation both work):
新开task-id=init-kmp,然后开个 init-kmp 分支
The model runs the bundled bootstrap script; success is proven by three lines:
Task state: .../.agents/state/tasks/init-kmp
Current task: init-kmp
Session binding: /Users/you/.dsh/sessions/.../session.jsonl.zstd
Progress then lives in .agents/state/tasks/init-kmp/process.md; say
继续,task-id=init-kmp later to resume. A directory without a session
binding is only a partial result — the model must report it as such.
If Python (3.9+) is missing on first use, the model reports the gap and shows the install command for your platform, installing only after your explicit consent — never silently.
handoff: export / resume a session
When a thread gets long and you want a fresh one, say:
帮我做个 handoff
You get a paste-ready next-thread prompt (workspace / branch / done / verification status / next step). In the fresh session, open with:
继续上次 handoff
The model rebuilds context from state files instead of chat history.
Phrases like 交接, 新开线程继续, 继续上次, and resume trigger it too.
The two skills cooperate
When a task-id is active in the same repo, handoff treats
.agents/state/tasks/<task-id>/process.md as the canonical state instead
of inventing a parallel one.
Cross-agent handoff
The state layout is identical to the Codex and Claude editions: a handoff
exported from dsh can be resumed in Codex or Claude and vice versa (all
three share the same session-tasks.json).
Automation (hook equivalents)
The three behaviors the original kit implemented through Codex/Claude hooks run automatically on the dsh host side via the harness event system — installed, they just work:
| Original hook | dsh equivalent | Behavior |
|---|---|---|
SessionStart |
first agent/pre-step (step 1) |
The active task's process.md / process.auto.md is injected as a baseline user message — say "继续" in a fresh session and the state is already there; the baseline ends with a reminder to run the handoff skill after completing a milestone, keeping the semantic state fresh |
UserPromptSubmit (task routing) |
agent/pre-step message scan |
A task=<id> marker in the incoming user message re-binds the session and switches current-task (creating the task dir), then injects a switch notice for the new task |
| Continuation | agent/pre-step message scan |
A short continuation prompt (继续 / 接着 / resume / 交接 …) re-injects the persisted state mid-session, labeled as a re-injection |
Stop |
session/event turn/end |
process.auto.md is refreshed after every turn (capturing the turn's last model output) and mirrored into an existing process.recent.md; the same turn also appends one summary line to the ## Auto Log section of process.md (newest last, capped at maxLogEntries, hand-written sections untouched) |
PreCompact / PostCompact |
compaction/start / compaction/summary |
Snapshots are written before and after compaction plus a context_guard.json marker; completed compactions increment auto_compact_count, and at compactThreshold (default 3) clear_required flips on and the next injected baseline carries a controlled-clear notice (hand off, start a fresh session) |
Task resolution matches the original: the session's transcript binding in
session-tasks.json first (dsh sessions align by their transcript path
under $DSH_HOME/sessions), then the current-task pointer. Every write
lands in the same .agents/state/ the Codex/Claude editions use.
Interop with the Codex and pi editions: context_guard.json is written
read–merge–write with the Codex field contract (auto_compact_count,
clear_required, threshold, last_*), and keys owned by other runtimes
(pi_compact_count, last_pi_session_id, …) pass through untouched. The
clear threshold check sums the pi and dsh counters together, so one repo
alternated between runtimes still guards correctly.
To disable a piece, override the row in your profile patch:
- id: shared-handoff
name: 'shared-handoff-dsh'
config:
injectBaseline: false # no session-start injection
autoSnapshot: false # no per-turn snapshots
autoLog: false # no per-turn Auto Log lines in process.md
compactionGuard: false # no compaction guard
handoffReminder: false # no proactive-handoff reminder in the baseline
maxLogChars: 300 # per-entry truncation for Auto Log lines
maxLogEntries: 100 # Auto Log section length cap
compactThreshold: 3 # compactions before a controlled clear is advised
process.auto.md and context_guard.json are host-owned metadata — the
SKILL.md tells the model never to hand-write them; process.md stays
model-maintained except for the host-appended ## Auto Log section at its
end.
Design notes
- archify-dsh pattern:
cordis.patch.ymlmounts an isolated@deepseek-ai/dsh-skill-filesysteminstance (includeDefaultRoots: false- a unique
providerName+bundledSkillDirpointing at the packagedskills/), leaving the stockfilesystemprovider untouched.
- a unique
- Host half (hook equivalents): zero external dependencies (Node
builtins only) — listens to
agent/pre-stepandsession/eventfor injection/snapshots/guard, see Automation above; listeners swallow their own errors, so a snapshot failure can never break the agent loop. - Subagents are read-only (single-writer rule): delegated children and
forks (
origin: "subagent"/ positivedelegationDepth) receive the baseline injection but never write state — no snapshots, no Auto Log entries, no bindings, no compaction-guard updates, and notask=<id>routing (a delegated prompt mentioning a task marker cannot hijack the repo's active task). Parallel children would otherwise clobber each other's snapshots and interleave the Auto Log; the parent session is the single writer, and children's findings flow back through their reports. - Session binding: dsh injects
DSH_SESSION_JSONL(the current session transcript path) into the managed bash/PowerShell environment; the bootstrap script binds it via--transcript-pathwith zero script changes, writing into the samesession-tasks.jsonthe Codex/Claude editions use. - Cross-platform: the SKILL.md ships both bash and PowerShell command
forms plus a Windows 10/11 Python detection matrix (py launcher, Store
alias stub, winget availability); the lock module uses
fcntlon POSIX andmsvcrton Windows, identical to the original. - Missing Python: never installed silently — report the gap, show the
platform-specific command, install only after explicit consent; the
handoffskill and the host-half automation work regardless (they need no Python).
Known limitations
- Only the two platform-neutral skills were ported;
claude-handoff(Claude Code specific) and the Codex/Claude hook runtimes stay with the original kit. - The auto snapshot records the turn's last model output verbatim (facts,
not summaries) — semantic progress still lives in the model-maintained
process.md; the## Auto Logsection gives it a per-turn, timestamped trail without replacing that curation. - Local path installs (
dsh plugin add <path>) resolve as a link; publishing to npm is the sturdier sharing route.
License
MIT (inherited from shared-handoff-kit).
No comments yet. Be the first to write one.