Architecture Overview
August 22, 2026 · View on GitHub
dsh-plugin-message-edit provides ChatGPT/Claude-style conversation branching and message editing for DeepSeek Harness (DSH).
Because DSH session event logs are append-only without native in-session branching, this plugin splits responsibilities across a Node.js Host Service and a Browser/Web Client.
1. System Components
┌─────────────────────────────────────────────────────────────┐
│ DSH Desktop / Web │
│ │
│ ┌──────────────────────┐ ┌──────────────────────┐ │
│ │ Client Half │ HTTP │ Host Half │ │
│ │ (plugin.client.js) │<───────>│ (lib/index.js) │ │
│ └──────────┬───────────┘ └──────────┬───────────┘ │
│ │ │ │
│ Shadow User Message Cordis Services: │
│ Versions Tab (Graph) - sessions │
│ Settings UI - agents │
│ - webServer │
│ - sessionPersistence │
└─────────────────────────────────────────────────────────────┘
1.1 Host Half (lib/index.js)
- Runs in the Node.js backend process via Cordis lifecycle injection.
- Registers the
/message-treeHTTP route onctx.webServer. - Owns branch creation transactions (
POST /message-tree):- Truncates parent events up to the target turn.
- Seeds a new DSH session with the prefix events.
- Appends a durable
message-tree/versionmarker withignorable: true. - Submits the edited prompt into the new session.
- Owns graph queries (
GET /message-tree?sessionId=...):- Traverses the session family DAG.
- Recovers deleted/ghost ancestors from surviving descendants' event logs.
- Extracts turn event boundaries for turn-level rendering.
1.2 Client Half (plugin.client.js)
- Runs in the browser / renderer process.
- Injects a shadowed
usermessage renderer at priority-1to add the edit/copy/retry toolbar and‹ n/m ›version ring without modifying agent responses, tool calls, or reasoning blocks. - Adds the Versions tab (
VIEW_ORDER: 16) providing an interactive pan/zoom graph with spring physics. - Adds settings options in Settings → Message Edit with live layout switching (ChatGPT, DeepSeek, Claude styles).
2. Durable Storage Model
DSH sessions are immutable append-only logs. When branching:
- Seed Inheritance: A new session is initialized whose log begins with an exact clone of the parent's event log up to the start of the edited turn (
seedLength). - Durable Marker: The host appends a custom event:
{ "type": "message-tree/version", "data": { "schemaVersion": 1, "effect": { "operation": "edit", "targetTurn": 1, "targetEventSeq": 5, "before": "Original message text", "after": "Edited message text" }, "inverse": { "kind": "restore-version", "sessionId": "parent-session-id" } } } ignorableFlag: Custom plugin event types fall outside DSH's core schema. The event envelope must setignorable: true; otherwise, DSH's built-in event reader will reject the entire session log.
3. HTTP API
GET /message-tree?sessionId={id}
Returns the entire conversation family surrounding the requested session.
Response Schema:
{
"sessionId": "current-session-id",
"versions": [
{
"sessionId": "session-a",
"createdAt": 1724334000000,
"depth": 0,
"current": false,
"onCurrentPath": true,
"turns": [
{ "turn": 1, "text": "Hello", "time": 1724334001000 },
{ "turn": 2, "text": "Tell me more", "time": 1724334005000 }
]
},
{
"sessionId": "session-b",
"parentSessionId": "session-a",
"createdAt": 1724334020000,
"depth": 1,
"current": true,
"onCurrentPath": true,
"operation": "edit",
"targetTurn": 1,
"before": "Hello",
"after": "Hello world",
"turns": [
{ "turn": 1, "text": "Hello world", "time": 1724334021000 },
{ "turn": 2, "text": "What is next?", "time": 1724334025000 }
]
}
]
}
POST /message-tree
Performs branch creation or reactivation.
edit: Rewinds to before the specified user turn, creates a new branched session, appends a durablemessage-tree/versionmarker, and submits the replacement prompt.retry: Rewinds to before the target turn, creates a child session, and replays the original user prompt.activate: Unarchives an archived version session via the host registry queue so the client can navigate to it.
4. Performance & In-Memory Caching
-
Host-Side Parsed Session Cache (
sessionParsedCache):- Parses turn boundaries (
extractTurns) and version headers once per immutable event sequence. - Bounded to 500 session entries with key invalidation on live event count / disk mtime changes.
- Subsequent
tree()queries across siblings in the family hit in-memory cache in sub-millisecond time.
- Parses turn boundaries (
-
Client-Side Family SWR Store (
treeStore):- Maps every non-deleted branch in a tree to the shared family structure upon fetch.
- Switching between sibling branches (
‹ n/m ›or Versions view) is 100% synchronous (0ms lag, zero indicator flicker). - Uses monotonic request timestamps to prevent race-condition overwrites from out-of-order responses.
- Optimistically seeds newly created edit/retry branches before navigation.
5. Security and Error Resilience
- Ignorable Event Envelope:
ignorable: trueensures foreign event markers do not crash the core DSH log parser. - Fail-Safe Mutation Recovery: Transaction reversals (
child.dispose()) on failures prevent dangling session artifacts. - Memory Bounded Stores: LRU bounds (500 sessions) prevent unbounded memory growth in long-running processes.
6. Naming & Namespaces
- NPM Package:
dsh-plugin-message-edit - Cordis Service Name:
message-tree - HTTP Path:
/message-tree - Durable Event Type:
message-tree/version
The package uses
dsh-plugin-message-editfor discovery, but retainsmessage-treein routes, cordis IDs, and event types to prevent collisions with prior third-party plugins (such asdsh-message-edit) and ensure seamless side-by-side operation.