deepseek-harness
deepseek-ai
DeepSeek Harness: Everything is a Plugin.
dfycaly98931680/dsh-trajectory-governance
Agent trajectory governance & anomaly diagnosis plugin for DeepSeek Harness (dsh): multi-branch trajectory trees, loop-deadlock / invalid-retry / goal-drift detection, cost attribution, alerts, one-click interrupt & breakpoint fork, independent GUI tab. Zero kernel modification.
PROJECT TOPICS
INSTALL REFERENCE
dsh plugin --profile web add github:dfycaly98931680/dsh-trajectory-governance
该命令指向仓库当前默认分支;尚无绑定当前 commit 的完整验证结果。
PROJECT README
Agent trajectory governance & anomaly diagnosis for DeepSeek Harness (dsh).
Rebuilds the flat session/event log into a structured, multi-branch trajectory
tree, keeps observation-layer snapshots, and runs three temporal anomaly
strategies (loop deadlock / invalid retry / goal drift) with results mounted on
tree nodes and surfaced in an independent GUI tab.
Zero kernel modification · consume-only event subscription · observation-layer snapshots (no control-plane rollback) · independent SQLite storage · never overwrites the official Trajectory view.
The official Trajectory page is a flat raw-event log. For long-running agent tasks (dozens of turns, subagents, forks) you cannot see:
This plugin is an upper observation & reasoning layer: it consumes committed events and derives structure, snapshots, and diagnoses — it never steers, intercepts, or rolls back the agent. Both views coexist.
| Aspect | Official Trajectory | dsh-trajectory-governance |
|---|---|---|
| View | flat raw event log | structured multi-branch trajectory tree |
| Lineage | none | parent/child + fork/subagent branches (derived implicitly) |
| Snapshots | no | observation-layer snapshots (nodeId + context hash + branchId) |
| Diagnosis | no | loop_deadlock / invalid_retry / goal_drift with confidence + suggestions |
| Storage | host storage | plugin-private SQLite (~/.dsh-trajectory-governance/) |
| Behavior | — | consume-only; never schedules, forks, or rewinds the agent |
dsh web profile
├─ @deepseek-ai/dsh-base (official core)
└─ dsh-trajectory-governance (this bundle)
│
│ ctx.on('session/event' | 'session/created' | 'session/disposed'
│ | 'subagent/start' | 'subagent/end') ← emit-mode, post-commit, read-only
▼
┌─ ingest ───────────────┐ ┌─ tree ─────────────────┐
│ normalize (scalars) │──▶│ cross-session trajectory │
│ sqlite (events/sessions)│ │ tree + branch attach │
└────────────────────────┘ └─────────────────────────┘
┌─ snapshot ─────────────┐ ┌─ diagnose ──────────────┐
│ index-only snapshots │ │ 3 strategies (async) │
│ LRU/TTL prune, branches │ │ results → anomalies DB │
└────────────────────────┘ └─────────────────────────┘
│
▼
┌─ api (host) ────────────┐ ┌─ client (browser) ─────┐
│ /trajectory-governance/ │◀──│ independent Tab: │
│ api/* (JSON, same-origin)│ │ conversation.view slot, │
└─────────────────────────┘ │ id 'trajectory-…' │
└─────────────────────────┘
Data flow: session/event (durable, post-commit) → normalized + persisted →
tree/snapshot/diagnosis services → JSON API → the GUI tab. The diagnosis engine
runs asynchronously on an interval (incremental watermark + tail overlap) and
never blocks the agent loop.
Requires dsh >= 0.1.0-rc.6. Two ways:
Bundle (published / git):
dsh plugin --profile web add github:dfycaly98931680/dsh-trajectory-governance#<commit-sha>
A git install fetches sources, so the package ships a prepare build; pnpm
requires an explicit allow-list for it (add the printed key to the profile's
pnpm-workspace.yaml, then re-run):
allowBuilds:
dsh-trajectory-governance: true
Alternatively install a built tarball (pnpm pack) — no build permission needed.
Dev overlay (no pnpm):
dsh web --patch C:\path\to\dsh-plugin\overlay.dev.yml
Then restart the web app. You should see [trajectory-governance] loaded; storage=... sessions=N events=M anomalies=K in the logs.
conversation.view
entry — the official Trajectory tab is untouched).CLI inspection utilities (against the plugin's own SQLite):
node scripts/inspect.mjs [dbPath] # sessions/events overview
node scripts/tree.mjs <sessionId> [dbPath] # trajectory tree JSON
node scripts/snapshot.mjs <dbPath> <cmd> [...] # list|create|context|delete|prune
The plugin row accepts config (all optional; deep-merged over defaults):
- insert:
- id: trajectory-governance
name: dsh-trajectory-governance
config:
storage:
path: C:/data/trajectory.db # default ~/.dsh-trajectory-governance/trajectory.db
diagnosis:
strategyA:
enabled: true
windowSize: 5
similarityThreshold: 0.85
resultSimilarityThreshold: 0.8
strategyB:
enabled: true
minRounds: 3
strategyC:
enabled: true
sampleEveryNRounds: 5
similarityThreshold: 0.5
consecutiveSamples: 2
embedder: lexical # 'lexical' built-in; 'llm' is the extension seam
analyzer:
enabled: true
intervalMs: 10000
alerts:
enabled: true
minConfidence: 0.8
cooldownMs: 600000
channels:
desktop: true # browser Notification (client side)
cordisEvent: true # 'trajectory/anomaly' bus event for the ecosystem
webhook:
url: "" # Feishu/DingTalk/Slack-style text webhook
actions:
onLoopDeadlock: notify # notify | suggest-stop(一键中断按钮) | auto-stop
onInvalidRetry: notify
onGoalDrift: notify
cost:
enabled: true
tokenPricePerM: 0.28 # adjust to your provider pricing
estimateWhenUsageMissing: true
Full schema: DIAGNOSIS_CONFIG_SCHEMA in src/diagnose/config.ts.
When a NEW anomaly is detected (confidence ≥ alerts.minConfidence), the plugin:
trajectory/anomaly on the Cordis bus (ecosystem notification plugins
can subscribe) and POSTs a text webhook if configured — the message is in
stop-loss language: type, confidence, and how much tokens/money/time the
range already consumed (from official assistant/message.usage);/api/alerts, shows a desktop notification (browser
Notification API, permission button in the bar), and pins abnormal sessions
on top of the dropdown sorted by wasted tokens;POST /api/actions/interrupt) which calls
the official agent.cancel capability — never a monkey-patch. Default tier
is notify; auto-stop (loop deadlock only, confidence ≥ 0.9) can be
configured for unattended setups.Breakpoint exit — the legitimate lightweight "rollback". Instead of a
control-plane rewind (already covered by dsh-turn-rewind),
this plugin offers a diagnosis-driven restart: at any snapshot / anomaly
start / selected node, "branch a new session here" resolves the target down
to the nearest stable turn/end boundary and calls the official
ctx.sessions.fork(source, boundary) — a fresh child session seeded at that
point. It never touches workspace files, keeps the observation-layer stance,
and turns "you wasted money here" into a one-click action.
Waste attribution report — not another usage-stats dashboard (that niche is saturated): it answers the attribution question nobody else does, "which sessions wasted tokens/money, on which anomaly types":
curl http://127.0.0.1:3080/trajectory-governance/api/report/waste # all sessions (Markdown + JSON)
curl "http://127.0.0.1:3080/trajectory-governance/api/report/waste?sessionId=<id>" # one session detail
Both are also reachable from the tab ("浪费报告" / "本会话报告" buttons).
Instant (no waiting for a real loop): seed a synthetic session into the
live store, refresh the tab, pick demo-session:
node scripts/demo-seed.mjs # writes into the default live DB
You should see a tree with red-highlighted loop_deadlock (5 identical tool
calls) and a severe goal_drift range, plus a snapshot mark (★).
Real agent:
loop_deadlock on the
trigger node.goal_drift (mild/moderate/severe) against
the original baseline.Verify: the tree tab highlights the ranges in red; scripts/inspect.mjs shows the
anomaly counts; scripts/tree.mjs <sessionId> dumps the mounted anomalyInfo.
TODO — add after the first live run: tree tab overview / anomaly card / snapshot list. (Placeholders reserved here.)
npm install
npm run build && npm test # 46 tests: normalize/store/subscriber/tree/snapshot/diagnose/api
session/event etc. are emit-mode, post-commit,
fire-and-forget listeners; payloads are never mutated.trajectory) is never overwritten.SESSION_FORMAT_VERSION = 0, no compatibility implied. The
event vocabulary is centralized in src/core/event-catalog.ts; unknown types
honor the envelope's ignorable marker.src/
index.ts # Cordis plugin entry (name/apply)
core/ # types + 44-type event catalog
ingest/ # normalize + session-event subscriber
persistence/ # node:sqlite store (events/sessions/snapshots/anomalies)
tree/ # trajectory tree builder + queries
snapshot/ # observation snapshots + branch manager
diagnose/ # similarity, config, 3 strategies, engine, mount, runtime
api/ # host JSON API (/trajectory-governance/api/*)
client/ # independent GUI tab (conversation.view, id 'trajectory-governance')
tests/ # node:test suites
scripts/ # inspect / tree / snapshot / smoke
cordis.patch.yml # official bundle load row
plugin.manifest.yaml # self-describing metadata (loader uses cordis.patch.yml)
MIT — see LICENSE. Part of the awesome-dsh-plugin
ecosystem. Topic: dsh-plugin.
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: 无有效分类标签。