Computer use in Claude Code: fewer tokens for every desktop read
Downshift by Tiago Vilas Boas. Updated
Downshift here is a Go tool for AI coding agents, not the React downshift autocomplete library and unrelated to any car transmission.
TL;DR
Desktop agents read the whole screen after every click. With agent-desktop, that read is an accessibility tree in JSON, not a screenshot. Downshift re-encodes it one line per element with every field kept, and sends a repeat read of the same window as only the lines that changed. On synthetic fixtures a read, act, verify loop came out 84.9% smaller; a live desktop is still to be measured.
Why computer use burns tokens
An agent that drives a desktop app works in a loop: read the window, act on one element, read the window again to check what happened. Every read lands in the context, and most of it is the same as the read before.
Reading the accessibility tree as JSON is already far smaller than an image of the screen. The JSON still repeats every key name, quote mark and the snapshot id inside every element ref, and the verify read repeats the whole window to show that one button changed.
Step one: the compact view
Downshift rewrites agent-desktop snapshot and agent-desktop find through downshift compact and prints one line per element, indented by depth. Refs are written eN under a legend, the action list most elements share is written once, and states, bounds, native ids and classes get short forms. Any field without a short form is written as JSON, so nothing is dropped. A test decodes the view back to the same JSON.
agent-desktop snapshot (envelope 2.6) app="Chat" complete=true ref_count=175 snapshot_id="s9x0lmz4"
refs: eN means @s9x0lmz4:eN
actions: an eN line without actions= has Click; actions=- means none
window "general - Acme - Chat"
group "Sidebar"
tree "Channels"
e5 treeitem "# general" [selected] .sidebar-item
group "Channel"
e174 textfield "Message #general" actions=Click,SetFocus .editor ph="Message #general"
e175 button "Send now" [disabled]
Step two: only what changed
The tool numbers elements the same way while the window does not change; only the snapshot id is new, and older refs stay valid. So a line that reads the same in both views is the same element with the same ref. A repeat read of the same window, within 10 minutes, comes back as the changed lines:
delta from snapshot s9x0lmz4 (same window, read 4s ago): 2 of 212 lines changed.
@@ line 211
e174 textfield "Message #general" actions=Click,SetFocus .editor ph="Message #general"
- e175 button "Send now" [disabled]
+ e175 button "Send now"
[downshift compact: compacted 26839 to 668 bytes; full output: downshift retrieve d3bb124d09d8]
The delta is sent only when both reads are complete, the raw read is kept locally so downshift retrieve can bring it back whole, and the delta is under 60% of the view. Otherwise the full view goes out.
How much smaller
Measured with the downshift binary on synthetic reads built to the tool's output schema, not on a live desktop. Bytes include the marker line.
| Read | Raw bytes | Printed bytes | Saving |
|---|---|---|---|
| File manager window, first read (219 refs) | 30,272 | 14,183 | 53.1% |
| Chat app window, first read (175 refs) | 26,861 | 10,802 | 59.8% |
find, 18 buttons | 3,899 | 1,455 | 62.7% |
| Same chat window after one action (2 lines changed) | 26,839 | 764 | 97.2% |
| Same chat window, nothing changed | 26,839 | 567 | 97.9% |
| Read, act, verify: the three chat reads | 80,539 | 12,133 | 84.9% |
The tool's own -i, --compact and --skeleton flags shrink the tree first; Downshift stacks on top. Every read is counted in downshift report, downshift stats and the session panel, with bytes read back through retrieve subtracted.
Turn it on
In Claude Code with the Downshift hook there is nothing to do: the read is rewritten for you. In any other harness, or a script, the agent runs the read through the compactor, and both steps apply:
downshift compact -- agent-desktop snapshot --app Files -i
Set DOWNSHIFT_DESKTOP_DELTA=0 to send every read whole. The MCP form of the tool is not compacted, because Downshift does not see MCP results.
Limits
- Agents that share a session, or direct calls from one directory, share the delta scope. An agent can get a delta against a read it never saw; the delta says so and points to
downshift retrieve. - A new element early in the tree renumbers the refs after it, and the full view is sent instead.
- Every figure here is from synthetic reads. Run the same task with
DOWNSHIFT_EXEC=0and with the hook on, and comparedownshift report.
Frequently asked questions
Does Downshift take screenshots or drive the desktop?
No. Downshift does not install or run a desktop driver. It only shortens what agent-desktop prints when the agent reads the screen.
Is anything lost in the compact view?
No field is dropped. A test decodes the view back to the same JSON, and the raw read stays one downshift retrieve away.
Does it work outside Claude Code?
Yes. Claude Code rewrites the read automatically. In other harnesses the agent runs downshift compact -- agent-desktop snapshot ..., and the delta is scoped to the working directory.
How much does it save?
On synthetic reads, 53–60% on a first read, about 97% on a repeat read after one action, and 84.9% over a read, act, verify loop of three reads. It has not been measured on a live desktop yet.
Install
Run downshift setup --dry-run first to preview every change. downshift setup --undo restores your backups.
curl -fsSL https://raw.githubusercontent.com/tiagovilasboas/downshift-ai/main/install.sh | sh && downshift setupClaude Code plugin
/plugin install downshift --marketplace tiagovilasboas/downshift-aiRelated guides
Sources
- Downshift guidemeasured
docs/guides/agent-desktop.md
how the view and the delta work, the conditions and the limits - Downshift fixturessynthetic
internal/compressor/testdata/corpus
the reads behind the table, built to the tool's output schema; measured with the downshift binary on 2026-11-09 - Round-trip testmeasured
agent_desktop_roundtrip_test.go
decodes the compact view back to the same JSON