deepseek-harness
deepseek-ai
DeepSeek Harness: Everything is a Plugin.
AndrasSama/dsh-omp-advisor
Ward concil is oh-my-pi advisor subsystem ported to DeepSeek Harness — independent reviewer models watch your agent and advise it (nit injects, concern/blocker steer) it also include an auto resume and git checkpoints
PROJECT TOPICS
INSTALL REFERENCE
dsh plugin --profile web add github:AndrasSama/dsh-omp-advisor
该命令指向仓库当前默认分支;尚无绑定当前 commit 的完整验证结果。
PROJECT README
Advisors guide. The ward protects. The model executes.
Package name:
dsh-omp-advisor— the name under which it installs and stores settings.
Your coding agent is good, but on a long session it can tunnel-vision: miss a security hole, claim "done" before the tests actually pass, or plow ahead after a wrong turn. Ward Council gives it a second set of eyes — one or more independent advisor models that watch the session in real time and speak up when something matters.
Each advisor reads the transcript as it grows, may investigate your workspace with read-only tools (read / grep / glob), and hands over concrete advice through a dedicated advise tool. Advice arrives as a clearly-labeled note the primary agent weighs — never a command it must obey:
<advisory advisor="The Red Teamer" severity="concern" guidance="weigh, don't blindly obey">
The SQL in search.py interpolates the user query directly — parameterize it before this ships.
</advisory>
You pick each advisor's model from DSH's model list, scope it to specific workspaces, and give it a persona (25 presets included) plus curated domain skills (250 packaged). It is the advisor-watchdog design from can1357/oh-my-pi, rebuilt natively on DeepSeek Harness (DSH) plugin seams.
primary agent ──► session log ──► delta renderer ──► advisor model (your pick from the DSH model list)
▲ │ read/grep/glob (read-only)
│ ▼
└──── agent.inject / agent.steer ◄── advise tool ── dedupe + quarantine
nit / concern / blocker) and the guidance "weigh, don't blindly obey"; the primary agent decides what to do.tools/pre-execute waterfall refuses the call before its body runs (deny), or holds it for your approval (ask). Bounded, so an advisor can never deadlock the agent.dsh-model-search plugin.user/message, assistant/message, tool/call, tool/result) into a compact markdown update the advisor model reviews.Advice, not orders. Notes arrive as
<advisory advisor="…" severity="…" guidance="weigh, don't blindly obey">…</advisory>
messages. The primary agent decides what to do with them.
Severities. nit (default) · concern · blocker. Escalation-rank dedupe: the same note only re-delivers at a strictly higher severity.
Delivery channels (DSH-native).
| Severity | Primary running | Primary idle |
|---|---|---|
non-interrupting (default: nit) |
agent.inject — rides the next step boundary, never wakes |
agent.inject |
interrupting (default: concern, blocker) |
agent.steer — nearest step boundary |
concern downgrades to inject; blocker still steers (may wake a turn) |
Mid-turn deferral. With reviewTrigger: step, non-blocker notes raised while the turn is still running are withheld and flushed deterministically when the turn completes, so partial work is not interrupted and no advice is lost.
Coalescing (optional). With several advisors attached, notes can land in rapid succession. Set Coalesce advice to a window in ms (e.g. 1500) and the runtime buffers notes from all advisors for that window, then emits them as one multi-<advisory> message per delivery channel instead of one message per note. Semantics:
0 (default) — every note is delivered individually, exactly as above.concern/blocker (per your interrupting set) flushes the whole batch immediately, so urgent advice never waits out the window.turn/end with reason.kind: "error") receives an automatic "continue from where you left off" followup message after the same delay, bounded per failure episode and reset by any completed turn.1–999, or 0 = unlimited (the message labels the cap ∞). User aborts and permanent errors (unknown model/provider) never retry — even with an unlimited cap. Toggle the whole feature off with Auto-retry failures.tools/pre-execute waterfall whose listeners return a PreToolDecision — allow, deny, or ask — before the tool body runs. Calling next() lets the call proceed; returning a decision instead ends the chain, so a deny means the tool genuinely never executes. Ward Council's gate turns an advisor finding into exactly that decision:blocker). The runtime records it as the session's armed finding.bash, write, edit) is intercepted. In deny mode the call is refused and the model gets the advisor's reason plus your optional extra guidance; in ask mode the call is held for your decision, with a localized prompt.maxDenials calls (default 2); after that the gate stands down for that finding and the call proceeds, so a disagreeing advisor can never deadlock the agent. A new finding re-arms the gate and resets the bound. Set 0 to never stand down.gate-denied, gate-ask, gate-stood-down), and an armed finding appears in the sidebar as a chip (tool gate: <advisor> <severity> (n/max)) with a Clear gate button — the clearToolGate RPC releases gated calls immediately. The same data rides the session snapshot as a toolGate field.PreToolDecision already carried allow / deny / ask in the alpha line (verified in dsh-tools@0.1.0-rc.6) and the same union is in 0.2. The info error identity and localized displayReason Ward Council sends are additive fields that older hosts simply ignore.next()), exactly as in earlier releases — enabling the gate is the only thing that changes tool-call behaviour.blocker while the primary agent is running, the plugin calls agent.cancel on the running step — tool calls not yet dispatched abort, already-running calls commit — then wakes the agent with the advisory as a followup so it sees the reason and can react. Use Blocker intervention when you want the running step abandoned, and the Tool gate when you want a specific call refused before it runs. A call already in flight is never killed. Without either opt-in, advice stays advice..gitignore), stored as commit objects under the hidden namespace refs/dsh-omp-advisor/**. Your index, HEAD, branch, and worktree are never touched, and no reset/clean/stash command is ever run. Snapshots happen at turn boundaries and (optionally) before mutating tools via pass-through fs/write-intent / fs/edit-intent / tools/pre-execute listeners with a bounded wait that never blocks your tools. Advisors gain read-only list_restore_points / diff_restore_points tools; after a destructive or wrong step an advisor can call advise with rewindTo — the advisory then carries the exact worktree-only restore recipe (git restore --source=<sha> --worktree --staged .) plus the advisor's classification of which steps must not happen again and which were progress. The primary model executes the restore itself; the plugin never rewinds anything. Files created after a point are kept, never deleted. Non-git workspaces are skipped.acceptance advisory reminds the agent to commit the accepted state to the branch it is working on (the plugin marks the latest restore point accepted; the agent runs the commit).conversation.input.model). This plugin registers a searchable
variant for it, so the seat becomes a search box over the same per-session model
directory the stock selector and the /model popup read — a choice made in either
place stays in sync, and nothing else about model selection changes.↑/↓ move, Enter
picks, Esc closes, and the active row is kept scrolled into view.try/catch-guarded contribution inside the
client entry, it needs only the host page's react/react-dom, and it declares no
extra dsh.client.inject package — so if anything about it is unavailable the
settings section still loads and the stock seat simply renders instead. It lives in
src/client/model-select.ts, vendored from dsh-model-search v0.1.0.workspaces field), Memory (persistent advisor memory — pluggable engines, write gate, per-advisor engine toggles), and Monitor (live status + activity feed).! when one is halted/errored, hidden when none are attached here). Since v0.7.5 it is also a workspace advisor manager: it lists every configured advisor split into Active in this workspace and Not active here (reason: off, disabled here, or not in this workspace), with inline Enable here / Disable here buttons and a single theme-aware Add advisor ▾ dropdown that lists the built-in presets (a self-rendered menu, not a native <select>, so it follows the light/dark scheme; new advisors are scoped to this workspace and use the first available model). Since v0.7.6 the toggle is truly workspace-scoped: "Disable here" appends an exact =<workspace> entry to a new orthogonal disabledWorkspaces exclusion list — it never flips the advisor's global enabled switch and never deletes authored workspaces inclusion patterns, so an always-on advisor can be switched off in just this workspace and keeps running everywhere else; "Enable here" clears the exclusion (and turns the advisor on / adds an inclusion pattern if needed). Writes go through narrow host-side RPCs (setAdvisorWorkspace, addWorkspaceAdvisor) that load-modify-save the current settings atomically — the sidebar never read-modify-writes its (up-to-2s-stale) cache, so a concurrent edit in the settings dialog is not clobbered. The host's workspace matcher honors disabledWorkspaces, so a disabled-here advisor actually stops attaching/reviewing in that workspace (not just in the tab's rendering). Since v0.9.0 a session whose tool gate is armed shows a tool gate: <advisor> <severity> (n/max) chip with the finding's note on hover and a Clear gate button that releases gated calls through the clearToolGate RPC. Detection is a bounded runtime probe — never a hard dependency: without the sidebar the plugin loads and behaves exactly as before.Prerequisites
dsh web) — verified on 0.2.0-rc.2 and on the 0.1.2-alpha.4 line. v0.9.0 adds 0.2 support, which changed two things the plugin had to follow:settings.register / settingsScope API; a plugin's settings are its Loader entry Config, edited through the host's settings service (update/replace) and described by the entry's schema. Ward Council binds settings adaptively: it uses settings.register when the host provides it (alpha line) and the config + settings-service path when it does not (0.2). Either way the settings document and the UI are the same.internal/update, which disposes and re-applies the plugin. Ward Council treats that as normal: session runtimes are rebuilt in place on the write path, and any session is re-attached lazily on its next event, so advisors resume without a restart.
The rest of the consumed surface is unchanged and was re-verified on 0.2.0-rc.2: Service(ctx, name), createUserMessage + the plugin source kind, llm.stream, agents.get, the session/turn/fs event names, the two-argument connection.rpc.handle, the tools/pre-execute / fs/write-intent / fs/edit-intent waterfalls, the settings.section slot, the __ModuleLoader__ client wrapper, and the dsh.bundle.patch / dsh.client package.json manifest shape.Install
# from GitHub
dsh plugin --profile web add github:AndrasSama/dsh-omp-advisor
# or from a local checkout
dsh plugin --profile web add "file:/path/to/dsh-omp-advisor"
Then restart DSH Web and hard-refresh the browser (Ctrl+Shift+R). The restart is mandatory: a running server computes plugin bundle revisions at startup, so a freshly installed or updated plugin never appears until the server process restarts.
Verify
Upgrade / uninstall
# upgrade: re-run add with the same spec, then restart DSH Web
dsh plugin --profile web add github:AndrasSama/dsh-omp-advisor
# uninstall (settings in the dsh-omp-advisor namespace stay on disk)
dsh plugin --profile web remove dsh-omp-advisor
Rate-limit guidance. Each advisor makes one model call per reviewed transcript update. On tight free tiers (e.g. 5 req/min), keep Review trigger on turn, keep the roster small, and leave Auto-retry on with a delay at least as long as the provider's rate window.
Hand this to an AI agent with shell access to the DSH host — it is self-contained:
Install the dsh-omp-advisor plugin into the DSH web profile.
Context:
- DSH CLI: `dsh` (must be on PATH; often ~/.npm-global/bin/dsh). Version must be
0.1.2-alpha.4+ (the alpha line). The web profile directory is ~/.dsh/profiles/web (pnpm-managed).
- `dsh plugin --profile web <cmd>` delegates to pnpm inside that profile dir.
- A `dsh web` server may currently be RUNNING and hosting live user sessions.
NEVER kill it yourself unless the user explicitly says they will restart it;
the plugin only activates after a server restart, so finish the install and
then ask the user to restart `dsh web` and hard-refresh the browser.
Steps:
1. Install from GitHub:
dsh plugin --profile web add github:AndrasSama/dsh-omp-advisor
(or from a local checkout: dsh plugin --profile web add "file:/abs/path/to/dsh-omp-advisor")
2. Verify it registered:
dsh plugin --profile web list | grep dsh-omp-advisor
Expect one line showing dsh-omp-advisor.
3. Sanity-check the installed copy at ~/.dsh/profiles/web/node_modules/dsh-omp-advisor:
package.json version matches the release, and lib/index.js + lib/client.js +
skills/ exist. KNOWN PITFALL with `file:` installs: pnpm hardlinks files at
first install, so later edits to the source checkout can leave the installed
copy partially stale. If anything looks stale, mirror the checkout over it:
rsync -a --delete --exclude node_modules --exclude .git \
/abs/path/to/dsh-omp-advisor/ ~/.dsh/profiles/web/node_modules/dsh-omp-advisor/
4. Ask the user to restart `dsh web` and hard-refresh the browser (Ctrl+Shift+R).
5. Post-restart verification in the GUI: Settings shows a "Ward Council"
section. The plugin is INERT until the user enables "Attach advisors to
sessions" (off by default) and adds at least one advisor with a model picked
from the DSH model list — tell them this.
6. If the section is missing after restart: check the server log for plugin
load errors, confirm step 2/3, and confirm the browser was hard-refreshed.
Do not edit ~/.dsh/settings.yaml by hand for this plugin; configuration lives
in the dsh-omp-advisor settings namespace and is edited through the GUI section.
Open Settings → Ward Council. The section has five inner tabs — General, Advisors, Workspaces, Memory, Monitor — patterned after the Plugin Market's sub-tab bar. Settings live in the dsh-omp-advisor namespace and apply live — no restart needed when you edit the roster. Advisor model calls go through ctx.llm.stream with the provider route + model id you picked, so billing, routing, and failover behave exactly like your other DSH model traffic.
turn (review completed turns) or step (review while the turn runs). Step mode fires on every tool step — the UI warns it is heavy on rate-limited or metered providers.0 = deliver each note immediately; >0 = batch notes from all advisors within the window into one message per channel (see How it works). Clamped to 0–10000.deny refuses the call and tells the model why / ask holds it for your decision), the severities that arm it (default blocker), max denials per finding before the gate stands down (default 2, 0 = never stand down), the gated tools (comma-separated; empty = bash, write, edit), and an optional note appended to the refusal the model sees.0 = review everything; >0 = skip transcript updates smaller than this./home/sama also matches /home/sama/anything — so for broad paths prefix with = for an exact cwd match (=/home/sama). This is how you give the writing bench to your novel workspace and the engineering bench to your code workspace.×), add any packaged skill from the catalog dropdown, or reset to preset defaults if the advisor was created from a preset (see Skills),inject (default: full skill bodies in the system prompt) or lazy (id+description index plus a load_skill tool — saves tokens, costs one extra call per loaded skill),workspaces field the card editor uses. An advisor with no patterns runs everywhere — its cells render indeterminate, and checking one scopes it to that single workspace. A free-text row lets you add a workspace pattern that no session has opened yet.Advisors get persistent, workspace-scoped memory: before each review they recall relevant lessons into their context, and after a review they may write a durable lesson back. Multiple engines can run at once, and each advisor picks its own engines on its card.
<workspace>/.dsh-omp-advisor/lessons.md, recalled with a deterministic BM25-lite keyword search. Zero LLM calls, zero dependencies, human-editable.servers/mcp-proxy.mjs, auto-resolved from the profile's node_modules). Recall via find, store via remember — so OpenViking lessons can be written too. (The plugin's openvikingMemory host service is isolate-scoped and not reachable across plugins, hence the proxy.)dist/mcp-server.js, auto-resolved) with HINDSIGHT_MCP_HARNESS=dsh; recall/search knowledge pages and ingest lessons.deepseek.recovery.search); DSH only rewrites dots→underscores when surfacing tools to agents, so the preset matches the dots.resolveScript specifier resolved across the enclosing and profile node_modules at spawn time, so no profile-specific absolute path is hardcoded. If the package isn't installed the engine shows "not installed" and stays gray.gate-denied, gate-ask, gate-stood-down), restore-point snapshots, session attach/detach. The same feed powers the optional sidebar tab.The Add from preset dropdown ships 25 ready-made advisor personas. Applying a preset creates a new advisor (name collisions get a numeric suffix) whose specialization instructions are the persona's expanded soul description and whose skill list is the persona's 10 curated skills. You can then edit everything — model, instructions, skills — like any advisor.
| # | Role | Preset |
|---|---|---|
| 1 | High-Concurrency Backend | The Rustacean Weaver |
| 2 | AI Inference Integrator | The Weights Whisperer |
| 3 | Appchain Developer | The Genesis Architect |
| 4 | Infrastructure Admin | The Edge Guardian |
| 5 | Python Service Architect | The Django Synthesizer |
| 6 | Node.js Systems Dev | The Event Loop Maestro |
| 7 | Harness Plugin Creator | The Meta Coder |
| 8 | Code Review Gatekeeper | The Linting Oracle |
| 9 | Technical Writer | The Clarifier |
| 10 | Security Auditor | The Red Teamer |
| 11 | Digital Marketing Strategist | The Conversion Alchemist |
| 12 | Direct Response Copywriter | The Hook Master |
| 13 | Web Novel Architect | The Worldbuilder |
| 14 | Author Community Manager | The Patron Whisperer |
| 15 | Investigative Journalist | The Fact Finder |
| 16 | Editorial Desk Editor | The Style Enforcer |
| 17 | Financial Analyst | The Ledger Reader |
| 18 | Legal Contract Reviewer | The Clause Hunter |
| 19 | GDPR & Privacy Officer | The Data Steward |
| 20 | EU AI Act & Governance | The Model Auditor |
| 21 | IP & Copyright Sentinel | The License Guardian |
| 22 | Cybersecurity & NIS2 Readiness | The Resiliency Engineer |
| 23 | E-Commerce & Consumer Protection | The Consumer Shield |
| 24 | Privacy-by-Design Engineer | The Minimizer |
| 25 | Agent Tool-Safety Guardian | The Tool Warden |
Domain presets (finance, legal, privacy, marketing…) frame their advice as review flags and analysis, not professional counsel — the soul descriptions tell them to surface risks and defer final judgment to qualified humans.
The plugin packages 250 advisor skills under skills/<id>/SKILL.md — 10 curated per preset. Each skill is a compact briefing (what to watch for, best practices, a quick checklist) that sharpens the advisor in a specific domain, e.g. n-plus-one-query-audit, prompt-injection-via-tool-results, gdpr-data-mapping, cliffhanger-mechanics.
<skills><skill name="id">…</skill></skills> on every review call. Unknown ids are skipped, never fatal. One model call covers everything — best on rate-limited providers.lazy, the system prompt carries only an id+description index and the advisor gets a load_skill tool to fetch a body on demand. Saves ~15KB of prompt per advisor; each loaded skill costs one extra tool-loop call, so prefer it on token-metered providers with headroom.× removes one, the + add packaged skill… dropdown adds any of the 250 (with its description as tooltip), and advisors created from a preset get a reset to preset defaults button restoring the curated list.scripts/gen-skills.mjs scans skills/ and generates the host embed (full bodies) and the client catalog (ids + descriptions) before every build and test run; the skills/ tree is the source of truth and ships in the package.read, grep, glob, plus load_skill in lazy mode). No mutating tools yet — oh-my-pi's WATCHDOG.yml grant system is planned for a later release behind DSH's approval flow (see Blocker intervention for what exists today).maxDenials refusals per finding precisely so an advisor cannot hold your agent hostage.refs/dsh-omp-advisor/** via a throwaway index — the user's index, HEAD, branch, and worktree are never touched; only an allowlist of git verbs runs, object ids spliced into arguments are SHA-format validated, prompts are disabled, and every spawn has a hard timeout. Restores and commits are always executed by the primary model (under your normal tool authority/approvals), never by the plugin; a restore keeps files created after the point instead of deleting anything. Pre-mutation snapshot waits are bounded so a tool call is never blocked on git./dsh-omp-advisor RPC channel is reached through the same Host/Origin trust fence as /api (loopback, or a deployment's --trusted-host authorities), so the settings section and live status panel also work from remote GUIs. On the alpha line and 0.2 alike, rpc.handle(channel, handler) takes two arguments — trust and authentication are applied by the physical carrier before dispatch, so the channel needs no authority option of its own. Handlers return RpcResult values and never throw.snapshot / update endpoints) instead of ctx.settingsScope: DSH keeps settingsScope persistence loopback-only, so a scope-bound section would render "unavailable" in every remote browser. Host-side, update still goes through the settings domain's schema + validation + live watch.npm install # dev deps only; DSH packages are runtime-provided
npm run build # gen-skills + host ESM (lib/index.js) + client CJS ModuleLoader bundle (lib/client.js)
npm test # 180 unit tests over the ported semantics + memory
npm run typecheck # tsc --noEmit (DSH packages shimmed)
Syncing a local install (read this before testing your change). Installing this plugin from a checkout with a file: spec makes the profile materialise it as a hard-link farm — every installed file shares an inode with the file in your checkout. That looks like it stays in sync, and for most files it genuinely does: lib/index.js, package.json and cordis.patch.yml come out with nlink 2 and a write to either side is visible from the other immediately.
lib/client.js is the exception, and it is the one that matters. Check the link state and you will see it sitting at nlink 1 with a different inode from your checkout — the build does not edit it in place, it renames a new file over the old one, which allocates a new inode and breaks the link permanently. From that moment the installed copy keeps serving the previous client bundle, with no error and no version mismatch; the only symptom is that your change is simply not there — a merged feature that never renders, while the tests that inspect the checkout pass. (This is not hypothetical: it is how the searchable composer seat shipped, passed every test, and was absent from the running profile.)
node -e "const f=require('fs');for(const p of ['lib/client.js','lib/index.js'])console.log(f.statSync(p).ino, p)" # local vs installed: same inode = still linked
So after every build, before restarting DSH:
node scripts/sync-installed.mjs # defaults to $DSH_HOME/profiles/web/node_modules/dsh-omp-advisor
It only rewrites files that are already installed, refuses a target that is not this plugin, and is a no-op when already in sync. Then restart DSH Web for the host half and reload the page for the client half.
Layout: src/ host plugin (settings, service, runtime, advisor loop, tools, delivery, quarantine, delta, restore-points, memory), src/client/ settings section (multi-tab) + presets + optional better-sidebar tab (sidebar.tsx), src/prompts/ ported advisor prompts (incl. the completion-gate protocol and the memory-recall protocol), skills/ the 250 packaged advisor skills (source of truth for the build-time embeds), scripts/gen-skills.mjs the skill embed generator, test/ node:test suite (git-backed tests run against real temporary repositories and skip cleanly when git is absent; client modules are tested through a minimal React stub).
Advisor semantics and prompt texts ported from can1357/oh-my-pi (packages/coding-agent/src/advisor/), © Mario Zechner / Can Bölük / Stencil Labs, under the MIT license reproduced in NOTICE-oh-my-pi-LICENSE. This plugin is an independent port for DeepSeek Harness and is not affiliated with the oh-my-pi project.
The restore-point design borrows patterns (no code) from two community plugins: PerryLink/dsh-checkpoint-rewind (Apache-2.0) — side-effect-free git-object snapshots, pre-mutation capture listeners, worktree-only restore that keeps post-snapshot files — and Anionex/dsh-turn-rewind (BSD-3-Clause) — the explicit-only / no-Git-control-plane-mutation safety contract. Thanks to both projects for publishing their designs.
The optional sidebar monitor tab integrates with omdsh-dev/DSH-better-sidebar (MIT) through its public ctx.betterSidebar.registerTab service API, following its external-plugin guide (optional peer dependency, effect-wrapped registration, runtime probe instead of a hard inject).
License. Ward Council is distributed under the SamaCorp Inc. Personal Use License — see LICENSE: full license for personal use and modification; no sale of the software or modified derivatives; unauthorized sales trigger full buyer refunds plus legal fees and $50 per copy sold owed to SamaCorp Inc. One carve-out: the advisor semantics and prompts ported from oh-my-pi remain under MIT (see NOTICE-oh-my-pi-LICENSE), as MIT requires — those portions keep their MIT terms in every copy. Versions up to and including v0.6.0 were released under MIT; copies already distributed under MIT keep those terms (the relicense is forward-only, from v0.6.1).
ctx.changeLedger when dsh-turn-rewind is installed and session-state (seed-replay) rewind are future work. The gate's ask mode covers human-approval routing for finding-armed calls; general pattern-based risk approval (e.g. "ask before any rm -rf") is still future work.nit or concern as a gating severity will hold up ordinary work. maxDenials bounds the cost of a disagreement, not the quality of the judgment.CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: 无有效分类标签。