Skip to content
dsh-market Browse plugins GitHub 中文

shenA2024/whale-persona

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.

Stars ★ 3 Category Identity & Communication Listed 2026-09-22 npm whale-persona

Install

Inside DeepSeek Harness, with dsh-market

dsh plugin --profile web add dshmarket

Or from the command line

dsh plugin --profile web add whale-persona

Installing runs third-party code with your own permissions — it can read your files, use your credentials and reach the network. Review the source first, and pin a commit (github:owner/repo#sha) when you can.

README

CI

简体中文 | English

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 two hosts. DeepSeek Harness is the primary host; the ZCode adapter is retired (2026-09-19) and kept for history only — no further development, no real-machine regression runs, not first in line for fixes. 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 / --base are whitelist-validated;
  • The local editor page binds 127.0.0.1 only, validates the Host header, uses a one-shot CSP nonce and a JSON-only write endpoint;
  • npm run sec runs 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/  retired ZCode plugin (history only)
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

Content from the project README on GitHub ↗

Comments

Comments live in GitHub Discussions. Sign in with GitHub to post or react.