--- type: concept title: OMP Snapcompact — Bitmap-Frame Compaction description: How snapcompact archives session history as bitmap frames, what shape frank-archon resolves to, the measured recall/billing table behind the fleet's settings, and the models.yml knobs that actually exist. resource: https://github.com/can1357/oh-my-pi/tree/main/packages/snapcompact tags: - omp - compaction - snapcompact - frank-archon verified: 2026-10-27 timestamp: 2026-10-27 --- # OMP Snapcompact — Bitmap-Frame Compaction Snapcompact is omp's automatic-maintenance method that replaces the LLM summarizer call with a local, deterministic archival pass: discarded history is serialized, whitespace-collapsed, and printed onto dense PNG frames of pixel-font glyphs that a vision-capable model reads back directly. No model, key, or network is involved, so it also serves overflow recovery. It runs only when the current model's row declares `input` including `image`; otherwise maintenance advances to the next method in `compaction.methodOrder`. Fleet position (`agent/config.yml`): `methodOrder: [shake, snapcompact, soft, handoff, remote]` — deterministic, lossless-first. Shake elides heavy blocks to `artifact://` references before anything is archived; snapcompact then archives what shake couldn't reclaim; the lossy LLM lanes (`soft`/`handoff`/`remote` via frank-zealot) should never be reached while a vision endpoint is active. ## Shape resolution for the fleet The frame shape (font grid + pitch + frame width) resolves from the **model id** against a measured table, falling back to the **wire API family** when the id is unmeasured: | Matcher | Shape | Frame | |---|---|---| | claude (fable/mythos) | `11on16-bw` | 1932px | | claude | `11on16-bw` | 1568px | | gemini | `8on22-bw` | 2048px | | gpt / codex | `8on22-bw` | 1568px | | kimi | `8on22-bw` | 1568px | | glm | `8on16-bw` | 1568px | | openai-completions wire (unmeasured id) | `8on22-bw` | 1568px | There is **no qwen matcher**: `frank-archon` (radiance, Qwen3.8 vision tower, `openai-completions` wire) resolves via the wire fallback to `8on22-bw` @1568px — which is 56 clean 28px token-rows for a Qwen-style ViT. `snapcompact.shape` stays `auto`; forcing a variant would bypass the font-aware CJK escape hatch (`silver16-bw`). ## Measured recall and billing (frank-archon, 2026-10-27) A 212,916-char tool-traffic transcript with 8 planted unique facts was sent to `frank-archon` four ways (probe: `@oh-my-pi/snapcompact` renderer, production request shape, `omp` 18.12.5-era bundle): | Leg | Frames | Billed prompt tokens | Recall | |---|---|---|---| | Plain text baseline | — | 63,066 | 8/8 | | auto = `8on22-bw` | 14 | 33,533 | **8/8** | | forced `8on16-bw` | 11 | 24,364 | 6/8 (dropped characters) | | forced `11on16-bw` | 14 | 33,533 | 6/8 (dropped characters) | Laws this established: - **The default shape is the accurate one for the fleet.** The Qwen3.8 FP8 tower OCRs `8on22-bw` pixel fonts with full recall; both denser grids drop single characters inside identifiers — matching upstream's toolbench finding (spacing-tuned cells won everywhere; dense prose-era shapes erase line structure). - **Bitmap archive ≈ 47 % of the billed tokens of raw text at equal recall.** - **True radiance billing is ~2,400 tokens/frame; the harness charges a blind 5,024 floor.** Unpriced custom endpoints get `FRAME_TOKEN_ESTIMATE` (5,024) per frame in archive sizing, so archives plan roughly half the frames the window actually fits. This is conservative (never overflows) and costs recall-per-compaction. ## The knobs that exist (and the one that doesn't) - `imageCountBudget: 16` (top-level models.yml row field, set on `frank-archon`): the catalog never matches custom providers, so the unknown-provider floor of **5 images per request** silently caps archives. Radiance accepted 14 frames in one probe request; 16 leaves margin. Real frame count stays bounded by the sizing law below. - `imageTokenization` is **catalog-only** (compiled KDL compat rules; no user-row key reaches the pricing path). A custom row cannot mark frames verified or price them — until upstream prices `openai-completions` vision, custom-endpoint archive capacity is count-bound. - Archive sizing law: frames get **half the room left under the compaction threshold** after system prompt, tools, and kept recent turns; the compacted result targets ≤ 60 % of threshold, and post-compaction headroom must reach the 80 % recovery band. - `snapcompact.systemPrompt: none` and `snapcompact.toolResults: false` stay off fleet-wide: imaging inline text is a token-cost lever that routes always-loaded instructions through the OCR path — accuracy-negative. ## The 85 % trigger law `compaction.thresholdPercent: 85` on frank-archon is load-bearing for the max_tokens clamp documented in `agent/models.yml`: `170,000 est × 1.03 + 16,384 ≤ 200,000`. At 95 % the clamp squeezes output to ~6 k near the trigger and the worst-case request overshoots the window, so radiance **refuses** and compaction reroutes through the overflow-recovery emergency path instead of the planned threshold pass. ## Follow-ups - `frank-dragoon` / `frank-zealot` rows carry the same unpriced vision towers; the count budget and probe apply to them but are unmeasured there. - Re-run the probe after the next upstream snapcompact/omp release (renderer and shape table move under us).