Da qualche mese i numeri di Sustainable ITC arrivano su Substack in modo diverso, e il motivo è meno nobile di quanto vorrei: mi ero stufato di fare avanti e indietro tra Claude e l’editor di Substack. Ma per capire dove sta il problema, conviene raccontare come nasce un numero.
Si comincia sempre leggendo: articoli, paper, report, tutto quello che, nel corso della settimana, mi ha fatto alzare un sopracciglio. Poi chiedo a un LLM (Claudio o Perplesso) di cercare altre fonti sullo stesso tema, le leggo, tengo quelle che reggono e scarto le altre. A quel punto il modello intreccia il materiale in uno scheletro di numeri, con una skill di logica avversariale che mette alla prova numeri e concetti prima che finiscano nel testo, perché una newsletter sulla sostenibilità che cita dati sbagliati perde in fretta la fiducia di chi la legge.

Chi segue questo blog potrebbe obiettare: «E la Fase 0? Qui lo scheletro argomentativo lo scrivo io, e Claude non procede finché non c’è (ne ho parlato nel paradosso del cervello aumentato). Sulla newsletter il lavoro è di un altro tipo. Le fonti le scelgo io, sia quelle che porto sia quelle proposte dal modello, che entrano solo dopo che le ho lette e approvate; al modello delego l’intreccio di un materiale già selezionato e verificato, e lo scheletro che ne esce lo compilo io, che è il momento in cui il numero prende la mia voce.
Il problema arrivava dopo, perché lo scheletro viveva in una conversazione con Claude mentre il numero doveva finire nell’editor di Substack. In mezzo c’era un corridoio di copia e incolla: copiavo, incollavo, mi accorgevo che un paragrafo andava riscritto, tornavo nella chat, lo riscrivevo e ricominciavo il giro, e alla fine restava ancora la copertina da generare, scaricare e caricare a mano. Erano passaggi banali, che facevo con la testa già al numero successivo, ed era proprio lì che si annidavano gli errori.
Come funziona adesso
Oggi lo scheletro arriva come file Markdown e diventa una bozza su Substack con un solo comando:
substack article draft numero.md --cover copertina.png
Quando apro Substack trovo la bozza con titolo, sottotitolo e copertina, e da quel momento lavoro direttamente nell’editor web, senza più riportare il testo nella chat. Sul singolo numero il risparmio è contenuto, nell’ordine dei minuti. Quello che è cambiato davvero è che posso tenere più numeri in lavorazione contemporaneamente, ognuno già al suo posto su Substack, e sbaglio meno nelle fasi di pubblicazione. C’è un’eccezione: alcuni numeri sono traduzioni di articoli tecnici della Green Software Foundation (GSF) senza un mio commento, e per quelli il tempo si è ridotto di diversi ordini di grandezza.
Quando il numero è uscito, faccio il percorso inverso:
substack article export 123456789 --out numeri/123.md
L’articolo torna in Markdown e finisce in un repository locale che uso come fonte di verità e come memoria della newsletter. Quando preparo un numero nuovo, il modello può vedere cosa ho già scritto e proporre collegamenti con i numeri precedenti; quali tenere lo decido io, con una regola precisa: un numero vecchio si cita per rafforzare le fonti originali, mai per sostituirle. È il mio piccolo “te l’avevo (già) detto” alla Puffo Quattrocchi, che però arriva sempre accompagnato dalla fonte da cui è nato.
C’è poi la coda delle note, i messaggi brevi di Substack. Confesso che finora non le avevo mai gestite, un po’ per pigrizia e un po’ perché le consideravo un’attività a basso valore aggiunto che mangia tempo, cioè proprio il tipo di lavoro che ha senso delegare a un LLM. Adesso le faccio ricavare direttamente dagli articoli, le metto in coda e le pubblico dal CLI, a mano oppure a orario: in quel caso basta un comando lanciato ogni minuto da cron, da un timer systemd o da un CronJob su k3s (una distribuzione leggera di Kubernetes), che le pubblica all’orario previsto.
Le note sono anche il motivo principale per cui il CLI ha un comando generate, che chiede a un modello di scrivere un testo a partire da un tema (o da un post appena scritto), passando dall’API di Anthropic (application programming interface, l’interfaccia con cui un programma dialoga con un servizio) oppure dal mio server locale come llama.cpp (o Ollama). Per ora nel mio processo non ha ancora un ruolo stabile, e mi è capitato di usarlo anche per riassumere i concetti principali di documenti molto lunghi. In ogni caso, produce solo bozze e note in coda: niente di ciò che genera va online da solo e senza il mio esplicito consenso.
Perché tanta cautela
Substack non offre API pubbliche, quindi substack-cli usa quelle interne del sito e si autentica con il cookie di sessione del vostro account, il che significa che ogni comando lanciato dal programma, per Substack, arriva da voi. Lo stesso programma che crea una bozza potrebbe pubblicare un articolo a metà o inviare un’email a tutti gli iscritti alle tre di notte, solo perché uno script è partito all’ora sbagliata.
Per questo, se si prova a pubblicare da uno script senza una conferma esplicita, il programma si ferma prima di fare qualsiasi richiesta di rete:
$ substack article publish 123456789
Errore: Pubblicazione non interattiva: aggiungi
--yes per confermare esplicitamente
Da terminale la conferma è una parola digitata a mano, da uno script serve il flag --yes. Con article publish l’email agli iscritti parte solo se aggiungete --send-email. Il cookie non compare mai in output, log o messaggi d’errore, e viene inviato soltanto a substack.com. La coda delle note è protetta da un lock, e una nota di cui non si sa se sia uscita resta ferma finché non decidete voi, così non rischiate di pubblicarla due volte.
Qualcuno potrebbe pensare che, per uno strumento nato per l’uso personale, sia troppo. Penso che la sicurezza serva anche quando l’unica persona che puoi danneggiare sei tu, perché la mia lista di iscritti merita la stessa cura di quella di chiunque altro; il fatto che il progetto sia open source, e quindi possa finire sulle newsletter di persone che non conosco, alza soltanto l’asticella.
La cura si vede anche nei numeri del progetto.
Ci sono, ad oggi, 379 test, tra unitari, funzionali e di sicurezza, e un mutation score del 96% su 1.523 mutanti (il mutation testing introduce piccoli errori nel codice e verifica che i test se ne accorgano). C’è un report di red team pubblico, cioè un resoconto dei tentativi di attaccare il programma come farebbe un avversario. E le dipendenze di runtime sono tre: marked, yaml, zod. Chi ha letto Espandi, poi pota riconoscere il metodo, e chi ha letto Adversarial verification come metodo riconoscerà il red team.
I limiti, detti chiaramente
substack-cli è uno strumento non ufficiale e in beta.
Le API che usa non sono documentate e possono cambiare domani mattina; quando succede, il programma esce con un codice d’errore dedicato invece di fare danni in silenzio, ma smette comunque di funzionare finché qualcuno non lo aggiorna. Gli endpoint per il caricamento di immagini e copertine sono ancora contrassegnati come non confermati nella documentazione. Il Markdown supportato copre quanto serve per un articolo (titoli, enfasi, liste, citazioni, codice, link) e rifiuta con un errore esplicito ciò che non sa gestire, come le tabelle e l’HTML grezzo. Prima di usarlo conviene dare un’occhiata alle condizioni d’uso di Substack, perché l’uso è a vostro rischio.
La morale
Il codice si scrive perché c’è un obiettivo, e il mio era togliermi di mano i passaggi meccanici, quelli in cui sbagliavo di più, per lasciare più spazio alla lettura e alla scrittura. Le decisioni su cosa pubblicare, quando e con quali fonti restano mie; il CLI porta il testo dove serve, mette una sicura sui comandi che non si possono annullare e tiene in ordine un archivio che il modello può consultare.
Se scrivete una newsletter su Substack, provatelo: trovate tutto su fullo.github.io/substack-cli e il codice su GitHub. Poi ditemi come lo state usando, cosa vi manca e cosa si rompe. Le issue sono aperte, e mi interessa soprattutto il caso d’uso a cui non ho pensato.