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 sollen nur feuern, solange ein Tab offen ist: Ohne Tab werden Ereignisse eingereiht, laut begrenzt, bis du zurückkehrst. Heute funktionieren Inbox und Scharfschalten, aber ein scharfer Trigger löst seinen Lauf noch nicht aus. 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.