# Harness Nexus documentation (development docs) These are the **development process docs**, imported from the repository's `docs/` folder (2026-09). They are the historical record of how each phase was scoped and built. > **New work is issue-driven now**: development is organized around GitHub > issues + milestones (see the repo's `CONTRIBUTING.md`). Big designs start > as a design-discussion issue; per-phase PRD/design docs like these are the > legacy of the phase-driven era and remain the authoritative description of > what shipped. User-facing feature guides are the top-level topic pages, > linked from the wiki [Home](Home). Documentation is split by type so it's clear what each file is for. | Folder | What it is | When to read it | | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | | [`prd/`](./prd) | **Product requirements** (PRD) — the _why_ and _what_. User stories, scope, acceptance. Written in the [to-spec](https://github.com/mattflick/to-spec) PRD template. | To understand what a phase delivers and why, before diving into how. | | [`design/`](./design) | **Technical design** (the "how") — data models, API surfaces, internals, wiring. The development-plan docs. | Before changing a phase's implementation; the authoritative source for current behavior. | | [`research/`](./research) | **Technical research** — option comparisons, spike notes, technology surveys done before a design. | When weighing an approach for an upcoming phase. | | [`adr/`](./adr) | *stayed in the repository* — architecture decision records. | When asking "why this stack/convention?". | Cross-cutting overviews: [`architecture.md`](https://github.com/sinrimin/harness-nexus/blob/main/docs/architecture.md) (layering, storage contract, MCP transport) stayed in the repository next to the code; the historical [`roadmap.md`](./roadmap.md) (phase status) is here. Machine-local, git-ignored material that is deliberately **not** on the wiki (the dev box holds the only copy): the UI exploration comps (`docs/dev/theme-designs/01-bay/` — the **spec** for anything skin-visible), the UI refactor's phase record (`docs/dev/ui-refactor/`: skeleton/content/ interaction/contract, the comp inventory, and the per-phase acceptance walks), the snapshot baselines (`docs/dev/ui-baselines/`), and `docs/dev/test-rig.md`. The durable rules those documents produced are stated in [`design-skin-system.md`](design-skin-system.md). > Legacy convention (still describes these files): each phase has a paired > `prd-phase-N-.md` and `design-phase-N-.md`. The PRD was > written when the phase was scoped; the design doc **before** implementation. ## Index by phase ### Phase 1 — Users, roles & authentication ✅ - PRD: [`prd-phase-1-auth.md`](prd-phase-1-auth.md) - Design: [`design-phase-1-auth.md`](design-phase-1-auth.md) ### Phase 2.1 — MCP connection config & credentials ✅ - PRD: [`prd-phase-2.1-credentials.md`](prd-phase-2.1-credentials.md) - Design: [`design-phase-2.1-credentials.md`](design-phase-2.1-credentials.md) ### Phase 2.2 — MCP registry, proxy & profiles ✅ - PRD: [`prd-phase-2.2-registry.md`](prd-phase-2.2-registry.md) - Design: [`design-phase-2.2-registry.md`](design-phase-2.2-registry.md) ### Phase 2.3 — Callable-function scripts ⏸️ on hold - PRD: [`prd-phase-2.3-callable-functions.md`](prd-phase-2.3-callable-functions.md) - Research: [`research-phase-2.3-sandbox.md`](research-phase-2.3-sandbox.md) - Design: _to be written before implementation_ - > Not currently planned for development. ### Phase 2.4 — proxy MCP connect & tool inspection ✅ - PRD: [`prd-phase-2.4-connect-tools.md`](prd-phase-2.4-connect-tools.md) - Design: [`design-phase-2.4-connect-tools.md`](design-phase-2.4-connect-tools.md) ### Phase 3 — Install pipeline 🚧 (3.1, 3.2 done) - Research: [`research-phase-3-ecc-install-patterns.md`](research-phase-3-ecc-install-patterns.md) — the install-pipeline architecture extracted from ECC (adapter factory + plan/apply + install-state ledger; Codex ground-truth format). - Research: [`research-phase-3-plugin-targets.md`](research-phase-3-plugin-targets.md) — per-target plugin formats (Claude Code / Hermes; ZCode superseded). Superseded on architecture by the ECC doc above. - Research: [`research-phase-3.5-marketplace-emitter-spike.md`](research-phase-3.5-marketplace-emitter-spike.md) — empirical spike: Claude Code consumes a plain-HTTP `marketplace.json` + `archive` (zip) plugin sources; capability-URL auth; version/SSRF constraints. Basis for the 3.5 re-plan (marketplace emission preferred over adapter writes for claude-code). - Design: [`design-phase-3.5-marketplace-emitter.md`](design-phase-3.5-marketplace-emitter.md) — the emitter surface: PAT-in-path catalog + per-profile archive zips, plugin zip layout, MCP emission, config `PUBLIC_BASE_URL`. - PRD: [`prd-phase-3-install.md`](prd-phase-3-install.md) - Design: [`design-phase-3-install.md`](design-phase-3-install.md) — target adapter factory (one adapter per target: Hermes → Claude Code → Codex), plan/apply, install-state ledger. ZCode out of install scope. ### Phase 4 — Resource management & PAT UI ✅ (4.1–4.6 done) - PRD: [`prd-phase-4-web-ui.md`](prd-phase-4-web-ui.md) - Design: [`design-phase-4-web-ui.md`](design-phase-4-web-ui.md) - Research: [`research-phase-4.5-hooks.md`](research-phase-4.5-hooks.md) — the hook event × target support matrix (CC ~30 events, ZCode 7, Hermes different model); lands in `packages/shared/src/hooks.ts`. - All resource kinds shipped: sub-agent, rule, command (single-file inline), hook (hooks.json + event/target matrix), skill (inline + inline-bundle multi-file). ### Phase 5 — ACP bridge ➡️ absorbed into Phase 8 - Delivered by Phase 8: C1 (daemon + control channel) and C5 (ACP chat). See the Phase 8 entries below. ### Phase 6 — Platform features ⏳ - stdio bridge entry → resolved by Phase 8 C2 (the stdio shim IS the entry). Remaining: Channels (adjacent to Phase 8 C6), LLM-WIKI, memory/notes. ### Phase 7 — Skill multi-source & plugin references ✅ - PRD: [`prd-phase-7-skills.md`](prd-phase-7-skills.md) — covers all four sub-phases (7.1–7.4); carries the research corrections (10 Hermes adapters, 4 trust tiers internally / 3 surfaced, CC has 4 live source kinds and no npm, `category` is the filter axis). - Design 7.1: [`design-phase-7.1-plugin-source.md`](design-phase-7.1-plugin-source.md) — `plugin` `ResourceSource` variant + trust/provenance labels + `SkillSource` port + validator/smoke flip. Zero outbound network. - Design 7.2: [`design-phase-7.2-marketplace-fetch.md`](design-phase-7.2-marketplace-fetch.md) — the server's first outbound HTTP path: `SkillCatalogService` (lazy TTL cache + in-flight dedup), `MARKETPLACE_ALLOWLIST`, `/api/skills/marketplaces/:id/plugins`, fixture-injection test mode. - Design 7.3: [`design-phase-7.3-hub-ui.md`](design-phase-7.3-hub-ui.md) — the `/skills/hub` browse page: category/free-text filters, client-side trust badge (neutral variants, not `--signal`), inline save-as-skill dialog with install-warning UX. - Design 7.4: [`design-phase-7.4-multi-source.md`](design-phase-7.4-multi-source.md) — 4 `SkillSource` adapters (github/well-known/url/marketplace), `SkillSearchRouter` (per-source timeout + identifier dedupe + trust-rank), `/api/skills/search`, hub dual-mode (browse + cross-source search). skills.sh/browse.sh deferred; clawhub/lobehub/hermes-index skipped (verified). - Research: [`research-phase-4.4-skills.md`](research-phase-4.4-skills.md) — external skill sourcing: CC/ZCode marketplace plugin model + Hermes's `SkillSource` adapter model, trust tiers, provenance pinning. - 7.2–7.4 designs to be written before each ships. ### Phase 8 — Harness Nexus client & agent orchestration 🚧 (C1–C5 shipped) - PRD: [`prd-phase-8-client.md`](prd-phase-8-client.md) — the vision shift (control plane / data plane), the four locked decisions (credential distributability, `/mcp` outlet narrowing, on-demand daemon, uniform stdio MCP), and the C1–C6 scope. - Design: [`design-phase-8-client.md`](design-phase-8-client.md) — data model (`Machine`/`AgentInstance`/`Job`/`AcSession`), the Socket.IO-over-WSS realtime protocol (bidirectional role namespaces `/ctl` daemon + `/app` browser, event catalog, rooms, isolation layers; daemon as protocol-adaptation edge), the MCP shim process model + dial-site routing derivation, jobs/deploy, inventory/diff/import, ACP chat, security model, and the per-phase development plan. - Design C1: [`design-phase-8-c1.md`](design-phase-8-c1.md) — the shipped C1 plan: machines storage + migration `0006`, machine PATs (`machine-ctl`, REST-rejected), realtime v0 (`/ctl` handshake/hello/presence + `/app` push), `/api/machines` CRUD, `hnx enroll`/`hnx daemon`, the Machines web page, and the verification matrix (unit + integration + smoke `[8 C1]`). - Design C3: [`design-phase-8-c3.md`](design-phase-8-c3.md) — the shipped C3 plan: daemon per-target scanners (claude-code/codex/hermes), normalized snapshots over `/ctl` (`inventory:scan|report|collect|payload`), latest-per-(machine,target) storage (migration `0008`), the pure profile diff, and one-click import (reuse-or-create resources + McpServer rows + a new profile) with daemon-side secret redaction. - Design C4: [`design-phase-8-c4.md`](design-phase-8-c4.md) — the shipped C4 plan: the Job state machine (queue/dispatch/ack-timeout sweep/disconnect recovery with attempt caps), remote deploy reusing the unchanged 3.3 pipeline via a machine-PAT deploy-bundle fetch, AgentInstance upserts, and the MachineDetail deployments UI. - Research C5: [`research-phase-8-c5-acp-web-demo.md`](research-phase-8-c5-acp-web-demo.md) — the web-vibecoding-demo reference (browser ↔ portal ↔ acp-bridge → DSH): ACP as the chat payload dialect, permission `optionId` passthrough, session-op mutual exclusion, cancel watchdog, reconnect re-registration, the fold/StreamBuffer streaming model, and fs/terminal channel boundaries. First filled row of the C5 adapter matrix (DSH). - Design C2: [`design-phase-8-c2.md`](design-phase-8-c2.md) — the shipped C2 plan: the normative dial-site × distributability matrix, migration `0007`, the `mcp-runtime` `UpstreamPool` extraction (stdio included), the client-config API contract (machine-PAT exception + secret-leak rules), the `hnx mcp serve` stdio shim, install-adapter shim entries + the Codex adapter, and emitter `emitMode` (client default / server fallback). - Research C5: [`research-phase-8-c5-acp-web-demo.md`](research-phase-8-c5-acp-web-demo.md) — the ACP web-demo reference study (chat dialect, permission/session pitfalls, fold/StreamBuffer) + the completed per-target ACP adapter matrix (claude-code/codex via official Zed adapters, hermes native, zcode deferred). - Design C5: [`design-phase-8-c5.md`](design-phase-8-c5.md) — the shipped C5 plan: the `chat:*` wire protocol + ACP dialect schemas, the semantic `ChatStreamEvent` stream, `AcSession` audit rows (migration `0010`, no FKs), `ChatService` gating/watchdogs/teardown, the daemon's ACP adapter subprocess table + JSON-RPC/stdio client, and the `/chat` web UI. - Research T1: [`research-phase-8-t1-deepseek-harness.md`](research-phase-8-t1-deepseek-harness.md) — DeepSeek Harness (dsh) ground truth pinned to `v0.1.2-rc.1`: the `~/.dsh` home + home-level `cordis.patch.yml` (applies to every profile, hot-reloads), the Agent-Skills format with mandatory frontmatter, `dsh-mcp-client` MCP rows, hook bridges/subagent providers (why they're skipped), and the native `dsh --profile acp` server. - Design T1: [`design-phase-8-t1-deepseek.md`](design-phase-8-t1-deepseek.md) — the shipped T1 plan: the `deepseek` target end to end (install adapter with frontmatter synthesis + marked-region patch surgery, C3 scanner, C5 ACP row, C4 deployability), the T-wave numbering decision (supersedes the 3.8 "other agents" bucket), the supported-harnesses list, and the registry-resilience fix the T1 smoke surfaced. ### Phase 9 — Harness runtime lifecycle 🧪 designed - Research: [`research-phase-9-harness-runtime.md`](research-phase-9-harness-runtime.md) — ground truth for managing the harness software itself: per-CLI install methods (claude native/npm/brew incl. channel + auto-updater interference, codex npm/brew, dsh npm), `--version` shapes, install-method detection by bin path, and each harness's native provider/key config slots (CC `settings.json` env, codex `config.toml` + `auth.json`, dsh `dsh-llm-pi-ai` patch rows + `apiKeyEnv`). - Design: [`design-phase-9-harness-runtime.md`](design-phase-9-harness-runtime.md) — **Agent-first** runtime arm on the inventory payload (the Agent is the primary object; items nest under it), `AgentInstance (source: 'detected')` auto-registration so any detected Agent is chatable (closes the emitter claude-code gap), capture-as-profile for default state, `harness` job type on the C4 pipeline (install/upgrade/pin), `RuntimeConfig` entity (migration `0011`) referencing distributable credentials, per-target native config writers, redacted `runtime:config.get` viewing, waves W1–W4. - Research W6: [`research-phase-9-portal-chat-ui.md`](research-phase-9-portal-chat-ui.md) — the portal half of the ACP reference (`~/acp-ref/portal/`): session list grouped by cwd, the row-sequence fold model (user/assistant-step/tool/system/turn-tail), the disclosure tool-card registry + Read/Diff/Terminal/Search/Io blocks, and stick-to-bottom scroll policy. - Design W5+W6: [`design-phase-9-portal-ui.md`](design-phase-9-portal-ui.md) — the shared `FormDialog` modal container (create flows off the list pages) and the portal-style chat rebuild: Agent cards → session page, machine `baseWorkspace` + daemon-routed `workspace:list` directory picker, `AcSession.cwd/title` (migration `0013`), the enriched `acpToolCallView` wire (toolName/rawInput/content/output), and the Signal-styled stream components. - Design W7: [`design-phase-9-w7-native-sessions.md`](design-phase-9-w7-native-sessions.md) — native agent sessions (list + resume, NO platform session store; migration `0014` drops `ac_sessions`), the one-shape history wire with three producers, and the post-ship § "dsh live streaming" addendum (transcript-file tail streaming, daemon `0.10.1-p9w7`). - Design W7.1: [`design-phase-9-w7.1-dsh-event-tap.md`](design-phase-9-w7.1-dsh-event-tap.md) — the in-process dsh cordis-plugin event tap (spawn-time `--patch` insert of a zero-dep plugin streaming the `session/event` bus back to the daemon over localhost JSON-lines), now the PRIMARY dsh streaming source with the file tail as fallback; daemon `0.11.0-p9w7.1`; rig A/B numbers and the resolved implementation decisions in §Post-ship notes. - Design W8: [`design-phase-9-w8-sender.md`](design-phase-9-w8-sender.md) — **shipped**: the chat Sender (composer) upgrade — a card-style two-row input (autogrow textarea, context-usage meter, circular send/stop toggle) shaped after the reference composer but styled per Signal, with zero wire changes; attach / permission-mode / model / effort controls enumerated as deferred stubs with the wire arms each needs. Also records the claude-acp-bridge reference-code adoption notes and the post-ship finding that the `@agentclientprotocol` claude wrapper reports context occupancy too. - Research W9: [`research-phase-9-w9-composer-controls.md`](research-phase-9-w9-composer-controls.md) — the deferred Sender controls, grounded: ACP's standard session-config surface (`modes`/`configOptions` + `session/set_mode`/`set_config_option` + the two push updates) verified against claude wrapper 0.76.0 / codex-acp 0.16.0 / dsh 0.1.2-rc.1 (support matrix incl. per-adapter image-prompt admission and OPAQUE option values), the portal reference's optimistic-switch pattern, our wire gaps per layer, and a phased A/B/C plan (config selectors → image attach → @ file mention). - Design W9: [`design-phase-9-w9-sender-controls.md`](design-phase-9-w9-sender-controls.md) — **shipped**: the three A/B/C wires — `session_config` stream events (daemon-merged snapshots in the history ring) + `chat:config.set` + `promptCapabilities` on ready; the `image` prompt block with browser-side downscale and the +/paste/drag attach paths; the workspace `files` arm + FilePicker behind `resource_link` chips. Post-ship notes carry the rig E2E (real claude wrapper: selectors round-trip, vision verified, Read-tool file reference). - Design W10: [`design-phase-9-w10-llm-providers.md`](design-phase-9-w10-llm-providers.md) — **shipped**: LLM provider management (cc-switch-inspired) — the `LlmProvider` entity (migration `0015`, three api kinds `openai-chat`/`openai-responses`/`anthropic`, per-Agent support matrix, credential-referenced keys), server-side model-list discovery (`POST /api/llm-providers/query-models`, the platform's second outbound HTTP surface), the provider-first machine page flow, and multi-model via `RuntimeConfigSpec.models` (dsh's native per-provider list; ground truth for codex/claude-code inside). - Design W11: [`design-phase-9-w11-adapter-lifecycle.md`](design-phase-9-w11-adapter-lifecycle.md) — **COMPLETE — A + B + E + C + D + D6 shipped**: B = channel snapshot + tab bar + 一键清理 (server+web, hardened same-day: mount-sync catch-up, opens never close other channels, USER-scoped liveness so one window's refresh never kills another window's tabs) — `chat:channels` per-user snapshot pushes with `channels.sync`, the live-channel tab strip on both chat pages, and `chat:channels.closeAll` (idle now, mid-turn deferred). A = the daemon adapter pid ledger (`~/.hnx/adapters/`, entry written at spawn inside `AcpAgentConnection.start`, kill paths never unlink — audit/sweep own removal, boot sweep in `runDaemon`, initialize-failure kill; daemon `0.13.0-p9w11`). E = disconnect grace + reconnect reconcile — a `/ctl` transport blip no longer kills every channel (daemon `HN_TEARDOWN_GRACE_MS` + server `CHAT_RECONNECT_GRACE_MS`, both default 8000/`=0` off; `chat:reconcile {sessionIds}` → daemon ack `{held}` → server `retainOnly` on every (re)connect; deliberate closes bypass the grace; daemon `0.14.0-p9w11`). C = the adapter-process report (`GET /api/machines/:id/adapters` over `adapters:report`, instant daemon-side from the live sessions map) + the MachineDetail 适配器进程 panel with the owner-or-admin 终止 path (daemon `0.15.0-p9w11`; /ctl presence registration hardened synchronous along the way). D6 resolved 2026-09-15: `lastActiveAt` on the snapshot + 30-minute idle-age tab labels + the 只清理闲置 variant of the broom + `CHAT_IDLE_TTL_MS` (default off), plus two user-found fixes (resume-dedupe while establishing; closing the current channel returns the pane to its welcome state). D = the daemon-side `sessions:list` TTL cache (`SESSIONS_CACHE_TTL_MS` default 15s — hits skip the adapter spawn; `?refresh=1` from the rail's manual refresh bypasses; failures never cache; concurrent requests share one spawn; daemon `0.16.0-p9w11`). - Design W12: [`design-phase-9-w12-opencode.md`](design-phase-9-w12-opencode.md) — **shipped**: OpenCode (SST) as a runtime-managed Agent, full surface — RUNTIME_TARGETS/AgentTarget/SCANNABLE_TARGETS + harness npm jobs (`opencode-ai`) + native `opencode acp` chat row + `applyOpencodeConfig` (provider block + `/v1`-normalized baseURL + `{file:}` 0600 raw key) + wholesale-redacted key viewer + the `~/.config/opencode` scanner (external ground truth in [`research-phase-9-w12-opencode.md`](research-phase-9-w12-opencode.md); daemon `0.17.0-p9w12`; hermes later cancelled 2026-09-17). - Research W13: [`research-phase-9-w13-multi-model-picker.md`](research-phase-9-w13-multi-model-picker.md) — feasibility of making the session model dropdown list ONLY usable (gateway-servable) models, source-verified per adapter: claude-code via the native `availableModels` settings allowlist (wrapper synthesizes unknown ids verbatim), codex via a daemon-side option rewrite (set_config_option accepts raw ids; no config seam exists), opencode via an `harness-nexus/`-prefix filter (its registry already contains our W12 models map), dsh already shipped in W10. Recommended surface: one writer key + one daemon rewrite + one server open-hint; zero schema/web changes. - Design W13: [`design-phase-9-w13-multi-model.md`](design-phase-9-w13-multi-model.md) — **shipped**: the multi-model picker — claude-code writer `availableModels` allowlist, daemon-side model-option rewrite for codex/opencode at all four admission points (establishment / live push / capture history; idempotent, empty-intersection and out-of-picker currentValue semantics), the `chat:session.start` `modelOptions` hint from the stored RuntimeConfig, deepseek untouched (W10). Daemon `0.18.0-p9w13`. - Research W14/W15: [`research-phase-9-w14-w15-plan-commands.md`](research-phase-9-w14-w15-plan-commands.md) — source-verified ground truth for the ACP `plan` (todo) snapshots and `available_commands_update` catalogs across the four shipped adapters: claude-agent-acp converts TodoWrite/Task* EXCLUSIVELY into plan updates (tool calls suppressed) and pushes a rich command catalog; codex-acp maps update_plan + a builtin command list; opencode pushes Command.Info; dsh emits neither. Also: no command-invocation RPC exists (a command is a `/name args` prompt), and the draft subagent protocol (PR #1992) is deliberately not adopted. - Design W14: [`design-phase-9-w14-plan-todo.md`](design-phase-9-w14-plan-todo.md) — **shipped**: the plan/todo panel — a `plan` stream kind (full-replace snapshots, bounded), a stateless daemon arm, fold-carried state, and the TodoPanel above the composer (progress summary, status glyphs); plus the wave's verification deliverable (permissions E2E on claude/opencode, subagent Task-card path; rig truth: codex is the live plan producer today, claude's task lane dormant on CLI 2.1.263). Daemon `0.19.0-p9w14`. - Design W15: [`design-phase-9-w15-commands.md`](design-phase-9-w15-commands.md) — **shipped**: slash commands in the composer — a `commands` stream kind (the agent's advertised catalog, bounded), the `/`-prefix palette (first-word filter, ↑/↓ cycle, bare Enter selects + fills `/name `, Enter-with-args sends as a normal prompt), no fallback table (honest absence for dsh/hermes); platform-deployed plugin commands surface through the agent's own catalog. Daemon `0.20.0-p9w15`. - Research W14.1: [`research-phase-9-w14.1-claude-ground-truth.md`](research-phase-9-w14.1-claude-ground-truth.md) — the post-W14 re-verification of the ask-user/plan surface, probe-driven: the three-layer matrix (native / ACP adapter / portal — claude is the ONLY target with an adapter-side elicitation bridge), the discovery that portal claude sessions run the SDK-BUNDLED CLI (2.1.270, not the native 2.1.263), tool-existence probes (TaskCreate/TodoWrite/AskUserQuestion per env), the raw `elicitation/create` wire capture (top-level method, form mode, oneOf-const schema, the AskUserQuestion mapping), and the `CLAUDE_CODE_ENABLE_TODO_TOOLS=1` revival that made plan snapshots flow E2E. Also corrects the W14 "claude dormant on 2.1.263" attribution. - Design W14.1: [`design-phase-9-w14.1-claude-elicitation.md`](design-phase-9-w14.1-claude-elicitation.md) — **shipped**: Ask User for claude channels — daemon advertises `elicitation.form` + answers the top-level `elicitation/create` request (bounded field view via `takeElicitationView`; empty fields = message-only decline/cancel card), server relays the two stream kinds + watchdog + `chat:elicitation.respond` routing (permission lifecycle mirrored; values verbatim as ACP content), web question cards (enum radios / multi checkboxes / text / number / boolean, required gating, settled cards vanish), plus the companion claude todo/plan revival via the adapter env (url-mode elicitation deliberately NOT advertised). Daemon `0.21.0-p9w14.1`. - Research W16 (feasibility, not scheduled): [`research-phase-9-w16-pi-agent.md`](research-phase-9-w16-pi-agent.md) — onboarding **pi** (`@earendil-works/pi-coding-agent`; the old `@mariozechner` scope is deprecated) as a runtime-managed Agent, verified against pi.dev docs + npm manifests: npm arm + Node ≥22.19 engine, JSON-only W3/W4 surfaces with pi's `api` enum covering ALL THREE of our provider api kinds (first 1:1 target; `!command` apiKey syntax gives the 0600-keyfile pattern), plain-JSONL W7 sessions scan, **no native ACP** (chat = a daemon-side ACP↔pi-RPC bridge; community `pi-acp` 0.0.x as dialect reference), profile deploy partial (Agent-Skills-standard skills + prompt templates; MCP is extension-based — no declarative surface; hooks/sub-agents are TS code). Companion decision recorded in the roadmap: **hermes runtime management cancelled** (2026-09-17). - Design W16: [`design-phase-9-w16-pi-agent.md`](design-phase-9-w16-pi-agent.md) — **shipped**: pi onboarding with the SELF-DEVELOPED in-daemon ACP bridge — the `AgentConnection` surface extraction (chat.ts is now dialect-agnostic) + `PiRpcConnection` (ACP requests ⇄ pi `--mode rpc` JSONL; prompt responses HELD until `agent_settled`; `\n`-only line codec; rig-captured dialect: payload under `data`, deltas under `assistantMessageEvent`), npm runtime arm + Node ≥22.19 warning, the W3 writer (`!cat` 0600 keyfile, baseUrl verbatim) + W4 files, the JSONL sessions rail + leaf-chain replay parser, the deploy adapter (skills/prompts) + scanner, and the W13 `harness-nexus/` model-option intersect. Rig E2E: install 0.85.1 → detected card → provider push (headless PONG) → masked viewer → rail rows → streamed turn (W16OK) → live model switch to doubao. Daemon `0.22.0-p9w16`. - Design #10 (live Sender): [`design-live-sender.md`](design-live-sender.md) — **shipped**: mid-turn config writes unlocked (web-only; server+daemon always forwarded them) + the SERVER-owned send queue (depth 1): `queue_state` stream event (server-emitted only, `flushed` distinguishes run-clear from cancel-clear), busy sends park into a chip above the composer (`QUEUE_FULL` beyond one), the busy→idle transition flushes (chip → fold user row → forwarded prompt), `chat:queue.cancel` (edit = cancel + take-back-to-draft), turn cancel drops the slot, reattach replays it; daemon UNCHANGED. Rig E2E: selects live mid-turn, 排队发送+停止 coexist, auto-flush verified end-to-end. - Research #10 (live Sender): [`research-live-sender.md`](research-live-sender.md) — source-verified per-target ground truth for mid-turn interaction: prompt-while-busy is QUEUED natively by claude-agent-acp (`turnQueue`), steer-joins at opencode, REJECTED by dsh (-32602) and by OUR pi façade; codex 0.16.0 has no rejection path (queued inferred); mid-turn config writes are accepted by every target (claude pushes to the live query, the rest pin per-prompt/next-turn; dsh+pi have NO permission modes) — and the ACP spec leaves all of it implementation-defined while requiring set_mode/config to be callable "whether idle or generating". Baseline conclusion: unlock the selects now; queue in the DAEMON (uniform across targets), not client-side. ### Concept notes (design/) - [`design/profiles.md`](design-profiles.md) — the broader profile concept + intended CLI install flow (future). - [`design/mcp-proxy-legacy.md`](design-mcp-proxy-legacy.md) — original proxy concept sketch; superseded by `phase-2.2-registry.md`. ### Decisions (adr/) - [`adr/0001-initial-stack.md`](./adr/0001-initial-stack.md) — stack rationale. ### Issue-era designs (issue-driven workflow, 2026-09 onward) New work is anchored on GitHub issues (see the repo's `CONTRIBUTING.md`); these are the durable design docs that came out of it. - Design: [`design-fast-session-pipeline.md`](design-fast-session-pipeline.md) — issue #2, shipped: pinned adapter provisioning (`~/.hnx/acp-adapters`, npx fallback, kill switch), the idempotent dist patch set (skip-redundant-setmodel-on-resume on the claude wrapper), and live-channel listings (`liveConnectionFor`). Rig: claude listing 2.7s → 0.13s, resume-open 6.1s → ~1.2s. - Design: [`design-adapter-prewarm.md`](design-adapter-prewarm.md) — issues #3–#4, shipped: the per-target, machine-scoped adapter pre-warm pool (`machines.chat_prewarm`, strict replace-semantics map; pool holds ONE initialized adapter per target, consumed on open, idle TTL 120s, dsh tap armed at prewarm time). Rig: dsh 1.5s → 59–206ms, codex 2.3s → 199ms, claude 1.2s → 666ms, opencode 2.5s → 846–887ms. - Design: [`design-ui-system.md`](design-ui-system.md) — issue #23, shipped: the console's design system as a durable contract — the thesis (structure belongs to the base, materials to the skin; four extension points), the one content principle (protocol material on a **Well**, prose in prose; the data→device mapping table; **numbers never lie**: numerator/denominator + a qualifier; the accent budget of one live thing per screen), the shell geometry (30px spine + 168px plate + 56px chrome bar + readout strip; page identity in the chrome; no ruler column; below 900px drawer + `navstrip`), the type roles (`--app-font-label`, uppercase only in the label role, mono + tabular for all data), and the interaction language (four state surfaces, two-level confirmations with one name throughout, overlays designed on panel materials, four sanctioned motions + reduced-motion final states, pinned row-action column on phones with tap targets as hit AREAS). Also **how a page plugs into the shell** (one route declaration in `nav.ts`, `usePageTitle` + `PageSlot` for identity/actions/margin, the shell owns scrolling unless `layout: 'panes'`) and the **five page recipes** (list / resource-kind / detail / chat / overview). Points to the skin doc for the skin axis. - Design: [`design-skin-system.md`](design-skin-system.md) — issue #23, shipped (Signal + BAY; LEDGER/NIGHTWATCH deferred): the two-axis theme model (`next-themes` mode axis + `data-skin` skin axis with pre-paint script and `hnx.skin` storage), the frozen token contract (scrim, inverted-surface wells, runtime font hooks `--app-font-*`, plus P7's density/material/lamp set), the status device (`Lamp`, with `StateSignal` as the inline mark sharing one `lamp-body` slot — D-13), the full **hook vocabulary** a skin may depend on (`data-region`/`data-slot`/`data-state`/`data-tone`/`data-variant`/`data-nav-group`/`data-bay-number`/`data-live`/`data-density`, plus the empty `marginalia` slot) and the rule that an opt-out must be a **variant** the skin can read, the **control scale** (`--control-h*`, `--row-ctl-h` = "the skin's small control, never taller than the row that holds it", `--touch` as a hit AREA not a bigger box), **addresses & navigation** (English uppercase bay addresses engraved from data — `label` vs the translated `labelKey` — the 30px vertical spine, the `navstrip` phone jump bar carrying every destination, `PageAction` shrinking to its icon below `sm`), and the rule that bands and lists are composed from kit devices, never hand-rolled (the session rail, the Sender's baseline toolbar). Topology registry (constellation / plate / radar, all real), the two hard skin rules as test assertions, and the `scripts/ui-snap.mjs` snapshot rig (single-mode skins skip the locked mode). Layout skeleton never changes. - Design: [`design-cc-marketplace-deploy.md`](design-cc-marketplace-deploy.md) — issue #6, shipped: claude-code profiles deploy ONE-CLICK from the machine page through the 3.5 emitter — the daemon drives CC's own plugin CLI (`marketplace add/update` + install-or-update, state read from CC's JSON files, never CLI text); the emitter accepts machine-ctl PATs (no secret in the job payload); `profile.version` became editable (the publish switch — CC compares versions); the web Edit dialog covers name/description/version + entry re-picking. Rig: deploy + one-click update 1.0.0→1.1.0 verified. - Design: [`design-admin-scope.md`](design-admin-scope.md) — issue #36, shipped: personal resources are owner-ONLY for every role (machines, jobs, inventory, workspace, runtime-config, credentials, mcp-servers, profiles, resources, llm-providers — 404 existence-hiding, admin included); an admin's extras are exactly user management, the registration switch, and global-row create/modify (`canManage`); posture is all-`self`, the realtime `admins` room is gone. - Design: [`design-version-surfacing.md`](design-version-surfacing.md) — issue #37, shipped: build versions everywhere — `hnx --version`, daemon reports its real package version (the invented `0.25.0-i6` is dead), server exposes `GET /api/system/info` reading shared's lockstep manifest, hello ack carries `serverVersion`; skew WARNS (web chip + daemon line), proto stays the gate; shared gained `compareVersions`. - Design: [`design-client-logbook.md`](design-client-logbook.md) — issue #38, shipped: the daemon's local logbook — `~/.hnx/logs/ops.log` (operation trail) + `comm.log` (metadata-level /ctl traffic, chat:event bursts aggregate to one summary line, connect/disconnect markers; `HNX_LOG_COMM=payload` is the debug-only escape hatch), hard rotation 256KB×3 / 1MB×5, `hnx logs [--tail|--bundle]`. Built as a ring-buffered BUS with file sinks as subscribers — the groundwork for the TUI (#39). - Design: [`design-cli-tui.md`](design-cli-tui.md) — issue #39, shipped: `hnx tui` — the daemon's live console (daemon in-process via `startDaemon` + a zero-dep nmon-style stacked-band renderer): metrics bar, agents/sessions pane (`sessionsSnapshot` + `prewarmStatus`), ops pane (bus op/log entries; console captured while the TUI owns stdout), comm pane (its own `CommAggregator` — same burst collapse as the file), and a per-(target, model) token pane (`UsageLedger`; the `usage` event gained dialect-normalized `cacheReadTokens`/`cacheWriteTokens`). Single-daemon pid lock (`DAEMON_LOCKED` — two /ctl sockets would double-run jobs). `--dump`/non-TTY → one-shot snapshot. - Design: [`design-dsh-client-version-gate.md`](design-dsh-client-version-gate.md) — issue #46, shipped: fast-moving Agent clients get NO back-compat — the daemon integrates ONE ground-truth line (dsh 0.2.0-rc.2) and the connect path REFUSES out-of-range clients with an upgrade hint (`adapters.ts` `minVersion` floor + `acp/version-gate.ts` probe of ` --version`; enforced at channel open BEFORE any spawn and at prewarm; `HN_ACP_COMMAND_` overrides stay ungated). Rides the same issue's session-log v4 rewrite (W7 #46 addendum) and tap v2 (W7.1 #46 addendum). - Design: [`design-service-layer.md`](design-service-layer.md) — issue #53, shipped (17 slices; blocks-unlocks #52): principal-carrying services in `packages/server/src/services/` — the single authorization enforcement point (#36 rules move INSIDE services; routes thin to authenticate → parse → service → reply; `Principal = {userId, role}` is an explicit parameter; AppError-only failures; Fastify-free, no env, realtime dispatch stays at routes). One slice per module, assistant-relevant first (resources → skills-hub → machines → system → …); closes only at FULL extraction (the point is consistency — no permanent mixed state). Route tests pass unchanged through every slice = the regression net. - Design: [`design-provider-model-registry.md`](design-provider-model-registry.md) — issue #51, shipped: model configs live ON the LlmProvider row (`models: ProviderModelConfig[]`, JSON column) — regular (id, type chat|embedding, displayName, contextWindow, maxOutputTokens, vision) + advanced (temperature, topP, serverTools for openai-responses, extraBody for openai-compatible); `query-models` demoted to a seeding button inside the provider dialog ONLY; consumer forms (runtime-config, assistant) pick from the registry — one-shot cutover, no dual-track; spec snapshots become full model objects so `applyPiConfig` writes real contextWindow/maxTokens/name (usage contextSize unhides); advanced params apply per-consumer capability, stored-but-unused is never faked. - Design: [`design-platform-assistant.md`](design-platform-assistant.md) — issue #52, agreed (depends on #50+#51): a server-embedded pi-agent-core/pi-ai assistant operating the platform AS the user — identity via an AsyncLocalStorage actor context feeding the root auth hook (fresh user lookup per call, `viaAssistant` audit marker, NO minted tokens; unforgeable from outside the process); tools = `app.inject()` against our own REST surface behind `beforeToolCall` group gates + audit rows; no delete/credential tools in v1; MCP reuses the server-side McpRegistry pool; skills inject as prompt index + `read_skill` (progressive disclosure); sessions are platform-owned (explicit W7 counter-exception) with pi state rebuilt per turn; streaming rides `/app` rooms with a new `assistant:*` family reusing ChatStreamEvent shapes; Chat page gains a pinned-first assistant 端 (dropdown at the old back-link, star-pinned default 端, sender Agent+Model selects with next-turn effect); per-user multiple named assistants with a DataTable+FormDialog config page. - Design: [`design-session-delete.md`](design-session-delete.md) — issue #55, shipped (Phase A): session deletion on BOTH rails — platform assistant rows (REST delete + live guard + owner push) and native agent rows (`DELETE /api/agent-instances/:id/sessions/:sid` → `sessions:delete` over /ctl, new daemon capability bit `sessions-delete`). Per-target arms: ACP `session/delete` (claude-code yes; opencode only ≥v2.0.7, capability-gated; codex rides the CLI's own `codex delete --force` — rollout-file truth for idempotency, never unlink), dsh rm-rf of the `` dir, pi unlink (both idempotent). Live channels refuse (close first, both ends). Web: shared `SessionRow` (desktop hover trash + phone `SwipeRow` swipe-left, zero-dep) + kit ConfirmDialog.