Dopo qualche mese di sviluppo, anche un progetto che conosci bene smette di stare tutto in testa. Route API, servizi, componenti, test, documenti di progetto: una ricerca testuale trova le stringhe, ma non mostra come i pezzi si collegano né quali parti del codice dipendono da quali altre.
In questa guida documentiamo il setup che abbiamo configurato sul repository di Virtese, un'applicazione Next.js. Graphify trasforma il codebase in un grafo, Claude Code lo genera e lo aggiorna, Obsidian lo rende navigabile come una raccolta di note collegate. Non è una panoramica teorica: ogni comando che trovi qui sotto è stato eseguito sul nostro ambiente, e i numeri che citiamo sono quelli ottenuti sul nostro progetto, non limiti o prestazioni generali degli strumenti.
Cosa volevamo ottenere
Una mappa del codebase da consultare senza aprire un file dopo l'altro.
Una knowledge base in Obsidian separata dal repository: il codice resta dov'è, le note vivono altrove.
Un solo vault per tutti i progetti, con una cartella dedicata a ciascuno.
Un procedimento ripetibile per aggiornare grafo e note quando il codice cambia.
Nessun rischio per le note personali già presenti nel vault.
Gli strumenti in breve
Graphify
Graphify è uno strumento open source, distribuito come pacchetto Python graphifyy (con due y) e usato con il comando graphify. Costruisce un knowledge graph a partire da una cartella. Il codice viene analizzato in modo strutturale, leggendo l'albero sintattico (AST), senza modelli linguistici; documenti e immagini richiedono invece un'estrazione semantica affidata a un LLM. Il risultato è un grafo fatto di nodi (file, funzioni, tipi, concetti), collegamenti (import, chiamate, riferimenti) e community, cioè gruppi di nodi strettamente collegati fra loro.
Claude Code
Graphify si integra con Claude Code tramite una skill: una cartella con un file SKILL.md che aggiunge il comando /graphify. È Claude Code a eseguire la procedura e, per documenti e immagini, a fare da modello per l'estrazione semantica, a meno che non sia configurata una chiave per Gemini, che Graphify può usare in alternativa.
Obsidian
Obsidian è un'app per prendere note basata su file Markdown raccolti in una cartella, il vault. Le impostazioni del vault stanno nella cartella nascosta .obsidian al suo interno. Graphify può esportare il grafo come note Markdown collegate da link [[...]], più un file graph.canvas nel formato aperto JSON Canvas, quello che Obsidian usa per le sue lavagne.
Come sono organizzate le cartelle
Il principio è semplice: tre posti diversi per tre cose diverse.
~/Desktop/development/virtese/ ← repository: codice sorgente, tracciato da Git
├── app/
├── tests/
└── graphify-out/ ← artefatti locali di Graphify, non tracciati
├── graph.json
├── GRAPH_REPORT.md
├── graph.html
└── .graphify_labels.json
~/Documents/Developer Knowledge/ ← vault Obsidian: la knowledge base
├── .obsidian/ ← impostazioni del vault
├── Welcome.md ← note personali
└── Virtese/ ← export di Graphify per questo progetto
├── .graphify_obsidian_manifest.json
├── graph.canvas
├── _COMMUNITY_….md ← una nota per community
└── ….md ← una nota per nodo
~/Documents/Obsidian Backups/ ← fuori dal vault
└── developer-knowledge-root-virtese-export-20261030-091616/Il repository contiene il codice e la sua storia. La cartella graphify-out/ sta dentro il repository ma è un prodotto locale: Graphify la rigenera, e nel nostro caso Git la mostra come non tracciata. Il vault contiene note generate a partire da quegli artefatti, pensate per essere lette in Obsidian, e vive completamente fuori dal repository.
Prerequisiti
Un terminale. Noi abbiamo lavorato su macOS con zsh.
Git e un repository da analizzare.
Claude Code, per eseguire la skill di Graphify.
Il pacchetto
graphifyy, che fornisce il comandographify. Sulla nostra macchina è installato come tool di uv.Obsidian, con un vault già creato.
python3, che in questa guida usiamo solo per alcuni controlli in sola lettura.
Installazione e verifica
La CLI
Per prima cosa, controlla la versione e come è stato installato il pacchetto:
graphify --version
# graphify 0.9.97
uv tool list
# graphifyy v0.9.97
# - graphify
# - graphify-mcpSe il pacchetto manca, la pagina del progetto su PyPI indica pip install graphifyy; la skill di Claude Code, quando non lo trova, lo installa con uv tool install --upgrade graphifyy. L'elenco completo dei sottocomandi è in graphify --help.
La skill di Claude Code
Le skill personali di Claude Code stanno in ~/.claude/skills/<nome>/SKILL.md e si invocano con /nome. Quella di Graphify:
ls ~/.claude/skills/graphify/
# SKILL.md
# referencesSe manca, graphify --help elenca il comando che la copia nella configurazione dell'agente: graphify install, con l'opzione --platform per scegliere la piattaforma.
Il file CLAUDE.md
Nel nostro setup Graphify è registrato nel file CLAUDE.md a livello utente:
grep -n graphify ~/.claude/CLAUDE.md
# 1:# graphify
# 2:- **graphify** (`~/.claude/skills/graphify/SKILL.md`) - any input to knowledge graph. Trigger: `/graphify`
# 3:When the user types `/graphify`, use the installed graphify skill or instructions before doing anything else.La differenza conta. ~/.claude/CLAUDE.md contiene istruzioni personali valide per tutti i tuoi progetti; un CLAUDE.md nella root del repository contiene istruzioni condivise per quel progetto. Il repository di Virtese non ha un CLAUDE.md di progetto: l'integrazione vive nel file utente. Se vuoi che chiunque lavori sul repository sappia che esiste un grafo, puoi scriverlo in un CLAUDE.md di progetto, ma non serve perché la skill funzioni.
Generare e leggere il grafo
La prima esecuzione
In Claude Code, dalla root del repository:
/graphify .La skill individua i file supportati, estrae la struttura del codice, affida a Claude Code l'estrazione semantica di documenti e immagini (riusando la cache per i file che non sono cambiati), raggruppa i nodi in community, dà un nome a ciascuna e scrive i risultati in graphify-out/.
I file di graphify-out/
graphify-out/
├── graph.json ← il grafo: nodi, collegamenti e community
├── GRAPH_REPORT.md ← il report: god node, connessioni sorprendenti, domande suggerite
├── graph.html ← la visualizzazione interattiva, da aprire nel browser
├── .graphify_labels.json ← i nomi delle community
├── manifest.json ← lo stato dei file analizzati, usato dagli aggiornamenti incrementali
├── cost.json ← i token usati a ogni esecuzione
└── cache/ ← la cache delle estrazioniAlcuni chiarimenti:
graph.jsonè la fonte da cui partono tutti gli export, compreso quello per Obsidian. Registra anche il commit su cui è stato costruito, nel campobuilt_at_commit.GRAPH_REPORT.mdè fatto per essere letto: elenca i nodi più connessi (god node), i collegamenti inattesi fra parti diverse del progetto, le community poco coese e alcune domande che il grafo può aiutare a esplorare..graphify_labels.jsonassocia a ogni community un nome leggibile. È il file che passeremo all'export.I file nascosti
.graphify_pythone.graphify_rootservono alla skill per ricordare quale interprete Python usare e quale cartella è stata analizzata.
Il grafo è aggiornato?
Un grafo vecchio è peggio di nessun grafo, perché sembra affidabile. Il controllo più semplice confronta il commit registrato in graph.json con quello attuale:
python3 -c "import json; print(json.load(open('graphify-out/graph.json'))['built_at_commit'][:7])"
git rev-parse --short HEADSe i due valori coincidono e git status non mostra modifiche al codice, il grafo descrive il codice attuale.
Nel caso di Virtese, dopo l'ultimo aggiornamento il grafo copre 374 file e contiene 2.134 nodi, 5.395 collegamenti e 120 community, costruiti sul commit 1a44d27.
Esportare in Obsidian
Un vault, una cartella per progetto
Abbiamo scelto un vault permanente, ~/Documents/Developer Knowledge, con una sottocartella per ciascun progetto. I vantaggi:
un'unica knowledge base da aprire, cercare e collegare;
una cartella separata per ogni progetto, con le sue note generate;
il codice sorgente resta nel repository, le note nel vault;
altri progetti potranno aggiungersi in cartelle proprie, senza mescolare i loro export.
C'è anche un motivo tecnico. Graphify tiene traccia dei file che ha scritto con un manifest, uno per cartella di destinazione. Due progetti esportati nella stessa cartella condividerebbero lo stesso manifest, e l'export del secondo eliminerebbe le note del primo.
Il comando di esportazione
Dalla root del repository:
graphify export obsidian \
--graph graphify-out/graph.json \
--labels graphify-out/.graphify_labels.json \
--dir "$HOME/Documents/Developer Knowledge/Virtese"export obsidiangenera una nota Markdown per ogni nodo, una nota di riepilogo per ogni community e il filegraph.canvas.--graphindica il grafo da esportare. Passarlo in modo esplicito evita sorprese se lanci il comando dalla cartella sbagliata.--labelsindica il file con i nomi delle community. Se ometti l'opzione, Graphify cerca.graphify_labels.jsonaccanto al grafo.--dirè la cartella di destinazione. Il valore predefinito ègraphify-out/obsidian; noi puntiamo alla sottocartella del vault. Le virgolette sono obbligatorie, perché il percorso contiene uno spazio.
L'output della nostra esecuzione, con i percorsi abbreviati:
Obsidian vault: 2254 notes in ~/Documents/Developer Knowledge/Virtese/
Canvas: ~/Documents/Developer Knowledge/Virtese/graph.canvas
Open ~/Documents/Developer Knowledge/Virtese/ as a vault in Obsidian.L'ultima riga suggerisce di aprire la cartella come vault autonomo. Noi non lo facciamo, perché vogliamo un unico vault; questa scelta ha una conseguenza sul canvas, descritta più avanti.
Cosa contiene l'export
Le note dei nodi: una per nodo, con un frontmatter che indica file sorgente, tipo, community, posizione nel file e tag (per esempio
community/Blog_Renderer), seguito dall'elenco delle connessioni come link[[...]], ciascuna con il tipo di relazione e il livello di confidenza.Le note delle community: una per community, con il prefisso
_COMMUNITY_nel nome del file.Il manifest
.graphify_obsidian_manifest.json: l'elenco dei file che Graphify considera suoi.graph.canvas: una lavagna in cui le community sono gruppi e i nodi sono schede.
Come tratta i file che trova
La documentazione della CLI non descrive questi dettagli, quindi abbiamo letto il codice della versione 0.9.97:
I file elencati nel manifest vengono riscritti solo se il contenuto è cambiato.
I file elencati nel manifest che non corrispondono più a un nodo del grafo vengono eliminati.
Un file che non è nel manifest non viene mai sovrascritto: Graphify lo salta e stampa un avviso.
graph.canvasviene riscritto a ogni export, senza protezione: le modifiche fatte a mano si perdono alla prossima esportazione.Per colorare le community, Graphify scrive
.obsidian/graph.jsondentro la cartella di destinazione, ma solo se quel file non esiste già o è suo. In un export in sottocartella finisce quindi inVirtese/.obsidian/graph.json, mentre Obsidian legge le impostazioni dalla cartella.obsidiandel vault: i colori non vengono applicati al vault principale.
Queste regole spiegano perché non conviene cancellare a mano i file generati. Il manifest è il registro di ciò che Graphify gestisce: un file eliminato a mano viene ricreato alla prossima esportazione se il nodo esiste ancora, mentre le note dei nodi spariti dal grafo vengono già rimosse dall'export.
Il canvas in una sottocartella
È il dettaglio che ci era sfuggito al primo controllo. Graphify scrive i riferimenti delle schede come percorsi relativi alla cartella di esportazione, per esempio:
"file": "renderNode().md"Quando l'export è nella root del vault, quel percorso è corretto. Quando l'export è in Virtese/, la nota si trova in Virtese/renderNode().md, ma la scheda continua a indicare renderNode().md. L'API di Obsidian descrive le schede di tipo file come riferimenti a un file che si trova nel vault, quindi conviene verificare: apri Virtese/graph.canvas e controlla che le schede mostrino il contenuto delle note. Le note non hanno questo problema, perché si collegano fra loro con link per nome, come [[BlogRenderer()]].
Se le schede risultano vuote, puoi aggiungere il prefisso della cartella ai percorsi. Lo script seguente modifica solo graph.canvas, si può rieseguire senza danni e va rilanciato dopo ogni export, perché Graphify riscrive il canvas:
python3 - "$HOME/Documents/Developer Knowledge" Virtese <<'PY'
import json, sys
from pathlib import Path
vault, folder = Path(sys.argv[1]), sys.argv[2]
path = vault / folder / "graph.canvas"
canvas = json.loads(path.read_text())
for node in canvas["nodes"]:
if node.get("type") == "file" and not node["file"].startswith(folder + "/"):
node["file"] = f"{folder}/{node['file']}"
path.write_text(json.dumps(canvas, indent=2))
files = [n["file"] for n in canvas["nodes"] if n.get("type") == "file"]
print(sum((vault / f).exists() for f in files), "of", len(files), "cards resolve from the vault root")
PYNel caso di Virtese, le 2.134 schede di tipo file corrispondono a note che esistono nella cartella Virtese/, ma con percorsi relativi a quella cartella. Con il prefisso, tutte le 2.134 vengono risolte dalla root del vault: lo abbiamo verificato su una copia, senza modificare il vault.
Verificare e proteggere i dati esistenti
Prima dell'export
Se la destinazione è dentro un vault esistente, fai un backup prima di esportare e controlla che la cartella di destinazione sia vuota o contenga solo un export precedente di Graphify. Noi abbiamo verificato che Virtese/ non esistesse e abbiamo preso un'impronta dei file della root, della cartella .obsidian e del vecchio ambiente di test, per confrontarla dopo l'export. Su macOS, per esempio:
VAULT="$HOME/Documents/Developer Knowledge"
find "$VAULT/.obsidian" -maxdepth 1 -type f -exec stat -f '%m %z %N' {} + | sort | shasumIl comando combina data di modifica, dimensione e nome di ogni file in un'unica impronta: se dopo l'export il valore è identico, quei file non sono stati toccati. Su Linux la sintassi di stat è diversa.
Dopo l'export: i controlli
Un comando che termina senza errori non dimostra che il risultato sia corretto. Questi sono i controlli che abbiamo eseguito, tutti in sola lettura:
VAULT="$HOME/Documents/Developer Knowledge"
EXPORT="$VAULT/Virtese"
# note esportate e note delle community
find "$EXPORT" -name '*.md' -not -path '*/.obsidian/*' | wc -l
find "$EXPORT" -name '_COMMUNITY_*.md' | wc -l
# voci del manifest
python3 -c "import json, sys; print(len(json.load(open(sys.argv[1]))['files']))" "$EXPORT/.graphify_obsidian_manifest.json"
# schede e collegamenti del canvas
python3 -c "import json, sys; c = json.load(open(sys.argv[1])); print(len(c['nodes']), len(c['edges']))" "$EXPORT/graph.canvas"Per il canvas serve un controllo severo, che risolva i percorsi come farà Obsidian, cioè a partire dalla root del vault:
python3 - "$HOME/Documents/Developer Knowledge" <<'PY'
import json, sys
from pathlib import Path
vault = Path(sys.argv[1])
canvas = json.loads((vault / "Virtese" / "graph.canvas").read_text())
files = [n["file"] for n in canvas["nodes"] if n.get("type") == "file"]
missing = [f for f in files if not (vault / f).exists()]
print(len(files), "file cards,", len(missing), "not found from the vault root")
PYInfine, lo stato del repository:
git status --short
# ?? graphify-out/Nel caso di Virtese: 2.254 note (2.134 di nodi e 120 di community), un manifest con 2.255 voci (le note più .obsidian/graph.json) e un canvas con 2.254 schede e 200 collegamenti. I file personali della root, fra cui Welcome.md, 2026-10-30.md e Untitled.canvas, e la cartella .obsidian sono rimasti identici, e il vecchio ambiente di test sul Desktop non è stato toccato.
Spostare un vecchio export senza perdere nulla
Prima di scegliere la sottocartella avevamo provato un export nella root del vault. Quando abbiamo creato Virtese/, la root conteneva ancora le note vecchie con gli stessi nomi, e in Obsidian le avremmo viste due volte. Le abbiamo spostate fuori dal vault, senza cancellarle, in questo modo:
Leggere il manifest della root e controllare ogni voce: nomi semplici, file regolari, nessuna nota personale.
Trattare come personale tutto ciò che non è nel manifest.
graph.canvase il manifest stesso non sono elencati: abbiamo verificato dal contenuto che il canvas appartenesse al vecchio export, perché tutte le sue schede puntavano a note del manifest.Creare una cartella di backup nuova, con data e ora nel nome, fuori dal vault e sullo stesso disco, così che ogni spostamento sia una semplice rinomina.
Scrivere, prima di spostare, un inventario con l'hash SHA-256 di ogni file e un
RESTORE.txtcon le istruzioni per il ripristino.Spostare i file senza mai sovrascrivere, fermandosi al primo errore, e il manifest per ultimo.
Ricalcolare gli hash nel backup e confrontarli con l'inventario.
L'ultimo passo, in sola lettura:
python3 - "$HOME/Documents/Obsidian Backups/developer-knowledge-root-virtese-export-20261030-091616" <<'PY'
import hashlib, json, sys
from pathlib import Path
backup = Path(sys.argv[1])
inventory = json.loads((backup / "inventory.json").read_text())["files"]
bad = [name for name, meta in inventory.items()
if hashlib.sha256((backup / name).read_bytes()).hexdigest() != meta["sha256"]]
print(len(inventory) - len(bad), "of", len(inventory), "files match the inventory")
PYNel caso di Virtese sono stati spostati 2.225 file (2.223 note, il vecchio graph.canvas e il manifest), e tutti i 2.225 hash corrispondono all'inventario.
Aggiornare il grafo nel lavoro di tutti i giorni
Graphify e Obsidian non si sincronizzano da soli: l'export è una fotografia del grafo nel momento in cui lo esegui. Conviene tenere distinti quattro passaggi:
Modifichi il codice, e di solito fai commit.
Aggiorni il grafo, in Claude Code, con
/graphify . --update.Riesporti le note in Obsidian con lo stesso comando di export.
Consulti grafo e note in Obsidian, oppure interroghi il grafo da terminale.
Aggiornare il grafo
/graphify . --updateCon --update, la skill confronta i file con lo stato salvato in graphify-out/manifest.json e rielabora solo quelli nuovi o modificati. Se sono tutti file di codice, salta l'estrazione semantica: nessun LLM e nessun token. Poi sostituisce nel grafo i nodi dei file cambiati, ricalcola le community e Claude Code aggiorna i loro nomi.
La CLI offre anche graphify update <path>, che secondo graphify --help e la documentazione rielabora il codice modificato senza modello. Noi abbiamo usato il flusso della skill, che si occupa anche dei nomi delle community; come la CLI gestisca quei nomi non l'abbiamo verificato.
Nel caso di Virtese, dopo due commit l'aggiornamento ha trovato 8 file di codice modificati, ha sostituito 41 nodi con 65 nuovi, è passato da 117 a 120 community e ha usato 0 token. 101 community su 120 hanno mantenuto il nome precedente.
Riesportare le note
Riesegui lo stesso comando di export. Grazie al manifest, Graphify aggiorna le proprie note, rimuove quelle dei nodi spariti e lascia stare il resto del vault. Se avevi corretto i percorsi del canvas, rilancia anche quello script: il canvas viene riscritto a ogni export.
Consultare grafo e note
In Obsidian puoi aprire le note dei nodi, seguire i link, cercare per tag come community/... o usare la vista grafo. Da terminale, graphify --help elenca tre comandi di consultazione che lavorano su graph.json: query per una domanda in linguaggio naturale, path per il percorso più breve fra due nodi ed explain per la spiegazione di un nodo. In questo setup non li abbiamo ancora usati in modo sistematico.
Esistono anche strumenti per automatizzare l'aggiornamento: graphify hook install aggiunge degli hook Git e graphify watch <path> ricostruisce il grafo quando il codice cambia. Non li abbiamo configurati, e secondo la documentazione aggiornano il grafo, non l'export: il passaggio verso Obsidian resta esplicito.
Problemi comuni e soluzioni
Confondere repository e vault
Sintomo: un comando parte dalla cartella sbagliata, oppure scrive dove non dovrebbe. Soluzione: prima di ogni comando che crea, sposta o cancella file, controlla dove sei con pwd e usa percorsi completi basati su $HOME, fra virgolette se contengono spazi.
Esportare nella root di un vault esistente
Sintomo: migliaia di note generate mescolate alle tue, con il rischio che un secondo export elimini quelle del primo. Soluzione: una sottocartella per progetto, sempre.
Note duplicate dopo un cambio di cartella
Sintomo: dopo aver spostato l'export in una sottocartella, le note vecchie restano nella root con gli stessi nomi. Soluzione: spostarle fuori dal vault con un backup verificato, come descritto sopra.
Schede del canvas vuote
Sintomo: le note funzionano, ma il canvas di una sottocartella non mostra il contenuto delle schede. Soluzione: controllare i percorsi delle schede ed eventualmente aggiungere il prefisso della cartella.
Il report indica pochi file
Sintomo: dopo /graphify . --update, la sezione Corpus Check di GRAPH_REPORT.md riporta solo il numero dei file modificati (nel nostro caso 8) invece dell'intero corpus. Soluzione: è un effetto del flusso incrementale; i numeri reali del corpus compaiono nel passo in cui la skill individua i file.
File video non trascritti
Sintomo: Graphify avvisa che non riesce a trascrivere un video. Nel nostro caso il messaggio chiedeva di installare l'estensione graphifyy[video], che porta con sé faster-whisper. Soluzione: installarla se i video contengono parlato utile, altrimenti l'avviso si può ignorare.
graphify-out/ e Git
Sintomo: git status mostra graphify-out/ come cartella non tracciata. Nel nostro caso non è nel .gitignore e non l'abbiamo modificato durante questo setup. Soluzione: decidere in base al flusso di lavoro. Se il grafo serve solo a te puoi ignorare la cartella; se vuoi condividerlo con il team, la guida di Graphify sul lavoro in team consiglia di versionare solo graph.json. In ogni caso aggiungi i file a Git per nome e controlla cosa stai includendo: evita git add . finché graphify-out/ non è ignorata.
Il comando che non esiste
Sintomo: zsh risponde command not found: sl. Soluzione: il comando per elencare i file è ls; sl non è un comando standard e non è installato di default.
Best practice
Tieni separati codice, artefatti locali e note: tre posti, tre ruoli.
Nel vault usa una sottocartella per progetto, mai la root.
Prima di esportare in un vault esistente, fai un backup e controlla la destinazione.
Non modificare a mano i file che Graphify gestisce, e non cancellarli senza aver letto il manifest.
Non modificare
graph.canvasa mano: viene riscritto a ogni export. Tieni le tue lavagne fuori dalla cartella dell'export.Verifica i risultati con controlli severi: risolvi i percorsi come li risolverà Obsidian, non limitarti a cercare i nomi dei file.
Prima di spostare file, scrivi un inventario con gli hash e verificalo dopo lo spostamento.
Dopo ogni modifica importante al codice, aggiorna il grafo e poi riesporta.
Aggiungi i file a Git per nome.
Checklist finale
graphify --versionrisponde con la versione attesa.La skill è in
~/.claude/skills/graphify/e Claude Code riconosce/graphify.graphify-out/graph.jsonè stato costruito sul commit attuale.La destinazione dell'export è una sottocartella dedicata del vault.
Il vault ha un backup recente, e la destinazione era vuota o conteneva solo un export di Graphify.
Il numero di note corrisponde a nodi più community.
Il manifest esiste e tutte le sue voci corrispondono a file presenti.
Le schede del canvas si aprono in Obsidian.
Le note personali e la cartella
.obsidiandella root sono invariate.git statusnon mostra modifiche inattese.
Conclusione
Graphify e Obsidian, usati insieme, offrono due modi complementari di guardare un codebase: il grafo per capirne la struttura, le note per navigarla e ritrovare le informazioni quando servono. La parte delicata non è il comando di export, che sta in una riga, ma tutto quello che gli sta intorno: scegliere dove scrivere, sapere quali file lo strumento considera suoi, verificare il risultato con controlli severi e non perdere nulla di quello che c'era prima.
Il setup descritto qui è pensato per durare: un vault unico, una cartella per progetto e un flusso in quattro passaggi per tenere tutto aggiornato. E quando qualcosa non torna, il manifest e un backup verificato permettono di tornare indietro.



