deepseek-harness
deepseek-ai
DeepSeek Harness: Everything is a Plugin.
PROJECT TOPICS
PROJECT README
A dsh plugin: named model profiles you can switch and configure interactively through the host's native ask-user flow — one implementation that works on the TUI and the web surface, and fails fast with guidance on headless.
A model profile is a snapshot of your whole model configuration:
/model selection), andSwitching between contexts (work ↔ personal) becomes one command instead
of a /model + per-agent tour.
"profile" means two different things in dsh — this plugin is the model kind. A dsh profile (
~/.dsh/profiles/<name>/,dsh --profile <name>) is the boot-time plugin composition; it cannot change while the process runs. The model profiles this plugin switches live in~/.dsh/model-profiles.json, apply at runtime, and are scoped to the workspace tree that binds them.
dsh plugin --profile <your-profile> add @aiwayds/dsh-profile-switch
The plugin mounts with inject: ['commands', 'userQuestions'] — both are
dsh-base services, so it coexists with any surface and any plugin stack.
/profile-switchOne question: which profile this workspace tree binds to. Answering applies the profile in layers:
.dsh-profile into the current directory
(nearest file up the tree wins, .nvmrc style), so every NEW session in
this tree assembles its initial selection from the profile. Other trees
are untouched: a switch is workspace-scoped, never machine-global.The switch deliberately does NOT write the global agent-default-model
setting — that stays /model's write, and crossing tree boundaries is
exactly what a profile switch must not do.
The list also carries (unbind this tree) when the tree is bound:
removes the pin (guarded — a hand-decorated pin file is never clobbered; the
plugin refuses and says so).
/profile-cfgThe configuration wizard — an operation menu, then the matching flow:
| Operation | What it asks |
|---|---|
new |
name → default model chain → per-subagent overrides |
edit |
pick a profile → re-answer the same chain (current values shown in the questions) |
save-current |
name → captures the live selection (or the deployment default) → optionally snapshot every discovered agent's baseline |
rename |
pick a profile → new name |
delete |
pick a profile → confirm (the last remaining profile is refused) |
Every model choice is a three-step narrowing chain of separate ask-user
questions — provider → that provider's models → that model's think levels —
because each step's options depend on the previous answer. All three lists
are read live from the installed llm adapters (listProviders /
listModels / resolveModelInfo), so think levels are exactly what the
adapter serves — never hardcoded (the llm-deepseek route rejects medium;
only the adapter knows what a model accepts). A provider that lists nothing
falls back to typing a model id; a model with no selectable efforts skips
the think step.
Cancel anywhere (Esc / closing the question) aborts the wizard with nothing saved — the store is written exactly once, at the end.
When dsh-subagent-registry
is installed, the new/edit wizards add a multi-select over your
discovered agents (~/.dsh/agents/*.md), then the same provider → model →
think chain per selected agent — with (inherit) leading every step.
Composing semantics:
Without the registry the overrides would have no consumer, so the
per-agent section is skipped with a note and profiles simply hold the main
default model — detection is a contract-member probe
(composeAgentRuntime / readModelProfilesDoc / workspaceProfileName),
the same convention dsh-tui-pi established.
| TUI | web | headless | |
|---|---|---|---|
| Question rendering | dsh-tui-pi's ask-user dock panel | the web composer takeover | — |
| Live default-model switch | yes (tui-pi bridge) | yes (session controller) | n/a |
| Tree binding + store | yes | yes | via files |
| No-answerer behavior | — | — | fast-fail with guidance |
On a surface with no ask-user answerer (headless runs one task and exits),
the commands fail fast with guidance pointing at the non-interactive path:
write <workspace>/.dsh-profile and edit ~/.dsh/model-profiles.json
directly. Nothing hangs.
~/.dsh/model-profiles.json — the store ($DSH_HOME honored). Versioned
(version: 1), self-healing (a corrupt/unknown file degrades to the
seeded work / personal / other profiles, never throws), atomically
written (tmp sibling + rename). This file is a shared contract:
dsh-subagent-registry reads it (spawn-time composition) and dsh-tui-pi's
session bootstrap reads it (new-session seeding from the pin). Schema:
{
"version": 1,
"current": "work", // informational, last applied anywhere
"profiles": [
{
"name": "work",
"defaultModel": { "provider": "zai-coding-cn", "model": "glm-5.3", "reasoningEffort": "high" },
"agents": {
"workhorse": { "model": "volc-ark-plan/deepseek-v4-flash", "thinking": "high" },
"oldfox": {} // empty entry = explicit inherit
}
}
]
}
<workspace>/.dsh-profile — the tree pin: one line naming the profile;
blank lines and # comments allowed. The plugin overwrites it on a switch
ONLY when it parses as exactly one entry line — a hand-decorated file is
refused and surfaced, never clobbered.
The model-profile feature moved here from dsh-tui-pi (which carried it as TUI-only panels). Pairing:
dshTuiModelSelection bridge:
/profile-switch also live-switches the current TUI session's default
model;/agents manager writes the same
store with the same schema — both editors coexist;/profile-cfg session longer than 90s echoed
a spurious aborted due to timeout (the panel itself kept working;
2.18.1 restored the dispatch). On web/headless surfaces no such guard
exists and any plugin version pairs with anything.No manual profile wiring is expected anywhere: dsh plugin add reconciles
the bundle entry, the bundle patch mounts the plugin, and the commands
register on every surface the profile boots.
dsh plugin --profile <your-profile> remove @aiwayds/dsh-profile-switch
The plugin owns no daemons and holds no host resources, so removal is clean on the next boot. Your data is intentionally preserved:
~/.dsh/model-profiles.json — delete it if you want the store gone;<workspace>/.dsh-profile pins — delete per tree (rm .dsh-profile); a
pin naming a missing profile simply binds nothing.pnpm install
pnpm build && pnpm check && pnpm test # unit suite (builds first)
node scripts/smoke-boot.mjs # real-host boot gate (needs global dsh)
pnpm contract # write↔read handshake with the registry
# (auto-skips where no registry resolves)
The contract check proves the deployed three-repo shape on real files: the
plugin's store write (pin + per-agent overrides) composed back through the
registry's composeAgentRuntime — override wins, explicit-inherit and
baseline fallback hold, and the probe leg confirms registryDetected()
resolves through the profile's sibling node_modules exactly as it does in a
live deployment. On machines/profiles without the registry it degrades to a
documented skip, so it can run anywhere.
scripts/link-dsh-closure.mjs re-points node_modules/@deepseek-ai/* at
the global dsh CLI's own closure so typecheck and tests see exactly one
cordis. CI runs the same steps on Node 22/24 plus the boot smoke, and a
daily schedule watches for upstream rc/stable drift.
License — MIT.
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: 无有效分类标签。