# Architecture English | [中文](architecture.zh.md) ## Product boundary ``` DeepSeek Harness ↓ capability surfaces and domain state ↓ internal dshline presentation adapters ↓ bounded TuiSlots / Screen rows ↓ native terminal ``` **Harness owns capabilities; dshline owns terminal presentation.** Harness is where lifecycle, state, persistence, provider selection, authority, and policy belong. dshline reads the narrowest authoritative surface, turns structured facts into terminal rows, and does not recreate a runtime, a provider connection, or a domain state machine. The renderer package is below that boundary. It knows display widths, control escaping, keys, boxes, and `Screen`; it must not learn about Harness, agents, jobs, providers, or a domain such as Todos. ## Native scrollback is the terminal model `Screen.commit()` writes finished transcript rows into the user's real terminal scrollback. Those rows are never virtualized, retained as an in-memory screen, or rewritten. `Screen` redraws only the bounded live region at the bottom: a streaming line, composer, status, or temporary overlay. Every terminal write passes through it so that live region stays last. This is deliberate product architecture, not a temporary implementation choice. dshline will not replace `Screen` with a reconciler that owns historical terminal output, or adopt an alternate-screen/full-screen transcript model. React + Ink can support different terminal trade-offs; dshline keeps normal terminal scrolling, selection, and copying available for its finished transcript. Future view code may become more declarative, but its final output must still be bounded terminal rows for `TuiSlots` and `Screen`. An overlay may change the live region while it is open; it must not rewrite committed scrollback. ## Supporting Harness capabilities Supporting a Harness plugin does not mean copying each plugin or provider into dshline. The upstream service graph calls some of these surfaces *seams* and others core services; for presentation, the important distinction is whether there is a standard authoritative contract dshline can consume. ### 1. Generic capability surfaces Prefer a standard Harness surface over a concrete package or provider: | Need | Authority | Presentation consequence | | --- | --- | --- | | background work | `ctx.jobs` | Observe generic job snapshots and changes. | | delegated work | `ctx.subagents` | Observe provider-neutral lifecycle and discovery. | | live agent registry | `ctx.agents` | Resolve live local Agents and delegate fresh/resumed attachment through the published factory seam; do not own AgentLoop or persistence policy. | | orchestrated work | `ctx.workflowEngine` + durable `tool-workflow/*` records | Observe run identity, phases, and members; own no run handle. | | models | `ctx.llm` | Read registered provider/model metadata, and the configurable-provider directory of routes configuration can activate. | | default model | `ctx.agentDefaultModel` | Read or save the composition's default selection when the optional service is mounted; do not persist a second copy in dshline. | | user configuration | `ctx.settings` | Read redacted namespace descriptors; write path ops against the revision they were read at. | | secrets | `ctx.credentials` | Ask whether a reference or record is configured and writable; never hold a value. | | obtaining a credential | `ctx.authorization` | Render the seam's neutral notice and prompt vocabulary; own no login protocol. | | human commands | `ctx.commands` | Discover and execute the registered command contract. Attachment admission is the registry's: honour `input.attachments` before dispatch, and submit only the discriminated attachment kinds this frontend can author. | | assistant output | durable `assistant/message` / `assistant/attempt` on `session/event`, plus live `agent/assistant-stream` frames | Two contracts, kept apart. The settlements are the transcript; the frames are transient presentation for the attached Agent alone. Never expand an embedded stream into a live feed, never persist a frame, and never commit an attempt that settled without a message. | | tools | `ctx.tools` | Render tool-owned presentation intents, not tool-name cases. | | human answers | `ctx.userQuestions` | Register a terminal answerer; claim a request this frontend can present, never assuming it was addressed only to this frontend. | | approvals | `ctx.approval` | Answer only requests owned by this frontend; let the waterfall fail closed for other agent identities. | | permission presets | `ctx.permissionPresets` + `ctx.sessionProjections` (`permissions`) | Two authorities, not one. Read the live process-level catalog with `catalog()` at the moment a picker opens, and the durable current selection from the projection; keep a copy of neither. Mutate only through the registered `/permission ` command, and offer nothing the live catalog does not list. Treat both as optional. | | sessions | `ctx.sessionQuery` | Query Harness's live-preferred session corpus; do not build another database. Its full-text methods are abstract, so treat content search as optional. Its `SessionHeader.cwd` values are also the only working-directory authority: group them transiently, never store a directory list, a worktree registry, or a Git state cache. | | attachments | `ctx.fs` + `ctx.attachments` | Keep paths as session-local drafts; perform bounded reads through the active filesystem and publish durable image references as one batch. Never persist bytes, base64, or host paths. | | log-derived state | `ctx.sessionProjections` | Consume registered domain snapshots and changes. | | context occupancy | `ctx.sessionProjections` (`contextPressure`, `contextBreakdown`, `tokenUsage`) | Read the O(1) folds; never count tokens or tokenize. | | session statistics | `ctx.sessionProjections` (`sessionStats`) | Read the whole-log counts and wall times; derive nothing beyond one division over two published totals. Treat the unit as optional. | | turn outline | `ctx.sessionProjections` (`turnOutline`) | Read Harness's turn number, each turn's `turn/start` seq, and the bounded prompt/response previews. Keep no turn list, fold no events, and never infer a completed turn from a preview — an empty preview is a valid state. Treat the unit as optional. | | request metadata | `Session.requestHeader()` + `Session.requestContext()` | Read the logged route and tool counts, and the recorded route's system-prompt update mode, for cache/usage views; do not maintain a parallel header. | | the system prompt | durable `system/message` surface nodes | It is conversation history, not request metadata: read it as a surface entry through the same authorities every other entry uses, keep it out of the human transcript, and hold no prompt state of dshline's own. | | context composition per entry | `ctx.tokenMeter` | Ask for the per-node measurement only when an inspector needs it; its own contract calls it O(surface). | | plan mode | committed `plan/mode` events; Harness's `plan` projection as contract evidence | Fold committed mode events with `planModeAfter()`; do not maintain a mutable second state or read `ctx.planMode` as a presentation mirror. | | reducing context | `ctx.commands` (`/compact`) | Dispatch the registered command; observe `compaction/*` events. Never call `ctx.compaction`. | | agent composition | `ctx.agentPresets` | Read the roster, one preset's composition, and which preset a session actually runs; join or switch an agent through the seam, never a private registry. | | host composition | `ctx.dshHomePath`, `ctx.baseUrl`, `dsh plugin` | Read the profile roster from Harness's own home-path service and the booted profile from the Loader's base URL; mutate only by forwarding to `dsh plugin`, never by writing a profile manifest. | | subprocess | `ctx.subprocess` | Forward the launcher argv, environment, and timeout through the Harness runtime; do not reimplement launcher or profile policy. | | session title | `ctx.sessionTitle` | Rename through the live-session service; do not mutate a copied header or maintain a title store. | | skills | `ctx.skills` | Observe the effective per-scope catalog with `snapshot({ cwd, scope: agent })`; offer and inspect the resolved summaries. Never discover, load, or inject a skill body — a leading `/name` line is sent verbatim and `dsh-tool-skill` owns what it means. | | provider health | `ctx.subagents` | Ask the registry which providers exist before presenting a row that names one as usable; never infer availability from a row being enabled. | A new subagent provider should appear through `ctx.subagents`; a background producer through `ctx.jobs`; an LLM adapter through `ctx.llm`; and a command or tool through its standard registry. The real Codex acceptance has proven that a provider publishing `ctx.subagents` / `ctx.jobs` is shown by generic Work, not by Codex-specific dshline code. [Provider acceptance](provider-acceptance.md) records that evidence and its configuration boundary. If a required fact is absent from the surface, improve the upstream contract rather than parse text or connect to a provider privately. Skills are the current live example of that last rule. `ctx.skills` answers which skills an agent can see and which of them are `userInvocable`, but the consumer that actually interprets a human `/name` gesture is a separate package (`dsh-tool-skill`), and no surface says whether a composition mounted it. So a hand-built composition can publish a user-invocable skill that no `/name` line reaches. dshline does not infer readiness — not by parsing preset YAML, not by inspecting Cordis listener registrations, and not by treating a model tool named `skill` as proof of a human gesture boundary; every one of those reads implementation rather than contract. It follows `userInvocable`, which is the same contract Harness's own Web client follows (`session-controller`'s skill catalog Remote filters on `isUserInvocable` alone), and the gap is documented for the user rather than guessed at. An authoritative readiness seam is upstream work. ### 2. Known projection domains A domain plugin may publish structured, log-derived state through `ctx.sessionProjections`. dshline can offer a native presentation adapter for a known key such as `todos` or `goal`, but the domain and Harness remain the state authority. The TUI must not parse tool output, fold a second copy of the session log, or create a competing persistence format. The projection pattern is: ``` domain plugin ↓ registers a projection unit Harness projection registry drives, caches, and notifies ↓ snapshot + change feed dshline presentation adapter ``` For authoritative projection state, read `ctx.sessionProjections.snapshot(session)` and subscribe with `ctx.sessionProjections.onChanged(...)`. The registry drives registered pure units over committed events, gives `snapshot()` one synchronous consistent cut, and emits a change only when a unit changes. dshline's internal, session-scoped observer subscribes once for the exact `Session`, coalesces an invalidation in a microtask after that synchronous drive settles, and leaves all values in the registry for adapters to read through `snapshot()`. It is not a second projection store. Projection-key presence is process-wide, not a per-session capability signal: a key registered by any composition can appear in every session snapshot. Interpret the projection value (for example, a Todo list or `null`) rather than treating the presence of `todos` as proof that this exact agent has Todos enabled. This is an internal architecture pattern, **not** a stable public `ProjectionAdapter` interface. `todos` is the second proof. `@deepseek-ai/dsh-tool-todo` supplies the model-facing `todo_write` tool, durable whole-list `todo/write` events, and the optional `todos` projection. dshline presents its current snapshot through a bounded `/todos` overlay and an optional `todo completed/total` status segment; it owns no Todo mutation, lifecycle, fold, or persistence. Todo items have only `content` and `pending`, `in_progress`, or `completed` status; each write replaces the complete list. The projection is `null` before a write, contains the latest list, and clears on the next `turn/start`. The intended path is: ``` @deepseek-ai/dsh-tool-todo ↓ todo/write and todos projection ctx.sessionProjections ↓ dshline Todo presentation ``` It must not inspect `todo_write` calls or rendered cards to infer state. Permission selection follows the same boundary, but over two Harness authorities rather than one, because Harness owns them at two different scopes. `ctx.permissionPresets.catalog()` is the live, process-level list of selectable options, and it changes with contributions Harness announces on `permission-presets/catalog-changed`; the `permissions` session projection carries only the durable current selection. The intended path is: ``` ctx.permissionPresets.catalog() ctx.sessionProjections ↓ live selectable options ↓ permissions: current selection \ / dshline permission picker ↓ /permission