Skip to content

Claude Code

Spotify’s shunt blocks Claude Code reads over 350 lines

7 min read

Written by an AI model from the linked sources and checked against them by a second model. How we work

All about: Claude Code versions and changes →
Image: engineering.atspotify.com

A Claude Code plugin called shunt intercepts large file reads and hands them to Gemini 2.5 Flash running inside Portal by Spotify. Across four test scenarios, mean savings on bulk reads came to about 90%, according to a September 4 post on Spotify’s engineering blog (Atspotify). What makes it work is the enforcement. The routing is not a polite request in a prompt. A hook refuses the read before Claude ever sees the file.

The author’s starting point is that most of what a coding agent does is I/O, with very little thinking involved: reading five files to answer a question about one method, writing a test that copies the pattern of the twenty tests next to it, updating docs after a meeting. The post puts numbers on the bill. A quarter of engineering leaders already spend $200–$500 per developer per month on tokens, some spend well past $2,000, and AI coding costs are expected to pass the average developer’s salary by 2028. The post’s answer is to give the grunt work to a cheaper model and keep the frontier model for problems that need it.

What a mode is

The worker side runs on AiKA Modes. AiKA is the AI knowledge assistant Spotify built for its own teams and now sells as part of Portal. A mode is a declarative agent on an ephemeral runtime, which the post describes as “think AWS Lambda, but for agents.” You write the instructions, pick a model, set parameters such as temperature and attach MCP tools. Portal runs it, so there are no servers to keep up and no API keys to manage. Modes can be called from the Portal CLI or the API, and they can be public to the whole company or private.

Shunt uses two modes. Both run Gemini 2.5 Flash at temperature 0.2, though the model field accepts any model configured in your Portal instance.

  • bulk-reader covers the case where Claude would otherwise read several large files to answer one question. Its instructions ask for “structured bullets only”, with every bullet led by “the exact name, type, or line number”, and nothing the caller did not ask for.
  • code-writer handles tests, config scaffolding, type stubs and other output you can predict from existing patterns. It is told to match the reference code’s conventions exactly and to “Output only the code”.

The author says that last instruction matters. Without it the model wraps everything in markdown fences and explanatory prose, and Claude then has to dig through it.

From CLAUDE.md to hooks

The first version was a block of routing rules in CLAUDE.md. Claude would read them and sometimes route itself to Portal. “The rules were advisory, not enforced,” the author writes. Claude could ignore them, and every project needed its own copy. The current version is a plugin that delegates through the Portal CLI actions registry, so it runs against any Portal instance with the AiKA plugin enabled. It is built in three layers.

The first layer is two PreToolUse hooks. In Claude Code these fire before a tool call runs, and per Anthropic’s hooks documentation they can block it by returning permissionDecision: "deny". check-file-size fires on every Read. If the file is longer than a threshold, 350 lines by default, the hook blocks the read and tells Claude to use the /bulk-reader skill. Targeted reads with an offset and limit go through, because Claude already knows which section it wants. check-bash-read closes the obvious loophole by catching cat, head, tail, less and more on large files. Piped commands such as cat file | grep pass, since they count as targeted reads. The threshold lives in the SHUNT_MIN_LINES environment variable, set in your shell profile or in .claude/settings.json as { "env": { "SHUNT_MIN_LINES": "500" } }.

The second layer is two bash scripts that wrap the Portal CLI. Claude calls them with named arguments, and they build the request, invoke the action, unwrap errors and report token usage to stderr. bulk-read wraps each file in XML tags so the boundaries are clear, then sends the files and the question to the mode:

bulk-read --question "What does this service do?" --paths src/Service.java src/Handler.java

Each delegation is one shot, and nothing is stored on the server. A follow-up question re-sends the same files, which costs Claude nothing, because the files go to the worker model and never enter Claude’s context. code-write takes a spec and a reference file, strips markdown fences from the output and can write straight to disk with --target, so Claude never sees the generated code. The reference file is required. Without it, the author notes, the worker would produce context-free code “that fits nothing in your project.”

Portal resolves modes by name, case-insensitively, looking first for your own mode, then your team’s, then public ones. If you fork the public bulk-reader, your version takes over with no configuration.

The third layer is two skills, markdown files with a description and usage examples. When a hook blocks a read, its message points Claude to the skill with the exact syntax. The layers are meant to fail gently: if Claude skips the skill description, the hook still stops the expensive read.

What the 90% measures

The benchmark compared the tokens Claude would spend reading files directly with the tokens it spends reading the bulk-reader’s summary. It ran four scenarios on a Java monorepo. The roughly 90% mean comes from that bulk-read comparison alone, so the headline number covers only reads, in four scenarios, in one codebase.

The author did not put a token figure on code-write, saying it is harder to measure. Without shunt, Claude reads the reference files and then produces the code as output tokens. With shunt, the code goes to disk and skips Claude entirely. That second part may be where much of the money is, given that output tokens in Claude Code cost about 5x what input does, by Anthropic’s August breakdown of a session bill.

Where delegation stops

Editing can’t be delegated. The worker’s summaries don’t carry reliable line numbers, so before Claude edits anything it still has to read the relevant section itself. That is why the hooks let offset-and-limit reads through. The savings apply to understanding code. They don’t apply to changing it.

Reasoning can’t be delegated either. In the author’s testing the worker model found surface-level patterns but missed a subtle thread-safety bug, which Claude spotted “in seconds once given the right context.” The routing rules exclude debugging, architectural decisions and safety-critical code.

Then there is latency. Every delegation is a network round trip from Claude Code to the Portal backend to the worker model and back. Responses typically take 10–30 seconds, and Portal caps a single invocation at 30 seconds, so the slow end of a normal response already sits at the limit. Very large generations have to be split into smaller calls. Below the line threshold, the wait costs more than the tokens it saves, which is why the threshold exists.

Swapping the worker

The plugin decides when to delegate, and the mode decides how to respond. You can switch to a model cheaper than Gemini Flash, rewrite the system prompt or add MCP tools without touching shunt. The post suggests more modes built the same way: a doc-writer, a reviewer for code review summaries, a translator for i18n. In the author’s words, modes turn model routing “from a systems engineering problem into a configuration problem.”

Both plugins install from the spotify/portal-ai-plugins marketplace with claude plugin marketplace add spotify/portal-ai-plugins, then claude plugin install portal@portal and claude plugin install shunt@portal. The portal plugin supplies the CLI that shunt delegates through, and running /portal:setup in a new Claude Code session authenticates it against your Portal instance. The bulk-reader and code-writer modes are already public, so there is nothing to create. To use a different worker model or different instructions, fork them in Portal.

No comments yet. Be the first.

Join the conversation

Sign in to leave a comment. It appears after moderation.