Peter Reckers

Innovatiepartner waar het telt · overheid, zorg, energie, infra · Automatisering & AI · Mijn werk spreekt voor zich door devblog

Van Stop-hook naar transcripts: devblog schrijft zichzelf

Deze post is geschreven door het ding waar de post over gaat. Dat is het hele punt.

devblog is een Claude Code-plugin die mijn codeersessies omzet in blogposts. Niet "een AI die wat verzint over je project", maar een tool die leest wat ik écht gedaan heb en daar een verhaal van maakt. Ik schrijf veel te weinig over mijn werk. De sessies bestaan al. Het gat zat ertussen.

Het eerste idee was te ijverig

De eerste versie deed wat je verwacht van iemand die te enthousiast begint: alles loggen. Een Stop-hook vuurde na elke turn, riep Claude aan om er één zin van te maken, en plakte die regel in een logbestand per project. De levensloop van een post (concept, goedgekeurd, gepubliceerd) zat in een SQLite-database. Er was zelfs een TUI om door je samenvattingen te bladeren.

Het werkte. Het was ook overdreven. Elke turn een LLM-call voor een zin die ik daarna nooit meer las.

De pivot zat in één zin

Toen typte ik dit, typefout en al:

ik wil het anders, ikw il niet iedere regel wegschrijven, ik wil de samenvatter van claude gebruiken, if 3 dagen niet actief dan blog schrijven en voorstellen

Daar staat de hele herbouw in. Claude Code houdt zélf al een volledig transcript bij van elke sessie. Die .jsonl-bestanden staan gewoon op je schijf. Ik was data aan het dupliceren die er al was. Mijn vraag daarna was simpel: "staat in transcript alle transcript?" Ja dus. De ruwe sessie staat erin, plus als bonus de compactie-samenvattingen die Claude soms zelf maakt. Niks gaat verloren, en ik hoef niks bij te houden.

Weg met de Stop-hook. Weg met het per-turn loggen. Weg met SQLite. En een tijdje later: weg met de TUI. De staat van een post is nu gewoon een map. Een draft is een markdown-bestand in drafts/. Goedkeuren is het bestand naar approved/ verplaatsen, publiceren naar published/. Je kunt de hele pipeline met ls en cat bekijken. Geen database om te migreren, niks magisch.

Hoe het nu loopt

De kern is één claude -p-run. Geen werk terwijl je codeert.

Dat de scan cross-project is, was een expliciete eis. Ik werk aan vijf dingen tegelijk; eentje is af en ga ik nooit meer openen. Juist díe verdient een terugblik. Dus draait de trigger op gebruikersniveau, via een dagelijkse launchd/cron-job plus de SessionStart-hook. Niet aan één repo vastgeklonken. En wil ik niet wachten op die drie dagen, dan tik ik /devblog write en schrijft hij nú.

Skills doen het zware werk

De schrijver is dom; de skills zijn slim. De claude -p-run krijgt een lijstje skills mee, en standaard zijn dat er drie:

"en de blog moet interresant en vermakelijk zijn", schreef ik ergens. Een changelog kan iedereen genereren. Een verhaal niet. De skills zijn losse markdown-bestanden, dus een mooie bloggersskill die ik tegenkom voeg ik toe aan de lijst, zonder een regel code aan te raken.

De moeilijkste eis: niet liegen

Een transcript is een rommelig dagboek. Het staat vol doodlopende wegen, ideeën die ik tien minuten later weggooide, en architecturen die nooit het daglicht zagen. Als de schrijver dat klakkeloos navertelt, krijg je een post die beschrijft hoe het project níet werkt.

Mijn correctie hierop: "ik moet beter de repo bijhouden en die ook laten scannen met transcript". Dat werd de splitsing die alles eronder draagt:

Verlaten ontwerpen mogen alleen als verleden langskomen. Bij twijfel: check de repo, niet het transcript. Daarom durf ik in deze post over die oude Stop-hook te schrijven. Ik weet zeker dat hij weg is, want hij staat niet meer in de code.

De rommel die niemand ziet

Een headless run heeft geen mens die op "allow" klikt, dus draait hij met overgeslagen permissies in een non-interactieve modus. Logisch, maar je moet het wel willen.

Vervelender: de schrijf-run is zelf een Claude Code-sessie, en die laat óók een transcript achter. Zonder ingreep wordt devblog dus materiaal voor zijn eigen volgende post. Een slang die zijn staart opeet. Twee hekjes lossen dat op. Een DEVBLOG_RUNNING-vlag zorgt dat de run de SessionStart-hook niet opnieuw afvuurt, en de run draait vanuit een wegwerp-map zodat zijn eigen transcript buiten de bronnen valt. En omdat dates op macOS en Linux verschillend werken, is er een epoch-functie die met allebei overweg kan. Klein, saai, en precies het soort ding dat je een uur kost.

Waar het nu staat

devblog publiceert standaard naar één statische HTML-pagina die het uit je posts bouwt, in de stijl van mijn eigen site, met dark mode en per-post SEO-meta. Liever losse markdown-bestanden of je eigen doel? Dan wijs je een andere adapter aan: argv in, body via stdin, één ref-regel op stdout. Pure bash. De enige afhankelijkheden zijn dingen die elke Claude Code-gebruiker al heeft: claude, jq, git.

Het mooiste: ik hoef hier niks meer voor te doen. Over drie dagen, als deze repo stil blijft, scant de cron-job hem, ziet nieuw materiaal, en schrijft de volgende post. Of hij over precies dít verhaal begint? Daar ga ik niet over. Dat is aan de transcripts.