ctx.getExtension stable
Consume another extension's published API — the mechanism that lets features live outside core (git, terminal, themes) yet expose capabilities to other extensions. This is how "first-party = third-party" works in practice.
ctx.getExtension<API>(id: string): ExtensionHandle<API> | undefinedExample
// consume the git extension's API, tolerating its absence
const git = ctx.getExtension<GitAPI>("silo.git");
if (git?.active && git.api) {
const status = await git.api.status(cwd);
}Returns undefined if no extension with that id is known. Even when known, its api is undefined until that extension has activated — so always handle absence: the provider may be disabled or activate after you. Call getExtension at use time, not inside your own activate.
Publishing an API
The other side of the mechanism: return an object from your activate and it becomes your published API. Nothing else about the extension is required — activate can register zero UI and still be a complete, useful extension; see Extension-to-extension APIs for a worked headless example.
export const extension: Extension<GitAPI> = {
id: "silo.git",
activate(ctx): GitAPI {
return { status: (cwd) => /* … */ };
},
};The <API> generic here is compile-time only — getExtension resolves by a plain string id at runtime, so a consumer's type safety depends entirely on you publishing real types for them to import. Ship your API's types as their own npm package — @silo-code/git-api is the reference example — rather than bundling them into the extension itself; see Extension-to-extension APIs for the full pattern (package shape, devDependency + external, why a hand-copied interface isn't enough).
Types
ExtensionHandle · Extension (its activate return is the API).