You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
OpenClaw already has a real plugin-first kernel. The strongest parts are:
manifest-first discovery and activation planning
registry-based capability registration
typed hooks
shared channel/provider kernels
session workflow state seams
The core problem is not "plugins are the wrong direction." The core problem is
that the current public SDK surface mixes too many classes of API at the same
level:
declaration-time registration
setup/bootstrap-only discovery
live session/workflow control
runtime helper facades
bundled-only authority seams
compatibility and migration debt
So the right cleanup is not to smash everything into one generic API. The right
cleanup is:
classify the whole shipped surface from one source of truth
make lifecycle semantics explicit
make grouped families canonical
freeze and de-emphasize wide barrels and compat shims
internalize bundled-only and semi-internal subsystems where the repo already
treats them as special
This preserves features while reducing accidental permanent API.
What This Audit Covered
the full OpenClawPluginApi shape in src/plugins/types.ts
the root openclaw package export map for openclaw/plugin-sdk/*
docs and generated-baseline surfaces
repo-wide import usage across extensions, tests, docs, and runtime code
internal lifecycle enforcement around post-register callability
compatibility and plugin-owned/public classifications
This was informed by direct repo inspection plus four independent read-only
subagent passes over:
lifecycle and role classification
export/publicness drift
architectural taxonomy and boundaries
real in-repo usage and blast radius
Current Surface Snapshot
Counts
OpenClawPluginApi currently exposes 79 top-level fields/methods.
Root package.json currently publishes 305 exports total.
Rough file-family distribution of those non-test plugin-sdk modules:
131 include runtime
59 are channel-related
40 are provider-related
23 are test-ish/testing/contract/mocks
21 are memory-related
4 are compat/legacy-marked
255 unique plugin-sdk/* subpaths are explicitly mentioned in docs/plugins/sdk-subpaths.md.
48 shipped plugin-sdk exports are not catalogued there.
39 shipped plugin-sdk exports had zero in-repo imports in the static scan.
Strongest Stable Usage
The highest-blast-radius shipped subpaths in production-ish extension code are:
text-runtime
config-types
runtime-env
plugin-entry
provider-model-shared
channel-contract
channel-message
routing
provider-auth
provider-http
The highest-use consumer families are channel/plugin stacks like:
discord
telegram
slack
matrix
whatsapp
That means many apparently generic helpers are really carrying mature
channel-stack behavior and should not be casually churned.
Low-Risk Consolidation Signals
The new grouped aliases in api.session.*, api.agent.*, api.runContext.*, and api.lifecycle.* are basically docs/tests/facade-only
today, with no meaningful in-repo author adoption yet.
openclaw/plugin-sdk/compat is effectively dead in-repo.
the bare root openclaw/plugin-sdk import behaves mostly like a migration or
test surface, not a healthy primary authoring surface
many host-workflow/session-control registrars are still mostly fixture and
contract-level seams, not widely used bundled-plugin author APIs
Those are exactly the conditions that make canonicalization and de-emphasis safe.
Core Diagnosis
Two structural problems explain most of the SDK sprawl.
1. Publication-by-list, not publication-by-policy
The public package contract is mechanically generated from the entrypoint list.
That makes it easy to ship new subpaths, but harder to keep "exported",
"documented", "supported", "compat-only", and "bundled-only" aligned.
Today there are multiple overlapping policy layers:
the root package export map
plugin-sdk-entrypoints.json
plugin-sdk/entrypoints.ts classification arrays
docs/plugins/sdk-subpaths.md
pluginSdkDocMetadata
boundary/contract tests
That is workable, but it is not one authoritative support model.
2. Lifecycle flattening
OpenClawPluginApi currently flattens at least four different kinds of API into
one top-level type:
declaration-time registration
setup-only/bootstrap discovery
live workflow/session control
trusted in-process runtime power
That flattening makes the API feel broader and more inconsistent than it needs
to be. It also explains why reviewer discomfort shows up as "the API keeps
expanding" even when some of the seams are individually valid.
Architectural Thesis
The long-term SDK should read as a small number of explicit families:
kernel
capabilities
workflow
client-contrib
runtime-facades
compat
bundled-internal
memory
The first four are the plugin-first public platform.
The last four need much stronger curation and labeling.
Target Taxonomy
flowchart TD
A["OpenClaw Plugin SDK Today"] --> B["Flat OpenClawPluginApi"]
A --> C["302 shipped plugin-sdk subpaths"]
B --> D["declaration-time registration"]
B --> E["setup/bootstrap-only seams"]
B --> F["host workflow and session control"]
B --> G["trusted runtime escape hatch"]
H["Target Model"] --> I["kernel"]
H --> J["capabilities"]
H --> K["workflow"]
H --> L["client-contrib"]
H --> M["runtime-facades"]
H --> N["compat"]
H --> O["bundled-internal"]
H --> P["memory"]
K --> Q["session.state"]
K --> R["session.workflow"]
K --> S["agent.events"]
K --> T["runContext"]
K --> U["lifecycle"]
L --> V["session.controls"]
Loading
Kernel
Keep as the architectural center:
manifest/discovery
entrypoints
activation planning
registration modes
narrow import discipline
This is the cleanest and healthiest part of the system.
Capabilities
These are the true foundational public primitives:
provider registration
channel registration
tool registration
command registration
route registration
CLI registration
service registration
discovery registration
These should stay public and canonical.
Workflow
These are real plugin-first app behavior primitives:
session extensions
next-turn injections
run context
lifecycle cleanup
event subscription/emission
scheduler ownership and session workflow helpers
These should stay public, but the grouped family shape should become the main
story.
Client-Contrib
These are useful, but they are not kernel primitives:
control UI descriptors
typed session actions
They should read as client-extension contracts, not as generic platform verbs.
Runtime-Facades
These should remain narrow and cheap:
channel/provider/runtime helper subpaths
utility leaves used by bundled and external plugins
They should not become a backdoor to host internals or another broad pseudo-root
SDK.
Compat
These are transitional:
compat
testing
channel-runtime
infra-runtime
branded compatibility facades
legacy reply/runtime shims
They should remain supported where needed, but visibly not be peers of the
kernel.
Bundled-Internal
These are real seams, but they are not healthy third-party platform primitives:
trusted tool policy
agent tool result middleware
Codex app-server extension factories
host-owned authority surfaces
experimental agent-harness-level seams
They should be labeled and treated as advanced/bundled-native, not casually
public.
Memory
Memory needs special treatment. The exclusive capability idea is good, but much
of the current memory-host SDK family is still a semi-internal bridge dressed as
public SDK. This is the strongest whole-surface internalization candidate.
These should remain available, but the grouped family model should become
canonical:
api.session.state.*
api.session.workflow.*
api.session.controls.*
api.agent.events.*
api.runContext.*
api.lifecycle.*
Fold or Alias
registerHook(...) -> legacy alias to api.on(...)
registerNodeCliFeature(...) -> helper over registerCli(...)
registerMemoryPromptSection(...) -> alias to registerMemoryCapability(...)
registerMemoryFlushPlan(...) -> alias to registerMemoryCapability(...)
registerMemoryRuntime(...) -> alias to registerMemoryCapability(...)
flat host-workflow/control/run-context methods -> compatibility aliases over
grouped family entrypoints
Freeze and De-Emphasize
Do not keep growing these as primary design targets:
bare root openclaw/plugin-sdk
compat
testing
channel-runtime
infra-runtime
config-runtime
wide umbrellas like core, reply-runtime, media-runtime, text-runtime, agent-runtime, plugin-runtime
These can stay shipped, but should be treated as supported umbrellas or compat,
not as the best place for new API design.
Advanced / Bundled-Only / Internalize
Strong internalization or advanced-only candidates:
runtime
registerTrustedToolPolicy(...)
registerAgentToolResultMiddleware(...)
registerCodexAppServerExtensionFactory(...)
registerAgentHarness(...)
registerContextEngine(...)
registerCompactionProvider(...)
registerDetachedTaskRuntime(...)
session attachment and scheduled-turn authority seams, insofar as they depend
on host-owned trust/runtime lanes
the broad memory-core-host-* and memory-host-* entrypoint families until
they are truly package-owned and independently defensible as public SDK
Deprecate Harder
openclaw/plugin-sdk/compat
bare openclaw/plugin-sdk root import
branded facades that are explicitly transitional
wide reply/channel compat bridges where the repo already prefers narrower
leaves
Lifecycle Model
This needs to become explicit in code, docs, and tests.
Proposed Lifecycle Classes
declaration
registration-only, valid only during register(api)
setup_only
early discovery/bootstrap-only seams
late_call_live
may be called after register() closes through the guarded API
active_loaded_live
live only when a plugin is loaded/active and the host runtime is present
bundled_internal
trusted or authority-bearing seam not intended as ordinary third-party API
Important Current Inconsistencies
activate(api) is not a true second lifecycle phase; loader effectively
aliases it to register
only sendSessionAttachment, scheduleSessionTurn, and unscheduleSessionTurnsByTag are explicitly late-callable today
emitAgentEvent and run-context methods look like runtime handles, but they
are not generally treated as late-callable by the guarded loader path
registerConfigMigration and registerAutoEnableProbe sit on the main API
but are only meaningful in setup-only mode
registerCli and registerChannel have special wiring characteristics
some concerns exist as both entry-definition fields and runtime API methods,
which blurs declaration-only vs registrar semantics
This is why lifecycle metadata should be authoritative and loader-enforced.
Safe Start Order
Phase 0: Governance, not churn
Add one authoritative SDK surface manifest.
Each shipped export and each OpenClawPluginApi method should declare:
status: stable, supported_umbrella, compat, plugin_owned_public, experimental, bundled_internal, or internal_only
lifecycle class
docs class/category
owner, if plugin-owned or bundled-only
Generate these from that manifest:
root package exports
docs catalog
API baseline
boundary report
deprecation report
Freeze new broad barrels and new top-level live verbs.
This is the highest-value first step because it reduces future API sprawl
without breaking any current features.
Phase 1: Canonicalize the public story
Make grouped host-workflow families canonical in docs and examples.
Keep flat methods as compatibility aliases.
Make api.on(...) the canonical hook registration story.
Reclassify registerNodeCliFeature(...) as a CLI helper, not a peer
primitive.
Collapse the deprecated memory trio into registerMemoryCapability(...).
This is low-risk because repo adoption of the grouped families is still minimal.
Phase 2: Make lifecycle semantics real
Replace the current tiny post-register allowlist with authoritative method
lifecycle metadata.
Split setup-only surfaces from ordinary registration semantics in docs and
policy.
Clarify which surfaces are:
declarative
retained runtime handles
bundled-only authority seams
Phase 3: Export-surface cleanup
Review the undocumented exported subpaths first.
Decide one of:
document as intentional
classify as compat
internalize
Priority review set:
root plugin-sdk
compat
config-runtime
channel-runtime
sandbox
runtime-doctor
agent-harness-runtime
provider-stream-shared
channel-secret-basic-runtime
Internalize anything useful in-tree but not truly intended for external
plugin authors, using the same pattern the repo already uses for QA-only
surfaces.
Phase 4: Subsystem cleanup
Memory-host surface review and likely shrink/internalization
bundled facade review
channel/reply/runtime bridge cleanup
follow-on rationalization of wide umbrellas
What This Means for #80219 and #80229
#80219
#80219 should become the umbrella whole-surface issue, not just a note about
the four active PR seams. The current issue direction is good, but it should be
reframed as the architecture plan for:
whole-surface classification
lifecycle cleanup
public vs compat vs bundled-only policy
export and docs generation policy
#80229
#80229 should be framed as a valid Phase 1 slice, not as "the" Plugin SDK
cleanup.
Its best architectural value is:
grouped host-workflow aliases
narrow late-callability metadata
proof-backed session/workflow/media seams
That is real progress, but it only addresses one part of the whole SDK surface.
Explicit Non-Goals
do not collapse the SDK into one generic API
do not widen generic runtime.llm.complete(...) into the structured
media-understanding seam
do not remove compatibility shims before policy classification exists
do not rewrite high-blast-radius channel/provider helpers casually
do not treat bundled-only trust surfaces as healthy third-party primitives
Bottom Line
The highest-confidence architecture plan is:
keep manifest-first kernel and capability registration as the center
keep workflow/session seams, but group them and label them clearly
stop treating every exported helper as equal public platform API
separate stable public primitives from compat, bundled-only, and semi-internal
lanes
use one authoritative surface manifest to govern exports, docs, baselines, and
lifecycle policy
In one sentence:
OpenClaw should expand through fewer, better-grouped, better-labeled plugin
primitives, not through more flat top-level verbs and more mechanically
published SDK surface.
OpenClaw Plugin SDK Whole-Surface Architecture Plan
Date: 2026-05-10
Status: Whole-surface audit complete
Confidence: 95%+
Repo:
/Volumes/LEXAR/repos/openclaw-plugin-sdk-consolidationExecutive Summary
OpenClaw already has a real plugin-first kernel. The strongest parts are:
The core problem is not "plugins are the wrong direction." The core problem is
that the current public SDK surface mixes too many classes of API at the same
level:
So the right cleanup is not to smash everything into one generic API. The right
cleanup is:
treats them as special
This preserves features while reducing accidental permanent API.
What This Audit Covered
OpenClawPluginApishape insrc/plugins/types.tsopenclawpackage export map foropenclaw/plugin-sdk/*This was informed by direct repo inspection plus four independent read-only
subagent passes over:
Current Surface Snapshot
Counts
OpenClawPluginApicurrently exposes79top-level fields/methods.package.jsoncurrently publishes305exports total.302of those are./plugin-sdk*entrypoints.376non-testsrc/plugin-sdk/*.tsmodules exist in-tree.131includeruntime59are channel-related40are provider-related23are test-ish/testing/contract/mocks21are memory-related4are compat/legacy-marked255uniqueplugin-sdk/*subpaths are explicitly mentioned indocs/plugins/sdk-subpaths.md.48shipped plugin-sdk exports are not catalogued there.39shipped plugin-sdk exports had zero in-repo imports in the static scan.Strongest Stable Usage
The highest-blast-radius shipped subpaths in production-ish extension code are:
text-runtimeconfig-typesruntime-envplugin-entryprovider-model-sharedchannel-contractchannel-messageroutingprovider-authprovider-httpThe highest-use consumer families are channel/plugin stacks like:
discordtelegramslackmatrixwhatsappThat means many apparently generic helpers are really carrying mature
channel-stack behavior and should not be casually churned.
Low-Risk Consolidation Signals
api.session.*,api.agent.*,api.runContext.*, andapi.lifecycle.*are basically docs/tests/facade-onlytoday, with no meaningful in-repo author adoption yet.
openclaw/plugin-sdk/compatis effectively dead in-repo.openclaw/plugin-sdkimport behaves mostly like a migration ortest surface, not a healthy primary authoring surface
contract-level seams, not widely used bundled-plugin author APIs
Those are exactly the conditions that make canonicalization and de-emphasis safe.
Core Diagnosis
Two structural problems explain most of the SDK sprawl.
1. Publication-by-list, not publication-by-policy
The public package contract is mechanically generated from the entrypoint list.
That makes it easy to ship new subpaths, but harder to keep "exported",
"documented", "supported", "compat-only", and "bundled-only" aligned.
Today there are multiple overlapping policy layers:
plugin-sdk-entrypoints.jsonplugin-sdk/entrypoints.tsclassification arraysdocs/plugins/sdk-subpaths.mdpluginSdkDocMetadataThat is workable, but it is not one authoritative support model.
2. Lifecycle flattening
OpenClawPluginApicurrently flattens at least four different kinds of API intoone top-level type:
That flattening makes the API feel broader and more inconsistent than it needs
to be. It also explains why reviewer discomfort shows up as "the API keeps
expanding" even when some of the seams are individually valid.
Architectural Thesis
The long-term SDK should read as a small number of explicit families:
kernelcapabilitiesworkflowclient-contribruntime-facadescompatbundled-internalmemoryThe first four are the plugin-first public platform.
The last four need much stronger curation and labeling.
Target Taxonomy
flowchart TD A["OpenClaw Plugin SDK Today"] --> B["Flat OpenClawPluginApi"] A --> C["302 shipped plugin-sdk subpaths"] B --> D["declaration-time registration"] B --> E["setup/bootstrap-only seams"] B --> F["host workflow and session control"] B --> G["trusted runtime escape hatch"] H["Target Model"] --> I["kernel"] H --> J["capabilities"] H --> K["workflow"] H --> L["client-contrib"] H --> M["runtime-facades"] H --> N["compat"] H --> O["bundled-internal"] H --> P["memory"] K --> Q["session.state"] K --> R["session.workflow"] K --> S["agent.events"] K --> T["runContext"] K --> U["lifecycle"] L --> V["session.controls"]Kernel
Keep as the architectural center:
This is the cleanest and healthiest part of the system.
Capabilities
These are the true foundational public primitives:
These should stay public and canonical.
Workflow
These are real plugin-first app behavior primitives:
These should stay public, but the grouped family shape should become the main
story.
Client-Contrib
These are useful, but they are not kernel primitives:
They should read as client-extension contracts, not as generic platform verbs.
Runtime-Facades
These should remain narrow and cheap:
They should not become a backdoor to host internals or another broad pseudo-root
SDK.
Compat
These are transitional:
compattestingchannel-runtimeinfra-runtimeThey should remain supported where needed, but visibly not be peers of the
kernel.
Bundled-Internal
These are real seams, but they are not healthy third-party platform primitives:
They should be labeled and treated as advanced/bundled-native, not casually
public.
Memory
Memory needs special treatment. The exclusive capability idea is good, but much
of the current memory-host SDK family is still a semi-internal bridge dressed as
public SDK. This is the strongest whole-surface internalization candidate.
Whole-Surface Classification
Keep Public and Canonical
definePluginEntry(...)api.on(...)registerMemoryCapability(...)plugin-entry,config-types,routing,channel-contract,channel-message,provider-model-shared,provider-auth,provider-httpKeep Public but Reclassify as Families
registerSessionExtensionenqueueNextTurnInjectionregisterRuntimeLifecycleregisterAgentEventSubscriptionemitAgentEventsetRunContext/getRunContext/clearRunContextregisterSessionSchedulerJobregisterSessionActionregisterControlUiDescriptorsendSessionAttachmentscheduleSessionTurnunscheduleSessionTurnsByTagThese should remain available, but the grouped family model should become
canonical:
api.session.state.*api.session.workflow.*api.session.controls.*api.agent.events.*api.runContext.*api.lifecycle.*Fold or Alias
registerHook(...)-> legacy alias toapi.on(...)registerNodeCliFeature(...)-> helper overregisterCli(...)registerMemoryPromptSection(...)-> alias toregisterMemoryCapability(...)registerMemoryFlushPlan(...)-> alias toregisterMemoryCapability(...)registerMemoryRuntime(...)-> alias toregisterMemoryCapability(...)grouped family entrypoints
Freeze and De-Emphasize
Do not keep growing these as primary design targets:
openclaw/plugin-sdkcompattestingchannel-runtimeinfra-runtimeconfig-runtimecore,reply-runtime,media-runtime,text-runtime,agent-runtime,plugin-runtimeThese can stay shipped, but should be treated as supported umbrellas or compat,
not as the best place for new API design.
Advanced / Bundled-Only / Internalize
Strong internalization or advanced-only candidates:
runtimeregisterTrustedToolPolicy(...)registerAgentToolResultMiddleware(...)registerCodexAppServerExtensionFactory(...)registerAgentHarness(...)registerContextEngine(...)registerCompactionProvider(...)registerDetachedTaskRuntime(...)on host-owned trust/runtime lanes
memory-core-host-*andmemory-host-*entrypoint families untilthey are truly package-owned and independently defensible as public SDK
Deprecate Harder
openclaw/plugin-sdk/compatopenclaw/plugin-sdkroot importleaves
Lifecycle Model
This needs to become explicit in code, docs, and tests.
Proposed Lifecycle Classes
declarationregister(api)setup_onlylate_call_liveregister()closes through the guarded APIactive_loaded_livebundled_internalImportant Current Inconsistencies
activate(api)is not a true second lifecycle phase; loader effectivelyaliases it to
registersendSessionAttachment,scheduleSessionTurn, andunscheduleSessionTurnsByTagare explicitly late-callable todayemitAgentEventand run-context methods look like runtime handles, but theyare not generally treated as late-callable by the guarded loader path
registerConfigMigrationandregisterAutoEnableProbesit on the main APIbut are only meaningful in setup-only mode
registerCliandregisterChannelhave special wiring characteristicswhich blurs declaration-only vs registrar semantics
This is why lifecycle metadata should be authoritative and loader-enforced.
Safe Start Order
Phase 0: Governance, not churn
Add one authoritative SDK surface manifest.
Each shipped export and each
OpenClawPluginApimethod should declare:stable,supported_umbrella,compat,plugin_owned_public,experimental,bundled_internal, orinternal_onlyGenerate these from that manifest:
Freeze new broad barrels and new top-level live verbs.
This is the highest-value first step because it reduces future API sprawl
without breaking any current features.
Phase 1: Canonicalize the public story
api.on(...)the canonical hook registration story.registerNodeCliFeature(...)as a CLI helper, not a peerprimitive.
registerMemoryCapability(...).This is low-risk because repo adoption of the grouped families is still minimal.
Phase 2: Make lifecycle semantics real
lifecycle metadata.
policy.
Phase 3: Export-surface cleanup
Priority review set:
plugin-sdkcompatconfig-runtimechannel-runtimesandboxruntime-doctoragent-harness-runtimeprovider-stream-sharedchannel-secret-basic-runtimeplugin authors, using the same pattern the repo already uses for QA-only
surfaces.
Phase 4: Subsystem cleanup
What This Means for
#80219and#80229#80219#80219should become the umbrella whole-surface issue, not just a note aboutthe four active PR seams. The current issue direction is good, but it should be
reframed as the architecture plan for:
#80229#80229should be framed as a valid Phase 1 slice, not as "the" Plugin SDKcleanup.
Its best architectural value is:
That is real progress, but it only addresses one part of the whole SDK surface.
Explicit Non-Goals
runtime.llm.complete(...)into the structuredmedia-understanding seam
Bottom Line
The highest-confidence architecture plan is:
lanes
lifecycle policy
In one sentence:
OpenClaw should expand through fewer, better-grouped, better-labeled plugin
primitives, not through more flat top-level verbs and more mechanically
published SDK surface.