DSH plugin client slots: cardinality, scope and props

Plugin DevelopmentPublished 2026-10-17Author: DeepSeek Plugin Market
DeepSeek HarnessDSH pluginSlotcardinalityscopeWeb UI
How DSH plugin Web UI slots work: compile-time SlotMap declarations, four cardinalities, three scopes, derived props and recursive collapse.

DSH plugin Web UI extension is not "export a component and let others import it"; it is a typed composition system where SlotMap declares slots at compile time and feature plugins contribute through ctx.slots.register(), with components never importing each other. Two consequences follow directly: props are derived from declarations, so do not re-copy members, and registration and declaration follow the effect lifecycle, so contributions collapse recursively when the owner unloads. Those two rules prevent the three most common problems: missing session values, duplicate registration errors and leftover UI after unload.

DSH plugin slot declarations and lifecycle

Bottom line: declaring a child does three things at once, and each declaration allows exactly one live owner.

  1. Three effects: the child key activates, the parent entry is authorized to call renderSlot/renderSlotChain, and the runtime dispatch spec is recorded.
  2. Single owner: registering into an undeclared slot, or re-declaring a child another entry owns, fails at plugin activation.
  3. root is special: the only built-in declaration and the only key rendered by the Cordis service itself; all descendants render through props.
  4. Effect lifecycle: destroying an entry removes its contributions and recursively collapses the child slots it declared.
  5. Cross-package contribution: use ctx.slots.inject(key, callback); the callback runs per declaration lifecycle and re-runs when the owner remounts.

DSH plugin cardinalities: count and addressing

Bottom line: single picks a winner, list lays out by id, keyed matches by key, chain competes through select.

cardinalityBehaviorUse
singleOne cell rendering the current priority winnerExactly one implementation
listEntries addressed by required id, ordered by order then registrationMultiple equal contributions
keyedOwner passes entryKey; the matching cell renders with that key's propsContributions addressed by entity
chainEach entry provides select(owner); first non-null wins"Who can handle this" decisions
  1. Do not treat single as a list: declare a child slot for side-by-side content.
  2. Priority semantics: shadowing priority for single/list/keyed, election order for chain; smaller runs first.
  3. Add with new ids: use a new list id or keyed key; reusing an existing cell replaces it intentionally.
  4. Chain fallback: the owner's fallback renders when everything declines.

DSH plugin scopes: whether a session binding is required

Bottom line: root has one instance, session requires a definite session, session-maybe tolerates absence.

  1. root: one root-scoped component and store instance.
  2. session: requires a resolvable outer Provider binding and receives a definite Session value.
  3. session-maybe: inherits the outer binding but renders without one, with an optional session value.
  4. Subtree override: declaring session or session-maybe children provides SessionProvider; omitting it inherits, while passing a reference or undefined overrides only that subtree.
  5. Remount rules: strict session entries remount when the binding generation changes; blank session-maybe entries do not remount on first acceptance, only on later generation changes or returning to missing.

DSH plugin component props: derive, do not copy

Bottom line: six input classes each have a declarer; components derive props from types while service objects stay in the closure.

InputSourceType
Owner and scope valuesSlotMap entry and scope adaptersPropsRuntime<K>
Authorized child renderersEntry's children keysPropsRenderSlots<S>
Shared view stateEntry's storePropsStore<H>
Private data and observablesEntry's inject factoryInjectFace<I>
Localization functionlocale namespacePropsLocale<N>
Chain-selected valueselect resultComposedProps.matched
  1. No ctx: components never receive the context object.
  2. Parent values via owner: values known at render time arrive through renderSlot's owner argument.
  3. Services stay hidden: service and model objects remain in the apply closure, projecting callbacks or observable sources.
  4. Localize through the namespace: do not hardcode copy.

DSH plugin slot troubleshooting

Bottom line: separate undeclared, registration conflict and missing values.

  1. Registration errors — confirm the target slot is declared and the child is not owned elsewhere.
  2. Duplicate registration — the same id registered twice.
  3. Missing session — check whether the scope is session or session-maybe and whether a binding exists.
  4. Leftover UI after unload — registration is not on an effect, or inject was bypassed.
  5. Wrong list order — check order, then registration order.
  6. Repair status, stated honestly: declaration effects, cardinalities, scopes and input classes follow the official Web Client Slots page; confirm slot keys and types against the official package and your version.

Sources: Web Client Slots, dsh-client-ui-slots README, Client resources.

FAQ

Why should a DSH plugin contribute to another slot through slots.inject rather than register directly?

DSH plugin registration and declaration follow the Cordis effect lifecycle, so contributions disappear when the owner collapses. slots.inject callbacks run once per declaration lifecycle, so contributions return automatically when the owner remounts.

Which DSH plugin slot cardinality should I choose: single, list, keyed or chain?

DSH plugin single renders the current priority winner, list lays out entries addressed by a required id, keyed matches an entryKey passed by the owner, and chain lets entries compete through select. Declare a child slot when you need side-by-side content instead of treating single as a list.

What is the difference between the session and session-maybe DSH plugin scopes?

DSH plugin session requires a resolvable outer Provider binding and a definite session value, while session-maybe can render without a binding and treats the session value as optional. Choosing wrong makes components disappear when no session exists.

Do DSH plugin slot components receive ctx through props?

No: DSH plugin slot components never receive ctx. Values the parent already knows arrive through renderSlot's owner argument, shared view state uses the declared store, and services stay in the apply closure projecting callbacks or observables.

What does declaring a DSH plugin child slot actually do?

Declaring a DSH plugin child does three things: it activates the child key, authorizes the parent entry to call renderSlot or renderSlotChain, and records the runtime dispatch spec. Each declaration allows exactly one live owner.

Related Terms

SlotMap
SlotMap is the compile-time registry of DSH plugin Web UI slots where packages declare keys, cardinality, scope, owner props, keyed props and an optional inject face through declaration merging. Runtime declarations are the entries an owning component supplies in children.— https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/slots
cardinality
Cardinality decides how many contributions a slot holds, taking the values single, list, keyed or chain. It describes count and addressing only, independent of scope.— https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/slots
scope
Scope decides whether a slot component can receive a session binding, taking root, session-maybe or session. Root has one instance, session requires a definite session, and session-maybe tolerates absence.— https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/slots
chain cardinality
Chain is a DSH plugin slot cardinality where each entry provides a pure select(owner) function, the first non-null result by priority wins and receives matched, and the owner fallback renders when all decline.— https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/slots

Sources