Kanon
Elke regel die deze sessie stuurt, bij naam. Ook die waarvan je dacht dat hij geladen was.
Een CLAUDE.md kan van allerlei kanten je context binnenkomen, en Claude Code meldt er geen enkele. Wat je niet ziet laden, kun je ook niet beoordelen.
- TypeScript
- Bun
- Claude Code
- hooks
GitHub (opent in een nieuw tabblad)README (opent in een nieuw tabblad)Changelog (opent in een nieuw tabblad)
Wat het doet
Kanon is een Claude Code-plugin, geen MCP-server: hooks die meeschrijven zodra er een instructiebestand laadt. Aan het eind van een sessie weet je welk bestand je context binnenkwam, in welke volgorde, en om welke reden Claude Code het laadde.
Een CLAUDE.md kan van veel kanten komen. Uit het project waar je in zit, uit je eigen ~/.claude-map, uit een map boven je, uit een submap waar Claude langskwam, uit een @path-import vier stappen verderop, of uit een dependency die er stilletjes een meelevert. Claude Code laadt ze allemaal op dezelfde manier en meldt er geen enkele.

FOREIGN is de belangrijkste vermelding in dat overzicht. Zo'n bestand praat mee in je sessie zonder dat jij daarvoor koos. missing is een fout: dat bestand hoorde bij de start te laden en deed dat niet. quiet zegt alleen iets over deze sessie: die regel stond er wel, maar niets bracht hem in werking.
Wat er veranderde sinds de vorige keer
Kanon onthoudt welke instructiebestanden hier eerder een sessie stuurden, met een sha256 van elk. Een bestand dat het nooit eerder zag laden heet appeared, een bestand waarvan de bytes veranderden changed, en een bestand dat van schijf is verdwenen vanished, eenmalig, op het moment dat het weggaat.
Het geval waarvoor die sectie bestaat, is een dependency die wordt bijgewerkt en daarbij zijn CLAUDE.md stilletjes herschrijft. De lijst bestanden ziet er dan volkomen normaal uit en alleen de inhoud is anders. Een digest ziet dat verschil zonder dat Kanon hoeft te lezen wat er staat, en dus kan Kanon je vertellen dát een bestand veranderde, maar niet wat erin veranderde. Die diff lees je zelf.
Wat Claude te horen krijgt
Claude krijgt alle instructiebestanden samengevoegd in één context, zonder te weten waar ze vandaan komen. Een regel die jij schreef en een regel die een dependency meestuurde zien er van binnenuit identiek uit. Bij de start van elke sessie zet Kanon dat recht:

Van elk bestand de herkomst, van elk vreemd bestand de eerste instructie die het oplegt, wat er sinds de vorige sessie veranderde, en de opdracht om je te vertellen wat er opvalt. Dat gaat via beide kanalen van SessionStart: additionalContext bereikt het model, systemMessage staat in je transcript. Allebei dezelfde tekst, want een briefing die jou iets anders vertelt dan Claude is precies de fout die deze plugin moet vangen.
Een instructiebestand kan ook uren later nog laden, lang nadat die briefing is gegeven. Gaat het om een vreemd bestand, dan noemt Kanon het bij je eerstvolgende prompt. Dat moet daar gebeuren, want Claude Code gooit de uitvoer van InstructionsLoaded weg: de hook die ziet dat er een bestand laadt, kan daar zelf niets over zeggen. Op een gewone beurt kost die controle één wc -l, en is het sessielog niet gegroeid, dan start Bun niet eens.
Snel starten
Vereist Bun 1.1 of nieuwer, verder niets. Kanon doet geen enkel netwerkverzoek, heeft geen API key en blokkeert nooit een sessie.
claude plugin marketplace add https://aranea-development.nl/plugins/marketplace.json
claude plugin install kanon@araneaHooks worden bij de start van een sessie geregistreerd, dus start een nieuwe sessie voordat Kanon iets ziet. Wat er vóór de installatie gebeurde, valt niet te reconstrueren.
Loopt de installatie vast op ssh: connect to host github.com port 22, dan haalt git de plugin uit de GitHub-repository over SSH en lukt dat op die machine niet. De melding wijst naar toegangsrechten, maar de repository is openbaar. Het transport is het probleem. Eén regel zet git op HTTPS, daarna kun je opnieuw installeren:
git config --global --add url."https://github.com/".insteadOf "git@github.com:"In de README staat de uitgebreide versie, inclusief hoe je het terugdraait.
Drie vragen, drie commando's
/kanon geeft het rapport van de sessie waar je in zit. Zonder argumenten pakt het de laatste sessie die vanuit deze repository is opgenomen, en het wijkt nooit uit naar een sessie uit een andere map: wat in de ene repository laadde afzetten tegen de verwachtingen van de andere levert alarm op dat nergens op slaat.
/kanon:whose <zinsnede> beantwoordt de vraag waar een regel vandaan komt. Claude krijgt alle instructiebestanden samengevoegd in één context, zonder bronvermelding, dus als hij iets doet wat je niet verwachtte, kun je nergens navragen welk bestand dat oplegde. Dit is die vraag.
WHOSE "geen em dashes" observed
user ~/.claude/rules/schrijfstijl.md line 24
"- **Geen em dashes (—).** Gebruik een komma of twee korte zinnen."Zoeken is hoofdletterongevoelig en doorzoekt de tekst met de witruimte samengevouwen, zodat een zinsnede die over een regeleinde heen valt toch gevonden wordt. Instructiebestanden hebben harde regeleindes, en juist de zin die je onthoudt wordt daar meestal door in tweeën gebroken.
Het lege antwoord is vaak het nuttigst. Staat de zinsnede in geen enkel sturend bestand, dan zegt Kanon dat en noemt hoeveel bestanden het doorzocht. Die richtlijn kwam dan binnen via een oppervlak dat Kanon niet ziet: een skill, een MCP-server of de hook van een andere plugin. Of hij stond nooit in een instructiebestand.
/kanon:audit somt elk instructiebestand op dat in deze checkout een sessie zou kúnnen sturen. Er is geen sessie voor nodig, dus het werkt ook in een repository waarin nog niets heeft gedraaid. Dat is het punt: je hebt net iets gekloond, of een installatie heeft packages toegevoegd, en je wilt weten wat er een stem heeft gekregen, voordat het die stem gebruikt.

De tweede kolom zegt hoe een bestand zóú laden, nooit dat het geladen is. Een on-demand-bestand in een dependency komt pas in werking als Claude iets in die map leest. De audit gaat dependency- en puntmappen bewust binnen, wat de rest van Kanon weigert. Die weigering houdt stand zolang er een sessie is die het laden kan waarnemen, en een audit draait juist waar nog niets liep. .git gaat nooit open.
Twee lagen, en waarom dat uitmaakt
De plugin bestaat uit twee helften die opzettelijk gescheiden zijn.
De eerste helft kijkt. Een hook schrijft elk event onbewerkt weg naar ~/.kanon/sessions/<id>.jsonl en ontleedt vrijwel niets. Deze helft heeft geen model van Claude Code nodig en staat dus nooit ter discussie.
De tweede helft voorspelt. Die bouwt na hoe Claude Code instructiebestanden opzoekt, om te kunnen zeggen wat er had moeten laden. Dat kan misgaan, en de code geeft dat toe: laadt er een bestand dat het model niet voorzag, dan zegt Kanon dat en verklaart zijn eigen NOT LOADED-sectie onbetrouwbaar voor die sessie. Wat er werkelijk laadde, blijft daarbij overeind, want die helft steunt op geen enkel model.
Elk rapport draagt een ruleset-stempel. Kanon moet Claude Code modelleren om verwachtingen te kunnen uitspreken, en dat gedrag is van Anthropic: het kan veranderen. De stempel zorgt dat een verouderd model opvalt in plaats van stilletjes mee te draaien.

Wat het niet doet
Kanon meldt welke bestanden je context bereikten en waar ze vandaan komen. Het leest ze niet inhoudelijk, geeft ze geen cijfer, rangschikt ze niet en scant ze niet op prompt injection. Of de instructies van een dependency in jouw sessie thuishoren, beslis jij. Kanon zorgt dat je weet dat ze er zijn.
Op dat laatste is één uitzondering: de briefing citeert de eerste inhoudelijke regel van een vreemd bestand, zodat Claude die kan herkennen tussen de instructies die al in zijn context zitten. Het blijft daarbij bij citeren.
/kanon:whose zoekt in diezelfde bestanden naar een letterlijke tekst en citeert de regel waarop die staat. Dat is herkomst, dezelfde categorie als de digest en het geciteerde eerste voorschrift: het wijst tekst aan zonder er een mening over te vormen. Treffers staan op volgorde van herkomst, zonder score of rangschikking, en Kanon zegt nergens of een regel een goede regel is.
Een richtlijn kan ook uit een skill komen, uit een MCP-server, uit een output style of uit de hook van een andere plugin. Die oppervlakken modelleert Kanon niet, en dat is structureel: Claude Code vuurt een hook af als een instructiebestand laadt en vuurt niets af als de tekst van een skill of de instructies van een server je context binnenkomen. Alles wat Kanon over instructiebestanden meldt is waargenomen, of het draagt het etiket van een voorspelling die je ertegen kunt afzetten. Op die andere oppervlakken heeft het die grond niet, en /kanon:whose zegt dat dan ook op het moment dat het erop aankomt.
Blokkeren doet Kanon nooit. ConfigChange kan een configuratiewijziging tegenhouden, en Kanon laat dat na.
Alles staat onder ~/.kanon/, en Kanon schrijft nergens anders. Het leest ~/.claude/ en schrijft daar nooit in. Wat ouder is dan 90 dagen wordt bij de volgende run opgeruimd.