This'll probably be a familiar idea to most people as I think it's been raised/mentioned in a few contexts now. When this was raised previously it was closed because it was too broad, presumably as it was too difficult to see how our needs might be met for the various examples given, so I'd like to take a different approach and outline a solution design for how I believe IDE extensions could be implemented.
Rather than adding IDE specific functionality to RootSchema (which should be decoupled), the JadeSchema should export a package which contains the classes/interfaces needed to implement extensions.
As extensions should operate in their own sandbox, any classes created or methods invoked should be invoke in context of their associated schema by initializing the required application context dynamically when needed (depends on implementing these improvements).
On startup of the IDE, it'd retrieve all implementors of the main extension interface which would act as a facade (it could just have type methods rather than needing to be instantiated), let's call this IJadeExtensionFacade.
The facade interface would define methods to initialize/finalize the extension on startup/shutdown of the IDE. The initialize method would be supplied with a controller/facade implemented by the IDE, one of which would be instantiated to represent each extension, let's call this JadeExtension. The properties defined by this would be populated during IJadeExtensionFacade::initialize to describe the extension (name, icon, author, version, enabled by default, etc). The methods implemented/exposed by JadeExtension would provide the ability to register components associated with the extension.
Fundamentally, there's two kinds of components, both of which could have a name, description & icon.
These would be instantiated by the extension and supplied when registered. They'd implement an interface, let's say JadeExtensionCommand with methods to retrieve it's details (name, description & icon), to execute the command when invoked, and to check if it should currently be visible/enabled.
Commands could be invoked via a toolbar button or menu item, which would be implied by how it's registered. For toolbar commands, they'd be registered in association with a named toolbar to group it with other commands (which could span other extensions). For menu commands, they'd be registered in association with a menu item path, where the root element would refer to an IDE form class and menu item in relation to which the menu item needs to be added.
These could also be referred to as utilities, which can be docked at the sides of the IDE (in portrait and/or landscape modes). Like Visual Studio, we should be able to switch between multiple utilities using tabs, or drag them so they're shown side-by-side.
These would inherit from a Control class and implement an interface, let's say JadeExtensionWindow. Unlike commands, the registration should be handled by supplying the class rather than being instantiated upfront. The IDE would instantiate these when required to add them to the main IDE form (and parent dock bar control to position them appropriately).
The interface for these would provide methods to retrieve it's details, the name/icon in particular would be used to show a header appropriately above the control. Methods would also be needed to load, queryUnload, unload & resize the window (as it may need to reposition its internal controls).
To refresh/adapt to the changing context in the IDE, the extension would need to be notified when schema entities are selected & subsequently deselected (probably just need to cover the basic ones like classes and features that can be selected in the class browser). Ideally, there'd also be a way to query whether or not the entity can be deselected before switching to something else (may possibly have changes to save), but this could also be handled via the queryUnload method referred to above for JadeExtensionWindow.
Rather than implementing methods for this purpose on the facade directly, it'd be better to define a method to retrieve a provider of a given interface (which may or may not be implemented by the extension). This could then be used to retrieve other interfaces/providers which may be introduced in future without needing to change the facade interface.