Spotify Portal로 Claude Code 토큰 사용량을 90% 줄였다
TMThttps://engineering.atspotify.com/2026/9/portal-by-spotify-cut-my-claude-code-token-usage-by-90
AI 코딩 에이전트가 저를 대신해 하는 일은 대부분 생각하는 작업이 아닙니다. 입출력입니다.
메서드 하나를 묻는 질문에 답하려고 파일 다섯 개를 읽습니다. 옆에 놓인 테스트 파일 스무 개와 완전히 똑같은 패턴을 따르는 테스트 파일을 생성합니다. 회의가 끝나면 문서를 갱신합니다. 토큰은 수천 개씩 사라지는데 추론은 거의 하지 않습니다. 부담스러운 쪽은 사용자당 라이선스 요금이 아니라 토큰입니다. 게다가 그 일을 전부 최상위 모델에 떠넘기고 있는데, 이런 작업에 쓰기엔 한참 과분한 모델입니다. 허드렛일은 그만큼 잘 처리하는 더 저렴한 모델로 보내고, 비싼 모델은 정말 그 성능이 필요한 문제에 아껴 쓸 수 있다면 어떨까요?
이게 저만 겪는 문제는 결코 아닙니다. 2028년이 되면 AI 코딩 비용이 개발자 평균 연봉을 훌쩍 넘어설 것으로 전망됩니다. 엔지니어링 리더 네 명 가운데 한 명은 이미 개발자 한 명당 매달 200~500달러를 토큰에 쓰고 있습니다. 2,000달러를 훌쩍 넘기는 곳도 있습니다. 이런 도구는 충분히 값을 하지만, 그건 굳이 필요하지도 않은 작업에 최상위 모델 토큰을 태우는 일을 멈출 때만 그렇습니다.
알고 보니 해결책에는 플랫폼 팀도, 새 구독도 필요하지 않았습니다. 모드 두 개면 충분했습니다.
모드 두 개, 코드는 한 줄도 없이
Spotify Portal의 AiKA 모드는 바로 이런 용도를 겨냥해 만든 기능입니다. 모드는 일회성 런타임에서 실행되는 선언형 에이전트입니다. 에이전트를 위한 AWS Lambda라고 생각하면 됩니다. 지시문을 정의하고, 모델을 고르고, temperature 같은 파라미터를 설정하고, MCP 도구를 붙입니다. 나머지는 Portal이 알아서 처리합니다. 관리할 인프라도, API 키도, 계속 띄워 둘 서버도 없습니다. 모드는 Portal CLI나 API로 호출할 수 있습니다. 공개로 두어 회사 전체와 공유하거나, 비공개로 둘 수도 있습니다.
이 라우터를 돌리려고 모드를 두 개 만들었습니다. 아래 예시에서는 둘 다 워커 모델로 Gemini 2.5 Flash를 쓰지만, model 필드에는 Portal 인스턴스에 설정해 둔 모델을 무엇이든 넣을 수 있습니다. 각자 맞는 모델을 고르면 됩니다.
모드 1: bulk-reader
질문 하나에 답하려고 Claude가 큰 파일을 여러 개 읽어야 하는 상황에 씁니다.
name: bulk-reader
description: Bulk file reader for code analysis - delegates I/O from Claude Code
instructions: You are a precise code analyst. Read the provided files and answer the question concisely. Output structured bullets only. No greetings, no prose, no preambles. Lead every bullet with the exact name, type, or line number. Use nested bullets for details. Skip anything the caller did not ask for.
visibility: public
model: gemini-2.5-flash
resourceLimits:
temperature: 0.2
tags:
- coding
- delegation모드 2: code-writer
테스트, 설정 골격, 타입 스텁처럼 기존 패턴만 보면 결과물이 뻔히 예상되는 작업에 씁니다.
name: code-writer
description: Boilerplate code generator - delegates output-heavy work from Claude Code
instructions: You generate code files based on a spec and reference files. Match the existing patterns, conventions, naming, and style exactly. Output only the code — no explanations, no markdown fences unless asked. If the spec is ambiguous, make reasonable choices that match the reference code's patterns.
visibility: public
model: gemini-2.5-flash
resourceLimits:
temperature: 0.2
tags:
- coding
- delegation여기서 "코드만 출력하라"는 지시가 중요합니다. 이게 없으면 모델이 결과물을 마크다운 코드 펜스와 설명 문장으로 감싸 버리고, Claude는 그걸 다시 헤집어 읽어야 합니다.
라우팅
처음 만든 버전은 CLAUDE.md에 적어 둔 라우팅 규칙 한 덩어리였습니다. 어느 정도는 동작했습니다. Claude가 그 지시를 읽고 스스로 Portal로 넘겼습니다. 하지만 문제가 있었습니다. 그 규칙은 권고일 뿐 강제되지 않았습니다. Claude가 무시할 수도 있었습니다. 게다가 프로젝트마다 지시문 사본을 따로 둬야 했습니다.
지금 버전은 shunt라는 Claude Code 플러그인입니다. 위임은 Portal CLI 액션 레지스트리를 거치기 때문에, AiKA 플러그인을 켜 둔 Portal 인스턴스라면 어디서든 이 플러그인이 동작합니다.
1계층: 훅
Claude Code 훅은 모든 도구 호출 앞에서 실행됩니다. shunt는 PreToolUse 훅 두 개를 등록합니다.
check-file-size는 Read 호출마다 실행됩니다. 파일이 설정 가능한 줄 수 기준(기본값 350줄)을 넘으면 훅이 읽기를 막고, 대신 /bulk-reader 스킬을 쓰라고 Claude에게 알려 줍니다. 범위를 좁힌 읽기는 그대로 통과합니다. 어느 구간이 필요한지 Claude가 이미 알고 있기 때문입니다.
check-bash-read는 큰 파일을 대상으로 한 cat, head, tail, less, more를 잡아냅니다. 파이프로 이어진 명령(cat file | grep)은 범위를 좁힌 읽기라서 통과시킵니다.
기준값은 SHUNT_MIN_LINES 환경 변수로 조정합니다. 셸 프로파일이나 .claude/settings.json에 설정하면 됩니다.
{
"env": {
"SHUNT_MIN_LINES": "500"
}
}2계층: 스크립트
Portal CLI 호출을 감싼 bash 스크립트가 두 개 있습니다. Claude는 이름 붙은 인자를 넘겨 스크립트를 호출합니다. 요청을 만들고, 액션을 호출하고, 오류를 풀어내고, 토큰 사용량을 stderr로 알리는 일은 스크립트가 안에서 모두 처리합니다.
모드는 이름으로 지정하고, 그 이름이 어느 모드인지는 Portal이 찾아 줍니다. 대소문자를 구분하지 않고, 본인 모드를 먼저, 그다음 팀 모드, 마지막으로 공개 모드를 찾습니다. 공개된 bulk-reader를 포크해 자신에게 맞게 고쳐 두면 그 버전이 자동으로 우선합니다. 따로 설정할 것은 없습니다.
bulk-read는 경계가 분명하도록 파일마다 XML 태그로 감싼 뒤, 질문과 함께 bulk-reader 모드로 보냅니다.
bulk-read --question "What does this service do?" --paths src/Service.java src/Handler.java
# 후속 질문: 같은 경로로 한 번 더 물어봅니다
bulk-read --question "Which methods call the database?" --paths src/Service.java src/Handler.java위임은 매번 한 번으로 끝납니다. 호출은 일회성이고(서버에는 아무것도 저장되지 않습니다), 후속 질문에서 파일을 다시 보내도 정작 중요한 지점에서는 비용이 들지 않습니다. 파일 전체가 워커 모델로 가고 Claude의 컨텍스트에는 아예 들어오지 않기 때문입니다.
code-write는 명세와 참조 파일을 code-writer 모드로 보내고, 결과에서 마크다운 코드 펜스를 걷어낸 뒤, 디스크에 바로 쓸 수도 있습니다. 생성된 코드를 Claude는 전혀 보지 않습니다. 참조 파일은 반드시 있어야 합니다. 패턴을 맞춰 볼 파일이 없으면 워커가 맥락 없는 코드를 만들어 내고, 그 코드는 프로젝트 어디에도 맞지 않습니다.
code-write --spec "Write tests for UserService" --reference tests/OrderTest.java --target tests/UserTest.java
# 표준 출력으로 내보내기
code-write --spec "Generate a config stub" --reference config/existing.yaml3계층: 스킬
스킬 파일 두 개가 스크립트를 언제 그리고 어떻게 호출할지 Claude에게 알려 줍니다. 스킬은 설명과 사용 예시를 담은 마크다운 파일입니다. 훅이 읽기를 막으면 그 차단 메시지가 Claude를 /bulk-reader 스킬로 안내하고, 스킬에는 정확한 호출 문법이 적혀 있습니다.
이렇게 계층을 나눠 두면 한 단계가 작동하지 않아도 전체가 무너지지 않습니다. Claude가 스킬 설명을 읽지 않더라도 훅이 비용 큰 읽기를 여전히 막아 줍니다. 스킬은 그 우회를 좀 더 매끄럽게 만들어 줄 뿐입니다.
벤치마크
Java 모노레포를 대상으로 시나리오 네 가지를 시험했습니다. Claude가 파일을 직접 읽을 때 쓰는 토큰과, bulk-reader의 요약을 받아 읽거나 code-writer로 코드를 쓸 때 쓰는 토큰을 비교했습니다. bulk-read의 평균 절감률은 무려 90% 안팎이었습니다.
code-write 시나리오는 토큰으로 측정하기가 더 어렵습니다. shunt가 없으면 Claude가 참조 파일을 읽는 데다 결과물까지 비싼 출력 토큰으로 생성하기 때문입니다. shunt를 쓰면 코드가 디스크로 곧장 가고, Claude는 그 코드를 보지 않습니다.
잘 되지 않는 것
편집은 위임할 수 없습니다. 워커 모델이 만든 요약에는 믿을 만한 줄 번호가 들어 있지 않습니다. 분석 결과를 바탕으로 Claude가 코드를 고쳐야 한다면, 해당 구간은 여전히 직접 읽어야 합니다. 훅이 offset과 limit으로 범위를 좁힌 읽기는 허용하는 이유가 바로 이것이고, 그래서 위임으로 아끼는 토큰은 코드를 이해하는 단계에서 나옵니다.
추론은 위임할 수 없습니다. 제가 시험해 보니 워커 모델은 겉으로 드러난 패턴은 찾아냈지만, 미묘한 스레드 안전성 버그는 놓쳤습니다. Claude는 맥락만 제대로 받으면 몇 초 만에 그 버그를 잡아냈습니다. 그래서 이 라우팅에서는 디버깅, 아키텍처 결정, 안전이 중요한 코드를 명시적으로 제외했습니다.
지연 시간이 쌓입니다. 위임할 때마다 네트워크를 한 바퀴 돕니다. Claude Code에서 Portal 백엔드로, 다시 워커 모델로 갔다가 되돌아옵니다. 응답에는 보통 10~30초가 걸리고, Portal은 호출 한 번을 30초로 제한하기 때문에 아주 큰 생성 작업은 작은 호출 여러 개로 쪼개야 합니다. 큰 파일을 읽을 때는 감수할 만하지만, 작은 파일에서는 오히려 손해입니다. 줄 수 기준을 둔 이유가 이것입니다. 그 아래에서는 위임에 드는 부대 비용이 절감분보다 큽니다.
토큰 절감은 시작일 뿐
이 플러그인 자체는 Claude Code용 산출물이지만, 그 밑에 깔린 발상은 AiKA 모드로 굴리는 모델 라우팅입니다. 무게를 실제로 받치는 쪽은 모드입니다.
- 재사용할 수 있습니다. 같은 bulk-reader와 code-writer 모드가 모든 프로젝트에서, 그리고 Portal CLI를 셸로 호출할 수 있는 모든 도구에서 동작합니다.
- 공유할 수 있습니다. 두 모드는 AiKA에 공개되어 있습니다. 직접 만들지 않아도 누구나 오늘부터 쓸 수 있습니다.
- 조합할 수 있습니다. 문서 작업용 doc-writer 모드, 코드 리뷰 요약용 reviewer 모드, 다국어 지원용 translator 모드를 만들 수 있습니다. 하나하나가 클릭 몇 번이면 됩니다.
- 라우팅 결정과 워커를 떼어 놓습니다. 언제 위임할지는 플러그인이 정하고, 어떻게 답할지는 모드가 정합니다. Gemini Flash를 더 저렴한 모델로 바꾸거나, 시스템 프롬프트를 고치거나, MCP 도구를 붙여도 플러그인은 그대로입니다.
AiKA 모드의 진짜 힘이 여기 있습니다. 모델 라우팅을 시스템 엔지니어링 문제에서 설정 문제로 바꿔 놓습니다. 인프라를 만들 필요가 없습니다. 원하는 것을 적고 이름만 붙이면 됩니다.
직접 해 보기
spotify/portal-ai-plugins 마켓플레이스에서 두 플러그인을 설치합니다.
- claude plugin marketplace add spotify/portal-ai-plugins
- claude plugin install portal@portal
- claude plugin install shunt@portal
portal 플러그인은 shunt가 위임에 사용하는 Portal CLI를 제공합니다.
- 새 Claude Code 세션에서
/portal:setup을 실행해 Portal 인스턴스에 맞춰 Portal CLI를 설정하고 인증합니다. - 준비가 끝났습니다. 파일 여러 개에 걸친 질문을 던져 보면 됩니다.
bulk-reader와 code-writer 모드는 이미 공개되어 있어서 따로 만들 것이 없습니다. 워커 모델을 바꾸거나 지시문을 고쳐 쓰고 싶다면 Portal에서 포크하면 되고, 그러면 그 버전이 자동으로 우선 적용됩니다.
모드는 여러 프로젝트에서 재사용할 수 있고 팀과 공유할 수도 있습니다. 라우팅은 플러그인이 강제하니 신경 쓰지 않아도 됩니다. 모드에 대해 더 알아보기