dsh-command-context
Manifest validAdds a /context slash command to DeepSeek Harness: shows how much of the session context window is used, how much is free, and a per-category breakdown (system prompt, memory files, skills, messages,
dsh-command-context
English | 中文
A /context slash command for DeepSeek Harness: type it in a session to see how much
of the context window is used, how much is free, and which part of the prompt takes the
most room.
Inspired by Claude Code's /context, but every number comes from the harness's own
measurement instead of a parallel accounting of its own.
Context: deepseek-v4.1-flash (myapi)
[#####---------------] 253.3k / 1.00M tokens (25.3%) measured
Free space: 746.7k tokens (74.7%)
By message type (sum 120.1k tokens)
System prompt 2.1k (1.8%)
Memory files 369.0 (0.3%)
Skills 1.1k (0.9%)
User messages 7.9k (6.6%)
Assistant replies 39.1k (32.5%)
Tool results 69.5k (57.8%)
Compaction trigger: ~800.0k tokens (80.0%), 546.7k headroom
Illustrative numbers. measured means the headline figure came from reusable provider
usage; estimated means it fell back to the character heuristic.
The card renders expanded by default. A command result normally lands in the generic
collapsed card that needs a click to open; this plugin's client half takes over the keyed
client slot conversation.chat.commandview for the context command only, so the report
is simply visible. Every other command keeps the built-in card. In a composition without a
chat UI the host half still works and the generic card is used.
Install
dsh plugin --profile <profile> add dsh-command-context
Or install it from the plugin directory. The bundle is Host-only — no client half, no extra services to compose:
- insert:
- id: dsh-command-context
name: dsh-command-context
Requires @deepseek-ai/dsh >=0.2.1-rc.5 <0.3.0-0. The command is registered globally,
so it is available in every agent of that profile.
How categories are decided
Classification is per surface node, not by slicing text: every surface node already carries its own token price, so the command only has to decide which bucket it belongs to.
| Event | Bucket |
|---|---|
system/message | System prompt |
user/message whose blocks are all <system-reminder> and mention workspace instructions / Instructions from: / memory root: | Memory files |
user/message whose blocks are all <system-reminder> and mention skills are available / <available_skills> | Skills |
user/message, any other <system-reminder> injection | Injected context |
user/message, real input | User messages |
developer/message | Injected context |
assistant/message | Assistant replies |
tool/result | Tool results |
The part that matters: an instruction file (e.g. AGENTS.md) and the skills catalog each
arrive as their own user/message whose only block is a <system-reminder> — they are
neither part of the system prompt nor something the user typed. Leaving them in
User messages inflates that line badly, which is exactly what the first version of this
plugin got wrong.
The split is deliberately conservative: if a message contains even one block that is not a
<system-reminder>, the whole message stays under User messages. Under-splitting beats
misattributing text the user actually wrote.
Where the numbers come from
| Figure | Source |
|---|---|
| Used / pressure | ctx.tokenMeter.measure(session).totalTokens — replays the durable session log, no model call |
| Context capacity | session.requestContext().contextWindow (the request/context record) |
| Free space | capacity − pressure |
| Breakdown | measure().nodes, classified per node; denominator is surfaceTokens (= the sum of those nodes) |
| Compaction trigger | min(W * 0.8, W - maxTokens - 65536), the shipped compaction-basic defaults |
Occupancy follows the @deepseek-ai/dsh-token-meter definition verbatim: measured
pressure ÷ the capacity of the model route that owns it.
totalTokens = baseline.tokens + surfaceDeltaTokens. When baseline.kind === 'usage' the
baseline is the last request's reported usage (input + cache read/write + output);
otherwise it is the fixed four-characters-per-token heuristic, which under-prices CJK text
and JSON Schema documents.
The command is read-only: it never appends session events, never triggers a model call, and
never mutates session state. Its lifecycle (command/run, command/done) is recorded by
the command registry as log-only events.
Why the report body is ASCII-only English
A command result renders inside a <pre> with white-space: pre-wrap and a monospace font.
Full-width CJK glyphs are wider than the assumed cell, and block characters such as █░ are
taller than the line box — both visually collide with the neighbouring lines in that
container. ASCII has a constant width of one cell, so column alignment is exact: the meter
uses #/-, labels are English, and brackets are half-width.
Two languages are kept apart on purpose: the report body is English for the layout
reason above, while the command's description in the slash panel is Chinese
(查看当前会话的上下文窗口占用) to match built-in commands in a Chinese UI. Plugin Manager
metadata ships in both languages via locale/en.json and locale/zh.json.
Limitations
- An estimate, not a bill. The headline is measured only when reusable provider usage
exists. The breakdown is always per-message route pricing, so it is a different scale
from the headline and will not sum to it — the
By message typeline prints the node total so the two can be compared. - Tool schemas have no line of their own because they are not surface nodes. Exposing
them requires reading the
contextBreakdownprojection (systemTokens/toolsTokens/messageTokens); this version does not. Compaction triggerdescribes the default policy's threshold and does not assert that automatic compaction is enabled in your composition.- No capacity, no percentage. A session with no
request/contextrecord yet reports the used tokens and says plainly that it cannot compute a ratio. - Covers the current session only; subagent sessions are not included.
Updating during development
A bundle installed from a local directory is a junction into your source tree, and the HMR
watcher's default ignored includes **/node_modules — so editing the source does not
hot-reload the plugin. To load a new module generation without quitting the app:
- Toggle the plugin row off and on once (
set_pluginwithinclude:dsh-command-context,enabled: falsethentrue). The loader re-imports the module. - Set
DSH_CONTEXT_LOAD_STAMP=1before launching to have the plugin append atime rev=Nline to~/.dsh/tmp/dsh-command-context.loads.logon every activation, so you can tell which generation is live. Off by default — the plugin writes nothing to your home directory otherwise. - If the stamp does not advance, fully quit the app from its tray icon and relaunch (closing the window only minimizes it, and the host process keeps the old module).
install_bundle answers already-installed for an existing package; replacing a version
needs remove_bundle first, and that removes the junction — back up the source directory
before doing it.
Development
node --check index.js
node test/report.test.mjs
The test suite uses synthetic data to assert classification (including the memory/skills split and that mixed messages are not misattributed), the occupancy arithmetic, the unknown-capacity branch, ASCII-only output, column alignment, and the absence of explanatory copy in the report.
License
MIT
Comments
Loading…
From the same category
DeepSeek Harness plugin for Reactive Resume: bridges your resumes and job applications into a Harness session over MCP.
★ 41.7k
↓ 215/wk
MIT
Aug 24, 2026
dsh plugin --profile web add dsh-plugin-reactive-resumeby dsh-market
The plugin market inside DeepSeek Harness — browse, search, one-click install · DSH 可视化插件市场
★ 10.1k
↓ 361.7k/wk
MIT
TypeScript
Nov 1, 2026
dsh plugin --profile web add dshmarketby Tencent
Let AI agents use your real, logged-in browser without interrupting your work. CLI + extension for browser automation across any shell-capable AI agent.
★ 9.9k
↓ 12.3k/wk
MIT
TypeScript
Nov 1, 2026
dsh plugin --profile terminal add @wxg-prc-cpg/browser-skill-dsh-pluginby yjh051108
dsh-routing-suite — injector + router-standard kit: install the runtime injector first, then the task-aware reasoning-mode router preset (measured P1-P23).
★ 7k
MIT
JavaScript
Sep 18, 2026
dsh plugin --profile web add @dsh-external/dsh-super-injectorby superdesigndev
OpenRouter for agent tools. Join community here: https://discord.gg/6mQYYfFMAn
★ 7k
NOASSERTION
Python
Nov 2, 2026
dsh plugin --profile web add treg-dshby Q00
Agent OS: the agent gets smarter on its own. We just hold the line: Interview-gated, staged evaluation, budgeted evolution loop. MCP server, 14 runtimes: Claude Code, Codex CLI, Gemini CLI, OpenCode,
★ 6.3k
MIT
Python
Nov 1, 2026