dsh-pelican-watch
DSH community plugin: ask any set of models to draw a pelican riding a bicycle on a schedule, then lay every drawing out on a read-only board. No scoring — the pictures are the result. Pausable, with a settable interval.
- Stars
- 0
- Language
- JavaScript
- Created
- Oct 16, 2026
- Updated
- Oct 16, 2026
Introduction
@mi-lu-uncle/dsh-pelican-watch
A DeepSeek Harness community plugin that runs a long-term model-quality probe (降智监测) on a schedule, across any number of models:
- Pick your models — the gear in the panel's top-right corner lists every model the
configured providers report (live
/modelsdiscovery, merged with the models in your DSH profile) and probes a multi-selected set, each model through its own provider and API key. - Scheduled drawing — every 30 minutes (configurable) each selected model is asked to draw a pelican riding a bicycle as a single-file HTML page with an inline SVG.
- No skills, no tools — each run is a bare
chat/completionsrequest with no tool definitions and no agent loop, so the result measures the model alone, never your local skills. - Everything flat, nothing to click — the main board is read-only: one band per model, its status and figures on the left (when its newest drawing landed, runs, average duration, how many came back without a drawing, and the failure reason) and every drawing it ever made on the right, all laid out at once — nothing collapsed, filtered, or hidden behind a click.
- Run state in the header — while probing: “n/m done”, which models are in flight, how long the slowest has waited (m:ss) and the timeout cap (m:ss), so a slow model and a stuck one are told apart at a glance.
- One gear button — the panel's own top-right corner opens a settings sheet: pick models, probe now, open one drawing's original page. The board below stays pure viewing, so nothing has to be clicked to be read.
- Stop it, retune it — that same sheet can pause / resume automatic
probing, change the interval (1–1440 minutes), and stop the pass that is
running right now: requests in flight are aborted, models that had not started
are skipped without a request being sent. Pausing is written to
settings.jsonimmediately and survives a restart, so a plugin you only probe by hand never costs a token on its own. - Bounded history — keeps the newest N drawings (12 by default), pruning older ones automatically. Same prompt, same model, over days: degradation shows up as worse structure, refusals (saved and badged 「未检出 SVG」), or latency growth.
Install
From this GitHub repository (recommended):
dsh plugin --profile desktop add https://github.com/mi-lu-uncle/dsh-pelican-watch.git
Or from a local path or tarball:
dsh plugin --profile desktop add /absolute/path/to/dsh-pelican-watch
Note: link:-installed plugins are not watched by HMR, so editing
lib/index.js or lib/client.js requires an app restart to take effect.
Choosing models
The gear in the panel's top-right corner opens the settings sheet: every provider found in your DSH profiles, with
the models it serves (its own /models endpoint, merged with whatever the
profile already lists). Tick any number of models and Save models — from the next
cycle on each selected model draws its own picture and gets its own band on the
board.
That selection lives in dir/settings.json and is what the scheduler uses;
config.model / config.targets only seed the first run. The same file holds
two knobs that decide what you spend, both changeable from the panel's gear
without touching any config file:
| key | default | meaning |
|---|---|---|
autoEnabled | true | Off disarms the timer at once (nextRunAt goes empty); only the manual “probe now” then spends anything, and the choice survives a restart. |
intervalMinutes | follows config.intervalMinutes (30) | Changing it in the panel re-arms the countdown immediately — no restart. |
config.model / config.targets only seed the very first run. At most 12 | ||
models are probed per cycle — concurrency of them at the same time (3 by | ||
| default), one drawing each. |
Speed and timeouts
- Models run in parallel (3 at a time by default), so one slow model no longer delays the others: every drawing is written to disk the moment it arrives and shows up in the panel within seconds.
- Each request has its own timeout (
timeoutSeconds, default 180). A model that exceeds it is reported as超过 N 秒没有返回on its own band instead of hanging the whole pass. Reasoning models can genuinely be slow — measured against one provider:qwen3.7-max~52s,deepseek-flash~121s (15k of those completion tokens were reasoning), whileglm-5.3-flashsometimes exceeded 4 minutes. - A timeout or HTTP error is not a drawing: nothing is saved and it does not
count as a drawing, because that is an infrastructure fact rather than model
behaviour. A model that answers without an SVG (a refusal) is saved and
marked
没出图— that is the signal worth looking at. maxTokensis not sent by default: reasoning models spend tens of thousands of completion tokens before they draw, and a tight ceiling would truncate the SVG instead of speeding anything up.
Configuration
Defaults match the usual profile setup; override any of them on a
pelican-watch row in your profile patch (cordis.patch.yml):
- id: pelican-watch
config:
model: glm-5.3-flash # seed model (the panel's selection wins)
baseURL: https://taotoken.net/api/v1 # OpenAI-compatible endpoint
apiKeyEnv: TAOTOKEN_API_KEY # env var holding the API key…
# apiKey: sk-… # …or put the key here directly
# targets: # optional: seed several models at once
# - { provider: taotoken, baseURL: https://taotoken.net/api/v1, apiKeyEnv: TAOTOKEN_API_KEY, model: glm-5.3-flash }
intervalMinutes: 30 # drawing cadence
maxImages: 12 # history depth (per model ≈6h at 30min)
timeoutSeconds: 180 # per-request ceiling; raise it for slow models
concurrency: 3 # how many models are probed at once
# maxTokens: 8192 # optional; unset by default (see below)
dir: ~/.dsh/pelican-watch # where drawings are saved
runOnStart: true # draw once ~8s after boot
# temperature: 0.7 # optional; omitted by default
# prompt: … # only if you must change the benchmark
The benchmark prompt is deliberately fixed — changing it makes the history
incomparable, so treat prompt as a last resort.
API key
The key is resolved at call time, in this order:
- a literal
apiKeyin config; process.env[apiKeyEnv](defaultTAOTOKEN_API_KEY);- the same name in DSH's own credential store —
refs:in~/.dsh/.credentials.yaml(override the path withcredentialsFile).
Step 3 is why a DSH-configured provider key works with no extra setup: the
desktop app is launched from Finder/Dock and therefore does not inherit
environment variables exported in a shell, while refs: already holds the key
under the provider's apiKeyEnv name.
With none of the three the run is skipped and the panel shows the reason
(缺少 API Key:…) — set any one of them and the next scheduled run proceeds.
Display only — no scoring
This plugin does not score anything. It does two things: it asks every model the same drawing prompt on a schedule, and it lays the drawings out as they are.
Earlier versions computed a 0-100 "structural score" offline (is there an SVG, two wheels, a frame, wings…). That has been removed on request: such a number can only approximate “did these elements appear”, and it lends a false precision. The judgement is left to whoever looks at the pictures (or to a vision model): same prompt, same model, over consecutive days — the drawings themselves are the finding, and no digit has to stand in for them.
The numbers that remain on the board are not grades, just facts: how many runs,
average duration, when the newest drawing landed, and how many runs came back
without a drawing. 没有出图 means the request returned but carried no usable
SVG (typically a refusal); the raw answer is still saved so you can read it.
Storage
Drawings live in dir (default ~/.dsh/pelican-watch):
| File | Role |
|---|---|
<时间>_<模型>.html | The full generated page; first line is a meta comment (model, provider, time, duration, whether an SVG was detected) |
<时间>_<模型>.svg | The extracted inline SVG, used for the panel's <img> preview |
settings.json | The selected probe targets (written by the picker) plus the two pace knobs autoEnabled / intervalMinutes |
Deleting files there is safe; the panel always lists what is on disk.
Privacy & safety
- Every route is same-origin fenced like other plugin surfaces.
- Generated pages are served as
text/plainand rendered inside asandbox-less iframe (sandbox=""), so model output can never execute scripts in the app origin; SVG previews are served withx-content-type-options: nosniff.
Layout
| File | Role |
|---|---|
lib/index.js | Host half: multi-model scheduler, storage, scoring, /api/pelican-watch/* routes |
lib/client.js | Client half: the flat board (one band per model with all its drawings) plus the gear-opened settings sheet (React) |
cordis.patch.yml | Bundle patch that mounts the package as one host row |
package.json | npm metadata + dsh.bundle/dsh.client/dsh.compatibility |
test/pelican.test.mjs | Offline test: per-model roll-up, provider parsing, target selection, schedule control, route wiring |
Test
node test/pelican.test.mjs