Skip to main content
L

dsh-conductor

lucagiftzek/dsh-conductor

A Conductor tab and commands for a chat's context: /new replaces the context in place with a model-written handoff, /rewind restores the chat and the agent's file edits to an earlier prompt, plus /drop, pins, an automatic compaction level, recovery after failed turns, silent messages between chats and agent and task orchestration. Supersedes dsh-orchestrator, dsh-force-compact and dsh-continue, so do not install it alongside them. Requires DSH >= 0.2.1-rc.5, Node >= 22.5, the web profile and dsh-better-sidebar.

Install

dsh plugin --profile web add github:lucagiftzek/dsh-conductor

README

dsh-conductor

npm

Fresh context in the same chat, rewind to any prompt (chat and files), automatic compaction at your level and recovery after failed turns, all in one sidebar tab.

dsh plugin --profile web add dsh-better-sidebar   # the tab host, skip if installed (on DSH 0.2.1: dsh-better-sidebar@0.28.2)
dsh plugin --profile web add @lucagiftzek/dsh-conductor
# or from GitHub: dsh plugin --profile web add github:lucagiftzek/dsh-conductor
# restart dsh web, then open the Conductor tab from the sidebar's + menu

The Conductor tab next to a chat with a ghost message and an edited answer

Screenshot from a demo DSH instance with sample data.

Keep long DeepSeek Harness chats cheap and under control. /new gives a chat a fresh context in place: the model writes a handoff from the full conversation, and that handoff becomes the whole history. Same chat, same title, same pin, same position in the sidebar, same id for every script that talks to it. Nothing is lost: the full transcript stays visible above and is archived as Markdown.

Around that: /clear, /drop single items out of the context, pins that survive every reset, message versions shown right in the chat, "ghosts" (silent messages between chats that never wake the receiver, shown in the chat with a Ghost label), and multi-chat orchestration (agents, tasks, runners). One plugin, one sidebar tab with five sub-tabs, three model tools.

Ghosts and a v2 answer in the chat/new in progress (Cancel keeps the context)History: resets and edits with a diff
Rewind: chat and files, with a preview of what comes backAutomation: level, scheduled /new, relay, template, recovery

Why

Every request a chat sends carries its whole surviving history. A coordinator chat that has run for a week sends hundreds of thousands of tokens per step, most of it stale tool output. Compaction helps but keeps piling summaries on summaries; starting a new chat loses the chat's identity (scripts, pins, title, the place in the sidebar) and its accumulated context.

/new measured in the test lab: the first request after /new is the size of a brand new chat's first request plus the handoff (within 2K tokens), while the chat keeps its id, title and pins. The only fixed cost left is what every chat pays anyway: system prompt, workspace instructions and tool definitions.

Features

What it doesHow
/new [focus]Fresh context in the same chat from a model-written handoffA compaction whose summary is the handoff. One model call over the full context (reuses the provider cache); the handoff is also saved as a file
/clearEmpty the model context, keep the chatA compaction with a short placeholder; no model call
/force-compact [--pointer] [focus]Compact even past the model window (from dsh-force-compact)Map-reduce summary in parts that fit, or a mechanical checkpoint with no model call
/contextWhat fills the context, largest items firstReads the live surface and the token meter
/drop ..., /undropTake tool outputs, messages or whole steps out of the context, put them backSurface replacements that cite the originals; the transcript and a saved file keep them
/pin, /unpin, star buttonKeep a message verbatim across every /new, /clear and compactionSide store; pins are re-added to every checkpoint
VersionsEdit a message or an answer (you or the model); the chat shows the current text with a "v2" marker, every version is kept with a diffSurface replacement plus a version list; the chat renders through its own message renderer
Ghosts: /post, dsh-post, chats postSilent message into another chat: shown there as a message with a Ghost label, read by its model on the next turn, never wakes itAppended notice the chat renders as a message; script API with a secret
/checkpoint, /rewindGo back to any earlier prompt: the conversation, the files the agent edited, or both; or continue from there in a new chatA checkpoint per prompt; pre-images of the agent's file edits in Conductor's own store (your git is never touched); the rewound part is archived
Automatic level (/auto level)The chat compacts, or hands off to a fresh context, by itself at the percentage of the model window you choose, after one heads-up to the modelWraps the engine's pressure check with a per-chat threshold
Scheduled /new (/auto new)A fresh context every day at a set time or every N turnsRuns when the chat is idle
Recovery (/recovery)Resumes by itself after rate limits, provider errors, cut-off answers and restarts; stops at once on quota or credential errorsReads how each turn ended, after DSH's own retries; replaces dsh-continue
Relay (/relay <chat>)Every final answer of this chat arrives in a coordinator chat as a ghostNo scripts needed for worker reports
/recallSearch this chat's earlier epochs (archives, dropped items, handoffs)Keyword ranking over line windows, no model, no index
Handoff templateYour own handoff sections, for all chats or oneReplaces the eight default sections
OrchestrationAgents (spawn, prompt, fork, cancel), tasks (command, scrape, http, agent), runners, provider cardsFrom dsh-orchestrator, see docs/ORCHESTRATION.md
Conductor tabContext meter, then sub-tabs Context, Pins, Inbox, History, AgentsBetter Sidebar tab

Install

Requires DSH 0.2.1-rc.5 or newer, the web profile and dsh-better-sidebar (pin 0.28.2 on DSH 0.2.1; its latest needs DSH 0.2.2).

cd ~/.dsh && dsh plugin --profile web add dsh-better-sidebar && dsh plugin --profile web add @lucagiftzek/dsh-conductor
# on DSH 0.2.1 pin the sidebar: dsh plugin --profile web add dsh-better-sidebar@0.28.2 (its latest needs DSH 0.2.2)
# or from GitHub: dsh plugin --profile web add github:lucagiftzek/dsh-conductor
# restart dsh web

A brand new npm release is picked up by dsh plugin add about a day after it is published (pnpm's minimum release age); the GitHub line works at once.

From a checkout: add "@lucagiftzek/dsh-conductor": "link:/path/to/dsh-conductor" to ~/.dsh/profiles/web/package.json dependencies, append @lucagiftzek/dsh-conductor to dsh.profile.bundles, run pnpm install there and restart.

First run. On a fresh install the Conductor tab opens with a one-minute setup guide (what the assistant may do on its own, ghosts and the script secret, agents and tasks). "Use defaults" skips it; it can be run again from the tab's "..." menu or Settings. An agent that installs and configures the plugin for you can skip the guide by writing setupCompleted: "<ISO time>" into the dsh-conductor row (the migration below does this).

Coming from dsh-orchestrator, dsh-force-compact or dsh-continue? Their features are inside dsh-conductor. Install it as above, then run the migration (dry run first) and restart:

M=~/.dsh/profiles/web/node_modules/@lucagiftzek/dsh-conductor/scripts/migrate-profile.mjs
node $M                                          # shows what changes
node $M --apply                                  # backs up, then edits package.json and cordis.patch.yml
cd ~/.dsh/profiles/web && pnpm install           # then restart dsh web

It removes the old plugins, carries the orchestrator's runners, providers and trusted hosts and dsh-continue's resume text over, keeps shell tasks on if you used runners, keeps the old orch_* tool names (tools.legacy) and the old /dsh-orchestrator/api route (legacyRoute) so existing prompts and scripts keep working. Archives stay in ~/.dsh/compact-archive. Roll back by copying the two *.bak-conductor-* files back.

Using it

The Conductor tab

Open it from the sidebar's + menu (or type /conductor, /pins, /inbox, /versions). The header is one line: "12K of 200K 6%" over a thin bar (click the numbers for the breakdown by category), the New context button (/new) and a "..." menu with Clear (asks once, because it has no undo), Compact and Refresh. While a reset runs, the header shows its elapsed time and a Cancel button that leaves the context untouched; afterwards, View handoff and View archive open the files in the sidebar.

Below, one sub-tab at a time (the last one is remembered per chat):

Sub-tabShows
Contextthe 8 biggest items with a Drop button each; "Show all items" or "Select several" opens the full inspector
Pinspinned messages, their size, notes, unpin
Inboxghosts received, unread first, Mark all read, Add to context, Post to another chat
Historyone timeline of resets (tokens before and after), edits (versions, diff, Restore) and other activity
Agentswhat is running now; all agents, tasks, runners and providers behind two links

Reversible actions (drop, unpin, mark read, dismiss) show a toast with Undo for 10 seconds (Ctrl/Cmd+Z works too). The tab polls only while it is visible.

/new

Type /new (optionally with what matters: /new focus on the migration). The chat shows a command row while the handoff is written (usually under a minute), then:

Fresh context from a handoff: 212K to 9K tokens. 2 pin(s) kept.
Handoff: ~/.dsh/dsh-conductor/handoffs/<chat>/<time>.md
Archive: ~/.dsh/compact-archive/<chat>/<time>.md

Keep typing in the same box. The model now sees: the system prompt, the workspace instructions, the handoff, your pins and a pointer to the archive it can search when it needs an old detail. The handoff has fixed sections: role and standing orders, goal and state, decisions, open items (your latest requests quoted), files and commands, running work, gotchas, next step.

There is no undo, by design: nothing is destroyed. The transcript stays visible above the divider and verbatim in the archive.

/clear

Empties the model context without a summary (no model call). Pins are kept. Use /new when the work should carry on, /clear when it should not.

/drop and /context

/context                     what fills the context, with the numbers /drop uses
/drop last 3                 the 3 most recent tool outputs
/drop tool browser_snapshot keep 1
/drop file src/app.ts        tool outputs whose call mentions it
/drop larger 10K             every tool output above 10K tokens
/drop 41 57                  exact items
/undrop                      put the last one back (/undrop all, /undrop <id>)

Bare /drop opens the Conductor tab on the Context inspector: tick items, the footer shows what you save, one click drops them. A dropped item leaves a one-line placeholder for the model, so it knows something was there, and the original is saved to a file it can read if needed. An assistant step is dropped together with its tool results. DSH's log format only accepts a rewritten tool output inside a turn, so tool outputs dropped while the chat is idle leave the context at the start of your next message (the inspector marks them as pending); messages and steps leave at once.

Pins

/pin pins the last answer, /pin user your last message, the star in an answer's action row toggles it. Pins are kept verbatim through every /new, /clear and compaction (up to 50 per chat; each shows its token cost). The model can pin too, and cannot remove your pins.

Versions

Open a message in the Context sub-tab and choose Edit (or the model edits its own final answer through the chat tool). The chat shows the new text in place with a small "v2" marker (click it for the versions and Restore), and the model sees the new text from its next step, marked as edited. Every version is kept with a word diff in History. User messages keep their role; an edited assistant answer is shown to the model as a quoted correction, because DSH's log never accepts a rewritten assistant message.

Ghosts: silent messages between chats

/post "Coordinator" the nightly import finished: 1,204 rows

The target chat shows it as a message with a Ghost label (and Report or Alert), lists it in the Inbox sub-tab with an unread count, and its model reads it on its next turn. It is not woken, so a coordinator chat does not pay a full-context turn for every worker report. From scripts and cron:

export DSH_CONDUCTOR_SECRET_FILE=~/.dsh/dsh-conductor/api-secret   # set the secret in Settings first
scripts/dsh-post --kind report --from "nightly import" "Coordinator" "done: 1,204 rows"

Raw API: POST /dsh-conductor/api/remote/post with header x-conductor-secret and body { "to", "text", "from", "kind": "report|alert|note", "visible": "user+model|user" }.

Checkpoints and rewind

A checkpoint is made at the start of every prompt; /checkpoint <name> marks one by hand (the model can too, before something risky). /rewind lists them, newest first.

/rewind 1              back to before the last prompt: conversation and files
/rewind "before migration" --files    only the files
/rewind 3 --chat       only the conversation
/rewind 3 --branch     continue from there in a new chat; this one stays as it is
/rewind undo           put back the files the last rewind restored
  • Conversation: everything after the checkpoint leaves the model's context (archived first); the chat window keeps the old messages and shows a "Rewound" divider. This part cannot be undone in place, but the archive keeps the text and --branch works on any checkpoint. If a reset or compaction has since merged that point into a summary, an exact in-place rewind is impossible and Conductor says so; --branch still works.
  • Files: before the agent's file tools change a file for the first time in a turn, its content is copied into Conductor's own store. A rewind puts every such file back and removes files created after the checkpoint. A file someone changed after the agent's last edit is a conflict and is skipped unless you add --force. The current content is saved first, so /rewind undo reverses a file restore. Changes made by shell commands, scripts or other programs are not tracked (as in Claude Code); use git for those.
  • Up to 100 checkpoints per chat; older file copies are removed with them. Files over 2 MB, symbolic links and hard links are not copied.

Automation: level, scheduled /new, relay

/auto                      what is active in this chat
/auto level 50             compact by itself at 50% of the model window
/auto level 50 handoff     at 50%, hand off to a fresh context instead (like /new, automatically)
/auto level default        back to the global level (Settings); DSH's own default is about 80%
/auto pause | resume       stop or restart the automatic level for this chat
/auto new daily 03:00      a fresh context every night (only when the chat is idle)
/auto new turns 40         a fresh context every 40 turns
/relay "Coordinator"       every final answer of this chat arrives there as a ghost; /relay off stops

Shortly before the level (at 85% of it) the model gets one short heads-up to read less and finish cleanly. The level applies to automatic compaction during a turn; DSH's own recovery when a request overflows the window is unchanged.

Recovery

When a turn ends badly, Conductor carries on by itself, after DSH's own quick retries have given up:

What happenedWhat Recovery does
Rate limit, provider error, connection problemResumes after the provider's Retry-After, or with growing waits (2 s, 4 s, 8 s, ... up to a minute), at most 5 times in a row and 20 times an hour
Quota or balance exhausted, credentials rejected, invalid requestStops at once and leaves a ghost in the chat (and in the coordinator it relays to)
The context overflowed and DSH could not recoverHands off to a fresh context (/new), then continues
The answer was cut off at the output limitAsks the model to continue exactly where it stopped
dsh-web restarted or crashed during a turnWhen the chat is loaded again (chats active in the last 20 minutes are loaded at start), continues and names tools whose outcome is unknown

An optional fallback model (Settings, Recovery) takes over after a number of failures, for that chat only, and the chat goes back to its own model after a good turn. /recovery off lets failed turns wait for you in one chat. Recovery stays off while @weibaohui/dsh-continue is still installed, so the two never both send "continue".

Searching earlier context

/recall deploy key (or "exact phrase") searches this chat's earlier epochs: the archive of every /new, /clear, compaction and rewind, dropped items and handoffs, and shows the best passages with file and line. The model has the same search (chat tool, action recall) and is told to use it instead of reading archive files.

Handoff template

The handoff has eight sections by default. Settings, Conductor, Handoff template replaces them for every chat; the Automation panel (or POST .../template) sets one for a single chat, for example with "Customers" and "Deploy state" sections.

Model tools

Three tools instead of sixteen, because every tool definition is paid on every request (about 1.8K tokens for all three; the 14 old orch_* tools alone were about 2.2K):

ToolActions
chatthis chat: context, drop, undrop, pin, unpin, pins, edit, versions, new, compact, clear, inbox, mark_read, recall, relay, checkpoint
chatsother chats: list, status, prompt (wakes), post (silent), spawn, fork, cancel
tasksoverview, create (command, scrape, http, agent), list, status, output, cancel, runners, providers

Changes the model asks for during its own turn are applied before its next step, never inside a tool call; new, compact and clear run when the turn ends. What the model may do is set in Settings, Conductor, "The model may" (default: everything except clear). Every model action is written to the chat's Activity log.

How it works

  • In place, through core compaction. /new, /clear and /force-compact call the chat's own /compact. DSH's compaction engine keeps the locking, the events and the surface replacement; Conductor only decides what the checkpoint says, through the engine's documented summarize() hook. Manual compaction replaces everything except the system prompt and the last answer, and DSH re-adds the workspace instructions and runtime context on the next request (verified in the lab).
  • Checkpoints use DSH's file hooks. The agent's file tools announce every write and edit through DSH's file service; Conductor copies the file just before the first change in each turn. A rewind of the conversation is the same kind of replacement as a drop, over everything after the checkpoint.
  • Nothing is deleted. DSH keeps an append-only log. Every change is a replace event that shadows earlier nodes and cites them. The chat transcript keeps showing the originals; archives and saved files keep them verbatim.
  • Side store. Pins, versions, inbox, epochs, drops and activity live in one JSON file per chat (<stateDir>/sessions/<chat>.json, mode 0600), never in the session log, so removing the plugin never makes a chat unloadable.
  • Log format rules found and enforced: a rewritten tool output must sit inside a turn; an assistant message cannot be a replacement; the system prompt is never touched; nothing changes while a compaction is open; every change keeps tool calls paired with their results.

Settings

Settings, Conductor (or the dsh-conductor row of the profile's cordis.patch.yml):

KeyDefaultMeaning
modulesall oncontext (/new, /clear, /drop, /force-compact), pins, posts, versions, orchestration
toolschat, chats, tasks on, legacy offwhich model tools exist; legacy adds the 14 orch_* names
modelMayall on except clearwhat the model may do: drop, edit, pin, new, compact, clear, post, prompt, spawn, cancel
handoffDir<stateDir>/handoffswhere handoff files go
posts.maxChars, posts.chatRow8000, offlonger posts are saved to a file and linked; chatRow adds a command row in the target for clients without the Conductor UI (the web UI shows ghosts as messages)
resetTimeoutMs15 mincap for one /new
tasks.allowCommandTasks, tasks.allowRemoteRunnersoffshell tasks and ssh/http runners are opt-in
compactengine defaultsarchiveDir, archiveEveryCompaction, overflowFallback, chunk sizes (row config, applied at start)
legacyRouteoffalso serve the API under /dsh-orchestrator/api
setupCompletedemptywhen the first-run guide was finished; empty shows the guide in the Conductor tab
autoCompact{ percent: 0, action: compact, nudge: true }the automatic level for every chat: percent of the model window (0 = DSH default, about 80%), compact or handoff, and the heads-up before it
recoveryonenabled, maxAttempts 5, baseDelayMs 2000, maxDelayMs 60000, hourlyCap 20, continueTruncated, overflow (handoff or stop), resumeCrashed, crashWindowMinutes 20, fallbackProvider, fallbackModel, fallbackAfter 3, resumeText
handoffTemplateemptyyour handoff sections for every chat (empty = the eight default sections)
stateDir~/.dsh/dsh-conductorside store, handoffs, saved posts, task history

The orchestration settings (runners, providers, limits, the machine secret) are described in docs/ORCHESTRATION.md.

Files

PathWhat
~/.dsh/compact-archive/<chat>/<time>.mdverbatim transcript of every replaced span (every /new, /clear, compaction)
~/.dsh/compact-archive/<chat>/drops/originals of dropped items
<stateDir>/handoffs/<chat>/<time>.mdhandoff documents
<stateDir>/sessions/<chat>.jsonpins, versions, inbox, epochs, drops, checkpoints, automation, activity
<stateDir>/checkpoints/<chat>/copies of files before the agent changed them (content addressed) and one manifest per turn

All 0600 in 0700 directories. Archives can contain anything that passed through the chat, including tool output: keep them private. They are not pruned automatically.

Security

  • Browser routes: loopback peer, trusted Host, same-origin, JSON content type, x-requested-with: dsh-conductor and the harness session cookie on every mutation. No GET mutates.
  • Machine routes (/remote/*): secret only (x-conductor-secret or Authorization: Bearer), constant-time compare, rate limited, fail closed without a configured secret.
  • Shell tasks and remote runners are off until you enable them. The model cannot clear a chat or remove your pins unless you allow it.
  • Known limit: if DSH's session-log upload to the official DeepSeek API is enabled, dropped originals are still part of the log it uploads.

Testing

npm test               # unit tests: engine modes, surface rules, store, commands, tools, orchestration, settings, client
test/lab/setup.sh      # once: create the lab, a separate DSH home (~/dsh-lab) that never touches ~/.dsh
npm run lab start      # the lab on 127.0.0.1:3193 with a scripted mock model on 127.0.0.1:3194
npm run test:e2e       # end to end against the lab, including a restart and a reload check of every chat it touched

The end-to-end suite asserts on the real session log, the real surface and the exact requests the model receives. test/lab/demo.sh runs a separate demo instance with sample chats (the README screenshots come from it). See test/lab/.

Compatibility

Built and tested on DSH 0.2.1-rc.5 with dsh-better-sidebar 0.28.2. The plugin resolves every DSH package at run time and degrades with a clear warning when a seam is missing (no compaction engine: /new and /clear report it; no Better Sidebar: no tab, everything else works).

More plugins by the same author

All of them are open source and run on DeepSeek Harness 0.2.x.

PluginWhat it does
dsh-artifactsAn Artifacts tab that lists the files an agent produced and previews them in place, plus a template library agents can use and extend
dsh-mailMail client and agent mail tools: IMAP, POP3, SMTP and OAuth2 accounts, scheduled and bulk sends with unsubscribe handling
dsh-note-keeperObsidian-compatible Markdown notes in the sidebar with search, graph, audio notes and transcription, OCR and client-side encryption
dsh-phoneSMS and calls (Twilio, SIP via Asterisk) with call audio through your own server, live voicemail and Telegram
dsh-voiceRead-aloud, dictation and language-aware speech with 23 TTS and STT providers, per-language routing and word highlighting
dsh-orchestratorThe earlier standalone agent and task orchestration plugin; dsh-conductor includes all of it
dsh-workspace-railA workspace-first sidebar rail: pinned chats, projects as folders, live Recents, search and unread markers
DSH-Idle-WatchdogIdle-chat nudges and an authenticated HTTP API that posts a prompt into any chat
dsh-plugin-updatesUpdate checker that only offers releases your running DSH core can load
dsh-subagent-tieringSubagents default to a cheaper sibling of the parent model unless the agent names a route
dsh-fs-reobserveEnds self-inflicted stale-file errors after an agent's own shell commands
dsh-request-image-capClamps every image sent to the model to a pixel cap, fixing many-image request errors
dsh-sealAn encrypted channel in front of DSH: a Go reverse proxy plus a service worker that seal all DSH browser traffic

Built by Luca Tzekos, who also makes Job Opportunities API: employer-direct job data with per-field provenance you can verify yourself, free to read and available as an API. If this plugin is useful to you, a star on this repo or a look at jobopportunitiesapi.org is the best thanks.

License

MIT. Includes the code of dsh-orchestrator and dsh-force-compact (same author).

Related plugins