Scopelet

For Claude Code, Codex and OpenCode

Your agent reads a 17 KB test log to learn one thing.
Send it the one thing.

Scopelet sits on the hook your coding agent already has. When a command prints something large, the model reads a bounded view instead: failures, diagnostics and their locations first, repeats counted, every gap declared. The exact original bytes stay on your disk, one command away. No second model, no API key, no proxy.

See it

A Jest run prints 481 results. One of them matters.

Without Scopelet17,549 bytes
> app@1.4.2 test
> jest --runInBand

PASS  src/modules/module0.test.js
PASS  src/modules/module1.test.js
PASS  src/modules/module2.test.js
        ... 237 more PASS lines ...
FAIL  src/auth/session.test.js
  ● session › refreshes an expiring token

    expect(received).toBe(expected)

    Expected: 1735689600
    Received: 1735689599

      at Object.<anonymous> (src/auth/session.test.js:42:31)
PASS  src/modules/module240.test.js
        ... 239 more PASS lines ...

Test Suites: 1 failed, 480 passed, 481 total
Tests:       1 failed, 1327 passed, 1328 total
Time:        84.113 s
With Scopelet542 bytes
[scopelet v5 47487d02d1c0 omitted=0 abridged=1;
 gaps are not absence]
1-3
 > app@1.4.2 test
 > jest --runInBand

4 similar=480 last=492 PASS  src/modules/module0.test.js
244-252
 FAIL  src/auth/session.test.js
   ● session › refreshes an expiring token

     expect(received).toBe(expected)

     Expected: 1735689600
     Received: 1735689599

       at Object.<anonymous> (src/auth/session.test.js:42:31)
493-496

 Test Suites: 1 failed, 480 passed, 481 total
 Tests:       1 failed, 1327 passed, 1328 total
 Time:        84.113 s

The failure keeps its expected value, its received value and its stack frame. The 480 passes become one line that still says how many there were and where the last one was. The header says what the view cost: omitted=0 means every line is shown or folded into a counted group, and the ID names the original, still on disk byte for byte.

How it works

  1. A command finishes

    Claude Code and OpenCode hand its output to Scopelet's hook. Codex runs recognized commands through scopelet run --auto, after its own approval.

  2. Small outputs pass untouched

    Up to 2 KiB, or 16 KiB for a file read, the model reads exactly what was printed. Most outputs end here.

  3. The command picks a profile

    Tests, search, Git, logs, file reads and installs each get a budget that fits what their output is for, from 2 KiB for an install to 16 KiB for a file.

  4. A bounded view is built

    Terminal noise is dropped, repeats are counted, the first occurrence of each diagnostic is kept with its location, and the first and last lines always survive.

  5. Only if it pays

    The view replaces the output only when it saves at least 20% and 512 bytes, its own metadata included. Otherwise the original goes through as printed.

  6. The original is kept

    The exact bytes go to a local content-addressed store. Any line is one expand away, and recovery is byte-exact or it fails loudly.

What it promises, and what it does not

Nothing leaves the machine

No other model summarizes anything, no API traffic is intercepted, and the decision journal records program names and sizes only, never content or arguments.

Every gap is declared

A view counts what it left out in its first line. Gaps are not absence: a partial view never claims an exhaustive search or an exact count.

Deterministic

The same output gives the same view. Content fixtures are pinned by SHA-256, and a change that drops a diagnostic fails the build.

Out of the way

Small outputs, other tools, MCP results and outputs the host already saved to a file pass through. If anything inside Scopelet fails, the hook steps aside and the agent gets the output as printed. scopelet mode off idles the hooks in one command.

Repeats and loops

In Claude Code, an output the conversation has already seen becomes a one-line reference. When the same failure comes back three times in one turn, the agent gets a single note to rethink instead of re-running.

Honest about cost

Bytes are not tokens and no figure here is a bill. Whole-session cost depends on the host, the model and the task; the benchmarks say how they were measured.

The numbers

Each row is a real command output hiding one fact an agent needs. Printed is what the command wrote; read is what reaches the model instead. Every figure is rebuilt and checked against the shipped binary on every change.

What the command printedWhat the agent reads insteadPrintedReadRemoved
480 passing tests, one failureThe failing test with expected value, received value and stack frame; the passes as one counted line17,54954296.9%
A retry loop hiding one fatal errorThe retry line once, marked repeat=1000, then the fatal line with its line number28,03916399.4%
1000 progress lines, then two diagnosticsBoth diagnostics word for word; the progress as one counted line136,06330499.8%
A receipt buried in the middle of a logThe receipt line at line 501, amount and currency exact136,19342899.7%
A 1000-row JSON arrayA CSV table of the first rows, the failed one and the last; constant columns named once171,8343,20998.1%
A 32-byte command outputThe 32 bytes exactly as printed3232untouched

In real sessions

Live A/B campaigns run real, billed Claude Code sessions on sixteen synthetic tasks in paired rounds, with and without Scopelet, and judge each arm by what it was billed.

−9%average billed cost per session, 95% interval below zero
96 / 96tasks right with Scopelet, and 96 / 96 without: no quality given up
0extra model calls, API keys or proxies

Scopelet 1.2.4 against no Scopelet, Claude Code 2.1.318 with Haiku, six paired rounds, 192 sessions, November 2026. Whole-session cost depends on your host, model and task: measure your own setup before quoting a percentage. Every campaign, its intervals and everything that went wrong are in the benchmark report.

Compression time is in milliseconds: a 3 MB log in a few tens of them on an Apple Silicon laptop. The current figures are in the README, measured on every release.

Nothing is lost

Every view names the artifact that holds the original. Reading it back does not involve the model, and a partial view tells the agent to recover the exact bytes before editing something it only saw a summary of.

$ scopelet expand last --find 'Received:' --context 3
$ scopelet expand 3f9c2d1e --find 'panick(ed)? at' --regex
$ scopelet expand blob:HASH --start 240 --end 260
$ scopelet expand blob:HASH --raw > original.log

Install

With the skill (Node.js 22.20+)

$ npx skills add maxgfr/scopelet --skill scopelet \
    --global -a codex claude-code opencode -y
$ node "$HOME/.agents/skills/scopelet/scripts/scopelet.mjs" install --agent all
$ node "$HOME/.agents/skills/scopelet/scripts/scopelet.mjs" doctor

With Homebrew

$ brew install maxgfr/tap/scopelet
$ scopelet install --agent all
$ scopelet doctor

Then restart your agent sessions. In Codex, trust the new hooks through /hooks. Compression is automatic from the next prompt; scopelet mode off idles it and scopelet uninstall --agent all removes it. Binaries cover macOS and Linux on Intel and ARM.