Bundle
silverhand-dsh-pet
Silverhand desktop pet for the DeepSeek Harness Web GUI — drag to move, walks in the drag direction, reacts to agent state.
- Source
- Qiao-NEYC
- stars
- 1 stars
- License
- MIT
- Updated
- Updated 14 days ago
Readme
# Silverhand — DSH Desktop Pet
[](LICENSE)


<div align="center">
<img src="docs/demo.gif" alt="Silverhand desktop pet demo" width="384">
</div>
A desktop pet for the **DeepSeek Harness** Web GUI. Silverhand (a cyberpunk
mercenary with a silver cybernetic arm) lives in the bottom-right corner and
reacts to what the agent is doing — idle breathing, active work, reviewing
output, waving hello, celebrating a finished turn, sulking on an error, and
waiting for your approval.
The character artwork is migrated **as-is** from the Codex pet format — no
redesign, just the original `spritesheet.webp` + `pet.json`.
## Features
- Renders in the frame-wide `shell.overlay` layer, fixed to the bottom-right.
- Click-through by default (only the pet itself is interactive).
- Reacts to real agent state, driven by DSH host events:
- `idle` / `running` from `agent/status`
- `review` from `tools/result`
- `failed` from `agent/error`
- `waving` from `agent/created` / `agent/session-start`
- `jumping` when a turn finishes (`running` → `idle`)
- `waiting` while an approval request is open (`approval/request`)
- Drag the pet to move it — it walks left/right in the drag direction.
- Hover to see the current state; click (no movement) to make it jump.
## Install
This is a standard DSH plugin package. Two ways to install:
### From GitHub (recommended)
1. Add it to your profile's `dependencies` and `dsh.profile.bundles`
(in `~/.dsh/profiles/<profile>/package.json`):
```json
{
"dependencies": {
"silverhand-dsh-pet": "github:Qiao-NEYC/silverhand-dsh-pet"
},
"dsh": {
"profile": {
"bundles": [
"...your existing bundles...",
"silverhand-dsh-pet"
]
}
}
}
```
2. Run `pnpm install` in the profile directory (or let the DSH desktop app
install on launch).
3. Restart DSH. The pet appears in the bottom-right.
### From npm
Once published: `npm i silverhand-dsh-pet`, then add `"silverhand-dsh-pet"` to
`dsh.profile.bundles`.
## Layout
```
Silverhand/
├── README.md
├── LICENSE
├── .gitignore
├── package.json # DSH plugin manifest (dsh.client, exports)
├── lib/
│ ├── index.js # host half: reads the sprite, serves HTTP routes + state
│ └── client.js # client half: renders the pet, polls state
├── assets/
│ ├── pet.json # migrated Codex manifest
│ └── spritesheet.webp # migrated sprite atlas (8×9, 192×208 cells)
├── scripts/
│ ├── make_demo_gif.py # render docs/demo.gif (animated demo)
│ ├── analyze_frames.py # measure per-row frame counts / diffs
│ └── contact_sheet.py # render a labeled contact sheet
└── docs/
├── demo.gif # animated demo (all animations)
└── sprite-atlas.md # atlas layout + state mapping
```
## Anatomy
A DSH plugin is a Cordis plugin split into two halves:
- **Host** (`lib/index.js`) runs in the DSH Node process. It reads the sprite
from its own `assets/` (via `import.meta.url`, so it works no matter where
the package is installed) and registers two HTTP routes:
- `GET /silverhand-pet/spritesheet.webp` — the sprite atlas.
- `GET /silverhand-pet/state` — `{ "state": "..." }` derived from agent events.
- **Client** (`lib/client.js`) runs in the browser. It registers into
`shell.overlay`, polls `/silverhand-pet/state` every 300 ms, and animates the
matching atlas row from `/silverhand-pet/spritesheet.webp`.
The two halves communicate over plain same-origin HTTP routes.
## Configuration
All tunables are constants at the top of each half:
- `lib/index.js` — `ROUTE_SPRITE` / `ROUTE_STATE`, and the per-state transient
durations in the event listeners.
- `lib/client.js` — `ANIMS` (row / frame count / cadence per animation),
`STATE_ANIM` (state → animation), `PET_W` / `PET_H` (display size), and the
`CSS` block (position, shadow, hover).
## Troubleshooting blank or missing pet artwork
- Use package version `1.0.1` or newer. The client bundle now declares the
layout dependency explicitly, so `shell.overlay` is available before the pet
registers.
- The client probes `/silverhand-pet/spritesheet.webp` and logs a route error in
the browser console if the Host half is not serving the atlas. A `404` or
`500` means the host package is not active; reinstall the bundle and restart
DSH.
- Animation frames are reset whenever the state changes. This prevents a stale
frame index from selecting an empty atlas cell when switching back to the
six-frame `idle` or `waiting` rows.
- If the pet container exists but is transparent, inspect the browser Network
panel for the sprite route and confirm its response is `image/webp` with a
payload around 1 MB.
## Asset provenance
The artwork was migrated from the local Codex pet directory
(`~/.codex/pets/silverhand/`). It is **your asset** — before publishing this
repo to GitHub, confirm you hold (or have) the right to redistribute the
`sprite` and the Silverhand likeness. The code in this repository is MIT
licensed; the sprite's licensing is yours to state.
## Development helpers
```bash
# Regenerate docs/demo.gif
python scripts/make_demo_gif.py
# Report per-row opaque-cell counts and consecutive-frame deltas
python scripts/analyze_frames.py
# Render a labeled contact sheet (full + zoomed ambiguous rows)
python scripts/contact_sheet.py
```
`analyze_frames.py` / `contact_sheet.py` require Python 3 with `Pillow` and
`numpy`.
Install
dsh plugin --profile web add github:Qiao-NEYC/silverhand-dsh-pet
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install silverhand-dsh-pet from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.