👥 dsh-background-agents
August 30, 2026 · View on GitHub
👥 dsh-background-agents
- 1024 store channel:
npm i -g dsh1024once, thendsh1024 plugin --profile web add dsh-background-agents(counts toward the deepseek1024.com install ranking).
Interactive long-session background agents plus persistent multi-agent team rooms for DeepSeek Harness — start a durable child agent that keeps working while you keep talking.
Steer live conversations and coordinate a team across sessions; everything survives restarts through the harness's own storage.
Compatibility
| Surface | Status |
|---|---|
| Harness | DeepSeek Harness 0.1.1-rc.2 (peers >=0.1.0-rc.8 <0.2.0) |
| Node | ^22.19.0 || >=24.0.0 |
| Platforms | All (host tools; optional Web sidebar panel and team rooms via the storage-domain capability) |
| Model | Any (children inherit the parent's route; childProvider/childModel override) |
What you get
dsh-background-agents upgrades DSH's fire-and-forget background jobs into two coordinated surfaces:
- Five steering tools —
background_agentstarts a durable, continuable child on the official subagent seam (optionaltool_filter— removes tools, never grants new ones;persona;max_depth;childProvider/childModelroute).bg_messagedelivers a later turn;bg_listreports status (or the descendant tree withparentId/depth);bg_resultreads the latest result text (reasoning fallback flaggedtextSource: 'reasoning');bg_stoprequests interruption. - Progress and archive —
autoReportinjects one throttled progress line after each child turn;reportDelivery: wakeupstarts a parent turn when idle. The idle sweep archives quiet children andbg_messagewakes them back up (autoArchive: falseparks quiet watchers instead). - Dashboard projection + Web panel — the
backgroundAgentssession projection folds the parent log into rows; a sidebar panel shows live status, jump, message, stop, and result peek. Everything reconstructs from the durable log — no separate database. - Team rooms (v0.5.0+) — the
/roomcommand family plus eightroom_*tools build persistent multi-agent rooms: members (each an independent session), a message bus (directed/broadcast), a shared task board, and a shared timeline — stored in theteam_roomsstorage domain (SQLite or JSONL) and recovered across DSH restarts. Cross-member task handoffs route through the official approval seam.
Quick start
# 1. install the bundle into your profile
dsh plugin --profile web add "github:PerryLink/dsh-background-agents#main"
# or from npm (published releases)
dsh plugin --profile web add dsh-background-agents
# 2. restart and verify the row
dsh --profile web --dump-config | grep -A4 'id: background-agents'
The bundle patch carries the plugin row; provider is required. The repo commits its build output (lib/), so git installs need no build step. The plugin needs the subagent spine already mounted (any profile built on @deepseek-ai/dsh-base has it). Team rooms mount wherever the storage domain is composed (@deepseek-ai/dsh-storage-domain); the five bg_* tools work without it.
Then, in any session, just ask the model — or call the tools directly:
background_agent "watch the repo for test failures and keep me posted" (label: test-watch)
bg_list
bg_message <agentId> "also check the snapshot tests now"
bg_stop <agentId>
Install & uninstall
- git channel (latest
main):dsh plugin --profile web add "github:PerryLink/dsh-background-agents#main"— committedlib/, noprepareorallowBuildsstep. - npm channel (published releases):
dsh plugin --profile web add dsh-background-agents. - tarball channel:
pnpm packin this repo, thendsh plugin --profile web add ./dsh-background-agents-<version>.tgz. - uninstall:
dsh plugin --profile web remove dsh-background-agents(or remove the row from the profile patch).
Configuration
Every tunable is a validated Schemastery Config field — change it in cordis.yml, never in code. Only provider is required.
| Key | Default | Meaning |
|---|---|---|
provider | (required) | ctx.subagents provider name for continuable starts (spawn) |
autoReport | true | Inject one progress line into the parent after each child turn |
reportDelivery | quiet | quiet appends the line to the next model request; wakeup starts a parent turn when idle |
reportThrottleMs | 15000 | Minimum gap between two progress injections for one child |
reportSummaryMaxChars | 300 | Hard cap on the injected progress-line text (ellipsized) |
resultMaxChars | 4000 | Hard cap on the bg_result text (ellipsized, flagged truncated) |
maxBackgroundAgents | 4 | Hard cap on non-archived background agents per parent session |
autoArchive | true | Idle-archive toggle; when false, the sweep never archives quiet children |
idleTimeoutMinutes | 120 | Idle window after which a quiet child is archived (>= 1) |
idleSweepIntervalMs | 60000 | Archive sweep period |
maxLabelChars | 120 | Display-label cap (ellipsized) |
childProvider | (inherit) | Provider route for child model requests |
childModel | (inherit) | Model id for child model requests |
maxChildDepth | (none) | Config ceiling for a start's max_depth argument |
allowedChildTools | (none) | Allowlist for tool_filter names; empty/absent = no limit |
maxRooms | 16 | Hard cap on team rooms across the profile |
maxMembersPerRoom | 8 | Hard cap on members per room |
maxRoomsPerMember | 4 | Hard cap on rooms one member session may join |
busRetention | 200 | Bus messages kept per room |
timelineRetention | 500 | Timeline events kept per room |
taskRetention | 50 | Completed tasks kept per room |
maxMessageChars | 4000 | Hard cap on one room message's text (rejected above, never truncated) |
injectRoomBrief | true | Inject the short room brief into member sessions (join + resume) |
roomOpenTimeoutMs | 15000 | How long the team_rooms storage-domain open may take before every room operation fails loud (store-unavailable) instead of hanging |
allowUnmarkedFacts | false | Force log-only fact events on hosts that drop the ignorable marker (dangerous: unmarked facts make sessions unresumable elsewhere); default is detect-and-skip |
observability | true | Per-agent cost/status observability toggle: capture one metrics fact per child turn (tokens, turn wall time, error flag) and aggregate them into each row's metrics totals for the cost panel; false disables the capture (the panel renders metrics as unavailable) |
inbound.enabled | false | Enable the stdio JSON-RPC inbound bridge for external agent runtimes (OpenAI Agents SDK / CrewAI). Disabled by default (fail-closed). |
inbound.command | (none) | External runtime launch command; when enabled and present, the plugin spawns it and listens for newline-delimited JSON-RPC notifications. Absent/unspawnable = the bridge stays dormant (logged). |
Tools & surfaces
| Surface | Kind | Notes |
|---|---|---|
background_agent | tool | Start a durable, continuable child (label, tool_filter, persona, max_depth) |
bg_message | tool | Deliver a later turn to a child by agent id |
bg_list | tool | Status of your agents (or the descendant tree with recursive: true) |
bg_result | tool | Fetch a child's latest assistant output text |
bg_stop | tool | Request interruption of the current turn |
/room | command | create|join|leave|list|send|tasks|task add|assign|claim|done|delete |
room_list_rooms / room_post / room_read | tools | Message bus: roster, post (broadcast/directed), read history |
room_list_tasks / room_create_task / room_claim_task | tools | Shared task board |
room_transfer_task / room_complete_task | tools | Handoff (approval-gated) and completion |
backgroundAgents projection | session projection | Dashboard rows folded from the parent log, including per-agent metrics totals (tokens, turn wall time, error count) |
teamRoom projection | session projection | Shared timeline folded from team-room/fact events |
| Web sidebar panel | client | Live status, jump, message, stop, result peek, per-agent cost/status totals, JSON export/copy |
How it works — and why it survives restarts
Everything rides the official subagent seam: startContinuable, followup, interrupt, listChildren — the plugin performs no lifecycle routing of its own, never touches another session's Agent, and never kills a process tree (stop = request interruption, teardown belongs to the continuation manager).
The plugin writes every fact through one structured channel and one model-visible channel:
background-agents/factstructured fact events — the registered / message / stop / progress / archived facts plus the per-turnmetricssamples (tokens, turn wall time, error flag), appended to the parent log as log-only records with the envelope'signorable: truemarker; readers that do not know the type skip the records instead of refusing the log. Hosts whoseSession.appendpredates the marker (every released rc line through0.1.0-rc.8and0.1.1-rc.2drops it silently — the stamping fix exists on harness master only — making unmarked sessions unresumable on stricter builds) are detected before the first append (peer-version pre-check, then a probe of the returned envelope) and fact appends are skipped with a one-time warning — the durable store, the notices, and the tools keep working, and the projections degrade to an empty fact fold.tool/resultreplay metadata — the same facts in logs written before the structured channel (folded only while a row has no structured provenance).- injected
user/messagenotices (model-visible), source{ kind: 'plugin', plugin: 'dsh-background-agents' }— the throttled progress lines and archive notices (canonical[background-agent <id>] …prefix). - the official
subagent-settlednotice — the child's durable "settled" fact. - Team rooms mirror the same discipline: every delivered room message is a durable
user/messagein the member's own log, and the shared timeline mirrors as log-onlyteam-room/factevents in theteam_roomsstorage domain.
The backgroundAgents projection folds the structured channel and keeps the legacy folds; the dashboard value and bg_list facts reconstruct on every reopen without parsing human-readable notice text. When the catalog itself is unavailable, bg_list returns an explicit unrecoverable marker — it never fabricates an empty list.
How this relates to the built-in subagent tools
The harness core ships its own subagent tools (subagent, send_message, interrupt_agent, and the child-side report tool). This plugin's bg_* tools are their session-scoped companions; both can be mounted together:
| Built-in tool | This plugin | Difference |
|---|---|---|
subagent (backgroundMode: 'continuable') | background_agent | Same startContinuable seam; this plugin adds per-child tool_filter/persona/max_depth validation and the per-session cap |
send_message | bg_message | Same delivery semantics; bg_message addresses this conversation's background agents and maintains the projection facts |
interrupt_agent | bg_stop | Same interrupt semantics; bg_stop also records a structured stop fact |
child-side report tool | autoReport | The built-in is called by the child model itself; this plugin injects throttled progress after every child turn automatically |
What the core tools lack: bg_list, bg_result, idle archiving, and the per-parent folded panel projection.
Not in scope: scheduled triggering (the schedule seam exists), cross-machine/remote agents, and any change to the official subagent activation contract.
Not this plugin
| Project | What it does | The boundary |
|---|---|---|
| titanwings/dsh-automation | Scheduled coding tasks in fresh agent sessions | It owns when tasks run (scheduling). This plugin owns interactive steering of one long-lived conversation — no scheduler seam, no cron. |
| vlln/dsh-task-status | Status bar for background jobs (progress + output tail) | It displays tool-level jobs. This plugin creates and steers agent sessions; its dashboard is one panel of it, not the product. |
| YYTbit/dsh-plugin-agent-dashboard | Multi-agent dashboard skill | Display-oriented. This plugin's rows are actionable: jump into the child session, send messages, stop — through the official control plane. |
Permissions & data
- Permissions: the workshop manifest declares
session:append,subagent:spawn, andtools:register. - Data: team rooms live in the
team_roomsstorage domain (SQLite or JSONL — zero extra services); background-agent facts ride the parent session log. No separate database, no network. - Session log:
background-agents/factandteam-room/factevents are appended with the envelope'signorable: truemarker on hosts that honor it (pre-marker hosts are detected and fact appends are skipped — seeallowUnmarkedFacts); the model-visible progress lines and room deliveries are realuser/messagerecords.
Security boundaries
- Official seam only. Start, message, and stop are thin adapters over
startContinuable/followup/interrupt; stop requests interruption and never kills processes. tool_filteronly restricts. It removes tools from the child's view — never grants new ones; names are validated againstallowedChildTools.- Approval-gated handoffs.
room_transfer_taskroutes through the official approval seam and fails closed when no answerer grants it. - Model-visible ⟺ logged. Every delivered room message is a durable
user/messagein the member's own log; the shared timeline mirrors as log-onlyteam-room/factevents. - No scheduling, no cross-machine agents. Children are process-local continuable sessions of the deployment.
Cross-ecosystem inbound (P2)
External agent runtimes — OpenAI Agents SDK, CrewAI, and similar — can publish into a team room through a minimal newline-delimited JSON-RPC 2.0 bridge over stdio. This is a JSON-RPC direct-connect minimal set, not the official ACP wire protocol: full ACP compatibility waits for the upstream seam.
Enable it with two Config fields and point inbound.command at a launcher that emits one JSON notification per line on stdout:
# cordis.yml (plugin row)
inbound:
enabled: true
command: "python external_runtime.py --room <room-id>"
The runtime emits three notification kinds; method is the event name and params.name is the external agent's display name:
{"jsonrpc":"2.0","method":"agent_started","params":{"name":"researcher","room":"<room-id>","traceId":"t-1"}}
{"jsonrpc":"2.0","method":"agent_message","params":{"name":"researcher","room":"<room-id>","traceId":"t-1","message":"found the failing test"}}
{"jsonrpc":"2.0","method":"agent_finished","params":{"name":"researcher","room":"<room-id>","traceId":"t-1","status":"ok","usage":{"inputTokens":100,"outputTokens":40}}}
Each maps onto the room's existing surfaces: agent_started opens a task-board card, agent_message posts to the message bus, and agent_finished completes the card and posts the outcome. Invalid messages fail closed — they are dropped and a JSON-RPC error is written back. External runtimes are not DSH sessions, so the room owner's member session stands in as the sender; a room with no owner member drops the event. Start and stop are owned by the plugin fiber through a disposer; an unspawnable inbound.command degrades to a logged warning (the bridge stays dormant, nothing else is affected).
Known limitations
- Team rooms require the storage domain to be composed; without
@deepseek-ai/dsh-storage-domain, the/roomcommand androom_*tools are disabled (the fivebg_*tools still load). providermust name a continuable-capable provider (prepareContinuable); a missing provider makesbackground_agentfail until it appears.maxBackgroundAgentsis a shared budget across every continuable direct child of the session, including ones the built-insubagenttool started.- One-shot children are never listed or messaged —
bg_listkeeps continuable rows only. - Children are process-local: the schedule seam owns "when", this plugin owns steering a live conversation.
- Cost metrics are raw token/duration totals, not currency: the harness exposes no per-model pricing table to the plugin or the browser, so the cost panel and export never convert tokens to money (they show
—when the adapter reports no token accounting).
Development
pnpm install # tooling only; harness packages resolve against a sibling checkout
pnpm run typecheck # strict TS, node + client programs
pnpm test # vitest: unit + end-to-end tests (real subagent seam, scripted LLM, jsdom panel)
pnpm run build # lib/index.js (node half) + lib/client.js (web client bundle)
pnpm run gen-aliases # re-map harness package paths after the checkout moves
A keyless end-to-end demo drives a real parent session and a background child through a deterministic scripted LLM (no API key; dev/ is gitignored — adapt the paths to your checkout):
$env:DSH_HOME = 'D:/deepseek-harness/Project/Plugins/dsh-background-agents/dev/dsh-home'
pnpm dsh --profile headless --patch dev/cordis.yml "【父会话】驱动后台 agent 演示"
Topics
dsh, dsh-plugin, deepseek-harness, subagent, background-agent, background-agents, agent-dashboard, conversation-steering, team-rooms, multi-agent, message-bus, task-board, collaboration
Contributors
- @PerryLink — creator and maintainer: the background-agent runtime on the official subagent seam, the team-room hub, the Web UI sidebar panel, the session projections, docs, CI/CD and releases.
PerryLink DSH Plugin Family
This project is one of the 33 DeepSeek Harness plugins maintained by PerryLink. If this one helps you, the others likely will too:
| Plugin | One-liner |
|---|---|
| dsh-dsh-auto-review | Second-model auto-review on the approval chain, fail-closed by default |
| dsh-dsh-budget | Cost governance for DeepSeek Harness: budgets, carbon, and latency in one panel. |
| dsh-dsh-checkpoint-rewind | Claude Code /rewind-equivalent: snapshots, session forks, one-shot restore |
| dsh-dsh-claude-move | Migrate Claude Code sessions, memory, skills and CLAUDE.md into DSH |
| dsh-dsh-click | Cross-platform native desktop control for DeepSeek Harness — Windows first. |
| dsh-dsh-composer-history | Terminal-style input history for the web composer: arrows, Ctrl+R search |
| dsh-dsh-data-quality | Dataset quality checks and citation cross-checks (the optional numeric bridge consumed here) |
| dsh-dsh-defend | Prompt-injection, jailbreak, and secret-leak defense for DeepSeek Harness. |
| dsh-dsh-doublecheck | Engineering-discipline guard: requirements grill, test gates, adversary review |
| dsh-dsh-draw | Unified static-image generation routing for DeepSeek Harness. |
| dsh-dsh-fast | Read-only performance diagnostics for DeepSeek Harness. |
| dsh-dsh-fund-research | Deterministic research reports for Chinese public mutual funds |
| dsh-dsh-github | GitHub PR/issues integration for DSH, every write gated by approval |
| dsh-dsh-industry-research | Industry research orchestration that seals its deliverables through this plugin's ctx.researchReport.assemble |
| dsh-dsh-library | Local document knowledge base for DeepSeek Harness. |
| dsh-dsh-local-ai | Local-model (Ollama) integration for DeepSeek Harness. |
| dsh-dsh-lsp-actions | LSP diagnostics, formatting, completion, code actions and rename over language servers |
| dsh-dsh-mask | PII masking middleware: anonymize at the model boundary, restore at the display layer |
| dsh-dsh-mcp-panel | Read-only MCP runtime panel: /mcp command + Settings tab with status, tools and errors |
| dsh-dsh-memento | Approval-gated cross-session memory: ctx.memory seam + SQLite + memory tool |
| dsh-dsh-observe | OpenTelemetry and Langfuse observability exporter for DeepSeek Harness. |
| dsh-dsh-output-styles | Claude Code outputStyles-equivalent runtime style switching |
| dsh-dsh-permission-rules | Claude Code-style declarative allow/deny/ask permission rules with audit |
| dsh-dsh-plugin-guide | Plugin-development knowledge base as an on-demand agent skill |
| dsh-dsh-research-report | Verifiable research-report engine: content-addressed evidence ledger and sealed versions |
| dsh-dsh-score | Multi-dimensional quality scoring for DeepSeek Harness plugins. |
| dsh-dsh-session-pin | Pin sessions in the Web sidebar with durable ordering |
| dsh-dsh-session-sync | Cross-device session sync for DeepSeek Harness — a dedicated git mirror of your session store. |
| dsh-dsh-skill-pack-security | Security-audit skill pack: secret scan, dependency and supply-chain review |
| dsh-dsh-talk | Voice-first session loop for DeepSeek Harness: talk to it, hear it answer. |
| dsh-dsh-test-drive | Isolated install-and-smoke test drives for DeepSeek Harness plugins. |
| dsh-dsh-translate | Vendor parameter translation and deterministic JSON repair for DeepSeek Harness. |
License
Apache License 2.0 © 2026 dsh-background-agents contributors