Torna al blog

Sviluppo guidato dalle specifiche con Claude Code

Sviluppo guidato dalle specifiche con Claude Code

Lo sviluppatore che digita "add user authentication" in Claude Code ottiene un risultato diverso ogni volta. Forse JWT. Forse cookie di sessione. Forse un flusso OAuth2 completo con refresh token e PKCE. L'agente non sa cosa vuoi perche non gliel'hai detto. Gli hai dato una direzione, non una destinazione.

Gli sviluppatori che vedo ottenere output consistente e pronto per il rilascio da Claude Code condividono un'abitudine: scrivono una specifica prima di affidare il lavoro all'agente. Non un romanzo. Non un ticket Jira con tre frasi di contesto. Un documento concreto che definisce come appare "completato" prima che qualcuno scriva una riga di codice.

Non e una saggezza nuova. Lo sviluppo spec-first precede l'IA di decenni. Ma con gli agenti, il costo di saltare la specifica e piu alto e il beneficio di scriverne una e piu grande. Uno sviluppatore umano puo fermarsi a meta dell'implementazione e chiedere "aspetta, intendevi autenticazione con password o SSO?" Un agente ne scegliera uno in silenzio e proseguira. Quando te ne accorgi, ha costruito la cosa sbagliata, e hai speso 20 minuti a revisionare codice da buttare.

Questo articolo attraversa il ciclo di vita spec-driven che uso con Claude Code ogni giorno: come scrivere specifiche contro cui gli agenti possono eseguire, il checkpoint plan-before-code che cattura i malintesi in anticipo, e un protocollo di verifica piu rigoroso di "compila."

Perche "costruiscilo e basta" fallisce con gli agenti

Siamo specifici sulla modalita di fallimento. Quando dai a Claude Code un'istruzione vaga, tre cose vanno storte:

Assunzioni silenziose. L'agente colma ogni lacuna nella tua specifica con le proprie assunzioni. A volte sono ragionevoli. A volte no. Non saprai in quale categoria sei fino a quando non leggi l'output. Con istruzioni vaghe, finisci per leggere l'output con piu attenzione di quanto avresti impiegato a scrivere una specifica.

Risultati non riproducibili. Esegui lo stesso prompt vago due volte e ottieni due implementazioni diverse. Non solo nomi di variabili o formattazione diversi. Decisioni architetturali diverse. Librerie diverse. Strategie di gestione degli errori diverse. Se non puoi riprodurre l'output, non puoi costruire un processo affidabile attorno ad esso.

La revisione diventa il collo di bottiglia. Quando l'agente prende tutte le decisioni, devi verificare tutte le decisioni. Un diff di 400 righe dove comprendi ogni scelta richiede 5 minuti di revisione. Un diff di 400 righe dove l'agente ha scelto lo schema del database, la forma dell'API, i codici di errore e la logica di validazione richiede 30 minuti perche stai ricostruendo la specifica dall'implementazione.

La soluzione non sono prompt migliori. E anticipare le decisioni importanti in un documento contro cui l'agente puo eseguire.

Il ciclo di vita spec-driven

Il workflow ha cinque fasi. Ognuna ha una chiara condizione d'ingresso e una chiara condizione d'uscita.

Fase 1: Brainstorming. Esplori lo spazio del problema. Quali sono i vincoli? Quali approcci esistono? Cosa hai provato prima? Qui pensi ad alta voce, da solo o con Claude Code in modalita conversazionale. Condizione d'uscita: hai un approccio preferito e comprendi i compromessi.

Fase 2: Revisione. Metti l'approccio sotto pressione. Cosa potrebbe andare storto? Quali casi limite esistono? Questo entra in conflitto con qualcosa gia presente nel codebase? Se lavori con piu agenti, qui un agente di architettura o un secondo parere e prezioso. Condizione d'uscita: sei sicuro che l'approccio sia solido.

Fase 3: Specifica. Scrivi cio che hai deciso. Descrizione del problema, approccio proposto, file da modificare, criteri di accettazione verificabili meccanicamente e un piano di test. Questo e il contratto. Condizione d'uscita: qualcuno (umano o agente) potrebbe leggere questa specifica e sapere esattamente cosa costruire e come verificarlo.

Fase 4: Implementazione. L'agente esegue contro la specifica. Non contro un'idea vaga. Contro un documento concreto con criteri testabili. Condizione d'uscita: l'agente dichiara di aver completato e ha pubblicato prove di verifica.

Fase 5: Verifica. Tu (o un agente QA) confermi che l'implementazione corrisponde alla specifica. Non "sembra corretto" ma "soddisfa ogni criterio di accettazione." Condizione d'uscita: ogni criterio e verificato, e quelli che falliscono tornano alla Fase 4.

L'intuizione chiave: le fasi 1-3 costano poco. Richiedono 10-20 minuti per una funzionalita di medie dimensioni. La fase 4 richiede il tempo necessario per l'implementazione. La fase 5 richiede 5-10 minuti. Saltare le fasi 1-3 non fa risparmiare 10-20 minuti. Costa il tempo per revisionare, debuggare e rifare lavoro che andava nella direzione sbagliata.

Come appare una buona specifica per agenti

Ecco un vero template di specifica. Non una user story. Non un documento di requisiti di prodotto. Un documento di lavoro che dice a un agente esattamente cosa costruire.

## Problem
The filter bar resets when switching workspaces. Users lose their
filter state and have to re-apply filters every time they switch.

## Approach
Persist filter state per-workspace in localStorage. Key the stored
state by workspace database path so filters don't bleed across
workspaces.

## Files to Modify
- lib/local-storage.ts: Add getWorkspaceFilters / setWorkspaceFilters
- components/filter-bar.tsx: Read initial state from localStorage,
  write on every change
- hooks/use-workspace.ts: Trigger filter restore on workspace switch

## Acceptance Criteria
1. Select workspace A, set filters to status=open + type=bug
2. Switch to workspace B. Filters reset to defaults.
3. Switch back to workspace A. Filters restore to status=open + type=bug.
4. Close the browser tab, reopen. Filters for the active workspace
   are still applied.
5. bd list --status=open --type=bug output matches the filtered table.

## Out of Scope
- Server-side filter persistence
- Filter presets / saved filter combinations
- URL-based filter state (query params)

## Test Plan
- Unit test: getWorkspaceFilters returns stored value for matching
  workspace path
- Unit test: setWorkspaceFilters writes correct key format
- Manual test: steps 1-5 from acceptance criteria above

Nota cosa contiene e cosa non contiene questa specifica. Non spiega come funziona localStorage. Claude Code lo sa. Non giustifica perche abbiamo scelto localStorage al posto degli URL params. Questo e successo nella fase di brainstorming. Lista ogni file che l'agente dovrebbe toccare, il che significa che se l'agente inizia a modificare file fuori da questa lista, e un segnale d'allarme. Include una sezione fuori ambito, che impedisce all'agente di fare gold plating.

I criteri di accettazione sono la parte piu importante. Ognuno e un'azione concreta con un risultato osservabile. Non "i filtri dovrebbero persistere." Questo e ambiguo. "Passa al workspace A, verifica che i filtri siano status=open + type=bug" e testabile. Un agente puo eseguirlo. Un revisore QA puo verificarlo.

Il pattern plan-before-code

Ecco un protocollo che cattura la maggior parte degli errori di implementazione prima che diventino codice: richiedere all'agente di pubblicare il suo piano di implementazione prima di scrivere qualsiasi cosa.

In pratica, si presenta come un commento strutturato sul task. Prima che l'agente apra qualsiasi file, scrive esattamente cosa intende fare.

PLAN: Persist filter state per-workspace using localStorage.

1. Add workspace-scoped storage helpers to lib/local-storage.ts:
   - getWorkspaceFilters(dbPath: string): FilterState | null
   - setWorkspaceFilters(dbPath: string, filters: FilterState): void
   - Key format: "beadbox:filters:{dbPath}"

2. Update components/filter-bar.tsx:
   - On mount, read stored filters for current workspace
   - On every filter change, write to localStorage
   - Accept databasePath as prop (currently not passed)

3. Update hooks/use-workspace.ts:
   - On workspace switch, emit event that filter-bar listens for
   - Filter-bar reads new workspace's stored filters on event

4. Threading databasePath:
   - filter-bar needs databasePath from the workspace context
   - Will add it to the WorkspaceProvider context value

Files: lib/local-storage.ts, components/filter-bar.tsx,
       hooks/use-workspace.ts, components/workspace-provider.tsx

Test: Unit tests for storage helpers, manual test of all 5
acceptance criteria.

All'agente servono circa 30 secondi per produrlo. A te servono circa 2 minuti per leggerlo. E in quei 2 minuti, puoi individuare problemi che richiederebbero 20 minuti per essere corretti dopo l'implementazione:

  • L'agente sta toccando file fuori dalla specifica? (Aggiungere workspace-provider.tsx non era nella specifica. Va bene o e scope creep?)
  • L'approccio ha senso? (Usare un event emitter per i cambi di workspace potrebbe essere sovradimensionato. Un semplice cambio di prop potrebbe bastare.)
  • Mancano dei passaggi? (Che dire della pulizia delle vecchie voci localStorage quando un workspace viene rimosso?)

Il piano e un checkpoint. Se sembra corretto, dici all'agente di procedere. Se sembra sbagliato, correggi il piano. In ogni caso, hai investito 2 minuti invece di 20.

Questo e il problema che Beadbox risolve.

Visibilita in tempo reale su cosa sta facendo l'intera flotta di agenti.

Provalo gratis durante la beta →

La verifica non e "compila"

La modalita di fallimento piu comune che vedo con Claude Code non e che gli agenti scrivano codice cattivo. E che nessuno ha verificato l'output contro la specifica.

L'agente dice "DONE." Lo sviluppatore scorre il diff, lo trova ragionevole e fa merge. Due giorni dopo qualcuno scopre che la funzionalita non gestisce il caso limite numero 3 dei criteri di accettazione. Ora stai debuggando in produzione invece di averlo intercettato al passaggio di verifica di 5 minuti.

Verifica significa controllare meccanicamente ogni criterio di accettazione. Non "sembra funzionare." Non "i test passano" (i test possono essere sbagliati o incompleti). Ogni criterio dalla specifica riceve un controllo concreto.

Ecco come appare un rapporto di completamento appropriato:

DONE: Filter bar now persists selected filters across workspace
switches using per-workspace localStorage.

Changes:
- lib/local-storage.ts: Added getWorkspaceFilters/setWorkspaceFilters
  with key format "beadbox:filters:{dbPath}"
- components/filter-bar.tsx: Reads stored filters on mount, writes
  on change. Accepts databasePath prop.
- hooks/use-workspace.ts: Triggers filter restore on workspace switch
  via callback prop.

QA Verification:
1. Open http://localhost:41420, select workspace A
2. Set filters to status=open, type=bug
3. Switch to workspace B via header dropdown
4. Switch back to workspace A
5. Verify filters are still status=open, type=bug
   -> Confirmed: filters restore correctly
6. Close tab, reopen. Filters persist.
   -> Confirmed: localStorage key present, filters applied on mount
7. Run: bd list --status=open --type=bug
   -> Output matches filtered table contents (14 beads)

Acceptance criteria:
- [x] Filters persist across workspace switches (steps 2-5)
- [x] Filters survive browser restart (step 6)
- [x] Filtered view matches bd CLI output (step 7)
- [x] Filters don't bleed between workspaces (step 3: workspace B
      shows defaults)

Unit tests: 3 added (storage read/write/key format). All passing.

Commit: a1b2c3d

La differenza tra questo e "DONE: Fixed the filter bar" e la differenza tra un passaggio QA di 5 minuti e un'indagine di 30 minuti. Ogni affermazione nel commento DONE e supportata da un controllo specifico. Ogni criterio di accettazione e mappato a un passaggio di verifica. Il revisore sa esattamente cosa e stato costruito, come e stato verificato e dove guardare se qualcosa sembra strano.

Beads come contenitore di specifiche

Il ciclo di vita che ho appena descritto ha bisogno di un posto dove vivere. La specifica, il commento del piano, l'implementazione, il rapporto di completamento, i risultati di verifica. Tutto allegato a un task, in un unico posto.

Questo e il problema che risolve beads. Beads e un issue tracker open-source e local-first progettato per esattamente questo workflow. Ogni "bead" e un task con una descrizione (la tua specifica), un thread di commenti (piani e rapporti di completamento), uno stato (open, in_progress, ready_for_qa, closed) e metadati come priorita, dipendenze e assegnazioni.

Ecco come appare il ciclo di vita spec-driven in pratica con il CLI bd:

Crea il bead con la tua specifica:

bd create --title "Persist filter state across workspace switches" \
  --description "## Problem
The filter bar resets when switching workspaces...

## Acceptance Criteria
1. Select workspace A, set filters...
2. Switch to workspace B..." \
  --type feature --priority p2

L'agente reclama il lavoro e pubblica un piano:

bd update bb-a1b2 --claim --actor eng1
bd comments add bb-a1b2 --author eng1 "PLAN: Persist filter state
per-workspace using localStorage.

1. Add workspace-scoped storage helpers...
2. Update filter-bar component...
3. ..."

L'agente completa il lavoro e pubblica un rapporto:

bd comments add bb-a1b2 --author eng1 "DONE: Filter bar now persists
selected filters across workspace switches.

QA Verification:
1. Open http://localhost:41420...

Acceptance criteria:
- [x] Filters persist across workspace switches
- [x] Filters survive browser restart
...

Commit: a1b2c3d"

bd update bb-a1b2 --status ready_for_qa

Il QA prende in carico e verifica:

bd show bb-a1b2  # Leggi la specifica e il commento DONE
# Esegui i passaggi di verifica
bd comments add bb-a1b2 --author qa1 "QA PASS: All 5 acceptance
criteria verified. Filters persist, restore, and match bd CLI output."

L'intero ciclo di vita e nel bead. La specifica e la descrizione. Il piano e un commento. Il rapporto di completamento e un commento. Il risultato QA e un commento. Tra sei mesi, se qualcuno chiede "come funziona la persistenza dei filtri e perche abbiamo scelto localStorage invece degli URL params?", la risposta e nel thread dei commenti del bead.

Quando fai passare una sola specifica attraverso questa pipeline, un terminale e bd show bastano. Ma questo workflow mostra il suo vero valore quando esegui piu specifiche in parallelo.

Scalare lo sviluppo spec-driven

Immagina lo scenario reale: hai tre agenti Claude Code, ognuno che implementa una specifica diversa. L'Agente A costruisce una funzionalita di persistenza dei filtri. L'Agente B aggiunge un nuovo endpoint API per le statistiche dei workspace. L'Agente C corregge un bug di riconnessione WebSocket. Ognuno e in qualche punto del ciclo di vita spec-driven.

Nel terminale, dovresti eseguire bd list per vedere tutti i bead attivi, poi bd show su ognuno per controllare lo stato e leggere l'ultimo commento. Sono sei comandi per ottenere uno snapshot di tre flussi di lavoro paralleli. Moltiplica per cinque o dieci agenti e stai spendendo piu tempo a controllare lo stato che a revisionare i piani.

Qui entra in gioco Beadbox. Beadbox e una dashboard in tempo reale che mostra lo stato di ogni bead nel tuo workspace. Quali specifiche sono aperte e in attesa di un agente. Quali hanno piani pubblicati che necessitano della tua revisione. Quali sono in corso. Quali sono pronte per la verifica QA. Tutto si aggiorna in tempo reale mentre gli agenti scrivono commenti e cambiano stati attraverso il CLI bd.

Non hai bisogno di Beadbox per fare sviluppo spec-driven. Il CLI gestisce l'intero ciclo di vita. Ma quando esegui piu workflow spec-driven in parallelo, poter vedere la pipeline a colpo d'occhio piuttosto che interrogare lo stato di ogni agente individualmente cambia la velocita con cui puoi revisionare piani, sbloccare agenti e individuare lavoro in stallo.

Beadbox e gratuito durante la beta, e il CLI beads su cui funziona e open-source.

Cosa resta vero indipendentemente dagli strumenti

Che tu usi beads, GitHub Issues, Linear o semplici file di testo, il pattern spec-driven funziona perche affronta un'asimmetria fondamentale nel modo in cui operano gli agenti: sono veloci nell'esecuzione e scarsi nel giudizio. Ogni minuto che spendi a scrivere una specifica chiara fa risparmiare piu minuti nella revisione di output errato, nel debug di assunzioni silenziose e nel rifacimento di lavoro che ha preso la direzione sbagliata.

I principi:

  1. Definisci "completato" prima di "iniziare." I criteri di accettazione non sono opzionali. Sono l'unica cosa che rende possibile la verifica.

  2. I piani sono checkpoint, non burocrazia. Un commento piano di 30 secondi fa risparmiare riscritture di 20 minuti. Revisiona il piano, non il codice.

  3. La verifica e un protocollo, non una sensazione. "Mi sembra buono" non e verifica. Mappare ogni criterio di accettazione a un controllo concreto lo e.

  4. La specifica e la singola fonte di verita. Quando implementazione e specifica non concordano, l'implementazione e sbagliata. Questa regola esiste perche gli agenti non metteranno in discussione un piano sbagliato. Lo eseguiranno fedelmente e produrranno output fedelmente sbagliato.

  5. I confini di ambito prevengono la deriva. Una lista esplicita di file da modificare e una sezione fuori ambito impediscono all'agente di "migliorare" cose che non hai chiesto di migliorare.

L'investimento e piccolo: 10-20 minuti per scrivere una specifica per una funzionalita che richiede un'ora di implementazione. Il ritorno e grande: risultati consistenti, output revisionabile e una registrazione permanente di cosa e stato costruito e perche.

Se stai costruendo workflow come questi, metti una stella a Beadbox su GitHub.

Like what you read?

Beadbox is a real-time dashboard for AI agent coordination. Free during the beta.

Share