Il punto in cui la maggior parte delle deleghe fallisce non è la definizione dell’agente: è ciò che il genitore dimentica di scrivergli. Un subagent parte con la memoria vuota, e nessuna quantità di prompt engineering nel suo system prompt recupera un percorso di file che non gli hai passato.

Definire e invocare

Nell’Agent SDK i subagent si dichiarano nel parametro agents e Claude li chiama attraverso il tool Agent. Obbligatori sono solo description e prompt; il resto serve a stringere il perimetro:

description     quando usare questo agente (guida la scelta automatica)
prompt          il system prompt dell'agente
tools           tool ammessi; se omesso eredita tutti quelli disponibili
disallowedTools tool da rimuovere dall'insieme ereditato
model           'opus', 'sonnet', 'haiku', 'inherit' o un ID completo
skills          skill precaricate nel contesto all'avvio
maxTurns        tetto di turni: oltre, l'output torna marcato come parziale
background      forza l'esecuzione in background
effort          low | medium | high | xhigh | max
permissionMode  modalità permessi dentro l'agente

Due strade per l’invocazione. Quella automatica si gioca interamente sulla descrizione: “Claude automatically decides when to invoke subagents based on the task and each subagent’s description.” Quella esplicita è deterministica dal lato tuo, perché nominare l’agente nel prompt “bypasses automatic matching and directly invokes the named subagent”. In produzione, se un passaggio è obbligatorio, nominalo: una descrizione vaga è routing non deterministico travestito da configurazione.

Un default che sorprende: “Subagents run in the background by default.” Claude imposta run_in_background: false solo quando gli serve il risultato prima di proseguire. Se il tuo codice assume che il lavoro sia finito quando il tool ritorna, verifica.

Il contesto non si eredita, si scrive

Questa è la frase che cambia il modo di scrivere le deleghe: “The only content you pass from parent to subagent is the Agent tool’s prompt string, so include any file paths, error messages, or decisions the subagent needs directly in that prompt.”

Il subagent riceve il proprio system prompt, il prompt del tool Agent, il CLAUDE.md di progetto e le definizioni dei tool. Non riceve la cronologia del genitore, né i suoi tool result, né il suo system prompt. Al ritorno il canale è ancora più stretto: “only its final message returns to the parent”. Questo è il beneficio — il contesto del genitore cresce del riassunto, non dell’intera trascrizione — e insieme il vincolo: se ti serve l’output integrale, va chiesto esplicitamente, perché il genitore “may summarize it in its own response”.

Quando il ri-briefing costerebbe più del risparmio, esiste l’alternativa: “A fork is a subagent that inherits the entire conversation so far instead of starting fresh.” Il fork perde l’isolamento in ingresso ma mantiene quello in uscita, e va usato “when any other subagent would need too much background to be useful”.

Una nota di sicurezza che appartiene all’architettura, non alla compliance: il messaggio finale di un subagent viene ispezionato alla ricerca di pattern che imitano istruzioni prima che il genitore lo legga, con neutralizzazione dei tag di controllo e dei marcatori di turno. Progetta di conseguenza: il risultato di un agente è dato, non comando.

Contenere lo spawning

“Claude decides on its own when to spawn a subagent and how many to spawn”, e un subagent può generarne altri: un solo prompt può diventare un albero. Tre limiti, due dei quali sono variabili d’ambiente:

CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH   default 3; con 1 i tuoi subagent non ne generano
CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS   default 20 in esecuzione simultanea
max_budget_usd / maxBudgetUsd          nessun default; conta anche i subagent

Al limite di concorrenza il tool result riporta Concurrent subagent limit reached; al tetto di spesa arriva Budget limit reached, i subagent in background vengono fermati e la query chiude con error_max_budget_usd. Vale la pena impostarli quando il modello delega volentieri: su Opus 5 la documentazione avverte che “Claude Opus 5 delegates to subagents more readily than earlier models”, e un’istruzione di prompt “only steers Claude, so set the limits as well”.

Enforcement e handoff: chi garantisce il passaggio

In un flusso multi-step, «ho scritto nel prompt di non farlo» non è un controllo. La distinzione è esplicita: gli hook “provide more deterministic control over Claude’s behavior” e “All hooks are deterministically triggered”. Un PreToolUse hook può ispezionare una chiamata e bloccarla, con exit code 2 oppure con una decisione su stdout:

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "Destructive command blocked by hook"
  }
}

Sui passaggi di consegne valgono gli eventi di ciclo: TaskCreated con exit 2 impedisce la creazione di un task e rimanda feedback, TaskCompleted con exit 2 impedisce che venga marcato completo, TeammateIdle con exit 2 tiene l’agente al lavoro invece di lasciarlo fermare. È così che si costruisce un quality gate che non dipende dalla buona volontà del modello.

Sulla forma del passaggio, i due schemi si comportano in modo opposto. Nel sequenziale “Agents at each stage process inputs, make decisions, make tool calls as needed, then pass results to the next stage”; nel parallelo, invece, “Agents don’t hand off work to each other—they operate autonomously and produce results that contribute to the overall task”. Progettare un fan-out sperando in un handoff implicito fra i rami è l’errore classico.

Oltre le poche deleghe per turno, l’orchestrazione va spostata nel codice: “A workflow moves the plan into code”, con i risultati intermedi in variabili di script invece che nel contesto. Il corpo è JavaScript con agent() per un singolo subagent, pipeline() per uno per elemento e parallel() per un insieme simultaneo, entro limiti duri: fino a 16 agenti concorrenti, 4.096 elementi per singola chiamata, 1.000 agenti per run. Un vincolo però decide l’architettura dei tuoi handoff: “No mid-run user input”, e la contromisura documentata è chiara — “For sign-off between stages, run each stage as its own workflow”. Se il processo richiede un’approvazione umana a metà, non è un workflow solo: sono due.