design phase 8 t1 deepseek - sinrimin/harness-nexus GitHub Wiki

Design: Phase 8 T1 β€” DeepSeek Harness (dsh) target support

Status: implemented (branch phase-8-t1-deepseek). Research: research-phase-8-t1-deepseek-harness.md (ground truth: dsh v0.1.2-rc.1). Ground-truth update (#46, 2026-10-13): the integration moved to dsh 0.2.0-rc.2 with NO back-compat — the session-log reader, the event tap and the connect gate all target the latest line only; see design-phase-9-w7-native-sessions.md § #46 addendum, design-phase-9-w7.1-dsh-event-tap.md § #46 addendum, and design-dsh-client-version-gate.md. The install/scanner surfaces below (~/.dsh/skills frontmatter, cordis.patch.yml insert rows, @deepseek-ai/dsh-mcp-client, the ACP profile + settings.yaml route) were source-diffed 0.1.2-rc.1 → 0.2.0-rc.2 and verified UNCHANGED; the T1 ACP row (acp/adapters.ts) now carries minVersion: '0.2.0-rc.2', which the daemon's version gate enforces before every spawn. Verification: CLI 26/26 (11 new adapter tests — frontmatter synthesis, per-profile managed-region replace-idempotence, long-slug cap, skipped kinds, outDir override), scanner cases in inventory.test.ts (bundles→skill / flat→command split, platform vs local MCP origins, stdio + streamable-http collect), server 55/55 (incl. a NEW registry-resilience.test.ts regression — see below), and smoke 283/283 with a [8 T1] block driving the REAL CLI dist: create profile → install --apply → ~/.dsh/skills/<slug>/SKILL.md with synthesized frontmatter + flat command skill + managed cordis.patch.yml insert row + ledger → reinstall is an idempotent overwrite of OUR marked region only.

Out-of-band fix surfaced by the T1 smoke (committed with it): a stdio auto row referencing a MISSING credential (the C3-import shape β€” env values redacted to ${cred:KEY} before upload, import saves rows directly via the UnitOfWork) derives dial site server, and McpRegistry.resolveTransport THREW on stdio β€” crashing the fire-and-forget reload (unhandled rejection killed the process; the code comment even claimed it was "skipped rather than crashing the pool"). C5-era smokes never hit it only because no /api/mcp-servers mutation followed the import. Fix: serverDialedDefinitions skips rows whose transport cannot resolve (warn log; Phase 2.2 "misconfigured upstreams never block the pool" rule), and connectServer on such a row maps to 409 not_dialable.

Numbering: target onboarding becomes a T-wave inside Phase 8 β€” it lands on Phase 8 surfaces (C3 scanner, C4 deploy, C5 ACP row) plus the 3.x install pipeline; the roadmap's 3.8 "other agents" bucket is superseded by this wave (same absorption move as 3.6β†’C2). T1 was pulled ahead of all other pending target work (ECC/Superpower import, CC local-write fallback) by explicit priority decision. Supported-harnesses list (one-click install + ACP chat) after T1: Claude Code, Codex, DeepSeek Harness β€” user-facing docs mention only these three for now; existing adapters (hermes) keep working unlisted. Profile target range is otherwise unchanged (additive deepseek only). Parent: Phase 8 design design-phase-8-client.md; adapter template: the Codex adapter (8 C2).

Scope

Add deepseek as a first-class AgentTarget across the platform:

  1. shared β€” agentTargetSchema += 'deepseek' (kept in sync with core/domain/resource.ts, per the documented duplication rule); HOOK_SUPPORT['deepseek'] = null (hook bridges are opt-in packages β€” research Β§ Hooks); SCANNABLE_TARGETS += 'deepseek'.
  2. core β€” AgentTarget union += 'deepseek'.
  3. CLI install adapter (install/adapters/deepseek.ts, registered in registry.ts) β€” target root ~/.dsh, home kind:
    • skills β†’ ~/.dsh/skills/<slug>/… bundle files (inline + inline-bundle), with frontmatter synthesis: dsh rejects SKILL.md without YAML frontmatter name + description; the adapter guarantees both (slug from the resource name, description from the resource record), kebab-case per dsh's ^[a-z0-9]+(?:-[a-z0-9]+)*$.
    • commands β†’ flat ~/.dsh/skills/<slug>.md (dsh's /name invocation surface IS the skill surface; frontmatter kept/synthesized, body unchanged β€” unlike Codex which strips it).
    • mcp β†’ a managed - insert: block appended to the home-level ~/.dsh/cordis.patch.yml: one @deepseek-ai/dsh-mcp-client row per profile, transport: stdio, command = the hnx executable, args = [mcp, serve, --profile <id>, --server <base>] (HN_SERVER resolution identical to the Codex adapter). The block sits between # BEGIN/END harness-nexus (managed) markers β€” re-planning replaces the block wholesale (idempotent overwrite semantics, like Codex's TOML section surgery); user content outside markers is preserved byte-for-byte.
    • rule / sub_agent / hook entries β†’ skipped with warnings (research table; same policy as Codex).
  4. CLI inventory scanner (inventory/scanners/deepseek.ts, added to SCANNERS) β€” scans ~/.dsh/skills (bundles + flat files) and MCP rows from the home patch (tolerant text parse of - insert: rows whose name === '@deepseek-ai/dsh-mcp-client'; the parse handles the README field spellings, not arbitrary YAML β€” same tradeoff as the Codex TOML parser). Platform-origin detection reuses the ledger + harness-nexus serverName convention. Import: MCP items become McpServer rows (stdio arm), skills/commands become resources β€” the C3 pipeline needs no target-specific changes.
  5. C5 ACP adapter row (daemon/acp/adapters.ts) β€” deepseek: ['dsh', '--profile', 'acp'] (dsh on PATH; provider must be configured on the machine β€” documented prerequisite; env override HN_ACP_COMMAND_DEEPSEEK).
  6. server β€” DEPLOYABLE_TARGETS += 'deepseek' (it has a local-write adapter; remote deploy rides the unchanged C4 job pipeline).
  7. web β€” profile editor target list += deepseek; MachineDetail deploy filter += deepseek; resource-editor target checkboxes follow the Codex precedent (Codex is not listed there today β€” deepseek matches it; only the profile surface changes).
  8. Tests + smoke β€” CLI unit tests for the adapter (skill frontmatter synthesis, command emission, managed-block replace-idempotence, skipped kinds, outDir override) and scanner additions in packages/cli/test/inventory.test.ts; smoke gains a deepseek install + inventory block mirroring the Codex one.

Non-goals / explicit out-of-scope

  • dsh plugin-package distribution (dsh plugin --profile X add <pkg> / dsh.bundle.patch manifests) β€” that path requires pnpm on the target machine and per-profile management; our local-write adapter achieves the same capability wiring through the home patch layer. Revisit only if dsh grows a marketplace surface worth emitting (like 3.5 did for Claude Code).
  • Hook bridges (dsh-hooks-claude-code) β€” opt-in packages; would need per-profile pnpm. HOOK_SUPPORT stays null; revisit if bridges ever ship in-box.
  • Rulesβ†’persona writing β€” replacing a user's system-prompt persona row from an installer is destructive; skipped.
  • session/resume chat semantics β€” dsh ACP supports it; our v1 daemon contract is "no resume" and stays that way.
  • DSH_HOME env plumbing through the daemon β€” the adapter resolves ~/.dsh via the standard homeDir input (same as every adapter); jobs can still override the whole root with payload.directory.

Task order

  1. shared (enum + matrix + SCANNABLE_TARGETS) β†’ core union β€” typecheck.
  2. CLI adapter + registry + warnings plumbing β€” unit tests.
  3. CLI scanner + registry β€” inventory tests.
  4. ACP row + server DEPLOYABLE_TARGETS + web pickers.
  5. pnpm -r typecheck + targeted builds + pnpm format.
  6. smoke [8 T1] block; full suites green.
  7. Docs: research/design status flip, roadmap (T-wave + priority note), AGENTS.md, docs/README.md, README supported-harnesses list; merge to main.

Security notes

  • No secrets in any emission: the MCP row carries the hnx command line only; credentials resolve server-side at the outlet, exactly like the Codex row.
  • The managed-block markers bound our writes; anything outside them is untouched (and hnx uninstall restores pre-install snapshots from the ledger as always).
  • Frontmatter synthesis never copies more than name/description (resource-scoped fields) into the target home.
⚠️ **GitHub.com Fallback** ⚠️