Open Source Project #253: dsh-superagent — DeepSeek's Open-Source Proactive Coding Agent Prototype, Built Around Taking as Little Human Attention as Possible

dsh-superagent is a research prototype open-sourced by the DeepSeek team: a proactive coding agent for a single GitHub repository, packaged as a plugin bundle for DeepSeek Harness. It listens to GitHub (and optionally Feishu); when an allowed person asks, it opens a ticket, works in its own agent session and directory, and answers in the original conversation, for example with a pull request. Its design revolves around one sentence: take as little human attention as possible, and give as much value as possible. MIT licensed, 15k stars in three days. The README states plainly that it is not an official DeepSeek product.

·25 min read·AI Engineering

Introduction

An agent that can act for a whole team can also waste a whole team's attention.

This is article 253 in the "One Open Source Project a Day" series. Today's project is dsh-superagent (deepseek-ai/dsh-superagent-prototype).

Start with the disclaimer at the top of the README, because it matters: this is a research prototype for reference only, not an official DeepSeek product. The code grew out of the team's day-to-day development, with much of the engineering done by coding agents. It isn't identical to the internal version or to the implementation described in the article Exploring Super-agent Design: Towards a More Autonomous Agent System, and some designs in that article are future directions not implemented here.

So where's the value? Not in code maturity, but in the design documents. Nine numbered documents, read in order, spell out how restrained a proactive agent should be: when to act, when it must stay quiet, how authority is granted and withdrawn, and how a ticket starts, resumes and ends.

What You'll Learn

  • What dsh-superagent is, and how it relates to DeepSeek Harness
  • How the principle "little attention, much value" turns into concrete design
  • The domain model: Source, Trigger, Thread, Eval, Mandate, Ticket
  • Authorization and admission: who may start work, and why proactive work defaults to record-only
  • How a ticket executes, delivers and recovers
  • Limits and where it fits

Prerequisites

  • Familiarity with GitHub Issues, pull requests and notifications
  • Basic concepts of coding agents (Claude Code, Codex, DeepSeek Harness)
  • Interest in how to put boundaries on automated agents

Project Background

Overview

dsh-superagent is a proactive coding agent for one GitHub repository, packaged as a bundle for DeepSeek Harness (DSH).

The README describes it: it listens to GitHub and, optionally, Feishu. When someone allowed asks the agent for work, it opens a work item, works on it in its own agent session and directory, and answers in the original conversation, for example with a pull request. A web panel shows what needs a person.

About DeepSeek Harness: per its website it is an open-source harness from DeepSeek, built on Cordis's "everything is a plugin" architecture, runnable as a desktop app or by launching the web UI from code, and currently in worldwide public preview. dsh-superagent is a plugin bundle in that system.

Team

  • Maker: DeepSeek (GitHub org deepseek-ai)
  • Created: 2026-10-31; so far a single commit ("feat: add the dsh-superagent research prototype")
  • Status: research prototype; the README says it may still contain bugs, that its coding style and engineering practices may be inconsistent, and that you should review and adapt it first

Project Data

As of GitHub on 2026-11-03; treat as a snapshot:

  • ⭐ GitHub Stars: ~15,500 (three days after creation)
  • 🍴 Forks: ~1,660
  • 📄 License: MIT
  • 💻 Languages: about 2 MB of TypeScript, with a little CSS and Python
  • 📦 Runtime needs: Node.js 22.19+ or 24+, pnpm, git 2.32+, tmux, Python 3.8+, GitHub CLI 2.48+, and DSH within the engines.dsh range
  • 🌐 DSH website: deepseek.com/en/harness

Main Features

What It Does

The chain it runs:

  1. Listen: GitHub notifications, watched Issues and PRs, CI changes, PRs merged or closed; Feishu live events and topic polling
  2. Judge: a request counts only when an allowed person addresses the agent directly; work nobody asked for needs a rule the team wrote
  3. Start: each request gets a ticket with its own Executor Session and directory
  4. Deliver: the result goes back into the original conversation, usually as a pull request
  5. Panel: the web panel lists only what needs a person; a healthy state takes no space

Use Cases

  1. Small everyday tasks in a team repo

    • Comment @agent <request> on an Issue; a ticket appears in about a minute, followed by an acknowledgement and later a PR
  2. Requests in a Feishu chat

    • With the bot configured, allowed people mention it in the chat
  3. Follow-ups after review

    • Review comments and CI results return to the right ticket through subscriptions, and the agent keeps working
  4. Proactive work under team rules

    • Write a rule for, say, a class of dependency updates; run in observe mode first, where it only records what it "would have accepted", then switch to auto once it looks right
  5. Managing the agent like a colleague

    • Use the panel for to-dos, approvals, retries and pausing, instead of staring at logs

Quick Start

The official approach is itself interesting: setup has many steps, so an agent does it with you.

Tell your coding agent:

Read SETUP.md in this repository and set up dsh-superagent with me.

SETUP.md is the install flow written for an agent, and it makes the setup agent follow "little attention" too:

  • Before the first question, read only SETUP.md and docs/000-philosophy.md and run one probe; read nothing else until every answer is collected
  • Ask one question per message, each under 300 words, each with a recommended answer you can accept with one word
  • Don't execute while asking: collect every answer, send one full plan, and act only after you confirm
  • Never ask for a secret in the chat; steps that need your hands (creating an account, signing a CLI in, entering an app secret) go into one message with the exact commands for your own terminal

The questions follow the domain model: first where requests come from (GitHub only or also Feishu, which repository, which GitHub account), then who may ask, then what the agent does with a ticket (where the local clone is, commit identity, auto-merge).

Defaults are conservative:

  • A dedicated profile superagent on port 3082
  • Branch prefix agent/
  • Accept mode observe (record, don't act)
  • Commits attributed to the agent's own account
  • Auto-merge off: people merge until the agent's pull requests have been right for a while

The example manual profile is short:

- id: webserver
  config:
    host: 127.0.0.1
    port: 3082
- id: dsh-superagent
  config:
    stateDir: <absolute path, for example /home/me/.dsh/state/superagent>
# Feishu is optional
# - id: dsh-superagent-feishu
#   disabled: false

For developers, pnpm check runs the typecheck, the tests and the build.

Core Features

  1. Acts only when asked or when a written rule allows it

    • A request must address the agent directly and come from a person the team allowed
  2. Speaks only when a person must act or can use a result

    • Confirms once, stays quiet while it works, and writes again when a result is ready, a decision is needed, or it cannot finish
  3. Asks one concrete question at a time

    • In a structured form, so the question reaches the person instead of staying inside a long report
  4. Stops by impact, not by effort

    • A local change goes as far as a reviewable result; a change that needs a design decision stops with a clear question
  5. Reports honestly

    • A draft is marked unfinished, a failure is reported as a failure, and a limit is never bypassed to avoid asking
  6. Teams shape behaviour with words

    • Three team prompt sections (communication, ticket scope, delivery requirements) plus team skills cover most needs

Advantages

Aspectdsh-superagentCalling a coding agent by hand in a terminalTypical GitHub bots
Trigger@-mention in an Issue or chat, asynchronousA person sits at the terminalFixed event triggers
Permission boundaryAllowed list, mandate records and admission table, enforced by the hostWhatever the session hasWhatever the script has
ProactivityYes, but record-only by default and rules are the team's to writeNoneYes, but logic is hard-coded
Interruption of peopleMinimizing it is the design goalNoneOften noisy
AuditabilityThe panel traces Trigger → Eval → TicketTerminal historyLogs

Why read it?

  • It writes the restraint of a proactive agent as executable rules, not a slogan
  • The authorization model is fine-grained: who can start work, how far it may go, what happens when rules change
  • The documents are ordered so each depends only on earlier ones; a good template for design docs

Deep Dive

One Sentence of Philosophy: Attention Is a Cost

docs/000-philosophy.md is only about 3 KB, but the whole project unfolds from it:

Take as little human attention as possible, and give as much value as possible.

Every message, notification, question, setting, panel element and paragraph of documentation costs someone's attention, and each has to give more value than that, or it is removed.

That yields the demands on the agent (listed under Core Features above) and also on the design itself:

  • Few concepts: only domain concepts, such as a Source, and their concrete implementations, such as GitHub and Feishu; a business need becomes an attribute of one of them, or a prompt the agent follows
  • Few settings: a default replaces a setting when one value suits almost every team; behaviour a team describes in words is prompt text, not a setting
  • A panel that shows only what needs a person: a healthy state takes no space
  • Documents read in order: each numbered document builds only on the ones before it

The last section is "Responsibility", and it's blunt: the agent comments, opens pull requests and messages people under accounts your team sees every day, every message it sends costs your colleagues' attention, and you are responsible for it.

  • Start narrow: a short allowed list, with proactive work only recorded; widen once what it would have done looks right
  • Tune for less noise: when it's noisy, make the prompts shorter and stricter, or pause it; don't add more messages to explain the noise
  • Do not use it to produce volume: mass pull requests, broadcasts and busywork cost the team more than they give
  • Own what it says: read what it posts in your name, and correct it in the prompts

It closes: "The goal is the right help at the right time, and nothing at any other time."

The Domain Model: From Trigger to Ticket

docs/001-domain.md defines the concepts. The main line:

Work moves from Trigger to Eval to execution. A Source produces Triggers. A Trigger fans out as context to the Tickets subscribed to its Threads. A person's message that reached a Ticket this way stays with that Ticket; every other Trigger enters Eval, which decides whether it asks for new work. When Eval accepts, it creates a Ticket with a Mandate. An Assignment hands the Ticket to an Executor, and results go back to the Source through a Channel.

The core concepts:

ConceptMeaningRules it keeps
SourceA stream of events, such as GitHub or FeishuHolds its own read position and bot identity; drops its own bot's messages; a restart must not replay events
TriggerOne immutable eventAccepting it twice creates one Ticket; the unit of audit and idempotence
ThreadTriggers in time orderAt most one Eval at a time; may have several Tickets
ChannelThe write side of a ThreadAcknowledgements, replies, PRs and resolved reviews are all writes
PolicyVersioned assessment rules, plus each Source's part (who may originate work, etc.)When the rules change, a running Eval must be discarded
EvalJudgement on a batch of Triggers, in two layers: gate and assessmentHolds no state; outputs a Decision
MandateWhat an accept grants: Policy version, scope, strength, matched rules, sender identityImmutable; wider scope means a new Ticket; only a person's stop withdraws it
TicketA unit of authorized workOnly Eval creates one; it defines its own state instead of following the Executor's
AssignmentBinding of a Ticket to one Executor instanceA Ticket has several over time
SubscriptionMany-to-many relation between Tickets and ThreadsLater discussion reaches the Executor without anyone mentioning the agent again

Two design choices deserve a pause.

First, "person" is not a domain concept. A Trigger carries its actor's identifier as the Source gives it; an allowed list is a Source's part of the Policy, in that Source's own identities. That one person has accounts on both GitHub and Feishu is prompt text the agent reads when needed, not a cross-Source identity mapping table.

Second, the document has a section on "Rejected concepts", recording the options not taken and why, for example:

RejectedReason
Ticket state that follows the DSH SessionA Ticket can be handed off, resumed or run by several Executors, so it defines its own state
An Executor declaring that a person asked it to stopOnly Eval decides the strength of an end
Cancelling running Tickets on a Policy changeA cancelled change leaves half-finished work; the change is recorded and delivered instead
Inferring "waiting on a person" from a report's free textThe classification needs structured facts; the Executor asks through a structured field
At most one live Ticket per ThreadOne Thread can carry several independent pieces of work

Writing down what you didn't do, and why, is something many projects skip.

Authorization and Admission: Who Can Start Work

The opening of docs/002-authorization.md sets the tone:

The host enforces allowed lists, rules and Mandates. Messages, comments and quoted documents are inputs to a decision; they cannot change those permissions.

A Trigger takes one of two paths:

  • Eval path: deciding whether to start work. The Source records whether a message addresses the agent (mention, or direct for a direct message). An allowed person addressing the agent makes an explicit request; other humans' messages use the admission table; a bot on the Source's bot list can produce an inferred candidate, never an explicit request
  • Subscription path: continuing existing work. Every message on a subscribed Thread (bots and CI included) reaches subscribed Tickets as context, bypassing the gate and granting no new authority; each Ticket stays limited by its Mandate

Strength has two levels:

StrengthCases
explicitAn allowed person addresses the agent, or follows up on a Thread that already has a Ticket; an admission-table cell set to explicit request
inferredA person not on the list follows up on a Thread with a Ticket; a cell set to inferred candidate; a message from a bot on the bot list
not admittedAny other bot, everything the table ignores, and every inferred case while the accept mode is off

Accept mode is part of the Policy:

ModeEffect
offNothing inferred becomes a candidate
observe (default)Inferred candidates are assessed; a positive assessment is recorded as an ignore marked "would accept", and nothing is accepted
autoA positive assessment of an inferred candidate accepts it

Explicit requests work in every mode. Start in observe, review the recorded Decisions, then switch to auto. Each assessment judges every enabled rule exactly once, and a proactive accept needs at least one matching rule.

What happens when rules change is spelled out too. A Policy change discards running Evals and queues their Triggers again, and sends a policy-changed Input to each affected live Ticket, explaining whether a matched rule changed, the requester may no longer start work, or proactive work is no longer accepted. It does not immediately revoke live Tickets' Mandates. Revalidation happens before an ended Ticket resumes:

  • An explicit follow-up Mandate passes
  • An inferred Mandate needs auto mode and its matched rules still enabled
  • A Mandate admitted by a table cell must still receive at least its original strength; removing a sender from the list can revoke a Mandate accepted through the listed-sender cell
  • A bot's Mandate requires that bot to remain on the bot list

If revalidation fails, the Ticket stays ended and each waiting message is treated as having reached no Ticket; if no other Ticket owns it, it goes to Eval.

Two more details:

  • A person saying "stop" in a Thread is an ordinary Trigger, and Eval decides stop. An Executor cannot declare that a person asked it to stop
  • Stop in the panel is a command that acts on the Ticket directly and is recorded as a manual stop

Subscriptions and "Ownership": Who Owns a Follow-up

This is the part that is easy to get lost in, and it shows the design skill.

A person's message on a Ticket's own Thread belongs to that Ticket's Executor to decide, with no Eval and no Decision. The Executor either handles it within the Ticket's scope or hands it back when the request goes beyond the scope or belongs to another Ticket.

A message goes to a fresh Eval only after no Ticket still owns it, and the candidate carries the Executors' reasons.

When a Ticket ends, it releases the follow-ups its Executor didn't read or take up; those not acknowledged, answered or handed back go to Eval.

There is also a passive form: an Executor can follow a related Thread (another Issue or PR) as context only. Its messages reach the Ticket but grant no authority and don't wake an ended Ticket.

Execution: How a Ticket Lives

docs/003-execution.md puts an open Ticket into one stage at a time, taking the first matching row from the top:

StageConditionPanel label
person / deliveryDelivering an Input to the Executor Session failedInput undelivered
person / answerIt has an Attention (a question waiting for a person)Awaiting answer
person / reviewThe latest Report is readyAwaiting review
person / blocked, failedThe latest Report is blocked or failed, and no person has replied sinceBlocked · Failed
working / queuedNo Assignment, or a pending oneQueued
idleThe latest Report is waiting, or the Assignment endedWaiting for a Trigger
workingEverything elseWorking

Any person stage means the Ticket can't continue without human input. A new human message releases a blocked or failed Ticket back to its Executor.

What the Executor is: each Ticket gets an Executor Session named worker-<ticket id> and a directory named after the Ticket's short name. Sessions run commands without approval as the operator's OS user. Foreground shell commands move to background jobs after 5 seconds, so a worker can receive new messages at the next step instead of waiting for a long command.

The doc is detailed about background work:

  • When a turn ends with shell jobs or subagents still running, the Ticket keeps its worker slot and stays working; it isn't reported as waiting
  • After each turn, background work has at most 30 minutes; at that limit, shell jobs are killed and the Ticket is reported waiting, saying which were killed and which subagents remain
  • A handoff to a person frees the slot immediately; subagents stop, while shell jobs such as a server offered for review may continue until the Assignment ends

Concurrency: the configured limit applies to worker slots, plus one extra slot for a person's message or a status request. New work therefore can't prevent a person from continuing an existing Ticket.

Preparing the directory: before the first Assignment, if the Ticket directory doesn't exist, the prepare command runs once with sh in the execution root, with ten minutes to finish. A typical command uses git worktree. A PR belongs to the Ticket when its branch's last path segment matches the Ticket's short name.

Execution variables: the prepare command and the Executor read the same variables, such as DSH_SUPERAGENT_DIR, DSH_SUPERAGENT_TICKET, DSH_SUPERAGENT_GITHUB_REPOSITORY and DSH_SUPERAGENT_GITHUB_ACCOUNT, and none contains credentials.

Merging: Governed by Prompt, Not by the Host

Auto-merge is governed by the Delivery requirements prompt; the host has no merge-specific decision logic.

By default, the Executor never enables auto-merge as the agent account, because GitHub attributes the merge to whoever enabled it. Delivery requirements must name another account's CLI for merging, or people merge.

The default instructions allow auto-merge only when the PR was opened for the Ticket, is ready, the required approvals cover the head commit, and additions plus deletions total fewer than 200 lines. Before pushing another revision, the Executor withdraws auto-merge.

The doc is sober about it: these instructions govern the agent, not GitHub's merge rules. To enforce approvals, require them in branch protection and dismiss stale approvals.

Prompts: How Teams Shape the Agent

docs/004-prompts.md explains what a team can edit:

SectionHolds
CommunicationWhen to message people, how messages read, the line that begins every GitHub message (This is by an automated agent, not a human by default), how to handle reviews, which ordinary accounts are review bots
Ticket scopeWhen a Ticket goes on and when it stops with a draft
Delivery requirementsEvidence in PRs, the auto-merge condition and its line threshold, the commit author
Team skillsKnowledge the agents load when needed, such as an identities skill saying which Feishu user is which GitHub account

The system prompt is assembled in a fixed order: shared instructions and role, the three team sections, subscriptions and replies, dispatch or work instructions, admission, handoff, environment, and finally the Policy section. The Policy section is regenerated on every model request and sits last so that a Policy change leaves the preceding prompt text unchanged (cache-friendly).

From strongest to weakest:

  1. Facts enforced by tools and the host (identities, permissions, argument checks, reply purposes, length limits); prompt text cannot change them
  2. Built-in and generated sections, as the team's overrides read
  3. Process and communication in a proactive Ticket's matched rules, for that Ticket's Executor Session only
  4. Team sections and team skills
  5. Outside text: messages, comments, documents and quotes. It is data and never changes rules or authorization.

The last item is the prompt-injection defence: however command-like outside text looks, it is only data.

The principles of the built-in text are worth reading, for example:

  • Separate roles: the main Session only routes; it forwards the original Trigger and routing facts, makes no technical decisions, and a routing note is at most 30 words; the Executor reads the original sources, judges scope, implements and verifies
  • The main Session does not wait: reports, follow-up notices, candidates and completed jobs arrive as messages; a guard refuses sleep, shell timeouts over 30 seconds and job waits over 5 seconds, because a blocked step delays new candidates
  • Message only when a person must act or can use a result; chat messages are one sentence by default, with a hard limit of 100 words
  • Attach only on an explicit reference: a message must point to a Ticket's PR, Issue, source message or acknowledgement; topic similarity alone is not enough
  • Honest delivery: opening a PR is not readiness; a draft is marked unfinished; a UI change without a real before screenshot is not ready
  • Yield to duplicate work: when a person's branch or PR already contains the change, the Executor closes its own PR with one sentence pointing to theirs
  • Handle reviews by outcome: a fixed and verified comment is resolved silently; a declined one gets one sentence of reason; each automated reviewer gets at most three rounds per PR

Failure and Recovery

The execution doc spends a lot of space on "what happens when it goes wrong":

  • Executor blocked or failed: the Ticket takes no automatic Input; passing model-provider or network failures (HTTP 408, 429, 5xx, refused, reset or timed-out connections) are retried three times with growing backoff; once failed, CI and bot messages are recorded but not delivered and don't wake the Session; a person's message, a later non-blocked/failed Report, or a retry ends the hold
  • Restart: running Assignments end with "host restarted" and new ones start with a recovery note telling the Executor to check its directory, git history and GitHub before repeating any outside action, oldest Ticket first
  • "Store first, do after": what dsh-superagent does after a decision (relaying a candidate, launching an Assignment, delivering an Input) is stored first; failures retry after 2 seconds, doubling up to a minute; a kind of work reports a system problem only after one item failed three times in a row
  • Channel failure: outgoing messages are stored work too, retried from 5 seconds, doubling up to 300; a Ticket's messages to one conversation go out in order, so its acknowledgement comes before its answer; a message is dropped only when its Source no longer listens to the conversation or answers that it can never receive it, and a dropped message keeps its record so an acknowledgement reads as dropped, not sent
  • Pause processing: stops dispatch, new Evals, Eval timeouts, Input delivery and replies; Sources keep recording Triggers, and a running Executor turn isn't interrupted

The Panel: Three Questions Only

docs/005-panel.md says opening the panel answers three questions, in order: Does anything need me now? Is the system healthy and doing the right things? What is the history of one piece of work, from Trigger through Eval to Ticket?

Tabs follow the workflow: Overview, Source, Trigger, Eval, Execution, Settings. Overview lists Tickets needing action first, then system problems, 24-hour activity counts and Executor load.

Code Layout

Roughly how src is organized:

DirectoryContents
src/coreThe domain core: engine.ts, evals.ts, tickets.ts, assignments.ts, intake.ts, replies.ts, ports.ts and so on
src/sourcesThe GitHub and Feishu Source implementations: reading, triggers, channels, polling, registry
src/executorThe DSH integration (dsh.ts) and background-job handling (background.ts)
src/appRuntime, HTTP API, settings, prompt assembly, session management, migration, tools
src/clientThe panel frontend (React / TSX)
src/infraCommands, environment, health, paths
prompts/, skills/Default prompts and the GitHub and Feishu skills
tests/Many tests; the biggest, runtime.spec.ts (~142 KB) and core-engine.spec.ts (~107 KB)

docs/007-architecture.md is about 70 KB of architecture documentation and docs/008-cookbook.md about 30 KB on adding a Source. I did not read those two line by line.


Scope and Limits

  • Officially a research prototype: not a DeepSeek product, and not meant to be used as production software; review and adapt it first
  • Not identical to the article: it differs from the internal version and from the implementation the article describes; some designs there are future directions
  • Depends on DeepSeek Harness: it's a DSH plugin bundle and needs a DSH within the version range plus a configured model provider
  • The Executor's authority is large: sessions run commands without approval as the operator's OS user. The docs say outright that the wrappers and directories establish defaults, not a security boundary, and a worker can still run a program by absolute path. Think hard about what it can reach before deploying
  • Many prerequisites: Node 22.19+, pnpm, git, tmux, Python, GitHub CLI, DSH, and a dedicated GitHub account for the agent (the docs advise against using your own)
  • One GitHub repository, with Feishu optional; other hosts need a new Source (docs/008-cookbook.md covers it)
  • Humans stay in the loop by default: auto-merge is off and proactive acceptance is record-only
  • Very new: created three days ago, a single commit and no releases; the docs will evolve
  • Docs are in English, with a small amount of Chinese UI text (locale/zh.json)

Official

  • Article: Exploring Super-agent Design: Towards a More Autonomous Agent System (cited by the README; I couldn't find the original and haven't read it)
  • Cordis paper: listed on the DSH website

Summary and Outlook

Key Takeaways

  1. Attention is a cost: every message, setting and panel element must prove it's worth someone's attention, or be removed
  2. Proactive, but restrained: it acts only when asked or when a team rule allows; proactive acceptance is record-only by default
  3. Traceable, tamper-resistant authority: a Mandate is immutable; only an accept, a person's stop and a failed revalidation change it; outside text is only ever data
  4. Who owns the message: subscriptions and "hand back" ensure each follow-up has exactly one owner, never handled twice and never by nobody
  5. The docs are the product: ordered reading and a record of rejected options with reasons make a good design-document template

Who It's For

  • Engineering leads who want coding agents to work asynchronously and under control in a team repo
  • Developers designing authorization, admission, subscription and noise-reduction for proactive agents
  • People writing Skills, prompt systems or agent docs; the way this repo organizes its documentation is worth borrowing
  • Anyone following the DeepSeek Harness ecosystem

Suggestions

Don't install first. Read docs/000-philosophy.md through docs/003-execution.md in order (four short documents) and then decide whether to run it on your own repo. If you do, use a dedicated GitHub account, put only yourself on the allowed list, and keep the accept mode on observe so it "would have" done things for a while before you widen anything.


Explore PrimeSkills — curated AI agent and skill tools, each validated in real workflows. No hype, just tools that actually work.

Visit my homepage for more insights and interesting products.