Just for Fun

dsh-wildmon

swaylq/dsh-wildmon · ★ 2

swaylqCurated

Pokemon-style catch-em-all: your real work is the tall grass — turns, tool calls and errors spawn wild encounters; throw balls, fill a 28-slot dex, walk a team of six. Zero tokens, invisible to the model.

License
MIT
Added
2026-08-16
Maintenance
active
Install kind
github
Manifest details
Manifest status
Declared
Manifest path
package.json#dsh
Manifest checked
2026-08-19
Lifecycle scripts
None found

Static manifest checks report declarations only; they are not compatibility or security review.

安装

dsh plugin --profile web add github:swaylq/dsh-wildmon

GitHub 源码安装:首次需按提示配置 allowBuilds 构建授权后重试

For install and environment setup, plus plugin development tutorials, see DSH community docs ↗

README

Source README · body: en · Read Chinese README

Table of contents
  1. dsh-wildmon
  2. 30 seconds to the grass
  3. Habitats: how you work decides who you meet
  4. Why this exists
  5. Commands
  6. How it works
  7. Trust stance
  8. Known limits
  9. Verification record
  10. Homage and boundaries
  11. License

dsh-wildmon

Your real work is the tall grass — turns, tools and errors rustle it; wild critters pop out, you throw balls, you fill the dex.

Write code and the forge stirs; read docs and shadows cross the archive; ship errors daily — congratulations, the rare species of Glitch Ridge only trust your kind. And one legendary answers nothing but a deep-night error.

license dsh-plugin deps tokens tests

中文 | English

野生的 绒电鼠 Volttuft 出现了!◈ 少见 · 常野原
(A wild Volttuft appeared! Uncommon · Field)

  ⟋⟍  ⟋⟍
  (⚡ᴥ⚡)
  c(   )ɔ
    ⌁⌁

球 ×9 —— /mon throw to throw · /mon run to retreat

The catch ceremony

30 seconds to the grass

dsh plugin --profile web add github:swaylq/dsh-wildmon
# restart dsh, then in any session:
/mon start

Pick one of three starter-trio critters, take 8 balls, then just work. Every turn, message, tool call and error has a chance to rustle the grass; the longer nothing shows, the higher the odds (a pity mechanic). /mon to check — a wild one waits 10 minutes; /mon throw to catch, and rarer species are harder, every miss improves your next throw, but it may also bolt.

Fill the 28-slot dex, walk with a team of six: your first six catches auto-join, slot 1's aura raises its home habitat's encounter rate ×1.5, rearrange with /mon swap. Shinies exist, at 1/64.

Habitats: how you work decides who you meet

Habitat What rustles it Residents
🌾 Field (常野原) messages, turns, unclassifiable tools Fluffgrub, Dotfinch, Volttuft…
⚒️ Forge (锻造窟) writing files, running commands Malletclaw, Cogbadger, Coredrake…
📚 Archive (墨书林) reading code, searching docs Markmoth, Indexowl, Tomewyrm…
👾 Glitch ridge (故障岭) failed tools, agent errors Shardtoad, Tracepede, Panicray…
🌙 Night bound (夜阈) anything between 00:00–05:59 Lunasmudge, Dozetapir, Stardrift

Plus the starter trio (the two you didn't pick roam the field) and three legendaries: one surfaces every 250 turns; one only answers a deep-night error; the last only visits collectors who completed the first 25 slots. The dex offers only rumors about them.

Ball economy: 8 to start, +1 per finished turn (cap 30), and catching a species you already own trades the catch back for 2 balls — duplicate encounters are never a loss.

A wild encounter The dex

Why this exists

The DSH pet lane is busy: twenty-plus desk pets are state mirrors (agent thinks, pet does a thinking animation), and dsh-digipet added raising (one pet eats your work and evolves).

Collecting was still an empty slot: no encounters, no catching, no "looking forward to the next error because the dex wants it." As of 2026-08, searching the dsh-plugin topic (2,800+ repos) and all four curated awesome lists for pokemon / pokedex / catching / gacha returns zero hits. dsh-wildmon fills that slot — the complete collect-em-all loop (encounter → catch → dex → team) mounted on your actual workflow.

It complements digipet rather than replacing it: digipet is depth with one creature, wildmon is breadth across many. Both install side by side (different command, different save file). If /mon collides with another plugin, override config.command in your profile patch.

Commands

Command Does
/mon Check the grass: encounter card (art, rarity, time left) or quiet status
/mon start Begin the journey (bare form lists the three candidates)
/mon throw Throw one ball at the live encounter
/mon run Back out of the standoff
/mon dex Collection: caught ● / seen ◐ / unknown ○; legendaries show only rumors
/mon team Party and box (its numbering feeds swap / name)
/mon swap <a> <b> Reorder the party or exchange with the box (slot 1 leads)
/mon name <n> <name> Nickname a caught partner (16 chars)
/mon story The journey log
/mon about Mechanics and the trust stance

How it works

The whole plugin is four event taps and one slash command; the taps only roll dice:

Tap Base encounter rate
agent/turn-stopping (also refills 1 ball) 9%
agent/inbox/claimed (your messages) 5%
tools/result (routed by tool name to forge/archive/field; failures → glitch) 6% / 16% on failure
agent/error 20%

On top: +0.8% per quiet event (capped at +25%), lead's home habitat ×1.5, and at night a 70% roll swaps in the night pool. Catch odds = rarity base (65% / 45% / 28% / 12%) + 12% per prior miss, capped at 95%; after a miss the wild one may flee at a rarity-scaled rate. Every number lives as a named constant at the top of core.js.

The save lives at $DSH_HOME/wildmon/state.json, written the way the official JSON storage backend writes: temp file + fsync + atomic rename, throttled to one write per 1.5 s no matter how busy the agent is.

The invariant that matters: model-visible means logged — and this plugin simply shows the model nothing. No tool registration (tool schemas are a per-request token tax), no agent.inject(), no session events. The whole game lives in command result cards and contributes zero bytes to every model request.

Trust stance

  • Reads: only its own save file. Never your code, never conversation content — the listeners use only what kind of thing happened; message and tool payloads never touch the save.
  • Writes: only $DSH_HOME/wildmon/state.json.
  • Network: none.
  • Model-visible surface: none. Zero token cost; KV cache untouched.
  • Randomness: affects the game only. The listeners never veto, rewrite or delay real work (all hooks are notification-mode events).
  • Blast radius: every listener is wrapped in try/catch and the command handler has its own catch — a collapsing grassland cannot land on your work.

Known limits

  • One dex per DSH home; all profiles, sessions and subagents on the machine share (and rustle) the same grass — feature and limit at once.
  • Concurrent dsh processes: last writer wins, same single-process stance as the official JSON backend.
  • Encounters don't notify you (the price of a zero model-visible surface) — you check with /mon; the wild ones wait 10 minutes and misses land in the story log.
  • Tool routing is a name-regex heuristic; oddly named third-party tools count as field.
  • The night window is machine-local 00:00–05:59; travel across time zones and the nocturnals jet-lag with you.
  • Rates and thresholds are not configurable: changed numbers would leave the dex and the save with no common language.

Verification record

Verified for real on dsh 0.1.0-rc.6 (macOS, web profile):

  1. Installed with dsh plugin --profile web add <this repo>; the wildmon layer shows in --dump-config;
  2. dsh web boots clean;
  3. In a real browser, /mon start picks a partner and the send-off card renders (monospace, newlines kept);
  4. Six plain messages without an API key — every model request fails, but inbox/claimed and agent/error are real events: the save recorded messages:6, mishaps:6, and with pity at 10 the 6th round really spawned a Shardtoad (error event → glitch ridge, matching the table);
  5. /mon throw missed once (the card showed the throw-bonus note), caught on the second — party 2/6, dex 2/28, balls ×6 = 8 − 2 throws; the save reconciles line by line with the observed events;
  6. Observed caveat: on rc.6, MISSING_CREDENTIAL failure rounds do not fire agent/turn-stopping, so the per-turn ball refill wasn't observable on a keyless machine (it needs turns that complete); that path is covered by unit tests;
  7. 61 unit/integration tests (node --test) covering pure logic, rendering, the store and a fake-ctx integration.

Homage and boundaries

The design pays homage to the collect-em-all genre's traditions (grass encounters, the three-shake catch, a dex, a starter trio, an electric rodent, shinies). Pokémon is a trademark of Nintendo / Creatures / Game Freak; this project is not affiliated with them in any way. All 28 species names, ASCII art and text are original; no official names, characters or assets appear. The ball is just a ball that wobbles — that belongs to everyone who loves collecting things.

License

MIT