orphiczhou/dsh-session-tree ↗★ 0
@orphiczhou/dsh-session-tree
Left-sidebar session tree for DeepSeek Harness: every session with its nested subagent descendants, click-through to multi-turn conversations, plus the tree_send tool for messaging any continuable session across the tree. 适合需要清晰管理嵌套子会话、并跨树发送消息的复杂多智能体任务。
Install
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:orphiczhou/dsh-session-treeREADME
Read the full README ↗Usage
Expanding and opening
- Click the ▶ twisty on a row to expand or collapse it. Rows without children show no twisty.
- A collapsed row that has children shows its child count on the right.
- Click anywhere else on a row to open that session. Top-level sessions open through the shipped navigation (
openSession(sessionId)); subagent rows open throughopenSession({ parentSessionId, childSessionId, mode }), so a continuable subagent shows its multi-turn history and accepts your follow-up prompts. A finished one-shot subagent opens read-only — that is DSH's own behaviour, not this plugin's. - The
↗button on a subagent row opens the same conversation in the right sidebar as a separatesubagentchatpane, leaving the left sidebar where it is. - The
+button in the header starts a new session.
View options
The … button in the header opens:
- Order by — Last updated or Title. Pinned sessions lead the list in either order.
- Archived sessions — Hide archived (default), Show archived, or Archived only.
- Expand all / Collapse all.
- Reload titles — re-reads every session's current title from the Host (see How it works).
Per-row actions
The … button on a row (visible on hover) opens: Pin / Unpin, Rename, Fork session, Archive / Unarchive. Rename edits in place — Enter commits, Esc cancels, losing focus commits. Fork is offered for ordinary sessions only; subagent rows do not show it.
tree_send
tree_send delivers a message to a subagent session that is not your direct parent or direct child. The built-in send_message authorizes by an exact live sender and therefore enforces direct parent/child adjacency, so sibling-to-sibling messaging has no path through it. tree_send authorizes by the target's durable parent address instead, which is what makes siblings reachable.
| Parameter | Required | Meaning |
|---|---|---|
target | yes | Session id of the continuable subagent to message. |
message | yes | The message text to deliver. |
delivery | no | steer (default) delivers at the target's nearest step boundary; queue targets a later turn. |
parent | no | The target's direct parent session id. Omit it and the tool resolves it from the target's own session log. |
It returns acceptance only — a message id — and never waits for or returns a reply:
{ "messageId": "…", "parent": "session-1d637ac2-…", "delivery": "steer" }
Worked example
Consider one root session A with two continuable subagent children B and C, and a grandchild D under B:
A (top-level session, runs the tree_send tool)
├── B (continuable subagent)
│ └── D (continuable subagent)
└── C (continuable subagent)
Sibling → sibling. The agent inside B wants to hand a finding to C. It runs:
{ "target": "C", "message": "The schema you asked about is in packages/session/session-title/src/types.ts.", "delivery": "steer" }
parent is omitted, so the tool reads C's log, finds its parentSession (A), and delivers through that address. A is live, so the delivery is accepted. This is the case the built-in APIs cannot express, because B is not C's parent.
Parent → child. A messaging B or C is the same call with target set to the child, and resolves the same way — B's own log names A as its parent, which is exactly the address the delivery uses.
Root → grandchild is not a path. A messaging D would require delivering through D's direct parent address (B), and D is not that parent's own child from the tool's point of view — the request is refused with subagent/parent-unavailable. Chain two sends: A → B, then B → D.
Exact limits
- The target must be a continuable subagent (
mode: 'continuable'). A one-shot child is refused as not resumable. - The target's direct parent session must be live. If it is not, the call fails with
subagent/parent-unavailable. - The call returns acceptance only (a message id). It never waits for, and never returns, a reply.
- A target whose log has no
parentSessionis not a subagent session and cannot be addressed this way. Passingparentexplicitly is what decides the delivery address; if you pass a wrong one, the delivery is rejected by the service. - Two unrelated top-level sessions still cannot reach each other. They share no parent address, so there is no path —
tree_sendextends who can be addressed, not who is reachable.
Failures are reported as thrown errors with a tree_send: prefix, for example tree_send: delivery rejected — subagent/parent-unavailable: ….