Skill personalizzate per Claude Code: creare, testare e distribuire
Le regole che finiscono in `CLAUDE.md` sono comode finché sono poche: dopo un po' diventano un blocco di testo che pesa su ogni turno, anche quando non serve a nulla. Le skill di Claude Code risolvono il problema opposto: sono procedure, checklist o comandi che restano fuori dal contesto finché non li invochi — tu con `/nome-skill`, o Claude quando la `description` combacia con la richiesta. In questo tutorial ne costruisco una reale, `changelog-entry`, e la porto fino a dove servono contesto dinamico, tool pre-approvati, file di supporto e test automatici.
🧩 Cos'è una skill (e come si distingue da CLAUDE.md e hook)
Una skill è una cartella con dentro un `SKILL.md`: frontmatter YAML più istruzioni in markdown. La differenza sostanziale con `CLAUDE.md` è quando entra in contesto. `CLAUDE.md` è sempre presente, a ogni turno, che serva o meno. Il corpo di una skill invece si carica solo quando viene invocata: la sola `description` resta sempre visibile a Claude (per decidere se usarla), il resto — anche centinaia di righe di procedura — non costa un token finché non scatta.
Rispetto agli hook il ruolo è complementare, non alternativo: l'hook è codice deterministico che gira sempre, a un punto preciso del ciclo di vita, e può bloccare un'azione. La skill è conoscenza o procedura che Claude applica quando è rilevante, oppure che tu inneschi a comando. Un hook garantisce un'invariante («non chiudere il turno con i test rossi»); una skill descrive un modo di lavorare («ecco come genero una voce di changelog»).
CLAUDE.md
- Sempre in contesto, a ogni turno
- Pesa in token anche quando non serve
- Fatti stabili: convenzioni, stack, vincoli
- Un solo file, cresce e basta
Skill
- Si carica solo quando viene invocata
- Corpo lungo, costo quasi zero finché inattiva
- Procedure, checklist, comandi ripetuti
- Tante cartelle, ciascuna focalizzata su un compito
CLAUDE.md è la memoria sempre accesa; la skill è il manuale che apri solo quando ti serve.
📁 Anatomia di una skill: cartella, SKILL.md e frontmatter
Dove salvi la cartella decide chi la può usare. Una skill personale in `~/.claude/skills/<nome>/SKILL.md` vale su tutti i tuoi progetti; una skill di progetto in `.claude/skills/<nome>/SKILL.md` si committa nel repo e vale per chiunque lo cloni, agenti inclusi. `SKILL.md` è l'unico file obbligatorio: il resto — riferimenti, script, esempi — è opzionale e si carica solo se la skill lo richiama.
Tutti i campi del frontmatter sono opzionali; solo `description` è consigliato, perché è il segnale che Claude legge per decidere quando applicare la skill. I campi che uso di più in questo tutorial:
- `description` — cosa fa e quando usarla: la frase che Claude confronta con la richiesta dell'utente.
- `argument-hint` — suggerimento mostrato in autocomplete, ad esempio `[version]`.
- `disable-model-invocation` — `true` per impedire che Claude la invochi da sola: resta solo `/nome-skill` manuale.
- `allowed-tools` — tool pre-approvati per il turno che invoca la skill, senza chiedere conferma.
- `context: fork` + `agent` — esegue la skill in un subagent isolato, non inline nella conversazione corrente.
.claude/skills/changelog-entry/
├── SKILL.md # richiesto: frontmatter + istruzioni
├── reference.md # tassonomia Keep a Changelog, letto solo se serve
└── scripts/
└── group-by-type.pySkills reference · Claude Docs ↗
🛠️ Creo la mia prima skill: changelog-entry
Costruisco una skill che genera una voce di changelog a partire dai commit dall'ultimo tag. Il frontmatter fa tre scelte: `disable-model-invocation: true` perché voglio decidere io quando scrivere le note di rilascio, non che Claude lo faccia di sua iniziativa; `allowed-tools` limitato ai soli sottocomandi `git log`, `git describe` e `git tag`, non a `Bash` intero; `argument-hint: [version]` per ricordare che la skill si invoca con la versione da documentare.
La riga con `` !`git log ...` `` usa il contesto dinamico: Claude Code esegue quel comando prima di mandare il prompt a Claude e sostituisce il placeholder con l'output. Non è qualcosa che Claude esegue: è preprocessing, e Claude vede solo il risultato già inserito. La sintassi scatta solo a inizio riga o dopo uno spazio — `KEY=` seguito da `` !`cmd` `` resterebbe testo letterale.
---
name: changelog-entry
description: Genera una voce di changelog dai commit dall'ultimo tag. Usa quando
chiedo di preparare le note di rilascio o "cosa e' cambiato dall'ultima versione".
argument-hint: [version]
disable-model-invocation: true
allowed-tools: Bash(git log *) Bash(git describe *) Bash(git tag *)
---
## Commit dall'ultimo tag
!`git log $(git describe --tags --abbrev=0 2>/dev/null)..HEAD --pretty=format:"- %s (%h)"`
## Istruzioni
Raggruppa i commit qui sopra nelle sezioni Keep a Changelog (Added, Changed,
Fixed, Removed) per la versione $ARGUMENTS. Frasi brevi, un bullet per commit
rilevante; scarta i commit "chore" e i merge.Skills reference · Claude Docs ↗
🖥️ La skill in azione
Digito `/changelog-entry 1.4.0`. Prima ancora che Claude veda il prompt, Claude Code lancia `git log` sul range tra l'ultimo tag e `HEAD` e incolla l'elenco dei commit nel testo della skill; `$ARGUMENTS` diventa `1.4.0`. Claude riceve tutto già pronto e restituisce una voce di changelog raggruppata per sezione, pronta da incollare in `CHANGELOG.md`.
Con `disable-model-invocation: true` questa skill non scatta mai da sola: se in chat scrivo «prepara le note di rilascio» senza il comando, Claude non la invoca, perché la `description` non è nemmeno nel suo contesto. È una scelta voluta — decido io quando generare le note, non un'euristica del modello.
Il contesto dinamico gira prima: Claude vede già i commit, non deve andarseli a cercare.
🔒 Tool pre-approvati e skill di sola lettura
`allowed-tools` pre-approva un tool per il turno che invoca la skill: non toglie nulla, aggiunge un via libera che evita la conferma manuale. Il grant si azzera al messaggio successivo, quindi va ripetuto a ogni invocazione — è un permesso per quel turno, non per la sessione. Per l'opposto — vietare un tool mentre la skill è attiva, anche se il modello ci prova — serve `disallowed-tools`.
Lo uso per una seconda skill, `security-scan`: gira in un subagent isolato (`context: fork`, `agent: Explore`) e non deve poter scrivere nulla, qualunque cosa succeda durante l'analisi. `disallowed-tools: Edit Write Bash` toglie quei tool dal pool per tutta la durata della skill: anche se Claude decidesse di correggere un file trovato, non potrebbe.
---
name: security-scan
description: Cerca segreti hardcoded, chiavi API e credenziali nel codice
sorgente. Usa quando chiedo un controllo di sicurezza sul repo.
context: fork
agent: Explore
disallowed-tools: Edit Write Bash
---
Cerca nel repository pattern di segreti hardcoded: chiavi API, token,
password, stringhe di connessione. Per ogni corrispondenza riporta file,
riga e una motivazione. Non modificare nessun file: solo analisi.📚 File di supporto e progressive disclosure
`SKILL.md` non deve contenere tutto: file come `reference.md` o script in `scripts/` restano fuori dal contesto finché la skill non li richiama esplicitamente. È la stessa logica del lazy loading applicata alla documentazione: la guida ufficiale raccomanda di tenere `SKILL.md` sotto le 500 righe e spostare il materiale di dettaglio altrove, referenziandolo con un link markdown.
Per gli script bundlati nella cartella della skill uso `${CLAUDE_SKILL_DIR}`: si espande alla cartella che contiene quel `SKILL.md`, indipendentemente da dove la skill è installata — personale, di progetto o dentro un plugin. Usando la stessa variabile anche in `allowed-tools`, il pattern combacia esattamente col comando che il corpo della skill chiede di eseguire, e lo script gira senza chiedere conferma.
---
name: changelog-entry
description: Genera una voce di changelog dai commit dall'ultimo tag.
allowed-tools: Bash(${CLAUDE_SKILL_DIR}/scripts/group-by-type.py *)
---
## Riferimenti
Per la tassonomia completa delle categorie, vedi [reference.md](reference.md).
## Categorizzazione automatica
Esegui `${CLAUDE_SKILL_DIR}/scripts/group-by-type.py` per raggruppare i
commit per tipo (feat, fix, chore...) prima di scrivere il changelog.Skills reference · Claude Docs ↗
🧪 Testare una skill con skill-creator
Vedere la skill scattare non dice se ha fatto la cosa giusta: sono due verifiche distinte. Serve un confronto baseline — le stesse richieste, in una sessione pulita, prima con la skill disponibile e poi con la skill disattivata (via `skillOverrides`) — perché il contesto lasciato dall'aver scritto la skill maschera i buchi nelle istruzioni.
Il plugin `skill-creator` automatizza il confronto: `/plugin install skill-creator@claude-plugins-official`, poi `/reload-plugins`, poi chiedo a Claude «valuta la mia skill changelog-entry con skill-creator». Il plugin salva i casi di test in `evals.json` dentro la cartella della skill, lancia un subagent isolato per ciascuno, e produce `grading.json` (pass/fail con evidenza) e `benchmark.json` (tasso di successo, token e tempo con e senza skill) — così vedo se il guadagno vale il costo in contesto.
benchmark.json mette a confronto pass rate, token e tempo: la skill vince solo se il guadagno supera il costo in contesto.
📦 Distribuire: personale, di progetto o plugin
Lo stesso formato `SKILL.md`, ambiti diversi. La skill personale resta sulla tua macchina e vale ovunque tu lavori; la skill di progetto si committa e vale per l'intero team, agenti compresi — a patto che ciascuno accetti il dialogo di trust sulla cartella la prima volta. Se lo stesso nome esiste a più livelli, vince quello più alto: enterprise, poi personale, poi progetto.
Per condividere una skill fuori da un singolo repo — con hook, subagent o server MCP inclusi — la impacchetto in un plugin: una cartella `skills/` dentro il plugin, distribuita tramite un marketplace. È lo stesso meccanismo con cui ho pubblicato le regole di stile di questo blog come plugin personale.
Personale · ~/.claude/skills/
- Vale su tutti i tuoi progetti
- Non versionata, resta sulla tua macchina
- Ideale per le tue abitudini di lavoro
- Nessun trust dialog da accettare
Progetto · .claude/skills/
- Vale solo per questo repository
- Committata: stessa skill per tutto il team
- Ideale per convenzioni e procedure condivise
- Richiede accettare il trust dialog sul repo
Stesso file SKILL.md, ambito diverso: dove lo salvi decide chi la usa.
✅ In sintesi
Una skill è conoscenza o procedura che entra in contesto solo quando serve: leggera su `CLAUDE.md`, complementare agli hook, condivisibile con lo stesso rigore di un file versionato. `changelog-entry` è volutamente semplice, ma il pattern — frontmatter mirato, contesto dinamico, tool pre-approvati o vietati, file di supporto caricati su richiesta — si applica a qualunque procedura che ripeti abbastanza spesso da valerne la formalizzazione.
Un dettaglio che vale la pena ricordare: `SKILL.md` segue lo standard aperto Agent Skills, pubblicato da Anthropic a dicembre 2025 e già supportato da Codex CLI, Gemini CLI e altri agenti. Una skill scritta per Claude Code, con qualche accortezza, funziona anche altrove.
- 01Crea la cartella~/.claude/skills/<nome>/ (personale) o .claude/skills/<nome>/ (progetto, da committare).
- 02Scrivi il frontmatterdescription chiara, argument-hint se serve, disable-model-invocation per l'invocazione solo manuale.
- 03Inietta contesto dinamico!`comando` gira prima del prompt: Claude legge l'output, non esegue nulla.
- 04Limita i toolallowed-tools pre-approva, disallowed-tools vieta: scegli in base al rischio dell'azione.
- 05Aggiungi file di supportoreference.md e scripts/ restano fuori dal contesto finché non richiamati.
- 06Testa con skill-creatorConfronto con/senza skill in sessione pulita: pass rate contro costo in token e tempo.
- 07CondividiCommitta in .claude/skills/ per il team, o impacchetta come plugin per distribuirla più in largo.
Domande frequenti su skill personalizzate Claude Code
Qual è la differenza tra una skill e un hook di Claude Code?
Un hook è codice deterministico che gira sempre, a un punto preciso del ciclo di vita, e può bloccare un'azione: garantisce un'invariante. Una skill è conoscenza o procedura che Claude applica quando è rilevante, oppure che inneschi tu con /nome-skill: descrive un modo di lavorare, non lo impone. Sono complementari: un hook Stop può, ad esempio, ricordare di far girare una skill di verifica prima di chiudere il turno.
Come impedisco che Claude invochi una skill da sola?
Imposta disable-model-invocation: true nel frontmatter. La description smette di essere caricata nel contesto di Claude, quindi il modello non la vede né la può scegliere: resta invocabile solo manualmente con /nome-skill. È la scelta giusta per azioni con effetti collaterali o che vuoi controllare tu, come generare note di rilascio o fare un deploy.
Cosa cambia tra allowed-tools e disallowed-tools?
allowed-tools pre-approva un tool per il turno che invoca la skill: evita la richiesta di conferma, ma non toglie nulla dal pool disponibile. disallowed-tools fa l'opposto, rimuove tool dal pool finché la skill è attiva, anche se il modello proverebbe a usarli. Il grant o il divieto si azzerano entrambi al messaggio successivo: vanno pensati per turno, non per l'intera sessione.
Le skill scritte per Claude Code funzionano anche con Codex o Gemini CLI?
Sì, nella parte comune. SKILL.md segue lo standard aperto Agent Skills pubblicato da Anthropic a dicembre 2025 e adottato da OpenAI Codex CLI, Gemini CLI e altri agenti. Le funzionalità estese di Claude Code — context: fork, allowed-tools con la sintassi Bash(pattern), il contesto dinamico !`comando` — restano specifiche di Claude Code; il nucleo con frontmatter e istruzioni markdown è portabile.
Come verifico che una skill funzioni davvero, non solo che scatti?
Servono due controlli distinti: se Claude la invoca sulle richieste giuste, e se l'output è quello atteso quando la invoca. Il modo affidabile è un confronto baseline — stesse richieste, sessione pulita, con e senza la skill — perché il contesto di chi l'ha scritta maschera i buchi. Il plugin skill-creator automatizza questo confronto e produce un report con pass rate, token e tempo.
Dove metto una skill che deve valere per tutto il team?
In .claude/skills/<nome>/SKILL.md dentro il repository, e la committi: vale per chiunque clona il progetto, agenti inclusi, dopo aver accettato il trust dialog sulla cartella la prima volta. Per condividerla anche fuori da quel repository, con hook o server MCP allegati, la impacchetti come plugin e la distribuisci tramite un marketplace.
Parliamone
Se questo tema ti riguarda, scrivimi: confrontarsi su codice e AI è sempre tempo speso bene.