Detection & capabilities
Know at runtime what's installed, authenticated, native, or emulated
Detecting providers
import { detectProviders } from "@klein-kit/core";
const statuses = await detectProviders(); // or detectProviders(["codex", "claude"])detectProviders is side-effect free, safe to call at startup, and never throws — problems become installed: false plus notes.
interface ProviderStatus {
provider: ProviderId;
installed: boolean;
path?: string;
version?: string;
authenticated?: boolean; // undefined = couldn't determine without side effects
authMethod?: string; // "chatgpt", "subscription", "api-key", "stored", "environment", …
notes?: string[];
}Claude deliberately reports authenticated: undefined — the reliable check would consume quota.
Capabilities
Fidelity over lowest common denominator: instead of hiding provider differences, each session tells you what's real.
type Support = "native" | "emulated" | "none";
interface ProviderCapabilities {
plans: Support; todos: Support;
permissionCallback: Support; permissionModes: Support;
resume: Support; subagents: Support;
reasoningControls: Support; usage: Support;
reasoningStream: Support; interrupt: Support;
mcp: Support; midSessionModelChange: Support;
}if (session.capabilities.todos === "none") hideTodoPanel();
if (session.capabilities.midSessionModelChange !== "none") showModelPicker();The full per-provider matrix is on the Providers page.
Escape hatches
event.raw— every event carries the untouched native payload.session.raw<T>()— the underlying protocol client, for provider-only features: Codex's JSON-RPC connection, Claude's child process +sendControlRequest, opencode's HTTP client, Pi's RPC handle.providerOptions— passed to the adapter untranslated, per session or per turn.
Custom adapters
The adapter SPI is public — register your own provider:
import { registerAdapter, BaseSession, type ProviderAdapter } from "@klein-kit/core";
registerAdapter("myagent" as ProviderId, async () => myAdapter);An adapter implements id, capabilities, detect(), and createSession(). Subclass BaseSession and implement the five native hooks (sendNative, respondNative, interruptNative, closeNative, raw); queueing, turn lifecycle, task-state folding, and event fan-out come for free.