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:
# 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 leavesDas 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:
| Protokoll | So verbindet es sich |
|---|---|
| Lokale Dateien & Uploads | ein File-Handle, direkt von der Platte gestreamt |
| HTTP(S), rein und raus | direkt aus dem Browser geholt — und gesendet |
| Cloud-Laufwerke | autorisiert ü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, Colab | Act-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.
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:
# 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-sendDer 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.