DeepSeek Harness plugin

omdsh-usage

API spend at a glance for the DeepSeek Harness web GUI: this conversation, this project, and the account balance, beside the mode chip in Chat and Work and in the corner in Code

Jump to install

Source facts

Repository
omdsh-plugins/omdsh-usage
Latest update
Aug 20, 2026
Category
UI Enhancements
GitHub stars
0
Format
plugin
Catalog evidence
Upstream dsh.bundle evidence
Evidence path
package.json#dsh.bundle
Checked against
0.1.0-rc.8
Upstream check date
2026-08-20

This evidence comes from the upstream catalog. This site has not installed, run, or security-reviewed the plugin.

Install

Start with a prompt that asks an agent to review the GitHub repository and source. Switch to the command if you want to install it yourself.

Copy this prompt into DSH, Codex, or another agent and ask it to review the GitHub repository and source first.

Do not install or run any commands yet. Read this plugin's GitHub repository, README, and relevant source code. Then answer the questions below clearly and directly so I can decide whether it fits my needs:

1. What is this plugin, and what problem does it solve?
2. Who is it for, and what are its typical use cases?
3. How is it used after installation? Include one minimal example.
4. What known limitations or privacy, security, compatibility, or maintenance risks does it have?
5. Give a clear recommendation: recommend, conditionally recommend, or do not recommend, with reasons.

Distinguish statements documented by the repository, inferences from source code, and unknowns. If evidence is insufficient, say so explicitly. Do not guess or simply repeat the README.

GitHub: https://github.com/omdsh-plugins/omdsh-usage
Plugin: omdsh-usage
Author: omdsh-plugins

Check the source files

Read the README and other files from this plugin directory before installing.

File explorer4 files
README.mdSource · read only
README language

omdsh-usage

English | 中文

What this conversation cost, what this project has cost, and what is left on the account — three figures in the row of the DeepSeek Harness web GUI you are already reading.

 Help   ⚙ Code mode   💬 0.023 ¥   📁 1.03 ¥   👛 964.15 ¥          Files  Terminal

In Chat and Work the badge sits in the session header, immediately right of the Chat Mode / Code mode chip. In Code the whole conversation column is a terminal and there is no header to sit in, so it moves to the opposite corner, just left of Files. (Files and Terminal at that end of the row belong to omdsh-sidepanel, not to this plugin; they are drawn here because they are what the corner has to sit inboard of.)

Under a configurable floor — 10 by default, in whatever currency the account is denominated in — all three icons turn red, and so they do when the provider reports the account itself unavailable, whatever the figure beside it says. Red therefore means two things rather than one. Above the floor nothing is tinted at all, and a balance that could not be read is not an alarm either: no key stored, or a network blip, leaves every icon its ordinary colour and puts the reason in the tooltip.

What it adds

SurfaceWhere it comes from
The three-figure badge in the session headerconversation.session.header.actions, ui-conversation's action row
The same badge in the frame's corner, whenever nothing is drawing a headershell.overlay, ui-layout's frame-wide floating layer
The omdshUsage per-model token foldsessionProjections.register — a projection unit the harness drives once per committed event and checkpoints
GET /omdsh-usage/summarywebServer, behind the same browser-trust check the /api gateway applies
The omdsh-usage settings namespacesettings.register, which is the whole of what the plugin hub needs to render this plugin a configuration page

The figures

ReadoutWhat it is
SessionEvery model call in the conversation on screen, priced.
ProjectThe same, summed over every conversation whose working directory is this one.
BalanceWhat the provider says is left on the account, in the provider's own currency.

Hover any of them for the tokens behind it, how many of those DeepSeek billed at its off-peak rate and what that part cost, the directory a project total is for, how much of the balance is promotional credit, or — when a figure is missing — why.

This conversation cost 3.02¥ over 1.2M billed tokens (1.2M in, 900k of it
cached; 42k out). 400k of those tokens were billed off-peak, at 1.01¥.

The off-peak line appears only when there is one to draw: a conversation that ran entirely inside the peak windows, and one this plugin never folded, both leave the tooltip a line shorter rather than claiming a zero neither of them can stand behind.

Prices, and the hour they were paid at

The harness carries no prices, so this plugin does. The shipped table is DeepSeek's published peak rate per million tokens, read from its pricing page on 2026-08-16:

CNY per 1M tokenscache hitcache missoutput
deepseek-v4-flash0.103.009.00
deepseek-v4-pro0.309.0027.00

Off-peak is half of each of those, and off-peak is most of the day: peak hours are 09:00-12:00 and 14:00-18:00 Beijing time (01:00-04:00 and 06:00-10:00 UTC), seven hours out of twenty-four. A badge that ignored the clock would overstate a night's work by exactly a factor of two, so the fold records which tier each message was billed at as it counts it — the event's own timestamp is the last place that information exists — and the discount multiplies that share at pricing time.

A published price is still a fact about last week: rates change, gateways discount, and your invoice is the only authority this code can never read. So all of it is yours to restate, in Settings → Plugins → Plugin hub → Usage. The panel renders the namespace as a form, and a deployment that wants to state its own writes the same shape into its profile's cordis.yml:

omdsh-usage:
  currency: CNY
  rates:
    default: 0.3/9/27           # <cache hit>/<cache miss>/<output>, per MILLION tokens, at PEAK
    deepseek-v4-flash: 0.1/3/9
    deepseek-v4-pro: 0.3/9/27
  offPeakDiscount: 0.5          # an off-peak token costs half of the line above
  lowBalance: 10

Every field is live: a repriced table reaches the next poll, a few seconds later, with nothing to restart.

FieldMeaning
currencyCNY or USD. The two spend figures are stated in it and the rates are read in it. The balance always reports the provider's own currency.
ratesOne line per model, "<cache hit>/<cache miss>/<output>" per million tokens, at the peak rate. The default row prices any model the table does not list — it ships as the dearer of the two published models, because overstating a model nobody has priced is the safer direction. A key may be a bare model id or a full provider/model.
offPeakDiscountWhat an off-peak token costs as a fraction of the line above: 0.5 is half price, 1 charges everything the peak rate. Changing it reprices history immediately, because which tokens were off-peak is already recorded.
lowBalanceThe floor under which all three icons turn red.
apiKeyEnvWhich stored credential the balance call uses — the credential's name, not the key. Defaults to DEEPSEEK_API_KEY.
baseURLWhere the balance is read from. Point it at the same gateway your model requests use.

A rate line that is not three non-negative numbers is refused at the moment it is written, rather than stored and failed on afterwards.

The peak windows are not a setting, while the discount is. The split has to be decided while the fold runs — the projection checkpoints its state and never revisits an event — so a window read from settings would make two checkpoints of the same conversation disagree depending on when each was written. The discount only multiplies at pricing time, so it costs nothing to let a person state it.

How it works

Almost none of the accounting is this plugin's. The session log already records provider usage on every assembled assistant message, and the harness's projection seam already folds and checkpoints per-session state. So:

  • The fold is a projection unit. omdshUsage accumulates billed tokens per

provider/model over the complete durable log, and, beside them, the share of each that was billed off-peak. The harness drives it once per committed event and checkpoints it, so the figures survive paging, compaction, and restarts — and a conversation using two models across both price tiers is priced at four rates rather than one blended average.

  • "This project" is the checkpoint table. Every session's checkpoint is

stored with its working directory, so a project total is a read of a few kilobytes of JSON rather than a walk through a directory of compressed logs.

  • The balance is one provider call, behind the credential seam, cached for

a minute and shared across every open tab.

  • The money is computed on the host. The browser receives numbers to

format and never a rate to multiply, so there is one implementation of the arithmetic and a stale page cannot render spend at last week's prices.

Two seats, both slots the harness already publishes: conversation.session.header.actions for the header, and shell.overlay for the understudy that holds the row's place when nothing is drawing one. The understudy decides its corner by measuring the frame — if the conversation column still holds a session header it takes the leading corner, and if something else has taken the column it takes the trailing one, inboard of whatever furniture is already there.

It re-measures on the three things that can move it, and two of them are invisible to a resize observer: a mode taking the column replaces the conversation with something else in exactly the same box, and a neighbouring surface appearing in that corner changes where "inboard" is without changing any size at all. Both are childList mutations on anchors their renderers publish — the conversation slot's, and the floating layer's — so that is what is watched.

What it does without

Every service either half injects — webServer, webRuntime, sessions, and sessionProjections on the host, slots, sessions, and locale in the page — is the harness's own, and both seats are taken through slots.inject. So no other plugin in this collection is a precondition: a profile carrying only this one boots, and the badge is there. What is missing is reported rather than waited for.

  • No credential store, or no key in it. The two spend figures are

unaffected; the balance is a dash and its tooltip says which of the two it was.

  • No session persistence or projection cache. The project total covers the

conversations this host has open rather than every conversation that ever ran in the directory.

is what replaces the conversation column with a terminal, and the trailing corner exists for that. Without it the header is always there to hold the badge, and the understudy only ever stands in for a blank conversation. Which corner is a measurement of the frame either way — nothing here asks who is installed.

Install

npx @omdsh-plugins/omdsh-plughub add omdsh-usage

That is the plugin hub's installer with argv where the button was. It resolves this plugin from the collection's registry, installs it from its GitHub repository, and writes the pnpm build-allowlist entry a bare dsh plugin add github:… would leave to you — the entry carries the commit pnpm resolved, so it can be copied out of a failure and never written down in advance.

dsh plugin --profile web add @omdsh-plugins/omdsh-usage is not that command yet: this package is not on npm, and pnpm answers ERR_PNPM_FETCH_404. The same install is also a button, on this plugin's card in Settings → Plugins → Plugin hub, once the hub itself is in the profile.

Or from a checkout, which is what an unpublished build wants:

pnpm install && pnpm run build   # a local checkout never runs `prepare` — build it yourself first
dsh plugin --profile web add /path/to/omdsh-usage
dsh web

Nothing else. The balance is read with the DEEPSEEK_API_KEY the harness already holds for model requests, so there is no second key to store — and if no key is stored, the two spend figures still work and the balance says why it is absent.

Remove it the same way:

dsh plugin --profile web remove @omdsh-plugins/omdsh-usage

Both halves go with it, and the header row closes back over the seat. Nothing in this collection is a precondition in either direction — see [what it does without](#what-it-does-without) for what each absence costs.

Commands

pnpm install
pnpm run build
pnpm run typecheck
pnpm run test

The committed manifest pins the published harness. To build against a sibling checkout instead:

pnpm run harness:local ../../deepseek-harness   # that checkout must be built first
pnpm install
pnpm run harness:npm                            # before committing — a link: is one machine's layout
pnpm run check:harness-pin

Every spec runs from a bare clone on the committed pin: the pure modules import the harness type-only, and the two that need a snapshot store are handed one rather than importing the browser bundle a test runner cannot load.

Known limitations

  • Conversations older than this plugin have no per-model fold, because

nothing was folding one when they ran. They fall back to the harness's own tokenUsage projection, which records neither the model nor the clock, so they are priced at the default row and at the peak rate — an upper bound in both directions at once. The tooltip says when a figure includes an estimate. Without this fallback a project total would read as "you have spent almost nothing here", which is a worse error.

  • A conversation folded by an older build of this plugin knows its models

but not its tiers; its stored checkpoint is kept rather than discarded, and everything in it is charged the peak rate until the conversation is reopened, at which point the whole log refolds and the tiers come back.

  • The tier is read off the assembled message's timestamp, which is when the

response finished rather than when the request was made. A turn straddling 09:00 or 18:00 Beijing time is billed on the wrong side of the boundary; a turn is minutes, and the windows are hours.

  • Cold conversations lag by up to a turn. A checkpoint is written at

turn/end; the conversation on screen is live and is recomputed on every poll.

  • Cache writes are billed as cache misses. DeepSeek prices them that way

and its adapter reports no separate bucket; a provider that charged separately would be priced conservatively.