DeepSeek Harness Plugin

Freakz2z/dsh-catgirl-plugin

Stars ★ 4 Downloads (30d) 1,079 Category Identity & Communication Added 2026-08-21 npm dsh-catgirl-plugin

Token-efficient persona runtime for DeepSeek Harness with local catgirl rendering and progressive tool-schema disclosure.

Install

# from npm (prebuilt)

dsh plugin --profile web add dsh-catgirl-plugin

# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)

dsh plugin --profile web add github:Freakz2z/dsh-catgirl-plugin

Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).

README

dsh-catgirl-plugin

A token-efficient persona runtime for DeepSeek Harness.

Keep personality in the interface, intelligence in the model.

简体中文 | English

Example

User: write me a sorting algorithm

Model (normal output): Wrote /tmp/qs.py: in-place quicksort, all 6 test cases PASS.

What you see: Wrote /tmp/qs.py: in-place quicksort, all 6 test cases PASS. 喵~ (。・ω・。)

Core idea

The traditional approach makes the LLM "act catgirl" itself: a few hundred tokens of persona injected into the system prompt, paid again on every request, and the model's output gets wordier.

This plugin does the opposite — persona virtualization:

  • The session log stores raw text — zero pollution of the model's context
  • Catgirl flavor at 0 LLM tokens — all rendered locally
  • Tool schema trimming: 25 → 8 tools, saving thousands of tokens per request

Measured results

Real DeepSeek API (2026-08-14): -67% new input on the first request, -66% cache reads in steady state, no quality degradation.

Cold start (first agent request, no cache)

Config First request new input Total new input Total cache reads Output
Baseline (no plugin) 12,372 12,520 25,856 838
Traditional catgirl 12,576 13,156 26,240 860
Lite + Economy 3,881 4,178 8,960 739

Steady state (second run, cache warm)

Config New input Cache reads
Baseline 497 38,144
Lite + Economy 386 12,800 (-66%)

Findings

  1. A traditional long-persona catgirl costs more tokens (+5%) — persona is a per-request recurring cost
  2. A minimal persona ≈ baseline — its value is letting the model output normal text, leaving the catgirl flavor to local rendering
  3. Tool schema trimming is the real token saver — ctx.tools.restrict() trims at the agent scope, keeping what the model sees aligned with what it can execute

Quality comparison

5-task battery (coding / web search / file search / pure Q&A / subagent): no quality degradation; the model adapts to missing tools (curl instead of web_search, direct answers instead of subagents).

Task Tool status Baseline quality Plugin quality Baseline tokens (new/cache) Plugin tokens
Coding kept ✅ ✅ (+edge cases) 309 / 37,760 725 / 22,016
Web search trimmed ✅ news data ✅ live API (curl) 2,476 / 65,408 1,403 / 17,024
File search kept ✅ 215 files ✅ 215 files 7,066 / 40,832 3,490 / 22,912
Pure Q&A no tools ✅ detailed ✅ concise 192 / 12,288 149 / 3,840
Subagent trimmed ⚠️ truncated output ✅ answered directly 18,702 / 61,312 189 / 3,840

The real boundary: tasks that require a specialized tool (parallel subagents, skill calls) change strategy. Progressive disclosure solves this:

Model: enable_tool("subagent") → tool unlocked
Model: subagent × 2 (parallel delegation) → subagents done → summary

Measured end-to-end: the model recognized the missing tool, called enable_tool, delegated to two parallel subagents, and summarized correctly. Capability fully restored, while the parent's tool schemas stay minimal until escalation (~2,000 tokens/request saved).

If a requested tool is not installed in the current profile, enable_tool reports it as unavailable and preserves the previous allow-list, so the session can continue unlocking other tools.

Quick start

# Install from npm
dsh plugin --profile demo add dsh-catgirl-plugin

Then add to the profile patch:

- insert:
    - id: catgirl-lite
      name: dsh-catgirl-plugin/catgirl-lite
      config:
        persona: 'Be concise, friendly, and natural.'
    - id: neko-renderer
      name: dsh-catgirl-plugin/neko-renderer
    - id: catgirl-economy
      name: dsh-catgirl-plugin/catgirl-economy
      config:
        profile: coding

Web UI rendering (optional): install dsh-catgirl-plugin-client and add it to the profile patch:

- insert:
    - id: neko-renderer-client
      name: dsh-catgirl-plugin-client

Plugin family

Plugin Role Token impact
catgirl-lite.js minimal persona (6 tokens) +6 per request
neko-renderer.js headless display decoration 0
catgirl-economy.js tool trimming + enable_tool on-demand unlock -8,491 per request (-69%)
client/ Web UI rendering (shadows the assistant renderer) 0
index.js traditional long persona (for comparison) +hundreds per request
usage-meter.js dev tool: records usage 0

Tool profiles

profile Initial tools Use case
coding editing, files, search, and todo Default for development work
normal reading, search, and Web Research and general assistance
chat no global tools Conversation; unlock tools with enable_tool when needed

When set, allow overrides the profile, including an explicit empty list. Use escalatable to control which tools may be unlocked on demand. Tools missing from the active DSH profile are filtered at startup instead of crashing agent creation.

Future direction

  • Add a Reasoning Router only after establishing cross-model quality baselines
  • Predict a tool profile by task while retaining explicit configuration as the fallback
  • Map the agent lifecycle to a richer Web UI state

Known Limitations

  • Headless one-shot does not wait for background subagents: run_in_background: true children are killed on parent exit (headless app limitation, not the plugin; sync mode works)
  • nya tool output is random (Math.random()), unsuitable for snapshot tests
  • Persona text is Chinese-only: edit INTENSITY_TEXT in index.js or extend via traits

Development

npm ci && npm test && npm run pack:check
npm ci --prefix client
npm run --prefix client typecheck
npm run --prefix client build
npm run --prefix client pack:check

Point the real Loader composition test at a built Harness checkout:

DSH_HARNESS_PATH=/path/to/deepseek-harness npm run test:composition

Quality runs write usage, output, overlay, and machine-readable metadata artifacts into one directory:

DSH_BIN=/path/to/dsh BENCHMARK_OUTPUT_DIR=/tmp/bench \
  npm run test:quality -- quicksort lite "write quicksort and run its tests"

The files under overlays/ use npm package paths and contain no machine-specific absolute paths. Root and client packages stay on the same version. The Release workflow publishes both npm packages and creates a GitHub Release only when a v* tag is explicitly pushed. Configure the repository NPM_TOKEN secret before the first release.

License

MIT

Content from the project README on GitHub ↗

Links

More in this category

View the whole category →

Community comments

Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.