feature
Jul 26, 2026RCLM's hook layer now detects images in tool results and downscales them before they enter your agent's context — measured token savings on Claude Code, measurement-only on Codex.
RCLM's hook layer now detects images inside tool results — screenshots, UI captures, anything read as an image file or returned by a screenshot-capable MCP tool — and downscales them before they're sent back to the model. This is opt-in, off by default, and ships first for Claude Code sessions, with measurement-only support for Codex.
The motivation is simple: a full-page screenshot from Playwright — the browser automation MCP server most agentic coding setups reach for when they need to look at a rendered page — routinely comes in at 3000+ pixels tall. Nothing about debugging a layout or reading a button label requires that resolution. And because tool results are resent on every subsequent turn of a session, an oversized screenshot taken early gets paid for again and again — the cost compounds with every turn that follows it.
Enable it with:
rclm-hooks-install --image-lifecycle
Once enabled, RCLM's PostToolUse hook inspects tool results for a base64-encoded image, across the shapes we've seen in practice: a native file read, an MCP tool's image content block (Playwright's browser_take_screenshot is the common case), and the standard MCP tool-result wrapper — which, we learned while building this, sometimes duplicates the image in two places at once. Both copies need rewriting, or you haven't actually saved anything. If the image is over a configurable size threshold, it's resized to a maximum dimension (1280px by default, configurable via --image-max-dim) and re-encoded — JPEG for most images, PNG preserved if the image has a meaningful alpha channel. Images are never upscaled.
The savings are tracked as a new image_downscale mechanism, alongside RCLM's existing hook-level reduction mechanisms (search-result shaping, read caching, exec-output compaction). It reports real, measured before/after token estimates — not a guess — using published per-provider image-token formulas (Anthropic's and OpenAI's own documented dimension-based calculations). In one of our own test sessions, a single screenshot read went from an estimated 2,096 tokens to 6 after downscaling. That's not a number we'd generalize from one session, but it's a real, measured one — and it's the kind of number a Playwright-driven session racks up repeatedly, once per screenshot, for every turn that follows it.
The rewrite itself — actually replacing the image the model sees — only works on Claude Code today. We verified this directly: Claude Code's PostToolUse hook can be made to return a smaller image in place of the original, and the model does see the smaller one.
Codex support is measurement-only. We looked into rewriting Codex's tool output for MCP-sourced images (Playwright screenshots included) and found that the mechanism Codex CLI exposes for it doesn't currently apply the change — the hook runs, but the platform doesn't honor the rewrite. So for Codex sessions with --image-lifecycle enabled, you'll see accurate before/after numbers in your session stats, but the model still receives the original image. We'd rather report that honestly than claim a capability that isn't real. If a future Codex CLI release fixes this, we'll turn it on.
Gemini CLI, Cursor, and OpenClaw don't have image-lifecycle support yet in either direction.
Alongside downscaling, we've shipped the groundwork for a second mechanism: detecting when a new image supersedes an older one from the same context (the same tool, the same page, the same viewport — exactly the pattern a Playwright session produces when it screenshots the same page repeatedly across a debugging loop) and estimating what evicting the stale one would save. This one is shadow-only — it measures and reports, but never rewrites anything, on any provider, regardless of settings. Actually evicting a stale image from context means mutating an earlier turn, which invalidates the model's prompt cache for everything downstream of it. We don't yet have enough real cache-usage data to say confidently when that tradeoff is worth making, so for now it's purely informational, and shown separately from the measured downscaling savings rather than added to them.
The default 1280px cap is a guess at "enough for an agent to read UI text without needing full resolution." If you're in a session where the agent needs to read genuinely fine print in a Playwright screenshot and it's struggling, that's exactly the edge case we want to hear about — the cap is configurable, but we'd rather learn from real sessions than guess at defaults forever.
We're also watching whether the stale-image detection heuristic is too coarse or too narrow in practice — it currently falls back to matching on tool name alone when a tool doesn't expose recognizable page or viewport arguments, a deliberately conservative choice we're not fully confident in yet.
The downscaling path is built to fail open: any decode error just passes the original image through untouched, so a broken or missing image should never be something this feature caused. If you see one anyway, tell us.