dsh-codex-compatible-pet
English | 中文
Desktop pet plugin: a codex-compatible animated pet that lives at the bottom-right of the Web GUI and follows the agent state. It is a dual-face client plugin — the node half serves pet files over HTTP, the browser half renders the sprite and the settings page.
Pet model (codex compatibility)
The pet model is ported from codex-rs (tui/src/pets/model.rs), so existing codex pets work unchanged:
- Manifest —
pet.json (legacy avatar.json also accepted) with id, displayName, description, spritesheetPath (default spritesheet.webp), frame (default 192×208, 8 columns × 9 rows), and animations (frames sprite indices, fps default 8, loop default true, fallback default idle). spriteVersionNumber: 2 (the Codex app sheet format) widens the default grid to 11 rows; other unknown fields such as kind are ignored exactly like the codex parser ignores them.
- Animation math — row-major sprite grids; pets on the default frame spec without custom tracks (built-ins, and standard 8×9 or version-2 8×11 sheets) play the full codex state table (
running, waiting, review, failed, …), while custom grids or custom tracks keep the codex idle-only rule — the Codex app behavior, which keeps standard sheets animating instead of motionless. Loop tracks use the prefix-then-loop timing, one-shot tracks fall back to idle after their duration, and a missing state track falls back to idle — all identical to codex ambient playback.
Pet sources
- Built-in pets — the codex catalog (Codex, Dewey, Fireball, Rocky, Seedy, Stacky, BSOD, Null Signal) proxied from the public Codex pets CDN through the host with a validating
$DSH_HOME/cache/dsh-pets cache.
- Local pets —
$DSH_HOME/pets/<id>/ (writable; the import target).
- Codex-home pets —
~/.codex/pets/<id>/ and legacy ~/.codex/avatars/<id>/ (CODEX_HOME respected), scanned read-only so pets installed for Codex appear automatically.
Host half (routes under /dsh-pet)
GET /dsh-pet/list — built-in catalog plus directory pets (broken manifests stay listed as disabled rows).
GET /dsh-pet/manifest/<source>/<id> — a pet's raw manifest JSON.
GET /dsh-pet/asset/<source>/<id>/<name> — a pet's spritesheet; the name must be the manifest's own spritesheetPath and stays inside the pet directory.
GET /dsh-pet/builtin/<file> — CDN proxy over a filename whitelist with a 4 MB cap and WebP validation.
POST /dsh-pet/import — imports a browser-picked .codex-pet directory (manifest plus base64 spritesheet); the frame grid must cover the WebP canvas exactly (the codex validation), and the write is staged then renamed.
Every route sits behind a browser trust fence (loopback plus configured trustedHosts), the same shape as the /api fence. Ids and asset names are pattern-restricted, so path traversal is rejected at the route layer.
Browser half
- Ambient overlay —
shell.overlay entry pet: the sprite plays running while the current session runs, waiting when an interaction (approval, question, plan review) blocks it, review for a few seconds after a running→idle edge, and idle otherwise, with a status bubble (思考中 / 等待确认 / 已完成). Clicking the pet plays the first available interaction track (wave, bounce, jumping, waving); dragging it with the mouse moves it anywhere and plays the direction-matched run animation (running-right/running-left, falling back through running to the status track) — a 4 px threshold separates drags from clicks, and the position persists in the store. Reduced-motion users see a static first frame.
- Hover detail card — hovering the pet shows what the agent is doing right now, codex-style and truncated: the latest user prompt as a larger bold title, the running tool call (
tool name plus a compact args head), the head of the latest assistant output (streaming text preferred), and the pending interaction kind. Long text keeps its head and ends with a trailing ellipsis. The facts derive from the object layer — the sessions list plus the current session binding — as one bare observable delivered through the inject hooks compartment, so no component carries subscription machinery.
- Settings page —
settings.section entry pet: catalog browsing with static previews, size options (小/中/大 = 94/117/150 px target sprite heights), .codex-pet directory import, and the disable control.
- Persistence — the selection, size, and drag offset live in the framework store engine under
dsh.pet (localStorage).
Install
This package is a dsh bundle: its dsh.bundle manifest inserts the ui-pet row into any profile that lists the package, and its dsh.client manifest plus lib/client.js carry the browser half for the Web GUI.
The easiest install is to let an agent do it — DeepSeek Harness itself, or any agent with terminal access to a machine that has the dsh CLI and can reach this repository. Paste this prompt:
Install the dsh-codex-compatible-pet plugin from https://github.com/youzhoujiMrLiu/dsh-codex-compatible-pet for me.
1. Run `dsh plugin add github:youzhoujiMrLiu/dsh-codex-compatible-pet` (add `--profile <name>` to target a specific profile).
2. pnpm ≥10 refuses git-dependency build scripts on the first attempt: copy the package key it prints into the profile's `pnpm-workspace.yaml` `allowBuilds` block and re-run the add.
3. Verify the row `ui-pet` shows up in the profile composition (`dsh --profile <name> --dump-config`) or on the Web GUI's Plugins page.
4. In the Web GUI, refresh the page — the pet appears at the bottom-right and a Pet page appears under Settings. After any server restart, refresh again.
Trust note: a git install runs this package's `prepare` build on the installing machine; pin a commit (`github:youzhoujiMrLiu/dsh-codex-compatible-pet#<sha>`) if you want a fixed revision.
Under the hood the agent runs the ordinary git-install path: prepare builds lib/ from src/ after the install and is self-contained — it assumes no monorepo checkout.
Model Experience
None, as the plugin changes browser presentation only and registers no prompt, tool, schema, session event, or provider request.
KV Cache effect
None; this package neither assembles nor sends a provider request.
Known Limitations and Deferred Work
- Status source is the session list — the pet derives its status from the standard
useSessions feed (running bit, pending interaction, and the running→idle edge), so a per-turn error has no dedicated failed animation yet; failed turns fall back to the review reminder and idle. The detail card's activity text does come from the current session's conversation window.
- Built-ins need the first download — a built-in pet fetches its spritesheet from the Codex CDN on first selection and shows nothing until that download completes.
- Import is the only write path — dropping a
.codex-pet folder into $DSH_HOME/pets/<id>/ by hand also works, but there is no in-app re-scan button beyond reopening the settings page.
- Uninstall is composition-level —
dsh plugin --profile <name> remove dsh-codex-compatible-pet removes both the dependency and the inserted layer; there is no runtime toggle. A row inserted by a user-installed bundle does not yet appear under the Custom plugins tab (that classification currently recognizes user patch layers only).