Repository navigation
roadmap
Status: historical record (through Phase 9 W16, 2026-09). Forward planning now lives in [GitHub Issues + Milestones] (https://github.com/sinrimin/harness-nexus/milestones) — each release milestone selects the issues that ship in it. The workflow is described in the repository's [CONTRIBUTING.md] (https://github.com/sinrimin/harness-nexus/blob/main/CONTRIBUTING.md).
Phased so each milestone is independently useful. ✅ done, 🚧 in-progress, ⏳ not
started. Doc links point at the PRD (prd-) and design (design-).
- ✅ Monorepo layout, tooling, configs
- ✅ Domain model + storage ports (
UnitOfWork) - ✅ Server boot path (Fastify + storage factory + health routes)
- ✅ SQLite storage + migrations
- ✅ Users / roles (admin, user) / registration switch + bootstrap admin
- ✅ JWT access tokens + PAT (
hnpat_…) - ✅ Front- and back-end permission interceptors
- ✅ Web auth UI (login, register, dashboard, users, settings)
- PRD:
prd-phase-1-auth.md· Design:design-phase-1-auth.md
- ✅ Credential store (AES-256-GCM at rest, masked previews)
- ✅ MCP client connection CRUD (SSE / Streamable HTTP; stdio via direct mode)
- ✅
${cred:NAME}placeholder injection (url/command/args/env/headers) - ✅ MCP mode:
proxy(server dials) /direct(tool dials); stdio forces direct - ✅ Scope model: global (admin-mutate) / personal (owner-only)
- PRD:
prd-phase-2.1-credentials.md· Design:design-phase-2.1-credentials.md
- ✅
McpRegistry: pooled upstream connections, namespaced tool aggregation - ✅
${cred:NAME}placeholders resolved into real values at connect time - ✅ Proxy re-exposure:
/mcp(Streamable HTTP) +/mcp/sse(SSE) - ✅ Profile CRUD + explicit profile routing (
?profile=<id>, PAT-gated) - ✅ Live connection status (
GET /api/mcp-servers/status) + dashboard mesh - PRD:
prd-phase-2.2-registry.md· Design:design-phase-2.2-registry.md
Status: on hold. Not currently planned for development. The original Phase 4 line item "Callable-function script editor + test-run (with 2.3)" is removed until this phase resumes.
- ⏸️ Admin-authored JS wrapping vendor APIs as MCP tools, run in a sandbox
- ⏸️
isolated-vmexecutor + host-injected allowlistedctx.fetch - ⏸️
ToolSourceabstraction (CallableRegistry alongside McpRegistry) - ⏸️ Profile entries for callable-functions; management UI
- PRD:
prd-phase-2.3-callable-functions.md· Research:research-phase-2.3-sandbox.md
- ✅ Per-row live connection status + tool-count badge on the MCP Management page (state-encoded colors per the Signal system; status polled on an interval)
- ✅ Explicit Connect/Disconnect buttons for proxy servers (incremental — startup auto-pooling from 2.2 is unchanged; Connect is for forcing a reconnect after a fix, Disconnect drops a live connection on demand)
- ✅ Expandable tool-inspection panel: lists the upstream's tools (original names)
with description +
inputSchemaparameters, plus a Refresh button - ✅ Direct rows show a neutral "dialed by the tool" hint, no connect controls
- PRD:
prd-phase-2.4-connect-tools.md· Design:design-phase-2.4-connect-tools.md
Restructured around the ECC adapter-factory pattern + plan/apply. Priority: Hermes → Claude Code → Codex. ZCode is out of install scope (no reproducible reference; retained in the enum but unsupported).
Direction decided — "Harness Nexus client" unification (2026-09): the
hnxCLI, the Phase 5 ACP bridge, machine registration, client-side MCP serving, and remote deploy fold into one Harness Nexus client program, under the broader repositioning of Harness Nexus as an agent orchestration platform (control plane = server/web, data plane = client). See Phase 8 below — PRDprd-phase-8-client.md, designdesign-phase-8-client.md. Consequences for this phase: 3.6 and 3.7 are absorbed into Phase 8 (C2 and C3 respectively); the local-write CC fallback adapter stays deferred.
- ✅ 3.1 —
McpServer.mode(proxy/direct) + stdio re-enabled in direct mode; "MCP Connections" → "MCP Management"; removedproxied(mode alone decides pooling) - ✅ 3.2 —
Profile.target(single, immutable) + target-narrowed creation form +TARGET_IMMUTABLE;codexadded to the enum,zcoderetained-but-unsupported - ✅ 3.3 — Install pipeline skeleton: target adapter factory + registry + plan/apply separation + install-state ledger +
hnx installCLI (dry-run default). No real target adapter yet. - ✅ 3.4 — Hermes adapter (priority 1). Python plugin bundle +
config.yamlmcp_servers:merge +AGENTS.mdrules;${HN_PAT_*}env placeholders. - ✅ 3.5 — Marketplace emitter (priority 2; re-planned). Serve each user's claude-code profiles as a native CC plugin marketplace over HTTP —
claude plugin marketplace add <PUBLIC_BASE_URL>/api/marketplace/<PAT>/marketplace.json+ archive-source zips; claude owns install/update/uninstall. Profile entries gained the{resourceId, kind}resource arm. The local-write CC adapter is demoted to an old-CLI (<2.1.224) / airgapped fallback — deferred behind the emitter. - ➡️ 3.6 — Codex adapter → absorbed into Phase 8 (C2): under the client
stdio unification every target emits one stdio shim entry, which makes the
Codex adapter the trivial case (TOML
config.tomlstdio entry). - ➡️ 3.7 — Cross-target profile import → absorbed into Phase 8 (C3): the daemon's inventory scan + diff + one-click import generalizes it
- ➡️ 3.8 — "Other well-known agents" half → superseded by the Phase 8 T-wave (T1 = DeepSeek Harness, explicitly prioritized ahead of the rest); ECC/Superpower import adapters remain here, pending
- PRD:
prd-phase-3-install.md· Design:design-phase-3-install.md· Design 3.5:design-phase-3.5-marketplace-emitter.md - Research:
research-phase-3-ecc-install-patterns.md(adapter factory + plan/apply + install-state; Codex ground-truth) ·research-phase-3-plugin-targets.md(per-target formats; CC/Hermes detail, ZCode superseded) ·research-phase-3.5-marketplace-emitter-spike.md(empirical CC marketplace protocol constraints)
- ✅ 4.1 — PAT management UI (list / create-once / revoke); backend ready
- ✅ 4.2 — Sub-agent management: shared Resource backend (SQLite v5
resourcestable, dual-driver repos replacingmemoryResourceStub,/api/resourcesCRUD, zod schema, SDK methods) + resource browser + sub-agent markdown editor - ✅ 4.3 — Rule management (rule markdown editor on the 4.2 backend)
- ✅ 4.4 — Command management: slash-command editor (single-file markdown;
commands/<name>.mdper target). Mirrors 4.2/4.3 —AVAILABLE_KINDS+ editor variant only. - ✅ 4.5 — Hook management: structured event→command editor emitting
hooks.json+ event/target support matrix (packages/shared/src/hooks.ts, shared with Phase 3.2). Hermes excluded (different hook model); events validated against the matrix. Research:research-phase-4.5-hooks.md - ✅ 4.6 — Skill management (local): inline skills + multi-file bundles.
New
ResourceSourceinline-bundlevariant (SKILL.md +references/+scripts/; ~42% of real skills are multi-file). Single-file skills reuseinline. External references / hub search are Phase 7. - PRD:
prd-phase-4-web-ui.md· Design:design-phase-4-web-ui.md - Order: by difficulty — command (4.4) → hook (4.5) → skill (4.6). External skill references / hub search are split out into Phase 7.
- ➡️ Absorbed into Phase 8 (C1 daemon + control channel, C5 ACP chat). The
packages/acp-bridgeskeleton is deleted when C1 lands.
- ➡️ stdio bridge entry → resolved by Phase 8 (C2): the per-session
hnx mcp servestdio shim IS the stdio entry; no server-side spawning of local processes ever happens. - ⏳ Chat-tool Channels (route external chats to controlled agents) — adjacent to Phase 8's C6 orchestration
- ⏳ LLM-WIKI knowledge base
- ⏳ Global memory / notes
Split by "independently verifiable + increasing difficulty + outbound network last". 7.1 is the zero-outbound foundation; 7.2 opens the first server-side outbound path (isolated in its own PR); 7.3 closes the UX loop; 7.4 is the large, least-certain multi-source block (can stop partway).
| # | Sub-phase | Status | Carries | Depends on | Outbound? |
|---|---|---|---|---|---|
| 7.1 | plugin source + trust model | ✅ |
ResourceSource plugin variant (CC marketplace 4 source kinds); trust tiers (builtin/trusted/community) + provenance pin (content_hash); SkillSource port (abstract, one no-op inspect); flip validateSkillResource + smoke |
Phase 4.6 | none (store spec only) |
| 7.2 | marketplace allowlist fetch | ✅ | server's first outbound path: GET /api/skills/marketplaces/:id/plugins (fetch + cache + timeout marketplace.json); MARKETPLACE_ALLOWLIST config; trust by repo owner; "save marketplace entry as skill resource" |
7.1 | yes (allowlisted GitHub raw) |
| 7.3 | hub search UI | ✅ | web marketplace browser (category filter + search + trust badge) → "save as skill resource" → reuses 7.1 plugin source storage; install-warning UX (trust tier + missing-pin warning) |
7.2 | no (calls 7.2 endpoint) |
| 7.4 | Hermes-style multi-source | ✅ | 4 SkillSource adapters (github/well-known/url/marketplace-wrapper); parallel search + per-source timeout + merge dedupe (identifier key, trust-rank); /api/skills/search; hub page dual-mode (browse + search); skills-sh/browse-sh deferred, clawhub/lobehub/hermes-index skipped |
7.1, 7.3 | yes (github/well-known fetch) |
- PRD:
prd-phase-7-skills.md· Design 7.1:design-phase-7.1-plugin-source.md· Design 7.2:design-phase-7.2-marketplace-fetch.md· Design 7.3:design-phase-7.3-hub-ui.md· Design 7.4:design-phase-7.4-multi-source.md· Research:research-phase-4.4-skills.md -
Research corrections carried into the PRD (ground-truth verified):
Hermes has 10 adapters (not 9 —
OptionalSkillSourceis theofficialsource); trust is 4 tiers internally (the 4th,agent-created, is off-by-default and not surfaced); the live CCmarketplace.jsonhas 4 source kinds (url/git-subdir/string-path/github) and nonpm;categoryis the filter axis (243/257 entries), nottags(3) ormetadata. - Out of scope: content security scanning (Hermes
skills_guard.pymodel) — Harness Nexus stores references, the target tool executes.
Repositioning: from asset-integration platform to agent orchestration platform. Control plane (server + web) / data plane (one
hnxclient program per enrolled machine). Decisions locked in the PRD; protocol, data model, and per-phase plan in the design doc.T-wave (target onboarding): adding a harness as a supported target spans install adapter + inventory scanner + ACP chat row + remote deploy — all but the first are Phase 8 surfaces, so onboarding lives here. The supported-harnesses list (one-click install + ACP chat): Claude Code, Codex, DeepSeek Harness, OpenCode — the user-facing docs mention only these four for now (hermes keeps working unlisted).
| # | Sub-phase | Delivers | Absorbs / impacts |
|---|---|---|---|
| C1 ✅ | daemon + machine registration |
hnx daemon + Machine entity + enrollment (machine PAT) + WSS control channel (Socket.IO /ctl) |
Phase 5 (half); deletes acp-bridge
|
| C2 ✅ | client MCP serving | stdio shims (hnx mcp serve), credential distributability + dial-site routing, /mcp outlet narrowing, emitter client mode |
2.1 mode, 2.2 pooling, 3.5 emitter, 3.6 |
| C3 ✅ | inventory + diff + import | per-target scans, profile diff, one-click import into resources + profile | 3.7 |
| C4 ✅ | remote deploy | job abstraction (queue/dispatch/replay) over the 3.3 pipeline + Agent instances | reuses 3.3 |
| C5 ✅ | ACP chat |
chat:* over /app↔/ctl (semantic stream + ACP payload dialect), daemon ACP adapter subprocesses (claude-code/codex/hermes), permission watchdog, AcSession audit, web /chat UI (owner-only, off by default) |
Phase 5 (other half) |
| T1 ✅ | DeepSeek Harness onboarding |
deepseek AgentTarget: install adapter (~/.dsh skills + home cordis.patch.yml MCP rows via the hnx mcp serve shim), C3 scanner, C5 ACP row (dsh --profile acp), C4-deployable |
supersedes 3.8 "other agents"; priority: first |
| C6 | orchestration | deliberately undesigned until C1–C5 land | Phase 6 Channels (adjacent) |
- Key locked decisions: global-scope credentials non-distributable by default
(server
/mcpis their sole outlet); daemon is on-demand and MCP never depends on it; agents consume MCP uniformly as stdio shims (proxy/direct deleted, dial site derived + admin override); realtime = Socket.IO over WSS with one bidirectional namespace per role —/app(browser: UI push + chat + agent control) and/ctl(daemon: management + routed interactive traffic; daemon adapts semantics ↔ agent protocol) — plusdomain:verbevent names, room addressing, and session-per-channel isolation; the channel pattern is the substrate for future file-management / web-terminal extensions. - PRD:
prd-phase-8-client.md· Design:design-phase-8-client.md· Design C1:design-phase-8-c1.md· Design C2:design-phase-8-c2.md· Design C3:design-phase-8-c3.md· Design C4:design-phase-8-c4.md - ✅ C1 shipped (2026-09, branch
phase-8-c1):Machineentity + repos + SQLite migration0006; machine PATs (scopes: ['machine-ctl']) rejected by the REST hook (realtime-only blast radius); realtime v0 —fastify-socket.iowith/ctl(daemon auth,machine:hello, rooms) +/app(JWT/PAT push,user:<id>/adminsrooms,machine:status), pureMachinePresencestate machine;/api/machinesCRUD (enroll token shown once, delete force-drops sockets + revokes); SDK machines methods;hnx enroll/hnx daemon(config in~/.hnx/config.json0600); Machines web page with live presence;acp-bridgepackage deleted. - ✅ C2 shipped (2026-09, branch
phase-8-c2):McpServer.modedeleted →dialSite: auto|client|server(migration0007folds proxy→auto, direct→client);Credential.distributable(personal always true, global admin opt-in); pure dial-site derivation inshared/dial-site.ts; NEWpackages/mcp-runtime(UpstreamPool— SSE/HTTP/stdio dialing + namespacing + passthrough, shared by the server registry and the shim);/api/client/mcp-config(machine-PAT exception; resolved transports for client-dialed only, secret-leak tested); registry pools exactly the server-dialed set (/mcpoutlet contract unchanged);409 STDIO_REQUIRES_CLIENT/409 CREDENTIAL_NOT_DISTRIBUTABLE/NOT_SERVER_DIALED;hnx mcp servestdio shim (low-levelServer, JSON schemas pass through); install adapters emit ONE baked-path shim entry (Hermes simplified, install-time secret inlining gone) + Codex adapter (skills/prompts/TOML[mcp_servers]merge — 3.6 delivered); emitteremitMode: clientdefault (stdio entry, no PAT env var) withserverfallback (EMITTER_MODE); web dial-site/distributable forms. - ✅ C3 shipped (2026-09, branch
phase-8-c3): daemon per-target scanners (claude-code~/.claude+~/.claude.json, codex~/.codexincl. TOML[mcp_servers]parse, hermes plugins/config.yaml/AGENTS.md) reporting normalized snapshots over/ctl(inventory:scan|report|collect|payload, auto-report after every hello, capabilityinventory);machine_inventorystorage (migration0008, latest per machine+target, cascades on machine delete);InventoryCoordinatorrequest/response waiters; purediffInventoryin shared (coarse MCP arm, hook entries skipped);/api/machines/:id/inventory+/scan+/diff+/import— import = collect → reuse-or-create (identical body reuses ⇒ idempotent re-import) → MCP items becomeMcpServerrows with daemon-side env/header redaction to${cred:<KEY>}placeholders → a new personal profile owned by the machine's owner;/appinventory:updatedpush; MachineDetail web page (inventory tables, diff view, import wizard) linked from Machines rows; SDK inventory methods; vitest wired into the CLI package. - ✅ C4 shipped (2026-09, branch
phase-8-c4):Jobstate machine (queued → dispatched → running → succeeded | failed, queued-only cancel; disconnect / ack-timeout-sweep recovery requeues withattempts+1, ≥JOB_MAX_ATTEMPTS⇒failed JOB_ABANDONED; terminal states ignore stale replay) inJobService(app.realtime.jobs);AgentInstanceupserted per (machine, profile) on deploy success — the C5/C6 addressable unit; migration0009+ both drivers;/api/machines/:id/jobs(POST deploy — softdeploy-capability gate when online,409 TARGET_NOT_DEPLOYABLEfor claude-code which stays on the 3.5 emitter path) + jobs list + cancel +/api/machines/:id/agents;GET /api/client/deploy-bundle(machine PAT REST exception #2 — the resolved bundle the daemon's executor fetches); daemonjob:dispatchhandler reusing the UNCHANGED 3.3 pipeline (plan/apply/ledger,job:progressper phase);/appjob:updatepush; MachineDetail Deployments card (deploy form, live jobs table, agent instances). C3's interactive scan/import stay direct request/response — jobs are for replayable fire-and-forget work. - ✅ T1 shipped (2026-09, branch
phase-8-t1-deepseek):deepseekAgentTargetend to end. Research pinned to dshv0.1.2-rc.1(~/.dshhome; home-levelcordis.patch.ymlapplies to EVERY profile and hot-reloads live; Agent-Skills format with MANDATORY frontmatter name+description, kebab-case;dsh-mcp-clientstdio rows; nativedsh --profile acp). CLI adapter (install/adapters/deepseek.ts): skills →~/.dsh/skills/<slug>/with frontmatter synthesis, commands → flatskills/<slug>.md(the/namesurface), MCP → per-profile MARKED region in the home patch (idempotent replace, other profiles' regions and user rows untouched), rule/sub_agent/hook skipped with warnings; C3 scanner (bundles→skill, flat→command, patch rows keyed byserverName); C5 ACP row['dsh', '--profile', 'acp'](HN_ACP_COMMAND_DEEPSEEKoverride); C4-deployable; web target pickers.HOOK_SUPPORT['deepseek'] = null(the CC/Codex hook BRIDGES are opt-in per-profile packages). Surfaced + fixed a latent registry crash: stdioauto+ missing credential (the C3-import${cred:KEY}shape) derives server-dial and crashed the fire-and-forget reload — now skipped with a warning (registry-resilience.test.ts). Supported harnesses (install + ACP): Claude Code, Codex, DeepSeek Harness, OpenCode (W12).
Cross-cutting (not a numbered phase):
- ✅ npm alpha shipped —
@harness-nexus/{core,shared,mcp-runtime,sdk,cli}@0.1.0-alpha.2, public,latest= alpha by design (young tool,npxmust work out of the box). Manifest prep:filesallowlists,exportsmaps,publishConfig.access,prepublishOnlybuild guards,packages/cli/README.mdas the npm landing page. - ✅
ci.yml— install → build → typecheck → test on every push + PR (Node 20, the engine floor). First run green onf37e746. - ✅
release.yml— manual workflow_dispatch publishing via OIDC trusted publishing (per-package trusted publisher registered on npmjs.com; zero npm credentials in GitHub). Encoded gotchas: pnpm lacks tokenless publishing →pnpm pack(workspace-version substitution) thennpm publish <tarball> --tag latest; node ≥ 22.22.2 for npm@latest; npm ≥ 12 requires an explicit--tagfor prerelease versions. - Manual channel (dev machine): granular bypass-2FA token + IP allowlist,
npm_config_registry=https://registry.npmjs.org/ pnpm -r publish. - Release procedure: bump the five manifests → push → run the workflow.
Manage the harness software itself on machines — presence, version, install/upgrade, and the LLM provider/model configuration it runs with — the piece users asked for after Phase 8 shipped artifact management only ("一键部署/升级 claude code / codex / dsh 软件本体,扫描 bin 与版本,可查看配置").
- Research:
research-phase-9-harness-runtime.md· Design:design-phase-9-harness-runtime.md(both 2026-09). Rides the Phase 8 machine/daemon/job infrastructure. - Waves:
-
W1 Agent-first inventory — SHIPPED (2026-09) —
runtimesarm folded into every inventory report (bin path,--version, install method; daemonruntimecapability), Agent cards with items nested under them + "not installed" states (MachineDetail),AgentInstance (source: 'detected')auto-registration with two-report hysteresis and deploy-precedence so any detected Agent is chatable (closes the emitter-installed claude-code gap), and capture-as-profile (POST /api/machines/:id/inventory/capture, zero-entry profiles allowed). -
W2 Install / upgrade / pin jobs — SHIPPED (2026-09) —
type: 'harness'jobs on the C4 pipeline (owner-only,harness-capability gated); daemon executor with npm command table +claude updatefor native CC upgrades +DISABLE_AUTOUPDATERsettings merge; post-install re-probe auto-report; Agent-card Install/Upgrade/pin controls. -
W3 Provider config push — SHIPPED (2026-09) —
RuntimeConfigentity (migration0012, per machine × target) referencing a distributable credential;PUT /api/machines/:id/runtime-config/:targetqueues anapply-configharness job; the daemon fetches the resolved{spec, secret}bundle at execution time (machine-PAT REST exception #3) and writes each harness's native slots merge-preservingly (CCsettings.jsonenv + model, codexconfig.tomlroot keys + provider section withrequires_openai_auth+auth.jsonapikey, dsh provider+default-model patch rows +~/.dsh/.env— dsh's own user-env credential layer). §11 open questions resolved with source-verified facts (research §8): codex removedwire_api="chat"(Responses-only), CC version-less installs track@stable. -
W4 Redacted config viewer — SHIPPED (2026-09) — daemon-side
runtime:config.getwith key-name-aware masking (JSON walk, unanchored TOML/YAML line masking, wholesale.envmasking, broken-JSON fallback; masked before upload, display paths only) over the inventory-style coordinator;GET /api/machines/:id/runtimes/:target/config(live round-trip,runtime-config-viewcapability gate); right-side Drawer in MachineDetail. "Re-scan after apply" dropped as a no-op (config files aren't scanned artifacts — the View button is the fresh read). -
W5 Modal containers — SHIPPED (2026-09) — the shared
FormDialogshell; every create flow (Profiles/Credentials/Mcp/Machines/Users, Resources re-shelled) opens in a modal instead of an inline Card. Also fixed the dev-only vite proxy swallowing/mcp-servers. Design:design-phase-9-portal-ui.md§W5. -
W6 Portal chat — SHIPPED (2026-09) — chat rebuilt as Agent cards →
session page (
/chat/agents/:id): left session list grouped by workspace cwd, right the portal-reference row stream (assistant steps, lifecycle tool rows, disclosure cards with Read/Diff/Terminal/Search/Io bodies, markdown + code highlight, turn tails, stick-to-bottom scroll). New sessions pick a subdirectory of the machine'sbaseWorkspace(migration0013; daemon-routedworkspace:listpicker;directoryonchat:session.open); theacpToolCallViewwire carries toolName/rawInput/content/output. Research:research-phase-9-portal-chat-ui.md· Design:design-phase-9-portal-ui.md§W6. -
W7 Native agent sessions — SHIPPED (2026-09) — the platform
persists NOTHING session-shaped (
ac_sessionsdropped, migration0014; ChatService is live-channel-only; "close" is now disconnect). The session rail lists the AGENT'S OWN store live (sessions:listover /ctl, capabilitysessions; claude-code/codex via adaptersession/list, dsh via a multi-frame-zstd file scan of~/.dsh/sessions); row click resumes (session/loadwith replay for claude/codex,session/resume+ transcript-parse for dsh) and history ships aschat:history— user blocks + ordinary events, folded through the same reducer; a per-channel ring replays on page-refresh rejoin. Design + adapter ground truth:design-phase-9-w7-native-sessions.md. W7.1 addendum (SHIPPED): the in-process dsh event tap — spawn-time--patchinsert of a zero-dep cordis plugin streaming thesession/eventbus over localhost JSON-lines — is the PRIMARY dsh streaming source (rig A/B: 107 deltas / 1ms median gap vs the tail's 3–4 batches), with the transcript tail as fallback andHN_DISABLE_DSH_TAP=1as the A/B switch. Design:design-phase-9-w7.1-dsh-event-tap.md. -
W8 Sender (composer) upgrade — SHIPPED (2026-09) — the chat
composer became a card-style two-row input (autogrow textarea +
toolbar with a context-usage meter and a circular send/stop toggle),
feature-shaped after the reference composer but styled per Signal;
zero wire changes. The new
@agentclientprotocolclaude wrapper reports context occupancy too, so the meter is live for claude-code as well as dsh. Attach / permission-mode chip / model and effort selectors remain deferred stubs (each needs a wire arm first). Design + post-ship notes:design-phase-9-w8-sender.md. Shipped with it: the chat channel lifecycle hardening + budget redesign (the W8 rig pass exposed three coupled defects — a page that never released the channel it left, a daemon that dropped closes racing the establishment, and a server that could not reap a restarted daemon's ghost channels; a full cap made sessions look empty). The budget itself was then redesigned per user feedback: 12 total / 5 active per machine, eviction of the oldest non-busy channel instead of rejection, MACHINE_BUSY at prompt time, and open-channel visibility (listingopen/openChannelId+ rail rejoin instead of hidden rows). See the C5 design doc § "Channel lifecycle hardening" and § "Channel budget redesign". -
W9 Sender controls — SHIPPED (2026-09) — the four deferred composer
controls, all riding STANDARD ACP surface verified across claude wrapper
0.76.0 / codex-acp 0.16.0 / dsh-acp 0.1.2-rc.1: permission-mode / model /
reasoning-effort selectors (
session_configsnapshots +chat:config.set, data-driven rendering, opaque values, dangerous modes confirm-first), image attachments (inlineimageprompt blocks with browser-side downscale,promptCapabilities.imagegating, thumbnails + lightbox; rig-verified with real model vision), and file references (resource_linkchips via the workspacefilesarm + a lazy picker behind+/trailing@; the agent reads them with its own tools). Research:research-phase-9-w9-composer-controls.md· design + E2E notes:design-phase-9-w9-sender-controls.md. -
W10 LLM provider management — SHIPPED (2026-09) — cc-switch-inspired
provider catalog: the
LlmProviderentity ({name, api kind, baseUrl?, credentialName}with the three kindsopenai-chat/openai-responses/anthropicand a per-Agent support matrix so the machine page only offers providers the target speaks), a server-side 获取模型 model-list discovery button (POST /api/llm-providers/query-models— the platform's second deliberate outbound HTTP surface; the key never leaves the server), a provider-first MachineDetail flow (pick provider → pick/fetch model → apply; manual arm kept), and multi-model viaRuntimeConfigSpec.models(dsh writes its native per-provider switchable list; codex/claude-code are single-default by construction — ground truth in the design doc §6). Design:design-phase-9-w10-llm-providers.md. -
W13 Multi-model picker — SHIPPED (2026-09) — the session model
dropdown lists only platform-configured models (default +
modelsextras): claude-code via the writer'savailableModelssettings allowlist (wrapper-native, unknown ids synthesized verbatim), codex + opencode via a daemon-side option rewrite on our wire (codex accepts raw ids on set; opencode's registry already holds ourharness-nexus/*values), deepseek native since W10. The configured set rideschat:session.start modelOptionsfrom the stored RuntimeConfig. Research:research-phase-9-w13-multi-model-picker.md· design:design-phase-9-w13-multi-model.md. -
W14 Plan/todo panel + verification — SHIPPED (2026-09-17) — the
agent's ACP
plansnapshots (FULL replace; claude wrapper surfaces TodoWrite/Task* exclusively this way, codex maps update_plan) became aplanstream kind + a TodoPanel above the composer (collapsed by default, progress summary, status glyphs). The wave's second deliverable — verification — confirmed the subagent (Agent-tool card) and permission (claude allow-once / opencode once-always-reject) flows E2E; rig truth: codex is the live plan producer today, claude's task-lane dormant on CLI 2.1.263 (headless sessions expose no task tools — the wire+panel are ready for when they do). Research:research-phase-9-w14-w15-plan-commands.md· design:design-phase-9-w14-plan-todo.md. -
W15 Slash commands — SHIPPED (2026-09-17) — the composer's
/palette lists the agent's OWN advertised commands (available_commands_update→ acommandsstream kind; claude 46 on the rig incl. emitter-installed plugin commands, codex 6, opencode 3, dsh none — honest absence, no fallback table). Invoking one is just a/name argsprompt (no new RPC); palette interaction per the portal reference (first-word filter, bare Enter selects + fills, Enter-with- args sends). Research:research-phase-9-w14-w15-plan-commands.md· design:design-phase-9-w15-commands.md. -
W14.1 Ask User (ACP elicitation) + claude todo/plan revival —
SHIPPED (2026-09-17) — post-W14 review re-verified the ask-user
surface against the pinned adapters AND live probes (ground truth:
three-layer matrix, the SDK-bundled CLI 2.1.270 discovery, the raw
elicitation/createwire capture). Two fixes: (1) the claude-code adapter env setsCLAUDE_CODE_ENABLE_TODO_TOOLS=1, reviving the Task tools → ACP plan snapshots → the W14 TodoPanel (the "dormant on 2.1.263" conclusion was right symptom, wrong cause — portal runs the SDK-bundled 2.1.270, task tools disabled-by-default since 2.1.233); (2) full elicitation wiring — daemon advertiseselicitation.form, handles the top-levelelicitation/createrequest (bounded field view; empty fields = message-only card), server relays + watchdogs +chat:elicitation.respondrouting, web question cards (enum/multi/ text/number/boolean; values verbatim as ACP content). claude is the only target with an adapter bridge today (codex/opencode/dsh verified to have none). Research:research-phase-9-w14.1-claude-ground-truth.md· design:design-phase-9-w14.1-claude-elicitation.md. -
W16 pi agent onboarding — SHIPPED (2026-09-17) — pi (Earendil
Works' minimal coding harness,
@earendil-works/pi-coding-agent; the old@mariozechnerscope is deprecated) is the fifth runtime-managed Agent, full surface: npm install/upgrade/pin jobs (Node ≥22.19 result warning), the W3 writer (models.jsonharness-nexusprovider +!cat0600 keyfile + settings defaults/enabledModels — baseUrl VERBATIM, rig-proven on Ark), the W4 viewer (auth.json + key file wholesale-redacted), the W7 sessions rail (plain-JSONL file scan + leaf-chain replay), the C3 scanner + deploy adapter (skills with guaranteed frontmatter, prompt-template commands; mcp/rules/sub_agents skipped — no declarative surface), and the SELF-DEVELOPED in-daemon ACP bridge (PiRpcConnection: ACP requests ⇄ pi--mode rpcJSONL, prompt responses held untilagent_settled, rig-captured dialect — payload underdata, deltas underassistantMessageEvent). Rig E2E end to end: install 0.85.1 → detected card → provider push (headless PONG) → masked viewer → rail rows → streamed chat turn → live model switch. Research:research-phase-9-w16-pi-agent.md· design:design-phase-9-w16-pi-agent.md. Daemon0.22.0-p9w16.
-
W1 Agent-first inventory — SHIPPED (2026-09) —
- Non-goals v1: harness uninstall, zcode runtimes, managed-settings hierarchies. hermes runtime management was CANCELLED with the user (2026-09-17): hermes stays a profile-deploy + inventory-scan + ACP-chat target only — never probed/installed/upgraded by the platform, and the former hermes-native-sessions follow-up is dropped with it.