DSH Plugins Marketplace

DSH Plugins

Plugins

/

Tools & Capabilities

/

dsh-offpeak

d

dsh-offpeak

Manifest valid

Holds DeepSeek model calls for the rest of each peak-hour window you configure instead of sending them, so they are billed at off-peak rates; also pauses active goals while it waits and shows the acco

UI (client)hasBundlePatch

dsh-offpeak

Holds DeepSeek model calls during peak pricing hours so they are sent at off-peak rates. While a window is open, a request is simply not sent: the agent waits, and resumes on its own when the window ends.

This is a standalone plugin. It reads and writes only its own files and does not depend on any other plugin.

Requirements

  • DeepSeek Harness with the web profile.
  • DEEPSEEK_API_KEY stored through the Models page, only if you want the balance and the spend chart. Pausing works without it.

Install

# from GitHub
dsh plugin --profile web add github:TetraSsky/dsh-offpeak

# or from a local checkout
dsh plugin --profile web add <path-to-this-package>

Then add dsh-offpeak to dsh.profile.bundles in $DSH_HOME/profiles/web/package.json and restart. The package's cordis.patch.yml inserts its own row.

For local development, a directory junction into the profile's node_modules plus an insert row in $DSH_HOME/profiles/web/cordis.patch.yml also works and reloads live — see Development.

How the hold works

Three separate mechanisms, which together are what "paused" means here:

MechanismEffect
Request gatellm/stream is the waterfall every model call passes through. Inside a window the call is parked before it reaches the adapter, so nothing is sent and nothing is billed.
Goal freezeAny goal in the active phase is paused, so it stops making progress and reads as paused rather than busy. Goals you paused yourself are never touched.
Status tooloffpeak_status lets the model report why it is waiting. Read-only: it cannot change the schedule.

There is no per-request override and no per-window skip. The schedule is the single statement of when calls are held; to end a pause early, edit the schedule or turn the plugin off.

A held request is released when its window ends, when the request is aborted, when the schedule changes so it is no longer held, or when the plugin unloads. A restart resumes exactly the goals this plugin paused, using a record it keeps for that purpose.

While the window is open (or about to open) the header carries a notice with a Dismiss button. Dismissing it silences that window for the rest of the page session — switching chats does not bring it back, since the header entry is rebuilt for every session — while a reload starts fresh and warns again. A different window is a different occurrence and is always announced.

Schedule and time zones

Peak pricing is defined in Beijing time, so the plugin keeps two zones apart:

  • Schedule time zone — the zone the windows are written in. Part of the schedule's identity.
  • Show times in — a viewing preference only. Changing it re-labels the times; it can never change a window.

Because the state machine is evaluated in the schedule zone, the browser and the host always agree about the state, whatever zone the browser is in.

Apply DeepSeek peak hours converts Beijing 09:00-12:00 and 14:00-18:00 (weekdays, two-minute margin) into whichever schedule zone you have selected, and appends them. It never changes your zone and never discards windows you added.

If your zone observes daylight saving, the converted windows drift relative to Beijing peak twice a year, because Beijing does not move. The settings page says so and offers to express the schedule in Beijing time instead, which cannot drift.

Balance and spend chart

With Show API balance on, the host reads the DeepSeek account balance with your stored key and the header shows the figure. Hovering it breaks the spend down; clicking it opens eight hours of ten-minute bars.

  • The key never leaves the host. The browser asks for the derived figure over an authenticated route.
  • Spend is the sum of balance drops, so a top-up cannot cancel out real spend.
  • Samples are taken every five minutes whenever the plugin is enabled, not only while the balance is displayed, and are kept in $DSH_HOME/offpeak-history.json (288 samples, about 24 hours).
  • Spend is a derived quantity, so history begins when the plugin does. Nothing can reconstruct usage from before it was installed.

Which currency is shown

The balance API answers in the account's own currency — for some accounts USD, for others CNY — and both the figure and its symbol come from that answer.

Balance currency overrides the symbol: Follow the API (the default), ¥ CNY, or $ USD. On its own the override only relabels the API's figure, which would misstate the amount if the two currencies differ, so choosing one also reveals CNY per USD. Leave that at 0 to show the API's figure unchanged; set a rate and every amount — balance, hover breakdown, chart bars — is converted at it.

Neither knob follows the interface language: a Chinese UI showing a USD account still shows the API's dollar figure unless you say otherwise.

Settings

SettingMeaning
Enable off-peak pauseMaster switch.
Schedule time zoneZone the windows are written in. The picker lists 58 zones covering every whole-hour offset from -11 to +14 plus the half- and quarter-hour ones, each labelled with its offset and sorted by it.
Show times inViewing zone for the second, greyed time.
Pause windowspauseAt-resumeAt wall-clock ranges, each with its own weekdays.
Days that pauseWeekdays the schedule applies to. Weekends are off-peak, so excluded.
Warn before pauseHow long before a window the notice appears.
Applies toAll calls, or DeepSeek official routes only. Default is official routes, because peak pricing exists only there.
Show API balanceBalance figure and spend chart.
Balance currencySymbol to show, and the rate to convert with. See above.
Show the status in the headerHide the header entry entirely.

Language

Strings follow the harness's own language selection; there is no separate setting, so switching the harness between English and Chinese switches this plugin with it.

The harness ships exactly two locales (zh and en), and the plugin ships a dictionary for each — no more and no less. A dictionary for a locale the harness does not ship could never be selected, and a locale the plugin has no dictionary for falls back to English. A missing key also falls back to English, so a raw key is never shown.

Files

PathContents
$DSH_HOME/settings.yamlConfiguration, under the offpeak namespace, in the harness settings document.
$DSH_HOME/offpeak-history.jsonBalance samples for the chart.
$DSH_HOME/offpeak-paused.jsonGoals paused by this plugin, so a restart resumes only those.

Development

There is no build step for the host half: index.js and src/*.js are the source.

The browser half is generated, because a client bundle cannot import a relative file and the schedule logic must be shared verbatim with the host:

node scripts/build-client.mjs   # src/{core,spend,money,i18n,client}.js -> client.js
node tests/run.mjs              # 163 tests

tests/bundle.test.mjs fails if client.js drifts from its sources, so run the build after changing any of those five files.

When installing through a junction, the plugin is realpath'd out of the profile, so @deepseek-ai/* stops resolving from it. A node_modules/@deepseek-ai junction inside this directory pointing at the profile's own set fixes that; it is not needed for a copied install.

Three things that cost time to find

The client locale service has to be declared in inject. ctx.get('locale') reads as a tolerant lookup, but a service is only returned once its providing fiber is active — read it a moment too early and you get undefined, after which every string in the plugin quietly falls back to English while the rest of the harness switches language. Declaring locale parks activation until the service is live. The settings section label is projected by the settings shell rather than by this plugin, so it is registered as a thunk; a plain string keeps whatever language it was registered under.

Connection's generic RPC is unusable from another plugin. ctx.connection.rpc.handle() looks like the right way to serve host facts to your own browser half, but it registers the route through Connection's own fiber, which never injects webServer. The registration throws and the route silently never exists. Its other seat, intercept('/api', ...), is already claimed by the API Gateway. So this plugin registers its own webServer prefix route and calls connection.requestRejection() per request to keep the same Host/Origin fence and browser-session check.

A route registered before Connection activates has no fence. Connection can come up after the route is installed, so requestRejection is resolved per request rather than captured once. Capturing it at install time silently serves an unauthenticated endpoint.

Credits

This plugin exists because of dsh-save-money by zhu168, which is MIT licensed. Reading its source is how the shape of the problem was learned: the llm/stream waterfall as the place to hold a call, pausing goals rather than only their next request, the DeepSeek peak-hours preset, and deriving spend from balance samples. The state machine's three phases and the half-open, midnight-crossing window matching follow its design.

It was written fresh rather than forked, because several of its decisions could not be kept: configuration resolved from live session state, a balance history keyed by API-key fingerprint, unauthenticated HTTP routes, and a model-facing tool that could rewrite the schedule. Those are documented in the commit history rather than copied here.

If you want the plugin this one replaces, use theirs. If you want the fixes, use this.

Licence

MIT.

Comments

Loading…

Similar plugins

dsh-balance-tracker

Real DeepSeek account balance and official spend tracker in the session header, with peak/off-peak badge, monetary alert with auto-stop, and one-click top-up.

Tools & CapabilitiesModels & ProvidersManifest valid

★ 0

dsh plugin --profile web add dsh-balance-tracker

Shows DeepSeek API balance and tells whether the current moment is peak or off-peak pricing time, with a live countdown to the next switch.

Tools & CapabilitiesModels & ProvidersManifest valid

★ 0

dsh plugin --profile web add dsh-balance

by itchenshi

DeepSeek Harness plugin: model usage & account balance in the session header (OpenCode Go plan usage + DeepSeek account balance)

Development & InfrastructureTools & CapabilitiesManifest valid

★ 0

MIT

JavaScript

Sep 25, 2026

dsh plugin --profile web add dsh-model-surplus

by cute-baobao

DeepSeek Harness usage recorder plugin: per-model hourly token usage (input/output/cache hits) with a stacked bar chart dashboard in the Web GUI.

Manifest valid

★ 3

↓ 124/wk

MIT

TypeScript

Aug 14, 2026

dsh plugin --profile web add @dsh-usage-meter/usage

by Tungpeng

Off-peak inbox for DeepSeek Harness: capture thoughts and todos whenever they occur, and the host launches each one as a real session only while the DeepSeek API bills at its off-peak rate.

Manifest valid

★ 0

MIT

TypeScript

Sep 22, 2026

dsh plugin --profile web add dsh-offpeak-inbox

DeepSeek account balance and model cost tracking with official peak/off-peak pricing, three-tier token billing (cache miss, cache hit, output), per-model and per-session breakdowns, a composer summary

Tools & CapabilitiesTerminal & ClientsModels & ProvidersManifest valid

★ 0

dsh plugin --profile web add dsh-balance-and-cost