DeepSeek Harness 插件

agentrq

AgentRQ task manager for DeepSeek Harness: create, manage, and auto-pull AgentRQ tasks without leaving the harness(英文原文)

跳到安装方式

来源信息

GitHub 仓库
agentrq/agentrq
最近更新
2026年8月22日
分类
插件市场与管理
GitHub stars
1088
载体类型
plugin
包路径
plugins/deepseek-harness
目录证据
上游声明已找到 dsh.bundle
证据路径
plugins/deepseek-harness/package.json#dsh.bundle
核对版本
0.1.0-rc.8
上游核对日期
2026-08-20

该证据由上游目录提供。本站没有安装、运行或安全审核这个插件。

安装

默认先复制一段 Prompt,让 Agent 读 GitHub 仓库和源码;需要自己装时再切到命令。

复制这段 Prompt,发给 DSH、Codex 或其他 Agent,让它先读 GitHub 仓库和源码。

请先不要安装或执行任何命令。阅读这个插件的 GitHub 仓库、README 和关键源码,然后用清楚、直接的方式回答以下问题,帮助我判断它是否适合我的需求:

1. 这个插件是什么,解决什么问题;
2. 适合哪些用户和典型使用场景;
3. 安装后如何使用,并给出一个最小使用示例;
4. 有哪些已知限制,以及隐私、安全、兼容性或维护风险;
5. 给出“推荐 / 有条件推荐 / 不推荐”的明确建议和理由。

请区分仓库明确说明、根据源码推断和未知信息。证据不足时请明确说明,不要猜测或照抄 README。

GitHub:https://github.com/agentrq/agentrq/tree/HEAD/plugins/deepseek-harness
插件名:agentrq
作者:agentrq

检查来源文件

安装前先看这个插件目录里的 README 和其他文件。

文件资源管理器3 个文件
README.md来源说明 · 只读预览

@agentrq/dsh-plugin-agentrq

AgentRQ task manager for DeepSeek Harness.

Create, manage, and automatically receive AgentRQ tasks without leaving the harness. The bundle ships two rows: the workspace's tools bridged to the model, and the harness-side behavior a tool bridge cannot provide on its own — a supervised workspace session that opens a dedicated dsh session for each task AgentRQ pushes, and the AgentRQ working agreement as a system-prompt section.

Install

Requires pnpm. dsh plugin is a thin forwarder to pnpm for every profile — installing any plugin, this one included, fails with pnpm not found on PATH unless pnpm is already installed (npm install -g pnpm, corepack enable pnpm, or brew install pnpm). This is a DeepSeek Harness CLI requirement, not something this plugin can opt out of.

One profile per workspace. A profile serves one AgentRQ workspace and carries its own endpoint, so name it after the workspace rather than using default — that is what makes [several workspaces](#multiple-workspaces) work. Your workspace's Settings → Setup → DeepSeek Harness page prints every command and config block below already filled in.

npx @deepseek-ai/dsh plugin --profile agentrq-<workspace> add @agentrq/dsh-plugin-agentrq

Then pin this workspace's endpoint in the profile's own patch layer, ~/.dsh/profiles/agentrq-<workspace>/cordis.patch.yml. Copy the URL from the Settings page — it already carries the ?token= credential that authenticates a headless client:

- id: agentrq
  name: '@agentrq/dsh-plugin-agentrq'
  config:
    url: "https://<workspace>.mcp.agentrq.com/mcp?token=<token>"

One row, one URL: the plugin mounts @deepseek-ai/dsh-mcp-client itself as a child fiber, so the endpoint is configured in exactly one place and the bridge shares this row's lifetime — disposal and HMR take it along.

npx @deepseek-ai/dsh --profile agentrq-<workspace> --dump-config   # shows the bundle layer and your override
npx @deepseek-ai/dsh --profile agentrq-<workspace>

The profile's patch is applied after every bundle layer, so those two rows win. dsh watches both cordis.patch.yml layers and reapplies valid edits transactionally, so changing the URL takes effect without a restart.

Using dsh web (browser UI)

dsh web is an alias for --profile web — a fixed, dsh-shipped profile that is a different profile from any agentrq-<workspace> profile made above, and the two do not share bundles. Installing into one does not make the plugin visible in the other. To use this plugin from the harness's browser UI, target web directly:

npx @deepseek-ai/dsh plugin --profile web add @agentrq/dsh-plugin-agentrq

Then either pin the endpoint in ~/.dsh/profiles/web/cordis.patch.yml (same block as above) or export AGENTRQ_WORKSPACE_MCP_URL before starting:

export AGENTRQ_WORKSPACE_MCP_URL='https://<workspace>.mcp.agentrq.com/mcp?token=<token>'
npx @deepseek-ai/dsh web

Because [a single profile cannot serve two workspaces](#multiple-workspaces), only one AgentRQ workspace can be wired into the browser UI this way — use the --profile agentrq-<workspace> flow above for several at once.

Configuring without a file edit

The bundle's own patch defaults both rows to !!js process.env.AGENTRQ_WORKSPACE_MCP_URL, so a container or CI job can export the endpoint instead of writing a profile patch:

export AGENTRQ_WORKSPACE_MCP_URL='https://<workspace>.mcp.agentrq.com/mcp?token=<token>'
npx @deepseek-ai/dsh --profile agentrq-<workspace>

Prefer the profile patch for an interactive install: an environment variable is process-global, so with one profile per workspace you have to remember the right export before each start, and the wrong one connects the wrong workspace without complaint. Supply neither and the row fails to load with the url field named — it is a required field, not a silent default.

Installing from a git checkout instead of the registry fetches sources rather than built artifacts, so pnpm must be allowed to run this package's prepare build. Add the allowance to your profile's pnpm-workspace.yaml and re-run the add:

allowBuilds:
  '@agentrq/dsh-plugin-agentrq': true

That allowance is permission to execute this package's code on your machine at install time. Pin a commit (github:agentrq/agentrq#<sha>) if you take that route. Publishing to npm or shipping a pnpm pack tarball avoids the allowance entirely.

What the model gets

Seven AgentRQ tools, bridged by @deepseek-ai/dsh-mcp-client under the agentrq namespace:

ToolPurpose
mcp__agentrq__getTaskFetch a task, or dequeue the next one assigned to this agent
mcp__agentrq__createTaskAssign work to the human or to another agent
mcp__agentrq__updateTaskStatusMove a task to ongoing, completed, blocked, …
mcp__agentrq__replySend a message into a task thread — the only thing the remote human sees
mcp__agentrq__getWorkspaceRead the workspace title and mission
mcp__agentrq__downloadAttachmentFetch an attachment's content
mcp__agentrq__publishEventFire a named event so subscriber workspaces spawn their trigger tasks

Plus one tool this package owns:

ToolPurpose
agentrq_autopullstatus, pause, resume, or pull_now for this session's AgentRQ delivery

pull_now returns the dequeued task as its own tool result rather than queuing a turn, because a tool body runs mid-turn by definition.

How work arrives

The plugin does not poll. AgentRQ already decides when there is work and pushes it over notifications/claude/channel:

  • creating a task assigned to the agent pushes it immediately (backend/internal/handler/api/task.go), provided nothing else is ongoing;
  • WorkspaceServer.StartPoller re-pushes the next unclaimed task — or a status check for the ongoing one — every 60 seconds.

The plugin's own workspace session subscribes to that channel, exactly as acp-gateway does for Gemini and other ACP agents. Polling the queue from the client would duplicate the server's own ticker and deliver every task twice.

Each push is forwarded as written. A new task, the periodic reminder, a status check, and a human's reply all arrive on the same channel; the plugin adds a framing line naming the chat_id and the tools to answer with, then hands over the content. It does not try to classify what kind of push it is, because that would only add a way to be wrong. The content is JSON-escaped into the framing, so pushed content cannot forge a framing field.

Each task gets its own dedicated dsh session. The plugin's own workspace connection is not tied to any chat you open — the first push for a given task (its chat_id) opens a fresh, dedicated agent via ctx.agents.create() and hands it the framed push; every later push for that same task (the reminder, a status check, a human's reply) is routed into that same session, not into whatever chat you happen to have open. This is what keeps one task's history from bleeding into another's. Delivery route within a task's session depends on its agent's state: inject() while a turn is running, so it lands at the next step boundary, and followup() while idle, since nothing else would wake it. Neither interrupts a turn in flight.

A session created with no provider/model fails every turn outright (prompt assembly has no value for {{model}}), and one created with the wrong cwd leaves the agent unable to find its own codebase, groups as "Ungrouped" instead of under your project in a capable UI, and can fall back to naming the session after that wrong directory (prompt assembly also has no value for {{cwd}} with none set at all). So every dedicated session gets an explicit cwd and agentOptions: cwd/provider/model config when set, otherwise both come from the reference agent — whichever live agent in the same process most recently started a turn (tracked from agent/status since the manager started), falling back to the longest-lived agent still around when nothing has been active yet. cwd deliberately does not fall back to process.cwd() except as an absolute last resort (no reference agent at all): under dsh web, the harness process's own cwd is the dsh profile directory (e.g. ~/.dsh/profiles/web), not the project a human actually works in, and defaulting to it left a real dedicated session stuck for dozens of steps trying to locate a codebase that was never there. There is no way to ask the harness for its own configured default model/cwd from a plugin, only to read them off an agent that already has them, so the very first task pushed before this process has ever seen any activity still fails/misbehaves unless model (and, if the process cwd is wrong for this deployment, cwd) is configured explicitly.

SendChannelNotification puts the task id in meta.chat_id on every push, so the id never has to be recovered from the content, and it doubles as the key the manager uses to find a task's session again.

A newly opened session is titled and grouped, not left for a UI to guess at. A session's display name is a durable session/title log event (@deepseek-ai/dsh-session-title) — never inferred from a message's content, and even that package's own deterministic fallback only considers genuinely human-sourced messages, which this plugin's pushes never are. So the manager calls sessionTitle.rename(session, title) directly: the task's own title when the push already carries it (the startup catch-up path), otherwise fetched via getTask — one extra round trip, only the first time a task's session opens, skipped silently (with a warning) if the lookup fails or the task has no title. Grouping works the same way: a session is never folded into a workspace just because its cwd happens to match one (@deepseek-ai/dsh-workspace's own docs: "later cwd-only sessions remain Ungrouped") — the manager resolves or creates the workspace owning the session's cwd and calls Workspace.attachSession explicitly. Both sessionTitle and workspaceRegistry are optional host services (ctx.get(name), never a direct ctx.sessionTitle/ctx.workspaceRegistry read — that assumes an inject-declared, guaranteed-present service, which these deliberately aren't); a deployment without session persistence mounts neither, and the session still works, just untitled and ungrouped.

A task's session survives a harness restart. The manager's live task→session map is only ever in memory, but a session's own id already encodes its task id (agentrq-task-<taskId>-<random>), so nothing separate needs to persist it: at startup the manager lists every session @deepseek-ai/dsh-session-persistence already knows about (headers only, not full logs), and the first push for a task whose session survived resumes it (ctx.agents.resume) instead of opening a duplicate. A resume that fails (a corrupted log, say) falls back to opening fresh rather than blocking delivery. The random suffix matters here, not just for looks: an incrementing in-process counter resets across a restart, and the moment the same task got pushed twice across one, the persistence layer rejected the reused id outright as already belonging to a different session.

Repeats are dropped. The workspace re-pushes an unclaimed task verbatim every minute; the manager remembers recent (task, content) pairs, so a task's session is handed it once and not woken every sixty seconds for work it already has. A genuinely new message on the same task still gets through.

A task's session closes itself once the task is done. An idle agent does not by itself mean the task is finished — it may simply have asked the human a question and be waiting on a reply, which must land in the same session. So on every idle transition the manager reads the task's own status back through getTask; only completed or rejected closes the dedicated session. blocked and anything else keep it open so the next push — including the human's reply — still has somewhere to go.

Staying connected is the load-bearing part. No workspace session, no pushes — so a closed transport or an unrecoverable transport error triggers a reconnect with exponential backoff (reconnect.initialDelayMs doubling to reconnect.maxDelayMs), on top of the SDK's own SSE resumption. Because the server re-pushes on its own schedule, a recovered connection catches up on the next tick without any client-side replay. A task's own dedicated session is unaffected by a workspace reconnect — it is a separate, harness-native agent, not part of the workspace transport.

catchUpOnStart dequeues one task when the workspace connection opens, so work that predates the connection does not wait for the server's next tick. A failed startup check costs latency, not work.

agentrq_autopull pause stops the manager from opening or routing into task sessions; already-open ones stay live until their task closes them, and the workspace connection itself stays open.

Multiple workspaces

AgentRQ users normally have several workspaces, each with its own queue, mission, and agent identity. Run one profile per workspace.

Install once per profile, and let each profile's cordis.patch.yml carry its own endpoint:

npx @deepseek-ai/dsh plugin --profile agentrq-acme add @agentrq/dsh-plugin-agentrq
npx @deepseek-ai/dsh plugin --profile agentrq-beta add @agentrq/dsh-plugin-agentrq
# …then pin acme's URL in ~/.dsh/profiles/agentrq-acme/cordis.patch.yml
#     and beta's URL in ~/.dsh/profiles/agentrq-beta/cordis.patch.yml

npx @deepseek-ai/dsh --profile agentrq-acme    # terminal 1
npx @deepseek-ai/dsh --profile agentrq-beta    # terminal 2

Because the endpoint lives in the profile rather than the environment, switching workspaces is switching profiles — nothing to re-export, and no way to start one workspace's profile pointed at another's queue.

Each profile gets its own process, sessions, working directory, and workspace connection, which matches how AgentRQ already models a workspace: one workspace, one agent, one mission. It also matches the usual case where workspaces track different repositories.

Two consequences worth knowing:

  • A single profile cannot serve two workspaces. Mounting the bundle twice in one profile registers the agentrq:protocol prompt section and the agentrq_autopull tool twice in the same layer, and both registrations throw on a duplicate name. Namespacing them per instance is deferred until someone needs it.
  • No cross-workspace view. AgentRQ's CoreMCP supervisor (https://mcp.agentrq.com/mcp) does expose listWorkspaces and listAllTasks, so a deployment that wants "what is outstanding everywhere" can mount it as an extra @deepseek-ai/dsh-mcp-client row. It sends no channel notifications, so it complements per-workspace delivery rather than replacing it.

serverName is safe to change: the guidance section and every framing derive their tool names from it, so the namespace the model sees and the namespace the prose describes cannot drift apart.

Config

KeyDefaultMeaning
url— (required)Workspace MCP endpoint, including its ?token= credential
token''Bearer token, for deployments that prefer an Authorization header over ?token=
mountBridgetrueMount the @deepseek-ai/dsh-mcp-client child that gives the model AgentRQ's tools
serverNameagentrqNamespace for the bridged tools; the guidance section and framings follow it
deliverPushestrueOpen and route into a dedicated session for each task the workspace pushes
catchUpOnStarttrueDequeue one task when the workspace connection opens
reconnect.initialDelayMs1000Delay before the first reconnect attempt
reconnect.maxDelayMs900000Ceiling for the reconnect backoff
guidancetrueContribute the AgentRQ working-agreement system-prompt section
requestTimeoutMs30000Timeout for one AgentRQ tool call
provider''Provider route for each task's dedicated session. Empty copies the most recently active agent's provider
model''Model id for each task's dedicated session. Empty copies the most recently active agent's model
cwd''Working directory for each task's dedicated session. Empty copies the reference agent's cwd (see above) — not the dsh process's own cwd, which under dsh web is the profile directory, not your project

Set any of these in the same profile patch. A patch replaces a row's whole config rather than merging into it, but every key except url has a schema default, so a row only restates what it changes:

- id: agentrq
  name: '@agentrq/dsh-plugin-agentrq'
  config:
    url: "https://<workspace>.mcp.agentrq.com/mcp?token=<token>"
    catchUpOnStart: false
    reconnect:
      initialDelayMs: 2000
      maxDelayMs: 60000

The prompt section

AgentRQ's MCP server ships its collaboration rules as server Instructions, and the harness does not surface an MCP server's instructions to the model. Without them the model has the tools but not the contract — that the human is remote, sees only what reply sends, and needs the task claimed before work starts. This package contributes those rules as the agentrq:protocol section in the tool-guidance band (order 150), so behavior in dsh matches behavior in the Claude Code and Gemini extensions. Turn it off with guidance: false when a deployment states the same protocol in its own persona.

Development

npm install --legacy-peer-deps   # harness packages declare peers pnpm resolves from the profile
npm run typecheck
npm test
npm run build

make plugin-deepseek from the repository root runs all four.

Releasing

.github/workflows/plugin-deepseek-harness.yml typechecks, tests, and builds this package on every pull request that touches plugins/deepseek-harness/**, and publishes it to npm when such a change lands on main.

Bumping version in package.json is what releases. npm refuses to republish an existing version, so the workflow checks first and skips the publish when the current version is already on the registry — an ordinary fix that touches this path does not need a version bump to merge.

Authentication is npm trusted publishing: the package names agentrq/agentrq and this workflow file as its trusted publisher, the job requests an OIDC token with id-token: write, and npm exchanges it for a short-lived publish credential. There is no NPM_TOKEN secret to store, rotate, or leak, and npm attaches build provenance automatically.

Two things that break it, both non-obvious:

  • Renaming the workflow file. The trusted-publisher record names plugin-deepseek-harness.yml exactly; a rename must be made on npm's side too or every publish is rejected.
  • npm older than 11.5.1. setup-node with Node 22 installs npm 10.x, which has no OIDC support and silently falls back to looking for a token. The workflow upgrades npm explicitly for this reason — do not remove that step.

Known limitations and deferred work

  • Two pushes racing for the same brand-new task can still open two sessionsdeliverPush doesn't await the previous call for a different chat, so if two pushes for a task neither has seen before arrive close enough together, both can find no live or persisted session and both create one. Existing pushes for an already-open task don't have this problem (they queue into the resolved session, live or resumed).
  • One workspace per profile — each row carries one url, and mounting the bundle