SpankNSave is designed around five constraints:
- Collection must add negligible model-context overhead.
- Provider-reported usage must remain distinct from estimates.
- Analysis must not require an additional LLM call for every turn.
- Recommendations must identify evidence, expected savings, and risk.
- Enforcement must be narrow, reversible, and opt-in.
src/plugin.ts subscribes to OpenCode hooks and events:
chat.messagechat.paramsexperimental.chat.system.transformtool.definitiontool.execute.after- Message, session, retry, diff, compaction, and idle events
It normalizes external message objects into small internal records. Raw prompt and tool-result text is not retained after estimation.
src/config.ts loads .opencode/spank-n-save.json, validates modes and collection options, clamps unsafe values, and supports the legacy .opencode/token-guard.json path.
src/estimation.ts implements:
- Configurable character-to-token estimates
- Stable hashes for normalized tool arguments
- Safe report filenames
- Head-and-tail truncation
Character-based estimates are deliberately labeled as estimates. They are used for component attribution, not authoritative billing.
src/analysis.ts is a pure deterministic function. It accepts normalized session state, configuration, and estimated tool-schema size. It produces a versioned report with ranked findings.
The separation allows unit testing without OpenCode or a model provider.
src/reporting.ts performs atomic JSON writes and prunes old reports according to maxReports. Temporary files are renamed only after a complete write.
Priority uses bounded components:
- Severity
- Confidence
- Log-scaled estimated savings
- Patch-risk penalty
This is not a proof of global optimality. It is a deterministic ranking intended to select the smallest likely high-value intervention from the available evidence.
Raw OpenCode event
→ extract numeric fields
→ estimate length where required
→ hash normalized arguments
→ discard raw content
→ retain session metrics in memory
→ write sanitized report on idle/dispose
- Logging failures do not interrupt OpenCode.
- TUI failures do not interrupt reporting.
- Report-write failures are logged and do not alter the active session.
- Enforcement is disabled unless
modeisenforce.