DSH plugin runtime invariants: InvariantInstaller checks
A DSH plugin runtime invariant is a rule a package sets for itself about what must always hold while it runs, registered and attributed through ctx.invariants. It is explicitly not a three-package capability seam and not part of the agent loop mainline: it is a support-group service where the registry handles selection, name reservation, child-fiber lifetime and package-attributed failure, while each workspace package publishes a ./invariant companion that registers under its exact npm name. The easiest thing to get wrong is what to check: official convention allows assertions over authoritative event streams or mutable data, and never checks for the existence of services or methods — that belongs to load time.
DSH plugin runtime invariants: what to assert and what not to
Bottom line: invariants guard relationships between data and events, not whether objects exist; existence belongs to dependency declarations.
- Assert: ordering that must never occur in an authoritative event stream, structural relationships in mutable data, cross-event count consistency.
- Do not assert: whether a service is registered, whether a method exists, whether a package is loaded.
- Violations fail: call
fail()instead of logging and continuing. - One companion per package: publishing and registration are exhaustive, but whether to install checks is the package's decision.
DSH plugin invariant selection: enabled plus two regex lists
Bottom line: the service is on by default; a package is selected only if the allowlist is empty or matches and the blocklist does not.
| Option | Meaning | Default |
|---|---|---|
enabled | Global switch | true |
package_allowlist | Case-sensitive regex sources; empty admits all | empty |
package_blocklist | Excludes after the allowlist, with priority | empty |
- Compilation: entries use
new RegExp(source); unanchored by default, so add^and$for exact matches. - No
/pattern/flagsparsing: express flags with inline groups instead of slashes. - Fail at startup: blank, whitespace-padded, duplicate or invalid entries throw instead of being skipped.
- May match nothing: a valid pattern can match no currently loaded package, keeping later loads and HMR deterministic.
- Fixed for the lifetime: do not expect filters to change while the service runs.
Writing a DSH plugin InvariantInstaller: ctx, fail and inject
Bottom line: an installer is a (ctx, fail) function; declare inject for the services you need, and synchronous or asynchronous checks both work.
type InvariantFailure = (message: string) => never
interface InvariantInstaller {
(ctx: Context, fail: InvariantFailure): void | Promise<void>
readonly inject?: Inject
}
- Declare inject first: only declared services are reachable.
- Check in the body: call
fail('...')describing which package contract was violated; the framework adds theinvariant violated by "<package>": …prefix. - Async is allowed: registration waits for the installer to settle, synchronously or asynchronously, before succeeding.
failreturns never: reporting a violation is throwing.- Verify: force one violation and confirm the message carries the right package name and code.
DSH plugin registration: reservation, child fiber and rollback
Bottom line: registration reserves one slot per full npm name; the installer runs in its own child fiber, and failure rolls back atomically.
- Register:
ctx.invariants.register(packageName, installer)
// returns an effect-scoped disposer
- Reservation is strict: it holds even when filtering keeps the installer inactive, so two plugins can never claim the same name silently.
- Duplicates throw: repeated, blank or whitespace-containing names fail.
- Runs in a child fiber: enabled installers run in a dedicated Cordis child fiber, and
installer.injectdecides which services it can reach. - Failure rolls back: a failed installer atomically disposes the child fiber and releases the reservation, so a reload can register again.
- Two-sided cleanup: the registration fiber belongs to the service while the returned disposer belongs to the companion plugin's fiber; unloading either side removes listeners, trace state and the reservation.
DSH plugin companion convention: empty installers need reasons
Bottom line: every package needs ./invariant; with nothing to check, the empty installer must explain why.
- Layout and publishing: each workspace package owns a
./invariantcompanion with complete export, publish, dependency and packaging wiring. - Install checks only when there is an observable relationship.
- Otherwise write an empty installer: the leading comment must start with
No runtime invariant:and explain the package specifically. - Mechanical validation:
pnpm run verify-package-invariantsrejects generated-file markers, unexplained empty installers, non-empty installers that ignore the reporter, wrong registration names and incomplete publishing wiring. - Do not invent checks to pass validation: an honest empty installer beats a fake assertion.
DSH plugin invariant troubleshooting
Bottom line: read the package attribution first, then separate a real violation from a wrong check.
- Package attribution:
invariant violated by "<package>"points directly at the owner. - Check the check: overly strict conditions — unanchored regexes, cross-event counts — report normal states as violations.
- Reservation conflict: two plugins registered the same npm name.
- Filter changes not taking effect: filters are fixed for the service lifetime; restart or recompose.
- Empty-installer errors: confirm the comment prefix and explanation are present.
- Repair status, stated honestly: selection rules, installer signature, reservation and rollback semantics come from the official Runtime invariants page and the dsh-invariants README; confirm validation commands and package conventions against the official repository.
Sources: Runtime invariants, dsh-invariants README, Plugins and lifecycle.
FAQ
A DSH plugin runtime invariant asserts relationships over authoritative event streams or mutable data, never whether services or methods exist. Existence is a load-time concern handled by dependency declarations and startup logs; invariants guard data states that must stay true while running.
In a DSH plugin, the InvariantInstaller fail parameter is a reporter bound to the registering package name; calling it throws an InvariantError carrying a stable code and the package name. It throws rather than returning a boolean so a violation interrupts immediately and stays attributable.
No: a failed DSH plugin installer atomically disposes its child fiber and releases the package-name reservation. The companion plugin can therefore reload and register the same name again after a fix.
In DSH plugin invariant selection, blocklist matches take priority over allowlist matches, and an empty allowlist admits everything. Entries compile with new RegExp(source), so patterns are unanchored unless you write ^ and $ yourself.
Yes, the DSH plugin companion convention requires a ./invariant for every package; with nothing to check, export an empty installer. Its leading comment must start with No runtime invariant: and explain why the package has no checks.
Related Terms
- runtime invariant
- A runtime invariant is a condition a DSH plugin asserts over authoritative event streams or mutable data that must always hold while running. The package publishes its own checks; the registry only selects, reserves and attributes failures.— https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/invariants
- InvariantInstaller
- InvariantInstaller is the check-installation function a package provides, typed (ctx, fail) => void | Promise<void>, optionally declaring inject for the services it needs. It runs in a dedicated child fiber and registration is not considered successful until it finishes.— https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/invariants
- InvariantError
- InvariantError is thrown when an invariant is violated; it extends Error with a stable code INVARIANT, the owning packageName, and a message prefixed invariant violated by "<package>". It keeps violations attributable without the registry importing product packages.— https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/invariants
- package_allowlist / package_blocklist
- These options are regex sources deciding which packages' invariants are enabled, matched case-sensitively and compiled with new RegExp(source). Blocklist takes priority over allowlist, and filters stay fixed for the service lifetime.— https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/invariants
Sources
- DeepSeek Harness docs — Runtime invariants (selection, installer, companion-plugin convention)· deepseek-harness.github.io
- dsh-invariants package README (registration, layout and composition)· deepseek-ai (GitHub)
- DeepSeek Harness docs — Plugins and lifecycle (child fibers and failure semantics)· deepseek-harness.github.io