Loom: una Memoria Locale per i Tuoi LLM, Ispirata a Karpathy

Loom - Memoria locale per LLM senza infrastruttura
Loom: il tuo archivio personale che l'IA capisce davvero
Matteo 10 min

C’è una domanda che prima o poi si pone chiunque inizia a usare seriamente i modelli AI in locale: “Ok, ma come faccio a fargli leggere i MIEI documenti?”

Hai appunti in Markdown, PDF di ricerca, frammenti di codice, note sparse in mille cartelle. L’LLM è bravo, ma non sa niente di quello che hai scritto tu. Come glielo dai?

La risposta classica è: costruisci un sistema RAG. Chunk, embedding, vector store, Docker, Qdrant, modello di embedding separato… un’infrastruttura che per installarla, mantenerla e farla funzionare richiede parecchie conoscenze e tempo.

Ho già percorso quella strada con Doc Analyzer, e funziona benissimo — per certi casi d’uso. Ma mi sono accorto che per le mie note personali, i miei appunti di lavoro, la mia base di conoscenza quotidiana, tutta quella complessità era spesso eccessiva.

Poi ho letto il gist llm-wiki di Andrej Karpathy — quello che ha co-fondato OpenAI — e ho avuto una di quelle illuminazioni da “perché non ci avevo pensato prima?”. Da lì è nato Loom.


L’idea di Karpathy: la wiki persistente

Prima di parlare di Loom, è giusto spiegare cosa propone davvero Karpathy nel suo gist — perché Loom non è una port fedele di quella idea, ma ne è ispirato.

Il RAG classico ha un difetto strutturale: non accumula niente. Ogni volta che fai una domanda, l’LLM riparte da zero — recupera chunk, li legge, sintetizza. Non c’è memoria che cresce nel tempo.

Karpathy propone qualcosa di diverso: lasciare che l’LLM costruisca e mantenga una wiki persistente fatta di pagine Markdown intercollegte. Ogni volta che aggiungi un nuovo documento, l’LLM lo legge, estrae le informazioni chiave, aggiorna le pagine esistenti, segnala le contraddizioni con quello che già sa. La conoscenza si accumula e si raffina, invece di essere riderivata ogni volta. Il gist è pensato per essere usato con un agente (Claude Code, Codex) su una cartella tipo Obsidian — l’LLM scrive la wiki, tu la sfoglio.

È un’idea bella e ambiziosa. Ma richiede un agente attivo e una certa disciplina nel workflow.

La mia variante: riassunti + BM25 su SQLite

Loom prende l’intuizione di fondo — pre-elabora i documenti una volta sola invece di scoprire tutto al momento della query — e la implementa in modo più semplice e autonomo.

Invece di costruire una wiki intercollegata, Loom chiede all’LLM di generare un riassunto compatto per ogni file (150-250 parole, 5-8 keyword). Una chiamata LLM per file, solo alla prima indicizzazione. Riassunti e contenuto originale finiscono in SQLite, e quando fai una domanda viene fatta una ricerca BM25 su tutto l’indice per trovare i file più pertinenti, che vengono poi passati all’LLM per la risposta.

Niente wiki da mantenere. Niente agente sempre attivo. Il filesystem è la verità: aggiungi un file, esegui loom scan, hai finito.

Cos’è BM25? È l’algoritmo di ranking che sta sotto Elasticsearch, Lucene e la maggior parte dei motori di ricerca seri. L’acronimo sta per Best Match 25 — il “25” non è un numero di versione poetico, è letteralmente il numero dell’iterazione dell’algoritmo che i ricercatori hanno ritenuto abbastanza buona da pubblicare. In pratica, BM25 assegna un punteggio a ogni documento in base a quante volte compaiono le parole della query, penalizzando i documenti molto lunghi (che tendono ad accumulare occorrenze per pura lunghezza) e tenendo conto di quanto una parola è rara nell’intera collezione. È veloce, deterministico, e funziona sorprendentemente bene per ricerche in cui sapete già che terminologia usate — che è esattamente il caso delle vostre note personali.

Meno infrastruttura. Meno cerimonie. Risultati sorprendentemente buoni per l’uso personale — e come vedremo, con piena libertà di scelta sul provider LLM.


Cos’è Loom

Loom è un tool open source scritto in Go che indicizza i file nella tua cartella ~/loom/ (o dove vuoi tu), li rende interrogabili in linguaggio naturale, e si integra con Claude Code, Claude Desktop e qualsiasi client MCP.

Tecnicamente:

  • Go — un singolo binario compilato, zero runtime da installare
  • SQLite + FTS5 — il database è un file, la ricerca full-text è integrata e supporta stemming e testi italiani
  • Provider LLM configurabile — Ollama in locale, oppure Claude di Anthropic, oppure GPT-4o di OpenAI: scegli tu
  • Wails — per la GUI desktop opzionale (Svelte + TypeScript sotto il cofano)
  • MCP server — per integrarsi direttamente con Claude e altri strumenti AI

Niente Qdrant. Niente Docker. Niente modello di embedding separato. Un file SQLite, un binario, e l’LLM che già usi.


Come funziona (in tre passi)

1. Metti i file nella cartella

~/loom/
├── note-progetto-x.md
├── ricerca-concorrenza.md
├── contratto-fornitore.pdf
├── lavoro/
│   ├── specifiche-api-v2.md
│   └── bug-report-q1.md
└── personale/
    └── idee-blog.md

La struttura è libera. Puoi usare sottocartelle come vuoi. Loom le gestisce ricorsivamente. Le cartelle nascoste (tipo .git o .obsidian) vengono saltate automaticamente.

2. Indicizza con loom scan

loom scan

Loom trova tutti i file nuovi o modificati e per ognuno chiede all’LLM configurato di generare un riassunto di 150-250 parole con 5-8 keyword. Una chiamata LLM per file, solo alla prima volta (o quando il file cambia). Tutto finisce in SQLite.

Una cosa interessante: se sposti o rinomini un file, Loom riconosce il contenuto tramite hash e riutilizza il riassunto esistente senza fare un’altra chiamata LLM. Il vecchio path viene rimosso dall’indice automaticamente.

3. Fai domande con loom ask

loom ask "quali sono i punti critici del contratto con il fornitore?"

Loom fa una ricerca BM25 su riassunti, keyword e contenuto, prende i top-5 file pertinenti, e fa una singola chiamata all’LLM passando i riassunti e il contenuto originale. La risposta arriva in streaming con citazioni nel formato [nomefile.md].

Esempio di risposta:

Dai documenti trovati, i punti critici emersi sono:

1. **Clausola di esclusiva** (90 giorni) — potenzialmente vincolante in caso
   di rinegoziazione anticipata [contratto-fornitore.pdf]

2. **SLA non definiti** per i ticket di priorità alta [bug-report-q1.md]

3. **Penali asimmetriche** — previste solo in una direzione [contratto-fornitore.pdf]

Installazione

Con Homebrew (macOS — il modo più comodo)

brew tap MatteoAdamo82/loom
brew install loom

Questo installa sia loom (CLI) che loom-mcp (server MCP). La GUI desktop (Loom.app) è disponibile come download separato nella pagina releases.

Da sorgente

git clone https://github.com/MatteoAdamo82/loom.git
cd loom
go install ./cmd/loom ./cmd/loom-mcp

Richiede Go 1.26+. Nient’altro.

Avvio rapido

# Inizializza: crea ~/.loom/config.toml e la cartella ~/loom/
loom init

# Metti i tuoi file in ~/loom/

# Indicizza
loom scan

# Interroga
loom ask "cosa ho scritto sul progetto X?"

Configurazione: scegli il tuo provider LLM

Questa è la parte dove Loom si distingue da tanti tool simili: non sei vincolato a un provider specifico. Il file ~/.loom/config.toml (creato automaticamente da loom init) contiene già tutti e tre i blocchi pronti, commentati:

# Ollama (locale, default)
[llm]
provider    = "ollama"
model       = "llama3.1:8b"
endpoint    = "http://localhost:11434"
api_key_env = ""

# Anthropic Claude
# [llm]
# provider    = "anthropic"
# model       = "claude-sonnet-4-5"
# api_key_env = "ANTHROPIC_API_KEY"

# OpenAI
# [llm]
# provider    = "openai"
# model       = "gpt-4o"
# api_key_env = "OPENAI_API_KEY"

Per cambiare provider: decommentate il blocco che volete e commentate gli altri. Fatto.

ProviderproviderEsempio modelloNote
Ollama (locale)ollamallama3.1:8b, qwq:32bNessuna API key, gira sul tuo PC
Anthropic Claudeanthropicclaude-sonnet-4-5Richiede ANTHROPIC_API_KEY
OpenAIopenaigpt-4oRichiede OPENAI_API_KEY

Nota su api_key_env: il valore è il nome della variabile d’ambiente, non la chiave stessa. La chiave non viene mai scritta su disco. Prima di avviare Loom, esportate la variabile nel vostro shell:

export ANTHROPIC_API_KEY=sk-ant-...
# oppure
export OPENAI_API_KEY=sk-...

La scelta del provider dipende dal vostro caso d’uso: Ollama se volete privacy totale e avete l’hardware (in caso contrario ci sono sempre i modelli :cloud), Claude o GPT-4o se volete la qualità massima dei riassunti senza preoccuparvi dei requisiti hardware e privacy.


Integrazione MCP: Loom dentro Claude

Loom include un server MCP (loom-mcp) che espone la vostra knowledge base a qualsiasi client MCP — Claude Desktop, Claude Code, e non solo.

Con Claude Desktop

Aggiungete al file ~/.claude/settings.json:

{
  "mcpServers": {
    "loom": {
      "command": "loom-mcp",
      "args": ["--config", "/Users/ilmionomeutente/.loom/config.toml"]
    }
  }
}

Da quel momento, Claude Desktop può accedere alle vostre note direttamente in conversazione. Potete chiedere: “controlla le note su postgres tuning” e Claude cercherà nei vostri file senza che dobbiate incollare niente.

Con Claude Code

claude mcp add loom loom-mcp

I tool MCP esposti sono cinque:

ToolCosa fa
loom.ask(question, top_k?)Risposta completa con citazioni (1 chiamata LLM)
loom.search(query, limit?)Ricerca BM25 grezza, nessuna chiamata LLM
loom.scan(force?)(Re)indicizza la cartella
loom.list_files()Lista tutti i file con riassunto e keyword
loom.get_file(rel_path)Contenuto completo di un file specifico

Supporto PDF e OCR

I PDF vengono gestiti in tre livelli:

  1. Estrazione testo puro con ledongthuc/pdf (Go nativo, zero dipendenze)
  2. Se una pagina è vuota e pdftoppm + tesseract sono nel PATH, viene usato l’OCR
  3. Se entrambi falliscono, il file viene comunque indicizzato con un placeholder — l’LLM non potrà citarlo, ma non crasha niente

Per attivare l’OCR:

# macOS
brew install poppler tesseract tesseract-lang

# Debian/Ubuntu
sudo apt install poppler-utils tesseract-ocr tesseract-ocr-ita

Lingue multiple? Impostate la variabile d’ambiente:

export TESSERACT_LANGS="eng+ita"

GUI Desktop (opzionale)

Se preferite qualcosa di più visuale, Loom include una GUI desktop costruita con Wails (Go + Svelte). Scaricate il binario per il vostro sistema dalla pagina releases.

L’interfaccia ha due pannelli: la lista dei file a sinistra, la chat a destra. Cliccate un file per aprire un viewer con rendering Markdown. Cliccate una pill di citazione [file.md] in una risposta per saltare direttamente a quel file. Le impostazioni (provider, modello, endpoint, variabile API key, cartella) sono in un unico modale. Tutto lì.


Casi d’uso: quando Loom ha senso

Le vostre note di lavoro e ricerca Anni di Markdown, export da Obsidian o Notion, appunti vari in una cartella. Loom li rende interrogabili senza migrazioni. Mettete la cartella in ~/loom/, fate loom scan, e potete chiedere cose tipo “cosa avevo deciso sulla gestione degli errori nel progetto Y?”.

Knowledge base personale Articoli salvati, PDF di documentazione, specifiche tecniche, note di meeting. Tutto quello che accumulate nel tempo e che poi non riuscite a ritrovare.

Integrazione nel workflow di sviluppo Con il server MCP, Claude Code può accedere alle vostre note mentre lavora sul codice. Un file decisioni-architetturali.md nella loom dir viene letto automaticamente quando è rilevante.

Documenti di progetto Specifiche, requisiti, bug report, changelogs. Roba che di solito è sparsa in mille posti e che vorreste poter interrogare in linguaggio naturale invece di fare grep -r.


Loom vs Doc Analyzer: quando usare quale

Avendo costruito entrambi, ho le idee chiare su quando uno vale l’altro.

LoomDoc Analyzer
Installazionebrew install loomDocker Compose + Qdrant
Provider LLMOllama / Claude / OpenAIOllama (LLM + embedding)
RicercaBM25 su FTS5Similarity search su vettori
ChunkingNo (file interi)Sì (~1000 char con overlap)
UICLI + GUI desktop opzionaleWeb app con auth HTTP Basic
MCPSì (nativo)No
Import URL/YouTubeNo

Usate Loom se: i vostri documenti sono già sul disco, volete zero infrastruttura, lavorate molto con Claude Code/Desktop, o volete flessibilità sulla scelta del provider LLM.

Usate Doc Analyzer se: avete documenti molto lunghi e eterogenei, volete la ricerca semantica vera, avete bisogno di un’interfaccia web condivisibile, o volete importare da URL e YouTube.

Non si escludono: io li uso entrambi, per contesti diversi.


La lezione (tecnica) dietro a Loom

Il RAG classico è spesso over-engineered per l’uso personale. Chunking, embedding, vector store, re-ranking — ogni pezzo ha senso in scenari enterprise con corpus enormi. Per le proprie note, il riassunto pre-calcolato + BM25 copre il 95% dei casi con il 20% della complessità.

l’LLM capisce il linguaggio naturale meglio di quanto un indice vettoriale capisca la similarità semantica. Se gli date i riassunti giusti, sa cosa è rilevante. Il vostro compito è solo trovare “abbastanza” candidati — e per quello, BM25 basta.

E il Go? Tre motivi. Il primo è tecnico: concorrenza nativa per scansionare molti file in parallelo, compilazione in un binario statico senza runtime da distribuire, performance che con Python avrebbero richiesto workaround. Il secondo è pratico: sul lavoro lo uso raramente, e un progetto personale è il contesto ideale per tenersi in forma su un linguaggio. Il terzo è che riduce la complessità del progetto: meno dipendenze, meno layer di astrazione, meno cose che possono rompersi. Non è la scelta “cool” del momento, ma è quella che ha senso per questo caso d’uso.


Risorse


P.S. Se vi aspettavate uno stack con Kubernetes, un message broker e almeno tre acronimi che non avete mai sentito, mi dispiace deludervi. Un file SQLite, un binario e l’LLM che già usate sono più che sufficienti nella maggior parte dei casi.

Copiato