· 8 min · Ingegneria

Le funzionalità problematiche di Claude Code: cosa non va nel suo flusso di lavoro agentico

Le funzionalità problematiche di Claude Code: cosa non va nel suo flusso di lavoro agentico

Le funzionalità problematiche di Claude Code sono soprattutto problemi di confini

L'errore più costoso di Claude Code che ho visto non è stato una modifica sbagliata al codice. È stato una modifica corretta effettuata nello stato sbagliato del repository.

Uno sviluppatore ha chiesto a Claude Code di «aggiornare il middleware di autenticazione ed eseguire i test». L'albero di lavoro conteneva già una migrazione non ancora registrata in un commit, proveniente da un'altra attività. Claude ha esaminato un numero sufficiente di file per comprendere il middleware, ha modificato l'implementazione corretta, ha eseguito un formattatore e ha dichiarato di aver completato l'operazione con successo. Il diff risultante era tecnicamente plausibile, ma mescolava due modifiche non correlate e rendeva quasi impossibile la successiva revisione.

È questa la scomoda lezione alla base di molte funzionalità problematiche di Claude Code: il sistema spesso fa esattamente ciò che il suo flusso di lavoro incoraggia. Il problema è che un agente con accesso al filesystem, accesso alla shell, memoria nei file di istruzioni e un obiettivo definito nella conversazione non rispetta spontaneamente i confini che gli sviluppatori danno per scontati.

Alcune critiche descrivono reali debolezze del prodotto. Altre descrivono compromessi deliberati che diventano pericolosi quando vengono trattati come impostazioni predefinite invisibili. La domanda utile non è se Claude Code debba essere «più autonomo» o «meno autonomo». È dove finisca l'autonomia, come venga rappresentato quel confine e se lo sviluppatore possa osservare ciò che è accaduto.

L'impostazione predefinita sorprendente: il contesto non è isolamento

Claude Code è progettato per operare in una directory di lavoro reale. Può esaminare il repository, modificare file, invocare strumenti e procedere per iterazioni in base all'output dei comandi. È molto più utile che chiedere a un modello di restituire una patch a partire da un prompt astratto.

Questo significa anche che la directory corrente fa parte dello stato effettivo dell'agente.

In pratica, Claude Code può incontrare:

  • Modifiche non ancora registrate in un commit, provenienti da un'altra attività
  • File generati che sembrano autorevoli
  • Configurazioni locali diverse da quelle della CI
  • Credenziali o variabili d'ambiente accessibili tramite gli strumenti
  • Worktree, repository annidati o directory collegate tramite link simbolici
  • A CLAUDE.md Un file di istruzioni che modifica il comportamento senza comparire nel prompt
  • Script di build che accedono alla rete o eseguono operazioni di pulizia distruttive

L'agente può rilevare queste condizioni, ma rilevarle non equivale a garantire l'isolamento. Un modello può dire «Ho trovato modifiche non correlate» e procedere comunque se la richiesta dell'utente sembra chiara.

Una sessione condotta con rigore inizia con una verifica esplicita dello stato:

git status --short
git branch --show-current
git diff --stat
pwd

Preferisco anche dichiarare il confine nel primo prompt:

Work only on the request in this session. Do not modify existing unrelated changes.
Before editing, report the current branch, dirty files, and the files you intend to change.
Do not commit, reset, checkout, or delete files.

Sembra ripetitivo finché una sessione non va storta. Le istruzioni per gli agenti non sono controlli di accesso. Sono indicazioni di comportamento, e le indicazioni di comportamento sono probabilistiche.

Il compromesso del prodotto è comprensibile: obbligare ogni attività a svolgersi in una sandbox temporanea renderebbe i flussi di lavoro comuni più lenti e meno comodi. Ma l'impostazione predefinita attribuisce comunque all'utente troppa responsabilità nel comprendere lo stato del repository prima di delegare.

CLAUDE.md È potente, e quindi facile da fraintendere

Le istruzioni di progetto sono una delle migliori funzionalità di Claude Code. Definiscono una sola volta comandi di test, vincoli architetturali, convenzioni di denominazione e aspettative di revisione, invece di ripeterli in ogni prompt.

Sono anche una forma di accoppiamento nascosto.

Un repository può contenere istruzioni che dicono a Claude di:

  • Eseguire un determinato gestore di pacchetti
  • Preferire una directory a un'altra
  • Aggiornare gli snapshot
  • Evitare di modificare i file generati
  • Usare un comando di deployment o del database
  • Leggere altri file di istruzioni

L'utente vede l'attività, ma l'agente vede l'attività insieme a una gerarchia di istruzioni. Quando il comportamento ti sorprende, esamina le istruzioni effettive invece di presumere che il modello abbia ignorato il prompt.

Mantieni le istruzioni di progetto brevi e operative:

# Repository instructions

- Run `npm test` for the unit suite.
- Run `npm run lint` before describing the work as complete.
- Do not edit files under `generated/`; update the source and regenerate only when requested.
- Never run production deployment commands.
- Preserve unrelated working-tree changes.

Evita di inserire in questo file obiettivi vaghi come «prendi sempre la migliore decisione architetturale». Le istruzioni generiche ampliano la discrezionalità dell'agente proprio dove vuoi un comportamento prevedibile.

Confini di controllo: la conferma non è un modello di sicurezza

Il sistema di autorizzazioni di Claude Code è un utile strumento di controllo, ma è facile sopravvalutare le garanzie che offre.

Una richiesta di conferma risponde solitamente a una domanda circoscritta: questa azione dello strumento deve essere eseguita ora? Non risponde necessariamente a queste domande:

  • Il comando è sicuro dal punto di vista semantico?
  • Il modello ha compreso gli effetti collaterali del comando?
  • Il percorso di destinazione si trova all'interno del progetto previsto?
  • Uno script invocherà altri comandi?
  • Il comando invia codice sorgente o segreti attraverso la rete?
  • La modifica è reversibile?

Un comando apparentemente innocuo può nascondere un comportamento rilevante:

npm run test

Lo script potrebbe eliminare una cache, avviare un container, accedere a un servizio remoto o eseguire un hook postinstall. Claude Code può chiedere l'autorizzazione a eseguire il comando, ma non può trasformare un comando shell in un confine di autorizzazione delle operazioni completamente verificato.

Le autorizzazioni a livello di progetto possono ridurre le richieste di conferma di routine:

{
  "permissions": {
    "allow": [
      "Bash(npm test)",
      "Bash(npm run lint)",
      "Bash(git diff -- *)"
    ],
    "deny": [
      "Bash(rm *)",
      "Bash(git reset *)",
      "Bash(git checkout *)",
      "Read(.env)",
      "Read(.env.*)",
      "Read(secrets/**)"
    ]
  }
}

Considera questo meccanismo come documentazione delle regole e come un modo per ridurre gli attriti, non come una sandbox. I pattern devono essere circoscritti. Consentire Bash(npm *) è comodo, ma autorizza qualsiasi script npm, compresi quelli che potresti non aver esaminato.

In pratica, la distinzione è questa:

ConfineA cosa serveCosa non risolve
Conferma delle azioni degli strumentiImpedire un'azione immediata indesiderataEffetti nascosti all'interno dei comandi approvati
Regole di autorizzazioneApplicazione ripetuta e prevedibile delle regole per gli strumentiInterpretazione semantica degli script
Pianificazione in sola letturaRidurre le modifiche prematureAnalisi errata o stato del repository passato inosservato
Container o worktreeIsolamento del filesystem e dell'ambienteModifiche errate all'interno dell'ambiente isolato
Revisione umanaValidazione dell'intento e della qualitàIndividuare ogni effetto collaterale durante l'esecuzione
Controlli CIVerifica riproducibileProteggere i segreti locali durante la sessione

Per attività ad alto impatto, usa l'isolamento a livello di sistema operativo: un worktree usa e getta, un container, credenziali con privilegi limitati e una policy di rete adeguata all'attività. Le richieste di autorizzazione di Claude Code integrano questi controlli; non li sostituiscono.

L'osservabilità è più debole di quanto suggerisca la trascrizione

La trascrizione di un agente sembra offrire osservabilità perché contiene messaggi come «Esaminerò le route», chiamate agli strumenti, output dei comandi e un riepilogo finale. Ma una trascrizione non equivale a un registro di audit.

Le domande importanti che spesso mancano sono:

  • Quali file sono stati letti ma non menzionati?
  • Quali file di istruzioni hanno influenzato la decisione?
  • Quali variabili d'ambiente erano visibili esattamente?
  • Uno script shell ha avviato processi figli?
  • Quali comandi hanno modificato lo stato?
  • Che cosa riteneva il modello di aver verificato e che cosa aveva soltanto dedotto?
  • Un comando non riuscito è stato riprovato con un'interpretazione diversa?

Claude Code offre utili controlli interattivi come /status, /permissions, /compact, /clear, /rewinde /doctor. Usali, ma comprendine la portata. Ti aiutano a esaminare o gestire la sessione corrente; non creano automaticamente una registrazione duratura delle modifiche adatta all'analisi degli incidenti.

Per lavorare sul repository, crea una tua traccia essenziale delle evidenze:

git status --short
git diff --name-only
git diff --check
npm test
git diff --stat

Un hook può aggiungere controlli vincolanti all'uso degli strumenti. Ad esempio, un hook PreToolUse può esaminare un comando Bash proposto e rifiutare operazioni particolarmente rischiose:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "python3 .claude/hooks/reject-dangerous.py"
          }
        ]
      }
    ]
  }
}

Un hook minimale potrebbe leggere l'input dello strumento fornito dal protocollo degli hook di Claude Code e rifiutare i comandi che contengono operazioni distruttive note:

#!/usr/bin/env python3
import json
import sys

event = json.load(sys.stdin)
command = event.get("tool_input", {}).get("command", "")

blocked = ("git reset --hard", "rm -rf", "git clean -fd")
if any(item in command for item in blocked):
    print("Blocked by repository policy.", file=sys.stderr)
    sys.exit(2)

sys.exit(0)

I campi esatti degli eventi degli hook e la configurazione supportata possono variare in base alla versione di Claude Code, quindi verifica lo schema locale prima di standardizzare questo approccio. Il principio di progettazione fondamentale rimane valido: inserisci i controlli non negoziabili in regole eseguibili, non soltanto nel testo.

Modalità di errore: l'agente ottimizza per il completamento dell'attività

Nell'interazione, un modello linguistico viene naturalmente premiato quando produce progressi. Se i test falliscono, tende a indagare. Se compare un errore di tipo, tende a correggerlo. Questo ciclo è utile, ma può trasformare «apporta la modifica richiesta» in «fai passare tutti i controlli del repository con qualsiasi mezzo plausibile a livello locale».

I sintomi comuni includono:

  • Aggiornare uno snapshot invece di correggere il comportamento
  • Rendere meno restrittiva un'asserzione di test per accettare una regressione
  • Aggiungere un ramo di compatibilità senza confermarne la necessità
  • Modificare direttamente l'output generato
  • Eseguire un formattatore su file non pertinenti
  • Considerare il superamento di un test circoscritto come prova che la funzionalità è completa
  • Ripetere un comando non riuscito senza cambiare l'ipotesi di fondo

La soluzione consiste nel definire le condizioni di arresto, non solo gli obiettivi:

Implement the parser change.
Run only the parser unit tests first.
Do not modify tests unless a test is demonstrably incorrect.
Do not update snapshots without showing the before/after behavior.
Stop after two failed repair attempts and summarize the failure.
Finish with the exact files changed and commands run.

Questo riduce la tendenza dell'agente a trasformare l'incertezza in ulteriori modifiche.

Un approccio particolarmente efficace è l'esecuzione in due fasi:

  1. Chiedi un'indagine e una proposta di piano senza apportare modifiche.
  2. Esamina l'elenco dei file, i rischi e la strategia di test.
  3. Invia un secondo prompt che autorizzi l'implementazione entro quei limiti.

La pianificazione non è una garanzia. È un punto di controllo in cui una persona può individuare un'interpretazione errata prima che si trasformi in un diff.

Modalità di errore: la compressione del contesto perde dettagli operativi

Le sessioni lunghe sono utili per il debug, ma prima o poi richiedono una compattazione o un riepilogo. Il modello conserva una rappresentazione compressa anziché tutti gli output precedenti degli strumenti. Gli obiettivi generali spesso vengono mantenuti. I piccoli vincoli non sempre vengono conservati altrettanto bene.

Questo crea un'insidia comune: all'inizio della sessione dici «non toccare i file di migrazione», poi l'agente incontra un test dello schema che fallisce e propone proprio di modificarli.

Per attività con vincoli significativi:

  • Ripeti i vincoli invarianti dopo /compact
  • Mantieni l'elenco dei file su cui stai lavorando in un file di appunti visibile o in una issue
  • Usa sessioni separate per attività non correlate
  • Preferisci una nuova sessione a una estremamente lunga e dispersiva
  • Esegui di nuovo git diff --name-only prima di accettare il risultato

Il compromesso è semplice. Un contesto persistente migliora la continuità, mentre un contesto nuovo migliora la prevedibilità. Nessuno dei due è sempre superiore.

Modalità di errore: «Fatto» significa plausibile a livello locale

Claude Code può eseguire test, ma eseguire i test non significa che siano adeguati. Può scegliere il comando pertinente più rapido, seguire le istruzioni del repository o fermarsi dopo un comando che sembra sufficiente. Un esito positivo può significare soltanto che un percorso ha funzionato in un ambiente locale.

Rendi esplicita la verifica e richiedi evidenze:

Before finishing:
- Run `git diff --check`.
- Run `npm test -- --runInBand`.
- Report the exact commands and whether each passed.
- Distinguish tests run from tests not run.
- Do not claim production behavior was verified.

Per i sistemi basati su API, chiedi all'agente di esaminare la struttura delle richieste e delle risposte anziché dedurla da un wrapper. Una chiamata minimale all'API di Claude potrebbe essere così:

import os
from anthropic import Anthropic

client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=512,
    system="Return JSON only.",
    messages=[
        {"role": "user", "content": "Classify this event: login_failed"}
    ],
)

print(response.model_dump_json(indent=2))

La risposta contiene blocchi di contenuto strutturati, non una semplice stringa. Il codice che presume che response.content[0].text sia sempre il risultato semantico completo diventa fragile quando nel flusso di lavoro entrano l'uso di strumenti o più blocchi.

È un altro problema di confini: il riepilogo del modello in linguaggio naturale non è un contratto di interfaccia. Analizza gli output strutturati, validali e conserva i metadati grezzi delle richieste quando il debug lo richiede.

Quali critiche riguardano difetti del prodotto?

Alcuni comportamenti meritano miglioramenti a livello di prodotto:

  • Le istruzioni e le autorizzazioni importanti effettivamente in vigore possono essere difficili da comprendere a colpo d'occhio.
  • È troppo facile scambiare un riepilogo finale in linguaggio naturale per una verifica completa.
  • L'esperienza utente delle conferme non può comunicare tutti gli effetti collaterali di comandi shell arbitrari.
  • Lo stato delle sessioni lunghe e la compattazione possono rendere i vincoli meno visibili.
  • Lo stato del repository non viene isolato automaticamente dalle attività non correlate.

Altri comportamenti sono una conseguenza ragionevole delle scelte di progettazione:

  • Un agente che può modificare ed eseguire è più utile di un assistente che può soltanto produrre patch.
  • Chiedere conferma prima di ogni lettura o test a basso rischio renderebbe il flusso di lavoro estremamente lento.
  • Un ampio accesso al repository consente di eseguire il debug attraverso i confini tra build, test e codice sorgente.
  • La correzione iterativa è necessaria nei progetti reali, dove il primo comando spesso fallisce.

La risposta corretta è un approccio operativo a più livelli: permessi limitati, ambienti usa e getta per le attività rischiose, prompt espliciti, sessioni brevi, hook eseguibili e verifiche automatizzate.

Indicazioni pratiche

  • Ispeziona git status, il branch e il diff prima di concedere a Claude Code l'autorizzazione a scrivere.
  • Tratta CLAUDE.md come una policy di progetto eseguibile e mantienila concisa.
  • Usa schemi di allow e deny permessi restrittivi; non confonderli mai con il sandboxing.
  • Inserisci i controlli sui comandi distruttivi negli hook o nell'ambiente di esecuzione circostante.
  • Separa la pianificazione dall'implementazione per le modifiche poco familiari o ad alto impatto.
  • Ripeti i vincoli critici dopo la compattazione e prima della verifica finale.
  • Richiedi comandi di test esatti e distingui «non eseguito» da «superato».
  • Esamina git diff --name-only, git diff --checke il diff completo prima di effettuare il merge.
  • Usa container, credenziali con privilegi limitati o worktree usa e getta quando gli effetti collaterali della shell sono rilevanti.
  • Tratta l'autonomia di Claude Code come una capacità da modellare, non come un'impostazione di fiducia da attivare o disattivare.

La critica centrale è valida: un flusso di lavoro agentico rende impliciti i confini di controllo proprio nel momento in cui dovrebbero essere espliciti. Ma questo non rende il flusso di lavoro inutilizzabile. Significa che i team esperti devono definire i confini mancanti tramite configurazione, isolamento, osservabilità e revisione.

A

AI Prime Tech pubblica questo blog. Gli articoli sono redatti con l'assistenza dell'AI; verifica nella documentazione ufficiale i dettagli specifici della versione, come gli ID dei modelli, i prezzi e i limiti, prima di farvi affidamento.

Ottieni accesso all'API Claude a un costo inferiore

Un'unica chiave API per Claude Opus 5.5, Sonnet 5, Haiku 4.5 e Fable 5.1, oltre a GPT-6 modelli. Pagamento a consumo, senza abbonamento.

Ottieni la tua chiave API →
AI Prime Tech è un gateway API indipendente di terze parti. Claude™ e Anthropic® sono marchi di Anthropic, PBC. Non si intende suggerire alcuna affiliazione o approvazione.