# dsh-agent-team-gui v0.5 Product and Contract Specification Status: implementation contract. This document is intentionally explicit so the Host, Web client, tests, documentation, and release checks can evolve in parallel without inventing incompatible behaviour. ## Product principles 1. A saved team is durable, reusable, and immediately interactive after restart or reconnect. 2. Existing v0.4 records remain valid. Missing v0.5 fields preserve v0.4 behaviour. 3. Simple paths stay simple; advanced orchestration is disclosed progressively. 4. Every long-running action is observable, cancellable, restart-safe, and bounded. 5. Provider token usage is reported as usage, never fabricated as currency cost. 6. Full member output remains durable, while the lead model receives bounded structured handoffs. 7. No child, planner, reviewer, or repair run may recursively dispatch a team or create unbounded descendants. ## Architecture guardrails The release is organised as explicit responsibilities instead of adding more conditionals to the original service and dashboard files: - **Domain and policy modules:** stable errors/default contracts plus pure DAG, recipe, handoff, retention, and usage functions. Pure policies have no React or browser dependency. - **Application services:** definition/version/import/mode use cases and execution/run use cases. They own storage consistency, cancellation, and orchestration while adapting the official Harness services supplied by the Cordis composition root. - **Infrastructure adapters:** FIFO read/write coordination, compensating storage units of work, and the narrow official token-usage projection adapter. - **Transport and presentation:** strict loopback RPC validation, client controllers/stores/view models, and focused React screens. Components receive data/actions through injected controllers and never reach into the Cordis context. `AgentTeamService` is the Host facade/composition root and the client registration is the Web composition root. Classes own lifecycle and stateful coordination; pure functions own validation, formatting, and scheduling rules. This is a pragmatic layered plugin, not a claim that the official Harness services are hidden behind a separate port for every call. New behaviour is tested at the lowest deterministic layer and again at the actual Host/Web boundary. ## Compatibility defaults - `activationMode` absent: `always` (the v0.4 guaranteed behaviour). - `memberSelectionMode` absent: `all` (all configured members exactly once). - `responseMode` absent: `foreground`. - `planningContext` absent: `current` for new UI records, but old records are interpreted as `full` only where that is required to preserve their existing fork behaviour. - Existing `executionMode`, `contextMode`, `triggerMode`, fixed order, failure policy, limits, and model routes keep their meanings. - Old export documents remain importable. New documents use a new version and are explicitly previewed before any write. ## Team activation and planning Teams support three activation policies: - `always`: every eligible non-empty top-level user request runs the team. - `smart`: a bounded planner may return `skip`; otherwise it selects one or more members. - `manual`: normal sends remain solo and an explicit UI/model dispatch starts the team. Member selection supports: - `all`: every configured member exactly once. - `adaptive`: the planner selects the smallest non-empty subset needed for the request. A plan has a stable decision and an acyclic dependency graph: ```ts interface SquadExecutionPlan { decision: 'run' | 'skip' reason: string summary: string assignments: Array<{ agentId: AgentId task: string dependsOn: AgentId[] }> memberOrder: AgentId[] // stable topological display order planner: 'main-agent' | 'squad-leader' | 'deterministic-fallback' usage?: AgentTokenUsage } ``` The executor runs all currently ready nodes up to `maxConcurrency`; a dependent assignment sees bounded handoffs from its declared dependencies. Invalid/cyclic plans fall back deterministically. Fixed `executionOrder` remains a serial override and does not invoke graph planning. `main-agent` means the plugin uses the active conversation's provider/model route in a bounded, tool-free planner child. It does not mutate or impersonate the live parent Agent instance. Planner controls: - `planningContext`: `current | recent | full`. - `plannerMaxTokens`: positive bounded integer; UI default 2048. - planners receive no execution/delegation tools and a strict structured output schema. - `smart` may skip acknowledgements, trivial formatting requests, or tasks outside the team's role. ## Bounded quality loop An optional quality gate names a reviewer, repair owner, and `maxRounds` in `0..2`. The reviewer returns structured `{ approved, feedback }`. When rejected, only the repair owner reruns with the bounded feedback, followed by another reviewer pass. No arbitrary recursion or planner-created agents are allowed. Every attempt is part of the same durable run and token budget. ## Foreground and background - `foreground`: the normal-send boundary awaits the team and gives a bounded handoff to the lead model for synthesis. - `background`: the boundary starts a durable run, immediately returns an acknowledgement, and the Run Center owns progress/result presentation. The run must never pretend the lead model already incorporated unfinished output. Background completion is observable in the Web UI. If Harness exposes no supported parent notice seam, the implementation must state that limitation rather than append unsupported Session events. The current Web profile does expose the official `ctx.jobs` registry and `ui-jobs` surface, so a background squad should register one owner-scoped `agent-team` job whose cancel hook aborts the same durable run. The plugin's Run Center remains the detailed source of truth; the official Jobs surface provides native discovery, stopping, and completion notice semantics. ## Durable run lifecycle Run status vocabulary: `planning | queued | running | completed | partial | failed | cancelled | interrupted | skipped` - At Host startup, persisted `planning`, `queued`, or `running` records without an active controller become `interrupted` with an explanatory reason. - Result status, durable status, and member status use the same cancellation semantics. - A retry creates a new run linked with `retryOf`; it never mutates historical output. - Automatic retention is opt-in: count and age default to `0` (disabled), while explicit positive limits prune independently. The plugin also provides explicit list/clear APIs, so upgrading never silently deletes existing run history. - Full outputs stay durable but list endpoints return summaries unless detail is requested. ## Token and insights semantics - Reuse the official `tokenUsage` projection. - Display uncached input, cache read, cache write, and output separately. - Attribute planner, member, quality, and repair usage separately. - Never label raw tokens as monetary price. - Aggregate by team, member, provider/model, project, and time window. - Soft budget stops scheduling new work; per-member `maxTokens` remains the hard provider bound. ## Reproducible versions and recipes Every saved team version includes the team record plus immutable snapshots of referenced member definitions. Restoring a version restores both team and member behaviour after a preview. A recipe contains one team and its member definitions without credentials. Recipe import is two phase: 1. preview/validate, report conflicts and missing provider/model routes; 2. apply with explicit route remapping and merge/copy policy. v0.5 deliberately does not fetch recipe URLs. Users import a reviewed local JSON document, which avoids turning the loopback Host into a server-side request-forgery surface. A future remote source feature would require an allowlisted fetch adapter, strict HTTPS, redirect/IP validation, byte/time bounds, and preview-only semantics before it can enter this contract. ## Session mode contract The three durable override states are first class: - `enabled`: this conversation explicitly uses a team; - `disabled`: this conversation explicitly stays Solo; - `inherit`: no conversation override; use the project default when available. The Web UI must expose all three. `mode/set` must not overload `null` to mean both disabled and inherit. A one-shot next-message override must be consumed exactly once and remain separate from the durable session state. ## RPC v3 surface The exact payload schemas remain Zod-validated and loopback-only. v3 retains all v2 endpoints and adds or extends: - `snapshot` -> v3 catalog and product capabilities. - `mode/get`, `mode/set`, `mode/inherit`, `mode/next-set`. - `plan/preview` -> non-executing plan preview. - `run/list`, `run/get`, `run/cancel`, `run/retry`, `run/clear`, `run/export`. - `insights/summary`. - `recipe/export`, `recipe/preview`, and `recipe/import`. - `recipe/fetch-preview` is reserved for a future SSRF-hardened capability and is not implemented in v0.5; `snapshot.capabilities.remoteRecipeFetch` is therefore always `false`. - squad versions return reproducible member snapshots and support preview before restore. Every endpoint returns stable tagged outcomes where domain-specific errors are needed; it does not extend Harness's closed RPC error-code set. ## Web information architecture Settings has three internal views rather than two stacked editors: 1. Teams: master list + one selected team editor. 2. Members: reusable member library + one selected member editor. 3. Recipes and data: templates, recipe import/export, definition backup, retention. The first existing item is selected automatically. Successful save keeps it selected. Dirty forms guard navigation/close. Basic fields appear first; orchestration, resilience, limits, and permissions are progressive-disclosure sections with inline validation and sticky actions. The composer entry shows a native-style status control and an accessible popover/equivalent panel: current state, selected team, project default, durable Team/Solo/Inherited choice, one-shot override, last run, edit link, and actionable reconnect/error state. No-team state links directly to Settings. Run Center presents plan -> dependency stages -> members -> optional quality loop -> lead synthesis, with live status, elapsed time, usage breakdown, stop/retry/export/clear actions, filters, and aggregate insights. The live dock links to the active run and exposes cancellation without trapping focus. ## Internationalization and accessibility - Use the official client locale service and registered zh/en dictionaries; never `navigator.language`. - Locale changes update mounted UI immediately. - All stateful icon buttons have dynamic accessible names. - Errors are visible text with retry actions, not title-only punctuation. - Keyboard order, focus-visible, screen-reader status, reduced motion, light/dark theme, and narrow viewport behaviour are tested. ## Verification gates No release is allowed until all pass: 1. Host, Client, and test TypeScript checks. 2. Unit/integration tests, including persistence reopen and crash reconciliation. 3. Rendered Client interaction tests for all mode/dirty/error/accessibility states. 4. Build and tarball content audit. 5. Fresh temporary `DSH_HOME` Web-profile install/boot/RPC smoke. 6. Browser journeys: template preview, edit/save/reload, project inheritance, Team/Solo refresh, preview, cancellation, retry, history/insights, locale/theme, and narrow viewport. Provider-backed foreground execution is a separate opt-in smoke because CI never receives user credentials. 7. Restart during a run and automatic `interrupted` recovery. 8. GitHub commit/tag install smoke with the exact release revision.