Skip to main content
S

dsh-token-frugal

songrui111/dsh-token-frugal

Cuts what a long session pays for context: reads only the requested lines, keeps a prose head plus a heading digest for oversized pages, and keeps both ends of large shell output. Measured 91-99% fewer tokens on files, pages and command output.

Install

dsh plugin --profile web add github:songrui111/dsh-token-frugal

README

dsh-token-frugal

Stop paying for files and pages you didn't need to read.

A small Host plugin for DeepSeek Harness that adds three deferred-loaded tools:

ToolWhat it does
read_rangeReads only the lines you asked for: a line window, every mention of a symbol with context, or a structural outline. Hard-capped output.
tool_catalogLists the tools this session can actually call, one line each. Because once tools are deferred, the model must be able to rediscover them.
fetch_recallReads any slice of a tool result that was slimmed, by absolute character offset.

It also slims oversized web_fetch results: a docs page can be ~177,000 characters (鈮?6k tokens) and every token of it is re-sent on each later turn. Above a threshold the plugin keeps a bounded head plus a digest of the page's headings, and offers fetch_recall for the rest.

Why

Every tool round trip re-sends the whole conversation. Dumping a 600-line file to answer "where is saveSelection defined" writes ~3,000 tokens into the context permanently — and that cost is re-paid on every later turn.

read_range in symbol mode answers the same question with the matching lines only.

Measured (offline, on real files from this workspace)

Same question, different read strategy:

FileLinesWhole readsymbol modeSaved
index.js4644,661 tok188 tok96.0%
publisher-radar/client/client.js7109,389 tok274 tok97.1%
dsh-agent-bench/lib/index.js8758,999 tok513 tok94.3%
total23,04997595.8%

Oversized fetch results, same idea:

BodyRawSlimmedSaved
docs page-shaped fixture4,742 tok495 tok89.6%
Live docs.python.org/3/library/asyncio-task.html46,582 tok~579 tok98.8%

Token figures are a deterministic approximation of the Harness token rule (CJK 鈮?1.7 chars/token, code 鈮?3.8 chars/token). They are for comparison, not billing.

Savings scale with file size. Small scripts save less because the per-call header and window context floor dominates.

Install

dsh plugin install dsh-token-frugal

Or install the folder as a bundle. The row id is token-diet; override config in your own cordis.patch.yml to change behaviour across upgrades.

Config

KeyDefaultMeaning
guidetrueInject the "prefer read_range over whole-file reads" prompt section. This is what makes the savings actually happen: without it the tools exist but a model keeps dumping whole files.
exposeCatalogtrueRegister tool_catalog. Set false for a read-only diet (keeps your own tool inventory untouched).
slimtrueSlim oversized tool results via tools/post-execute.
slimWebTools["web_fetch"]Web-shaped results: prose head + heading digest.
slimShellTools["pwsh","bash","wsl","tty_run"]Shell-shaped results: head + tail, because diagnostics live at the end. Deliberately narrow: post-execute is a global waterfall, so only listed tools are touched.
maxInlineChars8000Above this character count a result is slimmed.
headChars1500Web mode: characters kept inline as the head.
shellHeadLines / shellTailLines60 / 60Shell mode: lines kept from each end.
durableArchivetrueArchive slimmed bodies under ~/.dsh/token-diet/archive so locators survive a restart. Falls back to memory if the disk refuses.
maxArchiveFiles200Oldest archived bodies are pruned past this count.

Why shell output keeps its tail

A failing command writes its reason at the end — Access is denied, the exit summary, the copy count. The host's own cap (maxOutputBytes, 64000) keeps only the head and can cut mid-line, so the model sees the noise and never the error, then re-runs the command. Keeping head and tail is both cheaper (measured 91% fewer tokens than the capped head-only result) and more correct.

About the guidance section

  • It costs ~162 tokens per turn (612 chars). That is the price of the suggestion, and it is why guide is a switch: measure both ways on your own workload.
  • It renders only while read_range is visible to the rendering scope, so a preset, a restriction, or a failed registration cannot leave instructions pointing at a tool that is gone.
  • Section order is 210, chosen to sit in the plugin-guidance band (150 ssh, 152 docker, 200 task board) without colliding.

Honest limits

  • It does not shrink other plugins' tool schemas. There is no service or event to mark another plugin's ToolSchema as deferLoading; only this plugin's own tools are deferred. On a heavily loaded profile the fixed per-turn schema cost remains (measured 56k tokens across 169 tools on one such profile).
  • Symbol mode is textual, not semantic. It matches substrings, so save also hits savesSelection. Use mode: outline first when you don't know the exact identifier.
  • read is untouched. The upstream file tools keep working, so the model can always fall back — which also means the savings only appear when the model actually chooses read_range.
  • Slimmed bodies are archived on disk under ~/.dsh/token-diet/archive, content-addressed and session-scoped, so a locator survives a restart (verified across two processes). Two caveats: pruning keeps the most recent maxArchiveFiles bodies, and archived bodies are plain files under your user profile — readable by anything running as you. Do not enable this on shared machines if fetched content may be sensitive.
  • spillStore is not used. Its runtime availability could not be confirmed, and a hard dependency on it would disable slimming entirely if absent. The plugin owns its own small store instead.

Licence

MIT. Icon is original artwork drawn for this plugin.

Related plugins