Cyberbolt/dsh-snapcompact ↗★ 2
dsh-snapcompact
DeepSeek Harness plugin that compacts long chats by rendering history into compact bitmap frames a vision model can read, while keeping exact head/tail text and a searchable archive.
Other repositories with this package name
Install
npx -p @deepseek-ai/dsh dsh plugin --profile web add dsh-snapcompact@0.5.1README
Read the full README ↗Configuration
Configuration lives on the snapcompact row inside the selected Snapcompact preset's isolated compaction group. The settings card on the Plugins → Snapcompact page covers the common keys; the preset/config editor covers everything else. Both write into the active profile's configuration patch, so neither requires editing profile files by hand.
methodOrder: [snapcompact, handoff, shake, soft]
policy:
auto: true
# Trigger at 80% of the window; /snapcompact status shows the effective token count.
thresholdRatio: 0.8
rendering:
width: 1568
height: 1568
maxFrames: 20
lineHeight: 20
minGlyphPx: 12
serialization:
toolResultMaxChars: 2000
toolArgumentMaxChars: 500
messageTextMaxChars: 8000
headChars: 2000
tailChars: 2000
includeReasoning: false
maxCarriedImages: 4
Defaults use 1568×1568 frames and 20 frames per checkpoint, with a configurable maximum of 64; the host's per-message image cap (20 by default) still clamps the effective count. Other limits are 16 MiB of generated images, 64 MiB of source/archive data and a 15-second render deadline. The frame count is chosen dynamically under the checkpoint budget implied by the trigger (see the configuration reference).
In-app settings
The Snapcompact detail page under Plugins carries a settings card backed by a snapcompact-settings row in the current profile. The card writes through DSH's settings service into that profile's configuration patch, so saved values survive restarts without hand-editing YAML. It manages:
| Control | Config path | Default |
|---|---|---|
| Method chain | methodOrder | [snapcompact, handoff, shake, soft] |
| Custom trigger threshold | policy.thresholdRatio | unset (host default 0.8) |
| Frame size | rendering.width and rendering.height | 1568 |
| Maximum frames | rendering.maxFrames | 20 (max 64) |
| Archive limit | archiveMaxBytes | 64 MiB |
| Handoff budget | handoffMaxTokens | 4096 |
| Externalize above | shakeThresholdChars | 8192 |
Rules worth knowing:
- The engine is built when a session mounts the preset, so saved changes apply to new sessions; a running session keeps its configuration.
- For a key the card manages, the saved value overrides the same key in preset YAML.
thresholdRatiois the exception: it stays unset until you enable the custom threshold, so a preset-levelpolicy.thresholdRatiostill applies. - "Restore default" removes the override and falls back to the plugin default (or to YAML, for the threshold).
- Everything else — the rest of
policy,serialization,routePolicies, render timeouts — remains YAML-only.
Custom method chains and thresholds
methodOrder is a priority list: the engine tries methods in order and the first candidate that succeeds within its compression constraint wins, so the order is the fallback order. The final method must be soft. Subsets are allowed:
| Preset | methodOrder | Behavior |
|---|---|---|
| Visual-first (default) | [snapcompact, handoff, shake, soft] | Local visuals first, then handoff, excerpts, native summary |
| Visual + native | [snapcompact, soft] | Skip handoff/shake; native summary when visuals fail |
| Local-first | [snapcompact, shake, soft] | Call the native summarizer only after both local paths fail |
| Text-first | [handoff, shake, soft] | Spend one model call on a structured handoff first |
| Native-only | [soft] | Back to the DSH native summary; archive and recall remain |
Two easy misreadings: shake succeeds whenever any tool output exceeds shakeThresholdChars, so putting it first preempts the visual path; and the checkpoint budget (half of the room left under the trigger) only constrains snapcompact, while every other method merely has to shrink the source.
The trigger is still the native policy.thresholdRatio (a window fraction, default 0.8). /snapcompact status converts it into tokens for the current route and explains whether each method will run or be skipped.
If a model genuinely has image input and a known price but DSH's adapter exposes no image pricing, DeepSeek model IDs use a labelled 1024-token/frame conservative estimate. Other models can declare a conservative ceiling explicitly:
routePolicies:
- provider: your-provider
model: exact-model-id
visualTokensPerFrame: 4096 # Example only; calibrate for the model and frame size.
A ceiling is not actual usage and cannot grant missing image modality. See configuration for every field, the native policy pass-through and route-matching rules.