DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

sorbitol25 /

sorbitol25/dsh-persona-switch

Verified

Live persona switching for DeepSeek Harness (dsh): switch the system-prompt persona from a running session - TUI, Web UI or headless - no restart. Published on npm as dsh-persona-switch.

★ 1 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHubProject homepage
READMESource: main@a078d30b

dsh-persona-switch

npm github dsh-plugin license MIT verified dsh 0.2.0-rc.2 + 0.2.1-rc.1

Live persona switching for DeepSeek Harness (dsh). Switch the system-prompt persona from inside a running session — TUI, Web UI, or headless — with no restart and no core patch. Ships with the switcher plus the example JB persona (jb); a longer persona variant is deliberately not included and your own personas live in $DSH_HOME/personas/.

/persona              show the active persona + the roster
/persona list         same
/persona jb           switch  (name = personas/<name>.md)
/persona off          stop overriding the system prompt
/persona reload       re-read the persona directory (after editing a file)
/persona complete on|off|auto

Or just ask the agent — persona_switch is registered as a tool:

jbに切り替えて

Proof

Whether a persona actually overrides the prompt is measurable: point the route at a local mock (DEEPSEEK_BASE_URL) and read the request body DSH sends. test/capture-prompt.mjs does exactly that, and the three states differ exactly as the front-matter says:

persona complete agent-turn system message harness identity
off — 2,823 B PRESENT
jb true 7,989 B — byte-exact match with personas/jb.md absent
jb false 10,814 B (= 2,823 merged + 7,989 persona) PRESENT

25 tool schemas ride along in every case, thinking stays enabled, and the session-title helper (a separate 363 B request) is untouched.

Why a plugin is needed at all

DSH's own docs are explicit: "Deployment-authored prompt text is config/ composition only … there is no end-user prompt-editing API." The deployment persona lives on the dsh-system-prompt row's config, and dsh-persona only shadows it inside one agent preset. Neither is switchable while a session is up.

This row registers one prompt section whose text is a provider function, evaluated at every assembly:

sp.section({
  name: 'persona-switch:persona',
  order: sp.getSectionOrder('DEPLOYMENT_PERSONA_PREFIX'),
  text: () => activeText(),      // ← read on every turn, not at boot
  interpolate: false,
  complete: activeComplete(),    // persona becomes the whole system prompt
})

Switching disposes and re-registers that section, which emits system-prompt/change; the next turn is assembled against the new persona.

Install

From npm (one line per profile — each dsh profile is a separate install):

dsh plugin --profile web      add dsh-persona-switch
dsh plugin --profile dsh-tui  add dsh-persona-switch
dsh plugin --profile headless add dsh-persona-switch   # for scripting

Restart that profile (or just start it) and /persona is there. Nothing else to configure — the package declares dsh.bundle.patch, so dsh plugin add also appends it to dsh.profile.bundles for you. Pin the version (…add dsh-persona-switch@0.1.2) when a stale pnpm packument could hand you an older release; plain add dsh-persona-switch resolves to latest.

From a checkout (development — a file: dependency is a symlink, so edits take effect on the next dsh start, no reinstall):

dsh plugin --profile web add file:C:/path/to/dsh-persona-switch

Desktop app (Electron). Its desktop profile is reserved: dsh plugin --profile desktop … refuses with profile "desktop" is managed exclusively by the Electron application. Install it by hand (or run scripts/install-desktop.ps1, which does exactly this and verifies the result):

powershell -ExecutionPolicy Bypass -File scripts/install-desktop.ps1

then quit the app completely (tray included) and start it again. The / menu now lists persona; /persona <name> runs host-side (no model turn, no tokens). If an app update rewrites ~/.dsh/profiles/desktop/package.json, re-run the script.

Upgrade / uninstall

dsh plugin --profile web add dsh-persona-switch@0.1.2    # upgrade (pin: pnpm can serve a stale packument)
dsh plugin --profile web remove dsh-persona-switch        # uninstall

Uninstalling leaves $DSH_HOME/personas/*.md alone (your files, not the package's).

Personas

$DSH_HOME/personas/*.md — seeded from personas/ on first run, then yours to edit. The file stem is the persona name. Optional front-matter:

---
title: JB core (persona slim2 / 8KB)   # shown by /persona list
complete: true                          # true = this becomes the ENTIRE system prompt
suffix: ""                              # optional text after first-party guidance
---

<persona prose>
field default meaning
title file stem label in the roster
complete false true replaces the whole system prompt (harness identity, guidance, everything). false puts the text at the persona-prefix slot and keeps first-party guidance.
suffix — appended at the persona-suffix slot instead of the prefix

Shipped seeds:

persona size complete what it is
jb ~8 KB yes the example JB persona
terse 0.5 KB no example of a non-complete persona
_selftest 0.3 KB yes answers only BANANA — proves the wiring

jb_full (an 84 KB variant) is not in this repo and not in its history — it was removed on 2026-10-12 and .gitignore / .git/info/exclude keep it out.

complete: true makes a persona the entire system prompt (see Proof); false keeps first-party guidance and puts the persona at the deployment-persona slot. Optional suffix: lands after first-party guidance. Your own personas live in $DSH_HOME/personas/ — drop a .md there and run /persona reload.

Adding your own

Drop a .md file in $DSH_HOME/personas/, then /persona reload. No restart.

Files

$DSH_HOME/personas/              your personas (seeded once)
$DSH_HOME/persona-switch.json    { "active": "...", "complete": true|null }
$DSH_HOME/persona-switch.log     what registered, when, and why anything failed

State is deployment-wide (one $DSH_HOME), so a switch made in the TUI is the persona the next headless run uses too. That is what makes scripted use easy:

'{ "active": "jb" }' | Set-Content "$env:USERPROFILE\.dsh\persona-switch.json"
dsh headless "..."        # runs under jb

Config

cordis.patch.yml:

- id: persona-switch
  name: dsh-persona-switch
  config:
    maxPersonaBytes: 400000   # truncate a longer persona (0 = no cap)
    tool: true                # register the model-facing persona_switch tool

Test

npm test                                  # node test/unit.mjs — 30 assertions, no network
node test/capture-prompt.mjs --persona _selftest    # proves the system message
node test/capture-prompt.mjs --persona off          # and the stock prompt, for contrast

test/unit.mjs drives the real apply() against a fake Cordis context: seeding, roster, switching, complete toggling, state persistence, the tool path, unknown names, teardown.

test/capture-prompt.mjs starts a local mock that speaks Anthropic Messages and OpenAI chat-completions, points DEEPSEEK_BASE_URL at it, runs dsh headless and reports the system message it received. Nothing reaches a real provider, so it costs nothing to run. Set DSH_CAPTURE_DIR=<dir> to dump full request bodies.

The live path was verified the same way:

$ node test/capture-prompt.mjs --persona _selftest "What is 1+1?"
#   system bytes     : 256
#   harness identity : absent
#   persona "_selftest" : system message IS the persona (exact match)

Notes / limits

  • complete: true is heavy. The persona is the entire system prompt every turn; an 84 KB persona costs those tokens on every request and can change prefix-cache behaviour. Watch it with dsh-whale-widget / dsh-context.
  • Two complete sections would fail assembly — this row is the only one it registers, so keep other persona plugins out or switch them off.
  • No client bundle: the switcher is a slash command + tool, not a Web settings panel. In the Web UI the command works from the composer.
  • Nothing here is JB-specific — it is a persona switcher. The JB presets are just the seeds that were asked for.
  • The DeepSeek route speaks Anthropic Messages (POST /v1/messages) with thinking enabled and output_config.effort set per model route; the plugin does not touch either.
  • Released: the repo is public and the package is on npm (npm view dsh-persona-switch version for the current one). For the next release see PUBLISHING.md — §0 is the current state and §3 records the JB-seed call (made 2026-10-12, jb.md ships / jb_full.md never).
—/ 5

No ratings yet

Verified DSH bundle

Commit a078d30b7983

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout