Skip to content

Cordis

Five rules of the baseplate

Cordis is the vendored plugin framework. dsh has no kernel to patch; extend it by mounting a plugin beside the others.

  1. 1

    A plugin is one brick

    A brick may be a function or a Service subclass. It has a name, apply(ctx), and sometimes an inject list.

    A plugin implements Service. Function plugins export inject + apply(ctx); class plugins call super(ctx, name) in the constructor and register immediately.

  2. 2

    Context is the shared shelf

    A teacher puts the brain on the shelf; everyone else takes ctx.llm without importing that teacher.

    Context is the service repository. Stable keys include ctx.tools, ctx.llm, and ctx.sessions. Depend on service names, not implementations.

  3. 3

    inject waits for friends

    Say ‘I need the tool cabinet,’ and the baseplate waits until it appears before activating you. No manual queue required.

    Load order is expressed through service requirements, not manual boot sequencing.

  4. 4

    Events are ways to call out

    Broadcast, pass a note, work together, or take turns—four dispatch contracts.

    emit / waterfall / parallel / serial. Waterfall is around-middleware: listeners receive (...args, next).

  5. 5

    Every registration is reversible

    Remove the brick and everything it placed on the shelf or listened to disappears.

    Registrations use ctx.effect() or ctx.on() and unwind on fiber disposal. There is no privileged kernel to patch.

Four dispatch modes

ModeAwait?OrderReturnPlain-language version
emitNoObserve in registration orderNoneBroadcast: listeners may observe but cannot veto.
waterfallNo (but wraps)Onion, outside inYesCall next() to pass the paper inward; otherwise you take control.
parallelYesRun togetherNoneThe whole class works at once, such as flushing the journal to disk.
serialYesOne after anotherYesTake turns speaking, with no next(). turn-stopping uses this mode.

A waterfall is an onion

Outer listener: rewrite or short-circuit
Middle listener: call next() to continue
Core: the code that does the work

Skip next() and you take control. agent/pre-step, agent/request, llm/stream, and tools/* all use this onion.

A locker is not a water tap

scope · locker

One locker per person keeps coats on the right hook. It is not a fence.

dsh-scope partitions registration layers by agent. Use agent.ctx to scope a registration to one agent.

isolate · its own tap

This classroom's tap is separate from the lobby's. It may have another same-named service.

isolate(name, label) gives a child Context another same-named service. Agent presets use it to change outfits.