dsh-flat-teams
English | 中文
A flat-teams plugin for DeepSeek Harness (DSH): multiple independent agent windows (top-level sessions) form a leaderless flat team, dispatch structured tasks to each other across windows, while a built-in read-only "recorder" service keeps the books — so the user can ask for real progress from any member window.
Features
- Flat teams:
team_create(optionally with member specs — new member windows are created programmatically, inheriting the current workspace), existing windows self-register viateam_join, plusteam_leaveandteam_roster(members / areas / online status). No captain: any member can dispatch tasks to any other member. - Structured task dispatch:
task_dispatchtargets a member by name or by area. Task state machine:pending → delivered → claimed → in_progress → completed | failed | cancelled(plustimeout), every transition mints a fresh attemptId and appends to the event stream. - Three-stage delivery, no task loss: tasks are persisted to disk and to the recipient's mailbox (
<DSH_HOME>/flat-teams/<teamId>/inbox/) before a best-effort wake (followup when online; cold-resume viaagents.resumethen followup when offline). If the wake fails, the task staysdeliveredin the mailbox. - Recorder: a pure service — no window, no admin rights. It subscribes to the event stream and maintains
progress.json(per-task status and result summaries, per-member in-flight tasks and completion counts, team timeline). It is only a cached projection and can be fully rebuilt fromevents.jsonlat any time. - User queries:
team_statusreturns the recorder's structured progress. A bundled prompt protocol teaches the model: dispatches must be self-contained, receivers claim before working, results must be reported back, and progress questions are answered from recorder data — never fabricated. - Web dashboard: after installing into a web profile, a "team dashboard" badge appears at the top-right of the browser — a team list (member count / online / in-flight / dormant marker) drilling into a detail view (roster / task board / progress timeline). The dashboard exposes user-only admin actions: disband team and kick member (both with two-step confirmation, via
POST /plugins/flat-teams/teams/<teamId>/disband|kick; member agents do not have these capabilities). Data comes fromGET /plugins/flat-teams/state(5s polling).
Install
# npm (recommended, prebuilt artifacts, no build approval needed)
dsh plugin --profile <name> add dsh-flat-teams
# or from git (lib/ is committed, also no build approval)
dsh plugin --profile <name> add github:whateverboy2333/dsh-flat-teams
# local path (development)
dsh plugin --profile <profile> add /absolute/path/to/dsh-flat-teamsRestart the profile after installing. Verify:
dsh --profile <profile> --dump-config # the composition tree should show a flat-teams row (# == dsh-flat-teams layer)Uninstall: dsh plugin --profile <name> remove dsh-flat-teams.
Compatibility
- DSH
0.1.0-rc.6(@deepseek-ai/*on the same release train;@deepseek-ai/cordis ^4.0.1) - Node
^22.19or>=24 - The plugin ships a runtime version guard: on an incompatible DSH version it refuses to load with a loud error instead of failing silently
Tool Reference
| Tool | Purpose |
|---|---|
team_create | Create a team; optional member specs spawn member windows (name/area/persona); the current window becomes the first member |
team_join / team_leave / team_roster | Self-register / leave / list roster (with live online status) |
task_dispatch | Dispatch a task: to is a member name or area (multiple area candidates → error asking for an explicit name); persist + mailbox + best-effort wake |
task_claim / task_complete / task_fail | Receiver-driven states: claim (delivered→claimed→in_progress) / complete with result / fail with reason |
task_list / task_status / task_cancel | Query tasks (filter by status/member) / single-task detail / cancel (dispatcher only, optional attemptId generation check) |
team_status | Recorder's structured progress (task states & summaries, per-member in-flight, team timeline) |
flat_teams_ping | Plugin self-check |
All permissions are enforced in code: caller identity is resolved from the roster via the calling session, cancel is dispatcher-only, claim/complete are restricted to the designated recipient member.
Usage (natural language)
Create a team with members:
> Create a flat team "Website Revamp" with two members: Xiaotest (testing) and Awen (docs).
Dispatch work (no tool names needed):
> Have Xiaotest cover the edge cases of the login page by Friday.
The receiving window gets a [task from … #task-…] message and follows the prompt protocol: claim first, report back when done.
Ask for progress (in any member window):
> How is the project going? Is anything stuck?
The agent calls team_status and answers from recorder data.
Known Limitations (MVP)
1. Same process only: all member windows must live in one DSH process (cross-workspace within the same process is supported — team state is shared globally at the DSH_HOME level); cross-process / cross-machine transport is planned for v0.2 (file-registry based). 2. Member windows do not auto-revive across restarts: programmatically created member windows are held by the plugin fiber and are destroyed on plugin unload or process exit; member identity and task data persist under <DSH_HOME>/flat-teams/, but the windows themselves must be recreated/rejoined. 3. No automatic redelivery for offline targets: if cold-resume fails, the task stays in the mailbox (visible as delivered), but nothing re-pushes it automatically — it needs a new touch once the member is back (v0.2). 4. Cancel does not retract a delivered turn: task_cancel only transitions the state machine; a message already delivered to the receiver's window is not withdrawn. 5. Areas are not exclusive: area is routing metadata only; multiple members may share one area, in which case dispatch must name the member explicitly.
Also: concurrent writes to <DSH_HOME>/flat-teams/ from multiple processes are not guarded (declared MVP limitation, to be solved in v0.2).
Migration note (within v0.1.0): early internal builds (pre-open-source) stored team state under <workspace>/.flat-teams/ — that layout is deprecated: old directories are not migrated automatically and are no longer read or written; they can be deleted manually.
State Directory
Team state is workspace-independent and lives at the DSH_HOME level (a window in any workspace can join the same team):
<DSH_HOME>/flat-teams/<teamId>/
├── team.json # roster (disk is the source of truth)
├── tasks/<id>.json # task records (state machine + attemptId)
├── events.jsonl # event stream (the only event truth, replayable)
├── inbox/<member>.jsonl # delivery mailboxes (persistent copies)
└── progress.json # recorder cache projection (fully rebuildable from events.jsonl)Development
pnpm install
pnpm build # tsc (host + client) → tsdown → lib/> Note: the smoke verification scripts (scripts/) are not shipped in this repository; pnpm verify is only available to contributors with a full development copy.
License
MIT