DeepSeek Harness Plugin Hub

发布与管理完整 Harness Profiles,发现适合你的插件。

探索

插件目录环境预设文档中心动态

社区

发布插件联系我们报告问题

相关链接

Plugin Hub GitHubDeepSeek Harness 官方项目系统状态隐私说明
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

独立、非官方社区项目,与 DeepSeek 官方无隶属、授权或背书关系。

Reins — DeepSeek Harness 插件(DSH Plugin)
DeepSeek Harness Plugin Hub
ProfilesPlugins分类动态文档登录管理 Profiles
ProfilesPlugins分类动态文档登录
← Plugins
R

dsh-reins

Reins

面向 DeepSeek Harness 的持久化目标编排:任务 DAG、持久化审批与等待、崩溃恢复,以及自行运行测试的验收。

插件会安装到这里;不确定时保持 web。

npx -y @deepseek-ai/dsh plugin --profile web add github:dreamfarer-space/dsh-reins#366926cf11ff4995b80c3981be41108fcd12f6d9
README兼容性版本

兼容性与来源证明

Reins 以 dsh-reins 发布,当前版本为 0.4.0。Plugin Hub 会校验它的 manifest,并保存精确安装来源,便于复现安装结果。

DSH 兼容范围
*
运行环境
web
发布来源
github
Registry 更新时间
2026/10/3

版本

0.4.0stable
2026/10/3

相关插件

正在加载相关插件…

最新版
0.4.0
DSH
*
HMR
重启进程
Tree shaking
未声明可安全裁剪
解包体积
未提供
文件数
未提供
Surface
web
许可证
MIT
发布源
github
GitHub
★ 0
周下载
0
最近提交
2026/10/3
查看源码 ↗
README Badge

点击下方 Badge 复制 Markdown,粘贴到 README 即可。

这是你的 Plugin?认领权益 · 优先安全扫描

验证 package.json 声明的 GitHub 仓库,即可管理这个公开页面。认领后,Hub 会优先安排当前版本的安全扫描,并在通过后公开展示结果。

认领这个 Plugin →
报告问题

相关插件

继续浏览 agents-orchestration 分类下经过校验的插件。

Skills Manager@michengai/dsh-skills-managerDSH Skills Manager — 在 DeepSeek Harness 中统一加载并安全管理本机 Agent Skills · 在 DSH 中加载并安全管理本地 Agent SkillsDs Botds-botDS Bot:DeepSeek Harness 的一组长期运行的 Bot,支持主 Bot、Bot 间消息和群聊Agency Agents@michengai/dsh-agency-agentsDSH Agency Agents — 为 DeepSeek Harness 提供 331 名可召唤的领域专家DSCODE Desktop@toddzheng024/dscode-desktop为 Harness Desktop 提供编码协作、记忆、浏览器工作流和任务管理功能。

README

Reins — durable Objectives for DeepSeek Harness

English · 简体中文

Harness executes. Reins holds the reins.
Tell Reins what you want in one sentence. It plans it with you, keeps it moving across Tasks, sessions,
approvals, CI, failures and restarts, and calls it done only when the check it runs itself passes.

Install · Quick start · Commands · Configuration · Architecture · Security model · Tests · Development


Why Reins

An Agent conversation is good at "do this now". Real engineering goals take longer: change the code, run the tests, wait for someone to approve a push, wait for CI, fix what CI found, wait for review… and somewhere in between the process crashes or the machine restarts.

Keeping an Agent loop spinning while it waits wastes resources, and it makes it easy to mistake "the model said it is done" for "it is done". Reins moves all of that into a durable orchestration layer:

  • Describe the goal in plain words; your conversation's model plans it with you and asks when there is a real choice to make.
  • Waiting is durable state, not an idle Agent loop; when the event arrives, a new Attempt continues.
  • A sensitive call is denied when no one approves it; an approval authorizes exactly that one call.
  • A Task is complete only when it passes the acceptance gate. A finished Goal or a successful Attempt is not enough, and tests are run by Reins itself, never taken from the Agent's word.
  • Everything lives in SQLite. After a crash, Reins reconciles conservatively: nothing uncertain is ever treated as success.

How it works

From one sentence to an accepted result

/reins add a delete command to my notes tool
  1. The model of the conversation you typed this in looks at the project first.
  2. When the request leaves a real choice open, it asks you (DSH's question card with options). Things it can find out itself, it does not ask.
  3. If no existing test covers the change, it writes the check first and confirms that the check fails today.
  4. It calls reins_create_objective with the Tasks, their order and a check command per Task. Reins pins the check files by hash, so the Agent doing a Task cannot rewrite its own exam.
  5. Reins' own Agents do the work in the background, in their own sessions. When one needs approval, /reins-todo lists it, and /reins-approve <id> lets the Task continue where it stopped.
  6. Reins runs the check itself. Exit code 0 is the only way to "done".

This was verified with a real DeepSeek model in DSH Web. Asked for "a delete function for the notes tool", the model asked whether to delete by index or by text, wrote check-delete.mjs and saw it fail, and created the Objective. A Reins Agent implemented delete-by-index, and Reins ran the pinned check: exit 0, accepted.

Features

CapabilityWhat it means
💬Plain-words planning/reins <what you want>: the conversation's model plans with you, asks about real choices, writes the check first, then creates the Objective
🧭Task DAGAn Objective holds several Tasks with dependencies; a downstream Task becomes ready only when its upstream Tasks are accepted
🔁Attempt boundaryEvery run is an immutable Attempt; a finished Attempt never comes back to life, every resume is a new Attempt
✋Durable approvalsSensitive tools are denied and parked when no one approves; an approval becomes a one-shot grant bound to Task / Attempt / session / Goal / tool / arguments / policy version / expiry and is consumed atomically, once
⏳Durable waits and eventsawaiting_approval / awaiting_ci / awaiting_timer / awaiting_external_event; immutable events, idempotent consumption, duplicate suppression
📡Polling watchersGitHub Checks, PR reviews, local/remote processes; backoff, timeouts, rate limits, offline handling, stale results refused; credentials never stored or logged
🧩Safe replanningGraph revisions; the DAG changes only at safe points, and an Attempt from an old revision cannot be accepted (enforced in the database)
🌿Parallel worktreesParallel Tasks each get their own git worktree; orphan reconciliation, branch conflict avoidance, merging, acceptance bound to artifact hashes
🤖Subagents / session forkRoute a Task to a normal session, a read-only subagent or a session fork; seeing a tool is not permission to use it
🧪Acceptance gateFrozen criteria and deterministic validators (file checks, durable reins.* facts, and reins.command_succeeds, where Reins runs the test command itself); only a pass receipt completes a Task
📉No-progress detectionDeterministic failure fingerprints; repeated identical failures, a stalled acceptance, repeated denials or tool errors put the Task on hold for you

Install

Requirements

  • Node.js ≥ 22.13 (for the built-in node:sqlite)
  • DeepSeek Harness @deepseek-ai/dsh@0.2.0-rc.1 (Reins pins its peer dependencies to this version)
npm install -g @deepseek-ai/dsh@0.2.0-rc.1

Below, <DSH_HOME> is the Harness data directory (the DSH_HOME environment variable, ~/.dsh when unset) and web is the profile to install into.

1. Get a fixed copy

Install from a fixed snapshot directory, so that later changes to a working copy do not change what is installed:

git clone --branch v0.4.0 https://github.com/dreamfarer-space/dsh-reins.git reins-0.4.0

2. Install the plugin

Reins is a DSH plugin bundle. Either:

  • In DSH Web: sidebar Plugins → Add plugin, enter the absolute path of the snapshot directory (for example D:/plugins/reins-0.4.0), then Enable now.

  • From the command line:

    dsh plugin --profile web add file:/absolute/path/to/reins-0.4.0
    

Reins then appears under Plugins → Installed with its icon and description; the switch on the right starts and stops it. You do not need to edit cordis.patch.yml.

3. Settings on the Plugins page

Open Reins on the Plugins page. Settings are edited right there and apply as soon as you save, without a restart:

SettingWhat it does
Approval policyStrict: every tool needs approval. Recommended (default): reading and editing files is trusted; commands, network, subagents and unknown tools need approval. Custom: the recommended set plus tools you tick (pwsh, bash, web_fetch, …), and a list of tools that always need approval. Trust all: everything except the always-ask list (only for directories you can roll back)
Continue automaticallyContinue after events, retries or a finished Task without waiting for /reins-tick (the Objective must allow it too: ask for it in /reins, or /reins-goal --auto)
Approval wait in the pageHow long an approval may wait in the conversation before the Agent is released and it moves to /reins-todo
Default workspaceWhere Objectives without their own workspace work
Desktop notification / reminder in conversationHow Reins tells you that it needs you or that something finished

These settings are stored in the profile's cordis.patch.yml (config: under - id: reins) and can be edited by hand as well; the rest of the options are under Configuration.

4. Check

Type /reins in a conversation: the usage text lists all commands. Typing /reins also shows them in DSH's command menu. Reins only governs the Attempts it starts; your own conversations with an Agent are not affected.

Update, roll back, uninstall

  • Update: prepare a new snapshot directory and run dsh plugin --profile web add file:<new directory> again, or add it again on the Plugins page.
  • Roll back: before installing, back up package.json, pnpm-lock.yaml and cordis.patch.yml under <DSH_HOME>/profiles/web; to roll back, copy them back and run dsh plugin --profile web install.
  • Stop / uninstall: switch it off on the Plugins page to stop Reins (database and settings are kept); Uninstall removes the bundle.
  • From before 0.3.0: older versions needed a hand-written - insert: - id: reins ... in cordis.patch.yml. The bundle now declares that entry itself; change the old insert block into a settings override (- id: reins with config:), or reins is loaded twice.
  • From 0.3.x: every /reins <subcommand> is now its own command (/reins todo → /reins-todo, /reins dag <id> → /reins-status <id>, …). The old forms still work and print the new name; /reins followed by anything else is now a plain-words request.

Quick start

Say what you want

/reins the login endpoint crashes with a null pointer, fix it
/reins add CSV export to the report page, keep the current JSON export

The conversation's model plans it with you as described in How it works. It works in any conversation, including as the first message of a new one. If the project is not the conversation's directory, name the directory in the request.

One sentence, your own check

When you already know the command that proves the work is done, skip the planning:

/reins-goal fix the clamp edge cases
/reins-goal make lint pass --test "npm run lint" --workspace D:/work/app
/reins-goal fix clamp --dry-run          # preview only
/reins-goal fix clamp --auto             # continue on its own after events / retries (also needs unattendedEnabled)

Without --test, Reins detects the test command (package.json test script, Node test files, Cargo, Go, pytest) and tells you to pass --test if it finds none.

Then two commands are enough

/reins-todo                 # everything waiting for you: approvals, held Tasks (with the last error), Tasks waiting for a tick
/reins-approve 3f9c1a2b     # approve with the short id shown by /reins-todo

After an approval, the Task continues in its previous session (the Agent remembers where it was). You do not need /reins-tick. Reading and editing files is trusted by default; running commands (pwsh / bash), network access and subagents still need approval (see trustPreset under Configuration).

In DSH Web

  • Reins sessions are in the sidebar: the Agent conversation of each Task appears under "未分组" (Ungrouped), named after the Task. Open it to see what the Agent did.
  • Approve either way: a session that needs approval is marked "待审批" (awaiting approval), and you can click "允许一次 / 拒绝" (allow once / deny) there. If you do not, after interactiveApprovalTimeoutMs (5 minutes by default) the Agent is released and the request moves to /reins-todo with a short id. DSH's own approvals (for example pwsh asking to widen the sandbox) follow the same rule.
  • Reins tells you: when something needs you (an approval, a held Task, a finished or failed Objective), Windows shows a notification, and the next time you talk to any DSH conversation the Agent mentions it briefly, with the command to run.
  • After DSH was force-stopped: if nothing was running, Reins takes over on restart by itself. If an Objective had an Attempt running, Reins cannot prove it stopped, so it holds only that Objective (no takeover, no changes) and runs everything else. /reins-todo, the reminder and the notification all point to it. Once you are sure the old DSH is gone, run /reins-recover <id> --confirm: the unfinished Attempt is recorded as interrupted, side effects with an unknown result wait for you, and the Objective continues.

Several Tasks by hand: get a PR mergeable

For full control over Tasks, dependencies and criteria, write the Task graph yourself with /reins-objective: implement, test, then wait for CI.

/reins-objective {"id":"pr-7","summary":"Get PR #7 mergeable","workspace":"D:/work/app","tasks":[
  {"id":"fix","title":"Implement the fix","criteria":[{"kind":"file_contains","spec":{"path":"src/fix.js","substring":"FIXED"}}]},
  {"id":"tests","title":"Run the tests","dependsOn":["fix"],"criteria":[{"kind":"reins.command_succeeds","spec":{"argv":["node","--test"],"timeoutMs":300000}}]},
  {"id":"ci","title":"Wait for CI","dependsOn":["tests"],"criteria":[{"kind":"reins.wait_satisfied","spec":{"waitKind":"ci","eventType":"ci.passed"}}]}
]}

What happens next:

  1. Reins starts an Attempt for fix. The Agent gets a structured handoff (goal, current Task, criteria, last failure, budget, …) and calls task_complete when done.
  2. The acceptance gate checks the criteria; only a pass completes fix, which makes tests ready. For tests, Reins runs node --test itself and looks only at the exit code; no test report written by the Agent counts.
  3. In ci, the Agent pushes and calls reins_wait (kind: "ci"). The Attempt ends, the Agent stops, and a watcher starts polling.
  4. Pushing is sensitive: with no one there it is denied and parked. /reins-todo shows the request, /reins-approve <short id> approves it, and the Task continues in its previous session.
  5. If CI fails, a new Attempt continues with a compact failure context (failed checks, failure fingerprint); once CI passes, the Task is accepted.

See everything at any time:

/reins-status pr-7

[!IMPORTANT] Unattended runs are off by default. Attempts started by an event, a timer, an automatic retry or "the previous Task was accepted" are unattended; they do not start on their own, /reins-todo lists them and /reins-tick <objectiveId> runs them. Approvals you gave are not in that group: an approval authorizes the call and the Task continues by itself. To let Reins continue on its own all the way, set both the configuration unattendedEnabled: true and the Objective field "unattendedOptIn": true (--auto for /reins-goal; say so in a /reins request).

Commands

Commands

Every action is its own top-level command, so DSH's command menu lists and completes it. approve, deny and resolve accept the short id shown by /reins-todo (a unique prefix of at least 4 characters; an ambiguous prefix is refused).

CommandWhat it does
/reins <what you want>Plain-words request: this conversation's model plans it with you and creates the Objective. Without text: usage
/reins-goal <sentence> [--test "<cmd>"] [--workspace <dir>] [--id <id>] [--auto] [--dry-run]One-Task Objective that is done when the test command exits 0
/reins-todoEverything waiting for you: approvals (with short ids), approvals waiting in a DSH conversation, side effects with an unknown result, held Tasks and their last error, Tasks waiting for a tick, Objectives held after a forced stop
/reins-status [objectiveId]Without an id: all Objectives, unfinished first. With an id: Objective, Task DAG, current Attempts, acceptance, waits, approvals, watchers, budget, lease, recent events
/reins-approve <id> [reason]Approve a durable approval request
/reins-deny <id> [reason]Deny it; the Agent is told why
/reins-pause <objectiveId>Pause; running Attempts stop, state is kept
/reins-resume <objectiveId>Resume a paused Objective; also lifts held Tasks inside an active one (no progress, approval loop, wait timeout) and restarts no-progress counting
/reins-cancel <objectiveId>Cancel; unused grants are revoked first
/reins-tick [objectiveId]Run scheduling now (counts as attended)
/reins-recover [objectiveId] [--confirm]After a forced stop of DSH: list Objectives held by the old process; --confirm releases them once the old process is gone (also works when Reins could not start)
/reins-objective <json>Create an Objective from a hand-written Task graph (fields below)
/reins-replan <objectiveId> <json>Replan at a safe point: {"add":[…],"remove":[…],"modify":[…],"reopen":[…],"reason":"…"}
/reins-event <json>Deliver an external durable event
/reins-resolve <id> done|not_doneSay whether a side effect with an unknown result happened
/reins-merge <objectiveId> <taskId>
Objective and Task fields
FieldMeaning
idObjective id (optional, random by default)
summaryWhat the Objective is about
workspaceThe Objective's directory (absolute, must exist). Agents work there, and file criteria and acceptance commands run there. Default: evidenceRoot / repoRoot
tasks[]Tasks, at least one
tasks[].id / title / descriptionTask id, title and instructions
tasks[].dependsOnIds of Tasks that must be accepted first (no cycles)
tasks[].requiredWhether the Objective needs this Task, default true
tasks[].criteria[]Acceptance criteria: {"kind","spec","required"}
tasks[].capabilityRouting, see below
tasks[].maxAttempts / maxWallTimeTask budget
maxAttempts / maxWallTimeObjective budget; maxWallTime defaults to 7 days and includes waiting
maxActiveMsLimit on actual running time, excluding waiting
maxParallelParallel Attempts of one Objective (above 1 needs worktree isolation)
noProgressLimitNo-progress threshold (default: noProgressAttemptLimit)
unattendedOptInWhether it may continue unattended
Routing: capability
FieldMeaning
routesession (default, normal Agent + Goal), subagent (in-process child Agent), fork (forked from the previous Attempt's session)
readOnlyDefault true for subagent / fork: sensitive tools are always denied
isolationnone or worktree; a subagent that writes code must use worktree
providerSubagent provider (default spawn, fork for forks)
model / modelProviderModel and model provider
tools.allow / tools.denyLimit visible tools. Visible is not allowed: sensitive calls still need approval
maxGoalRoundsGoal rounds per Attempt, default 3
Acceptance criteria
kindspecPasses when
file_exists / file_absent{"path"}the file exists / does not exist
file_contains{"path","substring"}the file contains the text
file_sha256_equals{"path","sha256"}the file has this hash
json_field_equals{"path","pointer","expected"}the JSON field equals the value; pointer is a dotted path (a.b)
marker_count_equals{"path","marker","count"}the marker occurs that many times
reins.wait_satisfied{"waitKind","eventType"}the Task's last wait was satisfied by a durable event of that type, and the current Attempt is newer than the event
reins.output_contains{"substring"}the subagent's output contains the text
reins.no_ambiguous_side_effects{}the Task has no side effect with an unknown result
reins.command_succeeds{"argv","cwd","timeoutMs","expectExitCode","pins","env"}Reins runs the command itself at acceptance and the exit code equals expectExitCode (default 0)

File paths are relative to the Attempt's directory (the Objective's workspace, evidenceRoot or the worktree); absolute paths and .. are refused.

[!WARNING] File criteria check files in the working directory, and the Agent can write those files too. In a real-model test, after a failing test run the model rewrote test-report.json to {"passed":true}, and json_field_equals passed. For "tests pass" or "the build succeeds", use reins.command_succeeds, never a report file.

Rules of reins.command_succeeds:

Agent tools

ToolUsed byWhat it does
reins_create_objectivethe conversation where you typed /reinsCreates the planned Objective. Works once per /reins in that conversation, never in Reins' own sessions; validates Tasks, order, check commands, and pins checkFiles. dryRun shows the plan without creating it
task_completeReins AgentsClaims the Task is done; Reins pre-checks, the acceptance gate decides
reins_waitReins AgentsEnds the current Attempt and waits durably; a new Attempt continues when the event arrives

reins_wait kinds:

kindArgumentsResumes on
cirepo (owner/name), sha, optional requiredChecksci.passed / ci.failed
pr_reviewrepo, numberreview.approved / review.changes_requested / review.commented / pr.merged / pr.closed
processexitFile or pid, optional nameprocess.succeeded / process.failed / process.lost
remoteurl, optional name (host must be in remoteWatcherHosts)remote.succeeded / remote.failed / remote.cancelled
timerdelayMstimer.fired
external_eventsubject, eventTypesevents delivered with /reins-event

Every wait takes a timeoutMs (default 24 hours); after it, the Task is held for you instead of being retried blindly.

External event example (subject carries the ext: prefix and matches the subject of reins_wait):

/reins-event {"source":"deployer","sourceEventId":"deploy-42","type":"deploy.done","subject":"ext:deploy-42","objective":"pr-7","payload":{"env":"staging"}}

source + sourceEventId is the event's identity: a repeated delivery is suppressed, and the same identity with different content is flagged as a conflict instead of overwriting the original.

Single-Task commands (Phase 2/3, for scripts)

These are reachable as /reins <subcommand> only: create <summary> | <task title>, criteria-add <objectiveId> <taskId> <kind> <json-spec>, criteria-list <objectiveId> <taskId> [revision], criteria-revise <objectiveId> <taskId>, accept <objectiveId> <taskId> [attemptId], receipts <objectiveId> <taskId>. /reins-status, -pause, -resume and -cancel work for these Objectives too. For new work use /reins or /reins-goal.

Configuration

Configuration is validated strictly: unknown keys, invalid numbers, cloud URLs and UNC network paths are refused.

KeyDefaultMeaning
databasePath~/.dsh/dsh-reins/reins.sqliteLocal SQLite path (the directory is created if missing). One live Reins process per database
evidenceRootnullDefault directory for Objectives without a workspace; with neither this nor repoRoot, orchestrated Objectives must bring their own workspace
approvalRequiredTools[]Tools that always need approval
trustPresetworkspaceBuilt-in trusted set. workspace: read, glob, grep, write, edit, str_replace_editor, todo_write, get_goal, update_goal and Reins' task_complete, reins_wait; commands, network, subagents and unknown tools still need approval. none: only trustedTools
trustedTools[]Tools trusted in addition to the preset (for example ["pwsh"])
trustUnlistedToolsfalseWhether unlisted tools are trusted. Not by default: an unknown side effect needs approval
unattendedEnabledfalseAllow unattended runs (the Objective must also have unattendedOptIn)
defaultMaxAttempts5Default maximum Attempts per Task
defaultMaxWallTimeMs300000Default wall-clock budget of a single-Task Objective
orchestratedDefaultWallTimeMs7 daysDefault wall-clock budget of an orchestrated Objective (including waits)
noProgressAttemptLimit3No-progress threshold
maxConcurrentAttempts

Budgets: maxWallTime is wall-clock time, including waits for CI and approvals; maxActiveMs counts only the time Attempts actually run; maxGoalRounds bounds each Attempt. There is no reliable token telemetry, so there is no token or cost budget.

Architecture

Reins architecture

Reins is a Cordis plugin that uses only the public DeepSeek Harness API and never changes the Harness core:

  • Commands and planning (src/commands/): the /reins and /reins-* commands; /reins <request> hands the request to the conversation's model with agent.followup, and reins_create_objective turns its plan into an Objective.
  • Orchestrator (src/orchestrator/): schedules ready Tasks, keeps the DAG and graph revisions, durable waits and events, watchers, approvals, worktrees, routing, failure fingerprints and handoffs.
  • Runtime (src/orchestration/runtime.js): atomic admission, lease fencing, outer settle (disarm → cancel → idle → flush → final receipt), tool and step guards. Inside an Attempt, only the Harness goal-round driver continues the work.
  • Acceptance gate (src/acceptance/): the only path to completed; database triggers make completion without a pass receipt impossible.
  • Storage (src/store/ + migrations/): SQLite (node:sqlite), migrations 001–015, append-only audit, key invariants enforced by triggers.

How a resume happens

An approval, from park to acceptance

CI, timers, PR reviews and external events all take the same path: wait → durable event → idempotent consume → new Attempt.

Security model

Every capability of Reins obeys these invariants; the tests and the real-Harness verification are built around them:

  • Harness executes, Reins orchestrates. Public API only, no private imports, no changes to the Harness core.
  • Only the goal-round driver continues work inside an Attempt; one Objective has exactly one valid writer (lease + epoch fencing).
  • A finished Attempt never comes back to life; a parked Attempt always resumes as a new Attempt.
  • A sensitive call without approval is denied, and the denial must still be followed by park / cancel and a proof of quiescence.
  • Approval is not acceptance, and a finished Goal is not a finished Task. Approval cannot bypass the sandbox, guards, leases, budgets or the acceptance gate.
  • A wait keeps no Agent loop.
  • A side effect with an unknown result is never replayed automatically; a consumed grant is never restored, even if the tool failed or the process crashed.
  • SQLite and the Harness session log are separate consistency domains: quiet only with a flush proof; after a restart nothing uncertain is treated as success.
  • Taking over after a crash needs an exit proof bound to owner / Objective / epoch / execution; without it, that Objective is held (LEASE_BUSY) and never touched.
  • One live Reins process per database: another live owner makes startup fail with DATABASE_IN_USE; a process whose database was taken over stops scheduling and polling at once.
  • "Tests pass" is verified by Reins itself: reins.command_succeeds runs the frozen command at acceptance; if a pinned file changed, it does not run at all.
  • A planned Objective comes only from you: reins_create_objective works only after you typed /reins in that conversation, once, never in Reins' own sessions, and check files the planner wrote are pinned before any Agent starts.
  • Conservative takeover after a forced stop: a lease is taken over automatically only when the old process is recorded on this host, is confirmed gone, and had nothing running; otherwise you confirm with /reins-recover --confirm, and that confirmation is append-only.
  • After an approval, the same session continues: the next Attempt reopens the parked Harness session (still a new Attempt with a new Goal; the grant still allows exactly that one call). After a failure, crash or replan, a new session is used. A Task parked for approval 10 times in a row is held for you to decide.
  • URLs chosen by an Agent only reach allowed hosts: waits check when registered and before every poll, refuse redirects and never carry credentials.

Tests and verification

npm ci                    # dependencies
npm run typecheck         # type check against the public Harness API
npm test                  # main regression suite (about 70 seconds)
npm run test:runner       # scenario driver and verifier regression (including verifier negatives)
npm run test:live         # real DeepSeek Harness scenarios (about 4 minutes)
npm run test:live:phase3  # Phase 3 single-Task real Harness scenarios (about 2 minutes)
node scripts/build-diagrams.mjs   # rebuild the bilingual README diagrams

Current results:

SuiteResult
npm test499 / 499
npm run test:runner48 / 48 (including 28 Phase 4 verifier negatives)
npm run test:live7 / 7
npm run test:live:phase311 / 11 gates
npm run typecheckpasses

Real Harness scenarios (npm run test:live)

Each case starts a real dsh --profile process in an isolated DSH_HOME: real Cordis, Agent, agent loop, goal-round driver, session persistence, tool pipeline and headless approval; only the model is a deterministic fixture. User actions go through the really registered /reins-* commands; GitHub is a local stand-in that keeps its state across process restarts.

CaseWhat it proves
e2e"Get a PR mergeable" with five Tasks: no approver → park → approve → a new Attempt pushes exactly once; CI fails → fix → approved push again → CI passes; review handled; Objective completes after every acceptance
crash-runningAttempt killed with SIGKILL while running, restarted with an exit proof: reconciled as interrupted, retried, completed
crash-consumedKilled after the grant was consumed and the push happened but before the result was recorded: the side effect is marked ambiguous, not replayed, completed after you confirm
crash-awaiting-ciKilled while waiting for CI: the watcher resumes polling and drives the next Attempts to completion
no-proofKilled without an exit proof: that Objective is held (LEASE_BUSY), untouched, while Reins runs
second-processA second process on the same database while the first runs e2e: it refuses to start with DATABASE_IN_USE and runs nothing; the first completes normally
subagentReal subagent and session fork: sensitive calls from a read-only child are recognized and denied with zero physical side effects; the child session's parentSession is the Reins anchor session; a fork retry really derives from the previous session

The independent verifier scripts/phase4-harness-verify.mjs reads only SQLite (opened read-only), the physical side-effect log, the supervisor records and the real session logs, with 6–59 checks per case, and does not trust the scenario plugin's own conclusions. tests/runner/phase4-verifier-negative.test.js tampers with a real run snapshot one fact at a time to prove the verifier fails.

[!NOTE] The scenarios above use a deterministic model and a local GitHub stand-in. With a real model (DeepSeek), these were verified separately in DSH Web: /reins planning (look first, ask about a real choice, write and pin the check, create; then the Reins Agent did the work and the pinned check passed); /reins-goal; normal fixes, correcting after a denial, approvals, an impossible task, the default tool policy, a forged test report, and reins.command_succeeds acceptance (with a forged report present, Reins ran the tests itself, got exit 1, and the Task did not complete).

Project layout

reins/
├── src/
│   ├── plugin.js              # plugin entry (Cordis apply)
│   ├── config.js              # configuration schema and strict validation
│   ├── live-config.js         # settings saved on the Plugins page apply without a reload
│   ├── commands/              # /reins and /reins-* commands, /reins planning (plan.js)
│   ├── orchestrator/          # DAG, waits/events, watchers, approvals, worktrees, routing, fingerprints, handoffs
│   ├── orchestration/         # runtime: admission, budgets, no-progress, outer settle
│   ├── acceptance/            # acceptance gate, frozen criteria, validators, receipt integrity
│   ├── approval/              # relational approvals (Phase 2)
│   ├── store/                 # SQLite store, transactions, migrations, instance lock
│   ├── reconcile/             # startup reconciliation
│   ├── harness/               # public Harness API adapter
│   └── tools/                 # task_complete tool
├── client/client.js           # settings page on DSH Web's Plugins page
├── migrations/                # 001–015, only ever added to
├── scripts/                   # real Harness scenario drivers, independent verifiers, diagram builder
├── tests/                     # regression tests grouped by feature (see tests/README.md)
├── docs/assets/               # README images (English and Chinese)
└── smoke/public-api.ts        # public API type-check sample

Development

Rules

  1. For a feature or a fix, first write a test that reproduces the problem, then change the code.
  2. Never delete or loosen a safety assertion to make a test pass. Identity binding, lease fencing, and default-deny for approvals and acceptance stay.
  3. Task and Objective completion goes through the acceptance gate, never through a model's "done" or a direct database edit.
  4. Never commit API keys, real user configuration, real databases, logs or run evidence.
  5. After every change run typecheck, test and test:runner; for framework lifecycle, recovery or tool calls also test:live.

Conventions

  • Schema changes only add migrations; 001–015 are never rewritten.
  • A new user action is a new top-level /reins-<action> command (a row in COMMANDS in src/commands/register.js); the real-Cordis unload test pins the exact command set. listValidatorKinds() stays at the 6 file validators; new acceptance kinds go into the separate reins.* registry.
  • Temporary test files go through tests/fixtures/scratch.js; never hard-code local paths.
  • Text files use LF (enforced by .gitattributes).
  • The English and Chinese diagrams are built from one description by scripts/build-diagrams.mjs.

What gets published

package.json files contains the plugin only (src, migrations, client, locale, the bundle patch, icon, license and README); tests, scripts and dev dependencies are not published.

Known limitations

  • File criteria trust files in the working directory, which the Agent can write; for "tests / build pass" use reins.command_succeeds.
  • reins.command_succeeds runs code from the working directory; any file not pinned may have been changed by the Agent. It does not run in a sandbox.
  • /reins planning depends on the judgement of the conversation's model: it may decide something you would have liked to be asked about, or pick a check that is weaker than you want. Read its summary; /reins-status <id> shows the exact check of every Task. /reins-goal does not pin test files; for a stronger guarantee use /reins (which pins checks it wrote) or /reins-objective with pins.
  • With a real model, /reins planning, /reins-goal and single-Task scenarios are verified; CI / PR watchers, crash recovery, parallel worktrees, subagent / fork and replanning were verified in the real Harness with a deterministic model only.
  • Tested on Windows only; Linux and macOS are unverified.
  • Desktop notifications are built in on Windows only; elsewhere configure notifyCommand.
  • DSH's sandbox blocks commands that start child processes, such as node --test, so an Agent may ask to widen the sandbox; acceptance is not affected, because Reins runs the tests itself outside the sandbox.
  • Single-Task Objectives (/reins create) run one at a time and, without evidenceRoot, work in the DSH process's start directory; orchestrated Objectives run in parallel execution slots.

License

MIT.

💥Crash recoveryLeases and epoch fencing; taking over needs an exit proof bound to owner / Objective / epoch / execution; one live Reins process per database
Merge an accepted Task's worktree into the current branch
  • argv is an argument array and never goes through a shell; when argv[0] is node, the Node that runs the Harness is used. On Windows .cmd / .bat cannot be run directly; write ["node", "<script>"]. (/reins and /reins-goal wrap a command line you give them in cmd /d /s /c or sh -c for you.)
  • cwd is a relative path inside the working directory (default .); timeoutMs defaults to 10 minutes, at most 1 hour; on timeout the whole process tree is killed and the criterion fails.
  • The child gets a minimal environment (PATH, system and temp directories, …) plus the values declared in env; nothing else is inherited, and there is no stdin.
  • The command runs code from the working directory, which the Agent may have changed. pins ([{"path","sha256"}]) fix test files: if a hash differs, the criterion fails and the command never runs. /reins pins the check files its planner wrote.
  • task_complete runs it once as a pre-check and shows the Agent the end of a failing output; the gate runs it again for the final verdict.
  • 1
    Global limit on concurrent Attempts (max 16; above 1 needs worktree isolation)
    repoRoot / worktreeBaseDirnullgit repository root and worktree directory; parallel worktrees need repoRoot
    approvalRequestTtlMs24 hoursHow long an approval request stays open
    allowanceTtlMs15 minutesHow long a one-shot grant stays valid after approval
    subagentWallTimeMs600000Time limit of one subagent Attempt
    watcherCredentials{}Credential reference → environment variable name, for example {"github": "GITHUB_TOKEN"}. Variable names only, never secrets
    githubApiBasehttps://api.github.comGitHub API (can point to GitHub Enterprise)
    notifyDesktoptrueDesktop notification when Reins needs you (built in on Windows; elsewhere set notifyCommand)
    notifyInConversationtrueShort reminder from the Agent the next time you talk to DSH
    notifyCommand[]Your own notification command (argument array); receives REINS_TITLE / REINS_BODY as environment variables
    interactiveApprovalTimeoutMs5 minutesHow long an approval waits in a DSH conversation before the Agent is released and it becomes a /reins-approve request (0 waits indefinitely)
    minTimerWaitMs60 secondsShortest timer an Agent may wait for with reins_wait; shorter ones are refused and the Agent keeps working
    remoteWatcherHosts[]Hosts ("host" or "host:port") that remote waits may poll; empty disables remote waits
    orchestratorTickMs / watcherPollMs / watcherTimeoutMs2000 / 1000 / 15000Scheduling interval, polling interval, single query timeout
    leaseDurationMs / heartbeatIntervalMs10000 / 3000Lease duration and heartbeat (at least 3 renewals per lease period)
    remote
    remoteWatcherHosts