Skip to content
dsh.fish
Bundle

dsh-achievements

DeepSeek Harness achievement & gamification plugin: cross-session badges for turns, tool calls, sessions and daily streaks, with a badge panel, unlock toasts and a ctx.achievements service. Zero core changes.

Source
Blaczz
stars
3 stars
License
MIT
Updated
Updated 4 days ago

Readme

# dsh-achievements ๐Ÿ†[![Awesome DSH Plugin](https://awesome-dsh-plugin.com/badge.svg)](https://awesome-dsh-plugin.com)

> A gamification layer for **DeepSeek Harness (DSH)**: 68 achievements across seven five-tier growth lines, session behavior badges and trajectory chains โ€” with real-time unlock toasts, a badge wall in the settings page, shareable cards, Agent Wrapped and a public SDK for third-party packs. **Zero core changes.**

[็ฎ€ไฝ“ไธญๆ–‡](./README.zh.md)

## ๐Ÿ“ธ Screenshots

| Achievements panel: profile card, rarity stats, lifetime counters and the grouped badge wall | Expanded cards: icon, rarity, description, progress, XP and unlock timestamp |
|---|---|
| ![Achievements panel](docs/screenshots/badge-panel.png) | ![Achievement cards](docs/screenshots/badge-cards.png) |

## โœจ Highlights

- **68 achievements in three product lines** โ€” seven **five-tier lifetime growth lines** (rarity strictly `common โ†’ uncommon โ†’ rare โ†’ epic โ†’ legendary`), 10 **session behavior badges**, and 20 **session trajectory achievements** across four extra chains (one of them fully hidden). Every unlock earns XP, raises your level and persona, and is timestamped on the badge wall.
- **Real-time unlocks, no extra server** โ€” new achievements stream to the browser over **SSE**, with a 30s polling fallback (plus refresh on focus/visibility). A first-snapshot baseline means reinstalls and upgrades never produce a toast storm.
- **Zero core changes** โ€” the Host half listens only to the official `session/event` seam: `turn/end`, `step/start`, `assistant/message`, `step/end`, `tool/call`, `tool/result`, and Code Mode's `tool/code-dispatch`. All read-only events; no core patches, no forks of the runtime.
- **Pure, unit-testable core** โ€” a strict three-layer pipeline: event **classifier** โ†’ state **reducer** โ†’ unlock **evaluate**. Each layer is a pure function with its own tests: **19 test files, 251 tests**, all green.
- **State that survives and upgrades cleanly** โ€” v2 state (`profile` + per-session buckets) persists as a JSON file in the DSH home directory; v1 states migrate losslessly. Lifetime counters live on the profile and never depend on the 64-session retention window, with a conservative lower-bound backfill on upgrade; already-satisfied milestones are silently reconciled at startup (no reducer, no session attribution, no broadcast).
- **O(1) trajectory tracking** โ€” P7 session facts are maintained at low-frequency boundaries only (`step/start`, `assistant/message`, `step/end`, settled tool calls); per-token chunks are never consumed or persisted.
- **Privacy-safe by construction** โ€” share text, share cards, Agent Wrapped and achievement chains read aggregate counters, achievement metadata, persona and level only. File paths and command strings never leave the engine.
- **Open SDK** โ€” third-party Host plugins register achievements via `ctx.achievements.register` / `registerPack` and share the exact same evaluation path as the built-ins; duplicate ids throw immediately. Other client plugins read state through `ctx.achievementsState`.

## ๐Ÿ… The achievements (68)

Achievements fall into two tracks. Each of the **seven lifetime growth lines** has five tiers, always `common โ†’ uncommon โ†’ rare โ†’ epic โ†’ legendary` (new-milestone XP: 10 / 30 / 75 / 175 / 400):

| Line | Common | Uncommon | Rare | Epic | Legendary |
|---|---|---:|---:|---:|---:|---:|
| ๐ŸŽฌ Turns | 1 | 25 | 50 | 100 | 500 |
| ๐Ÿ”ง Tool calls | 1 | 25 | 100 | 500 | 2000 |
| ๐Ÿ’ฌ Sessions | 1 | 10 | 50 | 200 | 500 |
| ๐ŸŒ… Active days | 1 | 7 | 30 | 100 | 365 |
| ๐Ÿ“– File reads | 10 | 100 | 500 | 2500 | 10000 |
| โœ๏ธ File edits | 1 | 10 | 50 | 250 | 1000 |
| ๐Ÿงช Test runs | 1 | 10 | 50 | 250 | 1000 |

**Special achievements** โ€” daily streaks (`streak-3` / `streak-7`), the early `ten-turns` bonus, and ten per-session behavior badges:

| Achievement | Condition |
|---|---|
| ๐Ÿ” Dรฉjร  Vu | edit the same file 5 times in one session |
| ๐Ÿ•ณ Rabbit Hole | read 20 files before your first edit |
| ๐Ÿ’ฃ YOLO | edit 8 files before your first test |
| ๐Ÿ”ฅ It Works Eventually | pass after 5 failed tests |
| ๐ŸŽฐ Surely This Time | same test command fails 5 times in a row |
| ๐ŸŽฏ One Shot | pass the first test after a single edit |
| ๐Ÿ“š Librarian | read 30 distinct files in one session |
| ๐ŸŒฑ Touch Grass | 100 tool calls in one session |
| ๐Ÿฆด Dependency Archaeologist | read a file inside a dependency directory |
| ๐Ÿ—ฟ Gigachad | read, edit and pass a test within 5 tool calls |

**P7 trajectory chains** (20 achievements, rarity strictly `common โ†’ uncommon โ†’ rare โ†’ epic โ†’ legendary`, XP 10 / 20 / 40 / 70 / 120). They read only low-frequency boundaries and never persist per-token chunks:

| Chain | Metric | Five thresholds |
|---|---|---|
| ๐Ÿ’ฌ Session Marathon | distinct closed-step turns in one session | 5 / 20 / 50 / 100 / 200 |
| ๐Ÿชœ Turn Depth | closed steps within a single turn | 5 / 20 / 50 / 100 / 500 |
| ๐Ÿ”ง Tool Barrage | settled tool calls within a single step (incl. Code Mode sub-calls) | 5 / 10 / 25 / 50 / 100 |
| โณ Time Anomaly | single model-request think duration (`step/start โ†’ assistant/message`, hidden) | 30s / 100s / 300s / 500s / 1000s |

## โš™๏ธ Architecture

```
DSH session/event (turn/end, step/start, assistant/message, step/end, tool/call, tool/result, tool/code-dispatch)
  โ†’ src/events.ts        classifier  โ€” raw payload โ†’ standardized AchievementEvent + ToolSummary
  โ†’ src/reducer.ts       reducer     โ€” pure reduceState: profile counters + per-session behavior + P7 facts
  โ†’ src/achievements.ts  evaluate    โ€” applyEvent: buildContext + evaluate every still-locked def
  โ†’ src/index.ts         Host        โ€” persist JSON โ†’ SSE push (unlock) + read-only HTTP API; startup reconcile
  โ†’ src/client/          Browser     โ€” EventSource + 30s polling โ†’ badge panel + unlock toasts
```

The three layers are fully decoupled and independently unit-tested; the rules layer never reads raw Harness tool payloads. The browser bundle can only import modules that are safe for it (a purity gate in `tsdown.config.ts` blocks any `node:*` import from leaking in).

## ๐Ÿ“ฆ Install

Prereqs: DSH (`dsh web` works), Node โ‰ฅ 22.19.

```bash
# From GitHub (prebuilt lib/ is committed, no allowBuilds needed)
dsh plugin --profile web add "github:luumod/dsh-achievements#main"

# From a local checkout (npm pack is the reliable path on Windows; avoid `link:`)
cd dsh-achievements && npm install --legacy-peer-deps && npm run build
npm pack --ignore-scripts
dsh plugin --profile web add "<absolute path to>\dsh-achievements-0.1.0.tgz"
```

**Restart `dsh web` after installing**, then just use it โ€” the first completed turn unlocks the first achievement (all counting rides the official event seam, so simply chatting works).

## ๐ŸŽฎ Usage

1. Chat and let the agent work โ€” turns, tool calls, new sessions and daily activity accumulate silently; a toast pops in the bottom-right whenever a new achievement unlocks (rarity color, XP and flavor text included).
2. **Settings โ†’ ๐Ÿ† ๆˆๅฐฑ** shows the full experience:
   - **Profile card** โ€” persona, level with XP progress, unlocked/total count, favorite tool and a rarity breakdown;
   - **Lifetime counters** โ€” turns / tool calls / sessions / active days / file reads / file edits / test runs, plus the current and longest streak;
   - **Badge wall** โ€” collapsed into the seven growth routes and the special/trajectory chains, each group header showing its progress bar; a single *all / locked / unlocked* filter narrows the cards; unlocked cards carry timestamps, locked ones are dimmed, hidden achievements stay `???` until unlocked;
   - **Session report** โ€” the most recent session's turns, steps, deepest single turn, tool calls and read/edit/test split;
   - **๐ŸŽ Agent Wrapped** and **๐Ÿ“ค Share** โ€” local, private summary and shareable cards.

## ๐Ÿ”Œ For developers: the `ctx.achievements` SDK

Register your own achievements from a Host plugin โ€” built-ins and third-party packs share one evaluation path and one registry (duplicate ids throw):

```ts
export const inject = ['achievements']

export function apply(ctx: Context): void {
  ctx.achievements.register({
    id: 'python-first-run',
    icon: '๐Ÿ',
    title: { zh: '่Ÿ’่›‡ๅ‡บๆดž', en: 'First Python Run' },
    description: { zh: '้ฆ–ๆฌก่ฟ่กŒ Python', en: 'Run Python for the first time' },
    rarity: 'uncommon',
    xp: 20,
    scope: 'session',
    evaluate: ctx => ({ unlocked: ctx.session.toolCalls >= 1 }),
  })
}
```

Or register a whole pack: `ctx.achievements.registerPack({ id, version, name, achievements })`. Registrations reconcile immediately, so an already-satisfied lifetime pack unlocks without waiting for the next live event. See `docs/SDK.md` for the full guide and `examples/python-pack.ts` for a runnable pack.

On the browser side, other client plugins read state via `ctx.achievementsState.refresh()` / `ctx.achievementsState.unlockedIds()`.

## ๐Ÿ› ๏ธ Development

```bash
npm install --legacy-peer-deps
$env:DSH_NODE_MODULES = "$env:USERPROFILE\.dsh\profiles\node_modules"   # PowerShell; local runtime symlinks
npm run setup:dsh-workspace
npm run verify     # โ˜… one-shot gate: clean + typecheck + test + build (incl. the browser purity gate)
npm test           # vitest โ€” 19 files / 251 tests (engine rules, streaks, idempotency, SDK, manifestโ€ฆ)
```

> Note: if `npm run build` fails with `Failed to import module "unrun"`, run `npm install --no-save unrun` once (tsdown optional peer, Node โ‰ฅ 22.19 recommended).

## ๐Ÿ“ Layout

```
dsh-achievements/
โ”œโ”€โ”€ package.json            # dual contract: dsh.bundle.patch + dsh.client
โ”œโ”€โ”€ cordis.patch.yml        # bundle patch layer
โ”œโ”€โ”€ tsdown.config.ts        # client bundle + browser purity gate
โ”œโ”€โ”€ scripts/                # build / clean / setup-dsh-workspace / verify
โ”œโ”€โ”€ docs/SDK.md             # third-party authoring guide
โ”œโ”€โ”€ examples/python-pack.ts # runnable sample pack
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ index.ts            # Host half: event wiring, registry, persistence, HTTP + SSE, SDK
โ”‚   โ”œโ”€โ”€ events.ts           # โ˜… event classifier (standard AchievementEvent + ToolSummary)
โ”‚   โ”œโ”€โ”€ reducer.ts          # โ˜… pure reducer (reduceState / buildContext)
โ”‚   โ”œโ”€โ”€ achievements.ts     # โ˜… pure engine (applyEvent) + domain model + 68 built-ins
โ”‚   โ”œโ”€โ”€ state.ts            # State v2 (profile + sessions), migration, JSON persistence
โ”‚   โ”œโ”€โ”€ sdk.ts              # createAchievementRegistry + AchievementPack
โ”‚   โ”œโ”€โ”€ gamification.ts     # levelOf / xpForLevel / RARITY_META (browser-safe)
โ”‚   โ”œโ”€โ”€ profile.ts          # Profile ViewModel + persona + rarity summary (browser-safe)
โ”‚   โ”œโ”€โ”€ share.ts            # share cards / Agent Wrapped / chains (browser-safe, privacy-safe)
โ”‚   โ”œโ”€โ”€ api.ts              # API path constants + SSE frame format (browser-safe)
โ”‚   โ””โ”€โ”€ client/             # Browser half
โ”‚       โ”œโ”€โ”€ index.ts        # apply: ctx.achievementsState + polling + SSE + slot injection
โ”‚       โ”œโ”€โ”€ achievements-client.ts  # state HTTP client
โ”‚       โ”œโ”€โ”€ badge-panel.tsx # badge wall (settings.section), grouped from the chain model
โ”‚       โ”œโ”€โ”€ toast.ts        # unlock toast (zero-dependency DOM)
โ”‚       โ””โ”€โ”€ unlock-tracker.ts  # toast baseline dedup (pure)
โ””โ”€โ”€ tests/                  # 19 spec files: classifier / reducer / evaluate / state / SDK / chainsโ€ฆ
```

## ๐Ÿงฉ Ecosystem positioning

- **Fills a gap** โ€” the DSH ecosystem previously had no unified achievement/badge system (community research explicitly flagged the missing gamification layer).
- **Same dual-sided pattern as `dsh-soundscape`** โ€” Host drives a pure engine off the official event seams; the browser half is a client plugin (`settings.section` + state polling).
- **Zero core changes** โ€” read-only events + a private state file + `ctx.effect` registrations. A fork of [Blaczz/dsh-achievements](https://github.com/Blaczz/dsh-achievements), extended with behavior + trajectory achievements, the SDK and the sharing layer.

## โš–๏ธ License

MIT ยฉ 2026 Blaczz (upstream). An independent community plugin, not affiliated with [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness).

Install

dsh plugin --profile web add github:Blaczz/dsh-achievements

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