The Models page drops the generic schema renderer and the visible
environment-variable field: each editor is a curated per-family card whose
primary input is one write-only API key stored under a derived
<ROUTE>_API_KEY reference (recorded as apiKeyEnv in the pi-ai profile), an
unkeyed whole-section provider opens as its setup card, and the collapsed
customized-settings fold carries baseURL/reasoningEffort (deepseek) or
reasoning (pi-ai). dsh-client-schema-form reduces to the schema/draft model
layer (no React).
apps/cli/cordis.yml gains settings-local, credentials-local, and the bare
dormant llm-pi-ai row (manifest deps added for the resolver contract);
llm-deepseek drops its !!js apiKey inline for per-request credential
resolution. Both adapters tag apiKeyEnv role('credential-ref') so the
form mounts the credential control. The web e2e scaffold isolates a
harness home per run — an in-process boot must never touch the
developer's real ~/.dsh — and the new models-settings scenario pins the
whole loop through the shipped app: dormant directory as add vocabulary,
schema-driven editor apply landing in settings.yaml, the route
registering live (topology frame), and a write-only key landing in the
temp .env with the configured badge converging. A hermetic test-owned
reference name keeps a developer's real provider keys from flipping the
badge. schema-form joins the platform module table (seed + externals)
so client bundles share one instance.
The Models settings section joins llm.providers (the configurable
directory with live state), settings.describe (schemas, layered redacted
values, secret slots), and credentials.describe (value-free badges) into
provider rows with one editor card at a time. The editor renders the
provider's profile subtree through dsh-client-schema-form; the
credential-ref role mounts a control that shows configured/source state
and stores keys write-only through credentials.set. Apply without
removals merges a minimal patch (stored secrets outside it survive);
apply after a reset — and row deletion — replace the user section so
removals land. The client runtime bridges the three new host frames to
typed ctx events (settings/credentials/models changed), the page
refetches on any of them once loaded, and ui-model's per-session picker
directories reload on models/changed so a settings-born route appears in
open pickers without a reopen.
The five settings-surface registrants carried near-identical
spec-check/ledger-judge/subscribe scaffolding (three jscpd clones);
ui-slots now owns deferRegistration() — ledger-judged presence, refresh
for registrant-localized labels, one-call disposal — and every
registrant shrinks to its registration body.
Settings collaboration direction (recorded in the note): the shell only
provides composition faces — feature plugins register themselves. The
General section moves into the ui-settings shell (order 0, skeleton
rows) and declares the settings.general.item list slot; locale registers
the Language row and ui-theme the Appearance row (each with its own
store mirror, dictionaries, and ledger-judged deferral); the
ui-settings-general package is gone. ui-settings-models becomes
ui-models — a feature package that contributes its Settings section
rather than a settings-owned satellite. The item-slot SlotMap entry is
authored in the ui-settings contract and repeated verbatim in
locale/ui-theme (reference-cycle avoidance; declaration merging keeps
the copies identical).