Du bist der Maintainer dieser persönlichen Wissensbasis. Deine Aufgabe ist es, Rohdokumente in eine strukturierte, vernetzte Markdown-Wiki zu kompilieren und diese über Zeit zu pflegen.
- AI / Machine Learning: Papers, Modelle, Frameworks, Forschungstrends, LLMs, Agenten
- Business / Strategy: Märkte, Unternehmensstrategien, Frameworks, Prognosen, Wettbewerber
- Technologie: Spezifische Tech-Themen, Software-Architekturen, Tools, Plattformen
raw/ # Unveränderliche Quellen — NUR LESEN, niemals modifizieren
pdfs/ # Papers, Reports, Whitepapers
slides/ # Präsentationen (PPTX)
docs/ # Word-Dokumente, Textdateien (.docx, .txt)
links/ # Web-Artikel als .md
transcripts/ # Teams-Transkripte (.docx) — eigene Pipeline: transcript-ingest.py
inbox/ # Unsortierter Eingang
manuals/ # PDF-Handbücher (eigene Pipeline: manual-ingest.py)
.cache/ # Intern: extrahierte Texte + Bilder (nicht anfassen)
Clippings/ # Obsidian-Web-Clipper-Ablage (.md) — eigene Pipeline: clippings-ingest.py
# liegt im Vault-Root (Obsidian-Default), NICHT unter raw/
wiki/ # Alles hier wird von Dir gepflegt
index.md # Inhaltsverzeichnis aller Wiki-Seiten
log.md # Append-only Aktivitätslog
picture_index.md # Menschenlesbarer Bild-Index (für QUERY/Präsentationen)
concepts/ # Eine Seite pro Konzept oder Technologie
entities/ # Personen, Unternehmen, Produkte, Organisationen
sources/ # Eine Zusammenfassungsseite pro Rohdokument
syntheses/ # Themenübergreifende Muster und Verbindungen
code-wiki/ # Code-Wissensbasis — automatisch generiert via code-ingest.py
demand-ai/
index.md # Projektübersicht mit Modul- und Ticket-Links
changelog.md # Chronologischer Commit-Log
modules/ # Eine Seite pro Modul/Domäne (z.B. forecasting-pipeline.md)
<submodul>/ # Unterordner für größere Module (z.B. client-library/, customers/)
tickets/ # Eine Seite pro Ticket (DAI-661.md, DAI-663.md, ...)
scenario-mixture/
index.md
changelog.md
modules/ # Frontend/Backend-Module (api.md, forecast-ui.md, ...)
planning/ # Planungs-Unterordner
tickets/ # #1.md, #14.md, ... (GitHub-Issues)
manuals/ # Produkthandbücher — automatisch generiert via manual-ingest.py
index.md # Übersicht aller Produkte mit Kapitelzahlen und Bild-Counts
addone-bo/ # ADD*ONE Bestandsoptimierung Benutzerhandbuch
index.md # Kapitelübersicht mit Wikilinks
image-index.md # Alle Bilder mit Obsidian-Embeds (![[...]]) und Beschreibungen
assets/ # Extrahierte Bilder als .jpg
<kapitel>.md # Eine Seite pro TOC-Eintrag
addone-bo-admin/ # ADD*ONE BO Administratorhandbuch
index.md
image-index.md
assets/
<kapitel>.md
addone-bo-ls/ # ADD*ONE BO Leistungsbeschreibung 2026
index.md
assets/ # (leer — keine UI-Screenshots in diesem Dokument)
<kapitel>.md
powershell -ExecutionPolicy Bypass -File ".\watch.ps1"- Überwacht
raw/pdfs/,raw/slides/,raw/docs/,raw/links/auf neue Dateien - Ruft automatisch
ingest.py <datei>auf - Startup-Scan: beim Start werden alle Dateien ohne Cache-Eintrag nachverarbeitet
raw/manuals/undraw/transcripts/werden bewusst ignoriert — eigene Pipelines- Läuft als
at_logon-Daemon (unbegrenzt) — siehe Watcher-System unten
uv run transcript-ingest.py raw/transcripts/<datei.docx> \
--event "Kunde Acme – PoC Setup" [--date 2026-04-30] [--format meeting] \
[--language de] [--context "Erstgespräch zu Forecast-Pilot"] [--force]
uv run transcript-ingest.py raw/transcripts/foo.docx --no-ingest # Nur Cache, kein LLM- Parst die
.docxmit Sprecher-Awareness (Teams-HeaderVorname Nachname H:MM[:SS]) - Generiert eine strukturierte
.mdmit Frontmatter (auto-InitialenPeter Kunz→PK, Kollisionen →PK2/PK3) inraw/.cache/transcripts/<stem>.md - Ruft anschließend den regulären
ingest.py-Flow auf — der erkennt den Pfadraw/transcripts/und schaltet auf den transkript-spezifischen Prompt (siehe Frontmatter unten) --event/--contextals TODO-Platzhalter erlaubt; das LLM markiert sie dann als unklar- Wird
raw/transcripts/vonwatch.ps1bewusst ignoriert — Trigger erfolgt manuell oder über externen Daemon (z.B.code-watch.pyin knowledge-tree, analog zur manuals-Pipeline)
Wo finde ich das Teams-Transkript?
Nicht lokal — in der Cloud. Teams öffnen → Kalender → Meeting → Recap → Transkript → Herunterladen als .docx. Datei dann nach raw/transcripts/ legen und transcript-ingest.py aufrufen.
uv run clippings-ingest.py # Single-Poll: neue/geänderte Clips ingesten
uv run clippings-ingest.py --force # alle Clips erneut ingesten
uv run clippings-ingest.py --dry-run # nur anzeigen, kein LLM-Aufruf
uv run clippings-ingest.py --clippings-dir <pfad> # abweichender Ordner- Der Obsidian Web Clipper speichert geclippte Web-Seiten als
.mdim Vault-OrdnerClippings/— außerhalb vonraw/, daher siehtwatch.ps1sie nicht. Diese Pipeline schließt die Lücke. - Scannt
Clippings/**/*.mdund ruft für jede neue/geänderte Datei den reguläreningest.py-Flow auf — fachlich wie eineraw/links-Quelle (Web-Artikel → Quellenübersicht + Konzepte +index.md/log.md). - Eigener State (
path → mtime) in.clippings-state.json, weilingest.pyfür.md-Inputs keinenraw/.cache-Eintrag schreibt (Dedup wie beiscan-raw.py). - Läuft als Scheduled Task
WikiClippings(Single-Poll alle 15 Min, siehewatchers.json).cwddefaultet auf den Repo-Root, daher keine Pfad-Argumente nötig. - Alternativ kann man den Web-Clipper-Zielordner direkt auf
raw/links/umstellen — dann übernimmt der reguläre Watcher. Default-Clippings + diese Pipeline ist aber der wartungsärmere Weg (kein Obsidian-Reconfig).
uv run manual-ingest.py raw/manuals/Handbuch.pdf --product produkt-slug --max-level 2
uv run manual-ingest.py raw/manuals/foo.pdf --dry-run # Kapitelstruktur anzeigen
uv run manual-ingest.py raw/manuals/foo.pdf --only-chapters 6 # Nur Kapitel 6 neu generieren- Erzeugt
wiki/manuals/<produkt>/mit Kapitelseiten, Bild-Index, Bilder inassets/ - Wird automatisch von
code-watch.pygetriggert wenn PDF neu/geändert - Auto-Discovery: alle PDFs in
raw/manuals/*.pdfwerden erfasst —products:-Liste incode-repos.yamlist optional und wirkt als Slug-Override pro Datei
uv run code-watch.py # Single-Poll (für Scheduled Task)
uv run code-watch.py --loop # Daemon-Modus (nur für Debugging)- Pollt GitHub-Repos auf neue Commits →
code-extract.py→code-ingest.py - Prüft Änderungen in
raw/manuals/per mtime und startetmanual-ingest.py - Config:
$VAULT_ROOT/code-repos.yaml(Multi-Machine via OneDrive), Fallback auf Repo-internen Pfad. Template:code-repos.yaml.example
| Skript | Zweck |
|---|---|
clippings-ingest.py |
Obsidian-Web-Clipper-Clips (Clippings/*.md) → regulärer ingest.py-Flow |
code-extract.py |
GitHub-Commit-Diff → CommitDigest-JSON |
code-ingest.py |
CommitDigest → wiki/code-wiki/<projekt>/ |
extract-images.py |
Batch-Vision für Bilder aus PPTX/PDF |
synthesize.py |
LLM-Synthese aus mehreren Quellen |
generate.py |
PPTX aus Konzept-/Synthese-Seiten erzeugen |
pm-synthesize.py |
Team-/PM-View-Aggregation |
wiki-sync.py |
Wiki-MD → knowledge-wiki-archive (GitHub) |
scan-raw.py |
Generischer File-Watcher (Polling-Wrapper für Projekte ohne eigenen Watcher) |
rebuild-index.py |
Regeneriert wiki/index.md aus YAML-Frontmatter |
rebuild-code-wiki-index.py |
Patcht Obsidian-Wikilinks in wiki/code-wiki/ (Ticket-↔-Modul-Verlinkung) |
lint-links.py |
Graceful Link-Checker: löst [[wikilinks]] + bundle-relative Links auf, meldet Broken Links & Waisen; prüft visibility |
lint-tree.py |
Konsistenz-Check der Node-Rechte in vault-tree.yaml (read/write-Zonen vs. Hierarchie) |
access.py |
Retrieval-Filter-Bibliothek: can_read/filter_readable (visibility-Durchsetzung, fail closed) — single source of truth der visibility-Leiter |
pkwiki-mcp.py / pkwiki_server.py |
MCP-Server (stdio): stellt das Wiki als Agenten-Gedächtnis bereit, Zugriffe durch access.py gegated |
promote.py |
Promotion-Planner: validiert Hochstufen einer Seite in einen Vorfahr-Node (Review-Gate, kein Auto-Move) |
reorganise.py |
Reorganiser: klassifiziert kuratierte Seiten per LLM in die visibility-Leiter, labelt das Frontmatter und verschiebt personal-Seiten nach wiki/.trash/ (Dry-run per Default, --apply zum Ausführen) |
test-connection.py |
Smoke-Test der Azure-OpenAI- und GitHub-Verbindung |
Windows Scheduled Tasks werden aus einer deklarativen Config im Vault verwaltet.
Neue Watcher hinzufügen = JSON-Eintrag anhängen, ohne setup.ps1 neu laufen zu lassen.
| Pfad | Rolle |
|---|---|
watchers.json (Repo) |
Template, wird beim ersten Setup in den Vault kopiert |
$VAULT_ROOT/watchers.json |
Aktive Watcher-Config — hier editieren |
code-repos.yaml.example (Repo) |
Template für code-watch.py |
$VAULT_ROOT/code-repos.yaml |
Aktive Repo-Liste — hier editieren (OneDrive multi-machine-synchron) |
sync-watchers.ps1 |
Syncht Config → Scheduled Tasks (CREATE/UPDATE/DELETE) |
setup.ps1 |
Ersteinrichtung: Templates kopieren, MetaSync-Task registrieren |
{
"watchers": [
{
"name": "WikiSync",
"cwd": "C:\\code\\knowledge-wiki",
"script": "wiki-sync.py",
"args": [],
"runner": "uv",
"trigger": "interval",
"interval_minutes": 15,
"timeout_minutes": 10,
"description": "..."
}
]
}name→ Task wird alsKnowledgeTree-<name>registriertcwd→ Script-Wurzel (pro Eintrag separat, damit weitere Code-Projekte ihre Watcher anhängen können)script→ Datei relativ zucwd(Python oder.ps1)runner→"uv"(default, ruftuv run <script>) oder"powershell"(für.ps1-Watcher)trigger→"interval"(Single-Poll alle N Min) oder"at_logon"(Daemon, startet beim Login — für langlaufendeFileSystemWatcher-Skripte)interval_minutes/timeout_minutes→ nur beitrigger: "interval";at_logon-Daemons laufen unbegrenzt
setup.ps1 registriert einen Bootstrap-Task KnowledgeTree-MetaSync, der alle 15 Min
sync-watchers.ps1 ausführt. Änderungen an watchers.json wirken binnen 15 Min;
sofort triggern via:
Start-ScheduledTask -TaskName KnowledgeTree-MetaSync
# oder direkt:
powershell -ExecutionPolicy Bypass -File .\sync-watchers.ps11. Projekt hat eigenen Daemon (z.B. watch.ps1 mit nativem FileSystemWatcher):
per runner: "powershell" + trigger: "at_logon" direkt einbinden — Echtzeit-Reaktion,
kein Polling.
2. Projekt hat nur Per-Datei-Ingest (kein eigener Watcher): scan-raw.py als
generischer Polling-Wrapper. Scannt periodisch, pflegt State (path → mtime), ruft den
Ingest-Befehl pro neuer/geänderter Datei. interval_minutes: 1 ist das Windows-Minimum.
Watcher-Skripte führen einen Durchlauf aus und beenden sich. Der Task Scheduler
taktet das Intervall (analog zu cron). --loop-Modi existieren nur noch für Debugging.
---
title: Name des Konzepts
type: concept
domain: ai | business | tech | cross
sources: [raw/pdfs/paper1.pdf, raw/slides/vortrag2.pptx]
related: ["[[anderes-konzept]]", "[[entity-name]]"]
confidence: high | medium | low
visibility: public | customer | internal | team | personal
last_updated: YYYY-MM-DD
------
title: Name (Person / Unternehmen / Produkt)
type: entity
entity_type: person | company | product | organization
sources: [raw/...]
related: ["[[konzept]]"]
visibility: public | customer | internal | team | personal
last_updated: YYYY-MM-DD
------
title: Titel des Dokuments
type: source
source_file: raw/pdfs/dateiname.pdf
source_type: paper | slide | doc | article | talk | transcript
date: YYYY-MM-DD
key_concepts: ["[[konzept-1]]", "[[konzept-2]]"]
visibility: public | customer | internal | team | personal
last_updated: YYYY-MM-DD
------
title: Titel der Synthese
type: synthesis
domain: ai | business | tech | cross
sources: ["[[source-1]]", "[[source-2]]"]
related: ["[[konzept]]"]
visibility: public | customer | internal | team | personal
last_updated: YYYY-MM-DD
------
title: Modul- oder Ticket-Titel
type: code-module | code-ticket
project: demand-ai | scenario-mixture
last_updated: YYYY-MM-DD
---- Modul-Seiten: Architektur, Verantwortlichkeiten, Abhängigkeiten, offene Punkte
- Ticket-Seiten: Beschreibung, betroffene Module als
[[modul-slug]], Status [[wikilinks]]zwischen Modulen und Tickets
Transkripte (Meetings, Vorträge, Interviews, Podcasts, Calls) brauchen Kontext, sonst landet Smalltalk als Konzeptseite. Eingang ist das Teams-.docx wie aus dem Recap heruntergeladen — transcript-ingest.py erzeugt die strukturierte .md mit Frontmatter:
---
event: "Kundengespräch Acme – Forecasting Setup"
format: meeting | talk | interview | podcast | call | workshop
date: YYYY-MM-DD
language: de | en
speakers:
PK: "Peter Kunz"
MS: "Maria Schmidt"
context: "Erstgespräch zu Forecast-Pilot, Ziel: Scope für PoC klären"
---
**PK:** Guten Tag …
**MS:** Hallo …event und context werden aus den CLI-Flags übernommen (oder bleiben als TODO-Platzhalter). Sprecher-Initialen werden automatisch generiert (Peter Kunz → PK, Kollisionen → PK2). Das LLM erhält im Anschluss einen transkript-spezifischen Prompt (Fokus: Quellenübersicht mit Kontext / Kernaussagen je Sprecher / Entscheidungen / Action Items / Zitate; max. 0–3 Konzeptseiten; kein Smalltalk).
---
title: "Produktname › Kapitelname"
type: manual-chapter
product: addone-bo | addone-bo-admin | addone-bo-ls
generated: YYYY-MM-DD
keywords: [...]
---- Kapitel-Seiten mit Schritt-für-Schritt-Anleitungen, UI-Elementen fett
- Bilder inline eingebettet:
![[dateiname.jpg]] - Suche über Keywords, Querverweise auf andere Kapitel als
[[kapitel-slug]]
Jede kuratierte Seite (concepts/, entities/, sources/, syntheses/) trägt ein
visibility:-Feld, das die Wissensschicht klassifiziert — von offen nach restriktiv:
| Stufe | Wer darf lesen |
|---|---|
public |
extern sichtbar, keine Einschränkung |
customer |
Kunden / externe Software-User eines Produkts |
internal |
alle Firmenmitarbeiter |
team |
nur das jeweilige Team (Node) |
personal |
nur der Eigentümer-Node |
- Default (Feld fehlt) =
personal— safe by default: lieber zu restriktiv als versehentlich geleakt. Ein fehlendes Feld ist kein Fehler, nur ein Lint-Hinweis. - OKF-kompatibel:
visibilityist ein Custom-Key; Consumer, die es nicht kennen, dürfen die Seite nicht verwerfen (graceful degradation). - Die Stufe ist eine Klassifizierung, keine Sicherheitsgrenze — die Durchsetzung
(„
visibility ≤ clearance" vor der Kontextbefüllung) gehört in den Retrieval-Layer (siehe Epic #28, T3), nicht in die Markdown-Datei. - Auto-generierte Bundles (
code-wiki/,manuals/) tragen kein Feld pro Seite — sie erben die Sichtbarkeit ihres Nodes (siehe T5).lint-links.pyprüft sie daher nicht. - Prüfung:
uv run lint-links.pymeldet ungültige Werte und (mit--show-missing-visibility) Seiten ohne Feld.
Der Wissensbaum (company → team → personal) trägt pro Node ein rights-Block, das die
Read-/Write-Zonen explizit macht (vorher implizit über SharePoint/OneDrive-ACL):
rights:
clearance: internal # höchste (restriktivste) Stufe, die der Node LESEN darf
default_visibility: internal # Default-visibility für hier erzeugte Seiten (<= clearance)
read: [self, <vorfahren>] # nur nach oben lesen — keine seitlichen Leaks
write: [self, <nachfahren>] # nach oben schreiben = Promotion (Review-Gate, T4)- Read nur nach oben: ein Node liest sich selbst + Vorfahren, nie Geschwister-/Fremd-Nodes.
- Write nur nach unten: Hochstufen in einen Eltern-Layer ist Promotion (T4), kein Default.
clearancenimmt nach unten nicht ab — sonst könnte ein Kind den Eltern-Layer nicht lesen.- Prüfung:
uv run lint-tree.py [--strict]validiert diese Regeln gegen die Hierarchie.
Ein Agent erhält ein Capability-Profil, das clearance (Lese-Obergrenze) mit Read-/Write-Scope
verbindet. Effektiver Lesezugriff auf eine Seite:
rank(visibility) <= rank(clearance)undnode(seite) ∈ read_scope
agents:
- id: <slug>
clearance: <stufe> # höchste visibility, die der Agent lesen darf
read_scope: [<node>, ...] # Nodes, deren Inhalt sichtbar ist
write_scope: <node> | session # 'session' = ephemerer Sandbox-Node (kein Persist)Zwei Referenz-Profile (in vault-tree.yaml.example):
| Profil | clearance | read_scope | write_scope |
|---|---|---|---|
| Produkt-Agent (externe Software-User) | customer |
freigegebene Nodes (z.B. company) |
session (Sandbox) |
| Interner Team-Copilot | team |
eigener Team-Node + company |
eigener Team-Node |
Regeln (von lint-tree.py geprüft): read_scope/write_scope müssen existierende Nodes
referenzieren; ein Agent darf nicht in einen Node schreiben, dessen Default-Sichtbarkeit über
seiner clearance liegt (er könnte die Seite nicht zurücklesen); Low-Trust-Agenten
(clearance ≤ customer) sollten in einen session-Sandbox schreiben statt in einen
persistenten Node (Promotion → T4).
Die Klassifizierung ist nur dann eine Grenze, wenn sie vor der Kontextbefüllung
durchgesetzt wird. access.py ist die wiederverwendbare Bibliothek dafür (und die single
source of truth der visibility-Leiter — lint-links.py/lint-tree.py importieren sie):
from access import AgentProfile, Page, can_read, filter_readable
agent = AgentProfile("prod", clearance="customer",
read_scope=frozenset({"company"}), write_scope="session")
visible = filter_readable(candidate_pages, agent) # Gate vor dem Kontextfenster- Lesbar ⇔
rank(visibility) ≤ rank(clearance)undnode ∈ read_scope. - Fail closed: fehlende/ungültige Seiten-
visibility→personal(verbergen); fehlende/ ungültige Agenten-clearance→public(geringster Zugriff). Unbekanntes leakt nie. - Tests:
uv run --no-project python -m unittest test_access(Fokus: kein Leakage). - Reiner Stdlib-Code → von jedem Retrieval-Layer (Produkt-Agent, MCP-Server) importierbar.
Stellt das Wiki als Agenten-Gedächtnis über MCP (stdio) bereit. Der Server ist die Sicht
genau eines Agenten: er lädt dessen AgentProfile aus vault-tree.yaml (PKWIKI_AGENT_ID)
und setzt alle Zugriffe über access.py durch — kein Tool umgeht den Filter.
PKWIKI_AGENT_ID=internal-demand-ai-copilot VAULT_ROOT=/pfad uv run pkwiki-mcp.py| Tool | Wirkung |
|---|---|
search_wiki(query) |
Titel-/Volltextsuche — nur lesbare Treffer |
read_page(ref) |
Seiteninhalt (ref = node:pfad.md), nur wenn can_read |
list_index() |
lesbare Seiten nach Node |
remember(text) |
episodisch: an log.md im write_scope anhängen |
save_note(title, content) |
semantisch: Konzeptseite im write_scope (visibility = default_visibility des Nodes) |
- Read gefiltert durch
filter_readable; Write nur inwrite_scope(can_write). write_scope: session→ ephemerer Sandbox unter.sessions/<agent>/(gitignored, kein Persist).- Kernlogik in
pkwiki_server.py(ohnemcp/yaml-Import → testbar); Tests:test_mcp.py.
Das Wiki kann Langzeitgedächtnis eines Agenten sein. Dafür gilt:
Schreibzonen (aus dem write_scope des Agentenprofils, T2):
session— ephemerer Sandbox-Node, kein Persist im Baum. Default für Low-Trust-/ Produkt-Agenten: externer Input vergiftet so nie das persistente Gedächtnis.- persistenter Node (z.B. eigener
personal-/team-Node) — nur für vertrauenswürdige interne Agenten. Ein Agent schreibt ausschließlich in seinenwrite_scope(access.can_write).
Memory-Schichten (mappen auf bestehende Seitentypen):
- episodisch →
log.md(append-only): was wann passiert ist. - semantisch →
concepts/+entities/: verdichtetes, vernetztes Wissen (Graph). - prozedural/Quellen →
sources/: woher eine Erkenntnis stammt (Provenienz).
Promotion (Hochstufen in einen breiteren Layer):
- Wissen entsteht im engen Node (
session/personal) und wird erst nach Review inteam→companygehoben — Promotion verbreitert die Sichtbarkeit und ist nie automatisch. - Regeln: Ziel-Node muss Vorfahr sein (nur nach oben); Ziel-Sichtbarkeit =
default_visibilitydes Ziel-Nodes und muss das Publikum verbreitern. uv run promote.py --from <node> --to <node> --visibility <stufe>plant und validiert die Promotion (permissibel? resultierende Sichtbarkeit?), führt sie aber nicht aus — der Move + Review-Vermerk inlog.mdbleibt ein bewusster manueller Schritt (T4-Gate).
- Interne Links immer als
[[seiten-name]](Dateiname ohne .md, kebab-case) - Code-Wiki:
[[modul-slug]]für Module,[[661]]für Tickets (DAI-661) - Handbücher:
[[kapitel-slug]]für Kapitelverweise innerhalb eines Produkts - Bilder einbetten:
![[dateiname.jpg]](Obsidian-Syntax) - Neue Konzepte ohne Seite: als
[[neues-konzept]]verlinken, dann Seite anlegen
[[wikilinks]] sind die Obsidian-native Default-Form und bleiben es. Wo ein Link
außerhalb von Obsidian stabil bleiben muss (GitHub-Rendering, Archiv-Repo, fremde
Tools), ist zusätzlich die bundle-relative Form erlaubt — angelehnt an das
Open Knowledge Format:
ein Markdown-Link, dessen Pfad mit / ab dem wiki/-Root beginnt.
[OpenAI](/entities/openai.md) # bundle-relativ, ab wiki/ — portabel
[[openai]] # Obsidian-Wikilink — Defaultlint-links.pylöst beide Formen auf und prüft sie (siehe Operation: LINT).- Regel wie bei OKF: Links sind gerichtete Kanten; ein kaputtes Ziel ist kein Fehler, der etwas abbricht, sondern ein Lint-Befund (Ziel ggf. noch anzulegen).
Wenn der Nutzer sagt "ingest [Datei]" oder "ingest die neuen Dateien in raw/":
- Lese das Dokument vollständig
- Extrahiere die zentralen Konzepte, Argumente, Entitäten, Daten
- Erstelle oder aktualisiere Wiki-Seiten:
- 1 Quellenübersicht in
wiki/sources/ - 3–10 Konzept-Seiten in
wiki/concepts/(neue anlegen oder bestehende erweitern) - Entity-Seiten für relevante Personen/Unternehmen in
wiki/entities/ - Falls starke themenübergreifende Muster sichtbar: Synthese in
wiki/syntheses/
- 1 Quellenübersicht in
- Verlinke alle neuen/aktualisierten Seiten untereinander
- Aktualisiere
wiki/index.mdmit neuen Einträgen - Logge den Ingest in
wiki/log.md:## YYYY-MM-DD HH:MM — INGEST Quelle: raw/.../dateiname Neue Seiten: [[konzept-1]], [[entity-x]] Aktualisierte Seiten: [[konzept-2]]
Wenn der Nutzer eine inhaltliche Frage stellt:
- Lese
wiki/index.mdum relevante Seiten zu identifizieren - Bei Code-Fragen:
wiki/code-wiki/<projekt>/index.mdlesen - Bei Handbuch-Fragen:
wiki/manuals/index.md→ passendes Produkt → Kapitel - Lese die relevanten Seiten
- Synthetisiere eine Antwort mit Verweisen auf Wiki-Seiten und Originalquellen
- Falls die Antwort neue, wertvolle Erkenntnisse enthält: als neue Synthese-Seite speichern
- Logge die Query in
wiki/log.md
Wenn der Nutzer "lint" oder "wiki aufräumen" sagt:
Erst deterministisch vorprüfen, dann inhaltlich:
uv run lint-links.py # Broken Links + Waisen + ungültige visibility
uv run lint-links.py --show-missing-visibility # zusätzlich: Seiten ohne visibility-Feld
uv run lint-links.py --strict # Exit 1 bei Broken Links / ungültiger visibilityPrüfe die Wiki auf:
- Widersprüche: Seiten die widersprüchliche Aussagen machen → markieren mit
> ⚠️ Widerspruch zu [[andere-seite]] - Waisen: Seiten ohne eingehende Links → verlinken oder in index.md aufnehmen
- Verwaiste Links:
[[seiten-name]]die auf nicht existierende Seiten zeigen → Seite anlegen oder Link korrigieren - Veraltetes: Seiten mit
confidence: lowdie aktualisiert werden könnten - Lücken: Konzepte die aus mehreren Quellen referenziert werden, aber noch keine eigene Seite haben
Report als strukturierte Liste, dann Fixes durchführen.
Wenn der Nutzer sagt "reorganisiere die Wiki", "sortiere das Wissen / labele die Rechte" oder "lösche die privaten Inhalte":
uv run reorganise.py # Dry-run: Klassifizierungs-Plan, nichts wird verändert
uv run reorganise.py --apply # Labels schreiben + personal-Seiten nach wiki/.trash/
uv run reorganise.py --reclassify --apply # auch bereits gelabelte Seiten neu einstufen
uv run reorganise.py --limit 5 # nur die ersten 5 Seiten (zum Antesten)- Klassifiziert jede kuratierte Seite (
concepts//entities//sources//syntheses/) per Azure OpenAI in die visibility-Leiter (access.py= single source of truth) und schreibt das Label ins Frontmatter (visibility:+last_updated:). - Private Inhalte (
visibility: personal) werden aus der aktiven Wiki entfernt — nicht hart gelöscht, sondern nachwiki/.trash/<relpfad>verschoben (rückholbar, gitignored). - Sicher per Default: ohne
--applynur Plan; bestehende gültige Labels werden respektiert (außer--reclassify); graceful (eine fehlerhafte Seite bricht den Lauf nie ab). code-wiki/undmanuals/werden nicht angefasst (erben Node-Sichtbarkeit, T5).- Danach:
uv run rebuild-index.pyunduv run lint-links.pynachziehen (Index regenerieren, verwaiste Links auf nach.trashverschobene Seiten finden).
- Sprache: Deutsch bevorzugt, Fachbegriffe auf Englisch lassen
- Länge: Konzeptseiten 200–600 Wörter, Synthesen können länger sein
- Ton: Sachlich, präzise, keine Wertungen ohne Quelle
- Confidence-Level:
high— aus mehreren unabhängigen Quellen belegtmedium— aus einer Quelle, plausibellow— Spekulation oder veraltete Information
- Niemals Dateien in
raw/modifizieren - Niemals in
wiki/code-wiki/oderwiki/manuals/manuell schreiben — diese werden automatisch generiert - Immer
log.mdaktualisieren nach jeder manuellen Operation - Immer
index.mdaktualisieren wenn neue Seiten in concepts/entities/sources/syntheses angelegt werden - Bestehende Seiten erweitern statt Duplikate anlegen
- Bei Unsicherheit über Kategorisierung:
domain: crossverwenden - Graceful degradation (OKF-Prinzip „tolerate, don't reject"): Pipeline-Skripte, die über
viele Seiten iterieren, dürfen an einer fehlerhaften Einzelseite nie den ganzen Lauf
abbrechen — Seite überspringen, Warnung loggen, weitermachen. Unbekannte Frontmatter-Felder,
unbekannte
type-Werte und kaputte Links werden toleriert, nicht verworfen.
templates/inform-master.pptx # Sauberes Template – nur Master, keine Content-Slides
Layouts (Master 0):
title slide + rhomboid— Titelfolieheadline + text— Standard-Content-Slide (Bullet-Hierarchie)section slide— Zwischenfolie / Trenneragenda— Agenda-Folietext slide + rhomboid— Text mit Rhombus-Dekoheadline only/headline + rhomboid/empty slide/title slide + full image
Pattern für neue Präsentationen (python-pptx):
prs = Presentation("templates/inform-master.pptx")
master = prs.slide_masters[0]
layouts = {l.name: l for l in master.slide_layouts}
# Neue Slides hinzufügen BEVOR der Template-Placeholder-Slide entfernt wird
s1 = prs.slides.add_slide(layouts['headline + text'])
# ... alle Slides hinzufügen ...
# Am Ende: Original-Placeholder-Slide entfernen (slide1 im Template)
prs.slides._sldIdLst.remove(prs.slides._sldIdLst[0])
prs.save("output/praesentation.pptx")Wichtig: Erst alle neuen Slides adden, dann den ersten (Original) entfernen — sonst entstehen ZIP-Duplikate.
assets/image-index.json # Maschinenlesbarer Index aller extrahierten Bilder
wiki/picture_index.md # Menschenlesbarer Index (für QUERY)
wiki/manuals/*/image-index.md # Handbuch-Bilder pro Produkt (mit ![[...]]-Embeds)
wiki/manuals/*/assets/ # Extrahierte Handbuch-Screenshots als .jpg
wiki/picture_index.mdlesen — enthält Beschreibungen aller Bilder aus slides/pdfs/docswiki/manuals/<produkt>/image-index.mdfür Handbuch-Screenshots- Nach Stichwörtern suchen (Grep auf
assets/image-index.json) - Bildpfade aus slides/pdfs:
raw/.cache/.images/<unterordner>/<dateiname>_slide<N>.jpg # PPTX-Slides raw/.cache/.images/<unterordner>/<dateiname>_page<N>.jpg # PDF-Seiten
# Einzelne Datei (Text + Vision):
uv run extract.py raw/slides/datei.pptx
# Alle neuen Dateien (Batch-Vision für Bilder):
uv run extract-images.py
# Nur Index neu aufbauen (keine API-Calls):
uv run extract-images.py --index-onlyVoraussetzung: .env mit AZURE_OPENAI_API_KEY und AZURE_OPENAI_ENDPOINT.