Bauen

Daten: Dateien, Connectors und Datensätze

Deine Daten leben längst irgendwo — auf einer Platte, hinter einem HTTP-Endpunkt, in einem Cloud-Laufwerk, in einem Objektspeicher-Bucket, auf einer Maschine, die du über SSH erreichst. Scellis zieht eine scharfe Linie durch all das: Bytes, die hereinkommen, streamen auf dein Gerät — unter Zugangsdaten, die nur du hältst; Bytes, die hinausgehen, verlangen eine separate, stärkere Einwilligung, die das Ziel benennt. Dazwischen werden Daten zu dem, was in Scellis ohnehin alles ist — versioniert, inhaltsadressiert, per Hash zitierbar. Diese Seite geht diesen Weg ab: Dateien, Connectors, Zugangsdaten, die Richtungsregel — und wie rohe Bytes zu einem Dataset werden, das du per Hash reproduzieren kannst.

Lokale Dateien streamen direkt von der Platte#

Die häufigste Quelle ist die unspektakulärste. Eine lokale Datei streamt über ein File-Handle direkt von der Platte: Ein Multi-Gigabyte-Dataset wird an Ort und Stelle gelesen — standardmäßig nie hochgeladen und nie durch die lokale Datenbank des Browsers gequetscht. Diese Datenbank hält dein Arbeitsset — den local-first-Katalog dessen, was du hast — nicht deine Rohdaten. Eine große Datei zu öffnen kostet deshalb genau das, was das Lesen kostet, und nicht mehr: kein Importschritt, keine stille Duplikation von Gigabytes in den Browser-Speicher, keine Kopie, die du später mit dem Original abgleichen musst.

Connectors sind Content, kein Engine-Feature#

Alles andere kommt über einen Connector — und ein Connector ist Content, kein Engine-Feature. Er bündelt drei Dinge: einen deklarierten Effekt, damit ein Workflow, der ins Netz greift, das vor dem Lauf sagt; typisierte IO-Blöcke, damit ankommende Daten mit einer echten Form in den Graphen eintreten; und eine Auth-Bindung, damit die Zugangsdaten-Regeln unten einheitlich gelten. Darunter hat der Datensatz eine Form:

yaml
# A connector is content — three parts, checked like any block.
name: user/ada/s3_source           # namespaced — never shadows a builtin
version: 1
effect:  { id: net.ingress, direction: ingress }    # declared before it runs
auth:    { kind: api_key, store: device_only }       # never synced, never provenance-stamped
io:
  in:  [{ name: bucket, dtype: string }, { name: key, dtype: string }]
  out: [{ name: object, dtype: bytes }]               # enters the graph with a real shape
transport: client_signed           # SigV4 signed on device — the secret never leaves

Das ausgelieferte Set deckt die Protokolle ab, hinter denen die meisten Daten leben — lokale Dateien und Uploads, HTTP rein und raus, FTP/FTPS/SFTP über ein Relay, S3 und GCS mit client-seitigem Signieren, Google Drive und Dropbox über OAuth, SMTP-E-Mail, ein Telegram-Bot, aus- und eingehende Webhooks, Google-Sheets-Append und Colab-Export:

ProtokollSo verbindet es sich
Lokale Dateien & Uploadsein File-Handle, direkt von der Platte gestreamt
HTTP(S), rein und rausdirekt aus dem Browser geholt — und gesendet
Cloud-Laufwerkeautorisiert über OAuth (per-Datei-Scope)
Objektspeicher (S3 / GCS)Anfragen client-seitig signiert
SSH/SFTP und FTPüber ein Relay vermittelt — die eine benannte Ausnahme
E-Mail, Webhooks, Sheets, ColabAct-Blöcke und eine Inbox, je ein expliziter Egress oder Ingress

Weil ein Connector gewöhnlicher Content ist, ist dieses Set ein Boden, keine Decke. OneDrive, Slack, Discord, ein Gmail-API-Client — nichts davon ist ausgeliefert, und nichts muss es sein: Jedes ist ein Nachmittag Erstellen, so wie du jeden anderen Block erstellst — katalogisiert, teilbar und einwilligungspflichtig wie jeder andere. Eine fehlende Integration ist nie eine Maintainer-Warteschlange — sie ist das Schwungrad, das den Katalog antreibt.

Zugangsdaten verlassen dein Gerät nie#

Zugangsdaten sind radikal client-seitig. Ein Token, ein Schlüssel, ein Passwort wird auf deinem Gerät verschlüsselt abgelegt — AES-256-GCM unter einem gerätegebundenen Schlüssel — und dort endet sein Leben. Es wird nie synchronisiert. Es landet nie in der Sync-Warteschlange, die deine übrigen Änderungen für den Server puffert. Es wird nie in die Provenienz gestempelt. Ein Run protokolliert, was ankam — nie, wie du hineingekommen bist. Eine passphrasengeschützte Kopie kannst du für dich selbst exportieren; die Plattform behält keine. Das volle Vertrauensmodell ist Thema von Sicherheit und Privatsphäre.

Hinweis

Verlierst du das Gerät, sind die Zugangsdaten mit ihm weg: Du gibst sie auf der nächsten Maschine neu ein, denn einen Wiederherstellungspfad gibt es nicht. Das ist das Design, das funktioniert — nicht eines, das versagt: Es existiert keine Server-Kopie, die man stehlen könnte.

OAuth, als Content beschafft#

Selbst das Beschaffen eines OAuth-Tokens ist Content. Eine OAuthProviderSpec deklariert Endpunkte, Scopes und PKCE-Flow eines Providers, sodass ein neuer Provider eine Spec ist, die du schreibst — kein Engine-Code — und ein nutzererstellter Provider bringt seine eigene Client-Id mit. Scope-Minimalismus wird author-geprüft: Google ist nur mit dem per-Datei-Picker-Scope ausgeliefert, nie mit pauschalem Drive-Zugriff. Das eine relay-passierende Geheimnis (SSH/FTP-Auth, das ein Browser wirklich nicht vermeiden kann) ist eingewilligt, verbindungsgebunden und nur im Arbeitsspeicher gehalten.

Die Richtung ist die Privatsphäre-Linie#

Scellis behandelt „Netzwerkzugriff“ nicht als eine einzige Berechtigung. Ingress — Daten auf dein Gerät ziehen — ist ein eingewilligter Netzwerk-Effekt: Der Connector deklariert ihn, du genehmigst ihn, und danach liegen die Bytes lokal — zurück in der gewohnten Local-first-Geschichte. Egress — Daten, die dein Gerät verlassen — ist eine separate, stärkere Einwilligung, die das Ziel benennt, und sie kann nie auf einer Ingress-Genehmigung mitfahren. „Von dieser Quelle holen“ autorisiert niemals still, irgendetwas irgendwohin zu senden.

s3 · http · sftpDaten hereinholendein GerätZugangsdatenverschlüsseltnie synchronisiertDaten hinausschickenzweite Einwilligungnennt das Zielapi.lab.org
Abb. 1 — Die beiden Richtungen sind nicht dieselbe Erlaubnis. Daten hereinzuholen lässt die Bytes — und deine Zugangsdaten — auf deinem Gerät. Etwas hinauszuschicken muss eine zweite, stärkere Einwilligung passieren, die das Ziel beim Namen nennt — und das Gate unterbricht den Weg wirklich: Nichts geht hinaus, bevor du es sagst.

Die Linie hält auch, wenn Arbeit Geräte überspannt. In einem verteilten Job bleiben Connectors gerätelokal: Ingress läuft auf dem Gerät des Initiators, bevor die Arbeit partitioniert wird; Egress läuft, nachdem die Ergebnisse zusammengeführt sind. Peers bekommen Arbeit zum Rechnen — nie deine Zugangsdaten.

Hinaussenden — und die Welt hereinlassen#

Zwei Momente verdienen eine eigene Disziplin: Daten hinaussenden und etwas hereinlassen. Jeder Act-Block — eine E-Mail, ein Webhook, eine Nachricht — läuft zuerst als reiner Dry-Run. Er erzeugt den exakten ausgehenden Umschlag bei null Egress, sodass du genau siehst, was gesendet würde, bevor irgendetwas gesendet wird:

text
# Every act-block runs a pure dry-run first — the exact envelope, zero egress.
dry_run  email_send
  to       ada@example.org         # consent copy names this recipient
  subject  "run 812 finished"
  body     2.4 KB
  egress   none                    # nothing left the device
  ledger   send-key 5f1a…          # idempotent — a re-run will not double-send

Der echte Versand ist idempotent, abgesichert durch ein Send-Ledger, damit ein Re-Run nicht doppelt sendet; der Einwilligungstext benennt den Empfänger; Budgets sind laut. Eingehendes ist bewusst bescheiden. Ein Webhook-in ist eine plattform-vermittelte Inbox — eine rotierbare Capability-URL, größenbegrenzt und mit TTL — kein Socket, auf dem der Browser lauscht. Und Trigger feuern nur, solange ein Tab offen ist: Ohne Tab werden Ereignisse eingereiht, laut begrenzt, bis du zurückkehrst. Einen Trigger scharfzuschalten ist selbst die Einwilligung — eine stehende Zustimmung über die volle Effekt-Closure des Workflows, durch eine bewusste Geste geprägt und in dem Moment automatisch entschärft, in dem eine Bearbeitung diese Closure erweitert. Das ist ausdrücklich keine unbeaufsichtigte Automatisierung: Ein geschlossener Tab läuft nicht. (Send-Dedup ist pro Gerät, ein Re-Run auf einer anderen Maschine kann also erneut senden — die Provenienz protokolliert die Schlüssel — eine Grenze, die die Plattform offen benennt statt zu verstecken.)

Formate und Datensätze sind ebenfalls Content#

Ein fremdes Dateiformat ist nichts, das die Engine zufällig versteht; es ist ein Decode-Block — und auf dem Rückweg ein Encode-Block. Das eingebaute Set deckt CSV, Parquet und Arrow ab; ONNX, safetensors und PyTorch-State-Dicts; XLSX- und DOCX-Export; und BPE/WordPiece-Tokenizer, deren Vokabular selbst ein inhaltsadressiertes Artefakt ist. Zieh eine fremde Datei auf die Canvas, und sie läuft über Connector und Codec in einem Zug in die Dataset-Erstellung; ein Codec, der fehlt, ist erstellbar — wie alles andere auf der Plattform. Die ganze Fläche ist katalogisierter Content — zu sehen auf der Daten-Seite.

Dekodierte Daten werden zu einem Dataset: einer erstklassigen, versionierten Katalog-Entität. Jede Version ist inhaltsadressiert — gleiche Daten, gleicher Hash — und ein Trainingslauf referenziert die konsumierte Dataset-Version über genau diesen Hash. „Mit welchen Daten wurde dieses Modell trainiert?“ ist eine Abfrage, keine Archäologie. Splits gehen genauso tief: Ein Train/Val/Test-Split ist selbst ein versioniertes, inhaltsadressiertes Artefakt — eine deterministische Partition aus festem Seed — die exakten zurückgehaltenen Zeilen hinter einem Ergebnis sind also reproduzierbar, nicht ungefähr neu gezogen.

Jedes Dataset trägt eine Dataset-Card — Provenienz, Lizenz, Einwilligungsgrundlage, bekannte Grenzen — und eine Profiling-Ansicht: Spalten, Dtypes, fehlende Werte, Klassenbalance. Und wenn Daten erst Labels brauchen, bevor überwachtes Training beginnen kann, ist eine Labeling- und Annotationsoberfläche Teil der Plattform — kein Werkzeug, für das du sie verlässt.

Größer als der Speicher ist der Normalfall#

Multi-Gigabyte-Eingaben sind kein Randfall, den man überlebt; sie sind der Fall, für den die Engine plant. Jeder Block deklariert seine Streaming-Klasse — Single-Pass, begrenzter Multi-Pass oder volle Materialisierung — und die Engine plant damit stückweise Ausführung gegen explizite Budgets für RAM, VRAM und Speicherplatz. Die Machbarkeit wird vor der Ausführung geprüft, nicht währenddessen entdeckt: Ein Lauf, der nicht passt, wird vorab abgelehnt — mit benannten Optionen: Batch verkleinern, Streaming aktivieren, Präzision ändern — nie als Out-of-Memory-Überraschung mitten im Run. Eine Ablehnung, auf die du reagieren kannst, schlägt einen Absturz, dessen Ursache du hinterher ausgraben musst — denselben Tausch macht Scellis überall.

größer als der Speicher42 GBin Stücken geplantDurchgang für Durchgangvor dem Lauf geprüftSpeicher · Platteläuftstreamt, lädt nie ganzvorab abgelehntmit benanntem Fix
Abb. 2 — Daten, die größer sind als der Speicher, sind ein Plan, keine Panik. Eine 42-GB-Eingabe wird als Strom von Stücken geplant und gegen deinen Speicher und deine Platte geprüft, bevor irgendetwas läuft: Sie läuft — streamend, Durchgang für Durchgang — oder sie wird vorab abgelehnt, mit benanntem Fix.