2.3 KiB
RFC: Microkernel — extension via Cordis event taxonomy, one concrete loop
Status: implemented
Problem
The product principle is "everything is a plugin": hooks, /goal, /loop, dynamic workflows, compaction, sandboxing, permissions, UI, persistence, MCP, skills must all be writable as plugins without modifying the core.
Decision
Pure Cordis event taxonomy. The loop's extension seams are typed events with deliberate dispatch modes:
- waterfall (around-middleware) where plugins transform, veto, or wrap:
agent/prompt-submit,agent/request,agent/step-result,agent/turn-continuation,tools/pre-execute,tools/execute,tools/post-execute,llm/stream,system-prompt/assemble. - serial (awaited in listener order; a bail value stops later listeners) for ordered checkpoints: every
agent/pre-steplistener runs when all abstain, while the first stop returned fromagent/turn-stopmakes the terminal decision final. - parallel (awaited fan-out) where every listener must get an independent chance: the
session/flushdurability checkpoint. - emit (synchronous fire-and-forget) for notifications: turn/step boundaries, stream chunks, lifecycle, errors, and the contained immutable
tools/resultobservation.
The event vocabulary lives in interface packages (dsh-agent declares the agent/* events); @deepseek-ai/dsh-agent-loop is the only concrete loop plugin and is itself swappable — nothing outside it may depend on it.
Alternatives considered
A purpose-built middleware stack (koa-compose style) and an explicit phase state machine plugins insert into — both would re-implement dispatch, disposal, and reload semantics that Cordis's native event system already provides; as Cordis effects, listeners get HMR and disposal for free.
Consequences
- Every MVP feature maps to a listener (the feature → mechanism map is the proof obligation, kept current).
- HMR and disposal come free: listeners and registrations are Cordis effects.
- Waterfall semantics (call
next()or short-circuit) are non-obvious and must be taught — documented in AGENTS.md and covered by composition tests. - The loop must be defensive: plugin exceptions are contained at turn level, steering from any seam is never stranded (regression-tested).