Come Spotify ha tagliato del 90% i costi di Claude con Portal e due semplici ‘mode’

La maggior parte del lavoro che fa un agente AI per il coding non è ragionamento. È I/O puro.

Leggere cinque file per rispondere a una domanda su un singolo metodo. Generare un test che segue lo stesso identico pattern di altri venti test già presenti. Aggiornare la documentazione dopo un meeting. Migliaia di token bruciati, ragionamento vicino allo zero. Il problema non è la licenza: sono i token. E li stai dando in pasto a un modello frontier che è clamorosamente sovradimensionato per quello che gli stai chiedendo.

E se potessi instradare il lavoro di routine verso qualcosa di più economico che lo gestisce altrettanto bene, risparmiando il modello costoso solo per i problemi che ne hanno davvero bisogno?

Il problema non è solo di Spotify

Entro il 2028 i costi dell’AI per il coding sono destinati a superare lo stipendio medio di uno sviluppatore. Un quarto dei responsabili engineering brucia già tra 200 e 500 dollari al mese per sviluppatore solo in token. Alcuni superano i 2.000 dollari. Gli strumenti si ripagano da soli, certo — ma solo se smetti di incenerire token frontier su lavoro che non ne ha bisogno.

La soluzione? Non ha richiesto un platform team o un nuovo abbonamento. Solo due ‘mode’.

Due mode, zero codice da scrivere

È esattamente il tipo di caso d’uso per cui sono nate le AiKA Modes in Portal by Spotify. Una mode è un agente dichiarativo che gira su un runtime effimero — pensate ad AWS Lambda, ma per agenti. Definisci le istruzioni, scegli un modello, imposti parametri come la temperatura e alleghi strumenti MCP. Portal gestisce tutto il resto.

Niente infrastruttura da mantenere, niente API key sparse, niente server sempre accesi. Le mode sono richiamabili dalla CLI di Portal o via API. Possono essere pubbliche (condivise con tutta l’azienda) o private.

Per far funzionare questo router sono state create due mode. Entrambe usano Gemini 2.5 Flash come modello worker negli esempi, ma il campo model accetta qualsiasi modello configurato nella tua istanza Portal. Scegli quello che preferisci.

Mode 1: bulk-reader

Per quando Claude leggerebbe altrimenti più file pesanti solo per rispondere a una domanda.

name: bulk-reader
description: Bulk file reader for code analysis
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.
visibility: public
model: gemini-2.5-flash
temperature: 0.2

Mode 2: code-writer

Per test, scaffolding di configurazioni, type stub o qualsiasi cosa dove l’output è prevedibile da pattern esistenti.

name: code-writer
description: Boilerplate code generator
instructions: You generate code files based on a spec and reference files. Match existing patterns exactly. Output only the code — no explanations, no markdown fences unless asked.
visibility: public
model: gemini-2.5-flash
temperature: 0.2

Quella istruzione ‘output only the code’ è importante. Senza, il modello avvolge tutto in markdown fence e prosa esplicativa che Claude deve poi parsare.

Il routing: come funziona davvero

La prima versione erano regole di routing scritte in CLAUDE.md. Funzionava… più o meno. Le regole erano consigli, non vincoli. Claude poteva ignorarle. E ogni progetto aveva bisogno della propria copia delle istruzioni.

La versione attuale è un plugin di Claude Code chiamato shunt. La delega passa attraverso il registro azioni della CLI di Portal, quindi il plugin funziona con qualsiasi istanza Portal con il plugin AiKA attivo.

Layer 1: gli hook

Gli hook di Claude Code si attivano prima di ogni chiamata a strumento. Shunt registra due hook PreToolUse:

check-file-size scatta a ogni chiamata Read. Se il file supera una soglia configurabile di righe (default: 350), l’hook blocca la lettura e dice a Claude di usare invece lo skill /bulk-reader. Le letture mirate passano — Claude sa già quale sezione gli serve.

check-bash-read intercetta cat, head, tail, less e more su file grandi. I comandi con pipe (cat file | grep) passano, perché sono letture mirate.

La soglia è configurabile tramite la variabile d’ambiente SHUNT_MIN_LINES. Impostala nel tuo profilo shell o in .claude/settings.json:

{
  'env': {
    'SHUNT_MIN_LINES': '500'
  }
}

Layer 2: gli script

Ci sono due script bash che wrappano le chiamate alla CLI di Portal. Claude chiama uno script con argomenti nominati. Gli script gestiscono tutto internamente: costruire la richiesta, invocare le azioni, scartare errori, riportare l’uso dei token su stderr.

Le mode sono indirizzate per nome e risolte da Portal: senza distinzione maiuscole/minuscole, preferendo la tua mode, poi quella del tuo team, poi quelle pubbliche. Fai un fork della bulk-reader pubblica in una versione personalizzata e la tua prende automaticamente la precedenza — zero configurazione.

bulk-read avvolge ogni file in tag XML per delimitazioni chiare e li invia alla mode bulk-reader insieme alla domanda.

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

Ogni delega è one-shot. L’invocazione è effimera (niente viene salvato server-side) e reinviare i file in un follow-up è gratis dove conta: il corpus va al modello worker e non entra mai nel contesto di Claude.

code-write invia una specifica e un file di riferimento alla mode code-writer, rimuove i markdown fence dall’output e può scrivere direttamente su disco. Claude non vede mai il codice generato. Il riferimento è obbligatorio: senza un file da cui copiare i pattern, il worker genererebbe codice senza contesto che non si adatta a nulla nel tuo progetto.

code-write --spec 'Write tests for UserService' --reference tests/OrderTest.java --target tests/UserTest.java

Layer 3: le skill

Due file skill dicono a Claude quando e come chiamare gli script. Le skill sono file markdown con una descrizione e esempi d’uso. Quando l’hook blocca una lettura, il messaggio di blocco punta Claude verso la skill /bulk-reader, che mostra l’esatta sintassi di invocazione.

Questa stratificazione significa che il sistema degrada in modo elegante. Anche se Claude non legge la descrizione della skill, l’hook blocca comunque la lettura costosa. La skill rende solo il redirect più fluido.

I benchmark: quel 90% non è clickbait

Testato su un monorepo Java attraverso quattro scenari, misurando i token che Claude consumerebbe leggendo file direttamente vs. consumando il riassunto di bulk-reader o scrivendo codice via code-writer. Il risparmio medio di bulk-read si è attestato intorno a un clamoroso 90%.

Lo scenario code-write è più difficile da misurare in token perché senza shunt Claude sia legge i file di riferimento che genera l’output come costosi token di output. Con shunt, il codice va dritto su disco. Claude non lo vede mai.

Cosa non funziona (perché no, non è magia)

Non puoi delegare l’editing. I riassunti del modello worker non includono numeri di riga affidabili. Se Claude deve fare modifiche basate sull’analisi, deve comunque leggere direttamente la sezione specifica. Gli hook permettono letture mirate (con offset/limit) proprio per questo, quindi la delega risparmia token sulla comprensione.

Non puoi delegare il ragionamento. Il modello worker ha trovato pattern superficiali ma ha perso un bug sottile di thread-safety nei test. Claude l’ha individuato in secondi una volta dato il contesto giusto. Il routing esclude esplicitamente debugging, decisioni architetturali e codice safety-critical.

La latenza si accumula. Ogni delega è un round-trip di rete: Claude Code al backend Portal al modello worker e ritorno. Le risposte richiedono tipicamente 10-30 secondi, e Portal limita una singola invocazione a 30 secondi, quindi generazioni molto grandi vanno divise in chiamate più piccole. È accettabile per letture grandi, controproducente per quelle piccole. La soglia di righe esiste per questo: sotto quella soglia l’overhead della delega supera i risparmi.

I risparmi di token sono solo il punto di partenza

Il plugin è un artefatto di Claude Code, ma l’idea sotto è il model routing alimentato dalle mode AiKA. Le mode sono il pezzo che regge tutto:

Sono riutilizzabili. Le stesse mode bulk-reader e code-writer funzionano su ogni progetto e ogni strumento che può chiamare la CLI di Portal.

Sono condivisibili. Entrambe le mode sono pubbliche in AiKA. Chiunque può usarle oggi senza crearne di proprie.

Sono componibili. Potresti creare una mode doc-writer per la documentazione, una mode reviewer per riassunti di code review, una mode translator per i18n. Ognuna è a pochi click di distanza.

Disaccoppiano la decisione di routing dal worker. Il plugin decide quando delegare. La mode decide come rispondere. Sostituisci Gemini Flash con un modello più economico, cambia il prompt di sistema, aggiungi strumenti MCP — il plugin non cambia.

Questo è il vero potere delle mode AiKA: trasformano il model routing da problema di systems engineering a problema di configurazione. Non costruisci infrastruttura. Descrivi cosa vuoi e gli dai un nome.

Provalo tu stesso

Installa entrambi i plugin dal marketplace spotify/portal-ai-plugins:

claude plugin marketplace add spotify/portal-ai-plugins
claude plugin install portal@portal
claude plugin install shunt@portal

Il plugin portal fornisce la CLI di Portal attraverso cui shunt delega.

In una nuova sessione Claude Code, esegui /portal:setup per configurare e autenticare la CLI di Portal contro la tua istanza Portal.

Sei a posto. Basta fare una domanda che attraversa più file.

Le mode bulk-reader e code-writer sono già pubbliche, quindi non c’è niente da creare. Se vuoi personalizzarle — modello worker diverso, istruzioni diverse — fai un fork in Portal e la tua versione prende automaticamente la precedenza.

Le mode sono riutilizzabili tra progetti e condivisibili col tuo team. Il plugin impone il routing, quindi non devi pensarci.

AI LABELS_3x2_3_black