AGENTS.md
August 14, 2026 · View on GitHub
Out-of-tree DeepSeek Harness plugin (host + Web client bundle): form-level and file-level configuration management with an open registration SDK. Self-contained repository — every source, compiler, documentation, and project-reference path stays below this root; lib/ is committed and kept in sync with source.
Layout
src/index.ts host entry: function plugin (name/inject/Config/apply, no default export)
src/config.ts serializable schema + direct-call defaults (message only)
src/runtime.ts Cordis activation + host-boundary wiring (ctx.dshSettingsPlus, fabric binding)
src/crawler.ts read-only enumeration: listNamespaces (settings.describe, redacted) / listCompositionConfigs (registry rows)
src/service.ts the dshSettingsPlus host service: reads delegate to the crawler, writes route through the settings seam with expectedRevision guards
src/fabric.ts optional gateway exposed-namespaces widening (loaded from host context at binding time; three-posture)
src/sdk.ts open registration SDK: registerUserSettings / defineSettingsSection / settingsNamespace brand + ./sdk export
src/file-browser.ts closed writable manifest ($DSH_HOME root yml/yaml + profiles/<name>/cordis*.yml) + realpath boundary; never writes
src/file-store.ts atomic reads/writes through the injected FsLike channel, byte caps, expected-version write guard
src/yaml-editor.ts comment-preserving YAML round-trip
src/patch-validator.ts semantic validation that rejects patch edits breaking the document
src/hmr-aware.ts save strategy copy: the host owns reloading, this plugin never suggests a restart
src/invariant.ts invariant companion (documented empty installer — see its reason comment)
src/client/ browser half, served as the single file lib/client.js
index.ts settings.section registrations: entry (order 30) + three-phase status row + per-entry sections, signature-diff reconcile
catalog.ts observable catalog store + injectable settingsPlusCatalog source seam
component.tsx entry / status-row / data-section components
schema-form.tsx generic schema form renderer (whitelisted controls, secret placeholder protocol, reset, conflict, restart notice)
form-logic.ts pure form logic: path ops, secret placeholder decisions, conflict classification
locales.ts zh/en dictionaries; zh is the key-set source of truth, en satisfies Record<keyof typeof zh, string>
tests/ node-env host specs + jsdom client specs (client.spec.ts, schema-form.spec.tsx, form-logic.spec.ts, …)
Contracts with the harness (do not drift)
- The crawler and the SDK consume the host settings seam through minimal local contracts, never an import of the host package: crawler calls only
ctx.settings.describe({ redactSecrets: true }), the SDK onlyctx.settings.register(...). There is no second enumeration surface — the host settings service is the single arbiter of registered namespaces, and duplicates fail loud atregistertime. listCompositionConfigsreads livectx.registryrows: only rows whoseConfigexposestoJSON(schemastery) and whose fibers carry a string row id are surfaced; secrets are stripped by the schema-walkingredactValue.- The
dshSettingsPluswrite boundary is narrow by design:updateComposition/removeCompositionaccept only ids that are registered settings namespaces. Plaincordis.ymlrows are rejected loudly — file-surface orcordis.patch.ymlis the answer. cordis.patch.ymlcarries three rows:dsh-settings-plus,dsh-settings-plus-invariant, and a disabledcordis-fabricstub. The Fabric binding is optional: no facade mounted → safe no-op; facade mounted but malformed → loud error. Never edit the patch or the binding without updatingsrc/fabric.tstogether.- The file surface never touches anything outside the writable manifest:
file-browser.tsenumerates, every write path goes throughisWritableTarget+ realpath boundary, and the file store adds byte caps and an expected-version guard. No file creation, deletion, or rename — ever. - The client composes only through standing seams:
ctx.slots.inject('settings.section', ...)with declaration-aware deferral,ctx.locale.register, and thesettingsPlusCatalogsource seam. Section registration uses signature diffing (${key}\u0000${label}): unchanged signatures are reused, anything else is disposed and rebuilt. The catalog production default is the honest local empty source until the host wire surface lands. - The schema form's secret placeholder protocol is fixed: placeholders never travel, empty input keeps the stored value, only explicit input commits; per-field reset uses unset ops, never value-bearing writes. Revision conflicts surface a reload prompt (
form.conflict). - Locale keys:
src/client/locales.tsis the key-set source of truth; any new copy the client renders must be added to both dictionaries (theenside is compile-checked againstzh). Chinese is the product copy; code comments, JSDoc, and the English README are English.
Check ladder
pnpm run typecheck and pnpm test must be green before every commit, then pnpm run build (which also regenerates lib/), and finally pnpm run verify:self-contained (rejects dependency specs, out-of-repo paths, external/broken Markdown links, absolute workstation paths, and malformed skill metadata). pnpm run prepare regenerates consumer artifacts for Git/tarball installs. Keep lib/ committed and in sync: any source change that alters built output lands with its lib/ regeneration in the same commit.
Commit discipline
- Conventional commits (
feat:/fix:/docs:/build:/chore:) with a body: what and why. - One concern per commit; run the full check ladder before committing; never commit
node_modules/, logs, or credentials.