Gebouwd: 2026-07-09. Alleen python3-stdlib (sqlite3 met FTS5, getest op Python 3.12.3 / SQLite 3.45.1) en bash. Geen pip, geen server. Het pakket wordt LEEG geleverd; alle tests hieronder draaiden met zelfgemaakte dummy-data (fictieve gebruiker Alex, companion Nova, bedrijf Brightbeam; zie examples/sample-input/).
De lagen en de keuzes
- Ingest + zoek (
ingest.py,ask.py,fimo_core.py) Een SQLite-bestand (data/brain.db) met een documents-tabel plus FTS5-index (external content, triggers houden 'm in sync). Idempotent via sha256 per bestand: ongewijzigd = overslaan, gewijzigd = update in place, nieuw = insert. JSON-chatexports worden platgeslagen naar leesbare tekst (tekstvelden van elke vendor-vorm), datum/titel/bron best-effort gedetecteerd.ask.pyzoekt eerst in de memory-files (gedestilleerd), dan FTS over de bronnen, elke hit met snippet en bronpad. - Canon (
generate_canon.py->CANON/KERN.md+CANON/LLM-PROMPT.md) Twee routes: (a) offline extract zonder LLM (corpus-stats, top-topics, key statements met altijd/nooit/regel/besloten-signaalwoorden, recente docs) en (b) model-agnostische prompt + corpus-digest die de gebruiker aan een eigen LLM voert en importeert met--from-file. Handwerk tussen<!-- HAND --> ... <!-- /HAND -->overleeft elke re-run byte voor byte (regex-extractie, blokken worden na de generated-sectie teruggeplaatst); alleen het blok tussen de GENERATED-markers wordt herschreven. - Memory (
remember.py,memory/MEMORY.md) Eén file per onderwerp, indexregel in MEMORY.md, geen duplicaten: zelfde onderwerp opnieuw = append in de bestaande file. - Archivers (
archivers/)run_ingest.shals enige entry point; systemd-user-timer (hourly, Persistent) en cron-template, beide met__FIMO_DIR__-placeholder;install.shvult het echte pad in en valt terug op cron-instructies zonder systemd. Canon-regeneratie zit bewust NIET in de timer (canon is iets dat je reviewt). - Session-start + gedrag (
session-start/)build_context.pyprint KERN.md + MEMORY.md + gebruiksinstructies; CLAUDE.md-template en hook-voorbeeld voor Claude Code, generiek system-prompt-blok voor andere runners.behavior_catcher.py+behavior-rules.txt(regex :: uitleg) als gedrag-catcher, met Stop-hook-modus die een blocking decision teruggeeft.
Self-verify gate: letterlijke uitslagen (alles echt gedraaid)
1. Dummy-chats erin, ask.py vindt de gezegde zin (PASS)
=== INGEST RUN 1 ===
Scanned: 4 | new: 4 | updated: 0 | unchanged: 0
Total in brain: 4
=== ASK: purple heron ===
--- SOURCES (raw documents) ---
* [2026-05-14] First long chat about the garden project (input)
... the >>purple<< >>heron<< lands at midnight on the old jetty. ...
JSON-export ook gevonden, met datum uit create_time:
=== ASK: hardcovers ===
* [2026-06-10] chat-export (input)
... paperbacks only, I never buy >>hardcovers<<.
2. Canon geregenereerd, HAND-blok overleeft (PASS, bewijs: diff)
Twee handmatige HAND-blokken in KERN.md gezet, daarna geregenereerd:
=== FULL-FILE DIFF (regen vs regen) ===
4c4
< *Offline structured extract, generated 2026-07-09 17:08 UTC. ...*
> *Offline structured extract, generated 2026-07-09 17:09 UTC. ...*
=== HAND-ONLY DIFF ===
HAND-only diff exit: 0 (identical, byte for byte)
Alleen de timestamp in de generated-sectie verschilt; beide HAND-blokken byte-identiek terug. Ook getest met --from-file (LLM-antwoord als generated body): "hand blocks preserved: 2".
3. Memory-file blijft staan over een verse sessie (PASS)
remember.py gedraaid, daarna in een NIEUW proces session-start/build_context.py:
- [liner order rule](liner-order-rule.md): Pond liners must be ordered two weeks ahead, decided after the June delay
- [book format](book-format.md): Paperbacks only, never hardcovers
Zelfde onderwerp nogmaals remember-en: append in de file, geen dubbele indexregel (grep-count op de indexregel bleef 1).
4. Archiver pakt nieuwe input (PASS)
Nieuwe dummy-file in input/ gezet, bash archivers/run_ingest.sh 1x handmatig gedraaid:
Scanned: 5 | new: 1 | updated: 0 | unchanged: 4
=== ASK: silver fox towpath ===
* [2026-07-01] Night walk chat 2026-07-01 (input)
... The >>silver<< >>fox<< crossed the >>towpath<< at dawn today.
5. Idempotent (PASS, bewijs: counts)
Scanned: 5 | new: 0 | updated: 0 | unchanged: 5 (run 1)
Scanned: 5 | new: 0 | updated: 0 | unchanged: 5 (run 2)
documents: 5
distinct paths: 5
Extra: gedrag-catcher (PASS)
echo "As an AI language model I cannot help with that. Is there anything else?" | behavior_catcher.py -
-> 3 violations, exit 2
hook-modus met fake transcript.jsonl:
-> {"decision": "block", "reason": "Behavior rules violated: ..."} , exit 0
schone reply -> exit 0
Extra: installer-templates
bash -n op beide shellscripts OK; sed-substitutie van __FIMO_DIR__ gecontroleerd (ExecStart en cron-regel kloppen); hook-settings-voorbeeld is valide JSON. De timer is bewust NIET op deze machine geinstalleerd (zou hier een nutteloze user-timer achterlaten); de unit-files volgen hetzelfde patroon als de draaiende timers van dit systeem.
Privacy-check
Case-insensitive grep over het hele pakket op de zes gevoelige namen/termen uit de bouwopdracht: 0 hits buiten de productnaam "404-in-a-box". Het pakket bevat uitsluitend lege structuur en verzonnen dummy-data (Alex, Nova, Brightbeam); niets uit de bron-architectuur is inhoudelijk overgenomen.
Wat de gebruiker zelf doet
- Eigen data in
input/,python3 ingest.py. python3 generate_canon.py; voor echte destillatie LLM-PROMPT.md aan een eigen LLM voeren en met--from-fileimporteren.bash archivers/install.shvoor de timer (of cron-regel plakken).- Session-start koppelen (CLAUDE.md of system-prompt) en
behavior-rules.txtvullen met eigen regels.
Bekende grenzen / open punten
- SQLite over SMB/CIFS is traag en lock-gevoelig: het pakket hoort op een lokale schijf te draaien. Echt gemeten bij de oplevering: ingest met de db op de NAS-share gaf
sqlite3.OperationalError: database is locked; dezelfde geleverde kopie draaide daarna vlekkeloos end-to-end metFIMO_DBnaar een lokale schijf (ingest 4 docs, ask vond de dummy-zin, canon gegenereerd). Staat ook zo in de README-verwachting: lokaal draaien is de norm,FIMO_DBis de escape hatch. - De offline canon-extract is bewust simpel (frequenties + signaalwoorden); de echte destillatie-kwaliteit komt uit de LLM-route. Dat is een keuze, geen gat: model-agnostisch blijven was de eis.
- Windows: scripts zijn OS-neutraal (python3 + paden via os.path), maar de archiver-templates zijn systemd/cron; een Task Scheduler-template is niet meegeleverd. RECON NEEDED als er een Windows-koper komt: welke scheduler, dan is dat een template van 10 regels.
.json-extractie is heuristisch (tekstvelden op key-naam). Exotische exportvormen kunnen ruis geven; de fallback (pretty-printed JSON) blijft wel doorzoekbaar.