DeepSeek Harness Plugin

Signalight/codex-to-dsh-pet#dsh-codex-pet

Stars ★ 5 Downloads (30d) 610 Category Just for Fun Added 2026-08-18 npm @signalight/dsh-codex-pet

DSH web-GUI pet runtime that renders any Codex spritesheet-atlas pet (v1/v2) as a draggable overlay: drag/wave/jump, v2 mouse-tracking eyes that follow the active mouse, live agent-status poses, progress bubbles, and an in-GUI atlas importer; ships one original CC BY-NC demo pet (nastya), and user pets live in ~/.dsh/pets.

Install

# from npm (prebuilt)

dsh plugin --profile web add @signalight/dsh-codex-pet

# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)

dsh plugin --profile web add github:Signalight/codex-to-dsh-pet#path:/packages/dsh-codex-pet

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

A DSH web-GUI pet runtime plugin — one plugin that renders any Codex spritesheet-atlas pet (v1 / v2) as a draggable desktop pet in the DeepSeek Harness web GUI.

It is the runtime half of the codex-to-dsh-pet framework: instead of building each pet into its own plugin bundle, you install this plugin once, then add pets as plain data files — no per-pet code.

The plugin ships one built-in example pet nastya (娜斯佳) — an original character (CC BY-NC 4.0, non-commercial) — so the registry is never empty. See assets/nastya/.

Features

  • Renders Codex spritesheet atlases (8 columns × 192×208 cells):
    • v1 (1536×1872, 9 rows) — auto-detected;
    • v2 (1536×2288, 11 rows) — adds 16 mouse-tracking "look" cells.
  • Draggable (position persists across restarts), wave-on-hover, jump-on-double-click.
  • Opt-in mouse tracking (v2 only, default on): the «桌宠» settings section has an Eye tracking toggle; the UI notes it applies to v2 atlases only (v1 has no look cells, so the toggle is inert for v1 pets).
  • Live activity poses: idle / waiting / running / review, driven by the conversation state.
  • Progress bubble showing the running tool name or the live model text tail.
  • Optional fixed-interval first-person LLM summaries, with a per-session journal shown when hovering the pet. Automatic summaries observe only requests completed after selecting a session; they do not backfill historical conversations. Right- click the pet to explicitly analyze prior unsummarized requests. This is disabled by default. Enabling it sends bounded excerpts of user, assistant, tool, and error content to the selected LLM and incurs that provider's usage/cost. Select a provider and model before enabling summaries. Cadence and bubble duration are configurable.
  • Configurable completion, error and interruption voices, including per-track volume, bundled rotating takes and user-uploaded audio overrides.
  • Zero per-pet code: the browser half is registry-driven from /api/codex-pet/*.

DSH compatibility

DSH gates every profile plugin row on its @deepseek-ai/dsh* peerDependencies: a peer range the running DSH version does not satisfy disables the whole row (no pet, no settings section) with Plugin … is incompatible with dsh …: peerDependencies ….

This plugin therefore declares only peers that exist across the DSH 0.2 line and later, with open-ended ranges:

"@deepseek-ai/dsh-client-ui-slots": ">=0.1.0-rc.6",
"@deepseek-ai/dsh-host-webserver": ">=0.1.0-rc.6"

It works on 0.1.x and on 0.2.0-rc.1+. The obsolete @deepseek-ai/dsh-client-runtime peer is not declared: DSH 0.2.0-rc.1 removed that package, so declaring it (^0.1.0-rc.6, as 0.3.1 did) makes DSH disable the row — which is exactly why the pet vanished on 0.2.0-rc.1.

The same upgrade also retired the client runtime at runtime, not just in the manifest. On 0.1.x the pet overlay read the conversation from sessions.currentProvideInfo; that bridge is gone in the 0.2 line, which would leave the snapshot null and the bubble permanently blank (0.3.2 had this bug — the pet appeared but never spoke). The overlay now reads the internal uiSession service's main binding instead:

  • hooks.chat → the live tail (partial, runningCalls) plus turnEnds; this is the target dsh-client-ui-chat registers, i.e. the streaming reply text and the "running: <tool>" bubble text;
  • hooks.trajectory → the same fields plus requests, kept as a fallback when the chat hook is absent (its own partial only fills in once its target has accumulated chunks);
  • hooks.session → running, pendingSubmissions, openState;
  • nodes / turnEnds are rebuilt from the trajectory event nodes, keeping the done chime and the periodic summaries working.

uiSession is deliberately not listed in inject: it is an internal service that older hosts never provide, and Cordis parks the entire plugin when a hard dependency is missing. It is resolved lazily with ctx.get("uiSession") (plus a short polling subscribe, because the service can arrive after the plugin loads), and when it never shows up the overlay falls back to the legacy currentProvideInfo path — so one build serves both hosts.

Install

Recommended — one command (needs pnpm):

# from npm
dsh plugin --profile web add @signalight/dsh-codex-pet

# or straight from GitHub
dsh plugin --profile web add github:Signalight/codex-to-dsh-pet#path:/packages/dsh-codex-pet

Manual route (no pnpm): from the repository root run

.\install-runtime.ps1

This copies the package into ~/.dsh/profiles/node_modules/@signalight/dsh-codex-pet and registers the plugin row in ~/.dsh/profiles/web/cordis.patch.yml. Then:

  1. Hard-refresh http://127.0.0.1:3080 (Ctrl+Shift+R) — the DSH profile hot-reloads cordis.patch.yml. If the pet still doesn't show, fully quit and relaunch the DSH desktop app (command-line users can restart dsh web).

Rollback: delete ~/.dsh/profiles/node_modules/@signalight/dsh-codex-pet and restore the .bak next to the patch file.

Add a pet

A pet is a folder holding a pet.json manifest plus one atlas image. Drop it into either source (user pets override built-ins on id collision):

  • built-in: packages/dsh-codex-pet/assets/<pet>/
  • user: ~/.dsh/pets/<pet>/ (survives plugin updates)

pet.json:

{
  "id": "nastya",
  "displayName": "娜斯佳",
  "description": "娜斯佳 Nastya — original character (CC BY-NC 4.0).",
  "spritesheetPath": "spritesheet.webp",
  "spriteVersionNumber": 2,
  "size": 120,
  "pin": "bottom-right"
}

Only id and spritesheetPath are required. spriteVersionNumber is auto-detected from the image dimensions when omitted; size (px width) and pin (top-left / bottom-right / …) default to 120 and bottom-right.

No manual editing needed: in the DSH settings surface open the «桌宠» section and click 导入桌宠 (webp / png / gif) — the plugin writes the file into ~/.dsh/pets/<name>/, auto-detects the atlas version, and selects the new pet. The pet id comes from the filename (my-pet.webp → my-pet); if that id is already taken the plugin appends a -2 / -3 suffix instead of overwriting the earlier pet (all Codex atlases are named spritesheet.webp, so without this every import would clobber the previous one). Re-importing the same id with the same typed display name updates that pet in place.

Architecture

src/
├── index.js     host half: name/inject/apply, mounts service + routes
├── registry.js  scans assets/* + ~/.dsh/pets/*, normalizes Codex atlases
├── service.js   persisted selection + display config (~/.dsh/codex-pet.json)
├── routes.js    /api/codex-pet/* JSON API + /codex-pet/<id>/* assets
└── client.js    browser half: registry-driven overlay renderer
  • Host half registers same-origin routes via the DSH web server (ctx.webServer.register), serving the pet list, state and atlas assets.
  • Browser half fetches /api/codex-pet/state, renders the selected pet, mirrors drags back via POST /api/codex-pet/set-config, and seats a settings.section entry («桌宠») that edits the pet through the same API.

API

Endpoint Method Purpose
/api/codex-pet/pets GET pet registry (list of definitions)
/api/codex-pet/state GET selected pet + display config
/api/codex-pet/set-pet POST { petId } — switch pet
/api/codex-pet/set-config POST update display, summary, or sound settings
/api/codex-pet/set-visible POST { visible }
/api/codex-pet/import?id=<filename>&name=<displayName> POST raw image body — import a Codex atlas
/api/codex-pet/models GET available LLM providers and models for summaries
/api/codex-pet/summarize POST summarize one completed assistant-request batch
/api/codex-pet/journal?session=<id>&limit=<n> GET recent persisted summaries (&all=1 returns all records for manual coverage checks)
/api/codex-pet/sound?track=<id> POST upload a raw audio override (8 MiB maximum)
/api/codex-pet/reset-sound?track=<id> POST remove an audio override
/codex-pet-sound?track=<id> GET stream the effective done, error, or interrupt track
/codex-pet/<id>/<file> GET pet.json + spritesheet assets

Summary journals are stored under ~/.dsh/codex-pet-journal/. Uploaded voice overrides are stored under ~/.dsh/pets/sounds/ and survive plugin updates.

Roadmap

  • Settings section («桌宠» in the DSH settings surface: pet selector, show/hide, size, corner pin, bubble color/opacity, eye tracking — the last is v2-only and noted as such), backed by the plugin's own API.
  • In-GUI import button (upload a Codex atlas → auto-detect → install → select).
  • In-GUI preview before import (live canvas frame preview).
  • Published to npm (@signalight/dsh-codex-pet) + dsh-plugin GitHub topic.

License

MIT — see the repository root LICENSE.

Built-in scenario voice / sound assets

The plugin ships 8 built-in scenario sounds under assets/sounds/ (done-1~4.wav, error.wav, interrupt-1~3.wav):

  • Attribution: these sounds were generated by contributor @yabo083 (PR #4) using Qwen3-TTS VoiceDesign and submitted with the plugin; they were reviewed and accepted into this package, and are distributed under MIT together with the plugin.
  • Generator license: the Qwen3-TTS model repo is Apache-2.0; that license applies to the model repo only and does not change this project's license. Using Qwen3-TTS does not imply endorsement by Qwen.
  • Relationship to the character: these lines are usually performed as the built-in example pet nastya (娜斯佳). That character is an original character, and its atlas is licensed CC BY-NC 4.0 (non-commercial), so even though the sound files are MIT-licensed, using them as that character's voice keeps the character's non-commercial restriction in force; ask the character's author before any commercial use.
  • User audio: you may upload your own audio to replace any scenario sound (Settings → 完成提示音); custom audio's copyright and license are your own responsibility.

Content from the project README on GitHub ↗

Links

More in this category

View the whole category →

Community comments

Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.