22 KiB
CLAUDE.md — GerbilManager
Leitfaden für die Arbeit an diesem Repo. Bitte vor Änderungen lesen.
Was ist das?
Verwaltungs-App für eine Rennmaus-Zucht („Zucht der kleinen Chaoten"): Tiere, Würfe, Stammbäume/Ahnentafeln, Genetik (Farbschläge/Genotypen), Gehege, Kontakte (Züchter/Abnehmer), Abgabeverträge, Statistik und eine öffentliche CMS-Webseite. Single-User (die Züchterin), Daten größtenteils aus bestehenden Quelldateien importiert.
Architektur / Projekte
| Projekt | Zweck |
|---|---|
GerbilManager.AppHost |
.NET Aspire Orchestrator — startet PostgreSQL (Container) + WebAPI |
GerbilManagerWebAPI |
Backend: ASP.NET Minimal API, EF Core + Postgres, Endpoints in Endpoints/, Entities in Models/, DTOs in Dtos/ |
GerbilManager.ServiceDefaults |
Aspire-Defaults (Telemetry/Health) |
GerbilManager.Tests |
Backend-Tests (xUnit) |
gerbil-manager-web |
Frontend: React + Vite + TypeScript (React Router, react-d3-tree für den Stammbaum) |
tools/import |
Python-Import-Pipeline (zero-dep), wandelt Quelldateien → resolved_import.json |
App starten (IMMER über Aspire, nicht nur die WebAPI)
dotnet run --project GerbilManager.AppHost
- WebAPI: http://localhost:5179 · OpenAPI:
/openapi/v1.json - Aspire-Dashboard: https://localhost:17004 (Login-Token steht im AppHost-Log)
- EF-Migrationen werden beim Start automatisch angewandt (
db.Database.Migrate()inProgram.cs). - Postgres läuft als Container (Name wechselt pro Run, z. B.
postgres-xxxx); die Daten liegen in einem persistenten Volume → überleben Neustarts. DB-Name:gerbilmanager.
Produktion / Deployment (TrueNAS)
Prod läuft als TrueNAS SCALE Custom-App gerbilmanager auf dem Host truenas
(LAN-IP 192.168.2.115, TrueNAS 25.10 „Goldeye", Docker). Erstinstallation 2026-07-19.
- Zugriff (Bookmark der Züchterin): http://truenas:8090/ · API-Doku:
/scalar. (Port 80 ist durch den nginx-Reverse-Proxy der NAS belegt → App auf 8090, LAN-only, keine Auth.) - Sichtbar unter Apps, weil via
midclt call app.create {custom_app:true, app_name:"gerbilmanager", custom_compose_config_string:<yaml>}angelegt — nicht viadocker compose(das taucht in Apps NICHT auf). Container:ix-gerbilmanager-{db,api,frontend,backup}-1. - 4 Dienste:
db(postgres:18) ·api(.NET, EF-Migrationen laufen beim Start) ·frontend(nginx: SPA +/api-Proxy →api:8080) ·backup(täglich 03:00 pg_dump + Foto-Archiv, Shell-Scheduler). - App-Home auf dem Pool:
/mnt/JailStorage/DockerVolumes/gerbilmanager/mitpgdata/ photos/ keys/ backups/ scripts/ publicsite/unddeploy/truenas/{custom-app.compose.yaml,.env,scripts}. Images aus der Gitea-Registrygit.rismer.de/gulum/gerbilmanager-{api,frontend}:latest.
Deployen
Automatisch (Regelfall): Push auf main → Gitea Actions (.gitea/workflows/ci.yml): Tests →
Images bauen+pushen → Job deploy verbindet sich per SSH auf den NAS-Host und ruft
deploy/truenas/scripts/truenas-deploy.sh (→ midclt app.redeploy, zieht :latest neu, pgdata/
photos bleiben erhalten). Braucht die Gitea-Repo-Secrets NAS_SSH_HOST (=192.168.2.115) und
NAS_SSH_KEY (privater Deploy-Key; Pubkey liegt in /root/.ssh/authorized_keys).
Manuell (auf dem NAS-Host):
sh /mnt/JailStorage/DockerVolumes/gerbilmanager/deploy/truenas/scripts/truenas-deploy.sh
Legt die App an, wenn sie fehlt (create), sonst redeploy. Rendert custom-app.compose.yaml mit den
Werten aus deploy/truenas/.env (enthält POSTGRES_PASSWORD — nur auf der NAS, nie im Repo).
Lokale DB → Prod kopieren (einmalig gemacht): pg_dump der Aspire-DB → psql-Restore in den
ix-gerbilmanager-db-1-Container (dabei api kurz stoppen); Fotos aus GerbilManagerWebAPI/photo-storage/
per tar | ssh nach …/gerbilmanager/photos/.
Deployment-Stolperfallen
/optist auf Goldeye read-only → App-Home MUSS auf den Pool (/mnt/JailStorage/...).postgres:18legt PGDATA in/var/lib/postgresql/18/dockerab und deklariert das Volume als/var/lib/postgresql. Mount auf/var/lib/postgresql/data(alte v≤17-Konvention) lässt v18 nicht starten ("data in unused mount/volume") → db unhealthy → App-Rollback. Immer/var/lib/postgresqlmounten. (Debian-Image, nicht alpine → Localelibc/en_US.utf8= Quell-DB.)- Gitea-Runner ist containerisiert (Label
ubuntu-latest, keingoldeye, kein Host-/midclt-Zugriff) und läuftmaxParallel=1(Jobs sequenziell) — daher der SSH-Weg im Deploy-Job. - CI-Run-Status notfalls aus der Gitea-DB:
docker exec -e PGPASSWORD=gitea ix-gitea-postgresdb-1 psql -U gitea -d gitea -c "select name,status from action_run_job where run_id=(select max(id) from action_run);"(status: 1=success, 2=failure, 4=skipped).
Import → DB (3-stufig, WICHTIG)
Die DB wird nicht direkt von Python beschrieben. Nach jeder Import-Code-Änderung neu generieren UND neu einspielen, sonst zeigt die App den alten Stand.
Arbeitsweise (verbindlich, Owner-Regel — aktualisiert 2026-07-12): Für variable (von der Züchterin nicht angefasste) Import-Tiere gilt weiter: Datenfehler IMMER im Importierer beheben (Pipeline-Code +
conflict-decisions.json/rpro3-decisions.json) und neu importieren — für diese Tiere nicht die Live-DB patchen. Jeder Importer-Fix muss re-ingest-stabil sein (data-driven, deterministische GUIDs).Neu: Das Ziel ist nicht mehr „Importer perfekt, dann einmal final", sondern Tier für Tier konvergieren. Die Züchterin darf über die UI kuratieren, und das überlebt den Ingest (der wischt nicht mehr alles): (a) manuell angelegte Tiere/ Würfe/Kontakte (
IsManual=true) und (b) Overrides (GerbilOverride) für als „vollständig korrekt" markierte bzw. von Hand bearbeitete Tiere. Deren eigene Felder werden nach jedem Ingest eingefroren (Freeze). Siehe „Geprüfte Tiere / Freeze" unten. Zusätzlich zu diesen Overrides überleben weiterhin Tickets/Feedback.
# 1. Stammbäume + Wurfchronik → animals.json/litters.json (+ Fotos)
python tools/import/extract.py
# 2. Abgabeverträge (DOCX) → contracts.json
python tools/import/extract_contracts.py
# 3. Dedup, Eltern-Resolver, Provenance, Vertrags-Anreicherung → resolved_import.json
python tools/import/merge_and_resolve.py
# 4. In die laufende DB laden (API muss laufen): UPSERT + Freeze
curl -X POST http://localhost:5179/import/ingest-resolved
IngestResolvedService(seit 2026-07-12: UPSERT statt Total-Wipe). Importierte Zeilen (Gerbils/Litters/Contacts) werden per deterministischer Id gematcht und in place aktualisiert; stale importierte Zeilen (nicht mehr im Payload) werden entfernt (dangling Referenzen manueller Zeilen werden vorher genullt + im Rückgabestring gewarnt). Nie gelöscht/ überschrieben: Zeilen mitIsManual=truesowie user-eingegebene Sub-Records (Weights/Health) und Fotos manueller Tiere. SaleContracts werden weiter aus dem Payload neu erzeugt (manuelle Verträge sind noch nicht geschützt — Folgeaufgabe). Am Ende werden alleGerbilOverrideangewandt (Freeze der eigenen Felder) und für verifizierte Tiere der Rohimport-Stand vorher als Drift-Snapshot erfasst.- Feedback + GerbilOverride überleben den Ingest (werden nicht gewischt) — daher haben sie nur
lose, nullable Guid-Spalten ohne FK (
Feedback: GerbilId/LitterId/ContactId;GerbilOverride: GerbilId). Dieses Muster für alles nutzen, was Re-Ingests überleben soll. resolved_import.jsonist gitignored (Runtime-Output);review-report.mdist getrackt.- Deterministische GUIDs via
generate_guid("...")→ stabile IDs über Re-Ingests.
Quelldateien (lokal/Netzwerk)
- Stammbäume:
C:\Users\gulum\dev\Sttammbäume\*.xlsx - Wurfchronik:
C:\Users\gulum\dev\Wurfchronik der Kleine Chaoten Teil1.xlsx - Abgabeverträge:
\\truenas\Datengrab\Rennmäuse\Verträge\*.docx(~1,4k; kann zeitweise offline sein)
Build & Test
Frontend (cd gerbil-manager-web):
npx tsc --noEmit # Typecheck (muss sauber sein)
npx vitest run # Unit-Tests
npx eslint <dateien> # Lint
npx playwright test [spec]# e2e (Projekte: desktop + phone), läuft gegen Mock-API
- e2e nutzt einen Mock-Modus (
e2e/mock-api.ts+e2e/mock-data.ts), kein echtes Backend. Neue API-Routen/Felder dort spiegeln.skipUnlessMock()am Testanfang.
Backend:
dotnet build
dotnet test # GerbilManager.Tests
dotnet ef migrations add <Name> --project GerbilManagerWebAPI # neue Migration
- Zum Bauen muss eine laufende WebAPI ggf. gestoppt werden (Datei-Lock auf
bin).
Python (cd tools/import, zero-dep, exit 0 = pass):
python test_extract.py test_extract_docx.py test_genotype.py test_merge_resolve.py test_extract_contracts.py
Konventionen (bitte einhalten)
- Alle deutschen UI-Texte in
gerbil-manager-web/src/strings/de.ts— niemals in Komponenten hartkodieren. - EF-Migration für jede Schema-Änderung; wird beim Aspire-Start angewandt.
- Provenance/Datenherkunft liegt als JSON-Text-Spalte (
Provenance) auf Gerbil/Contact/Litter → JSON-Feld-Erweiterungen brauchen keine Migration. - Lose nullable Guid-Spalten ohne FK für Tabellen, die den Ingest-Wipe überleben.
- Commits: nur wenn der Nutzer es verlangt; auf
mainwird gearbeitet (Remote:http://truenas:13000/Gulum/GerbilManager.git). Commit-Messages auf Deutsch, Formatfeat(scope): …. - Subagenten committen NICHT — Haupt-Loop verifiziert und committet.
Domänenwissen (Rennmaus-Zucht)
- Lebensspanne ~6 Jahre → ein Elternteil kann max. ~6 Jahre älter als sein Kind
sein und muss vorher geboren sein (
parent_age_plausibleim Import; verwirft unplausible Eltern-Links). - Geschwisterverpaarung (Vollgeschwister als Eltern): erkannt, wenn Vater & Mutter
dieselbe
litterIdODER dasselbe Geburtsdatum teilen (gleiches DOB = starkes Indiz). UI: Diagramm führt den Vorfahren-Ast zusammen (Verweis-Knoten); Akte zeigt „⚭ Geschwisterverpaarung"-Chip. - Box-Farbe im Stammbaum-xlsx = Geschlecht: weiß = weiblich, blau = männlich.
- Bestandstier (
isResident) vs. reiner Vorfahre (Regel der Züchterin, Ticket 09bcac78): Ein Tier ist ihr Zuchttier ⇔ es hatte bei ihr Nachzucht mit Herkunft „von den Kleinen Chaoten" (nur dann konnten die Jungtiere ihren Zuchtnamen tragen). Trägt die Nachzucht einen fremden Herkunftsnamen (z. B. „of Black Forest", „of Topolino"), ist das Tier nur Vorfahre (isResident=false, keine Würfe/Charakter-Bereich). Ausnahme: zugekaufte Zuchttiere (fremder Herkunftsname, aber bei ihr gezüchtet → Nachzucht „von den Kleinen Chaoten") bleiben Bestandstiere (z. B. Echo/Elia of Black Forest). Sweep umgesetzt (2026-06-27, Ticket 381f7e51): Der Wurfchronik-Import-Default ist nicht mehris_resident=True. Neue Regel inmerge_and_resolve.py(später Sweep nach Eltern-/addLitters-Verknüpfung):isResident=truegenau dann, wenn (1) ein expliziterconflict-decisions.json-isResident-Override greift (gewinnt immer —truewie Echo/Elia,falsewie Akane/Naémi/Bentley), oder (2) das Tier Elternteil eines eigenen Wurfs ist (nicht-virtuell ODER aus Wurfchronik ODER Clan-Nachzucht ODER mit residentem Elternteil ODERaddLittermitShowInChronicle). Reine virtuelle Ahnen-Verpaarungen machen nicht resident (z. B. Antares bleibtfalse). Sonstfalse.ShowInChroniclewird nach dem Sweep berechnet (nutzt die finale Residenz). Effekt: resident 1711 → 442. UI-Label (de.tsisResidentLabel) = „Zuchtanwärter/ innen" — die Züchterin markiert künftige Zuchttiere selbst. Offene Folgeaufgabe: manuelle UI-Residenz-Markierungen überleben den Re-Ingest noch nicht (bräuchten eine ingest-stabile, FK-freie Override-Ablage analogFeedback). - Genotyp/Farbschlag: 8-Locus-Notation (siehe
tools/import/genotype.py,gerbil-manager-web/src/genetics). Unbekanntes Allel =-(nicht?). E-Locus:ee=Fuchs,eef=Fuchsschimmel,efef=Schimmel. Rezessiver Fuchs ist zwingend homozygot →e-ist ungültig (wirft),ee[-]→ee. - Genetik-Engine = korrektheitskritisch: IMMER vollständig mit Tests absichern.
Jede Änderung an
src/genetics/**(+ Backend-Mirror +genotype.py) braucht pro Use-Case/Ticket einen Regressionstest (src/genetics/__tests__/genetics.test.tsundtools/import/test_genotype.py), damit nie eine Regression entsteht.npx vitest run+python test_genotype.pymüssen grün sein, bevor „fertig". - Stammbaum-Charts: Generationen = Spaltenbänder (Proband links in Spalte B/2,
je Generation +3 Spalten); Eltern-Position: Vater oben, Mutter unten. Fotos liegen
je nach Datei links/auf der Namenszelle — die Seite wird heuristisch über die
geringste Spalten-Fehlausrichtung bestimmt (
extract._attach_photos).
Stolperfallen
- Aspire-Containername wechselt pro Run, das Daten-Volume bleibt → DB-Inhalt überlebt Neustarts (auch alte Schema-Stände → Migrationskonflikte möglich, s. u.).
- Migrations-Historie vs. committete Migration-IDs: Wird eine Migration angewandt
und danach mit neuem Zeitstempel neu generiert, sieht EF sie als „pending" und der
Start crasht („column … already exists"). Schema ist dann korrekt — nur die
__EFMigrationsHistory-IDs müssen an die committeten Dateinamen angeglichen werden. - PowerShell + psql: PascalCase-Identifier (
"__EFMigrationsHistory") über PowerShell→docker→psql zerschießen das Quoting. Stattdessen Bash-Heredoc:docker exec -i -e PGPASSWORD=$PW <container> psql -U postgres -d gerbilmanager <<'SQL' … SQL. Passwort:docker exec <container> printenv POSTGRES_PASSWORD. - Direkte DB-Schreibzugriffe (psql) werden vom Auto-Mode-Classifier blockiert — vorher beim Nutzer rückversichern.
- Bash-Tool ist Git-Bash (POSIX), das andere Tool ist PowerShell — je eigene Syntax.
Wo liegt was (Feature-Landkarte)
- Stammbaum-Viewer:
gerbil-manager-web/src/pages/StammbaumPage.tsx,src/pedigree/*(build.ts = Baum-Aufbau + Geschwister-Erkennung; types.ts). Desktop passt den ganzen Baum ein; Touch: Long-Press öffnet das Kontextmenü (ID kopieren / Fehler melden). - Datenherkunft/Nachverfolgung:
src/components/ProvenanceDialog.tsx; erzeugt im Import viabuild_entity_provenance/_build_*_history(chronologische, datei- attribuiertehistory[], inkl. „⚠ … verworfen — Grund; … verwendet"). - Fehler melden (Feedback):
src/components/ReportErrorDialog.tsx,src/api/feedback.ts, BackendEndpoints/FeedbackEndpoints.cs+Models/Feedback.cs. - Geprüfte Tiere / „vollständig korrekt"-Freeze: Backend
Models/GerbilOverride.cs(FK-frei, ingest-überlebend),Import/GerbilSnapshotService.cs(Akten-Snapshot + Freeze-Map + Diff, von App und Test geteilt),Endpoints/VerifiedGerbilEndpoints.cs(/verified-gerbils: POST markieren, DELETE entfernen/Toggle, GET Liste+Drift, GET/export= Golden-Fixture). Freeze wird inIngestResolvedServiceangewandt;GerbilEndpointssetztIsManual=truebei POST und legt bei Edit eines importierten Tiers einen per-field-Override an (verifiziert → Golden auto-aktualisiert). Frontend:src/api/verified.ts, Badge/Toggle/Drift-Karte inpages/GerbilDetailPage.tsx, Übersichtpages/VerifizierteTierePage.tsx(/hilfe/verifizierte-tiere); Texte instrings/de.ts(verified-Block). Modell:OverrideJson= Feld→Wert-Map;IsVerified=true= zertifiziert + voller Freeze + Regression/Export,false= „geschützt" (nur geänderte Felder). Status/Gehege und Abstammung/Nachzucht werden nicht eingefroren (nur erkannt/gemeldet). Regressionstest:GerbilManager.Tests/VerifiedGoldenTests.csgegentools/import/verified-golden.json(viaGET /verified-gerbils/exporterzeugen + committen; skippt, wenn Fixture/resolved_import.jsonfehlt). Scope-Grenze: Freeze/Override gelten für Gerbils; Edits an importierten Würfen/Kontakten und manuelle SaleContracts sind noch nicht geschützt (Folgeaufgaben). - Verträge:
Models/SaleContract.cs,Endpoints/ContractEndpoints.cs,ContractGenerator.cs, Frontendsrc/pages/Vertraege*; Import:extract_contracts.pyenrich_from_contractsinmerge_and_resolve.py.
- Import-Kernlogik:
tools/import/merge_and_resolve.py(Dedup, Eltern-Resolver mit Gender-/Alters-Plausibilität, Litter-/Sibling-Dedup, Provenance, Vertrags-Anreicherung). - RennmausPro-III-Import (rpro3): Backend-Importer
GerbilManagerWebAPI/Import/Rpro3/*(Rpro3ImportServiceAnalyze/Execute,Rpro3Dedup= automatischer Dubletten-Merge, Port vontools/import/compare_rpro3.py). Manuelle Dubletten-Entscheidungen der Züchterin (aus den „rpro3-import"-Tickets) liegen inGerbilManagerWebAPI/Import/Rpro3/rpro3-decisions.jsonund werden vonRpro3Dedup.Run(animals, decisions)honoriert:same= Force-Merge (eine rid zieht den Auto-Cluster mit),different= Force-Split,fields= Feld-Overrides (Farbe/DOB/Herkunft/genotype(roher Fcode)/resident/Notiz) am Cluster. Dergenotype-Override ist nötig, wenn Varianten sich im Gencode unterscheiden (z. B. C-Locus c[h] vs. c[chm]) und der Auto-Merge sonst den falschen Gencode (erstes Cluster-Mitglied) zöge — die Züchterin gibt den korrekten vor (z. B. MilkyWay →aa Cc[h] DD ee Gg P- spsp). Schlüssel ist die RPRO3-Nummer (rid), NIE der Variantenbuchstabe (Buchstaben verschieben sich bei geänderter Clusterbildung) — rids aus dem Ticket-agentContext. Triage-Helfertools/import/rpro3_lookup.py(Name- oder--rids-Modus) zieht Farbe/Gencode/ Eltern/Nachzucht+Partner aus_rpro3.dbfür die Rückfragen an die Züchterin. - Manuell ergänzte Würfe / versteckte Würfe:
conflict-decisions.jsonkennt nebenresolutions/addAnimalsauchaddLitters[{name, mother(+motherDob), father, children[], showInChronicle, totalBorn, date, notes}] — materialisiert inmerge_and_resolve.pyals späten Schritt (nach Dedup/Parent-Roles, vor json.dump): Wurf mit deterministischergenerate_guid("decision-litter-<slug>"), verknüpft Mutter/Vater/Kinder per Name(+dob), setzt Kinder-LitterId. Die name+dob-Resolutions können zusätzlichisResident,notes,receiver(Kontaktname→ReceiverContactId) auf bestehende Tiere setzen (läuft NACH der Residenz-Propagation).Litter.ShowInChronicle(bool, Default true; MigrationAddLitterShowInChronicle):falseblendet den Wurf aus der Wurfchronik (WuerfeListPage, FiltershowInChronicle==true) aus, zeigt ihn aber weiter auf der Tier-Akte (parentLitters-Query, ungefiltert). Use-Case: extern entstandener Wurf eines nicht-residenten Tieres (z. B. Akane × Bonaparte).
Verifikations-Checkliste vor „fertig"
npx tsc --noEmit,npx vitest run,npx eslintsauber.- Betroffene
npx playwright test-Specs grün. dotnet build+dotnet testgrün.- Bei Import-Änderungen:
python test_*.pygrün +resolved_import.jsonplausibel (Stichprobe), danach App neu starten +POST /import/ingest-resolved.
Gedächtnis (MemPalace) — IMMER nutzen
Dieses Projekt nutzt MemPalace als KI-Langzeitgedächtnis (lokal, kein API-Key). Die Anbindung ist im Repo persistiert und lädt automatisch:
.mcp.json(committet) registriert den MCP-Servermempalace-mcp→ 19 MCP-Tools (mempalace_search,mempalace_kg_query/add/invalidate/timeline,mempalace_add_drawer,mempalace_diary_*…). Aktiv ab Claude-Neustart (MCP-Server einmal bestätigen)..claude/settings.json(committet) verdrahtet die Hooksmempalace hook run --hook {session-start,stop,precompact} --harness claude-code: SessionStart lädt relevanten Kontext automatisch, Stop/PreCompact persistieren.- Voraussetzung:
mempalaceist installiert und auf PATH (~/.local/bin). Nachgit cloneggf. MemPalace installieren;mempalace.yaml(Raum-Config) ist bewusst gitignored (per-project, lokal). Der Palast selbst liegt lokal unter~/.mempalace(nicht im Repo).
Arbeitsweise pro Session: zu Aufgabenbeginn relevantes Wissen abrufen
(mempalace_search / mempalace_kg_query), bevor du im Code suchst; am Ende neue
durable Erkenntnisse ablegen.
Subagenten MÜSSEN MemPalace ebenfalls nutzen — das im Subagent-Prompt IMMER explizit
anweisen: zu Aufgabenbeginn den Palast abfragen (am einfachsten per CLI, kein Key nötig:
mempalace search "<keywords>" bzw. mempalace search "<…>" --wing gerbilmanager; falls
MCP-Tools verfügbar auch mempalace_search/mempalace_kg_query) — relevante Domänenregeln,
frühere Entscheidungen und Stolperfallen holen, BEVOR im Code gesucht wird; durable
Erkenntnisse am Ende ablegen (mempalace add-drawer/MCP). Gilt für JEDEN gespawnten Agenten.
Memory-Policy — WANN / WIE / WO eine Memory anlegen
WANN (anlegen): nur dauerhaft nützliches, nicht-offensichtliches Wissen, das künftige Sessions braucht — Architektur-/Design-Entscheidungen und ihr Warum, Domänenregeln (z. B. 6-Jahre-Lebensspanne, Geschwisterverpaarung), Konventionen, Stolperfallen, bestätigte Nutzer-Präferenzen, wiederkehrende Workflows. NICHT anlegen: transienter Task-Status; was Code/Git/CLAUDE.md ohnehin festhalten; Dinge, die nur für das aktuelle Gespräch zählen.
WIE (anlegen/pflegen):
- Fakt mit Gültigkeit →
mempalace_kg_add. Freitext-Notiz/Erkenntnis →mempalace_add_drawer(vorhermempalace_check_duplicate). - Ändert/erledigt sich ein Fakt →
mempalace_kg_invalidate(setzt End-Datum, nicht löschen — der Graph ist temporal). So bleibt nichts veraltet stehen. - Repo-Dateien werden über
mempalace mine <dir>automatisch gefilet;mempalace sync --apply --wing gerbilmanagerentfernt Drawers gelöschter/verschobener Dateien.
WO (welcher Speicher):
- MemPalace-Palast (
~/.mempalace, lokal): reichhaltiges, durchsuchbares Recall — der Default für Memories. - CLAUDE.md (Repo, committet): die kanonischen Projektfakten/Konventionen, die geteilt und versioniert sein müssen. Wichtige durable Erkenntnisse hier spiegeln, damit sie im Repo (nicht nur lokal) liegen.
Faustregel: durable + projektweit kanonisch → CLAUDE.md und Palast; sonstiges durable Wissen → Palast; veraltetes → invalidieren, nicht stehen lassen.