DeepSeek Harness plugin

dsh-pet-levi52

A Codex-style desktop pet plugin for DeepSeek Harness (dsh).

Jump to install

Source facts

Repository
levi52/dsh-pet
Latest update
Aug 19, 2026
Category
Just for Fun
GitHub stars
1
Format
plugin
Catalog evidence
Upstream dsh.bundle evidence
Evidence path
package.json#dsh.bundle
Checked against
0.1.0-rc.8
Upstream check date
2026-08-20

This evidence comes from the upstream catalog. This site has not installed, run, or security-reviewed the plugin.

Install

Start with a prompt that asks an agent to review the GitHub repository and source. Switch to the command if you want to install it yourself.

Copy this prompt into DSH, Codex, or another agent and ask it to review the GitHub repository and source first.

Do not install or run any commands yet. Read this plugin's GitHub repository, README, and relevant source code. Then answer the questions below clearly and directly so I can decide whether it fits my needs:

1. What is this plugin, and what problem does it solve?
2. Who is it for, and what are its typical use cases?
3. How is it used after installation? Include one minimal example.
4. What known limitations or privacy, security, compatibility, or maintenance risks does it have?
5. Give a clear recommendation: recommend, conditionally recommend, or do not recommend, with reasons.

Distinguish statements documented by the repository, inferences from source code, and unknowns. If evidence is insufficient, say so explicitly. Do not guess or simply repeat the README.

GitHub: https://github.com/levi52/dsh-pet
Plugin: dsh-pet-levi52
Author: levi52

Check the source files

Read the README and other files from this plugin directory before installing.

File explorer4 files
README.en.mdSource · read only
README language

<div align="center">

🐾 DeepSeek Harness Desktop Pet Plugin

A Codex-style desktop pet: embedded in the DSH web UI, playing animations that follow the agent's real-time state, with sprite and pacing fully configurable from the Settings page.

English · 中文

!License: MIT !Node >= 18 ![Developed with DeepSeek Harness](https://www.deepseek.com/harness/)

</div>

---

Features

  • 🏠 Embedded in the 3080 page: injects an overlay via the official webServer.tapIndex — the pet lives on the same origin and page as dsh, appearing and disappearing together with it
  • 🎬 Real event-driven: subscribes to the root context's session/event and switches between idle / thinking / working / waiting / completed / failed animations based on turn/start, tool/call, turn/end, etc.
  • 🖼️ Sprite as config: grid layout and state→row mapping are declared in configuration (config.sprite or a same-name .json sidecar file) and fetched by the renderer at runtime — swapping sprites requires no source changes
  • ⚙️ Managed in Settings: a visual "Desktop Pet" section in the dsh settings page — upload/select sprites, grids, state mapping, scale, animation speed, idle delay, show/hide
  • Changes take effect instantly: config is hot-pushed to the renderer via an SSE config event; scale, animation speed and idle-delay adjustments apply immediately, no refresh or restart needed
  • 💾 Automatic persistence: all settings are saved to pet/user-config.json, restored on refresh, and take priority over cordis.patch.yml
  • 🪟 Multiple presentation modes: besides the embedded overlay, the renderer also powers a standalone popup page, a Chrome app frameless window, a pywebview transparent window (packagable as .exe), and Electron — four ways to use it

Installation

Prerequisites

  • DeepSeek Harness (dsh CLI) installed, with the web profile run at least once
  • Node.js ≥ 18

Steps

# 1. Register the local plugin to the web profile
#    (the bundle takes effect automatically — no manual edits to dsh files):
dsh plugin --profile web add <path-to-this-directory>

# 2. Start dsh (the Web GUI starts along with it):
dsh --profile web

Once started, open dsh's web address (printed in the terminal, usually http://127.0.0.1:3080/) — the pet appears in the bottom-right corner; the management entry lives at Settings → Desktop Pet.

Uninstall

dsh plugin --profile web remove dsh-pet
#    User data (pet/user-config.json and pet/uploads/) is kept;
#    delete them manually if you want a full cleanup.

> Client-side changes only (sprite, scale, animation speed, etc.) just need a forced browser refresh; host-side changes (routes/logic in index.js) require restarting dsh.

UI Reference

The management panel lives in the "Desktop Pet" section of the dsh settings page (the settings.section slot). What each area does:

AreaDescription
EnableToggle for showing the pet, effective immediately (the overlay hides instantly when off)
SpritePreviews the current image; "Upload Image" picks any local sprite sheet (webp / png / gif / jpg / svg), stored automatically into pet/uploads/; uploaded images can be deleted; "Default (Doraemon)" always switches back to the built-in image
GridColumns / rows. The sprite sheet is evenly divided into columns × rows; each row is one state animation
State → row mappingAssign a sprite row (0-based) to each of idle / thinking / working / waiting / failed / completed
Look & pacingScale (0.5×–3×), animation speed (0.25×–4× global multiplier), idle delay (ms)
ActionsSave (writes pet/user-config.json and pushes via SSE), Reset to defaults

Data Storage

  • Config: pet/user-config.json (enabled, scale, fpsScale, idleMs, spriteFile, sprite grid/state mapping, etc.)
  • Uploaded images: the pet/uploads/ directory (config stores only the file name — large images are never embedded into the JSON)
  • Both are runtime user data, ignored by .gitignore and never committed; to share defaults across a team, use the cordis.patch.yml config instead

How It Works

  • Injection: the plugin obtains dsh's built-in webServer service and uses tapIndex to write <script type="module" src="/dsh-pet/overlay.js"> into the 3080 page; sprite, state and SSE all live under same-origin /dsh-pet/* routes
  • State machine: subscribes to the root context's session/event, maps event.type to a pet state and plays the corresponding animation row (see table below)
  • Layout delivery: /dsh-pet/sprite-config returns the grid and state mapping; cell pixel size is computed by the renderer as actual image size ÷ cols ÷ rows, so sprite sheets of any resolution are sliced correctly
  • Hot update: changes from the settings panel are persisted via POST /config and broadcast to the SSE stream; the renderer applies the config event immediately (the image is reloaded only when the sprite file actually changed, avoiding animation flicker)

State Mapping

dsh event (event.type)Pet stateAnimation rowNotes
turn/startthinkingRow 8A turn begins, the model is thinking
step/startworkingRow 1Entering an execution step
assistant/message, assistant/chunkthinkingRow 8Model is generating
tool/callworkingRow 1Calling a tool (bubble shows the tool name)
tool/resultworkingRow 1Processing a tool result
turn/end (reason.kind is completed)completedRow 4Task completed; returns to idle after idleMs
turn/end (reason.kind is error/aborted/interrupted/blocked)failedRow 5Execution interrupted

> dsh's agent state is recorded through the session event log (session.append(...)) and exposed to host plugins uniformly as the root context's session/event; agent/error and agent/status are dispatched on the agent's private dispatch, not in session/event, so this plugin uses turn/end's reason.kind as the failure signal. The waiting state is currently triggered only manually in demo mode.

Configuration

Override the defaults in your profile's cordis.patch.yml (cordis.patch.yml must be a top-level YAML array, each element being a patch entry):

- insert:
  - id: dsh-pet
    name: dsh-pet
    config:
      idleMs: 3000
      scale: 1
      fpsScale: 1
      injectOverlay: true
      overlayRoute: /dsh-pet
OptionTypeDefaultDescription
idleMsnumber3000How long after completion/error before returning to idle (ms, 500–600000)
scalenumber1Overlay size multiplier (0.5–3)
fpsScalenumber1Animation playback speed multiplier (0.25–4; a global multiplier applied to all states, without overriding per-row rowFps relative pacing)
injectOverlaybooleantrueWhether to inject the overlay into the 3080 page; set false to only serve the /dsh-pet/ popup page
overlayRoutestring/dsh-petSame-origin route prefix under which all resources are served
enabledbooleantrueWhether to show the pet; also toggleable in the settings panel (persisted to pet/user-config.json)
spriteFilestringdoraemonsprite.webpSprite sheet file name (relative to the pet/ directory)
spriteobjectsee belowSprite grid and state-mapping config (partial overrides supported, deep-merged with defaults)

sprite config structure:

sprite:
  cols: 8          # grid columns (max frames per row)
  rows: 9          # grid rows (number of animation states)
  fps: 8           # default frame rate (overridable per row via rowFps)
  rowFrames: { 0: 6, 1: 8 }   # optional: per-row frame count (defaults to cols)
  rowFps:    { 8: 12 }        # optional: per-row frame rate (defaults to fps)
  stateRows:                  # dsh state -> grid row number
    idle: 0
    thinking: 8
    working: 1
    waiting: 3
    failed: 5
    completed: 4

Animation layout of the default sprite (doraemonsprite.webp, 9 rows × 8 columns):

Rowdsh stateDefault framesDefault fpsMeaning
0idle66Idle
1working812Running right
2(unmapped)812Running left
3waiting45Waving
4completed58Happy
5failed910Faint / failure
6(unmapped)610Jumping
7(unmapped)79Laughing
8thinking68Thinking

Standalone Window Mode

Besides the embedded overlay, the pet renderer also provides a full-screen transparent page, suitable for running the pet as a standalone "desktop pet" window:

http://127.0.0.1:3080/dsh-pet/
# Chrome app mode (frameless window)
chrome --app="http://127.0.0.1:3080/dsh-pet/" --window-size=256x320

# pywebview + pyinstaller packaged into a single-file .exe (recommended for offline use)
cd dsh-pet/pet
pip install pywebview
python launch.py                       # local preview
pyinstaller --onefile --windowed --add-data "doraemonsprite.webp;." --add-data "pet.html;." launch.py

When dsh is not connected, the standalone page automatically cycles through all state animations (demo mode); press D to switch states manually.

File Structure

dsh-pet/
├── index.js              # Cordis plugin entry (hooks into webServer: overlay injection + same-origin routes + SSE)
├── cordis.patch.yml      # dsh bundle declaration (top-level YAML array)
├── package.json          # npm package and dsh client/bundle config (exports must include ./package.json)
├── LICENSE               # MIT license
├── README.md             # Chinese README
├── README.en.md          # This file (English)
├── lib/
│   └── client.js         # Client bundle: mounts the management panel into dsh's settings.section slot
└── pet/
    ├── doraemonsprite.webp   # Default sprite source (9 rows × 8 columns)
    ├── pet.html              # Full-page pet wrapper (thin wrapper, standalone window mode)
    ├── pet-render.js         # Shared rendering logic (reused by overlay and full page, incl. SSE config hot update)
    ├── overlay.js            # Overlay entry (injected into the 3080 page, sprite only)
    ├── settings-panel.js     # Management panel (vanilla JS, mounted in the settings page)
    ├── launch.py             # pywebview transparent window launcher (optional)
    ├── uploads/              # User-uploaded sprites (runtime-generated, gitignored)
    └── user-config.json      # Persisted config of the management panel (runtime-generated, gitignored)

Development

node --check index.js pet/pet-render.js pet/settings-panel.js pet/overlay.js   # syntax check
dsh --profile web                                                              # takes effect after restart

Host-side changes (index.js) require a dsh restart; the settings-page client entry depends on package.json's dsh.client.inject (real module IDs) and exports["./package.json"] — missing either one causes the client entry to be silently dropped from the boot manifest, leaving no "Desktop Pet" section in the settings page.

Security Notes

  • All data is stored locally only (the pet/ directory and the dsh profile); nothing is ever uploaded
  • The sprite upload endpoint accepts image formats only, with a filename whitelist check to prevent path traversal
  • No keys or credentials are collected; all resources are served on dsh's own service, accessible only locally

🤖 AI Disclosure

This project was developed with DeepSeek Harness.

License

[MIT](LICENSE) © Levi5