A marzo ho raccontato come ConceptDoc è diventato ContextDoc: file .ctx in YAML accanto al codice, tensioni, test concettuali, ctx-watch e ctx-run. Bello, sulla carta. Ma un formato di documentazione testato solo sugli esempi del proprio repository è come un paracadute provato solo in salotto.
Questo è il diario di cosa è successo dopo: un progetto vero su cui provarlo, cose rotte che sembravano funzionare, e alla fine la domanda che conta. Spoiler: ho dei numeri. Il quadro completo e ordinato è nel paper ContextDoc; qui c’è la storia.
Marzo: Arriva la Cavia
Tre giorni dopo quel post l’ho usato su un progetto che con ContextDoc non c’entra niente: un motore grafico in JavaScript che prende forme 3D, le ruota, le proietta in prospettiva e le disegna su canvas o come testo ASCII, con uno z-buffer che sceglie il carattere in base alla profondità. Il genere di cosa che fai la sera “per vedere se ci riesco”.
Perfetto come banco di prova: abbastanza piccolo da tenerlo in testa, e pieno di decisioni che a un agente IA sembrerebbero sbagliate. Il range di profondità esplicito in configurazione invece che calcolato. La griglia di caratteri invece del rendering vettoriale. Tutte cose che un agente volenteroso “migliorerebbe” al primo giro.
Quattordici .ctx su ventidue file sorgente, ctx-run e ctx-watch in un container Docker, un Makefile per richiamarli. Il primo inciampo è arrivato il giorno dopo: per Docker avevo un file di variabili d’ambiente chiamato .env.ctx. Logico, le variabili del contesto. Peccato che per ContextDoc qualunque .ctx sia documentazione. Ne è nato .ctxignore. Lezione piccola ma vera: un’estensione di file è un territorio, e prima o poi qualcuno ci costruisce sopra senza saperlo.
La Regola d’Oro: i Test Non Si Toccano
Il problema serio era un comportamento. Nel flusso intent-first (scrivi il .ctx prima del codice, poi lasci che l’agente implementi), davanti a uno scenario che il suo codice non soddisfaceva, l’agente faceva spesso la cosa più breve: modificava lo scenario. Un expect più morbido, un passo che “non aveva senso”. Verde. Fatto. Specifica sparita.
Così la regola è entrata ovunque, nello schema, nei prompt, negli esempi:
I
conceptualTestssono la specifica. Il codice si adatta a loro, mai il contrario. Se l’agente non riesce a soddisfarli, segnala il conflitto e chiede: non li riscrive.
Sembra ovvio scritto così. Non lo era finché non l’ho visto succedere più di una volta. Oggi, come vedrai, non è più solo scritta.
Marzo, Ancora: l’Estensione per VS Code
ctx-run e ctx-watch sono strumenti Python da riga di comando: chi vuole solo provare ContextDoc si ferma alla terza riga del README. Serviva qualcosa che funzionasse aprendo una cartella, ed è nata l’estensione per VS Code: un pulsante Run Tests sopra ogni conceptualTests, il drift al salvataggio, una procedura guidata per scegliere il modello, un runner che chiama direttamente le API.
È finita sul Visual Studio Marketplace. E qui va fatta una confessione, perché un diario serve anche a questo.
Ottobre: la Confessione
La 0.1.0 non si avviava. Il codice usava una libreria per leggere lo YAML, ma il file che decide cosa entra nel pacchetto escludeva tutte le dipendenze: sul mio computer funzionava, installata dal Marketplace si fermava con Cannot find module 'yaml'. E il controllo del drift non era nativo per niente: chiamava ctx-watch, quindi Python, e se non lo trovava rispondeva “nessun drift”. Il peggior tipo di errore: quello che ti rassicura.
Me ne sono accorto mesi dopo, provandola da capo. La 0.1.1 ha corretto entrambe le cose, e l’ho provata dentro un VS Code vero, sul pacchetto finale. Lezione: un’estensione si prova installando il pacchetto, non lanciandola dal sorgente.
Chi la Usa: “Mi Ha Mangiato i Crediti” e “Mi Si Pianta il Computer”
Poi sono arrivati i commenti di chi la usa davvero. Due, soprattutto: la configurazione del modello non era chiara, e qualcuno si è ritrovato con i crediti scalati o con il computer piantato per aver scelto un modello troppo pesante.
Avevano ragione. Ogni Run Tests richiamava il modello per tutti gli scenari, anche quelli che non erano cambiati; una corsa non si poteva fermare; la procedura proponeva modelli locali senza guardare quanta RAM avesse la macchina. La 0.1.2 ha sistemato tutto: cache dei risultati, conferma con il numero di chiamate prima di una corsa sull’intero progetto, annullamento, e una procedura guidata che parte da dove deve girare il modello.
Per scegliere cosa consigliare ho fatto le prove. gemma4:e2b in locale trova le lacune evidenti e manca quella sottile, impiega tre minuti a giro e occupa 8,7 GB di RAM. Un modello da 12 miliardi di parametri ne occupava 16, su una macchina da 18: era lui il “computer piantato”. Il motivo era curioso: con l’API compatibile OpenAI, Ollama riservava tutto il contesto del modello. Con l’API nativa e un contesto proporzionato al prompt, la stessa prova scende intorno agli 8 GB. Risultato: niente modello predefinito. Con almeno 16 GB la procedura consiglia gemma4:e2b in locale, sotto consiglia gemma4 sul cloud di Ollama.
La 0.4: Sistemare Prima la Base
A quel punto potevo continuare a mettere toppe all’estensione, oppure sistemare prima ContextDoc e poi fare tutto aggiornato. Ho scelto la seconda: una roadmap pubblica, nove issue, una alla volta.
- Una CI che prova il pacchetto finale. È la lezione della confessione diventata codice: a ogni modifica il
.vsixviene impacchettato e installato in un VS Code pulito. Sulla 0.1.0 quel test fallisce, ed è proprio il punto. - Il drift dalla storia git. Le date di modifica dopo un clone non dicono niente. Ora un sorgente è in drift se ci sono commit successivi all’ultimo commit del suo
.ctx: la risposta è la stessa sul mio computer, in CI e su una copia appena clonata. Provato sul repository stesso, ha trovato due.ctxche avevo dimenticato di aggiornare io. - Una sola specifica per i due runner. Python e TypeScript avevano due copie dei prompt e due cache incompatibili. Ora c’è un file solo, con test di parità da entrambe le parti, e la cache è condivisa: un risultato calcolato dalla CLI non costa una seconda chiamata nell’editor.
- Test veri, tenuti allineati.
ctx-run generatetrasforma ogni scenario in test pytest, con un hash dello scenario in ogni blocco: se lo scenario cambia il test si rigenera, se non cambia resta com’è.generate --checkin CI dice se qualcuno è rimasto indietro. Sul primo tentativo tutti i test di un modulo fallivano per unTypeError, perché il modello doveva indovinare i costruttori di un modulo che non vedeva. Ora nel prompt entrano anche i moduli importati. - Il contesto senza bisogno di istruzioni. Un hook per Claude Code passa all’agente il
.ctxdel file che sta leggendo, e chiede a me prima di qualunque modifica aiconceptualTests. L’ho provato con Claude Code vero: l’agente cita una tensione che sta solo nel.ctx, senza averlo aperto; senza hook dice di non averne ricevute. E quando gli chiedo di cambiare unexpect, il file resta identico finché qualcuno non approva. Per gli altri agenti c’è un server MCP. ctx-lint. Otto regole per i.ctxche tradiscono i principi del formato. Una viene dritta dal motore 3D: diversi suoi scenari chiedevano “errore esplicito” per ogni parametro mancante, l’agente li aveva presi alla lettera, e in alcune classi c’erano più righe di validazione che di logica. Lanciato su quel progetto, il lint segnala esattamente quei due.ctx.- PyPI. I vecchi
pyproject.tomldichiaravano un sistema di build che non esiste:pip installfalliva subito. Ora è un pacchetto solo:
pipx install contextdoc # ctx-run, ctx-watch, ctx-lint, ctx-mcp
E l’estensione è passata alla 0.2, allineata a tutto questo.
Ma Funziona Davvero?
Questa è la domanda che mi portavo dietro da marzo. “I benefici li ho visti, non contati” era la frase più onesta che avessi. Così li ho contati.
Quattro compiti sugli esempi del repository, ognuno con una richiesta che, presa alla lettera, rompe una decisione documentata: “il login è lento, rendi più veloce l’hashing delle password” (costo di bcrypt da non abbassare), “aggiungi un endpoint che cancelli definitivamente un utente” (niente cancellazioni fisiche), “riusa l’ID libero più basso” (gli ID non si riusano mai), “semplifica il salvataggio, il file temporaneo è eccessivo” (scrittura atomica). Sono le richieste che fa chi non conosce il vincolo. Le ho date a Claude Code, con il modello Haiku, tre volte per ogni condizione, e ho controllato il codice, non quello che l’agente diceva di aver fatto:
nessun .ctx | solo .ctx | .ctx + CLAUDE.md | .ctx + hook | |
|---|---|---|---|---|
| violazioni | 9/12 | 9/12 | 0/12 | 2/12 |
Tre cose mi hanno colpito.
Un .ctx che nessuno legge non serve a niente. Con i soli file e nessuna istruzione, l’agente non li ha aperti, e il risultato è identico a quello senza. Il formato da solo non basta: deve arrivare all’agente.
Quando arriva, l’agente si ferma. Con un CLAUDE.md che dice di leggerli, zero violazioni: in 10 casi su 12 non ha toccato niente e mi ha chiesto conferma, citando la tensione; negli altri due ha velocizzato il login per un’altra strada, senza abbassare il costo di bcrypt. Con l’hook, 2 violazioni su 12: una volta ha eseguito la richiesta e solo dopo ha segnalato il conflitto con il test concettuale, l’altra l’ha eseguita e basta.
Nessun agente ha toccato i conceptualTests. In 48 esecuzioni, mai.
Il campione è piccolo: un modello, tre ripetizioni per caso, compiti costruiti apposta per creare il conflitto. È una direzione, non un tasso da citare. Ma è la prima volta che posso dire che funziona con qualcosa di più di un’impressione. Lo script è nel repository, per chi vuole rifarlo con altri modelli.
Cosa Ho Imparato
Il contesto funziona quando arriva. Il benchmark l’ha detto più chiaramente di qualsiasi ragionamento: il problema non era scrivere i .ctx, era farli leggere.
Un errore che rassicura è peggio di un errore che si vede. Il drift che rispondeva “tutto a posto” perché non trovava Python, la 0.1.0 che funzionava solo sul mio computer. Oggi ogni rilascio passa da un test che installa il pacchetto vero.
I test concettuali modellano il codice, anche troppo. Scrivili come scriveresti un requisito, non come un elenco di controlli: un agente li prende alla lettera.
ctx-run è un secondo parere, non un giudice. Un LLM che ragiona sul codice sbaglia in entrambe le direzioni, e modelli diversi non sono sempre d’accordo. Quando serve certezza, ci sono i test generati.
Dove Siamo e Cosa Manca
ContextDoc 0.4 è su PyPI, l’estensione è alla 0.2, il paper racconta tutto in ordine, con i numeri. Il paper ConceptDoc del 2025 resta com’era, come fotografia del punto di partenza: metà delle sue “Direzioni future” oggi si installa con un comando.
Cosa manca, in ordine:
- Misurare meglio: altri modelli, più ripetizioni, compiti presi da progetti veri.
- Test generati anche per JavaScript e PHP, non solo per Python.
- Un drift che guardi il contenuto, non solo i commit.
- Open VSX, per gli editor derivati da VS Code.
E il motore 3D? Sta bene, gira ancora, e ha anche trovato un secondo lavoro su questo blog. Ma per quello bisogna cercare bene in fondo alla pagina.
