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
{{ message }}
Repository navigation
V2: support registering SDK plugins after a Location has booted #34799
In the embedded SDK (@opencode-ai/sdk-next), plugins contributed through opencode.plugin(...) only apply to Locations booted after registration. packages/core/src/plugin/sdk.ts documents this: a plugin registered after a Location has booted only applies to Locations booted afterward, and embedders are expected to register at startup before creating Sessions.
For long-lived embedders this turns into a startup-ordering invariant that every host app has to enforce itself. The opencode-agent app uses one long-lived Location, so a plugin registered even slightly late (a persona agent, a native bridge tool) silently never applies for the whole process generation. We have hit this twice and now structure the app's entire startup around "register everything before any Session can possibly be created", which is fragile knowledge that will not survive a second embedder.
Request: allow plugin registration to take effect on already-booted Locations, at least for Sessions created after registration. That would make plugin() safe to call at any point in the host's lifecycle and remove the ordering requirement entirely. Dynamic registration also opens up hosts that want to add capabilities at runtime rather than only at boot.
Happy to discuss implementation. The relevant seam looks like SdkPlugins.Service plus PluginInternal's per-Location-boot ctx.plugin.add application in packages/core/src/plugin/internal.ts.
Hard evidence for this from the #35556 investigation, verified on origin/v2 at 175d200: a plugin registered through opencode.plugin(...) after a Location has booted never activates in that Location. A core-level test polls the plugin registry and materialized tools for 2 seconds after registration and sees nothing, then activates immediately after one config Event.Updated, which is the supervisor's only post-boot reload trigger. With LocationServiceMap's 60 minute idle TTL never expiring under continuous traffic, a long-lived host waits forever unless a config file happens to change.
So the current documented behavior is not just an ordering invariant for hosts to enforce, it is a silent no-op with no error and no recovery path in a steady-state process. Whichever way the policy lands (apply to booted Locations or reject loudly), silent success should stop being an outcome.
Fixed by #35576. SDK registration now publishes an unlocated sdk.plugin.updated event, and every already-booted Location reloads through the ordinary serialized generation path. Regression coverage verifies multi-Location reloads and isolation between independent embedded hosts. Closing this issue; the separate initial empty-generation race remains tracked in #35556.
Activity
kitlangton commentedon Jul 6, 2026
Hard evidence for this from the #35556 investigation, verified on origin/v2 at 175d200: a plugin registered through
opencode.plugin(...)after a Location has booted never activates in that Location. A core-level test polls the plugin registry and materialized tools for 2 seconds after registration and sees nothing, then activates immediately after one configEvent.Updated, which is the supervisor's only post-boot reload trigger. WithLocationServiceMap's 60 minute idle TTL never expiring under continuous traffic, a long-lived host waits forever unless a config file happens to change.So the current documented behavior is not just an ordering invariant for hosts to enforce, it is a silent no-op with no error and no recovery path in a steady-state process. Whichever way the policy lands (apply to booted Locations or reject loudly), silent success should stop being an outcome.
kitlangton commentedon Jul 6, 2026
Fixed by #35576. SDK registration now publishes an unlocated
sdk.plugin.updatedevent, and every already-booted Location reloads through the ordinary serialized generation path. Regression coverage verifies multi-Location reloads and isolation between independent embedded hosts. Closing this issue; the separate initial empty-generation race remains tracked in #35556.