Architecture
This page provides a high-level overview of the AI Platform ecosystem architecture: physical disk layout, domain hierarchy, network traffic flow, PDAI document processing, and the four-machine cluster.
Physical Layout (~/ai-mac-studio/ Umbrella)
All ai-* directories are real directories under ~/ai-mac-studio/ — no Dropbox, no Conda, no PROJECT_BASE. Finder and every CLI tool walk each tree exactly once.
flowchart LR
subgraph umbrella ["~/ai-mac-studio/"]
platform["platform/\n(Hub, Proxy, Registry)"]
agents["agents/\n(Tool Packages)"]
pdai["pdai/\n(PDAI Pipeline, consolidated)"]
apps["apps/\n(Hybrid Native+Python)"]
scholarly["scholarly/\n(Research Projects)"]
publication["publication/\n(arXiv, Lektorat)"]
privat["privat/\n(PrivatKanzlei)"]
development["development/\n(Experiments)"]
syncthing["syncthing/\n(Sync Manager)"]
end
subgraph pdai1 ["External /Volumes/PDAI-1"]
pdaiColl["pdai-collections/\n(~37 Sammlungen, Bulk-Daten)"]
editions["editions/\n(Viewer-Registrierungen)"]
end
pdai -. "data_path()" .-> pdai1
scholarly -. "data_path()" .-> pdai1
~/ai-mac-studio is the tree on mac-studio, the central machine for PDAI data, the DuckLake, the MCP servers and Famulus development. Client machines (e.g. openscience) hold a Syncthing mirror of it at ~/ai-openscience and mount PDAI-1 via SMB; studio-only steps are queued in ~/syncthink/queue/.
Key properties:
- No Dropbox —
fileproviderdtraversiert keineai-*-Pfade - No conda / PROJECT_BASE — virtuelle Envs per Paket via
uv - No symlinks in der Umbrella — alle Pfade sind echte Verzeichnisse
- Bulk-Daten (~150+ GB) auf PDAI-1; Zugriff über
env.data_path("name") - Python ≥ 3.14/3.15, hatchling, keine
requirements.txt
Domain Hierarchy
graph TD
home["~/ai-mac-studio/"]
home --> platform["platform/\nGeneral Manager\n(Hub :5050, Proxy :5001)"]
home --> pdai["pdai/\nPDAI Document Pipeline\n(konsolidiert Aug 2026)"]
home --> agents["agents/\n29 Tool-Pakete\n(7 Kategorien)"]
home --> apps["apps/\nHybride Apps\n(ai-korrespondenz, ai-applevoicerecorder)"]
home --> scholarly["scholarly/\nForschungsprojekte\n(ai-karman-manager, ...)"]
home --> publication["publication/\narXiv, Lektorat"]
home --> development["development/\nExperimente\n(moss-transcribe, causal-architect)"]
pdai --> pipeline["pipeline/\nai-scholar, ai-classifypdf\nschema-audit, ai-ocr-dev"]
pdai --> index["index/\nai-lemma-index :5890\nai-oxford-dictionary"]
pdai --> pdaiAgents["agents/\nai-query :5113"]
pdai --> viewer["viewer/\nai-viewer :5100–5720"]
pdai --> format["format/\nlettre-pdai, ai-repository"]
pdai --> enrich["enrich/\nai-translation, ai-biblatex"]
agents --> infra["infrastructure/ (8)\nai-core, ai-cluster\nai-machine-registry"]
agents --> comm["communication/ (6)\nai-korrespondenz, ai-mail\nai-reporter"]
agents --> media["media/ (3)\nai-audio, ai-video, ai-foto"]
agents --> apple["apple/ (2)\nai-apple, ai-apple-documents"]
agents --> dataml["data-ml/ (4)\nai-chroma, ai-stanza\nai-index, ai-exo"]
agents --> mgmt["management/ (6)\nai-agenda, ai-voicememo\nai-task"]
Network Topology
Alle Internet-Anfragen kommen durch einen einzigen ngrok-Tunnel auf mac-studio, geroutet vom Proxy auf Port 5001 über config/routes.yaml.
graph LR
internet["Internet"]
ionos["IONOS\n*.lettre.ai\nFrameset-Weiterleitung"]
ngrok["https://lettre.ngrok.dev\nngrok-Tunnel"]
proxy["mac-studio :5001\nProxy\nroutes.yaml"]
internet --> ionos --> ngrok --> proxy
proxy --> hub[" :5050 Hub"]
proxy --> viewer[" :5100 AI Viewer"]
proxy --> aiquery[" :5113 AI Query API"]
proxy --> famnb[" :5118 Famulus Notebook"]
proxy --> glider[" :5890 Glider"]
proxy --> editions[" :5111 Editions"]
proxy --> diaries[" :5112 Diaries"]
proxy --> korrespondenz[" :5300 Korrespondenz"]
proxy --> inqua[" :8080 INQUA (Host-Header)"]
proxy --> more[" ... 14 weitere Routen"]
Externe Domänen (*.lettre.ai) sind in IONOS als HTML-Frameset-Weiterleitungen zu https://lettre.ngrok.dev/{path} konfiguriert.
Tailscale-Zugriff: https://mac-studio.tail147011.ts.net/ → Proxy :5001.
PDAI Document Pipeline
PDAI (Primary Document AI) ist das gelehrte Dokument-Verarbeitungssystem. Es konvertiert gescannte PDFs in strukturiertes XML für Annotation und Analyse.
Konsolidierter Code-Pfad: ~/ai-mac-studio/pdai/
Dokument-Daten: /Volumes/PDAI-1/pdai-collections/ (~37 Sammlungen)
graph TD
pdfs["Quell-PDFs\n(Bibliotheken, Archive)"]
classify["ai-classifypdf\n pdai/pipeline/ai-classifypdf\nErnte + Klassifizierung"]
pdai1["/Volumes/PDAI-1/pdai-collections/\n~37 thematische Sammlungen"]
scholar["ai-scholar process\n pdai/pipeline/ai-scholar\n--model qwen3.5:cloud / kimi-k2.7-code:cloud\n(+structure.xml für Argumentstruktur)"]
pages["pages/page_NNN/page_NNN.xml\nStrukturiertes PDAI 2.0 XML\n+ structure.xml"]
index["ai-lemma-index\n pdai/index/ai-lemma-index\nDuckDB + Parquet-Postings"]
query["ai-query :5113\n pdai/agents/ai-query\nQuery-Resolution-Agent"]
viewer["ai-viewer :5100–5720\n pdai/viewer/ai-viewer\nWeb-Dokumentbetrachter"]
pdfs --> classify --> pdai1 --> scholar --> pages
pages --> index --> query --> viewer
Wichtige Pfade (aktuell):
| Komponente | Pfad |
|---|---|
| Pipeline-Code | pdai/pipeline/ai-scholar/, pdai/pipeline/ai-classifypdf/ |
| Lemma-Index | pdai/index/ai-lemma-index/ |
| Query-Agent | pdai/agents/ai-query/ (v0.5.0) |
| Viewer | pdai/viewer/ai-viewer/ |
| Schemata (DTDs) | pdai/pipeline/ai-scholar/src/ai_scholar/schemas/ |
| Instruktions-Templates | pdai/pipeline/ai-scholar/src/ai_scholar/instructions/ + platform/registry/instructions/ |
| Produktions-Sammlungen | /Volumes/PDAI-1/pdai-collections/ |
| Editions-Registrierungen | /Volumes/PDAI-1/editions/<name>/registry.json |
OCR-Modellauswahl:
| Dokumenttyp | Standardmodell | Fallback |
|---|---|---|
| Gedruckte Gelehrten-PDFs | qwen3.5:cloud |
gemini-3.8-flash |
| Handschriftliche Korrespondenz | kimi-k2.7-code:cloud |
gemini-3.8-flash |
Reference layer (famulus reference)
Between the PDAI collections and their consumers sits the reference layer. Each collection is exported into one DuckLake; one MCP server serves items, citations and traces by fr: address. Overview: The Famulus universe; concept: Famulus reference; storage: DuckLake.
graph LR
coll["/Volumes/PDAI-1/pdai-collections/<coll>/"] -->|"famulus-reference build"| fdb["<coll>_famulus.duckdb"]
fdb -->|"export (mac-studio)"| lake["DuckLake _lake/famulus.ducklake"]
lake -->|"read replica, READ_ONLY"| mcp["famulus-reference MCP :5135"]
lake -->|"FAMULUS_LAKE=1"| proof["famulus-proof"]
mcp --> orch["ai-platform-mcp, Partituren"]
proof --> nb["famulus-notebook :5118"]
| Component | Path | Port |
|---|---|---|
| famulus-reference (build, export, MCP, harvest) | pdai/famulus-reference/ |
5135 |
| DuckLake catalog | /Volumes/PDAI-1/pdai-collections/_lake/famulus.ducklake |
— |
famulus-proof lake mode, fr: resolver |
development/famulus-proof/src/famulus_proof/lake.py |
— |
| intake skill | pdai/skills/pipeline/pdai-collection-intake/ |
— |
The lake has a single writer (mac-studio). Client machines read the lake over SMB or through the MCP server.
Laufende PDAI-Dienste
Supervisor: com.ai-platform.editions → startet alle Viewer + Glider + Landing
Query-Agent: com.ai-platform.ai-query
| Dienst | Port | Pfad | Route |
|---|---|---|---|
| Enestroem Viewer | 5100 | pdai/viewer/ai-viewer |
/viewer |
| Euler Opera Omnia | 5103 | pdai/viewer/ai-viewer |
/euler-opera |
| Kepler GW | 5104 | pdai/viewer/ai-viewer |
/kepler-gw |
| Copernicus | 5105 | pdai/viewer/ai-viewer |
/copernicus |
| Waefler | 5106 | pdai/viewer/ai-viewer |
/waefler |
| Euler OO IVA | 5107 | pdai/viewer/ai-viewer |
/euler-oo-iv |
| Pirckheimer | 5108 | pdai/viewer/ai-viewer |
/pirckheimer |
| Kirch | 5109 | pdai/viewer/ai-viewer |
/kirch |
| Editions Landing | 5111 | pdai/viewer/ai-viewer |
/editions |
| Astronomical Diaries | 5112 | pdai/viewer/ai-viewer |
/diaries |
| ai-query (API, Widget) | 5113 | pdai/agents/ai-query |
/ai-query |
| Famulus Notebook | 5118 | development/famulus-notebook |
/famulus-notebook |
| Famulus Reference MCP | 5135 | pdai/famulus-reference |
/famulus-reference (planned) |
| Glider Suche | 5890 | pdai/index/ai-lemma-index |
/glider |
| Ancient Sundials | 5720 | pdai/viewer/ai-viewer |
/sundials |
| Karman-Manager | 5725 | scholarly/projects/ai-karman-manager |
/karman |
Machine Cluster
graph TD
macstudio["mac-studio\n(Primary Hub)\nTailscale 100.102.189.23\nAlle Dienste hier"]
macmini["mac-mini\n100.121.127.59\nBatch-Worker"]
macm4["mac-m4\nnicht im Tailnet\nDev-Maschine, Batch-Worker"]
macerster["mac-erster\n100.87.180.115\n(= openscience, legacy)"]
macstudio <-->|"Tailscale VPN"| macmini
macstudio <-->|"Tailscale VPN"| macm4
macstudio <-->|"Tailscale VPN"| macerster
| Maschine | Rolle | Tailscale IP | Besonderheiten |
|---|---|---|---|
| mac-studio | Primary Hub | 100.102.189.23 | M1 Ultra 128 GB; alle Dienste, NFS-Server |
| mac-mini | Batch-Worker | 100.121.127.59 | OCR-Batch-Jobs, NFS-Client |
| mac-m4 | Dev + Batch | nicht im Tailnet (Stand 23.09.2026) | Entwicklung, OCR-Experimente |
| mac-erster | Legacy | 100.87.180.115 | = openscience; read-only |
NFS: mac-studio exportiert /Volumes/PDAI-1 via NFS an mac-mini.
Tailscale-URL: https://mac-studio.tail147011.ts.net/ → Proxy :5001.
Konfigurationsdateien
graph LR
routesyaml["config/routes.yaml\n(URL zu Port)"]
datamounts["config/data-mounts.yaml\n(PDAI-1 Mount-Namen)"]
machinesjson["machines/*.json\n(Maschinen-Konfiguration)"]
envpy["shared/env.py\n(Laufzeit-Pfad-Auflösung)"]
catalog["catalog.duckdb\n(Indexiertes Registry)"]
machinesjson --> envpy
datamounts --> envpy
routesyaml --> proxy["Proxy :5001"]
envpy --> allpackages["Alle ai-* Pakete"]
catalog --> hub["Hub :5050"]
config/service-commands.yaml ist nicht mehr autoritativ. Editionen werden von platform/scripts/editions_supervisor.py (launchd: com.ai-platform.editions) verwaltet. Die Datei wird nur noch als historische Referenz behalten.
Autoritative Start-Quelle: launchd-Plists in ~/Library/LaunchAgents/com.ai-platform.*.plist
Pfad-Auflösung
Alle Pakete verwenden platform_env — niemals hartcodierte absolute Pfade:
import importlib.util, sys
from pathlib import Path
def load_env():
env_path = Path.home() / "ai-mac-studio/platform/shared/env.py"
spec = importlib.util.spec_from_file_location("_platform_env", env_path)
mod = importlib.util.module_from_spec(spec)
sys.modules["_platform_env"] = mod
spec.loader.exec_module(mod)
return mod.detect()
env = load_env()
env.HOME # ~/ai-mac-studio
env.PLATFORM_DIR # ~/ai-mac-studio/platform
env.package_dir("ai-scholar") # ~/ai-mac-studio/pdai/pipeline/ai-scholar
env.data_path("pdai_collections") # /Volumes/PDAI-1/pdai-collectionsLetzte Aktualisierung: 2026-08-24