Il primo ostacolo è di navigazione, non di codice: la documentazione di Claude Code e del Claude Agent SDK vive su code.claude.com, mentre Messages API, Managed Agents e tool stanno su platform.claude.com. Cercare l’Agent SDK sul secondo dominio è il modo più rapido per perdere mezz’ora.

Quattro punti di ingresso, e cosa scegli davvero

La pagina di overview dell’Agent SDK mette a confronto quattro strade:

Agent SDK        libreria: il loop gira nel TUO processo (Python, TypeScript)
Claude Code CLI  uso interattivo da terminale, oppure one-shot con -p
Client SDK       chiami la Messages API e il loop tool-use lo scrivi tu
Managed Agents   API REST: Anthropic esegue l'agente e la sandbox

Il criterio è quanto del loop vuoi possedere. Il Client SDK dà accesso diretto al modello e nessun harness: è la scelta giusta se hai già un runtime di tool tuo, se i tool sono chiamate a servizi interni e non comandi di shell, o se ti serve controllo fine su ogni turno. L’Agent SDK dà il loop di Claude Code come libreria: tool su file e Bash, gestione del contesto, sessioni, permessi, hook, subagenti, MCP, skill e plugin. I Managed Agents danno l’harness e anche l’infrastruttura.

Un dettaglio che si dimentica: l’SDK esiste solo per Python e TypeScript. Da qualunque altro linguaggio la via ufficiale è eseguire la CLI come sottoprocesso con -p e --output-format json. La Exam Guide chiama «headless mode» questa modalità, ma è terminologia dell’esame: la pagina di documentazione si intitola Run Claude Code programmatically e la parola headless non vi compare.

claude -p "Find and fix the bug in auth.py" --allowedTools "Read,Edit,Bash"

Per script e CI aggiungi --bare: salta l’auto-discovery di hook, skill, comandi, subagenti, plugin, server MCP e CLAUDE.md, così ottieni lo stesso risultato su ogni macchina.

Il loop, e i suoi due freni

Il ciclo è sempre lo stesso: prompt in ingresso, il modello valuta e risponde con testo o richieste di tool, l’SDK esegue i tool e restituisce i risultati, si ripete. «Turns continue until Claude produces output with no tool calls, at which point the loop ends and the final result is delivered.»

Senza limiti il loop gira finché Claude decide di aver finito: benissimo su compiti circoscritti, male su prompt aperti. I freni sono due, max_turns che conta i soli turni con chiamate a tool e max_budget_usd che ferma sulla spesa e copre anche i subagenti. Al limite il risultato arriva con error_max_turns o error_max_budget_usd.

L’errore ricorrente sta qui: leggere il campo result senza guardare prima subtype. Il testo finale c’è solo nel caso success. Costo, token e session ID invece ci sono sempre, anche in errore.

Hosting: sottoprocesso tuo, o harness di Anthropic

Se ospiti tu, ricorda che l’Agent SDK non è un wrapper stateless. Genera e sorveglia un sottoprocesso claude che possiede una shell, una working directory e i transcript JSONL su disco locale. Una sessione, un sottoprocesso. Ne discendono due vincoli concreti: la concorrenza per host è limitata dalla RAM (il punto di partenza indicato è 1 GiB di RAM, 5 GiB di disco e 1 CPU per agente), e lo stato locale non sopravvive a un riavvio. Per riprendere una sessione serve un adattatore SessionStore, che però replica i soli transcript: i file CLAUDE.md e gli artefatti nella working directory vogliono una strategia loro.

I Managed Agents ribaltano il problema. Sono organizzati su quattro concetti — agent, environment, session, events — e Anthropic esegue sia il loop sia la sandbox. Sono in beta e richiedono l’header managed-agents-2026-04-01. Attenzione al vincolo che decide molte gare: le sessioni sono stateful per costruzione e il prodotto non è al momento eleggibile per Zero Data Retention né per il BAA HIPAA.

La terza via è la sandbox self-hosted dei Managed Agents: l’orchestrazione resta ad Anthropic, l’esecuzione dei tool avviene sulla tua infrastruttura, con la tua policy di rete. Da leggere con cura, perché è la fonte dell’equivoco più frequente: input e output dei tool continuano comunque a passare al control plane, altrimenti Claude non potrebbe decidere il passo successivo. Il self-hosting controlla dove il codice gira e quali reti raggiunge, non elimina il transito dei risultati.

Hook: la parte deterministica dell’agente

Gli hook sono callback che il runtime invoca su eventi del ciclo di vita: PreToolUse, PostToolUse, UserPromptSubmit, Stop, SubagentStart e SubagentStop, PreCompact, e molti altri. Un PreToolUse può bloccare o modificare la chiamata prima che parta; se la rifiuta, il tool non viene eseguito e Claude riceve il rifiuto come risultato.

Due proprietà contano più delle altre. Gli hook girano nel processo della tua applicazione, non dentro il context window, quindi non consumano contesto. E non vanno confusi con i permessi: allowedTools e permissionMode sono policy dichiarativa valutata dal runtime, l’hook è codice tuo che gira comunque. È lì che metti audit trail, redazione dei segreti, blocco dei comandi distruttivi, o l’invariante «i test devono passare prima che il task si chiuda».

options = ClaudeAgentOptions(
    hooks={"PreToolUse": [HookMatcher(matcher="Bash", hooks=[my_callback])]}
)

Ultima insidia: la copertura degli eventi non è simmetrica fra i due SDK. PreToolUse, PostToolUse, Stop, SubagentStart, SubagentStop, PreCompact e PermissionRequest esistono in entrambi; SessionStart, SessionEnd, PostToolBatch e diversi altri sono per ora solo TypeScript. Se progetti su Python, controlla la tabella prima di fondare una garanzia su un evento che lì non arriva.