A Plugin is a runtime unit, not an npm package
In Cordis, a Plugin is a runtime unit mounted into a Context with its own lifecycle. An npm package may export one or more Plugins, or it may only carry a Bundle patch. Separating packages, Plugins, and distribution units is essential to understanding DSH.
A Plugin can be a function with apply(ctx) or a class extending Service. Cordis creates a fiber for every mount and tracks its configuration, dependencies, state, and cleanup. Features therefore do not have to remain permanently attached to one global process.
Context is a service resolver
A Context holds the services visible in the current scope. Plugins find capabilities through stable ctx keys such as ctx.tools, ctx.llm, ctx.sessions, and ctx.agents instead of importing a concrete implementation.
A Service provides a named API on the Context. Consumers depend on that name and interface, so replacing a model adapter, filesystem backend, or subagent provider does not require rewriting every consumer.
export class AgentLoop extends Service {
static inject = ["agents", "sessions", "llm", "tools", "systemPrompt"];
constructor(ctx: Context, config: Config) {
super(ctx, "agentLoop");
// The loop consumes services through ctx instead of importing providers.
}
}inject expresses dependencies, not manual startup order
A Plugin declares required services with inject. Its fiber remains pending until those services exist, then activates. Cordis can coordinate the lifecycle again when a service disappears or its implementation changes.
The visual order of rows in cordis.patch.yml therefore helps people read and compose the tree; it is not a manual startup sequence. Runtime activation follows service availability and explicit dependencies.
Every registration is a reversible effect
Tools, prompt sections, providers, event listeners, and background resources enter the runtime through ctx.effect(), ctx.on(), or registration APIs that return a disposer. Each registration belongs to the fiber that created it.
When a Plugin unloads, Cordis awaits and runs disposers in reverse order. Hot updates, configuration reloads, test isolation, and application shutdown therefore share one ownership model instead of inventing separate teardown paths.
ctx.tools.register(tool);
ctx.on("tools/result", observeResult);
ctx.effect(() => {
const stop = startWorker();
return () => stop();
});What everything is a plugin really means
DSH does not stop at peripheral tools. Model adapters, the tool registry, session log, system prompt, agent registry, and even the default agent loop are mounted in the same Cordis tree.
Extensions can usually mount behavior beside existing Plugins or replace one service provider instead of modifying a privileged, irreplaceable core. The configuration describes the application architecture itself.