Zum Hauptinhalt springen

Umgebungsvariablen-Referenz

Bereitstellungsvariablen, Standardwerte, Geheimnisübergabe und die jeweils betroffenen Dienste.

55 Min. Lesezeit

Hier findest du Bereitstellungsvariablen, ihre Standardwerte und die Prozesse, die sie benötigen. Die Projektdatei .env ist eine mögliche Quelle; Container-Umgebungen und Secret-Manager können Werte ebenfalls bereitstellen. Die Beispieldatei enthält die zugehörige Quellkonfiguration.

Erstelle betroffene Dienste nach einer Umgebungsänderung über deinen Bereitstellungsablauf neu. docker compose restart behält die vorhandene Containerumgebung. Dateibasierte Organisationskonfiguration hat einen getrennten Lebenszyklus.

Wie du diese Seite liest

Die Tabellen nennen Variablennamen, Standardwerte und Zweck. Erforderliche Werte müssen den jeweiligen Dienst erreichen; einige erzeugt die Bereitstellung automatisch. Optionale Werte können ungesetzt bleiben. Ein angegebener Standard kann aus Compose stammen statt aus dem Prozess selbst.

Nutze zusätzlich die kommentierte Beispieldatei und prüfe bei fehlenden Werten die wirksame Umgebung des betroffenen Dienstes.

Domain-Identität (Pflicht beim ersten Boot)

NameDefaultBeschreibung
HOSTlocalhostPflicht. Hostname ohne Protokoll. Wird für Docker-Networking und ausgehende Mails verwendet.
SITE_URLhttps://localhostPflicht. Vollständige kanonische URL inklusive Schema und Port. Auth-Callbacks und externe Links nutzen das.
ADDITIONAL_SITE_URLSunsetOptional. Weitere Origins, auf denen dasselbe Deployment antwortet, per Komma oder Leerzeichen getrennt (z. B. https://a.example,https://b.example). Jeder ist ein vollwertiger Eingang. Siehe TLS und Domains.
TOTP_CLIENT_NAMEnicht gesetztKunde, den neu erzeugte Authenticator-Einträge und heruntergeladene Backup-Codes nennen, gelesen von platform, backend-api und der Rolle all: 1–40 Buchstaben, Ziffern, Leerzeichen oder & ' . + -. Leerzeichen am Rand werden entfernt. Mit Acme heißen Einträge Acme Tale Platform; ohne Wert oder mit Tale bleibt es bei Tale Platform. Ein ungültiger Name verhindert den Backend-Start.
TOTP_ENVIRONMENTnicht gesetztUmgebung, die neu erzeugte Authenticator-Einträge und heruntergeladene Backup-Codes nennen, gelesen von platform, backend-api und der Rolle all: 1–32 Buchstaben, Ziffern, Unterstriche oder Bindestriche. Leerzeichen am Rand werden entfernt, Buchstaben großgeschrieben. pr oder ein fehlender Wert fügt keine Umgebung hinzu; mit te wird aus Acme Tale Platform der Eintrag Acme Tale Platform TE, und die Backup-Codes werden als acme-tale-platform-te-backup-codes.txt gespeichert. Ein ungültiger Wert verhindert den Backend-Start.
BASE_PATHunsetOptional. Pfad-Präfix für Subpath-Deployments hinter einem Reverse-Proxy (z. B. /app). Bei Root-Deployment unset lassen.
DOCS_URLhttps://docs.<HOST>Öffentliche Origin des eigenen Dokumentationshosts im Proxy. Der Docs-Dienst muss ebenfalls zur Bereitstellung gehören.

SITE_URL bezeichnet den kanonischen öffentlichen Ursprung. Protokoll, Hostname und Port müssen zur Browseradresse und zu registrierten Callbacks passen. BASE_PATH ergänzt einen Bereitstellungspfad. Einen abschließenden Schrägstrich normalisiert der Proxy. Weitere Adressen gehören als reine Ursprünge in ADDITIONAL_SITE_URLS. Ungültige zusätzliche Ursprünge verhindern den Backend-Start.

Die Dokumentation verwendet eine eigene Origin. Auf der Plattform-Origin öffnet /docs die interaktive API-Referenz; /openapi.json liefert deren Schema. DOCS_URL ändert den Docs-Host des Proxys. Die Variable installiert keinen Docs-Dienst und schreibt keine Links in vorhandenen Client-Bundles um. TALE_DOCS_URL in den SEO-Buildwerkzeugen und das Build- und Laufzeitpfadpräfix DOCS_BASE_URL des Docs-Dienstes sind separate Einstellungen.

Eine Änderung von TOTP_CLIENT_NAME oder TOTP_ENVIRONMENT gilt für neu erzeugte QR-Codes und Einrichtungs-URIs, auch wenn ein bestehender Schlüssel erneut angezeigt wird, und für danach heruntergeladene Backup-Codes. Sie ändert weder den Schlüssel noch den Namen eines bereits auf deinem Gerät gespeicherten Eintrags. Diesen kannst du bei Bedarf in deiner Authenticator-App umbenennen.

TLS

NameDefaultBeschreibung
TLS_MODEselfsignedEiner von selfsigned, letsencrypt, external. Siehe TLS und Domains.
TLS_EMAILunsetKontakt-E-Mail für Let's-Encrypt-Benachrichtigungen. Optional aber empfohlen in Produktion.
TRUSTED_PROXIESprivate_rangesBei TLS_MODE=external die Adressen, deren weitergeleitete Header der Proxy übernimmt: durch Leerzeichen getrennte CIDR-Bereiche oder private_ranges. Die übrigen Modi ignorieren die Variable. Siehe TLS und Domains.

selfsigned erstellt ein lokales Caddy-Zertifikat. Vertraue der zugehörigen CA nur für deine eigene kontrollierte Installation. letsencrypt benötigt eine öffentliche Domain sowie erreichbare Ports 80/443. Bei external bedient Caddy HTTP hinter einem TLS-Proxy.

Sicherheits-Secrets (Pflicht)

NameDefaultBeschreibung
BETTER_AUTH_SECRETBeispielwert in der DateiAuthentifizierungsgeheimnis für alle Backend-Replikate. Erzeuge einen zufälligen Wert, etwa mit openssl rand -base64 32, und halte ihn stabil. Ein Wechsel kann Sitzungen und laufende Anmeldungen ungültig machen.
ENCRYPTION_SECRET_HEXBeispielwert in der DateiVerschlüsselungsschlüssel mit 32 Byte als Hex-Wert; erzeuge ihn mit openssl rand -hex 32. Bewahre den zu vorhandenen Geheimnissen passenden Wert auf. Ein Austausch migriert keine verschlüsselten Daten. Stelle den passenden Schlüssel wieder her oder erfasse betroffene Geheimnisse über ihren vorgesehenen Ablauf neu.
INSTANCE_SECRETBeispielwert in der DateiPflicht. Das Root-Secret der Instanz: 64 Hex-Zeichen, tale init erzeugt es (von Hand: openssl rand -hex 32). Beim Boot leitet Tale daraus den WebDAV-App-Passwort-HMAC-Schlüssel (WEBDAV_APP_PASSWORD_HMAC_KEY) ab, sofern du den nicht selbst setzt; auch die kurzlebigen Tokens, mit denen Sandbox-Sessions Blobs holen, signiert ein Unterschlüssel derselben Ableitung. Halte ihn über Deploys stabil: Eine Rotation leitet den Schlüssel neu ab und macht jedes WebDAV-App-Passwort ungültig.
SANDBOX_TOKENBeispielwert in der DateiPflicht. Gemeinsames HMAC-Secret zwischen Backend und Sandbox-Spawner: Das Backend signiert damit jeden Spawner-Aufruf, der Spawner weist unsignierte ab. Ohne das Secret startet der Spawner nicht — er hält den Docker-Socket des Hosts, es gibt also keinen unsignierten Modus. tale init und bun run dev erzeugen es; ein Stack, den du selbst zusammenstellst, setzt es vor dem ersten Boot (openssl rand -hex 32). Eine Rotation heißt: Backend und Spawner zusammen neu starten — sie müssen übereinstimmen.
SANDBOX_LLM_GATEWAY_ADMIN_PASSWORDnicht gesetztFür Sandbox-Agent-Laufzeit-Aufrufe erforderlich. Das Backend nutzt dieses Verwaltungsgeheimnis, um Sitzungsschlüssel am Gateway bereitzustellen. Gib dem Gateway denselben Wert: Solange es kein Admin-Konto hat, legt es eines nur für einen Aufrufer an, der dieses Geheimnis vorweist — so übernimmt das Backend das Gateway bei der ersten Verwendung. Das Image des Gateways nimmt diesen Wert immer als Setup-Token (BIFROST_SETUP_TOKEN) und ersetzt ein am Container gesetztes. Danach bleibt der Passwort-Hash in llm-gateway-data. Bewahre das passende Geheimnis auf oder nutze die unterstützte Wiederherstellung bzw. Rotation des Gateways. Lösche dessen Zustand nicht als gewöhnlichen Reparaturschritt. Der Benutzername ist standardmäßig admin (SANDBOX_LLM_GATEWAY_ADMIN_USERNAME).

Ersetze die unsicheren Beispielwerte aus .env.example, bevor du die Instanz für andere zugänglich machst.

Datenbank

Tale verwendet tale_app für Anwendungsdaten und tale_knowledge für Textabschnitte, Embeddings und Webseiten. Der Standardaufbau betreibt beide in einem Postgres-Dienst db mit dem Alias knowledge-db. Externe Verbindungen kannst du getrennt konfigurieren.

NameDefaultBeschreibung
DB_PASSWORDtale_password_change_meFür das mitgelieferte Postgres erforderlich. Gemeinsames Passwort der Anwendungs- und Wissensdatenbank im Standardaufbau. Ersetze den Beispielwert vor dem Produktivbetrieb.
DATABASE_URLaus DB_PASSWORD konstruiertOptional. Verbindungs-URL der operativen Datenbank. Setz sie, um das Backend auf einen Postgres zu richten, den du selbst betreibst: er braucht keine Extensions und keinen Superuser, nur eine Datenbank und eine Rolle, die Schemata anlegen darf. Wird bei jedem Start gelesen.
DATABASE_POOL_MAX10Optional. Maximale Verbindungen je Pool der operativen Datenbank. Jede Replik von backend-api oder backend-worker benötigt normalerweise bis zum Doppelten dieses Werts (App-Pool plus Job-Queue). Sandbox-Aktionen können vorübergehend je belegtem App-Pool-Platz eine weitere Verbindung öffnen: In der Spitze ist es das Dreifache je Replik. Rechne diese Spitze gegen max_connections der Datenbank.
AUTH_DATABASE_POOL_MAX5Optional. Verbindungen im Pool, über den jede Replik von backend-api Anmeldesitzungen auflöst; jede authentifizierte Anfrage liest darüber. Erhöhe den Wert für Repliken, die Tausende Anfragen pro Sekunde bedienen, und rechne ihn je Replik neben DATABASE_POOL_MAX gegen max_connections der Datenbank.
POSTGRES_CA_FILEnicht gesetztOptional. Pfad zu einem PEM-Bundle, dem jede Postgres-Verbindung vertraut: operative Datenbank, Wissens-Korpus und die Datenbanken, die Organisationen selbst mitbringen. Nötig, sobald eine URL sslmode=verify-ca oder verify-full gegen einen Anbieter verlangt, dessen Root Node nicht mitliefert — Amazon RDS ist der übliche Fall. Nutzen mehrere Datenbanken verschiedene Anbieter, häng ihre Roots in einer Datei aneinander.
KNOWLEDGE_DATABASE_URLpostgresql://tale:${DB_PASSWORD}@knowledge-db:5432/tale_knowledgeVerbindungs-URL des Standard-Wissenskorpus. Eine andere URL wählt eine andere Datenbank; vorhandene Textabschnitte und Vektoren werden nicht übertragen.
KNOWLEDGE_DB_POOL_MAX10Optional. Verbindungen, die ein Backend-Prozess zum Wissenskorpus öffnet. Jeder Indexierungsjob belegt eine, während er einen Block Textabschnitte festschreibt — erlaubt WORKER_CONCURRENCY mehr gleichzeitige Jobs als das, warten sie auf den Pool; erhöhe beide zusammen. Wie DATABASE_POOL_MAX zählt der Wert je Replik gegen max_connections der Korpus-Datenbank.
KNOWLEDGE_DB_NAMEtale_knowledgeName der Wissensdatenbank, die die mitgelieferte Datenbankinitialisierung erstellt.
KNOWLEDGE_INDEX_REPAIR_INLINE_MAX_BYTES1073741824Optional. Größter BM25-Suchindex (in Bytes), den das Backend beim Start synchron neu aufbaut, wenn es ihn beschädigt vorfindet; einen größeren baut ein Hintergrundjob neu auf, während Schreibzugriffe auf diesen Korpus abgewiesen werden. Siehe Container-Architektur.
KNOWLEDGE_INDEX_REPAIR_DISABLEDnicht gesetzt1 oder true deaktiviert die automatische BM25-Prüfung und Reparatur beim Start. Beschädigungen bleiben bestehen; fehlgeschlagene Abfragen oder Schreibzugriffe brauchen eine Untersuchung und kontrollierte Reparatur.
KNOWLEDGE_CRAWL_DOCUMENT_MAX_BYTES104857600Optional. Größtes Dokument (PDF, DOCX, XLSX, PPTX, ODT — in Bytes), das der Website-Crawler herunterlädt und ausliest; ein größeres vermerkt er an seiner Seite als zu groß. HTML-Seiten haben ein eigenes Budget von 2 MiB. Jeder Abruf liegt während der Textextraktion im Speicher, und bis zu fünf Websites werden gleichzeitig gescannt — bemesse den Speicher des Backends entsprechend. Ein Wert unter 1 MiB oder keine ganze Zahl fällt auf den Standard zurück.

Die erzeugte Verbindungs-URL lautet postgresql://tale:${DB_PASSWORD}@db:5432/tale_app; APP_DB_NAME ändert den Datenbanknamen. Der Wissenskorpus nutzt die Schemata private_knowledge und public_web. Unter Einstellungen > Datenresidenz kann eine Organisation eigene Verbindungen wählen. Eine gespeicherte URL ändert den Speicherort, überträgt aber keine Daten. Siehe Datenresidenz.

Zwei Dinge musst du wissen, bevor du eine der beiden Datenbanken auf eigene Infrastruktur richtest:

  • Der Wissens-Korpus braucht ein installiertes pgvector. Tale legt Schemata und Tabellen auf einer leeren Datenbank selbst an, installiert aber nie Extensions — die Chunk-Tabelle hat eine vector-Spalte, also muss CREATE EXTENSION vector; auf der Zieldatenbank bereits gelaufen sein. ParadeDBs pg_search ist optional: Fehlt es, fällt die Suche auf reine Vektorsuche zurück, statt zu scheitern. Die operative Datenbank braucht gar keine Extensions.
  • Verwende eine direkte oder sitzungskompatible Postgres-Verbindung. Job-Benachrichtigungen, Migrationssperren und vorbereitete Abfragen brauchen Sitzungseigenschaften. Prüfe einen verwalteten Verbindungsproxy anhand dieser Anforderungen.

Object-Store

Dateien und Medien verwenden S3-kompatiblen Speicher. Diese Variablen bestimmen den Bereitstellungsstandard. Eine ausdrücklich gewählte Organisationsverbindung hat Vorrang; ein ausgefallener Standardspeicher bedeutet nicht, dass auch die eigenen Buckets aller Organisationen ausfallen.

NameDefaultBeschreibung
OBJECT_STORE_ACCESS_KEYnicht gesetztZugriffsschlüssel der Standard-S3-Verbindung. Setze bei mitgeliefertem MinIO denselben Wert als MINIO_ROOT_USER. Ohne Zugangsdaten entsteht keine Standardverbindung; eine Organisation kann trotzdem eine eigene gültige Verbindung haben.
OBJECT_STORE_SECRET_KEYvon tale init autogeneriertGeheimschlüssel des Standardspeichers. Bei mitgeliefertem MinIO muss er zu MINIO_ROOT_PASSWORD passen. Rotiere Speicher- und Backend-Zugangsdaten abgestimmt und prüfe Lesen und Schreiben. Ein Passwortwechsel überträgt keine Dateien und macht sie nicht von sich aus verwaist.
OBJECT_STORE_BUCKETtale-blobsBucket, in dem Blobs liegen. Das Backend legt ihn an, wenn er fehlt und der Schlüssel das darf; einen vorhandenen nutzt es, wie er ist.
OBJECT_STORE_ENDPOINThttp://object-store:9000 im mitgelieferten ComposeEndpunkt des Speichers aus Sicht des Backends. AWS S3 verwendet keinen eigenen Endpunkt; entferne oder leere den mitgelieferten Endpunkt ausdrücklich in der wirksamen Compose-Umgebung. MinIO, R2 und andere kompatible Dienste verwenden eine eigene URL.
OBJECT_STORE_REGIONus-east-1Signier-Region. Auf AWS bedeutungstragend; bei einem selbst gehosteten Store beliebig, aber vom Signierer verlangt.
OBJECT_STORE_FORCE_PATH_STYLEtrue mit Endpoint, sonst falseAdressiert den Bucket als endpoint/bucket/key statt bucket.endpoint/key. Der Default folgt dem Endpoint und passt damit für beide Fälle; setz ihn nur für einen Store, der von seiner eigenen Form abweicht.
OBJECT_STORE_PREFIXnicht gesetztSchlüssel-Präfix im Bucket, damit Tales Blobs sich einen Bucket mit anderen Daten teilen können. Leer heißt Bucket-Wurzel.
OBJECT_STORE_PUBLIC_ENDPOINT${SITE_URL} (die CLI setzt ihn)Wo der Browser den Store erreicht. Der Proxy publiziert den gebündelten Store unter /<bucket>/* und leitet presignte URLs unverändert weiter, sodass Up- und Downloads direkt Browser↔Store laufen. Ist dieser Endpunkt einer der Ursprünge des Deployments, wird ein Link für einen Browser auf einem anderen konfigurierten Ursprung für jenen Ursprung signiert. Für einen Bucket, den der Browser ohnehin erreicht, lässt du ihn leer.

Der mitgelieferte Proxy macht die Objektroute im Browser erreichbar, ohne den Verwaltungsport des Speichers zu veröffentlichen. Ein externer Speicher kann über seinen eigenen öffentlichen Endpunkt erreichbar sein.

Wie diese Variablen im laufenden Deployment ankommen

Beim Start gleicht das Backend default/object-storage/connection.json mit seiner Umgebung ab. Erstelle backend-api und backend-worker mit den geänderten Werten neu. Die Startmeldungen unterscheiden diese Ergebnisse:

ZeileBedeutung
object store (seeded)es gab keine Verbindung; eine wurde aus der Umgebung geschrieben
object store (reconciled)die Umgebung hat sich geändert; die Verbindung zieht nach
object store (adopted)eine von einem älteren Release geschriebene Verbindung wurde erkannt und wird jetzt mitgeführt
object store (ignored)die Verbindung trägt "managedBy": "operator", diese Variablen tun also nichts
object store (skipped)Keine Zugangsdaten für einen Bereitstellungsstandard vorhanden. Prüfe, ob eine nutzbare bestehende oder organisationsgebundene Verbindung bleibt.
(nichts)schon im Gleichstand — der Normalfall

Willst du den Store lieber von Hand führen, trag "managedBy": "operator" in connection.json ein; das Backend fasst die Datei dann nie wieder an. Eine Datei ganz ohne managedBy — vor diesem Verhalten geschrieben — übernimmt das Backend nur, wenn sie noch denselben Bucket am selben Endpoint nennt wie die Umgebung; hattest du sie von Hand umgebogen, bleibt deine Änderung stehen.

Bucket-Rechte: Das Backend prüft mit HeadBucket, ob der Bucket existiert, und legt ihn nur an, wenn nicht. Ein Schlüssel, der Objekte lesen, schreiben und löschen darf, aber keine Buckets anlegen, reicht also — solange du den Bucket selbst anlegst. Presignte Up- und Downloads laufen im Browser, ein externer Bucket braucht deshalb zusätzlich eine CORS-Policy, die den Origin deines Deployments mit GET, PUT und HEAD zulässt — siehe Datenresidenz.

Datenschutz im Audit-Log

Ein Pepper pseudonymisiert personenbezogene Daten fehlgeschlagener Anmeldungen. Frühere Releases haben zusätzlich TALE_AUDIT_SIGNING_KEY und TALE_AUDIT_SIGNING_KEY_PREVIOUS erzeugt. Beide liest nichts mehr, einen vorhandenen Wert kannst du also behalten oder löschen.

NameDefaultBeschreibung
TALE_AUDIT_PEPPERvon tale init autogeneriertMindestens 16 Zeichen für die Pseudonymisierung fehlgeschlagener Anmeldungen: HMAC-SHA256 aus E-Mail und gekürzter IP-Adresse. Ohne Wert enthalten diese Audit-Felder Klartext und das Backend warnt. Nach einer Rotation lassen sich neue Kennungen nicht mit früheren vergleichen. Die Aufbewahrung folgt der angewendeten Organisationsrichtlinie.

Siehe Audit-Log-Integrität für das Verifikationsmodell.

Observability

NameDefaultBeschreibung
SENTRY_DSNunsetSentry-DSN für Error-Tracking. Unset zum Deaktivieren. Kompatibel mit selbst gehostetem GlitchTip und Bugsink.
SENTRY_ENVIRONMENTunsetGemeinsame Umgebungsbezeichnung für Fehler aus Browser, Backend und Sandbox. Verwaltete Deployments verwenden standardmäßig ihren bestehenden name; eine explizite Umgebungsreferenz kann eine kanonische Bezeichnung setzen, ohne das Deployment umzubenennen.
SENTRY_TRACES_SAMPLE_RATEunsetOptionale Abtastrate für Leistungstraces im Browser (0.0–1.0), unabhängig von der Backend-Abtastrate.
BACKEND_SENTRY_TRACES_SAMPLE_RATE0Abtastrate für HTTP- und Worker-Spans im Backend (0.0–1.0). Erfordert SENTRY_DSN und ein Ziel, das Sentry-Transaktionen annimmt; 0 deaktiviert Spans.
METRICS_BEARER_TOKENunsetBearer-Token für die Proxy-Routen /metrics/*. Ohne konfigurierten Token antworten sie mit 401. Den Netzwerkzugriff auf interne Prozessendpunkte musst du gesondert beschränken.
UMAMI_URLnicht gesetztHTTPS-Origin des authentifizierten Erfassungs-Gateways. HTTP ist nur für lokale Tests mit localhost, 127.0.0.1 oder [::1] zulässig. Erfordert gültige Website-ID und Proxy-Token; die URL enthält weder Pfad noch Suchparameter oder Zugangsdaten.
UMAMI_WEBSITE_IDnicht gesetztWebsite-UUID von Umami. Fehlt sie oder ist sie ungültig, bleibt die Erfassung aus. Verwende je Deployment eine eigene ID.
UMAMI_PROXY_TOKENnicht gesetztBearer-Token für das Erfassungs-Gateway, ausschließlich auf dem Server: 16–256 ASCII-Buchstaben, Ziffern oder Zeichen aus ._~-. Übergib es niemals an die Browserkonfiguration.

Mit METRICS_BEARER_TOKEN schützt der Proxy die Routen /metrics/platform, /metrics/backend und /metrics/sla-rules. Überwachung einrichten erklärt Inhalt und Grenzen der Messwerte.

Provider-Secrets-Verschlüsselung

SOPS schützt unterstützte Geheimnisdateien der Konfiguration. Aktuelle Anbieterzugangsdaten in der Datenbank verwenden ENCRYPTION_SECRET_HEX aus dem Abschnitt zu Sicherheitsgeheimnissen.

NameStandardBeschreibung
SOPS_AGE_KEYnicht gesetztEin direkt gesetzter privater age-Schlüssel. Hat Vorrang vor der Schlüsseldatei.
SOPS_AGE_KEY_FILEnicht gesetztIm lesenden Prozess erreichbarer Pfad mit einem oder mehreren privaten age-Schlüsseln, je einer pro Zeile. Binde die Datei in jeden benötigten Container ein.

Ohne age-Schlüssel schreibt der SOPS-Helfer unterstützte Geheimnisdateien als Klartext mit Modus 0600. Bereits verschlüsselte Dateien brauchen weiterhin ihren Schlüssel. Lies Geheimnisse mit SOPS, bevor du eine der Variablen änderst.

Anbieterzugangsdaten können stattdessen eine Variable mit Präfix TALE_PROVIDER_KEY_ und höchstens 40 Zeichen referenzieren. Zugangsdaten für Abonnement-Broker verwenden das getrennte Präfix TALE_TOKEN_SOURCE_ mit höchstens 60 Zeichen. Diese Felder speichern Variablennamen, keine Geheimniswerte. Übergib Werte an die Backend-Prozesse und erstelle betroffene Container nach Änderungen neu. Anbieter beschreibt die Einrichtung.

Connector-OAuth-Apps

OAuth-Connectors (Gmail, Google Drive, Outlook, Teams, Slack, …) lösen ihre Vendor-App zuerst pro Organisation auf: Eine unter Einstellungen > Connectors > OAuth-Apps hinterlegte App gewinnt für diese Org. Die Umgebung liefert darunter den deployment-weiten Standard (und ist die einzige Quelle für Slack, dessen Event-Signaturprüfung läuft, bevor eine Org bekannt ist). Pro Connector-Slug:

NameDefaultBeschreibung
CONNECTOR_OAUTH_<SLUG>_CLIENT_IDunsetOAuth-Client-ID für diesen Connector. Slug großgeschrieben, Bindestriche als Unterstriche (gmail → GMAIL).
CONNECTOR_OAUTH_<SLUG>_CLIENT_SECRETunsetPassendes Client-Secret.
CONNECTOR_SLACK_SIGNING_SECRETunsetDas Signing-Secret der Slack-App. Der eingehende Events-Endpunkt prüft jede Zustellung damit und antwortet mit 503, solange es fehlt.

Registriere ${SITE_URL}${BASE_PATH}/api/connectors/oauth2/callback in der Vendor-App, für Slack zusätzlich ${SITE_URL}${BASE_PATH}/api/connectors/slack/events als Events Request URL. Details: Connectors (Develop).

Knowledge-Cloud-Import (Dokumente)

Pro-Benutzer-Autorisierungen für OneDrive / Google Drive unter Wissen → Dokumente sind getrennt von Org-Connectors und vom Login. Auch hier hat eine unter Einstellungen > Connectors > OAuth-Apps hinterlegte Org-App Vorrang — der google-drive-Eintrag wird mit der Connector-Bahn geteilt, OneDrive / SharePoint (Wissens-Import) hat einen eigenen Eintrag; die Ketten unten greifen überall dort, wo die Org keine hinterlegt hat. Registriere diese Redirect-URI in der Microsoft- (oder Google-)App:

${SITE_URL}${BASE_PATH}/api/cloud-import/oauth2/callback

Credential-Auflösung für OneDrive (erster Treffer gewinnt):

NameBeschreibung
CLOUD_IMPORT_MICROSOFT_CLIENT_ID / _SECRETEigene Knowledge-Import-App (bevorzugt).
CLOUD_IMPORT_MICROSOFT_TENANT_IDDirectory-(Tenant-)ID für diese App.
AUTH_MICROSOFT_ENTRA_ID_ID / _SECRETMicrosoft-Login-App.
AUTH_MICROSOFT_ENTRA_ID_TENANT_IDDirectory-(Tenant-)ID für die Login-App.

Single-Tenant-Entra-App-Registrierungen brauchen eine tenant-spezifische Authorize-URL — /common scheitert mit AADSTS50194. Setze die Tenant-ID (oder organizations / common für eine Multi-Tenant-App). Fehlt sie, fällt Tale auf den Entra-SSO-Issuer-Tenant der Organisation zurück, falls konfiguriert.

Der Microsoft-Freigabe-Dialog fordert Graph Files.Read und Sites.Read.All (OneDrive und SharePoint listen/laden), User.Read (Konto-Label) und offline_access (Refresh-Token für Sync). Die Freigabe ist absichtlich und pro Benutzer — sie kommt nicht mit der Tale-Anmeldung.

Google Drive nutzt nur eine eigene App (kein Login-App-Fallback):

NameBeschreibung
CLOUD_IMPORT_GOOGLE_DRIVE_CLIENT_ID / _SECRETKnowledge-Google-Drive-Import-App.

Registriere dieselbe Cloud-Import-Callback-URI am Google-OAuth-Client. Die Freigabe fordert drive.readonly und userinfo.email.

Feature-Flags

Diese Variablen steuern Backend-Anmeldung, Datei-Ereignisse und Betreiberrechte. Erstelle die betroffenen Backend-Rollen nach einer Umgebungsänderung neu. Nur den Webcontainer zu ändern reicht nicht aus.

NameDefaultBeschreibung
TRUSTED_SECRET_HEADERRemote-Internal-SecretName des Request-Headers, der den Trusted-Header-Schlüssel der Organisation auf der Übergabeanfrage trägt.
TRUSTED_EMAIL_HEADERRemote-EmailName des Request-Headers mit der E-Mail-Adresse des Benutzers — die Identität, für die die Session ausgestellt wird.
TRUSTED_NAME_HEADERRemote-NameName des Request-Headers mit dem Anzeigenamen. Fehlt er, nimmt Tale den lokalen Teil der E-Mail-Adresse.
TRUSTED_ROLE_HEADERRemote-RoleName des Request-Headers mit der Organisationsrolle, mit der die Session handelt, begrenzt auf die Obergrenze der Organisation (member, wenn der Header fehlt).
TRUSTED_TEAMS_HEADERRemote-TeamsName des Request-Headers mit den Team-Zugehörigkeiten als kommagetrennte Teamnamen (id:name-Einträge werden ebenfalls akzeptiert). Fehlt er, bleiben Teams unangetastet; ist er gesetzt, gilt die Liste des Proxys für die von ihm vergebenen Zugehörigkeiten (leer entzieht sie).
TALE_FILE_EVENTSfalseStreamt Änderungen an Config-Dateien unter TALE_CONFIG_DIR an offene Browser-Tabs (/events/file): Eine auf der Platte bearbeitete Agent-, Skill- oder Branding-Datei erscheint ohne Reload. Im Dev-Compose an, in Produktion aus.
TALE_DEPLOYMENT_CONFIG_ADMINSunsetKommagetrennte E-Mail-Allowlist der Operatoren, die die Deployment-Konfigurationsdatei (deployment.yml, heute der Abschnitt zur Sandbox-Runtime) über die API schreiben dürfen. Leer/nicht gesetzt = nur lesend für alle Admins. Die Datenresidenz wird pro Organisation konfiguriert und hängt nicht an dieser Liste.
TALE_ALLOW_PRIVATE_PROVIDER_HOSTSnicht gesetztMit 1 in der Backend-Umgebung private Modellanbieter zulassen, einschließlich ihrer Sandbox-Gateway-Konfiguration. Cloud-Metadatenziele bleiben gesperrt. Siehe Anbieter.
TALE_ALLOW_PRIVATE_CRAWL_HOSTSnicht gesetztMit 1 Intranet-Crawl-Ziele und private Hosts in der imageUrl eines Produkts zulassen. Cloud-Metadatenziele bleiben gesperrt.
TALE_ALLOW_OPEN_SIGN_UPnicht gesetztGenau true hält POST /api/auth/sign-up/email auch nach dem ersten Konto der Installation offen. Nur für Wegwerf-Teststacks — der lokale Dev-Orchestrator und das Dev-Compose-Overlay setzen es selbst. Eine echte Installation lässt es ungesetzt, damit jedes weitere Konto von einer Administratorin oder einem Administrator angelegt wird.
TALE_ORGANIZATION_CREATORSnicht gesetztKommagetrennte E-Mail-Allowlist der Konten, die eine Organisation erstellen dürfen, verglichen ohne Rücksicht auf Groß- und Kleinschreibung. Ungesetzt darf das jede angemeldete Person. Gesetzt wird jede andere Person mit 403 ORGANIZATION_CREATION_FORBIDDEN abgewiesen, sobald die Installation eine Organisation hat — die erste ist immer erlaubt — und die App blendet Organisation erstellen für sie aus. Ein gesetzter, aber leerer Wert schließt die Erstellung für alle. Ein verwaltetes Deployment schreibt die Variable aus organizations.creators seiner Spezifikation; siehe Die tale-CLI installieren.

Die Freigabe privater Crawl-Ziele betrifft zwei Grenzen: Website-Registrierung und Crawler-Anfragen sowie die Validierung der imageUrl eines Produkts. Ohne Freigabe erhält ein privates Website-Ziel 400 WEBSITE_DOMAIN_NOT_CRAWLABLE; eine private Produktbild-URL erhält 400 INVALID_BODY. Bei Produktbildern wird nur die Hostzeichenfolge geprüft, ohne Bildabruf oder DNS-Auflösung. Website-Registrierung und Crawler prüfen zusätzlich die aufgelösten Adressen. Aktiviere die Variable nur, wenn die Installation diese privaten Ziele braucht. Sie ist unabhängig von der Freigabe privater Modellanbieter.

Deployment-Topologie

Diese Werte prägen die Anwendungsrollen eines Workspace-Deployments: die Replikatzahlen, die tale deploy aus der Projektumgebung liest und mit einer Warnung auf den unterstützten Bereich begrenzt, und wie viel Arbeit ein einzelnes Worker-Replikat gleichzeitig übernimmt.

NameDefaultBeschreibung
TALE_PLATFORM_REPLICAS1Replicas des Web-Tiers, der die App-Shell ausliefert. Bereich 1–16.
TALE_BACKEND_API_REPLICAS1Replicas der API — jede Anwendungstür, Auth und der Hint-Stream. Bereich 1–16.
TALE_BACKEND_WORKER_REPLICAS1Replicas des Job-Runners: Ingest, Crawls, Automations, Agent-Turns. Bereich 1–16.
UV_THREADPOOL_SIZE4Optional. Threads des Node.js-Prozesses, die sich Dateizugriffe, DNS-Abfragen und das Hashen von Passwörtern teilen; Node liest den Wert beim Start. Ein backend-api-Replikat prüft Passwörter auf höchstens der Hälfte davon gleichzeitig (standardmäßig 2) und antwortet mit 503, dem Code PASSWORD_CHECK_BUSY und einem Retry-After, sobald etwa 16 Prüfungen je Platz warten oder eine vier Sekunden gewartet hat. So bremst eine Anmeldewelle nur sich selbst und reiht sich nicht vor jede andere Anfrage. Erhöhe den Wert (etwa auf 8) auf einem Replikat mit freien CPU-Kernen, das viele Anmeldungen gleichzeitig bedient; eine laufende Prüfung braucht etwa 32 MiB. Die Metriken tale_backend_password_checks_waiting und tale_backend_password_checks_refused_total zeigen eine solche Welle, während sie läuft.
WORKER_CONCURRENCY5Jobs, die ein backend-worker-Replikat je Job-Warteschlange gleichzeitig ausführt — Ingest, Crawls, Automations und Agent-Turns erhalten jeweils so viele. Agent-Turn-Starts erhalten mindestens 8 und die Abarbeitungsfenster laufender Agent-Turns mindestens 16 je Warteschlange, da jedes vor allem auf seine Sandbox wartet (AGENT_START_SLOTS, AGENT_DRIVE_SLOTS). Chat-Antworten für API-Schlüssel erhalten mindestens 16, da jede vor allem auf das Modell wartet. Der Worker-Prozess liest sie selbst; Bereich 1–64. Stell zuerst diesen Wert höher, bevor du Worker-Replikate hinzufügst, wenn ein Rückstand wächst. Jeder laufende Indexierungsjob schreibt über den Wissens-Pool, also erhöhe KNOWLEDGE_DB_POOL_MAX mit.
AGENT_START_SLOTSWORKER_CONCURRENCY, mindestens 8Agent-Turn-Starts, die ein backend-worker-Replikat gleichzeitig ausführt, jeweils für Aufgabenläufe und für Automations-Schritte. Ein Start belegt seinen Platz während der Sandbox-Erstellung und des ersten 90-Sekunden-Fensters des Turns. Bereich 1–256.
AGENT_DRIVE_SLOTSWORKER_CONCURRENCY, mindestens 16Abarbeitungsfenster laufender Agent-Turns, die ein backend-worker-Replikat je Bereich gleichzeitig ausführt. Ein Replikat hält etwa das 2,5-Fache an laufenden Turns je Bereich abgearbeitet; darüber warten Fenster so lange, dass die Wiederherstellung eingreift. Erhöhe den Wert (oder füge Replikate hinzu) für mehr gleichzeitige Turns. Bereich 1–256.
AUTOMATION_ORG_CONCURRENCY8Automations-Schritte einer Organisation, die über alle backend-worker-Replikate hinweg gleichzeitig laufen. So belegt eine Organisation mit vielen Läufen auf einmal nicht alle Plätze der Worker, während die Läufe anderer Organisationen warten. 0 hebt die Grenze auf. Replikate, die im selben Moment Arbeit abholen, können je einen Schritt starten, daher laufen bei einem Ansturm kurz ein oder zwei mehr. Ein einzelnes Replikat mit dem Default von WORKER_CONCURRENCY erreicht sie nie. Bedient dein Deployment nur eine Organisation und bietet es mehr Plätze für Schritte, als dieser Wert zulässt, erhöhe ihn oder setze 0. Bereich 0–256.
AUTOMATION_RUNNER_PROCESSES2 bei backend-api; bei backend-worker einer pro CPU-Kern minus einer, höchstens 4In wie vielen Prozessen ein backend-Replikat Automations-Code auswertet: Templates, die der Runner liest, und Transform-Code. Ein Replikat startet einen und fügt nur dann einen weiteren hinzu, wenn alle vorhandenen beschäftigt sind; ein Prozess über den ersten hinaus endet nach fünf Minuten ohne Arbeit. Jeder belegt im Betrieb etwa 75 MB. Senke den Wert auf einem Replikat mit wenig Speicher; erhöhe ihn auf einem Worker, dessen Automatisierungen viel Transform-Code ausführen. Bereich 1–16.
SHUTDOWN_DRAIN_MS15000 bei backend-api, 90000 bei backend-workerWie lange ein backend-Replikat beim Anhalten in Millisekunden auf seine Jobs wartet, bevor es sich beendet. Ein Worker gibt dabei zuerst seine Automations-Läufe an einen anderen weiter: Jeder Lauf geht beim nächsten Schritt weiter, und ein Schritt, der nach 20 Sekunden noch arbeitet, wird unterbrochen und läuft auf dem nächsten Replikat noch einmal, außer er hat gerade etwas an einen externen Dienst gesendet — dann wartet der Lauf, bis eine Person entscheidet. Eine Chat-Antwort, die beim Ende dieser Frist noch streamt — eine App-Antwort in einem anhaltenden backend-api, eine Antwort für einen API-Schlüssel in einem anhaltenden backend-worker —, schlägt sofort als durch einen Neustart unterbrochen fehl, sodass die Person erneut senden kann, statt einen Ladekreis zu sehen, bis die Bereinigung der Generierungen ihn zehn Minuten später beendet. Setze stop_grace_period des Containers mindestens 15 Sekunden höher als diesen Wert; die mitgelieferten Compose-Dateien geben backend-api 30 Sekunden und backend-worker 120, und tale deploy hebt beide auf 15 Sekunden über einen höheren Wert an. Bereich 1000–600000.
TALE_BACKEND_URLhttp://backend-api:3005Wo der Web-Tier das Anwendungs-Backend erreicht: Die öffentliche /status-Seite prüft es darüber, und der Webserver holt sich dort die Antworten, die nur eine Datenbank geben kann. Das mitgelieferte Compose und der Container-Entrypoint setzen den In-Compose-Alias als Default; setze die Variable nur, wenn dein Backend-Service anders heißt. Liest nur der platform-Service.

Bei einem Workspace-Deployment laufen vorübergehend beide Farben. Plane Kapazität für diese Überschneidung. Erhöhe die Rolle, deren gemessene Last den Engpass bildet. Mehr Replikate brauchen auch mehr Datenbankverbindungen und Arbeitsspeicher. Siehe Upgrades.

Sitzungen

NameDefaultBeschreibung
SESSION_IDLE_TIMEOUT_MINUTESunsetOptional. Meldet eine Sitzung nach so vielen Minuten Inaktivität ab (1–1440). Das Fenster verschiebt sich bei Aktivität und wird serverseitig durchgesetzt — über E-Mail-/Passwort-, SSO- und Trusted-Headers-Sitzungen.
SESSION_COOKIE_CACHE_SECONDSunsetOptional. Eine Anfrage darf ihre aufgelöste Sitzung bis zu so viele Sekunden (1–300) aus einem signierten Cookie übernehmen, statt die Datenbank zu lesen. Auf einer stark genutzten Instanz spart das die meisten Lesezugriffe der Authentifizierung. Der Preis: Änderungen an der Sitzung oder am Konto erreichen gewöhnliche Anfragen erst, wenn die zwischengespeicherte Kopie abläuft (etwa eine Abmeldung auf einem anderen Gerät oder die Sitzungen, die enden, wenn sich ein Passwort ändert oder ein Admin den Passkey eines Mitglieds widerruft oder dessen Zwei-Faktor-Authentifizierung zurücksetzt). Mitgliedschaften in Organisationen richten sich nach AUTH_REQUEST_CACHE, und offene Live-Update-Streams prüfen die Sitzung innerhalb von 15 Sekunden. Ist SESSION_IDLE_TIMEOUT_MINUTES gesetzt, bleibt der Cache auf ein Viertel dieses Fensters begrenzt; der Widerruf wegen Inaktivität berücksichtigt den Cache, sodass das Inaktivitätslimit einer Organisation bis zu so viele Sekunden später greifen kann.
AUTH_REQUEST_CACHEanOptional. Jeder API-Prozess behält die Sitzungen und Organisationsmitgliedschaften, die er aufgelöst hat, sodass gewöhnliche Anfragen diese Lesezugriffe auf die Datenbank auslassen. Eine Änderung — eine Abmeldung auf einem anderen Gerät, ein neues Passwort, ein widerrufener Passkey, eine geänderte Rolle oder ein entferntes Mitglied — erreicht jeden Prozess innerhalb von etwa einer Sekunde: Die Datenbank hält jede Änderung fest, und jeder Prozess liest diese Einträge fünfmal pro Sekunde. Ein Prozess, der sie nicht lesen kann, antwortet aus der Datenbank, bis er es wieder kann. Die gleitende Verlängerung einer Sitzung geschieht weiterhin einmal pro Minute. Mit off liest jede Anfrage die Datenbank. Ist SESSION_COOKIE_CACHE_SECONDS gesetzt, kommen Sitzungen stattdessen aus diesem signierten Cookie, und dieser Cache behält nur Mitgliedschaften. Betreibst du mehr als ein paar API-Replikas, leite die Anfragen einer Person immer an dieselbe Replika (Sticky Sessions über das Sitzungs-Cookie): Jede Replika hat ihren eigenen Cache.

Ohne Wert gilt die normale Sitzungsdauer. Mit gesetztem Limit läuft eine inaktive Sitzung serverseitig ab; Aktivität verschiebt das Fenster. Organisationsadmins können es über die Richtlinie zur Sitzungsinaktivität weiter verkürzen. Die zugehörige Bereinigung läuft ungefähr alle fünf Minuten.

NameDefaultBeschreibung
TALE_CONTACT_SUPPORT_URLhttps://tale.dev/contactOptional, gelesen vom Dienst platform. Ziel des Links kontaktiere den Support auf den Fehlerseiten der App. Eine absolute http://- oder https://-URL.

Trag hier deinen eigenen Helpdesk ein, damit Personen nach einem Fehler das Team erreichen, das dein Deployment betreibt. Kennt die Fehlerseite die Organisation, hängt der Link organizationId=<id> an den Query-String an, hinter eine bereits vorhandene Query, und ersetzt einen organizationId-Parameter, den die URL schon trägt. Jeder andere Wert, etwa mailto: oder eine URL ohne Schema, wird mit einer Warnung im Log des Dienstes platform ignoriert, und der Link behält den Standardwert.

MCP-Endpunkt

NameDefaultBeschreibung
TALE_MCP_ALLOWED_ORIGINSnicht gesetztOptional, gelesen von backend-api und der Rolle all. Browser-Origins, von denen der MCP-Endpunkt neben SITE_URL und ADDITIONAL_SITE_URLS eine Anfrage mit Origin-Kopfzeile annimmt. Durch Kommas oder Leerzeichen getrennt, jeweils scheme://host[:port] ohne Pfad, etwa der eigene Origin eines Desktop-Editors wie vscode-file://vscode-app. Ein fehlerhafter Eintrag verhindert den Backend-Start.
TALE_MCP_ORIGIN_ENFORCEfalseOptional, gelesen von backend-api und der Rolle all. Mit true lehnt der Endpunkt eine Anfrage von jedem anderen Origin mit 403 und ORIGIN_FORBIDDEN ab; mit false protokolliert er sie nur.
TALE_MCP_CLIENT_METADATA_DOCUMENTStrueOptional, gelesen von backend-api und der Rolle all. Ob sich ein Coding-Agent am MCP-Endpunkt anmelden darf, indem er ein Client-Metadatendokument angibt, das er auf seinem eigenen HTTPS-Host veröffentlicht, wie es Claude Code und Codex tun. Das Backend ruft dieses Dokument ab und braucht dafür ausgehendes HTTPS zum Host des Agenten. Mit false ist dieser Weg abgeschaltet. Siehe Coding-Agents anmelden lassen.
TALE_MCP_CLIENT_METADATA_HOSTSnicht gesetztOptional, gelesen von backend-api und der Rolle all. Die einzigen Hosts, von denen ein solches Dokument kommen darf, als durch Kommas oder Leerzeichen getrennte Hostnamen wie claude.ai. Nicht gesetzt: jeder öffentliche HTTPS-Host. Ein fehlerhafter Eintrag verhindert den Backend-Start.
TALE_MCP_DYNAMIC_CLIENT_REGISTRATIONtrueOptional, gelesen von backend-api und der Rolle all. Ob sich ein Coding-Agent selbst beim Anmeldeserver von Tale registrieren darf, wie es Cursor, VS Code und Gemini CLI tun. Die Registrierung ist ratenbegrenzt, und eine App, die sich selbst registriert hat, gilt auf der Seite, auf der die Person den Zugriff erlaubt, als nicht bestätigt. Mit false ist dieser Weg abgeschaltet; sind sowohl diese Variable als auch TALE_MCP_CLIENT_METADATA_DOCUMENTS auf false gesetzt, können sich Agenten nicht anmelden. Siehe Coding-Agents anmelden lassen.
TALE_MCP_DCR_WEB_REDIRECT_HOSTSclaude.ai,claude.com,chatgpt.com,vscode.dev,insiders.vscode.devOptional, gelesen von backend-api und der Rolle all. Die Web-Hosts, zu denen ein selbst registrierter Agent die Person nach der Anmeldung zurückschicken darf, als durch Kommas oder Leerzeichen getrennte Hostnamen. Jeder andere Agent muss über den eigenen Computer der Person (localhost, 127.0.0.1 oder [::1]) oder über eine App zurückkehren. Ein fehlerhafter Eintrag verhindert den Backend-Start.

Coding-Agents im Terminal und serverseitige Clients senden keinen Origin, für sie greift die Prüfung nie. Eine Browserseite einer anderen Website sendet einen, und über einen API-Schlüssel in einer solchen Seite würde diese Website den Endpunkt erreichen. Solange die Durchsetzung aus ist, protokolliert der Endpunkt jede Anfrage von einem Origin außerhalb der Liste als [mcp] origin-mismatch mit dem Origin, der Organisation und der Person. Lies diese Zeilen, um zu sehen, welche deiner Clients einen Origin senden, bevor du TALE_MCP_ORIGIN_ENFORCE=true setzt, und trag ihre Origins in TALE_MCP_ALLOWED_ORIGINS ein.

Die vier Einstellungen am Ende der Tabelle gehören zur Anmeldung von Coding-Agents, mit der sich ein Agent ohne API-Schlüssel mit dem MCP-Endpunkt verbindet. Solange sie nicht vollständig ist, verbinden sich Agents mit einem API-Schlüssel, und beide Wege bleiben ausgeschaltet. Um ein Client-Metadatendokument zu lesen, braucht das Backend ausgehendes HTTPS zum Host des Agents. Es ruft nie ein Dokument von einer privaten Adresse oder vom eigenen Deployment ab und folgt nie einer Weiterleitung. Die Selbstregistrierung nimmt nur die Scopes für Coding-Agents an und ist pro Quelladresse und pro Deployment begrenzt.

Sandbox-Infrastruktur

Der Sandbox-Spawner liest die folgenden Einstellungen. Übergib sie seiner Umgebung und erstelle den Dienst nach einer Änderung neu. SANDBOX_MAX_SESSIONS legt die gemeinsame Kapazität aller Organisationen fest. Die drei Arbeitslimits einer Organisation ergeben automatisch ihre Gesamtsumme; liegt sie über dieser Kapazität, kannst du die Limits nicht speichern. Unter Sandboxes verwaltest du die Limits und siehst tatsächliche Laufzeitzahlen und Host-Messwerte getrennt von der Kontingentbelegung.

NameDefaultBeschreibung
SANDBOX_MAX_SESSIONSauf einem lokalen Docker-Host nach Host-Speicher und CPUs bemessen (mindestens 8, höchstens 256); sonst 8Höchstzahl laufender und startender Sessions aller Organisationen auf dem Docker-Host oder im Kubernetes-Namespace, einschließlich weiterlaufender Container im Leerlauf. Die Kapazität reserviert weder CPU noch Arbeitsspeicher. Fehlt die Variable auf einem Docker-Host, dessen Speicher der Spawner lesen kann, bemisst er sie nach diesem Speicher: eine Session je 768 MiB, die nach SANDBOX_MIN_FREE_MEMORY übrig bleiben, oder je 1,5 GiB, wenn Agent-Sessions Docker in der Sandbox betreiben, und höchstens zwei Sessions je CPU, die der Docker-Daemon meldet. Lässt sich der Speicher beim Start nicht lesen, bleibt die Kapazität bei 8, bis er lesbar ist. Ein expliziter Wert legt sie fest und schaltet die adaptive Speicherprüfung beim Start einer Session ab. Du musst dann selbst genug Speicher für andere Aufgaben auf dem Host frei halten. Die Datenträgerprüfung und die CPU-Druck-Prüfung (SANDBOX_CPU_PRESSURE_PERCENT) bleiben aktiv. Gleichzeitige Kubernetes-Replikate setzen sie nach bestem Bemühen durch; harte Ressourcengrenzen im Namespace setzt du mit ResourceQuota.
SANDBOX_MIN_FREE_MEMORYein Zehntel des Host-Speichers, mindestens 1gBei nicht gesetztem SANDBOX_MAX_SESSIONS: Speicher, den eine neue Session oder eine freigegebene, noch laufende Session bei der Wiederaufnahme auf einem lokalen Docker-Host frei lassen muss, neben dem, was noch startende und eben gestartete Sessions gleich belegen werden. Würde ein Start weniger übrig lassen, stoppt der Spawner zuerst eine freigegebene Session im Leerlauf; reicht der Speicher dann immer noch nicht, antwortet er mit „beschäftigt“, und die Arbeit wartet, bis laufende Sessions Speicher freigeben. Akzeptiert Größen wie 2g oder 1536m. Die Reserve muss unter dem gesamten Host-Speicher liegen. Kann der Spawner diesen beim Start lesen, verhindert eine unmögliche Reserve den Start mit einem Konfigurationsfehler. 0 entfernt die Reserve, nicht die Prüfung des Speicherbedarfs je Session. Wirkt nicht bei explizitem SANDBOX_MAX_SESSIONS, unter Kubernetes oder mit einem entfernten Docker-Daemon.
SANDBOX_CPU_PRESSURE_PERCENT60CPU-Druck auf einem lokalen Docker-Host in Prozent, ab dem neue Sessions und freigegebene Sessions, die wieder Arbeit aufnehmen, nur noch einzeln starten: der Anteil der letzten zehn Sekunden, in dem ein Prozess auf eine CPU gewartet hat, wie ihn die Pressure Stall Information des Kernels meldet (some avg10 in /proc/pressure/cpu). Darüber lässt der Spawner alle zehn Sekunden einen Start zu, in der Reihenfolge der Anfragen; die übrigen warten mit der Antwort „beschäftigt“. Laufende Arbeit wird nicht gebremst. 0 schaltet die Prüfung ab. Ein Kernel ohne Pressure Stall Information (ohne sie gebaut oder mit psi=0 gestartet) lässt die CPU bei der Zulassung außen vor; der Spawner protokolliert das einmal. Wirkt nicht unter Kubernetes oder mit einem entfernten Docker-Daemon.
SANDBOX_MIN_FREE_DISKein Zwanzigstel jedes Datenträgers, mindestens 2g, höchstens 20gFreier Speicher für neue und reaktivierte Sitzungen im Dateisystem der Arbeitsbereiche und im verifizierten Docker-Daten-Dateisystem. Unterhalb der Grenze wartet die Arbeit; gestoppte, ungenutzte Build-Caches werden zuerst entfernt. Akzeptiert 10g oder 4096m; 0 deaktiviert die Prüfung. Kubernetes stützt sich auf Storage-Klasse und Volume-Bereitstellung.
SANDBOX_CRITICAL_FREE_DISKein Viertel der Grenze aus SANDBOX_MIN_FREE_DISK, mindestens 1g und nie darüberFreier Speicher, unterhalb dessen der Datenträger der Sessions kritisch ist: Was laufende Sessions dort schreiben, schlägt bald fehl. Darunter werden freigegebene Sessions mit Docker in der Sandbox im Leerlauf sofort gestoppt, was ihre inneren Image-Speicher entfernt, und der Spawner protokolliert höchstens alle zehn Minuten die drei größten Arbeitsbereiche. Akzeptiert 2g oder 2048m; ein Wert über der Grenze zählt als die Grenze; 0 deaktiviert die Stufe, ebenso eine Grenze von 0. Nur mit dem Docker-Backend.
SANDBOX_DOCKER_WORKLOADSproject,workflowWorkloads, die Docker in ihrer Sandbox nutzen dürfen, wenn es für das Deployment aktiviert ist. Mit project starten Workflow-Agenten ohne Docker, mit workflow gilt das für Projektagenten und mit none für beide. Die Einstellung gilt für neu erstellte Sessions; bestehende behalten ihre Fähigkeiten. Eine Session-Anfrage kann Docker mit docker: false abwählen, aber weder diese Liste noch die Deployment-Einstellung erweitern.
SANDBOX_AGENT_CPUS2CPU-Grenze je Agent-Session. Berücksichtige bei der Session-Anzahl gleichzeitig laufende Builds und andere Aufgaben auf dem Host.
SANDBOX_AGENT_CPU_SHARES256CPU-Gewichtung einer Agent-Session und der Build-Cache-Hilfscontainer ihrer Organisation, solange die CPUs des Hosts ausgelastet sind, gegenüber Dockers Standardwert 1024, den die eigenen Dienste der Plattform behalten; Sessions mit dem Profil default (Codeausführungen, Seiten-Renderings) nutzen 128. Ausgelastete Sessions überlassen die CPU dann der Datenbank und dem Backend, statt sie auszubremsen; auf einem Host mit freier CPU nutzt eine Session weiterhin bis zu SANDBOX_AGENT_CPUS. Eine ganze Zahl von 2 bis 262144. Gilt für neu erstellte Sessions; ein laufender Hilfscontainer übernimmt einen neuen Wert sofort.
SANDBOX_AGENT_MEMORY4g; 8g mit Docker in der SandboxSpeichergrenze je Agent-Session, die auch für ihren inneren Docker-Daemon und dessen Container gilt. Ein expliziter Wert ersetzt beide Standardwerte und gilt für neu erstellte Sessions.
SANDBOX_AGENT_PROFILEagentWird von Backend-API und Worker gelesen. Profil für neue Agenten- und Workflow-Arbeitsbereiche: agent unterstützt inneres Docker; agent-light behält Coding-Werkzeuge und den persistenten Arbeitsbereich, ohne Docker oder Build-Cache-Helfer zu starten. Bestehende Arbeitsbereiche behalten ihr gespeichertes Profil.
TALE_SANDBOX_CLAUDE_EFFORTnicht gesetzt (übernimmt den Agent-Laufzeit-Standard)Wird von Backend-API und Worker gelesen. Denktiefe von Claude Code: low, medium, high oder max. Niedrigere Werte lassen die automatische Ultrathink-Anweisung weg und setzen den Wert pro Ausführung; adaptives Denken bleibt aktiv. Andere Agent-Laufzeiten und fremde Modelle bleiben unverändert. Vergleiche repräsentative Aufgaben, bevor du den Wert senkst; kürzere Läufe sind nicht garantiert.
SANDBOX_SESSION_CREATE_TIMEOUT_MS180000Gesamtbudget für den Sitzungsstart, einschließlich optionalem Build-Cache, Container- oder Pod-Start, Daemon-Bereitschaft und Umgebungsübergabe. Ein abgebrochener Request bricht seine Sitzungsstartarbeiten ab; die Bereinigung stoppt Compute und erhält den Arbeitsbereich. Die gemeinsame Cache-Vorbereitung hat eine eigene begrenzte Laufzeit.
SANDBOX_DOCKER_DATA_ROOTnicht gesetztOptionaler Host-Pfad, der Dockers DockerRootDir entspricht. Die CLI bindet ihn schreibgeschützt in den Sandbox-Dienst ein. Bei direktem Compose ist der unten gezeigte Mount erforderlich.
SANDBOX_DOCKER_DATA_PATH/var/lib/tale-sandbox/docker-data, wenn der Root-Pfad gesetzt istPfad dieses schreibgeschützten Mounts im Spawner. Die Zulassung prüft dieses Dateisystem zusätzlich zum Arbeitsbereich. Ein konfigurierter Mount, der nicht verifiziert oder gelesen werden kann, blockiert die Zulassung.
SANDBOX_BUILDKITD_CPUSSANDBOX_AGENT_CPUSCPU-Grenze des Build-Cache-Hilfscontainers einer Organisation, der die Image-Builds all ihrer Agent-Sessions ausführt, wenn Docker in der Sandbox läuft. Laufende Hilfscontainer übernehmen einen neuen Wert sofort. Die Anzahl paralleler BuildKit-Solver-Schritte entspricht diesem abgerundeten CPU-Limit, mindestens jedoch eins; diese Grenze gilt nach dem Neuerstellen eines inaktiven Hilfscontainers.
SANDBOX_BUILDKITD_MEMORYdas Doppelte von SANDBOX_AGENT_MEMORYSpeichergrenze des Build-Cache-Hilfscontainers einer Organisation, die sich die gleichzeitigen Builds ihrer Agent-Sessions teilen. Akzeptiert Größen wie 16g oder 12288m. Ein laufender Hilfscontainer übernimmt einen neuen Wert, wenn er neu erstellt wird, sobald kein Build läuft.
SANDBOX_BUILDKITD_IDLE_CACHE5gBuild-Cache, den der Build-Cache-Hilfscontainer einer Organisation behält, wenn er mangels Agent-Sessions stoppt. Unmittelbar vor diesem Stopp kürzt der Spawner den Cache auf diese Größe, die am längsten ungenutzten Einträge zuerst: Die eigene Speicherbereinigung des Caches läuft nur, solange der Hilfscontainer läuft. Akzeptiert Größen wie 5g oder 2048m; 0 behält nichts.
SANDBOX_BUILDKITD_MAX_CACHEein Zehntel des Session-Datenträgers, mindestens 1g, höchstens 20gGrößter Build-Cache, den der Build-Cache-Hilfscontainer einer Organisation behält; darüber werden die am längsten ungenutzten Einträge zuerst entfernt. Ohne Wert richtet sich die Grenze nach der Größe des Datenträgers, auf dem die Arbeitsbereiche der Sessions liegen, damit viele bauende Organisationen zusammen nicht mehr als einen Anteil davon belegen. Die Untergrenze, unter die knapper Speicherplatz den Cache nie kürzt, beträgt ein Zehntel dieser Grenze, höchstens 2 GiB. Akzeptiert Größen wie 8g oder 40960m, mindestens 1g. Ein laufender Hilfscontainer übernimmt einen neuen Wert, wenn er neu erstellt wird, sobald kein Build läuft.
SANDBOX_BUILDKITD_PROVISION_TIMEOUT_MS5000Gesamtes Zeitbudget in Millisekunden für den optionalen gemeinsamen Build-Cache beim Erstellen einer Sitzung, einschließlich wartender Docker-Aufrufe und Registry-Spiegel. Bereich 100–60000. Läuft das gemeinsame Zeitbudget ab, werden wartende Hilfscontainer-Aufrufe abgebrochen und später nicht mehr gestartet; die Session nutzt ihren lokalen Builder.
SANDBOX_BUILDKITD_CACHE_RETENTION14dWie lange die gestoppten Build-Cache-Hilfscontainer einer Organisation ihre Caches behalten. Ist der Builder länger gestoppt und kann keine Session der Organisation ihn nutzen, entfernt der Spawner ihre Hilfscontainer, ihr Netzwerk und ihre Cache-Volumes, wie beim Löschen einer Organisation; ihr nächster Build startet ohne Cache. Akzeptiert ganze Tage oder Stunden wie 14d oder 336h; off (oder 0) behält die Caches, bis die Organisation gelöscht wird.
SANDBOX_BUILDKITD_IDLE_MS600000 (10 Min.)Wie lange die Build-Cache-Hilfscontainer einer Organisation weiterlaufen, sobald keine Agent-Session der Organisation, die Images baut, sie mehr nutzen kann. Danach stoppen sie; Netzwerk und Cache-Volume des Builders bleiben erhalten, die Registry-Mirrors werden mit ihren Caches entfernt. Der nächste Build startet sie wieder: Ein Hilfscontainer mit aktuellem Image und aktuellen Einstellungen wird als gestoppter Container neu gestartet, jeder andere neu erstellt. Mindestens 60000.
SANDBOX_PACKAGE_CACHE_RETENTION14dWie lange die Paket-Caches einer Organisation nach ihrer letzten Nutzung bestehen bleiben: die Download-Caches von pip, uv, npm und bun, die ihre Sandboxes auf Docker teilen (Sandboxes mit Docker im Inneren und leichte Sandboxes nutzen sie nicht). Hat keine Sandbox der Organisation sie so lange genutzt, entfernt der Spawner sie bei seiner nächsten stündlichen Prüfung; die nächste Sandbox der Organisation startet mit leeren Caches, und Installationen dauern länger, bis sie wieder gefüllt sind. Caches, die es schon vor dieser Einstellung gab, zählen ab der ersten Prüfung nach dem Update. Akzeptiert ganze Tage oder Stunden wie 14d oder 336h; off (oder 0) behält die Caches, bis die Organisation gelöscht wird.
SANDBOX_SESSION_MAX_IDLE_MS1800000 (30 Min.)Leerlauffenster, nach dem nicht angepinnte Sessions stoppen. Die Build-Cache-Hilfscontainer einer Organisation folgen stattdessen SANDBOX_BUILDKITD_IDLE_MS.
SANDBOX_SESSION_RELEASED_IDLE_MS300000 (5 Min.)Leerlauffenster für eine freigegebene Session, also eine, deren Aufgabe oder Lauf beendet ist und die keine andere Arbeit mehr belegt. Eine nicht angepinnte, freigegebene Session stoppt nach dieser Leerlaufzeit, statt SANDBOX_SESSION_MAX_IDLE_MS abzuwarten; die nächste Runde setzt sie auf ihrem erhaltenen Arbeitsverzeichnis fort. Agent-Sessions mit Docker in der Sandbox behalten das volle Leerlauffenster, sobald ihr innerer Docker-Daemon gelaufen ist, weil er bei jeder Fortsetzung mit einem leeren Image-Speicher startet; eine Session, deren Daemon nie gestartet ist, erhält ebenfalls dieses kürzere Fenster.
SANDBOX_EXEC_STALL_MINUTES45Wie lange ein Befehl in einer Session nichts ausgeben darf, während seine Prozesse weniger als 1 % einer CPU nutzen, bevor die Sandbox ihn als hängend beendet. Ein Agent, der hängt, weil er auf eine Verbindung wartet, die nie antwortet, oder auf eine Eingabe, die niemand sendet, belegt seine Session sonst bis zum Zeitlimit seines Laufs. Arbeit, die der Befehl an Container übergibt, die er in der Sandbox gestartet hat, zählt als CPU-Nutzung. Ganze Minuten bis 1440; 0 deaktiviert die Prüfung. Gilt für neu erstellte Sessions.
SANDBOX_RUNTIME_IMAGEtale-sandbox-runtime:latestOptional, vom Spawner gelesen. Das Image, aus dem jeder Session-Container entsteht. Der Default ist der Tag, den der Entwicklungs-Stack lokal baut; ein Host, der seine Images zieht, setzt deshalb den Registry-Namen: ghcr.io/tale-project/tale/tale-sandbox-runtime:<version>, passend zum Rest des Stacks. tale deploy setzt ihn für dich.
SANDBOX_DIND_INNER_POOLnicht gesetzt (automatisch)Optionaler Adresspool für den inneren Docker-Daemon in Agent-Sessions auf Docker oder Kubernetes. Verwende ein kanonisches privates IPv4-/16 nach RFC1918 außerhalb deiner Pod-, Service- und VPC-Netze. Die Runtime lehnt Überschneidungen mit erkannten Netzen und Adressen ab.
SANDBOX_K8S_DOCKER_STORAGE_SIZE_LIMIT20GiNur Kubernetes. Die Größe des Speichers für das innere Docker einer Agent-Session, die Docker in ihrer Sandbox ausführt. Wächst eine Session darüber hinaus, räumt Kubernetes ihren Pod (Eviction); bemiss den Wert deshalb nach den größten Images, die deine Agents laden und bauen. Die übrigen Kubernetes-Einstellungen findest du unter Auf Kubernetes bereitstellen.
SANDBOX_K8S_EPHEMERAL_STORAGE_REQUEST / SANDBOX_K8S_EPHEMERAL_STORAGE_LIMIT256Mi / 2GiNur Kubernetes. Wie viel Platz auf der Festplatte des Nodes ein Session-Pod anfordert und wie viel er dort außerhalb seines temporären Workspaces und des Speichers für das innere Docker schreiben darf. Die Grenze des Pods rechnet diese Speicher hinzu; überschreitet eine Session sie, räumt Kubernetes nur ihren Pod, statt dass sie den Node füllt.
SANDBOX_K8S_NODE_SELECTOR / SANDBOX_K8S_TOLERATIONSnicht gesetztNur Kubernetes. Die Node-Labels, die jeder Session-Pod erfüllen muss, als JSON-Objekt wie {"tale.dev/sandbox":"true"}, und die Taints, die er toleriert, als JSON-Array von Pod-Tolerations. So laufen Sessions auf eigenen Nodes statt neben der Datenbank und der Plattform. Ein fehlerhafter Wert verhindert den Start des Spawners.
SANDBOX_K8S_PRIORITY_CLASSnicht gesetztNur Kubernetes. Die PriorityClass jedes Session-Pods. Liegt sie unter der Klasse der Plattform, darf der Scheduler Sessions verdrängen, um Pods der Plattform unterzubringen.
SANDBOX_EGRESS_MAX_CLIENTS2000Vom Dienst sandbox-egress gelesen, nicht vom Spawner: Erstelle diesen Dienst nach einer Änderung neu. Verbindungen, die der Egress-Proxy für alle Sessions zusammen gleichzeitig bedient; mit transparentem Egress läuft jede ausgehende Verbindung einer Session, ihrer Builds und ihrer Paketinstallationen über ihn. Jenseits der Grenze lehnt der Proxy neue Verbindungen ab, und Installationen und Seitenaufrufe brechen mit zurückgesetzten Verbindungen ab. Jede Verbindung belegt einen Thread und zwei offene Dateien, deshalb bemessen die mitgelieferten Compose-Dateien die Prozess- und Dateigrenzen des Proxys für den Default; ein höherer Wert braucht auch höhere Grenzen, und der Proxy warnt beim Start, wenn seine Grenze für offene Dateien zu niedrig ist. Beim Start hebt der Proxy seine Grenze für offene Dateien auf das an, was die Verbindungen brauchen, so weit die harte Grenze des Containers es erlaubt. Unter Kubernetes setzt du ihn am Egress-Deployment; eine Pod-Spezifikation setzt keine Prozessgrenze, daher muss das podPidsLimit des Nodes Platz für einen Thread je Verbindung lassen.
SANDBOX_EGRESS_MAX_CONNECTIONS_PER_SESSION256Vom Dienst sandbox-egress gelesen, nicht vom Spawner: Erstelle diesen Dienst nach einer Änderung neu. Verbindungen, die eine Session gleichzeitig zum Egress-Proxy offen halten darf, gezählt nach ihrer Adresse, damit eine einzelne Session den anderen nicht den ganzen Vorrat von SANDBOX_EGRESS_MAX_CLIENTS nimmt; die Build-Cache-Hilfscontainer jeder Organisation haben eigene Adressen. Eine Verbindung über der Grenze lehnt der Proxy sofort mit einem Reset ab, die übrigen Verbindungen der Session laufen weiter. 0 schaltet die Grenze ab, und ein Wert, der keine ganze Zahl ist, verhindert den Start des Proxys. Der Proxy setzt die Grenze beim Start als Firewall-Regel; auf einem Kernel ohne den connlimit-Match startet er ohne sie und protokolliert eine Warnung. Unter Kubernetes setzt du ihn am Egress-Deployment; wo das Cluster-Netz die Quelladressen der Sessions umschreibt, sodass sie den Proxy von einer gemeinsamen Adresse aus erreichen, teilen sie sich eine Grenze, setze dort also 0.

Die Backend-Einstellungen oben müssen API und Worker erreichen. Erstelle beide Dienste nach einer Änderung neu. Der Spawner prüft freien Arbeitsspeicher und Plattenplatz auch beim erneuten Belegen einer freigegebenen Sitzung; daher kann auch ein warmer Arbeitsbereich auf Kapazität warten.

Verbundene Geräte prüfen Arbeitsspeicher und freien Speicherplatz nach denselben Regeln wie ein lokaler Docker-Host; ihre konfigurierte Session-Obergrenze bleibt bestehen.

Ein absichtlich gestoppter Docker-Daemon bleibt für den nächsten Befehl bereit; Zustandsprüfungen starten ihn nicht. Eine fehlgeschlagene Prüfung sperrt sofort neue Arbeit, stoppt aber allein noch nicht die Session. Dafür müssen mindestens drei abgeschlossene Prüfungen über einen Zeitraum von mindestens fünf Sekunden fehlschlagen. Eine erfolgreiche Prüfung oder eine neue Engine setzt diese Fehlerhistorie zurück. Ein bestätigter Startfehler oder ein unerwartetes Ende der Engine kann die Wiederherstellung sofort auslösen. Der Spawner kann dann eine inaktive, nicht angepinnte Session nach einer atomaren Aktivitätsprüfung stoppen und ihren Arbeitsbereich für den nächsten Start behalten. Unter Docker geht beim Stoppen der gesamten Session ihr innerer Docker-Speicher verloren; beim automatischen Leerlaufstopp nur der inneren Engine bleibt er erhalten. Beschäftigte oder angepinnte Sessions bleiben bestehen und lehnen neue Starts ab, bis Docker wieder antwortet oder der Betreiber die Störung behebt.

Behalte bei einem schrittweisen Upgrade für jeden alten Spawner sein bisheriges, fest referenziertes Runtime-Image bei, bis der Spawner ersetzt ist. Ändere keinen Runtime-Tag, den ein alter Spawner noch verwendet: Er unterscheidet vorübergehende Prüfungsfehler nicht von bestätigten Ausfällen. Ein neuer Spawner mit einer älteren Runtime lehnt neue Arbeit bei einem fehlerhaften Zustand ab und behält die üblichen Grenzen für Leerlauf und Lebensdauer bei.

Ein Spawner im Container prüft Dockers Daten-Dateisystem automatisch, wenn sich sein vorhandener /etc/hostname-Mount anhand des Daemons verifizieren lässt. Gelingt die Erkennung nicht, bleibt die Prüfung der Arbeitsbereiche aktiv; /health meldet die Docker-Datenträgerüberwachung als unavailable. Ein ausdrücklich konfigurierter, schreibgeschützter Mount des Docker-Datenverzeichnisses hat Vorrang. Lässt er sich nicht verifizieren oder lesen, wartet die Zulassung neuer Arbeit, bis er verfügbar ist. Lies zur Konfiguration docker info --format '{{.DockerRootDir}}' aus und verwende diesen tatsächlichen Host-Pfad. Docker Desktop und entfernte Daemons können einen anderen Aufbau benötigen. Ergänze bei direktem Compose den folgenden Override und übergib beide Variablen an den Sandbox-Dienst:

yaml
services:
  sandbox:
    environment:
      SANDBOX_DOCKER_DATA_ROOT: ${SANDBOX_DOCKER_DATA_ROOT}
      SANDBOX_DOCKER_DATA_PATH: /var/lib/tale-sandbox/docker-data
    volumes:
      - ${SANDBOX_DOCKER_DATA_ROOT}:/var/lib/tale-sandbox/docker-data:ro

Eine Speichergrenze für die Zulassung ist keine Speicherquote pro Sitzung. Docker-Named-Volumes haben kein portables Größenlimit, und die Durchsetzung einer Kubernetes-PVC-Größenanforderung hängt vom Storage-Backend ab. Nutze für harte Quoten ein Dateisystem oder eine Storage-Klasse mit Quotenunterstützung. Überwache separat eingehängte containerd-Speicher, Volume-Verzeichnisse und externe Volume-Treiber zusätzlich zu Arbeitsbereichen, Image-Layern und Build-Caches.

Kubernetes-Sitzungen verwenden /readyz für die Startprüfung und /livez für die Lebendigkeitsprüfung des Daemons. Ein absichtlich gestoppter innerer Docker-Daemon gilt beim Start als bereit; ein laufender Docker-Daemon muss auf seine Gesundheitsprüfung antworten. Die Lebendigkeitsprüfung erfasst nur den Sandbox-Daemon, damit Fehler bei Abhängigkeiten keine beschäftigte Sitzung neu starten. Ein blockierter Daemon kann auch bei angehefteter Sitzung neu starten. Docker- und Egress-Diagnosen erscheinen unter /healthz.

Eine bereits aktive Generation wird nicht erneut angerechnet. Ein Workflow ohne inneres Docker behält die Identität und Werkzeuge seines Agenten, startet aber keinen Docker-Daemon und hält keine Build-Cache-Hilfscontainer aktiv. Ohne expliziten Wert für SANDBOX_AGENT_MEMORY gilt pro Session standardmäßig 4g ohne inneres Docker oder 8g mit Docker, auch wenn andere Sessions im Deployment Docker nutzen. Ein expliziter Wert gilt für beide Varianten. Die Grenzen sind Obergrenzen, kein reservierter Arbeitsspeicher.

Bei voller Kapazität kann der Spawner eine freigegebene, nicht angepinnte Session im Leerlauf schon vor Ablauf des Leerlauffensters stoppen, um neue Arbeit zuzulassen, zuerst die am längsten untätige. Der Daemon muss bestätigen, dass keine Arbeit läuft; beschäftigte Sessions und Sessions mit unbekanntem Zustand bleiben geschützt. Das dauerhafte Arbeitsverzeichnis oder Volume bleibt beim Stoppen erhalten. Lässt sich keine Session sicher freigeben, blockiert die Kapazitätsgrenze weiterhin neue Starts. Dasselbe gilt, wenn der freie Speicher des Hosts unter SANDBOX_MIN_FREE_MEMORY fallen würde. Solange der Datenträger mit den Arbeitsverzeichnissen der Sessions unter SANDBOX_MIN_FREE_DISK liegt, wartet neue Arbeit, ohne dass Sessions im Leerlauf gestoppt werden: Eine gestoppte Session behält ihr Arbeitsverzeichnis. Erst unterhalb von SANDBOX_CRITICAL_FREE_DISK stoppt der Spawner freigegebene Sessions mit Docker in der Sandbox im Leerlauf sofort, weil ihr Stopp ihre inneren Image-Speicher entfernt.

Datensätze im Agent-Laufzeit-Protokoll, einschließlich unvollständiger Zeilen, sind auf 8 MiB begrenzt. Zu große oder unvollständige Ausgaben führen zu einem ausdrücklichen Fehler; eine begrenzte Fortschrittsvorschau gilt nie als vollständiges strukturiertes Ergebnis. Vollständige Endantworten bleiben getrennt von dieser Vorschau erhalten.

Auch die Wiederaufnahme einer freigegebenen, noch laufenden Session prüft die Speicherreserve und reserviert vorab den erwarteten Arbeitsspeicher. Gleichzeitige Wiederaufnahmen teilen sich diese Berechnung. Eine Antwort „beschäftigt“ lässt sich erneut versuchen; sie löscht weder das Arbeitsverzeichnis noch unterbricht sie bereits belegte Sessions. Diese Reservierungen begrenzen nicht den späteren Speicherzuwachs aktiver Werkzeuge oder der Builder einer Organisation.

Ist Docker in Agent-Sandboxes aktiviert, startet der Daemon automatisch beim ersten Docker-Befehl. Agenten müssen keinen Modus wählen. Nach fünf Minuten ohne verbundene Clients stoppt er nur, wenn kein Container läuft, neu startet oder pausiert ist und für alle Container die automatische Neustartregel deaktiviert ist; bei unbekanntem Zustand läuft er weiter. Der nächste Befehl startet ihn mit denselben Images, Volumes und demselben Arbeitsverzeichnis. Sind beim Start des Session-Containers bereits Container-Metadaten vorhanden, startet der Daemon sofort, damit die Neustartregeln weiterhin greifen. Isolation, Berechtigungen und Speichergrenzen des Deployments bleiben dabei unverändert.

Session-Kapazität bemessen

Fehlt SANDBOX_MAX_SESSIONS auf einem Docker-Host, bemisst der Spawner die Kapazität nach Speicher und CPUs des Hosts (eine Session je 768 MiB über der Reserve, höchstens zwei je CPU: Ein Host mit 16 GiB und 8 CPUs erhält 16 Sessions, einer mit 64 GiB und 16 CPUs 32; ein Host mit 16 GiB erhält 9, wenn Agent-Sessions einen eigenen Docker-Daemon betreiben) und lässt eine neue Session nur zu, solange der Host SANDBOX_MIN_FREE_MEMORY frei behält, wobei er mitzählt, was noch startende und eben gestartete Sessions gleich belegen werden. Eine Lastspitze neuer Sessions, die den Host überbuchen würde, wartet deshalb, statt zu starten; Sessions, die bereits laufen, hindert diese Prüfung nicht daran, weiter zu wachsen. Steht die CPU des Hosts unter Druck (SANDBOX_CPU_PRESSURE_PERCENT), starten neue Sessions ebenso einzeln, statt die Last weiter zu erhöhen. Jeder Lauf eines Projektagenten, der gleichzeitig mit einem anderen arbeitet, bekommt eine eigene Session, einen Agenten-Worker: Ein Agent, der an drei Aufgaben gleichzeitig arbeitet, betreibt drei Sessions, jede mit ihrem eigenen Limit SANDBOX_AGENT_MEMORY. Diese beiden Einstellungen begrenzen also, wie viel Agentenarbeit parallel läuft. Lege die Kapazität selbst fest unter Kubernetes, mit einem entfernten Docker-Daemon oder wenn auf dem Host auch andere speicherhungrige Dienste laufen: Teste dann die Aufgaben, die deine Bereitstellung gleichzeitig ausführen soll. Browser-Rendering und Docker-Builds haben unterschiedliche Lastspitzen; berücksichtige Agents, Workflows und Crawling aller Organisationen. Ein freier Session-Platz garantiert keine ausreichenden Ressourcen.

Miss unter Docker den Ressourcenbedarf, während typische Aufgaben gleichzeitig laufen. Wiederhole diesen Befehl während des Durchlaufs; eine Messung im Leerlauf zeigt keine Lastspitzen:

bash
docker stats --no-stream --format 'table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}'

Ziehe den Bedarf von Betriebssystem, Plattformdiensten, Datenbanken und Build-Cache-Hilfscontainern sowie eine Sicherheitsreserve vom Host-Speicher ab. Teile den verbleibenden Speicher durch den gemessenen Spitzenbedarf je aktiver Session und runde ab. Beispiel: Ein Host mit 32 GiB, davon 8 GiB für Dienste und Reserve, und einem gemessenen Spitzenbedarf von 3 GiB je Session ergibt (32 - 8) / 3 = 8 Sessions. Das ist ein Rechenbeispiel, kein Benchmark. Bei gemischten Aufgaben addierst du die gleichzeitig auftretenden Spitzen. Prüfe außerdem CPU-Auslastung und Aufgabendauer, bevor du die Grenze erhöhst.

Die 4 GiB oder 8 GiB eines Agents sind eine Speicherobergrenze; beim Start reserviert er diesen Speicher nicht. Acht Agents mit laufenden Docker-Builds können daher deutlich mehr Speicher benötigen als acht überwiegend untätige Sessions. Miss unter typischer Last und halte Reserven frei. Erhöhe die Kapazität erst auf 16 oder mehr, wenn der Host die Last dauerhaft trägt. Verringere vor einer Absenkung alle Organisationssummen, die über dem neuen Wert liegen. Die Standardlimits einer Organisation ergeben 6; eine kleinere Bereitstellungskapazität braucht entsprechend kleinere Organisationslimits.

Eine Kapazitätsänderung anwenden

Ergänze oder ändere diese Zeile in der .env deiner Bereitstellung. Behalte die übrigen Einträge bei. Explizite Werte gelten auch nach Upgrades weiter; ohne einen bemisst ein Docker-Host die Kapazität wie oben beschrieben nach seinem Speicher, und Kubernetes verwendet 8.

dotenv
SANDBOX_MAX_SESSIONS=8

Erstelle bei einem selbst verwalteten Compose-Stack nur den Sandbox-Dienst mit seinem vorhandenen lokalen Image neu:

bash
docker compose up -d --no-deps --no-build --pull never sandbox

Verwende dasselbe Projekt, dieselben -f-Dateien und dieselben Optionen für Umgebungsdateien wie beim laufenden Stack. Ein Neustart allein lädt eine geänderte .env nicht. Für CLI-verwaltete Installationen folgst du dem Deployment-Ablauf unter Upgrades. Setze unter Kubernetes die Variable im Deployment des Sandbox-Spawners und führe dessen Rollout aus.

Prüfe die neue Bereitstellungskapazität unter Sandboxes. Bei Organisationslimits von 2/2/2 und einer Kapazität von 8 zeigt die Summe 6 / 8. Bestehende Organisationseinstellungen bleiben erhalten; zum Speichern muss ihre Summe weiterhin in die aktuelle Kapazität passen. Die Kapazitätsänderung erhöht keine CPU- oder Speichergrenze eines Containers.

Nach einem Upgrade

Die Standardkapazität lag bisher bei 16, und Organisationen aus früheren Versionen wurden mit den Limits 2/4/4 angelegt, also einer Summe von 10. Eine Bereitstellung, die SANDBOX_MAX_SESSIONS nie gesetzt hat, startet mit der neuen Version daher mit einer Kapazität von 8 und Organisationen, deren gespeicherte Summe darüber liegt. Laufende Arbeit ist davon nicht betroffen, und jede Organisation lässt weiterhin Arbeit unter ihren gespeicherten Limits zu; nur das Speichern der Sandbox-Seite bleibt gesperrt, bis die Summe passt, und niedrigere Limits lassen sich weiterhin speichern. Setze entweder SANDBOX_MAX_SESSIONS=16 explizit, um die bisherige Kapazität zu behalten, oder bitte jede betroffene Organisation, ein Limit zu verringern.

Ab dieser Version erhält eine Docker-Bereitstellung, die SANDBOX_MAX_SESSIONS nie gesetzt hat, eine nach dem Host-Speicher bemessene Kapazität statt 8, nie weniger als 8. Sie kann mehr Sessions gleichzeitig zulassen als zuvor, und das nur, solange der Host Speicher übrig hat. Ein expliziter Wert legt die Kapazität fest und schaltet die adaptive Speicherprüfung beim Start einer Session ab; bemiss ihn nach gemessenen Speicherspitzen. Die Datenträgerprüfung bleibt aktiv.

Diese bemessene Kapazität beträgt jetzt außerdem höchstens zwei Sessions je CPU; ein Host mit viel Speicher und wenigen CPUs erhält daher weniger Sessions als zuvor (ein Host mit 16 GiB und 4 CPUs: 8 statt 19). Steht die CPU des Hosts unter Druck, starten neue Sessions zudem einzeln (SANDBOX_CPU_PRESSURE_PERCENT, 0 schaltet das ab). Ein expliziter Wert für SANDBOX_MAX_SESSIONS bleibt unverändert.

Docker-Build-Caches

Die Vorbereitung des gemeinsamen Build-Caches verwendet SANDBOX_BUILDKITD_PROVISION_TIMEOUT_MS (standardmäßig 5 Sekunden). Eine Session wartet höchstens so lange oder ein Viertel ihres gesamten Startbudgets, falls das kürzer ist. Danach nutzt sie ihren lokalen Builder. Die gemeinsame Vorbereitung hat ein eigenes begrenztes Zeitbudget: Wird die Wartezeit einer Session abgebrochen, läuft die Vorbereitung für andere Sessions weiter. Eine Session, die bereits ihren lokalen Builder nutzt, wechselt bei einem verspäteten Ergebnis nicht nachträglich zum gemeinsamen Builder. Registry-Mirrors werden parallel vorbereitet. Die Zahl gleichzeitiger Schritte des gemeinsamen Builders ergibt sich aus seiner abgerundeten CPU-Grenze und beträgt mindestens eins; seine Speichergrenze gilt weiterhin. Die Vorbereitungszeit wird vom verbleibenden Startbudget der Session abgezogen.

Docker-Build-Caches sind nach Organisation getrennt. Jede Organisation nutzt einen privilegierten Builder und drei Registry-Mirrors ohne erhöhte Rechte. Sobald keine Session mehr auf sie zugreifen könnte, stoppen die Hilfscontainer nach SANDBOX_BUILDKITD_IDLE_MS (10 Minuten), und die Registry-Mirrors werden mit ihren Caches entfernt, denn der eigene Cache des Builders behält die Basis-Layer, die seine Builds genutzt haben. Der nächste Build startet den Builder mit seinem erhaltenen Cache-Volume neu und erstellt die Mirrors neu. Unmittelbar bevor der Builder stoppt, kürzt der Spawner seinen Cache auf SANDBOX_BUILDKITD_IDLE_CACHE, denn seine Speicherbereinigung läuft nur, solange er läuft. Der Cache einer gestoppten Organisation wird danach nicht weiter gekürzt; nach SANDBOX_BUILDKITD_CACHE_RETENTION (14 Tage) ohne Build werden ihre Hilfscontainer und Caches entfernt, sonst gehen sie mit der Organisation. Solange der Datenträger der Sessions unter SANDBOX_MIN_FREE_DISK liegt, gehen die Caches gestoppter Organisationen früher, die am längsten gestoppten zuerst. Das Netzwerk und das Cache-Volume des Builders bleiben für die Wiederverwendung bestehen. Kubernetes-Sessions nutzen ihren eigenen inneren Docker-Builder; der Kubernetes-Abgleich ruft für diese Hilfscontainer keine Docker-CLI auf.

Der Spawner füllt den ersten verfügbaren Docker-Adresspool mit Organisationsnetzwerken, bevor er zum nächsten wechselt. Standardmäßig erhält jedes Netzwerk ein /23 mit 512 Adressen; ein ansonsten freies /16 bietet damit Platz für 128 Organisationsnetzwerke. Kleinere in Docker konfigurierte Subnetze bleiben kleiner. Der Spawner schließt vorhandene Docker-Netzwerke, Routen und DNS-Serveradressen auf dem Host des Docker-Daemons sowie 172.31.0.0/16 für ältere Runtime-Images aus und prüft anschließend das angelegte Netzwerk.

Auch bei einem entfernten Docker-Daemon erfasst der Spawner dessen Host über einen kurzlebigen Container aus dem konfigurierten BuildKit-Image. Dieser läuft im Host-Netzwerk-Namespace mit schreibgeschütztem Dateisystem, ohne Capabilities und ohne Mounts. Scheitert diese Abfrage oder bleibt kein sicheres Subnetz frei, bauen Sessions lokal ohne gemeinsamen Cache. Ein ungenutztes eigenes Netzwerk mit ungültigem Subnetz legt der Spawner neu an; belegte und fremde Netzwerke bleiben erhalten.

Beim Upgrade entstehen leere Organisationscaches; die alten globalen Cachedaten bleiben vorerst erhalten. Alte Hilfscontainer stoppen automatisch, sobald keine laufende Session mehr auf sie angewiesen ist. Sind sie länger als SANDBOX_BUILDKITD_CACHE_RETENTION (14 Tage) gestoppt und ist weiterhin keine Session auf sie angewiesen, entfernt der Spawner diese Hilfscontainer und die vier alten Cache-Volumes (tale-buildkitd-cache sowie tale-buildkitd-mirror-cache-docker-io, -ghcr-io, -quay-io), jeweils nur, solange sie die alte Build-Cache-Markierung ohne Organisation tragen, und protokolliert jede Entfernung; off behält sie. Lass alte angepinnte Sessions auslaufen oder stoppe sie, um den Übergang abzuschließen; bis dahin bleibt der alte gemeinsame Cachedienst erreichbar. Browserautomatisierung nutzt Chromium ohne grafische Oberfläche. Die Live-Ansicht und manuelle Browserübernahme sind entfernt.

Images der inneren Docker-Engine

Ist der gemeinsame Build-Cache aktiv, lädt die innere Docker-Engine einer Session Docker-Hub-Images über den docker.io-Registry-Mirror ihrer Organisation, also denselben Cache, den ihre Builds nutzen. Läuft dieser Mirror nicht, lädt sie direkt von Docker Hub. Images aus anderen Registries lädt sie direkt. Geht eine innere Engine mit mehr als 10 GiB an Images und Build-Cache in den Leerlauf, entfernt sie vorher ihre unbenannten, unbenutzten Images und kürzt ihren Build-Cache auf die zuletzt genutzten 5 GiB; benannte Images, Container und Volumes bleiben. Unter Kubernetes begrenzt stattdessen die Größenbeschränkung des Volumes den inneren Speicher, wenn sie unter 10 GiB liegt.

Innere Docker-Netzwerke

Die automatische Auswahl prüft unter Docker und Kubernetes IPv4-Routen und Gateways aus allen Routingtabellen, Adressen und Präfixe der Schnittstellen, DNS-Server sowie die aufgelösten Adressen der beim Containerstart konfigurierten Proxy- und Gateway-Hosts. Hosts, die erst während eines Agent-Turns übergeben werden, fehlen in dieser anfänglichen Erfassung. Ein später angeschlossenes Docker-Organisationsnetzwerk berücksichtigt sie ebenfalls. Die Runtime bevorzugt ein freies 172.31.0.0/16 und prüft danach andere private /16-Bereiche. Das erste /24 gehört zu docker0; innere Compose-Netzwerke erhalten /24-Blöcke aus demselben Pool. Im automatischen Modus startet die Session nicht, wenn Abfragen scheitern oder kein privater Bereich frei bleibt.

Aus seinem eigenen Netzwerk-Namespace kennt ein Pod nicht die vollständigen Pod-, Service- und VPC-CIDRs des Clusters. Setze für DinD auf Kubernetes SANDBOX_DIND_INNER_POOL auf ein privates /16, das du gegen all diese Netze geprüft hast. Auch ein vorgegebener Pool scheitert bei jeder erkannten Überschneidung oder einem ungültigen Wert. Bleiben einzelne Abfragen ohne Ergebnis, nennt die Runtime sie in einer Warnung und kann mit dem vorgegebenen Pool fortfahren. Den nicht sichtbaren Adressraum musst du selbst berücksichtigen.

Starte nach einer Änderung dieses Pools den Spawner neu und erstelle bestehende Sessions neu, damit sie den Wert übernehmen. Ein Runner-Neustart innerhalb desselben Kubernetes-Pods behält dessen Umgebung und den inneren Docker-Speicher bei.

Der Egress-Proxy erlaubt DNS-Anfragen an die geprüften Nameserver-IP-Adressen aus seiner /etc/resolv.conf, auch an einen privaten Cluster-DNS-Dienst. Jede Ausnahme gilt nur für diese eine IP und den UDP-/TCP-Zielport 53. Andere private Ziele und die Weiterleitung zwischen angeschlossenen Netzwerken bleiben gesperrt.

IPv6-Weiterleitungsschutz

Halte sandbox, sandbox-egress und SANDBOX_RUNTIME_IMAGE beim Upgrade auf demselben Release. Bevor der Spawner unter Docker das Build-Netzwerk einer Organisation anschließt, prüft er den Weiterleitungsschutz der Session. Compose und generierte Docker-Session-Container deaktivieren IPv6 mit net.ipv6.conf.all.disable_ipv6=1 und net.ipv6.conf.default.disable_ipv6=1. Übernimm beide Werte in eigene Docker-Definitionen.

Kubernetes-Pods erhalten nicht automatisch unsichere Sysctls. Der Egress-Proxy braucht eine funktionierende IPv6-Firewall oder deaktiviertes IPv6 in seinem Netzwerk-Namespace. Ist die IPv6-Firewall nicht verfügbar, versucht der Entrypoint IPv6 dort zu deaktivieren und prüft danach den Standardwert und jede Schnittstelle. Ein schreibgeschütztes /proc/sys oder fehlende Schreibrechte können das verhindern; ohne Schutz für weiterhin aktives IPv6 startet der Proxy nicht. Konfiguriere den Egress-Pod vor dem Deployment mit den Netzwerkeinstellungen, die dein Cluster erlaubt.

SSH-Zugang zu Repositories

Die native Sandbox enthält OpenSSH und netcat-openbsd. Gib einen austauschbaren, auf das Repository beschränkten Schlüssel als benanntes Agent-Secret frei und lade ihn im berechtigten Lauf über stdin in ssh-agent. Die privaten Bytes bleiben in der Umgebung; schreibe keine Schlüsseldatei und gib sie nie aus. Ein von einem Mitglied gestarteter Lauf erhält keine Agent-Secrets. Git-Commits nutzen den Namen und die E-Mail des Workspace-Eigentümers auch ohne Freigabe eines GitHub-Connectors.

Interne Sitzungen nutzen ihren bestehenden HTTP_PROXY für ausgehende Verbindungen. Direktes SSH kann in diesem Netz nicht auf externe DNS-Auflösung bauen. Nutze den HTTP-CONNECT-Tunnel des Proxys und einen erlaubten Port. GitHub unterstützt SSH über ssh.github.com:443; prüfe den Host gegen GitHubs veröffentlichte Fingerabdrücke, wie unter SSH über Port 443 beschrieben. Lege eine öffentliche Known-Hosts-Datei mit dem unabhängig geprüften Schlüssel an und konfiguriere den Befehl, nachdem der Agent den privaten Schlüssel geladen hat:

python
import os
import shlex
import subprocess
from urllib.parse import urlsplit

proxy = urlsplit(os.environ["HTTP_PROXY"])
if proxy.scheme != "http" or not proxy.hostname or not proxy.port or proxy.username or proxy.password:
    raise ValueError("Expected the existing unauthenticated HTTP egress proxy")
connect = shlex.join(["nc", "-X", "connect", "-x", f"{proxy.hostname}:{proxy.port}", "%h", "%p"])
environment = os.environ.copy()
environment["GIT_SSH_COMMAND"] = shlex.join([
    "ssh", "-o", f"ProxyCommand={connect}", "-o", "StrictHostKeyChecking=yes",
    "-o", "UserKnownHostsFile=/tmp/repository-known-hosts",
    "-o", "GlobalKnownHostsFile=/dev/null", "-o", "BatchMode=yes",
    "-o", "ConnectTimeout=20",
])
subprocess.run(["git", "ls-remote", "--exit-code", "ssh://git@ssh.github.com:443/org/repository.git", "HEAD"], env=environment, check=True, timeout=30)

Die Known-Hosts-Datei enthält nur den öffentlichen Hostschlüssel des Anbieters; der private Repository-Schlüssel bleibt in ssh-agent. Die bestehende Egress-Richtlinie und der Zugriffsumfang des Repository-Schlüssels gelten weiterhin. Eine weitergehende GitHub-Connector-Freigabe ist nicht nötig.

Sandbox-Geräte

Organisationen können ihre Sandboxes auf eigenen Rechnern ausführen, die sie unter Einstellungen > Sandboxes verbinden. Ein Gerät baut über HTTPS eine Verbindung zu <SITE_URL><BASE_PATH>/sandbox/tunnel auf und hält einen WebSocket offen. Der mitgelieferte Proxy leitet diesen Pfad, und nur diesen, an den Geräte-Hub des Spawners weiter; die signierte API des Spawners bleibt im internen Netz. Geräte brauchen das Docker-Backend: Mit Kubernetes bleibt der Hub ausgeschaltet.

NameStandardBeschreibung
SANDBOX_HUB_PORT8004Liest der Spawner. Port des Geräte-Hubs, der nur ein per Ticket authentifiziertes WebSocket-Upgrade und eine Zustandsprüfung beantwortet. 0 schaltet Geräte aus: Gerät hinzufügen ist dann nicht verfügbar. Änderst du den Port, stelle auch SANDBOX_HUB_UPSTREAM darauf um.
SANDBOX_DEVICE_TUNNEL_URL<SITE_URL><BASE_PATH>/sandbox/tunnel als wss://Optional, liest das Backend. Wohin sich Geräte verbinden, wenn ein vorgeschalteter Proxy den Hub unter einem anderen Host oder Pfad veröffentlicht. Eine https://-Adresse gilt als wss://.
SANDBOX_DEVICE_IMAGE_REGISTRYGHCR_REGISTRY, sonst ghcr.io/tale-project/taleOptional, liest das Backend. Woher Geräte die Sandbox-Images des Server-Releases laden.
SANDBOX_HUB_UPSTREAMsandbox:8004Optional, liest der Proxy. Wohin der Proxy /sandbox/tunnel weiterleitet, wenn der Spawner nicht der Dienst sandbox ist.

Ein Gerät läuft immer mit dem Release des Servers. Es erfährt das Release bei jeder Erneuerung seiner Verbindung und ersetzt seine eigenen Container, sobald der Server weiterzieht, außer es wurde mit --no-auto-update verbunden. Es legt keine Daten auf dem Server ab: Seine Arbeitsbereiche bleiben auf dem Rechner. Sandboxes auf einem Gerät erreichen die Sandbox-Endpunkte des Backends und das Modell-Gateway über die Verbindung des Geräts, auf denselben Pfaden wie Sitzungen auf dem Server; die Verwaltungs-API des Gateways ist auf diesem Weg nie erreichbar. Ein Gerät behält die Adressen von Backend und Gateway, die es beim Verbinden erhalten hat: Nachdem du SANDBOX_HTTP_API_BASE_URL oder EXTERNAL_AGENT_GATEWAY_URL geändert hast, führe auf jedem Gerät tale sandbox update aus.

Ein Gerät muss dem TLS-Zertifikat der Website vertrauen. Eine Bereitstellung mit TLS_MODE=selfsigned kann keine Geräte aufnehmen.

Setzt du statt des mitgelieferten Proxys einen eigenen ein, leite /sandbox/tunnel an den Port SANDBOX_HUB_PORT des Spawners weiter, lass WebSocket-Upgrades und den Header Authorization unverändert und erlaube Verbindungen, die stundenlang offen bleiben.

Sandbox-Agent-Turns

NameDefaultBeschreibung
TALE_EXTERNAL_TURN_DEADLINE_MS1800000 (30 Min.)Optional. Wie lange ein Coding-Agent-Turn in der Sandbox (Claude Code, OpenCode, Codex) ohne Abnehmer seiner Ausgabe liegen darf, bevor der Sandbox-Daemon ihn abräumt. Ein gleitendes Fenster, das bei jedem Wiederanbinden der Plattform neu startet — keine absolute Obergrenze für den Turn. Ein laufender Agent-Turn wartet außerdem einen nicht erreichbaren Sandbox-Dienst ab, bevor er fehlschlägt: ein Drittel dieses Werts, höchstens 10 Minuten (beim Standardwert genau 10 Minuten). Senkst du den Wert, verkürzt sich diese Wartezeit. Millisekunden.
SANDBOX_LLM_GATEWAY_STREAM_IDLE_TIMEOUT_SECONDS600 (10 Min.)Optional. Wie lange das Modell-Gateway der Sandbox auf das nächste Byte eines stillen Upstream-Modells wartet, bevor es den Stream abbricht — auch während ein langsames lokales Modell noch einen langen Prompt verarbeitet. Das Backend liest den Wert und konfiguriert damit das Gateway. Claude-Code-Turns warten mindestens genauso lange, bevor sie einen stillen Stream aufgeben und die Anfrage erneut senden. Du kannst den Wert für ein langsames lokales Modell also erhöhen, ohne dass Claude Code oder Codex einen Turn doppelt sendet. Ein hängendes Upstream-Modell hält einen Turn dann aber auch länger auf, bevor das Gateway den Stream abbricht. Ein Wert über 600 hebt auch das Anfrage-Timeout des Gateways entsprechend an: Es begrenzt eine ganze nicht gestreamte Antwort, auf die ein Agent ausweicht, wenn ein Stream abbricht, und wie lange ein Upstream-Modell brauchen darf, um eine gestreamte Antwort zu beginnen. Sekunden.
SANDBOX_LLM_GATEWAY_PROVIDER_CONCURRENCY512Optional. Wie viele Anfragen das Modell-Gateway der Sandbox gleichzeitig an einen eingebauten Anbieter schickt (OpenAI, Anthropic, OpenRouter und die anderen Anbieter, die das Gateway selbst umsetzt), den sich alle Organisationen teilen. Das Backend liest den Wert und konfiguriert damit das Gateway. Das Gateway hält für jeden Anbieter so viele Worker bereit, ob ihn etwas aufruft oder nicht; ein höherer Wert kostet also Gateway-Speicher. Eine Anfrage, die alle Worker beschäftigt vorfindet, wartet in einer Warteschlange, die 16-mal so lang ist. Eine ganze Zahl von 1 bis 5.000.
SANDBOX_LLM_GATEWAY_CUSTOM_PROVIDER_CONCURRENCY64Optional. Dasselbe für einen eigenen Anbieter. Das Backend richtet ihn im Gateway für jede Organisation und jedes Modell einmal ein, die Zahl dieser Anbieter wächst also mit Organisationen und Modellen, und jeder hält seine Worker wie ein eingebauter. Der Anthropic-Weg eines eingebauten Anbieters für Agent-Laufzeiten (Claude Code über den Anthropic-Endpunkt von OpenRouter) erhält einen eigenen Anbieter je Organisation und Modell und richtet sich nach diesem Wert. Die Sandbox-Sitzungen einer Organisation haben selten mehr als ein paar Modellaufrufe gleichzeitig auf einem Modell offen. Erhöhe den Wert, wenn die API-Schlüssel einer Organisation mehr Anfragen gleichzeitig an ein eigenes Modell schicken. Eine ganze Zahl von 1 bis 5.000.
SANDBOX_LLM_GATEWAY_LOG_RETENTION_DAYS3Optional. Wie viele Tage das Modell-Gateway der Sandbox sein Anfrageprotokoll aufbewahrt: eine Zeile pro Modellaufruf mit Modell, Tokens, Kosten und Dauer, nie ein Prompt oder eine Antwort. Tale liest dieses Protokoll nicht. Budgets, Ausgaben und Nutzung stammen aus den Budgetzählern der Gateway-Schlüssel, ein kürzeres Protokoll ändert also keinen dieser Werte. Das Backend übergibt den Wert an das Gateway, das ihn bei seinem ersten Neustart anwendet, nachdem das Backend ihn übergeben hat: Dann löscht es ältere Zeilen und danach etwa einmal täglich. Ein tale deploy startet das Gateway neu, bevor das neue Backend den Wert übergibt; ein geänderter Wert gilt deshalb ab der folgenden Bereitstellung. Soll er früher gelten, starte den Dienst sandbox-llm-gateway einmal neu, nachdem die erste Sandbox-Sitzung gestartet ist. Der Speicher verwendet ihren Platz wieder, statt weiter zu wachsen. Eine ganze Zahl von Tagen, mindestens 1; jeden anderen Wert ignoriert das Backend mit einer Warnung im Log.

Untersuche zuerst, warum die Ausgabe nicht mehr gelesen wird. Die Frist begrenzt verwaiste Ausgabeströme, nicht die gesamte Aufgabendauer. Erstelle die betroffenen Backend-Rollen nach einer Umgebungsänderung neu.

Eine geänderte Worker-Zahl des Gateways erreicht einen Anbieter, sobald eine Organisation, die ihn nutzt, die nächste Sandbox-Sitzung startet oder die Modell-Endpunkte aufruft. Eine niedrigere Zahl erreicht auch alle anderen Anbieter, die das Gateway hält: Nach einem Neustart passt das Backend sie zwei bis fünf Minuten nach seiner ersten Sandbox-Sitzung oder Anfrage an die Modell-Endpunkte an.

Eine Ausnahme ist ein Anbieter, dessen Upstream-Host sich nicht mehr auflösen lässt, etwa der eines entfernten Connectors oder eines Hosts, den du aus deinem Netzwerk genommen hast: Das Gateway lehnt es ab, ihn neu zu schreiben, er behält also seine Worker, und das Backend protokolliert nach jedem Neustart eine Warnung, die ihn nennt. Lösche einen solchen Anbieter aus dem Gateway. Ein Anbieter, der noch genutzt wird, wird bei seiner nächsten Sandbox-Sitzung oder Anfrage an die Modell-Endpunkte neu eingerichtet. Schicke die Anfrage aus einem Backend-Container, der das Gateway erreicht und sein Admin-Passwort kennt; auf einem Host mit tale deploy enthält sein Name -backend-api:

bash
docker exec <backend-api-container> sh -c 'curl -fsS -X DELETE -u "${SANDBOX_LLM_GATEWAY_ADMIN_USERNAME:-admin}:$SANDBOX_LLM_GATEWAY_ADMIN_PASSWORD" "${SANDBOX_LLM_GATEWAY_URL:-http://sandbox-llm-gateway:8080}/api/providers/<name>"'

Unter Kubernetes verwendest du kubectl exec -n tale deploy/backend-api -- statt docker exec <backend-api-container>.

Das Gateway startet die Worker aller Anbieter beim Hochfahren, bevor das Backend es erreicht. Anbieter, die mit mehr Workern gespeichert sind, als diese Werte vorgeben (der eigene Default des Gateways ist 1.000), können mehr Speicher brauchen als das Limit des Gateways, 512 MiB mit tale deploy und im Kubernetes-Manifest. Das Gateway wird dann bei jedem Start beendet. Lösche sein Volume nicht: Es enthält das Admin-Konto des Gateways und die Schlüssel, die es ausgegeben hat. Erhöhe stattdessen das Limit, bis das Gateway startet: auf einem Host mit tale deploy mit docker update --memory 2g --memory-swap 2g <container> für den Container, dessen Name auf -sandbox-llm-gateway endet; unter Kubernetes über resources.limits.memory seines Deployments. Starte dann eine Sandbox-Sitzung oder rufe die Modell-Endpunkte auf und warte auf die Logzeile [llm-gateway] provider worker resize finished des Backends, die zwei bis fünf Minuten später erscheint. Sie zählt die Anbieter, die das Backend angepasst hat, die das Gateway abgelehnt hat und die das Backend nicht bestätigen konnte. Ein abgelehnter oder unbestätigter Anbieter behält seine Worker, und eine Warnung vor der Zeile nennt ihn; ein neu gestartetes Backend versucht einen unbestätigten Anbieter erneut. Lösche einen abgelehnten Anbieter, dessen Upstream-Host sich nicht mehr auflösen lässt, wie oben beschrieben, bevor du das Limit zurücksetzt. Setze das Limit danach mit docker update --memory 512m --memory-swap 1g <container> und docker restart <container> zurück, unter Kubernetes auf den ursprünglichen Wert des Deployments.

Der Worker verwendet diese Werte zum Abrufen von Videotranskripten. Sein Image enthält yt-dlp und ein PO-Token-Plugin. Video-Import hilft bei Quellenbeschränkungen, Egress-Problemen und berechtigten Sitzungen. Erstelle den Worker nach Änderungen seiner Umgebung neu. Erneutes Lesen einer Prozessvariablen lädt .env nicht nach.

NameStandardBeschreibung
VIDEO_INGEST_PROXY_URLnicht gesetztProxy für yt-dlp-Anfragen. Unterstützte Protokolle: http, https, socks4, socks4a, socks5, socks5h; das letzte löst Zielnamen am Proxy auf. Nutze einen freigegebenen Egress-Dienst.
VIDEO_INGEST_POT_PROVIDER_URLhttp://bgutil-provider:4416 (eingebacken)URL des PO-Token-Anbieters. Bei vorhandenem Image-Plugin gilt der mitgelieferte Sidecar als Standard. Token können den Abruf unterstützen, geben aber keinen Zugriff auf private Inhalte und garantieren keinen Erfolg.
VIDEO_INGEST_FETCH_POTalways, sobald ein Provider angebunden istZeitpunkt des Token-Abrufs: never, auto oder always. Mit mitgeliefertem Anbieter gilt always. Verwende never, wenn du diesen Token-Abruf bewusst deaktivierst.
VIDEO_INGEST_YTDLP_PLUGIN_DIRS/opt/yt-dlp/plugins (eingebacken)Verzeichnis, aus dem yt-dlp Plugins lädt — jedes Plugin eine Ebene tiefer verschachtelt (<dir>/<name>/yt_dlp_plugins/…). Standardmäßig das eingebackene bgutil-Plugin-Verzeichnis, wenn vorhanden; nur überschreiben, um eigene Plugins zu ergänzen.
VIDEO_INGEST_COOKIES_FILEnicht gesetztPfad im Worker zu einer Netscape-Cookiedatei. Schütze sie wie Kontozugangsdaten und verwende nur eine berechtigte Sitzung. Der organisationsgebundene Sitzungspool in der Video-Anleitung unterstützt verwalteten Import und Widerruf.
VIDEO_INGEST_PLAYER_CLIENTdefault,tv_simplyKommagetrennte Fallback-Liste der YouTube-Player-Clients. Mit angebundenem PO-Token-Provider erweitert sich der Standard auf default,mweb,tv_simply (mweb benötigt ein GVS-Token); explizit setzen, um eine Liste zu erzwingen.
VIDEO_INGEST_PO_TOKENnicht gesetztManuell gesetztes PO-Token (CLIENT.CONTEXT+TOKEN). Vor allem zum Testen — Tokens sind an die Video-ID gebunden und kurzlebig; den Provider bevorzugen.
VIDEO_INGEST_IMPERSONATEnicht gesetztZiel für Browser-TLS/JA3-Imitation (z. B. safari). Erfordert curl_cffi im Image; nicht setzen, sofern nicht verfügbar.
VIDEO_INGEST_BIN_DIRnicht gesetztVerzeichnis, das dem PATH des yt-dlp/ffmpeg-Kindprozesses vorangestellt wird, damit ein selbst bereitgestelltes yt-dlp (samt Deno-Runtime) außerhalb der eingebackenen Bin-Verzeichnisse zuerst gefunden wird. Das Backend-Image backt yt-dlp in den PATH ein, dort also nicht gesetzt lassen; auf einem Host- oder Dev-Rechner mit eigener Toolchain setzen.
VIDEO_INGEST_FFMPEG_LOCATION/usr/bin/ffmpegAbsoluter Pfad zu dem ffmpeg, das yt-dlp für die Nachbearbeitung nutzt (Untertitel-Konvertierung, Audio-Extraktion). Überschreiben, wenn ffmpeg woanders liegt — z. B. Homebrews /opt/homebrew/bin/ffmpeg auf einem macOS-Dev-Rechner.