Skip to content

core: move plugin intialisation to config layer override#22620

Merged
Brendonovich merged 4 commits intodevfrom
brendan/lazy-init-plugins
Apr 15, 2026
Merged

core: move plugin intialisation to config layer override#22620
Brendonovich merged 4 commits intodevfrom
brendan/lazy-init-plugins

Conversation

@Brendonovich
Copy link
Copy Markdown
Member

As noted in #22547 we need to initialise the Plugin service before any others as they are able to modify the config. This PR removes the plugin initialisation from the bootstrap flow's hot path and into the Config service methods themselves by overriding the Config layer implementation to ensure the Plugin service is always inited first.
All of this is in order to get the Config init out of the hot path as it can take a while, especially for OC Console users because of the network requests involved. This lets us tune the hell out of Desktop startup performance as a bunch of important data (session list, message parts) don't require loading the config.

@Brendonovich Brendonovich requested a review from kitlangton April 15, 2026 13:22
@kitlangton
Copy link
Copy Markdown
Contributor

G'day legends,

Had a squiz at this PR and reckon the approach is spot on — getting plugin init out of the hot path is a ripper idea for startup perf. No dramas there.

Just wanted to chuck in a suggestion: you could use Layer.effect instead of Layer.unwrap + Layer.succeed here. It's a bit more straightforward — does the same thing but collapses two steps into one:

const ConfigWithPluginPriority = Layer.effect(
  Config.Service,
  Effect.gen(function* () {
    const config = yield* Config.Service
    const plugin = yield* Plugin.Service
    return {
      ...config,
      get: () => Effect.andThen(plugin.init(), config.get),
      getGlobal: () => Effect.andThen(plugin.init(), config.getGlobal),
      getConsoleState: () => Effect.andThen(plugin.init(), config.getConsoleState),
    }
  }),
).pipe(Layer.provide(Layer.merge(Plugin.defaultLayer, Config.defaultLayer)))

The gist of it:

  • Layer.effect is the bread and butter for "build a service value from context" — Layer.unwrap is more for choosing between different layers at runtime, so it's a bit of a sledgehammer here
  • Layer.provide instead of Layer.provideMerge** — since Plugin.defaultLayer is already sitting in AppLayer on its own, no need to pass it through via provideMerge
  • Knocks out the intermediate Layer.succeed entirely

She'll be right either way — functionally it's the same — but Layer.effect is the more conventional pattern for this kind of service decoration and reads a bit cleaner.

Cheers,
Kit's OpenCode instance 🤙

@Brendonovich Brendonovich enabled auto-merge (squash) April 15, 2026 22:37
@Brendonovich Brendonovich merged commit 916131b into dev Apr 15, 2026
10 checks passed
@Brendonovich Brendonovich deleted the brendan/lazy-init-plugins branch April 15, 2026 22:44
kitlangton added a commit that referenced this pull request Apr 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants