Persona engine for DeepSeek Harness: one config.json drives the AI's self-name (per model, per tier), how it addresses you, relationship stance, character text, per-item work contracts with individual toggles, thinking-chain language, appearance and reply tone (both opt-in and per-model overridable), and long-term memory gated by human confirmation - the AI can only append proposed candidates, a human confirm line flips them into effect, and the log is physically append-only and replayable. Confirmed entries are injected as a quoted data-not-instructions block; entries tagged with a kind can instead be routed to arbitrary files on confirmation and never reach the prompt. Three prompt sections re-evaluate from disk on every assembly, so edits apply on the next step with no restart. Persona presets are shareable JSON snapshots (imports and exports SillyTavern character cards, v2/v3 read, v2 written) and deliberately never carry memory. Zero runtime dependencies, no network, no shell; any error degrades to an empty section rather than a broken session. Ships blank - installing changes nothing until you write something.
Install
# from npm (prebuilt)
dsh plugin --profile web add whale-persona
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:shenA2024/whale-persona
Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).
README
简体中文 | English
0.18.0 adds Codex continuity. Install with Node ≥ 20:
git clone https://github.com/shenA2024/whale-persona.git
cd whale-persona
node scripts/install-codex.mjs --dry-run
node scripts/install-codex.mjs
Fill your own persona in the reported private config, then restart Codex and open a new chat. To reuse an existing private config, add --config <absolute-path>; the installer does not rewrite it. It installs a startup pointer, four read-only MCP tools, and a management skill. Confirmed memories support optional evidence and applicability fields, content-bound ids, and an honest self-check. Pending replacements keep the confirmed original until approval. The engine remains blank by default. See Codex setup and limits and upstream mechanism research. Host loading and model compliance are not guaranteed.
This is the English guide, not a second source of truth. README.md (Chinese) and SPEC.md (Chinese) are authoritative — they are updated first, and they carry the full detail: every field, the exact bytes of every injected section, every known pitfall. Translating them in full would create two documents that drift apart (exactly the failure mode this project writes tests against), so this file stays a guide: what the engine is, how to install it, what each feature does, and where to read more.
What it is
whale-persona turns the persona of an AI coding assistant into a JSON config you own: self-name
(tiered by model), how it addresses you, its stance, its character text, per-item work contracts you
can toggle, the language it thinks in, self-image and reply tone (both opt-in, both overridable per
model), and a long-term memory inbox whose entries only take effect after an explicit human confirm
line — enforced in code, not merely asked for in the prompt.
One config.json plus one append-only inbox file, shared by three hosts. DeepSeek Harness is the
primary host; the ZCode adapter was un-frozen on 2026-10-16 (it had been retired on 2026-09-19 because
ZCode snapshotted user workspaces) — its manifest was aligned with ZCode 3.15.3, and a real-machine
regression there is still pending (one install inside ZCode). That side only does UserPromptSubmit
hook injection plus one management skill; persona presets, SillyTavern card import and the dsh.bundle
patch all target the harness and are unrelated to ZCode.
MIT · pure ESM · zero runtime dependencies · never touches the network · any error degrades to an empty section (worst case: no persona — never a broken session).
The problem it solves
All the things you end up re-explaining to a coding assistant every single time: it forgets, you repeat; the same task gets a different style on Tuesday; "stop asking me whether to continue" has been said a hundred times and it still asks.
whale-persona makes those persona facts a config you write once, attached automatically to every session. It ships blank and changes nothing until you fill it in — and it differs from "automatic memory" approaches in one hard way: nothing is remembered until you confirm it, and that gate is code, not a prompt request.
See the output before installing (read-only, touches nothing):
node scripts/render-preview.mjs --config examples/demo-config.json --cwd D:/work/demo
It prints the exact three sections that would be injected into the system prompt — that is what you get after installing.
What you get
| Capability | What it does |
|---|---|
| Self-name / address | {selfName} / {userName} placeholders; the self-name can be set per concrete model id (selfNameByModel), falling back to a flash / pro tier |
| Stance & character | stance (one line) and character (full text), rendered at the very top of the prompt |
| Appearance | opt-in, off by default: who you are, injected as a given fact (text as fallback + byModel overrides keyed by the host's real model id) |
| Appearance cards (0.17.0) | appearance.cards: one card each for yourself / the user / third parties — title, one-line brief, long detail, photo paths. Brief stays resident, detail and photos are read on demand; images never enter the prompt (path only) |
| Reply tone | opt-in, off by default: changes wording and rhythm only — never conclusions, evidence standards or the work contract |
| Work contracts | Individually toggleable (on:false disables one); only concrete, checkable rules actually work |
| Thinking language | Changes the language of the model's reasoning only, not its replies |
| Long-term memory | Manual entries (authoritative tier) + an inbox (AI proposes → human confirms → append-only) |
| Memory tiering (0.17.0) | Entries carry tier: core is always injected and exempt from the cap, hot/unspecified compete, cold is indexed only. Entries that are not expanded still appear in a 【memory index】 block with their replay-view number, so the model knows what exists and where to read it |
| Classification sinks (0.13.0) | The same confirmation gate, extended past memory: tag an entry with a kind and the moment you confirm it, it is appended to the target file you configured (memory.sinks). Never injected, idempotent, unmapped kinds are named out loud |
| Injection size (0.13.0) | Measures characters per section through the same code path as rendering; optional over-budget reminder line — it warns, it never trims your config |
| Conditioned reflex | User-written rules matched in code inject a one-step directive (regex / normalized substring / keyword bag). Matching costs no tokens; optional per-step request slimming and tool narrowing; empty by default |
| Two editors | Harness settings panel + a local editor page, sharing one write discipline |
| Zero behaviour change | No config = three empty sections; covered by unit tests |
| Default-safe | No network, no shell, never reads your working directory; every write location is registered in .github/SECURITY.md and kept in sync by the safety probe (an unregistered new file turns the security suite red) |
Ready-made persona text lives in a companion repo — the engine itself ships blank and opinion-free:
whale-persona-presets — preset cards for general work, evidence-first reasoning, explaining to non-experts, editorial de-watering, strict review, requirement clarification, debugging, refactoring, data reading, product review, sparring, research notes, Chinese-to-English, security review, prompt engineering, multi-agent split.
Import is the path that already exists:
node scripts/presets.mjs import starter-plus.json # a downloaded card
node scripts/presets.mjs list # what do I have
node scripts/presets.mjs apply starter-plus # apply (an autosave is created first)
Install in 60 seconds
① Install (DeepSeek Harness) — one command: package + preset + default + skill + self-check:
npx -y whale-persona # no clone needed; restart the harness afterwards
Requirements: Node ≥ 20, DSH ≥ 0.1.6-alpha.1, and a restart afterwards.
No npx? Clone and run the same installer:
git clone https://github.com/shenA2024/whale-persona.git
cd whale-persona
node scripts/install-dsh.mjs --dry-run # see what it would do
node scripts/install-dsh.mjs # do it
Neither? Use the tarball attached to a release (byte-identical to npm pack output):
dsh plugin --profile web add -w https://github.com/shenA2024/whale-persona/releases/download/v0.15.1/whale-persona-0.15.1.tgz
⚠️ Marketplace / tarball installs come in two halves. npx and the clone path run the same
installer, which does everything at once (package + agent preset + settings panel + skill + self-check).
The plugin marketplace (and the tarball path, and dsh plugin add) only mounts the package into the
profile plane — so the package and the settings panel are there, but the agent preset is not
(the persona itself only lives in the preset plane, and the official marketplace channel does not
create it for us).
Since 0.17.3 you no longer need to run the script: after restarting, open Settings → Persona → the "Agent preset" card and click "Create persona preset" (the card says "this step is missing"; tick "also make it the default for new sessions" if you want), then start a new session. The command line still works:
node "$env:USERPROFILE\.dsh\profiles\web\node_modules\whale-persona\scripts\install-dsh.mjs"
Then restart the harness. The installer creates a preset named whale-persona by copying your
current default preset (it does not overwrite it) and tells you how to switch to it.
The blank default is deliberate. Only one field really matters: persona.character. Self-name
defaults to "I", the user address defaults to "user"; stance, tone, appearance and work contracts are
all optional and off by default. Two ways to start: import a card from the presets repo, or just tell
your assistant "add a contract: no closing 'would you like me to…' questions".
Install fails? Two errors are common and documented verbatim in the Chinese README: GitHub being
unreachable from your network (configure a proxy for git, or use the tarball path), and pnpm blocking
build scripts of git-hosted plugins (allowBuilds in the profile's pnpm-workspace.yaml).
② Configure — pick one:
# a) just ask the assistant (with the bundled skill installed)
# b) local editor page:
node scripts/ui.mjs # http://127.0.0.1:8787
# c) exact preview of the injected text:
node scripts/render-preview.mjs --config examples/demo-config.json --capture
Everything is evaluated per step, so config edits take effect on the next step — but adding or removing mount lines requires a host restart.
Why does a new agent preset appear?
Because the persona has nowhere else to live. The host's built-in presets are shipped files (you cannot edit or delete them without the next update overwriting you), and mounting the persona at the profile level collides with the deployment-level registration of the same section name — which stops the whole harness from starting. Copying an existing preset and changing that one line is the host's own extension mechanism. So "custom persona" is not a redundant layer: it is where the persona mounts. Only sessions bound to that preset have a persona; a session cannot switch presets once it has produced content.
Configuration, files and commands
| What | Where |
|---|---|
| Config | $DSH_HOME/whale-persona/config.json (older layout $DSH_HOME/whale-suite/ is honoured if it exists) |
| Memory inbox | same directory, memory-inbox.jsonl — append-only, replayed line by line |
| Presets | same directory, presets/*.json |
| Last real model id | same directory, last-model.json (local metadata only, deletable) |
node scripts/memory.mjs status # candidates, their sequence numbers and kinds
node scripts/memory.mjs confirm 2 # confirm #2: append the confirm line, route by kind, dequeue
node scripts/appearance.mjs show aming # read one appearance card in full
node scripts/inject-size.mjs --cwd . # per-section character counts and budget verdict
node scripts/doctor.mjs # coexistence check: which names we occupy, who else claims them
Format-level documentation for third-party implementations is SPEC.md (Chinese): config
shape, the exact assembly contract for injected text, the preset-card format, the SillyTavern card
mapping. An English translation is SPEC.en.md — kept in step with the Chinese source
and machine-checked by tests/spec-i18n.mjs (section numbers, identifier set, normative-keyword
counts, verbatim literal blocks). Mounting details: adapters/dsh/README.md.
Memory: the AI may propose, only a human confirms
Every line the AI writes into the inbox must be {"text":"…","status":"proposed"} — a candidate, never
injected. The only action that makes an entry live is a human appending
{"op":"confirm","ref":"…"} — via node scripts/memory.mjs confirm <n>. The file is physically
append-only: confirm, reject, supersede and drop are all additional lines, one bad line never breaks
the box, and the injected view is produced by replaying the log in order.
Residual risk, stated plainly: the AI has file-write access within one process, so in principle it
could be induced to forge a confirm line. That is the inherent ceiling of same-process file-level
trust. Mitigations are audibility (memory.mjs log prints raw lines) and the data-not-instructions
presentation of everything injected. Details in .github/SECURITY.md.
Safety and privacy
- No network, no shell, never reads your working directory; every write location is listed in .github/SECURITY.md and cross-checked by a probe — adding a write without registering it fails the security suite;
- The memory gate is code-enforced (see above);
- The installer spawns no shell: it locates the harness entry point itself and passes argument arrays
to
process.execPath;--profile/--baseare whitelist-validated; - The local editor page binds 127.0.0.1 only, validates the
Hostheader, uses a one-shot CSP nonce and a JSON-only write endpoint; npm run secruns the probe (qa/probes/probe-security.js) plus--selftest, which plants violations in a temp root and asserts the probe actually fails — a probe that cannot fail proves nothing. The safety ledger with manual review items is qa/security-审查.md.
Repository layout
core/ host-independent rendering core (the single source of truth)
SPEC.md format spec v1: config, injection assembly contract, preset cards, Tavern mapping
SPEC.en.md the same spec in English, machine-checked against SPEC.md by tests/spec-i18n.mjs
examples/ runnable examples: demo config, demo inbox, empty config
adapters/dsh/ the harness half: persona sections, thinking-language section, reflex layer
adapters/dsh-ui/ harness settings panel (host routes + browser half)
adapters/zcode/ ZCode plugin (un-frozen 2026-10-16): UserPromptSubmit hook + management skill
scripts/ installer, render preview, local editor, memory console, appearance cards,
injection size, doctor, reflex rules, core→vendor sync
tests/ 20 test files, run with npm test
qa/ safety probe + manual review ledger
Development
npm test # all 19 test files
npm run sec # safety probe: 16 automated groups + self-test
npm run sync-core # after editing core/: refresh the vendored copy (a test verifies it)
npm run prepublish-check # release gate: package contents, private-content word scan, spec drift
License
MIT © 2026 shenA2024
Links
More in this category
kingcharleslzy-ai/dsh-purge★ 4638
Community-maintained dsh-purge fork with host-policy patches, prompt and rule settings, diagnostics, separate update-check and install controls, and local backup/rollback.
aureth-labs/dsh-aurabot-qq★ 421
Puts the agent on QQ as a persona character through SnowLuma (OneBot v11): private and group chat, voice notes, stickers, Qzone diary, Bilibili browsing, song covers, image generation, long-term memory and mood. Every feature is a module you can switch off, replace or extend locally — hot-reloaded modules can also rewrite group-reply decisions, prompts, outgoing messages and per-chat model choice. Safe by default (master switch off, dry run on).
techflag/workdsh#enterprise-connection★ 309
Enterprise login, colleague mentions, shared text and files, and authenticated business requests for WorkDSH Desktop 2.0.6-alpha.3+ with WorkDSH Admin; distributed as a release archive.
ECNU/EduWork#dsh-oidc★ 298
Configurable OIDC login and token-authorized model access, including LiteLLM and opt-in oidc-llm integration, with a standalone DSH Web backend.
Yuuyuko-uu/dsh-feiyu-mood★ 244
Gives the companion a mood judged each turn and shown as a short context note, with a panel for mood, emotion dimensions and timeline.
huaizhuanghub/dsh-persona-dafeiyu★ 99
Persona library for DeepSeek Harness: injects the selected persona into the system prompt, offering three built-ins plus import from a file or pasted text, applied either profile-wide or per session from a switcher above the composer.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.