Bundle
dsh-cost-gate
Spend gate for DeepSeek Harness: refuses over-budget model calls on the llm/stream waterfall, before they are billed. Auto-downgrade past a soft limit.
- Source
- frozo-ai
- stars
- 1 stars
- License
- MIT
- Updated
- Updated 5 days ago
Readme
# dsh-cost-gate
**Spend enforcement for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) — not another dashboard.**
The dsh ecosystem has plenty of cost plugins. Every one of them *measures*:
ledgers, statistics, heatmaps, balance widgets. They tell you what you spent
**after you spent it**.
This one **stops the call**.
```
┌─ over budget? ──> throw, before a single token is billed
llm/stream waterfall ─┼─ past 80%? ────> silently route to the cheap model
└─ fine? ────────> pass through, then meter the usage chunk
```
`llm/stream` is a cordis **waterfall** — the decision happens *before* `next()`
runs, which is the only place enforcement can actually work.
## Install
```sh
dsh plugin --profile web add github:frozo-ai/dsh-budget # npm: dsh-cost-gate
```
```yaml
- insert:
- id: budget
name: 'dsh-cost-gate/plugin'
config:
limitUsd: 50
period: monthly # daily | monthly | total
softFraction: 0.8 # start downgrading at 80%
downgradeModel: 'deepseek/deepseek-chat'
storePath: '~/.dsh/spend.json'
rates: # USD per MILLION tokens
'deepseek/deepseek-chat': { input: 0.28, output: 0.42 }
'anthropic/claude-3.5-sonnet': { input: 3, output: 15 }
```
Set `dryRun: true` to log decisions without blocking — roll out safely, then
turn it on.
## Design notes
**Integer micro-dollars.** Costs accumulate as integers, never floats. A test
runs 10,000 calls and asserts zero drift, because this decides whether people
get blocked.
**Cache tokens are disjoint.** Per dsh's `TokenUsage` contract, `cacheRead` and
`cacheWrite` are *not* included in `inputTokens`, so they're added at their own
rates rather than folded in.
**Atomic ledger writes.** Temp file plus rename — a torn write must not lose
budget state.
**UTC period boundaries**, so a daily budget resets at a time everyone agrees on.
**Fails open, deliberately.** No `limitUsd` means metering only. Enforcement is
opt-in: a budget plugin that accidentally blocks your whole team is worse than
one that doesn't block at all.
## Related work
[`PerryLink/dsh-budget`](https://github.com/PerryLink/dsh-budget) covers similar
ground — metering, caps, alerts, carbon estimates, a Settings tab. If you want
dashboards and reporting, look there first. This plugin is narrower on purpose:
it gates the `llm/stream` waterfall so an over-budget call is refused *before*
it is billed, and does little else.
## Attribution
```yaml
scopeBy: session # deployment (default) | session | user
perScopeLimitUsd:
'system:compaction': null # unlimited — overhead must never block the agent
'user:alice': 100
```
**`session`** uses `GenerateOptions.sessionId`, which dsh genuinely provides.
**`user`** needs a mapping dsh cannot supply — there is no user identity at the
llm seam. So it is given, never guessed:
- `userEnv: 'DSH_USER'` — one dsh instance per user
- `sessionUsers: { <sessionId>: 'alice' }` — an operator-supplied map
An unattributable call lands in `user:unattributed`. It is never charged to
whoever happens to be handy — a chargeback report that invents attributions is
worse than one that admits gaps.
**System overhead is separated.** Compaction and session-title calls carry a
`purpose` and are billed to `system:*`, so background work can never exhaust a
person's budget. Give them a `null` limit so they cannot be blocked.
## Known limitations
- **Per-user requires operator setup** — see Attribution above. dsh has no user
concept at the llm seam, so nothing can infer it.
- **Unknown models price as $0** rather than crashing. Add them to `rates`.
- Pricing tables are yours to maintain; providers change rates.
## Test
```sh
npm test # 29 checks: pricing, drift, periods, durability, decisions, attribution
```
MIT. Not affiliated with DeepSeek AI.
Install
dsh plugin --profile web add github:frozo-ai/dsh-budget
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-cost-gate from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.