Plugin-Plattform
Wie Owlat erweitert wird: ein validiertes Manifest, ein Capability-Modell und drei Ausführungsstufen.
Die Variationspunkte von Owlat — Versandtransporte, Agentenschritte, Entwurfsstrategien, Autonomie-Gates, Automatisierungen, Webhook-Events, Import-Provider, Crons, Navigation, Einstellungen — sind alle über Plugins erreichbar. Ein Plugin ist ein npm-Paket, das ein validiertes Manifest exportiert und optional statische Module hinter den Verträgen aus @owlat/plugin-kit.
Die Plattform hat drei bewusst gewählte Eigenschaften:
- Ein Manifest. Alles, was der Host braucht, um ein Plugin zusammenzusetzen, zu berechtigen, per Flag zu steuern, zu budgetieren und darzustellen, sind Daten in
definePlugin(...). Die Validierung ruft niemals Plugin-Code auf. - Deklaration ist keine Befugnis. Ein Manifest fordert Capabilities an. Ein Betreiber gewährt sie. Beides wird zum Zeitpunkt jeder vom Host durchgeführten Operation erneut geprüft.
- Kein beliebiger Laufzeitcode. Nichts lädt zur Laufzeit JavaScript in Convex oder in den Browser. Gebündelter Code wird zur Build-Zeit komponiert; nicht vertrauenswürdiger Code läuft außerhalb des Prozesses (eine verbundene App) oder hinter einer Betriebssystemgrenze (ein Sandbox-Worker-Job).
@owlat/plugin-kit ist die öffentliche Kompatibilitätsgrenze und das einzige Paket, das ein Plugin-Autor importiert. Seine Major-Version ist die Kompatibilitätslinie — einzelne Contribution-Schnittstellen tragen keine eigenen Versionen. Vor 1.0 folgt es der Version des Owlat-Repositorys, und Verträge können sich zusammen mit der Anwendung brechend ändern.
Die drei Stufen
| Stufe | Was es ist | Installation | Vertrauen |
|---|---|---|---|
| 1 — Gebündeltes Plugin | Ein npm-Paket, das in plugins.config.ts gelistet und in die Convex- und Nuxt-Builds komponiert wird | Konfiguration bearbeiten → Codegen → Rebuild → Deployment | Dasselbe Vertrauen wie der eigene deployte Code des Betreibers. Capabilities und Flags reduzieren die Befugnis; sie sind keine Sandbox |
| 2 — Verbundene App | Ein externer HTTPS-Dienst mit plugin-gebundenen API-Keys und Webhooks, dazu ein spezifiziertes signiertes synchrones Hook-Protokoll, dessen Laufzeit-Adapter nicht mitgeliefert wird — siehe Verbundene Apps | Im Dashboard registrieren; sofort wirksam, ohne Rebuild | Nicht vertrauenswürdiger Netzwerk-Peer. Jede Antwort wird strikt validiert, bereinigt, geklemmt und begrenzt |
| 3 — Sandbox-Worker-Job | Ein spezifiziertes Worker-Protokoll hinter der code-worker-Betriebssystemgrenze; ein hostseitiger Enqueue-Adapter wird nicht mitgeliefert | Reserviert | Nicht vertrauenswürdiger Prozess. Keine ambienten Zugangsdaten, harte Obergrenzen für CPU/Speicher/Zeit, vom Host kontrolliertes Kommando |
Für jede Stufe gibt es ein gepflegtes Referenz-Plugin:
| Stufe | Referenz | Was es beisteuert |
|---|---|---|
| 1 | examples/plugins/escalation-guard | Einen Agentenschritt, eine Entwurfsstrategie, alle drei Automatisierungs-Registries, ein Webhook-Event sowie Navigations- und Einstellungseinträge — alles im selben Prozess |
| 2 | examples/plugins/slack-approvals | Ein rein einschränkendes Hold-Gate, das außerhalb des Prozesses über das signierte Hook-Protokoll bedient wird; überhaupt keine In-Process-Beiträge |
| 3 | examples/plugins/deliverability-lab | Einen Seed-List-Job auf der Sandbox-Queue, dazu ein Tier-1-Versand-Gate, Cron- und UI-Einträge sowie llm:invoke für host-vermittelte Generierung |
Ein Plugin kann mehrere Stufen gleichzeitig nutzen, so wie es das Deliverability Lab tut. examples/conformance treibt bei jedem Testlauf alle drei durch den echten Host, das Codegen und das CLI.
Anatomie eines Plugins
import { definePlugin } from '@owlat/plugin-kit';
export const helloPlugin = definePlugin({
id: 'hello-owlat',
version: '0.1.0',
capabilities: ['plugin-storage:read', 'plugin-storage:write'],
// Storage capabilities REQUIRE a flag: access must be revocable at runtime.
flag: { default: false },
});
| Feld | Bedeutung |
|---|---|
id | Kleingeschriebenes Kebab-Case, ≤ 64 Zeichen. Bildet den Namensraum für Flags, Storage, Ausgaben, Audit-Zuordnung und jede beigesteuerte Art |
version | Semantische Version |
capabilities | Angeforderte Host-Operationen, domain:action, exakte Übereinstimmung, höchstens 64 |
contributes | Reine Datendeskriptoren je Contribution-Bucket, höchstens 256 pro Bucket |
flag | { default, requiredEnvVars? }. Erforderlich, sobald das Plugin irgendetwas beisteuert, Plugin-Storage anfordert oder llm:invoke anfordert |
llmBudget | { dailyUsd }. Zusammen mit llm:invoke erforderlich; eine harte Obergrenze pro UTC-Tag |
component | Ein bedingungsunabhängiger Convex-Component-Export, installiert unter einem injektiven plugin_<id>-Namensraum |
settingsSchema | Deklaratives Betreiberformular; der Host rendert, validiert und redigiert es |
Wie ein gebündeltes Plugin in die Produktion gelangt
- Der Paketname wird der eingecheckten
plugins.config.tsim Wurzelverzeichnis hinzugefügt. bun run plugins:codegen(oderowlat-plugins codegen) prüft Identität, Lockfile-Integrität und Realpath-Eingrenzung des installierten Pakets, importiert ausschließlich dessen Manifest-Einstiegspunkt, validiert einen unveränderlichen Snapshot und schreibt die eingecheckten Convex- und Nuxt-Kompositionsdateien, sortiert nach Manifest-ID.- Builds und CI führen
bun run plugins:checkaus, sodass eine veraltete oder ungültige Komposition den Build fail-closed scheitern lässt. - Das Deployment wird neu gebaut. Das Feature-Flag des Plugins startet mit seinem deklarierten Standardwert — normalerweise
false—, sodass nichts läuft, bis ein Betreiber es aktiviert und Capabilities gewährt.
Der Code eines gebündelten Plugins läuft in Owlats eigenen Prozessen. Capability-Deklarationen, Gewährungen, Flags und host-vermittelte Dienste reduzieren, was ein gebündeltes Plugin erreichen kann, und machen seine Aktionen zuordenbar — sie schließen feindlichen Code nicht ein. Alles, dem Sie nicht vollständig vertrauen, gehört in eine verbundene App (Stufe 2) oder einen Sandbox-Job (Stufe 3).
Paketübersicht
| Paket | Rolle |
|---|---|
packages/plugin-kit | Öffentliche Verträge: definePlugin, Capability-Konstanten, jeder Contribution-Typ. Das einzige Paket, das ein Plugin importiert |
packages/plugin-host | Privater, laufzeitneutraler Durchsetzungskern, den sich Convex und Nuxt teilen: Capability-Prüfungen, Flags, Reihenfolge, Gate-Ergebnisse, Policy für nicht vertrauenswürdigen Text |
packages/plugin-codegen | Build-Werkzeug, dem der einzige Kompositionspunkt und die generierten Kataloge/Registries gehören |
packages/plugin-cli | owlat-plugins — create, add, remove, codegen, dev |
examples/plugins/* | Gepflegte Referenz-Plugins, die die echten Contribution-Punkte durchspielen |
examples/conformance | Die Konformitätsgalerie: Lifecycle-Suites (install/add/remove/disable/upgrade) und Full-Pipeline-Replay-Suites über diesen Referenzen, dazu der Paritätsnachweis für Plugin-Provider — ein Fixture-ESP-Bundle, das durch die ausgelieferten Module für Routing, Dispatch, Messung, Return-Path und Zugangsdatenformulare getrieben wird |
Weiterlesen
- Ein Plugin bauen — Gerüst, Manifest, Module, Tests, Ausliefern
- Contribution-Referenz — jeder Bucket, seine Capability und seine Host-Semantik
- Capabilities & Vertrauen — das Berechtigungsmodell und die Invarianten, die ein Plugin niemals aufweichen kann
- Installieren & Betreiben — der Lebenszyklus aus Betreibersicht
- Verbundene Apps und Sandbox-Jobs
- Fehlerbehebung
Architekturentscheidungen: ADR-0049 (Plattformvertrag), ADR-0050 (Entwurfsstrategien), ADR-0051 (geordnete Autonomie-Gates), ADR-0052 (verbundene Apps und signierte Hooks), ADR-0053 (Sandbox-Plugin-Jobs).