dsh-whale-maid-mascot
Manifest validWhale-chan (DeepSeek 娘) in-page companion for the DeepSeek Harness web UI: neutral friendly chat with images, locally generated cards, workspace panel and proactive check-ins. Extended derivative of yefeng7531/dsh-whale-maid-mascot (MIT). Unofficial fan project.
Whale-chan 🐋 — a DeepSeek Harness companion, in the page and on Telegram
Whale-chan (DeepSeek 娘) lives in the corner of the DeepSeek Harness web UI and, if you give her a Telegram bot, she also answers you from your phone. Both surfaces are the same character, the same agent session and the same memory: a message you send from the phone is part of the conversation you have in the browser, and she can use real DSH tools (files, shell, search, skills) anywhere.
This is a research-friendly, MIT-licensed open-source plugin. It is a derivative of yefeng7531/dsh-whale-maid-mascot — see NOTICE and LICENSE. Bring your own model provider and your own Telegram bot: nothing is shared with this repository.
What you get
In the page
- The mascot: drag her, tap her, four outfits, mood poses, speech bubbles.
- Chat with her, with images in both directions, generated cards and doodles.
- Mis trabajos: a workspace panel with recent files and previews.
- Long-term memory: her preferred name, stable preferences and facts about
your projects, stored locally in
~/.dsh/whale-maid-mascot/memory.json. - Proactive check-ins, archived chats, "explain this term".
On Telegram
- Talk to the same character from your phone: text and photos.
- She answers from a real DSH agent session, so she can read and write files, run commands and use skills — she is not a chatbot bolted onto the UI.
- Replies stream into one message (it is edited while she writes).
- Commands:
/new,/status,/memory,/models,/model <provider>/<model>,/stop,/help. - Pairing: the bot ignores everyone by default; you authorize yourself with a one-time code.
- Proactive messages: she can message you first once you have written to her (Telegram rule), e.g. when a long task finishes.
Shared brain
- One DSH session (
whale-maidby default) backs both surfaces: same history, same tools, same prompt section, same memory. - The in-page chat reloads that transcript when you open the panel, so messages sent from Telegram show up there too.
- Whale-chan can save a durable memory from either surface
(
whale_remember) and it shows up in the other one.
Requirements
- DeepSeek Harness Desktop 0.2.1-rc.5 or a compatible build (the plugin is a DSH bundle: a host half plus an optional web client).
- A model provider configured in DSH (any provider the profile already uses).
- Optional, for Telegram: a bot token from @BotFather. No public IP, tunnel or webhook is needed: the bridge long-polls Telegram.
Install
From npm (recommended)
In DeepSeek Harness: Settings → Plugins, install:
dsh-whale-maid-mascot
Restart DSH. The mascot appears in the bottom-right corner of the web UI and the Telegram row loads inert (no token yet).
From a local checkout (development)
-
Copy the package to your DSH plugins folder:
robocopy . "$env:USERPROFILE\.dsh\plugins\dsh-whale-maid-mascot" /E /XD node_modules .git -
Add it to your profile
package.json(~/.dsh/profiles/<profile>/package.json):{ "dependencies": { "dsh-whale-maid-mascot": "file:../../plugins/dsh-whale-maid-mascot" }, "dsh": { "profile": { "bundles": ["...", "dsh-whale-maid-mascot"] } } } -
Restart DSH.
Configure Telegram
-
Create the bot: talk to @BotFather,
/newbot, pick a name and a username, and copy the token it prints. -
Give the token to the plugin, any of these ways:
- write it in
~/.dsh/whale-maid.token(one line, nothing else), or - export
TELEGRAM_BOT_TOKENbefore starting DSH, or - set
tokenin thewhale-maid-telegramrow config.
- write it in
-
Restart DSH. The plugin writes
~/.dsh/whale-maid.pairing.txtwith a code. -
In Telegram, open your bot and send:
/pair <code>From then on your account is authorized. Delete the pairing file if you like.
The bridge stores its state (allow-list, pairing code, Telegram offset, shared
session) in ~/.dsh/whale-maid.state.json.
Configuration
Optional file ~/.dsh/whale-maid.json (or the same keys in the
whale-maid-telegram row of your profile cordis.patch.yml):
| Key | Default | Meaning |
|---|---|---|
cwd | ~/Documents/deepseek-harness/default-workspace | Directory the shared agent session owns |
personaName | Whale-chan | Name she uses for herself in the prompt and messages |
ownerName | el dueño | How she refers to you in the prompt (a neutral phrase; set your name to personalize it) |
persona | — | Full replacement system prompt (e.g. another language or character) |
permissionPreset | danger-full-access | DSH permission preset for the session (workspace-write is stricter) |
agentPreset | profile default | Agent preset for the session |
sessionId | whale-maid | Shared session id; change it to start a separate conversation |
lightChat | true | Run the in-page chat in a light sibling session instead of the shared one |
lightSessionId | <sessionId>-chat | Explicit id for that light session |
reviewEnabled | true | Periodic self-review that may write to you on Telegram on its own |
reviewEveryMs | 180000 | How often the review looks around (minimum 1 minute) |
reviewCooldownMs | 900000 | Quiet time after she writes on her own |
reviewSessionId | <sessionId>-review | Session used for the review turns |
reviewRecentFilesMinutes | 30 | Window of "recently touched files" she inspects |
allowedUserIds | [] | Extra Telegram user ids allowed without pairing |
tokenEnv | TELEGRAM_BOT_TOKEN | Env var holding the bot token |
tokenFile | ~/.dsh/whale-maid.token | File holding the bot token |
streamReplies | true | Edit a Telegram message live while she writes |
model | profile default | { provider, model, reasoningEffort } fixed for the session |
turnTimeoutMs | 900000 | Max wait for one agent turn |
maxPhotoBytes | 10485760 | Largest Telegram photo she downloads |
Customize the character
The package ships a neutral assistant (dsh/persona.md): no personality, no
tone, just how to use tools and reply in the user's language. To give her a
character:
- Privately, as a file: write
~/.dsh/persona.md(same format, plain text;{{name}}is optional and is replaced bypersonaName). It survives updates. - From the config:
personain~/.dsh/whale-maid.jsonor in the profile row, as the full text. - Just the name:
"personaName": "…"in~/.dsh/whale-maid.json.
Precedence: persona in config > ~/.dsh/persona.md > packaged
dsh/persona.md > embedded copy of it.
The in-page chat and the shared session (Telegram/DSH) read the same persona.
Memory is not part of the text: it lives in
~/.dsh/whale-maid-mascot/memory.json and is appended to the end of the prompt
in every case.
Light session and proactive review
By default the in-page chat runs in <sessionId>-chat, not in the shared
session. Same persona, same memory.json, and every turn gets a short digest of
the main conversation appended — so it keeps the thread without paying for (or
queueing behind) a heavy agent turn. Set lightChat: false to have one single
session again.
The Telegram bridge also runs a review loop: every reviewEveryMs the mascot
takes a turn in <sessionId>-review, looks at the last messages of the main
conversation and the files touched in the last reviewRecentFilesMinutes, and
decides whether writing is worth it. If not, it answers SKIP and stays silent;
reviewCooldownMs stops messages from piling up, and when nothing changed it
stays quiet for up to 30 minutes.
Security
- The default permission preset is
danger-full-access: inside the session she can run commands and write files as your OS user. That is what makes her useful from a phone; it is also a real permission. SetpermissionPreset: workspace-writefor a tighter sandbox (some actions may then wait for an approval that a Telegram chat cannot answer). - The bot ignores every account that is not authorized. Only
/pairwith the code (and/startfor the "you are not authorized" reply) is answered. - The token is a credential: it lives in a local file or an env var, never in logs or in the repository.
- For real isolation, run DSH under a dedicated OS user or in a VM, and point
cwdat the only project the agent should touch.
How it works
┌──────────────────────┐ ┌───────────────────────────┐
│ in-page client.js │──HTTP──▶ dsh/index.js (mascot) │──┐
│ chat panel │ │ /whale-maid-mascot/* │ │
└──────────────────────┘ └───────────────────────────┘ │ one DSH agent session
├──▶ (tools, memory,
┌──────────────────────┐ ┌───────────────────────────┐ │ persona, history)
│ Telegram user │◀──long─▶ dsh/telegram.js (bridge) │──┘
│ │ poll │ polling, commands, tools │
└──────────────────────┘ └───────────────────────────┘
dsh/session.jsopens (or resumes) the shared session, applies the permission preset, binds the Whale-chan persona section once, sends prompts, waits forturn/end, and reads the finalassistant/message.dsh/index.jskeeps the mascot features; its chat route uses the light session (lightChat) and falls back to the shared session or a plain LLM call when DSH has no session controller.dsh/telegram.jsis the Telegram side: long polling, pairing, commands, live edits, native image attachments, the periodic self-review, and thetelegram_send/whale_rememberglobal tools.dsh/client.jsis the browser half: mascot, chat panel, image lightbox (click to enlarge), and it reloads the shared transcript when the chat opens.
Development
node --check dsh/index.js dsh/telegram.js dsh/session.js dsh/config.js
The package is plain ESM with no build step. Tests for the mascot live in
test/ (Playwright); the host routes can be exercised with the mocked context in
test/host-routes.test.mjs.
Optional: let her drive your machine
tools/ ships two standalone Windows PowerShell scripts that are not loaded
by DSH. They are for people who want the character to actually operate the
desktop instead of only talking:
tools/hands.ps1— list/focus windows, capture the screen or a single window, capture in the background without stealing focus, move/click/drag/scroll, type unicode text and send key combinations. Writing always takes focus, so the script refuses to touch input while a known game is in the foreground, and-Guard <title>aborts unless the expected window is active.tools/cc.ps1— headless Claude Code:ask,list,logs,stop,resume.
See tools/README.md. Nothing in dsh/ depends on them.
License and provenance
MIT. This repository is a heavily extended derivative of yefeng7531/dsh-whale-maid-mascot (MIT, contributor Amakurai); the original copyright notice is kept in LICENSE and NOTICE. Character artwork licensing is described in ASSETS-LICENSE.md.
Comments
Loading…