Composition and HMR: Import New Code, Dispose the Old Fiber, Then Activate
Understand stable ids, configuration groups, and Cordis HMR’s unload-reload cycle, including how to diagnose plugins stuck in PENDING.
The real HMR flow: save the file → import the replacement module → unload the old plugin and reverse its effects → register the replacement → activate it once dependencies are ready.
If HMR means only “import the file again”, the most important step is missing: the old instance must first lose its runtime side effects.
01 / Configuration entries are comparable runtime nodes
Give entries stable identities:
- id: logger
name: '@deepseek-ai/cordis-plugin-logger-console'
- id: timer
name: '@deepseek-ai/cordis-plugin-timer'
- id: hmr
name: '@deepseek-ai/cordis-plugin-hmr'
config:
root: ['.']
- id: hello
name: './hello.ts'id lets Loader distinguish retained, unloaded, and reconfigured rows after cordis.yml changes. Without it, a row can receive a new identity on every read and look like “remove, then add”.
group loads and unloads nested entries as one unit, while isolate gives a group independent service instances.
This HMR example also depends on the timer service and Node loader internals. It is server-side Node HMR, not the browser-side client-plugin HMR path.
02 / HMR imports the replacement before unloading the old instance
@deepseek-ai/cordis-plugin-hmr watches file changes:
- After a save, HMR classifies the change as configuration, plugin code, or an external file.
- For a plugin-code change, HMR imports the replacement module first.
- The old runtime is unloaded and all effects are reversed.
- The replacement module is then registered and
applyruns. - If its services are not ready, the new Fiber remains
PENDINGinstead of half-starting.
External or framework files are not single-plugin reload units; those changes make Loader exit so the host can restart.
Editing hello.ts can therefore stop the old output and produce the new one; editing the configuration lets Loader update rows by id.
03 / Why HMR can appear to do nothing
Separate two cases:
- A misspelled path or package name is a resolution problem. Check
nameand logs first. - A missing provider is a valid
PENDINGstate. The plugin produces no output and does not throw.
Inspect pending Fibers through the registry:
import { FiberState } from '@deepseek-ai/cordis'
for (const runtime of ctx.registry.values()) {
for (const fiber of runtime.fibers) {
if (fiber.state === FiberState.PENDING) {
console.log(fiber.name + ' is PENDING')
}
}
}04 / HMR’s safety boundary
HMR can reliably reverse resources that are registered as effects. Cordis manages event listeners, service registrations, and child plugins; custom timers, connections, and watchers must return disposers from ctx.effect().
If a resource escapes the Fiber, repeated saves can leave duplicate listeners or stale connections. “HMR-safe” first means clear ownership, and only then a watcher that detects the file.
05 / Why DSH puts HMR in the base composition
The dsh-base configuration includes timer and HMR plugins. Profiles add model, tool, session, and Agent capabilities on top. Editing a plugin can reuse the same unload-reload semantics instead of requiring a refresh implementation per capability.
The headless and web overlays disable server HMR. Browser-side client-plugin HMR is a separate path, so its behavior cannot be inferred from this Node watcher.
Where to go next
Sources: composition and HMR tutorial, HMR plugin, and dsh-base composition.
More Posts
Cordis Inside DeepSeek Harness: Making Everything a Plugin
Trace dsh-base, Context services, event domains, and the tool pipeline to see how Cordis organizes a replaceable Agent runtime.
Cordis: Turning a Running Application into a Reversible Plugin Tree
Follow cordis.yml, Loader, and Context to see how Cordis composes, replaces, and safely tears down runtime capabilities in DeepSeek Harness.
waterfall: Intercept, Wrap, and Short-Circuit with next()
Follow a Cordis waterfall chain to see listeners delegate downstream, wrap results, or short-circuit when they own the decision.
Newsletter
Join the community
Subscribe to our newsletter for the latest news and updates