Skip to content
dsh.fish
Bundle

dsh-codex-compatible-pet

Codex-compatible desktop pet for the DeepSeek Harness web GUI: animated pets that follow the agent state

Source
youzhoujiMrLiu
stars
1 stars
License
MIT
Updated
Updated 5 days ago

Readme

# dsh-codex-compatible-pet

English | [中文](README.zh.md)

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:

```text
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).

Install

dsh plugin --profile web add github:youzhoujiMrLiu/dsh-codex-compatible-pet

Profile: web

  • This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.
  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source