SCSnapcompactOh My Pi internals
High confidence · source reviewed main @ a53e4e7 August 12, 2026 PT

Snapcompact
in Oh My Pi

It does not ask another LLM to summarize old turns. It converts retired conversation history into a compact transcript, prints that transcript onto model-tuned PNG pages, and feeds those pages back through the current model’s vision input.

Critical distinction: this is prompt-context compression. It can reduce billed context tokens while increasing persisted bytes, because base64 PNG frames are stored in the session entry.
01 · Mental model

Two very different kinds of compaction

Both retire old messages from the active provider request. The difference is what replaces them.

A · CONTEXT-FULL SUMMARY

Semantic compression

A summarization model reads the old region and writes a condensed natural-language state transfer.

old turns
LLM call
summary text
Compact: usually small. Loss mode: omitted or synthesized meaning.
B · SNAPCOMPACT

Cross-modal archival

A local deterministic pipeline serializes the old region and rasterizes it. No summarization model is called.

old turns
PNG pages
vision input
More literal: but still lossy through caps, normalization, visual reading, and bounded archive budgets.
Not a magic codec: Snapcompact does not guarantee byte-for-byte recovery. It preserves a bounded, normalized transcript representation and relies on model vision recall.
02 · End-to-end pipeline

Click through the implementation path

The normal OMP compaction machinery chooses the boundary first. Snapcompact begins only after it receives the prepared “old” region.

01

Select a safe history boundary

OMP decides what can leave the live context while retaining a recent tail.

SESSIONold + recent SERIALIZE¶ scopes NORMALIZEglyph-safe RESOLVE SHAPEmodel × API PLAN ARCHIVEtext · HQ/LQ/HQ · text RUST PNGnative render PRESERVEre-attach later
03 · Session semantics

Disk history, display history, and model history diverge

Compaction appends a first-class session entry. It does not visually erase your scrollback, but it changes which path entries are rebuilt into the next provider request.

SESSION TREE / JSONL · original entries remain addressablefirstKeptEntryId → e07
usere01
assistante02
tool calle03
tool resulte04
assistante05
usere06
assistante07
tool calle08
tool resulte09
compactione10
usere11
assistante12
old region archived ↑ · recent tail retained →
WHAT THE LLM GETSlatest active path only
Snapcompact reading guide + FILESuser-facing context block
Oldest archive edgeplain text
Archived middle pagesPNG image blocks
Newest archive edgeplain text
Entries e07 → e09kept recent messages
Entries e11 → e12post-compaction messages
WHAT THE TUI GETSdisplay transcript mode
All chronological messagesscrollback preserved
── 📷 compacted · ctrl+o ──inline divider
Recent and later messagesnormal transcript
Invariant: the compaction boundary resets the provider context, not the visible conversation transcript.
04 · Serialization

Conversation objects become a dense text dialect

Tool calls and results are paired, noise is bounded, and repeated role prefixes are elided. The goal is high information density before rasterization.

INPUT OBJECTS
USER
Track down why the parser test is failing.
ASSISTANT · TOOL CALL
read(path="src/parser.ts")
TOOL RESULT
Large source listing with line numbers, imports, and the failing branch…
ASSISTANT
The branch treats an empty token as EOF. I’ll patch the guard.
2,000
chars / tool result
500
chars / arg value
2,000
chars / tool call
60 / 40
head / tail truncation
¶user:Track down why the parser test is failing.

¶call:read(path="src/parser.ts")//inspect parser
<out>
…bounded source listing… […middle elided…] …error tail…
</out>

¶ai:The branch treats an empty token as EOF.
I’ll patch the guard.
PAIRING

Result lives with its call

Tool results are indexed by call ID and merged into the originating ¶call: block. Orphans remain standalone.

SIGNAL

Tool output is visually dimmed

Zero-width control markers switch the native renderer to gray ink, so conversation text visually dominates tool noise.

ELISION

Useless pairs can vanish

A result explicitly flagged contextually useless—and its paired call—does not enter the archived source.

05 · Normalization + rasterization

Make the transcript printable, then turn cells into pixels

The TypeScript layer controls text shape and pagination. Rust owns the hot path from prepared page text to PNG bytes.

NORMALIZATION EXAMPLES
ANSI colorsstripped
spaces / tabssingle space
newline run█ one black cell
box drawing ├─ASCII +--
✅ / ⚠[OK] / [WARN]
decorative emojidropped
CJK-heavy textSilver font grid
unsupported glyphsfolded or “?”
Safety scan: auto shape selection can switch to the Silver Unicode grid when the default font would produce too many fallback glyphs.
Schematic frame · not production pixels
Higher-quality edge shape: more spacing, easier visual reading, fewer characters per frame.
TYPESCRIPT · snapcompact.ts

Orchestration

Serialize, normalize, choose shape, calculate cell geometry, paginate, plan HQ/LQ regions, and launch frame renders concurrently.

N-API BOUNDARY

renderSnapcompactPng

Prepared page text plus font, cell dimensions, ink variant, columns, repetition, and target width cross into native code.

RUST · snapcompact.rs

Raster + PNG

Draw bundled bitmap/TrueType glyphs, apply dim spans and newline cells, hug actual row height, encode PNG, return base64.

06 · Interactive archive lab

See when the archive becomes foveated

The real implementation is cell-aware and Unicode-aware. This calculator mirrors the core geometry with character-level approximations so the layout is understandable.

720,000 chars
80 frames
plain-text chronological edge high-quality image frames denser image center dropped oldest dense middle
resolved high shape
nominal columns × rows
nominal HQ chars / frame
persisted image frames
approx. chars dropped
full-frame token estimate
Approximation caveats: dim markers consume zero cells; CJK may consume two; two-column shapes wrap; final frame height can be shorter; provider token estimates are OMP’s implementation-side budgeting formulas, not universal pricing guarantees.
MODEL-AWARE GEOMETRY

Model ID chooses readability; wire API chooses billing

A Claude routed through another gateway still gets Claude-oriented glyph geometry. The API carrying the request determines image token estimation and detail hints.

Reader lineCurrent auto geometryFrame widthWhyBilling family
Claude Opus 4.7+ / Fable / Mythos11on16-bw1932 pxExtra tracking; high-res line can use a larger square under the visual-token cap.Actual request API
Older Claude11on16-bw1568 pxSame readable tracked glyphs, conservative size for lines that downscale larger inputs.Actual request API
Gemini 3.x8on22-bw2048 pxExtra leading keeps rows legible; OMP models image cost as fixed per image.Google
GPT / Codex8on22-bw1568 pxExtra leading; larger frames do not improve characters per estimated patch token.OpenAI
Kimi8on22-bw1568 pxCurrent source rule; image processing reportedly downscales beyond the useful range.Route-dependent
GLM8on16-bw1568 pxDenser 8×13 glyphs on a 16 px pitch.Route-dependent
CJK-heavy / unsafe fallbacksilver16-bwmodel defaultUnicode-focused Silver font when the bitmap shape cannot safely render the text.Actual request API
Source-of-truth note: the current Kimi rule in snapcompact.ts is 8on22-bw; one descriptive line in the compaction document appears to lag that implementation detail.
07 · Persistence + iterative compaction

The source text is authoritative; old PNGs are disposable

Every later Snapcompact pass unfolds the bounded prior archive source, appends newly retired history, replans the entire layout, and renders fresh frames.

CompactionEntry {
  type: "compaction",
  summary: "reading guide + FILES + HISTORY",
  firstKeptEntryId: "e07",
  tokensBefore: 184320,
  preserveData: {
    snapcompact: {
      text: /* bounded normalized source */,
      textHead: /* oldest verbatim edge */,
      frames: [
        {
          data: "iVBORw0KGgo…",
          mimeType: "image/png",
          cols: 175,
          rows: 120,
          chars: 20841,
          font: "8x13",
          variant: "bw"
        }
      ],
      textTail: /* newest verbatim edge */,
      totalChars: 612044,
      truncatedChars: 0
    }
  }
}
1 · Re-render, do not chain screenshots
The next pass reads Archive.text, not the prior frame pixels. This avoids compounding raster degradation.
2 · Chronological order is explicit
Rebuilt blocks are emitted oldest text → image middle → newest text, then the still-live recent messages.
3 · One text page pins each edge
The oldest and newest chronological edges stay plain text. The middle is the part converted to images.
4 · Foveation protects both image edges
When the image middle is too large, up to three HQ frames are retained at each side while the center uses a denser shape.
5 · Oldest dense middle fades first
If even the dense center exceeds maxFrames, its oldest slice is dropped and truncatedChars accumulates.
6 · File operations stay outside the pixels
Read/modified file lists are summarized in the textual guide so the current model has a crisp workspace map.
ARCHIVE CAP

80 frames default maximum

A caller may lower it, but the core compactor clamps the persisted frame count to the default upper bound.

REQUEST BODY CAP

3 MB base64 frame budget

On context rebuild, OMP keeps the newest frames that fit and inserts a chronological omission notice for older images.

IMAGE COUNT CAP

Provider-specific policy

Archive, system-prompt, and tool-result images share a per-request image budget.

08 · Guards + fallback behavior

What happens at the edges

OMP treats Snapcompact as one strategy inside a larger maintenance system, not as an unconditional replacement.

MODEL HAS NO IMAGE INPUT
Fall back to context-full summarization. The run emits a warning rather than creating an unreadable archive.
CUSTOM /compact INSTRUCTIONS
Use a directed LLM summary. Custom instructions imply semantic editorial intent, so the configured Snapcompact strategy is not used for that pass.
FRAME ARCHIVE CANNOT RECLAIM ENOUGH
Recovery machinery can fall back. Automatic maintenance must make measurable context progress; no-op loops are guarded.
REQUEST FRAME BYTES > 3 MB
Omit older image frames at replay time. Keep newest frames and both visible text edges, plus a gap notice.
UNSAFE GLYPH COVERAGE
Try the Silver Unicode shape. Auto resolution checks whether the selected font would turn too much content into fallback characters.
EXACT OLD DETAIL IS UNCLEAR
The reading guide tells the model to re-derive. It should re-read files or rerun commands rather than confidently guess from an ambiguous frame.
Why overflow recovery is possible: creating the archive itself does not send the overflowing prompt to another model. The expensive step is local rendering, so Snapcompact can operate when a normal summarization request could not fit.
09 · Related but separate

Archive compaction ≠ inline imaging

OMP also has a request-time transformer that can rasterize large prompt material without creating a compaction entry.

Snapcompact archive strategy

Runs when context maintenance chooses a compaction boundary.

  • Retires old history from the active context
  • Persists archive source and frames in preserveData
  • Re-attaches the archive on every context rebuild
  • Can replace the LLM summarization step

Snapcompact inline transformer

Runs per request after messages have been converted for the provider.

  • Can image AGENTS/context instructions or all system prompt text
  • Can image older large tool results, but keeps the freshest one as text
  • Requires at least 3,000 tool-result tokens and ≥10% estimated savings
  • Builds new request objects; it does not persist rendered images into session history
10 · Engineering assessment

What this design buys—and what it costs

Snapcompact is clever because it exploits a different provider billing and representation channel. It is not universally superior to a good semantic summary.

Strengths

+Deterministic archival pass. No summarizer temperature, no summary hallucination, no API credential dependency.
+Overflow-safe construction. It does not need to resend the already-overflowing text to create the replacement.
+More literal historical texture. Exact names, snippets, tool output tails, and turn ordering can survive where a summary may abstract them away.
+Provider-aware economics. Geometry is tuned to visual recall and image-token billing behavior.
+Idempotent source model. Recompaction starts from bounded source text, avoiding screenshot-of-screenshot degradation.

Costs / failure modes

Vision recall is imperfect. Tiny glyph OCR and visual attention can miss details, especially in dense middle frames.
Not byte-efficient. Base64 PNGs can inflate session storage and repeated HTTP request bodies.
Normalization changes representation. Whitespace collapses, unsupported symbols fold, and capped tool content loses its middle.
Economics are provider-specific. Image pricing, resizing, and model vision quality can change.
Bounded archive decay remains. Under sustained growth, the oldest dense center is eventually dropped.
Bottom line: this is best understood as a deterministic, model-readable archive tier—not as lossless compression and not as a replacement for all semantic state management.
11 · Practical knobs

How OMP exposes the behavior

The settings are separate so archive compaction can be enabled without also imaging system prompts or tool results inline.

compaction.strategy = "snapcompact"

Selects local bitmap archival instead of the usual summarizer for eligible compactions.

snapcompact.shape = "auto"

Lets model ID choose geometry and the request API choose billing estimation.

snapcompact.systemPrompt

Separate inline mode: none, context/AGENTS-style sections, or all prompt text.

snapcompact.toolResults

Separate inline switch for older large historical tool results.

# Conceptual settings paths
compaction.strategy      = "snapcompact"
snapcompact.shape        = "auto"
snapcompact.systemPrompt = "none"
snapcompact.toolResults  = false

# Manual behavior
/compact                 # honors configured strategy
/compact <instructions>  # directed LLM summary instead