flowchart LR probe["Probe in Reihenfolge"] --> lo["127.0.0.1"] probe --> lan["Adresse im lokalen Netz"] probe --> vpn["Adresse im VPN"] probe --> ts["Tailscale-Name"] lo --> first["erste Antwort gilt 60 s"] lan --> first vpn --> first ts --> first
Verknüpfung
Andere Rechner, andere Dienste, andere Notebooks
Eine Verknüpfung gibt einem anderen Famulus-Dienst einen Namen und eine Liste von Adressen; ein Block nennt diesen Namen, um dort eine Sammlung zu lesen, sich rechnen zu lassen oder ein Artefakt zu holen.
Die PDAI-Sammlungen liegen auf PDAI-1 am mac-studio. Ein Notebook auf einem anderen Rechner kommt an sie nur über den Dienst heran, der auf dem mac-studio läuft. Dieser Dienst heißt aus Sicht des Notebooks Peer. Ein Peer kann ein anderer Famulus-Notebook-Dienst sein, aber auch ai-query, der Lektor, ein Editions-Viewer oder ein MCP-Server.
1 Eine Verknüpfung eintragen
Die Verknüpfungen stehen in ~/.config/famulus/peers.yaml. Jeder Eintrag hat einen Namen, eine Art und die Adressen in der Reihenfolge, in der sie probiert werden.
peers:
mac-studio:
kind: notebook
endpoints:
- http://127.0.0.1:5118
- http://192.168.178.20:5118
- https://mac-studio.tail147011.ts.net/famulus-notebook
token_env: FAMULUS_TOKEN_MAC_STUDIODie Kommandozeile schreibt und prüft dieselbe Datei:
famulus-notebook peers add mac-studio --kind notebook \
--endpoint http://192.168.178.20:5118 \
--endpoint https://mac-studio.tail147011.ts.net/famulus-notebook \
--token-env FAMULUS_TOKEN_MAC_STUDIO
famulus-notebook peers probe mac-studio
famulus-notebook peers listtoken_env nennt die Umgebungsvariable, in der das Token des Peers steht. Das Token selbst gehört nicht in peers.yaml, nicht in ein Notebook und nicht in ein Log.
2 Welcher Weg genommen wird
Der Rechner probiert die Adressen der Reihe nach. Die Probe ist eine Anfrage an eine feste Adresse des Peers, für einen Notebook-Dienst /api/peer, für ai-query /api/health, für den Lektor /health. Sie wartet höchstens 1,5 Sekunden. Die erste Adresse, die antwortet, gilt 60 Sekunden lang; danach wird neu probiert.
So arbeitet ein Laptop mit einer einzigen peers.yaml zu Hause im lokalen Netz, unterwegs über das VPN und sonst über das Tailnet. Welcher Weg gewählt wurde, steht in jedem Ergebnis, das über den Peer kam.
3 Was ein Block über einen Peer tut
Ein Eintrag in duckdb nennt den Peer. Die Abfrage läuft dann auf dem Peer, nicht am eigenen Rechner. Der Pfad muss mit $PDAI_COLLECTIONS/<sammlung>/ beginnen; die Sammlung bleibt, wo sie ist.
```{famulus}
---
id: zaehlung
duckdb:
- alias: main
path: $PDAI_COLLECTIONS/pirckheimer/pirckheimer.duckdb
peer: mac-studio
partiturs:
- id: duckdb-read
input:
sql: SELECT direction, count(*) AS n FROM letters_resolved GROUP BY direction
artefacts:
- name: tabelle
kind: table
file: tabelle.json
---
Zähle die Briefe nach Richtung.
```Der Peer führt nur lesende Abfragen aus: SELECT oder WITH, ohne ATTACH, COPY, INSTALL, LOAD, PRAGMA und ohne schreibende Befehle. Die Datenbank wird nur lesend geöffnet, externer Zugriff ist abgeschaltet. Eine Antwort umfasst höchstens 5000 Zeilen, eine Abfrage läuft höchstens 30 Sekunden. Alle Datenbanken eines Blocks müssen zu demselben Peer und derselben Sammlung gehören.
engine nennt den Peer, der den ganzen Block ausführt. Der eigene Rechner braucht dann weder Sammlung noch Query-Pipeline.
engine: mac-studioDer Rechner schickt Präambel und Instruktion. Der Peer führt den Block in einem eigenen, leeren Paket aus und liefert den Verlauf fortlaufend zurück. Am Ende schickt er das ganze Log. Es landet im Log des eigenen Notebooks, genau wie bei einem lokalen Lauf, mit dem Namen des Peers im Manifest.
Ein Block mit engine darf keinen Querverweis {{ref:…}} und keine Setting-Datei enthalten: beides liegt im eigenen Paket, das der Peer nicht sieht. Der Rechner lehnt einen solchen Block vor dem Senden ab und nennt den Grund.
Ein Querverweis kann auf ein Notebook eines Peers zeigen. Die Form ist peer:<name>/fam:<projekt>/<notebook>/<block>.<artefakt>; die ältere Form peer:<name>/<notebook>/<block>.<artefakt> gilt weiter.
Nimm {{ref:peer:mac-studio/pirckheimer-briefpartner/briefpartner-roster.roster}} als Grundlage.
Der Rechner holt die Datei nach _famulus/cache/extern/<peer>/…/<artefakt>.json und legt daneben <artefakt>.source.json mit Verweis, Adresse und Zeitpunkt ab. Jeder Lauf holt die Datei neu; die abgelegte Kopie belegt, welche Fassung der Lauf benutzt hat.
4 Zugang
Ein Dienst entscheidet bei jeder Anfrage, ob er sie annimmt:
| Anfrage kommt | Zugang |
|---|---|
unmittelbar von 127.0.0.1 |
ohne Token; der Rechner gehört dem Besitzer |
| über den Plattform-Proxy oder Tailscale Serve | nur mit Token |
| aus dem Tailnet 100.64.0.0/10 | mit Token, oder ohne, wenn FAMULUS_TRUST_TAILNET=1 |
| von sonst woher | nur mit Token |
Ohne gültiges Token antwortet der Dienst mit 401. Frei zugänglich sind nur die Seite /notebook, ihre Dateien unter /assets/ und diese Dokumentation unter /docs; alle Daten liegen hinter /api/.
Das Token steht in ~/.config/famulus/token (Modus 0600). Ein Programm schickt es im Kopf Authorization: Bearer …. Ein Browser auf einem anderen Rechner öffnet die Seite einmal mit dem Token hinter dem Zeichen #:
https://mac-studio.tail147011.ts.net/famulus-notebook/notebook#token=…
Der Teil hinter # geht nicht an den Server und erscheint daher in keinem Zugriffsprotokoll. Die Seite liest ihn, tauscht ihn gegen ein Cookie, das kein Skript lesen kann, und entfernt ihn aus der Adresszeile.
Zwei Wege bleiben dem eigenen Rechner vorbehalten, auch mit Token: Anmerkungen an den Lernzyklus (/api/annotations) und die Besitzersitzung im Lektor (/lektorat). Ein fremder Aufrufer bekommt beim Lektor dessen eigene Anmeldeseite.
5 Auskunft eines Peers
GET /api/peer sagt, was ein Notebook-Dienst anbietet: Name und Version, Rechner, ob Blöcke ausgeführt werden können, die Namen seiner Notebooks, die Wurzel der Sammlungen und die Fähigkeiten notebooks, artefacts, collections-read, run-block und partitur. GET /api/collections listet die Sammlungen mit ihrem Stand aus status.json.