mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-22 10:25:20 -06:00
d2afbd05ad
* refactor(plugin-sdk): replace API baselines with diffs * perf(plugin-sdk): bound API diff resources * fix(plugin-sdk): isolate API diff dependencies * fix(release): forward Plugin SDK acknowledgement * fix(release): enforce SDK acknowledgement on publish * chore: preserve generated-doc ignore policy * fix(release): freeze SDK API evidence before publish * fix(ci): satisfy SDK evidence guards * fix(release): bind complete SDK evidence * fix(release): authenticate plugin SDK evidence * fix(plugin-sdk): abort interrupted API diffs * test(ui): freeze page clock in background-tasks rail e2e The rail transcript is compared byte-for-byte across the detail-panel round-trip while it renders live relative ages; on slow CI runners the second boundary ticks between the two reads (11s -> 12s) and fails the equality assertion. Fix the page Date with Playwright setFixedTime while keeping timers running so the tasks.list polling assertions still hold. Repro: a 1.5s stall between the reads fails pre-fix with the exact CI diff and passes post-fix. * fix(scripts): drop unused export on dependency-evidence CLI main Knip's workflow scan re-roots script references after an actions/checkout step that sets path:, so the new trusted-tooling checkout in openclaw-npm-release.yml stops marking this CLI as a workflow entry and its exported main() surfaces as an unused export in check-dependencies. Nothing imports main; the module invokes it through its own entry guard, so the export keyword was dead surface either way. --------- Co-authored-by: Peter Steinberger <steipete@gmail.com>
6.0 KiB
6.0 KiB
Plugin SDK Boundary
This directory is the public contract between plugins and core. Changes here can affect bundled plugins and third-party plugins.
Source Of Truth
- Docs:
docs/plugins/sdk-overview.mddocs/plugins/sdk-entrypoints.mddocs/plugins/sdk-runtime.mddocs/plugins/sdk-migration.mddocs/plugins/architecture.md
- Definition files:
package.jsonscripts/lib/plugin-sdk-entrypoints.jsonscripts/lib/plugin-sdk-entries.mtssrc/plugin-sdk/api-baseline.tssrc/plugin-sdk/plugin-entry.tssrc/plugin-sdk/core.tssrc/plugin-sdk/provider-entry.ts
Boundary Rules
- Host loads plugins; plugins should not reach through the SDK into arbitrary host internals.
- Prefer a small versioned host/kernel seam plus narrow documented SDK entrypoints over broad convenience barrels.
- Prefer narrow, purpose-built subpaths over broad convenience re-exports.
- Do not expose implementation convenience from
src/channels/**,src/agents/**,src/plugins/**, or other internals unless you are intentionally promoting a supported public contract. - Keep public SDK entrypoints cheap at module load. If a helper is only needed
on async paths such as send, monitor, probe, directory-live, login, or setup,
prefer a narrow
*.runtimesubpath over re-exporting it through a broad SDK barrel that hot channel entrypoints import on startup. - Keep SDK facades acyclic. Do not add back-edge re-exports that route a lightweight contract file back through heavier policy or runtime modules.
- Do not mix static and dynamic imports for the same runtime surface when shaping SDK seams. If a surface must stay lazy, keep the eager side on a light contract file and the deferred side on a dedicated runtime subpath.
- Prefer
api.runtimeor a focused SDK facade over telling extensions to reach into host internals directly. - When core or tests need bundled plugin helpers, prefer the plugin package
api.tsorruntime-api.tsplus generic SDK capabilities. Do not add a provider-namedsrc/plugin-sdk/<id>.tsseam just to make core aware of a bundled channel's private helpers. - Resolver/facade loader tests are the exception to broad source API coverage:
use generated tiny plugin fixtures for
api.js/runtime-api.jsfallback behavior. Do not point those tests at real bundled plugin source APIs. - For provider work, prefer family-level seams over provider-specific seams. Shared helpers should describe a reusable behavior such as replay policy, tool-schema compat, payload normalization, stream-wrapper composition, or transport decoration. Avoid adding a new SDK export that only wraps one provider's local implementation unless there is already a second consumer.
- Prefer named helpers over raw options objects when the options encode a stable contract. Example: export a helper for "OpenAI-style Anthropic tool payload compat" instead of making every plugin pass the same mode flags.
- Keep transport/runtime policy and plugin-facing helpers aligned. If the same behavior is used in plugin registration and in core runtime paths, expose one shared helper instead of letting the two paths drift.
- SDK subpaths should help callers resolve one capability or runtime need at a time. Do not grow new surfaces that require broad runtime registry access as the default path.
- If a proposed SDK export mainly exists to let setup/config/control-plane code execute plugin runtime, that is usually a boundary smell. Prefer metadata or descriptor-driven control-plane seams first.
Versioned Required Capabilities
- Always: when a shipped Plugin SDK parameter contract gains required host authority, introduce a versioned type that requires it. Keep the legacy type source-compatible for its documented deprecation window, and migrate every bundled/internal caller in the same change.
- Always: keep host capabilities generic and closure-bound. Bind every exposed tool, preparer, callback, approval operation, and native-action surface; retained copies must fail after owner or capability closure, including closure during awaited policy work.
- Never: treat legacy optionality as a capability-free runtime path, reconstruct host authority inside a plugin, or add provider-specific authority to the generic contract.
- Never: hand-edit generated SDK baselines, declarations, hashes, or budgets. Regenerate them canonically.
- Ask first: obtain SDK and security owner acceptance before shortening a compatibility window, making a shipped type source-incompatible, or widening a capability’s trust, authority, or persistence boundary.
Verification
- If you touch SDK seams that affect lazy loading, hot channel entrypoints, or
bundled plugin import topology, run
pnpm build. - If the change can alter bundled channel startup cost, also run the isolated
entrypoint profiler for the affected plugin:
OPENCLAW_LOCAL_CHECK=0 node --import tsx scripts/profile-extension-memory.mts --extension <id> --skip-combined --concurrency 1
Expanding The Boundary
- SDK surface is too large. Do not add compat barrels, aliases, or fallback exports for convenience. Replace old entrypoints when cleaner.
- Public third-party API is the only compat exception: document/version breaks, migrate ALL bundled/internal plugins first, then aggressively deprecate unused exports.
- When adding or changing a public subpath, keep these aligned:
- docs in
docs/plugins/* scripts/lib/plugin-sdk-entrypoints.jsonscripts/lib/plugin-sdk-entries.mtspackage.jsonexports- API diff and export checks
- docs in
- If a bundled channel/helper need crosses package boundaries, first ask
whether the need is truly generic. If yes, add a narrow generic subpath. If
not, keep it plugin-local through
api.ts/runtime-api.ts. - When expanding provider-facing seams, update or add the matching narrow tests that lock the contract: Plugin SDK diff/export checks for public subpaths and the most direct provider/plugin tests for the behavior you are centralizing.
- Breaking removals or renames are major-version work, not drive-by cleanup.