Dynamic Plugins
The runtime dynamic plugin model: Host and Client halves, immutable package versions, the define/run/stop/undefine lifecycle and approval flow
A dynamic plugin temporarily extends the running harness process: it mounts new capability without editing repository source or restarting. It suits temporary interfaces, one-off tools, or quick validation. It exists only in the current process — definitions are not written to on-disk config and do not survive a restart.
Host and Client halves
A dynamic plugin has two halves, each running on a different platform:
Runs in the DSH Node.js process. Suited to files, networking, commands, Agent/Session access, Host events, services, model tools, and JSON methods callable by the Client.
The halves communicate through package-private JSON methods, in the Client → Host direction; only lossless JSON crosses that boundary. Host versus Client is an implementation choice: use Client when visible page behavior is needed, Host otherwise.
Immutable package versions
A dynamic plugin is identified by a stable id and can be modified over time; each change appends a new immutable Package instead of overwriting an old one.
- pluginId: identifies one plugin that can be modified over time.
- packageId: one immutable Host/Client source version under that plugin.
- currentPackageId: the most recent fully successful version.
- nextPackageId: the target awaiting approval, being attempted, awaiting Client activation, or most recently failed.
Because old versions are never overwritten, you can update or roll back between versions.
Lifecycle
- define: records source without running it. Defining only validates parameters and syntax.
- run: activates one exact version. Use run for the first activation, restarting the current version, or rollback; use update to switch versions.
- update: stops the old version, then starts the target. A failed update does not automatically restart the old version.
- stop: stops the current run and cancels unfinished approval/activation requests, while retaining definitions, versions, and grants.
- undefine: permanently stops and deletes the plugin and all its versions.
Approval flow
Activating an unauthorized Client package creates an approval request; it proceeds only after authorization. A single check authorizes the current version only; double check authorizes future versions of the same plugin. A grant remains in effect after a technical failure; do not request approval again after the user rejects it.
Asynchronous results
A run result of "starting" only means the request entered the asynchronous flow — not success. Success, rejection, or technical failure is reported through runtime state; after a failure, read the diagnostics and fix the same plugin rather than silently creating another.
Every side effect is reversible
A plugin's services, events, tools, handlers, timers, Slots, styles, and theme overrides must all belong to the current fiber's lifecycle. Use ctx.effect(), ctx.on(), or official APIs that return a disposer, so stop, update, and undefine unwind every side effect.
Next steps
- To read and write services and events on the Host side, see Host Services & Events.
- To register Slot UI in the browser, see Client UI & Slots.
Architecture
DeepSeek Harness architecture overview: everything is a plugin, profiles & bundles, the core package map, events, the agent loop and capability seams
Host Services & Events
Host-side development: read optional services with ctx.get, declare hard dependencies with inject, listen to events and provide services