Files
deepseek-harness/packages/runtime-diagnostics/invariants
Turtle d1e22a7e24 feat(preset): declare Agent compositions in profile YAML (#4569)
* feat(preset): declare Agent compositions in profile YAML

* fix(preset): share scope binding cleanup and refresh module graph

* fix(preset): use host syntax colors in the YAML editor

* fix(preset): write new profile declarations as block YAML

* fix(preset): align eager activation with browser and worker surfaces

* fix(ui-agent-preset): retain the existing preset card layout

* fix(preset): keep rows waiting for a Host service mounted and re-audit after settlement

A preset row whose Host provider was still activating at declaration time
was reported as waiting for a missing service, and the registry recorded the
definition as broken for the rest of the process. Split the mount audit into
failed and pending rows: failures and root-realm leaks still reject the
mount, while pending rows stay mounted and every read and binding re-audits
them after the Host Loader tree settles.

Remove the accidental self-dependency of @deepseek-ai/dsh-web-app and its
lockfile self-link. Archive the copy-only preset authoring note, which the
declarative-preset note fully supersedes, and update the ralph note's
restore recipe to the profile-patch mechanism.

* chore(lint): re-key and prune the unknown-cast baseline after the master merge

* refactor(web-app): ship each Agent preset as its own bundle patch file

`dsh.bundle.patch` accepts an ordered file list, so the four shipped preset
declarations move out of the 1000-line web patch into
`presets/<id>.patch.yml`, one insert per file, applied after the host patch.
The host patch keeps the preset registry row. Gates and test scaffolds that
read the web layer resolve every patch file through `bundlePatchPaths`
instead of one hardcoded path.

* refactor(preset): drop the save notice injected into live Agents

The notice duplicated the save result the Web editor already shows, and
after the producer-owned message sources it would have needed its own
persisted source kind. Saving now only persists and reports the activation
diagnostic; the persistence catalog is unchanged from master.

* docs: regenerate the module graph after dropping the registry's llm dependency

* test(ui-agent-preset): cover the guide dialog's keyboard handling on the declarative section

* fix(preset): address the remaining review comments

Apply the lowercase id rule only when creating a declaration, so presets
declared with other ids stay editable. Export `isBuiltInPreset` from the
display fold and key the client card groups on it. Remove the dead `error`
and `retry` locale keys, the JSDoc orphaned by the `trust` removal, the
`trust` fields in the plugin-inventory test fixtures, and the stale
`dsh-agent-presets` package name in comments and READMEs.

* refactor(preset): make the Web preset page view-and-select only

Remove the child-plugin YAML editor, the `agent_preset` tool and the
registry's read/save Remote methods. Presets are declared and changed only by
bundle patches; the settings page keeps the roster, the new-task default and
the mode help, and its question icon explains that and offers to start a
Creator-mode task. The `editing-cordis-compositions` skill and the Creator
persona describe the bundle-based path, and the authored skill-load Session
and Web snapshots are refreshed for it.

* docs(skill): make the composition skill self-sufficient for preset authoring

State where the shipped declarations live, list every declaration field,
inline a complete minimal bundle and an override example, and name the
verification calls, so Creator mode no longer reads DSH package sources to
infer the format. Refresh the authored skill-load Session for the new text.

* test(tools): drop the removed agent_preset tool from the catalog expectation
2026-09-21 08:24:18 +00:00
..
2026-09-17 21:11:19 +08:00

description, kind
description kind
Runtime invariant checks for live compositions: the registry service that runs package-owned checks, for users and maintainers choosing, configuring, or debugging them. package-reference

@deepseek-ai/dsh-invariants

English | 中文

Summary

dsh-invariants runs package-owned runtime checks — invariants — inside a DeepSeek Harness composition: any package can ship a ./invariant companion that verifies its own durable relationships (authoritative event streams and mutable snapshots) while the composition runs. Checks run automatically, and a failed check reports an InvariantError attributed to the package that owns the violated relationship. Choose it for compositions that want self-checking diagnostics with a global switch and package-name filters; the standard agent composition already mounts it with the four core companions, and loading the service alone installs no checks.

Table of Contents


Use this package

Mount the registry when a composition should verify its own runtime contracts, then decide which packages' checks run. The service exposes ctx.invariants; companions register checks under their package's exact npm name, and every failure carries the owning package name.

When to use it

Use the registry for compositions that want live diagnostics. dsh-sdk-minimal mounts it with the four core stateful companions — dsh-session, dsh-agent, dsh-scope, and dsh-agent-loop; dsh-base deliberately omits runtime diagnostics. Custom compositions mount the registry and add companions for any other loaded package whose contracts they want checked. Loading the registry alone installs no checks: it ships no product checks of its own, so a composition that never mounts a companion observes no diagnostic behavior.

Enabling checks and selecting packages

The registry is enabled by default and checks every registered package unless filters say otherwise. Use enabled as a global switch, package_allowlist to admit only named packages, and package_blocklist to exclude packages after allowlist matching — a blocklist match overrides an allowlist match. Patterns are case-sensitive JavaScript regular-expression sources (unanchored unless they supply ^ and $), and an invalid, blank, or duplicate entry fails service startup instead of being skipped.

- name: '@deepseek-ai/dsh-invariants'
  config:
    enabled: true
    package_allowlist:
      - '^@deepseek-ai/dsh-'
Field Default Meaning
enabled true Global switch for all registered checks
package_allowlist [] Regex sources admitting package names; empty admits all
package_blocklist [] Regex sources excluding package names after allowlist matching

The generated configuration catalog is the exhaustive source for every accepted field and its JSDoc.

Which checks run

Each companion protects relationships its package owns, and a companion installs a check only for an observable event or mutable-data relationship — never for a service or method presence. The shipped executable companions cover:

Companion Checks
dsh-session, dsh-agent, dsh-scope, dsh-agent-loop Session log enclosure and call/result trace, agent-status transitions, scope-filtered dispatch subjects, loop-built request reconstruction
dsh-llm, dsh-llm-retry, dsh-tools, dsh-system-prompt LLM stream grammar, retry-failure shape, tool-pipeline stage pairing and frozen results, prompt-assembly section names
dsh-compaction, dsh-hook-protocol, dsh-sandbox-policy Compaction stream pairing, hook invocation/result pairing, sandbox mode values
dsh-fs, dsh-subagent, dsh-workflow, dsh-tool-workflow Filesystem event identity, subagent provider and start/end pairing, workflow lifecycle identity, workflow record shape
dsh-goal, dsh-goal-round-driver Durable goal-stream folds and reconstructed continuation prompts
dsh-permission-presets, dsh-user-approval, dsh-commands Preset references to live presets, approval asked/decided pairing, command run/done pairing
dsh-jobs, dsh-tool-todo, dsh-time-context Job snapshot field relationships, whole-list todo shape, durable clock readings
dsh-credentials, dsh-settings, dsh-storage-domain, dsh-workspace Commit events against the live service or memory state, entity-cache mirroring
dsh-agent-preset-registry, dsh-session-title, dsh-plan-mode, dsh-schedule Preset mount placement, title source citation, plan-mode payload, schedule stream
dsh-client-hmr, dsh-client-modules, dsh-client-runtime Browser/node-half stat-watcher lifecycle, boot entry graph, slot mutation versioning

Every other workspace package omits the companion and states the package-specific reason in its README.

Adding a companion to a custom composition

A companion is a normal plugin you mount beside the registry. It declares any services it needs and registers under its package's exact npm name; the registry joins its setup before the registration completes.

import type { Context } from '@deepseek-ai/cordis'
import InvariantRegistry from '@deepseek-ai/dsh-invariants'
import * as SessionInvariant from '@deepseek-ai/dsh-session/invariant'

declare const ctx: Context

ctx.plugin(InvariantRegistry, { enabled: true })
ctx.plugin(SessionInvariant)

When a check fails

A violation throws an InvariantError from the context that reported it: it carries the stable code INVARIANT, the full npm packageName of the owning package, and a message prefixed invariant violated by "<package>": …. The failure is therefore attributable to a package without the registry importing any product code. A companion whose installer itself fails is disposed and its registration rolled back, so a broken check cannot leave partial listeners behind.


Understand the implementation

Implementation internals — click to expand

This section explains the design behind the registry; the observable behavior is covered in Use this package.

Design philosophy

  • Product-independent registry. The service imports no session, agent, scope, or agent-loop package and contains none of their checks; companions carry checks next to their owners.
  • Real relationships, not synthetic assertions. A companion checks an event-stream or mutable-data relationship its package owns; confirming a method, plugin name, injection, or fixed pure result is a type, load, or unit-test concern, never a runtime invariant.
  • Registration reserves ownership. A package name is reserved even when filters keep its installer inactive, so two plugins can never silently claim the same name.
  • Companion wiring is mechanically enforced. pnpm run verify-package-invariants rejects empty installers, installers that omit or ignore the reporter, wrong registration names, incomplete publication wiring, and stale wiring for omitted companions (companion-omission note).

Source map

File Role
src/index.ts Plugin entry: Config schema, InvariantRegistry service, selection, registration, InvariantError
— No runtime invariant companion is published; registration ownership and child lifecycle are the service's mutation boundary itself; observing them from the same registry would only duplicate its implementation.

Selection and registration lifecycle

register(packageName, installer) reserves the full npm name and returns an effect-scoped disposer. An enabled installer runs in a dedicated child fiber; installer.inject declares the services that fiber may access, and synchronous or asynchronous completion is joined before registration succeeds. Failure disposes the child and releases the reservation atomically. The service owns every registration fiber, while the returned disposer also belongs to the companion fiber, so unloading either side removes listeners, trace state, and the reservation — a companion can reload and register the same name again without retained state. Session-backed companions rebuild their baseline from durable events; live-only companions observe operations that begin after reload.


Further Exploration

Read these pages when the package-level contract is not enough. They move from the generated service reference to the decision evidence and the group map.


Model Experience

None, as the observer validates requests but never rewrites their context.

KV Cache effect

Checks observe assembled requests and durable state without mutating request content, so provider cache reuse is exactly what the underlying composition produces.

Known Limitations and Deferred Work

These limits define when the registry is a poor fit or needs operational care. They are current package constraints, not a task backlog.

  • Filters are fixed for the service lifetime — enabled, package_allowlist, and package_blocklist are compiled once at startup; changing them requires a Cordis plugin reload.
  • Live-only companions miss pre-reload operations — a companion that only observes live operations cannot reconstruct operations that began before its own reload; session-backed companions rebuild their baseline from durable events.
  • Request reconstruction covers loop-built requests only — the dsh-agent-loop companion reconstructs requests explicitly built by the loop; direct one-shot LLM calls remain outside that contract even when callers freeze them or attach a session id.
  • No checks without a companion — the registry ships no product checks; a composition that mounts the service alone observes nothing.

Dev Note

Working context for maintainers — click to expand

None.