DeepSeek Harness Plugin Hub

发布与管理完整 Harness Profiles,发现适合你的插件。

探索

插件目录环境预设文档中心动态

社区

发布插件联系我们报告问题

相关链接

Plugin Hub GitHubDeepSeek Harness 官方项目系统状态隐私说明
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

独立、非官方社区项目,与 DeepSeek 官方无隶属、授权或背书关系。

Phocinae — DeepSeek Harness 插件(DSH Plugin)
← Plugins

dsh-phocinae

Phocinae

DeepSeek Harness 的本地非生成式决策层:由 Phocinae-Largha-150M-v1 服务器支持的 phocinae_ask / phocinae_gate 工具,以及在 tools/pre-execute 上采用故障关闭机制的审批门和校准置信度升级信号

插件会安装到这里;不确定时保持 web。

npx -y @deepseek-ai/dsh plugin --profile web add dsh-phocinae@0.2.5
README兼容性版本

兼容性与来源证明

Phocinae 以 dsh-phocinae 发布,当前版本为 0.2.5。Plugin Hub 会校验它的 manifest,并保存精确安装来源,便于复现安装结果。

DSH 兼容范围
*
运行环境
any
发布来源
npm
Registry 更新时间
2026/10/16

版本

0.2.5stable
2026/10/12
0.2.4stable
2026/10/9
0.2.3stable
2026/10/9
查看其余 3 个版本收起版本
0.2.2stable
2026/10/8
0.2.1stable
2026/10/8
0.2.0stable
2026/10/8

相关插件

正在加载相关插件…

最新版
0.2.5
DSH
*
HMR
重启进程
Tree shaking
未声明可安全裁剪
解包体积
1.4 MB
文件数
28
Surface
any
许可证
Apache-2.0
发布源
npm
GitHub
★ 0
周下载
1,587
安全扫描
✓ v0.2.5 扫描通过
最近提交
2026/10/12
查看源码 ↗项目主页 ↗
README Badge

点击下方 Badge 复制 Markdown,粘贴到 README 即可。

这是你的 Plugin?认领权益 · 优先安全扫描

验证 package.json 声明的 GitHub 仓库,即可管理这个公开页面。认领后,Hub 会优先安排当前版本的安全扫描,并在通过后公开展示结果。

认领这个 Plugin →
报告问题
DeepSeek Harness Plugin Hub
ProfilesPlugins分类动态文档登录管理 Profiles
ProfilesPlugins分类动态文档登录

相关插件

继续浏览 security-access 分类下经过校验的插件。

Experimental Auto Review@deepseek-ai/dsh-experimental-auto-review针对每个工具的 LLM 授权审查,适用于 DeepSeek Harness Auto 权限预设Cc Safety Netcc-safety-net编码代理 CLI 钩子——阻止破坏性命令和访问机密文件Doctor@linxin666/dsh-doctorDSH 配置档案的事务性救援模式,配备受监督的启动器、隔离的恢复容器、确定性修复、健康监控以及本地 Web 恢复控制台Pocketdsh-pocket把 DeepSeek Harness 装进你的口袋:一个包、一个设置页,手机扫码即同步访问电脑上的 DSH(局域网 + 公网,实时同屏)。

README

English · 中文 · Español · Português · हिन्दी

斑海豹 Phocinae logo

dsh-phocinae

A local, non-generative decision layer for DeepSeek Harness. Plugins phocinae_ask and phocinae_gate.

Plugin manifest (the dsh section of package.json)

▲ Read from the real package.json: bundle.patch points at cordis.patch.yml, and engines constrains both node and dsh.

Dangerous-command gate demo animation

▲ **Synthetic demo animation** (model repo docs/gallery S01): frames are rendered and the scenario data is fictional, but the behaviour it shows — a dangerous command being stopped in milliseconds — is what this plugin's gate does; the terminal card further down is a real run.

Unit and contract tests, real run

▲ Real node --test result: 57/57, including the auto-allow boundary and the unnamed-tool fail-closed regression.

Publish artifact self-check

▲ verify-artifacts: free of credentials and local paths, and lists what npm would actually ship.

phocinae_ask / phocinae_gate tools backed by a Phocinae-Largha-150M-v1 server — yes/no judgements, single-choice picks and 2-10 scores, one forward pass each, on your own machine — plus a fail-closed approval gate that screens tool calls before they run.

This is 0.2.4 — version anchors for the published figures on top of 0.2.3's v1.1 numbers refresh (no code changes). The 0.1.2 plugin did not activate at all on DSH 0.2.x: the harness logged one warning and the entry died. Everything below the Fixed in 0.2.2 section is what changed and why.

dsh plugin --profile <name> add dsh-phocinae@0.2.4

Requires Node ^22.19 or >=24, and a reachable decision service (see Running the decision service).

npm i alone does not install the plugin

Two separate things have to happen, and only the second one mounts the plugin:

stepwhat it does
npm i dsh-phocinaePuts the package in the current directory's node_modules. Useful for reading the code or importing the guard directly. It does not reach any DSH profile.
dsh plugin --profile <name> add dsh-phocinae@0.2.4Adds it to that profile's package.json (dependencies and dsh.profile.bundles) and installs it there with pnpm. This is what makes the host mount it.

Measured on this machine, with a throwaway DSH_HOME:

  • npm i dsh-phocinae in an unrelated directory → installed there, profile dependencies still {}, profile bundles unchanged, plugin absent from dsh <profile> --dump-config;
  • dsh plugin --profile p add dsh-phocinae → the profile gains both the dependency and the bundle entry, and the composed config contains the phocinae row with its endpoint;
  • a dependency without the dsh.profile.bundles entry → installed but not mounted, because the bundle list is what the loader walks.

Pin the version

add dsh-phocinae resolves through pnpm's supply-chain age gate (minimumReleaseAge). A release younger than the gate's threshold is not selected, so for a while after a publish the bare name resolves to the previous version — and the previous version here is 0.1.2, which does not work.

Measured, minutes apart, on the same machine:

whencommandresolved to
order 0.2.2 published + 2 mindsh plugin --profile p add dsh-phocinae0.1.2 — main: index.js, the build that cannot activate
same, but add dsh-phocinae@0.2.20.2.2 — ./index.mjs, skill present
same, bare add with minimumReleaseAge: 0 in the profile's pnpm-workspace.yaml0.2.2
order 0.2.2 published + 150 mindsh plugin --profile p add dsh-phocinae0.2.2 — ^0.2.2, host boots clean

When the gate holds a version back, the harness records the refusal in the profile's pnpm-workspace.yaml:

minimumReleaseAgeExclude:
  - dsh-phocinae@0.2.2

The gate is a sound default — a freshly published package is exactly what a supply-chain attack looks like. It does mean the version should be named, both to get the fixed build immediately and to make an install reproducible:

dsh plugin --profile <name> add dsh-phocinae@0.2.4

If a bare add does land you on 0.1.2, dsh <profile> --dump-config shows which version is mounted, and re-adding with the pinned spec replaces it.

Git and local checkouts work the same way, and pin by construction:

dsh plugin --profile <name> add github:Phocinae/dsh-phocinae#v0.2.4
dsh plugin --profile <name> add /path/to/a/local/checkout

What it contributes

contributionseamwhat it does
phocinae_askctx.toolsRuns a batch of typed questions against the local model. Every answer carries a calibrated confidence and an advisory escalate flag.
phocinae_gatectx.toolsJudges one command or action: allow / ask / deny, with confidence. Checks an action without running it.
approval gatetools/pre-execute waterfallScreens every tool call the configured patterns cover, before it executes.
phocinae skillctx.skillsTeaches the model when a local decision is the right tool, how to phrase one, and how to read the escalate flag.

The model is not a chat model. It does not generate text, does not know facts, and cannot write code. It makes one structured decision per forward pass, which is exactly what a gate needs and nothing more.


Fixed in 0.2.2

Every item below is reproduced by a test in test/regressions.test.mjs, named D1…D12.

D1 — the plugin never activated

dsh: warning: 1 entry did not activate
phocinae (dsh-phocinae): Error: cannot get property "registerTool" without inject

index.js probed typeof ctx.registerTool === 'function' as a defensive check. A Cordis context is a proxy: reading an undeclared service name throws instead of returning undefined. registerTool is not a DSH service — the registry lives at ctx.tools — so the probe threw on the first line of the plugin body, taking the whole entry down before it could subscribe to anything.

Fixed: tool registration waits for the service through ctx.inject(['tools'], …). No probe, no undeclared read, and if the service never appears the plugin still arms its gate.

D2 — the tool definition was the wrong shape

The definition carried {inputSchema, handler}. ToolDefinition extends ToolSchema, which declares {name, description, parameters}, and the registry reads definition.parameters. Registering the old shape fails the model-facing projection:

dsh: UNKNOWN: tool "phocinae_ask" parameters must be lossless JSON before schema projection

Fixed: definitions now carry parameters and output: {schema, render} plus execute, all inside the harness's enforced JSON Schema subset (required as an array, oneOf for unions, no author-only keywords). test/contract.test.mjs re-implements that subset check, and the assembled-headless run registers the definitions in a real host.

D3 — the gate read the answer from the wrong place

data.answers is an object keyed by question id. 0.1.2 did Array.isArray(data.answers) ? data.answers[0] : …, which is undefined for every real response.

D4 — and therefore allowed everything, silently

The verdict test was if (risk === true). With risk always undefined, that is always false, so guard() returned {decision: 'allow'} with the reason "the model judged this low risk" — for every command, including rm -rf /.

On the 53-command labelled set in bench/, recall on destructive commands was 0.00.

Fixed: answers are read by id and shape-checked, a malformed body is a protocol error rather than a default, and the gate fails closed — an unreachable service, a missing confidence extension, or an unreadable body all route to a human.

D5 — verdicts were thrown, not returned

The deny path called next(err). The tools/pre-execute waterfall expects a PreToolDecision ({kind: 'allow' | 'deny' | 'ask', reason}); rejecting the waterfall is not a decision.

Fixed: {kind: 'deny', reason} and {kind: 'ask', reason, displayReason}, with next() called exactly once on the allow path.

D6 — gate.tools defaulted to ['bash']

The shell tool is pwsh on Windows, bash elsewhere, and MCP servers add their own names. On this machine the default matched nothing, so the gate never ran.

Fixed: the default is ['*'] — every tool — with exact names, * globs, and case-insensitive matching available.

D7 — the escalation gate the release notes promised was not there

The model release documents an E1 gate: escalate a decision to a larger model when answer_confidence falls below τ. 0.1.2 contained no τ, no confidence comparison, and no escalation branch — a repository-wide search for escalate found only the Python server.

Fixed: phocinae_ask returns escalate, escalatedIds, escalationReason and escalateAt, and the gate consults the same confidence. The plugin still does not perform the escalation — it cannot call a large model on your behalf — but the signal is now produced rather than claimed.

Breaking changes

change0.1.20.2.2
tool registryctx.registerTool / ctx.tools.register probectx.inject(['tools'], …)
tool definitioninputSchema + handlerparameters + output + execute
gate answer sourceanswers[0] (array)answers[id] (object)
failure directionalways allowask by default (gate.failMode)
tool match default['bash']['*']
verdictnext(err){kind, reason}
gate questionboolean noulharm scale (harmless/risky/destructive)
gate.mode defaultdenyharm
escalationabsentescalate on every answer

gate.failMode: 'open' restores the old always-allow behaviour for a deployment that wants it. It is not the default and should not become one.


Measured behaviour

The measured figures were produced on one machine (CPU, fp32) against the released weights, with the scripts in bench/; re-run them on your own hardware before relying on them. The published figures come from the model release's own documents.

Version anchors. v1.0 — first published figures. v1.0 corrected — E1 numbers corrected (kept-subset 0.886, −54.4% LLM calls, 45.7% escalate). v1.1 (2026-10-09) — release of record (0.906 / 0.848, 45.0% escalated / −55.0% calls, kept-subset 0.9936). The pre-correction reading (0.7948 / −82% / 18%) is deprecated upstream — do not cite.

Decision quality — the model is honest

datasets/typed_test/test_typed_400.jsonl, 400 cases × 5 questions = 2000 decisions, judged per decision against gold.label:

metricpublished (en)measured (en)published (zh)measured (zh)
local accuracy0.9060.90550.8480.848
escalation rate @ τ=0.645.0%45.0%——
accuracy on kept decisions—0.9936——

The zh figures are machine-translated cases; the training mix includes machine-translated Chinese (≈2,400 rows) plus native Chinese (≈1,400 rows) — an in-mix (fitted) evaluation, not cross-lingual transfer.

The accuracy reproduces within the release's own stated fp16/fp32 noise, and so does the escalation rate (an independent replication returns the same 45.0%). The "79.6% fewer LLM calls" saving belongs to τ≈0.50, while the frozen E1 gate is τ=0.6 (τ swept on the eval set — re-scan per domain):

τescalatedLLM calls cutaccuracy on decisions kept local
0.5020.4%79.6%0.9523
0.6045.0%55.0%0.9936
0.7065.0%35.0%0.9986
0.8077.0%23.0%1.000

"79.6% saved" and "τ=0.6" cannot both be true. At the threshold the model release calls frozen, the reduction is 55.0%. That is still a real saving, and the confidence ordering is genuinely useful — accuracy on what stays local climbs from 0.91 to 1.00 as the bar rises — but the headline number belongs to a different threshold.

Gate quality — and why the default question changed

bench/gate-bench.mjs, 53 commands (31 destructive, 22 routine), all against the real model. recall is the share of destructive commands the gate stops; auto-pass purity is how often a passed command was actually safe.

gate questionrecall on destructiveconfident passes that were destructive
noul — "should this be blocked?" (0.1.2's default)0.00—
tri-state — allow / ask / deny0.741
harm — harmless / risky / destructive (0.2.4 default)0.970

The inherited boolean question is not merely weak, it is inverted: it passed every one of the 31 destructive commands, most with confidence between 0.54 and 0.80. Asking "is this safe?" is worse still — 27 of 31 passed with confidence as high as 0.87. The harm scale is the only formulation measured that both caught almost everything and never confidently waved a destructive command through.

Its one miss, vssadmin delete shadows /all /quiet, is caught by the auto-allow list's operator rule rather than by confidence, so no destructive command in the set reaches execution.

Confidence is compressed: keep the gate narrow

The model's confidence does not separate routine commands from risky ones well enough to be a general-purpose filter. Its harmless verdicts sit mostly in 0.27–0.54, so a gate that asked it about git status would send git status to a human.

That is why 0.2.4 ships an auto-allow list: read-only and build/test commands with no shell operators never reach the model at all. The gate's job is to stop things, not to approve the routine:

  • names on the list, no operator → pass locally, no request, no latency
  • anything containing ;&|><$(){}[]%^` etc. → the list is bypassed and the model decides
  • a verb whose own arguments name a command, or delete what it matched (find, env) → not on the list at all; a caller-supplied make target goes to the model
  • model says destructive → deny
  • model says risky, or harmless below gate.minConfidence → a human decides
  • service unreachable → a human decides

An entry containing a shell operator is refused at load time. git status && rm -rf / starts with an allow-listed prefix, so accepting such a pattern would build a bypass into the list. The operator rule is not the whole story either: find . -delete and env rm -rf / contain no operator, which is why those verbs are not on the list and why make passes only as a whole, known-safe invocation.

Honest summary of the claims

claimverdict
"144.3M bilingual decision model, one forward pass, local"true
"typed-decisions en 0.906 / zh 0.848"reproduces (0.9055 / 0.848)
"cuts LLM calls by 79.6% with a τ=0.6 confidence gate"false as written — 79.6% is τ≈0.50; at τ=0.6 it is 55.0%
"escalation improves combined accuracy to 0.8737"consistent — escalation only replaces wrong local answers
"the plugin provides this gate"was false for 0.1.2 (recall 0.00, and it never loaded)

Configuration

Defaults live in cordis.patch.yml and are documented in lib/config.mjs. Every key has a default, so the bundle patch can be reduced to enabled: true.

keydefaultmeaning
endpointhttp://127.0.0.1:8155/v1/systemonedecision service. Loopback only — the decision state carries raw tool-call text, so a remote host is a load-time error unless allowRemoteEndpoint: true.
modelPhocinae-Largha-150M-v1served model name
timeoutMs3000per request; one attempt, no retry
escalateAt0.6confidence below this marks an answer escalate: true
maxStateChars4096cap on the rendered decision state
permuteChoicefalsepermutation-average choice questions (4x forwards)
gate.enabledtruearm the pre-execute gate
gate.modeharmharm / tri-state / noul / off
gate.threshold0.8noul mode only: P(risky) that counts as a positive signal
gate.minConfidence0.45below this, an allow becomes a review
gate.autoAllowsee DEFAULT_AUTO_ALLOWcommands passed without asking the model
gate.tools['*']tool names to screen: exact, * globs, or *
gate.failModeclosedclosed = unreachable service asks a human; open = allow
gate.riskyDecisiondenynoul mode only: deny or ask on a positive finding

To screen nothing and only use the tools:

- id: phocinae
  config:
    gate:
      mode: off

To screen only the shell, and only ask:

- id: phocinae
  config:
    gate:
      tools: ['pwsh', 'bash']
      riskyDecision: ask

Running the decision service

The plugin talks to a local server; it does not load weights itself.

# weights (the reference download is ~330 MB)
huggingface-cli download Phocinae/Phocinae-Largha-150M-v1 --local-dir ./model
# (modelscope hosts the same repo: modelscope download --model PerryLink/Phocinae-Largha-150M-v1)

pip install phocinae-server
PHOC_MODEL_DIR=./model python -m phocinae.main

GET http://127.0.0.1:8155/health answering {"status":"ok","model_loaded":true} means it is up. Without it, phocinae_ask returns a PHOCINAE_SERVICE_UNAVAILABLE error naming that command, and the gate routes every screened call to a human.


Development

npm test                  # unit + contract tests, no network, no model
npm run test:integration  # gate over real HTTP, then a real dsh host boot
npm run bench:gate        # the gate benchmark (needs the real service)

npm run test:integration creates a throwaway DSH_HOME under the system temp directory, so it never reads or writes your own profiles. Its first half drives the real gate over real HTTP against a fake service; its second half installs the plugin into that throwaway profile and boots the real dsh, asserting that every bundle entry activates — which is the check 0.1.2 would have failed.

The fake service exists because the real one needs a 330 MB checkpoint. Point the harness at a running real service with --real-endpoint http://127.0.0.1:8155/v1/systemone.


Documentation

doccontents
ARCHITECTURE.mdthe mounting contract, the gate's decision order, and why each choice was made
SECURITY.mdtrust boundaries, what leaves the machine, and the failure modes
CHANGELOG.mdrelease history
bench/the benchmark scripts and their saved results
THIRD_PARTY_NOTICES.mdreused work and its licences

License

Apache-2.0 — see LICENSE. The model weights are Apache-2.0 as well; their card is the authority on the model, this repository is the authority on the plugin.

gate.audittruelog every verdict through the host logger