# Architecture and compatibility ## Components | File | Responsibility | |---|---| | lib/client.js | Plain lazy browser module, shell React, additive model/effort control, strict Remote codecs and session-keyed lifetime. | | lib/index.js | Shared Host Cordis service, native lifecycle hooks, catalog/metadata access and Remote registration. | | lib/controller.js | Durable policy saves, binding capture, conflict handling, root lookup and request routing. | | lib/policy.js | Pure route and session-identity helpers plus per-key write queues. | | lib/schema.js | Validated requests and the versioned preferences/bindings storage domain. | | cordis.patch.yml | Profile bundle registration for the shared Host service. | The service is shared across sessions and therefore belongs to the Host profile, not an individual agent preset. It consumes DSH's storageDomain, sessions, sessionPersistence, agents and llm services. It must use the same native Cordis installation as the running Host, not a second private registry copied from elsewhere. Neutral identifiers are package dsh-subagent-model-policy, service/Remote namespace subagentModelPolicy, registration row subagent-model-policy and storage domain subagent_model_policy. ## Lifecycle 1. The main session saves an explicit selection or Inherited. An expected revision prevents two browser tabs from silently overwriting each other. Readers see only successfully committed values. 2. A new native child emits agent/session-start with source startup and header origin subagent. The controller captures the owning root's latest committed preference. Resume, clear and compact are not fresh captures; agents already live at plugin activation are excluded. 3. The child's pending binding is saved before inference. An explicit Sub: policy overrides native spawn-time model/provider choices. With Inherited, the controller captures the effective first-request configuration that DSH resolves: normally the immediate parent's route, with any native spawn-time overrides applied. Adapter-default reasoning effort is resolved and the resulting route is saved before that request proceeds. 4. A child-scoped prompt-assembly hook aligns the provider/model prompt variables. The agent/request waterfall waits for binding durability and applies the fixed provider, model and effort to the request controls. 5. Continuations and cold resumes use the child's existing binding. They do not reread today's root preference to choose a new route. Newly created descendants can capture a newer root preference independently. 6. Disposal removes listeners and per-child hooks, drains admitted writes and closes the storage domain. Disabling the plugin removes enforcement; stored data does not route requests by itself. Session identities include creation time and workspace, so reusing an ID for a different session does not silently adopt an old binding. Ordinary conversation forks are independent roots; copied log history is not treated as policy storage. ### Initial capture failure and restart A failed initial binding write blocks the child's requests in the current process, but its failure marker exists only in memory. After restart, there is no durable binding to distinguish that failed capture from a legitimately unmanaged child. The controller therefore leaves it unmanaged and allows DSH's normal routing. The first release does not guarantee fail-closed behavior across restart for an initial capture that never saved. Successfully persisted bindings retain their normal continuation and cold-resume behavior. After an initial binding-save error, fix storage and create a new child rather than resuming the failed-capture child. See [recovery guidance](INSTALLATION.md#initial-binding-save-failure). ## Browser interface The browser bundle registers in conversation.input.right and leaves conversation.input.model untouched. It uses DSH's existing Remote connection and exposes no separate port. Selecting a model or effort saves immediately; child views are read-only. Remote inputs and outputs use strict schemas, with errors surfaced to the user. Styles belong to the React contribution and disappear when it unmounts. Named data-slot anchors account for DSH's display:contents wrappers. Responsive rules wrap and bound narrow toolbars and keep menus inside the viewport. The native model component is not imported through an unavailable private export; the adapted appearance is independently namespaced and attributed in NOTICE. The client is already JavaScript; there is no JSX/TypeScript transformation or application-shell rebuild step. DSH snapshots client assets, so a source edit requires an explicit supported reload or restart of the existing instance and a page refresh. No automatic watcher is assumed. ## What qualification must cover - Correct native package identity and a single Cordis graph. - Snapshot timing, concurrent saves, failed writes, identity reuse and root isolation. - Native spawn/fork and continuable children through a full shutdown/cold resume. - Strict Remote arguments and real storage-domain persistence/disposal. - Client cancellation/session switches, provider/effort validation and error surfaces. - Main-picker preservation, desktop order and narrow-screen interaction. - An isolated fresh-profile installation from the exact packaged artifact, not just tests against a developer checkout. A passing deterministic test suite is not proof of arbitrary provider inference, vision compatibility or every platform's browser rendering. External CLI subagents have different lifecycles and require their own integration. Native descriptors may keep their original model seed; inspect the actual request route rather than that label alone. Future DSH versions can change the lifecycle contract, request shape, exports or layout. Treat a new version as a compatibility event: test it, then deliberately extend the supported range. Do not patch the DSH core, discard saved bindings or silently fall back to another model to hide an incompatibility.