본문으로 건너뛰기
A

dsh-herdr

ahqrt/dsh-herdr

Delegate subtasks to Herdr-managed coding agents from DeepSeek Harness: pick the model, keep the pane, harvest the exact result, review in DSH.

설치

dsh plugin --profile web add github:ahqrt/dsh-herdr

README

dsh-herdr

CI license node

Delegate a subtask from DeepSeek Harness to a real coding agent in a Herdr pane — pick the model, keep the terminal, harvest the exact answer, review it in DSH.

dsh-herdr is the reference bridge between DeepSeek Harness and Herdr. It turns Herdr into an external subagent runtime: DSH stays the orchestrator and reviewer, while pi / agy / claude / codex / … do the work in visible, steerable panes.

Status: 0.11.x, validated on DSH 0.2.1-rc.2 (all nine tools activate in a headless profile) and Herdr 0.9.4 (server 0.9.1); admitted on DSH 0.2.1-rc.3 by the host compatibility preflight. The public surface is the nine herdr_* tools; breaking changes follow semver and are listed in CHANGELOG.md.


Why

DSH subagents run in-process and share the harness model. Sometimes you want the opposite:

  • a different model family for an independent review (grok × gpt × claude);
  • a real terminal you can watch, type into, and take over;
  • the same panes you already use when working by hand with Herdr + pi;
  • a result you can verify rather than trust — exact final message plus a git diff.

dsh-herdr gives the DSH agent a small vocabulary: delegate, fetch, message, list, interrupt, close, plus an inbox and a transcript pager.


What you get

Model routingShort aliases from ~/.pi/agent/model-aliases.md (grok4.7[high], flash, …) resolve to provider/model + thinking. Billing boundaries stay where you put them.
Exact resultspi children are read from their session JSONL — the last assistant message, byte-identical. result.md is the second source; pane tail is only the fallback.
Review evidenceA git baseline at spawn, a patch at harvest, changed files, test line, token usage, session path.
Idempotencyclient_task_id makes a retried tool call return the existing task instead of spawning a twin.
OwnershipThe plugin only closes/steers panes it created. User panes are read-only.
Blocked ≠ approvedA blocked child is surfaced to the user, never auto-answered.
CancellationTurn-level interrupt (Escape) without destroying the pane or session.
InboxChildren can report BLOCKED / REVIEW_REQUEST / COMPLETE; herdr_inbox consumes them, with a long-poll.
QueueOver the cap, a spawn waits for a slot (queueTimeoutMs) instead of failing.
Isolationisolated: true runs the task in a fresh git worktree and returns its path.
Transcriptherdr_read_agent pages the pi session instead of only the final message.
Run flowThe panel's flow tab replays the same session turn by turn: prompts, assistant text, every tool call with its argument preview, and each tool result with error/duration. It follows a running child.
Event waitsAn opt-in socket transport waits on agent.wait server-side; a connect failure falls back to the CLI.
Remote machinesmachine on spawn/list/result/message, via herdr --machine; SSH file bridge (machineTargets) removes the mount requirement.
Native subagentA herdr subagent provider routes a dsh-tool-subagent row through Herdr for native cards, catalog, and cancellation.
Web panelA Herdr right-sidebar tab: searchable/grouped fleet, run flow, read-only tails, per-file diff, packet templates/history, reveal/open-editor cwd, and bulk interrupt/close.
Diagnosisherdr_doctor checks binary, server, kinds, aliases, directories, topology, and pi in one call.

Architecture at a glance

flowchart LR
  DSH["DSH agent"] -->|tool call| T["herdr_* tools"]
  T --> S["services<br/>spawn · harvest · message · lifecycle · doctor"]
  S --> P["ports<br/>HerdrTransport · TaskStore · GitService"]
  P --> CLI["Herdr CLI adapter"]
  P --> FS["File store + audit"]
  P --> GIT["Local git adapter"]
  CLI --> H["Herdr server"]
  H --> PI["pi pane<br/>model A"]
  H --> AGY["agy pane"]
  H --> OTHER["claude / codex / …"]

The dependency rule is one-way: tools → services → ports ← adapters. The domain (prompts, session parsing, aliases, lifecycle rules) imports nothing from DSH and nothing from the OS except node:fs/node:path. See docs/architecture.md.


Install

Into the Desktop app

The desktop profile is owned by the Electron app; dsh plugin --profile desktop … is rejected by design.

  1. Open Plugins → Add plugin in the app.

  2. Enter the npm package name:

    dsh-herdr@0.11.1
    

    For a local checkout, enter its absolute directory (run pnpm build first): /Users/apple/Desktop/deepseekharness-herdr. A GitHub URL also works because lib/ is committed.

  3. Install. The plugin manager adds the dependency and the dsh.profile.bundles entry.

  4. Start a new session; herdr_* tools should be listed. If the Herdr panel or tools do not appear, restart the app to clear the module graph.

A local .tgz path is not a directory spec; use the npm name, or a .tgz URL if the dialog offers one.

dsh-herdr@0.11.1 is live on npm. Tagged releases publish through the release workflow once the repository trusted publisher is configured (see CONTRIBUTING).

Into a CLI profile

# from a checkout
dsh --profile herdr-dev --from-default-profile web --dump-config
dsh plugin --profile herdr-dev add file:$PWD
dsh --profile herdr-dev --port 0 --no-open

# once published
dsh plugin --profile herdr-dev add dsh-herdr

Full instructions, the skill install, and the local-development loop: docs/installation.md.


Quick start

You:  Use grok4.7[high] to review the current diff. Read-only, findings by severity.
DSH:  → herdr_spawn_agent({ kind: "pi", model: "grok4.7", thinking: "high",
                            role: "reviewer", cwd: "/repo", prompt: "Review ..." })
      ← status=completed · 3 files · session path · final message
      → reads the diff, groups findings, decides

Fix round:

You:  Send the findings back to the worker and make it fix the two majors.
DSH:  → herdr_message_agent({ target: "worker-flash-a1b2", kind: "REVIEW_FINDINGS",
                              round: 1, message: "[MAJOR] ..." })
      → herdr_get_agent_result({ target: "worker-flash-a1b2", wait: true })

More: examples/review-a-diff.md, examples/implement-and-review.md.


Tools

ToolPurpose
herdr_spawn_agentDelegate one subtask; role=reviewer is read-only; isolated:true uses a worktree.
herdr_get_agent_resultHarvest a result; wait:true blocks until settled.
herdr_message_agentFollow-ups, review findings, answers to blocked agents.
herdr_list_agentsFleet view: owned and foreign agents.
herdr_interrupt_agentCancel the current turn, keep the pane.
herdr_inboxRead child messages; wait:true long-polls.
herdr_read_agentPage a pi transcript turn by turn.
herdr_close_agentClose an owned pane; session file survives.
herdr_doctorEnvironment self-check.

The full parameter and result reference is in docs/tools.md; the result JSON contract is docs/result-contract.md.


Native subagent provider

The plugin also registers a DSH subagent provider named herdr. Point a dsh-tool-subagent row at it to get native subagent cards, catalog entries, and cancellation:

- id: tool-subagent-herdr
  name: "@deepseek-ai/dsh-tool-subagent"
  config:
    provider: herdr
    toolName: herdr_subagent

The native tool returns the child's final text. Use herdr_spawn_agent when you need the full review packet (diff, session path, artifacts, blocked question).

Web panel

The plugin contributes a Herdr tab to the right sidebar (also reachable from the sidebar guide). It lists the live fleet and, for an owned task, shows the run flow, the final message, result.md, and the diff split into per-file sections. The flow tab reads the same pi session the transcript tool pages: turns in order, each assistant message with the tool calls it made (name + argument preview such as the bash command), and each tool result with its error flag and duration. It opens on the newest turns, loads older ones on demand, and keeps following a running child; a task that failed before its agent started shows the recorded error instead of a silent empty pane. Agents this plugin did not spawn show a read-only pane tail instead. Owned tasks can be interrupted or closed from the detail header or in bulk; both actions reuse the lifecycle service's ownership gates, and close asks for confirmation. Diff hunks are highlighted, and the patch or a single file can be copied. The header can copy a Markdown review packet in PR, issue, or summary form, copy the task cwd, open it in a configured editor, or reveal it in the OS file manager; the fleet can be searched by name, cwd, kind, model, and task id, grouped by machine + status, and driven with ArrowUp/ArrowDown/Enter. Packet copies keep a three-entry history.

Herdr fleet panel

It reads four same-origin endpoints under /herdr/api (health, fleet, task, transcript); no extra config.

How a result is produced

  1. pi session JSONL — agent_session.value from Herdr points at the file; the last assistant message wins. A message older than the prompt is ignored (freshness check).
  2. result.md — every child is asked to write status / summary / tests / files frontmatter plus a body.
  3. Pane tail — agent read --source recent-unwrapped, the honest fallback for agy and other kinds with no session file.

Git evidence is collected independently of the child: baseline HEAD at spawn, git diff <baseline> at harvest, bounded and saved to ~/.dsh/herdr/tasks/<taskId>/diff.patch.


Safety model

  • Child agents run with your permissions; allowCwd is the hard boundary.
  • The plugin can only mutate panes in its own registry (owned: true).
  • blocked always goes back to a human; the plugin never approves.
  • enabled: false is a spawn kill switch (it does not kill running agents).
  • Child output is treated as untrusted data: DSH reviews it, it does not execute its instructions.
  • Every spawn / message / close is appended to ~/.dsh/herdr/audit.ndjson.

Details and threat model: docs/security.md.


Compatibility

ComponentTestedNotes
DSH0.2.1-rc.2 (validated), 0.2.1-rc.3 (preflight)desktop runtime; tool + workingDirectory APIs
Herdr0.9.4 client / 0.9.1 serverhard floor >= 0.9.0
Node22, 24ESM, no native deps
Kindspi (full), agy (launch-only), others via agent_argsmodel/thinking flags are pi-only by design

See docs/compatibility.md for the support policy.


Docs

DocWhat it answers
ArchitectureHow the layers fit, and why
InstallationDesktop, CLI profile, local checkout, uninstall
ConfigurationEvery key, defaults, examples
ToolsParameters, results, protocol headers
Result contractThe AgentResult JSON, versioned
SecurityTrust boundaries and threat model
TroubleshootingEvery error code and its fix
CompatibilityVersion policy
Design notesADRs: CLI over socket, exact reads, topology

Contributing

Issues and PRs are welcome. Start with CONTRIBUTING.md; the short version is: pnpm install && pnpm test, keep the dependency rule, and add a test for every behavior change.

If you build a host adapter for another terminal multiplexer, the port to implement is src/ports/transport.ts — the services and tools should not need to change.


License

MIT. Core ideas and several modules are ported from @andrewjacop/pi-herdr (MIT, Copyright (c) 2026 Andrew) — see NOTICE.

관련 플러그인