huxin7735-collab/dsh-maintainer-doc-guard ↗★ 0

dsh-maintainer-doc-guard

Keeps a long agent turn answerable to the user's actual request: a standing maintainer-document reminder, two pre-execute gates (read a same-basename precedent before editing infrastructure; say what a side-effecting step is for), an objective anchor that quotes the user's latest instruction plus an explicit precedence rule, and a nudge stage that corrects before it blocks. Details: (1) A standing system-prompt section that tells the model to read the workspace maintainer documents (plan.md / conventions.md / stack.md / state.md / maintainer/README.md) before every operation, so small-model context compaction cannot erase long-term project memory. (2) A `tools/pre-execute` precedent gate that denies a write/edit inside a guarded infrastructure area until a working same-basename precedent has been read. (3) A `tools/pre-execute` intent gate that polices the turn's side-effecting calls when the model never said what the step is for. (4) An OBJECTIVE ANCHOR: the user's latest instruction, quoted verbatim in a second prompt section with an explicit precedence rule (user's latest instruction > your own last stated plan > a lead you found yourself), so a long turn cannot silently redefine its own task. (5) A NUDGE stage that corrects before it blocks — the first unexplained action only injects a reminder the model reads at its next step, a drift reminder fires once per long turn, and only a repeated offence is denied. Plus a right-sidebar tab that views and edits those documents, and ten runtime knobs exposed in the harness settings page (设置 → 插件 → 插件配置). 适合需要防止智能体在长对话中偏离用户实际需求的用户。

Package
dsh-maintainer-doc-guard
Compatibility
Unverified
Version
0.5.1
License
MIT
Last updated
Sep 20, 2026

Install

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:huxin7735-collab/dsh-maintainer-doc-guard

Configuration

Row config (all optional):

keydefaultmeaning
enabledtrueturn the section off without removing the row
docs["plan.md","conventions.md","stack.md","state.md","maintainer/README.md"]document names to probe
onlyWhenPresentfalsewhen true, stay silent unless at least one document exists
inSubagentsfalsealso inject the document reminder into delegated children (true opts in)
order100section sort order (after the persona prefix at 0)
walkUp6ancestor levels to walk looking for the project root
projectMarkers[".git"]root markers for the walk-up
title / introbuilt-inoverride the reminder's heading / body text

Gate config lives under gate: and is also all optional:

keydefaultmeaning
gate.enabledtruemount the tools/pre-execute guard at all
gate.dryRunfalseobserve only: count what it would deny, never block
gate.tools["write","edit"]tool names the gate examines
gate.guardedGlobs[".dsh/profiles/", ".dsh/skills/", ".dsh/.agent-presets/", "node_modules/@deepseek-ai/"]POSIX substrings of the resolved target path that make it guarded
gate.exemptGlobs[]POSIX substrings that exempt a target even if guarded
gate.maxDeniesPerTarget2denials for one target before the gate gives up and lets it through
gate.maxCandidates3precedents listed in one denial
gate.scanLevels4ancestor levels scanned for sibling precedents
gate.entriesPerLevel400directory entries examined per level (caps node_modules scans)

Example — observe before enforcing:

- id: maintainer-doc-guard
  config:
    gate:
      dryRun: true

The gate is off for anything outside guardedGlobs, so ordinary project files (plan.md, source, notes, scratch scripts) are never touched by it.

Each document is probed in the session working directory first, then in the project root, so a document kept at the repo root is found even from a nested cwd.

Everything this plugin copies from outside itself — the quoted user instruction, document names, title / intro overrides — is defused for the harness's {{variable}} interpolation before it reaches the prompt (the two-character opener and closer are split apart), because rendering throws on an unregistered reference. A user who types {{x}} therefore cannot break prompt assembly for the rest of the session.

Anchor config lives under anchor: and is also all optional:

keydefaultmeaning
anchor.enabledtruerender the standing objective section at all
anchor.inSubagentsfalsealso render inside delegated children, quoting the child's own delegation under child-specific wording (true opts in)
anchor.order10150section sort order — late on purpose, so the section that changes on every user message invalidates as little prefix as possible
anchor.maxChars800clip the quoted instruction, marking the cut with … (truncated)
anchor.title / anchor.introbuilt-inoverride the heading / the framing sentence
anchor.prioritiesthe three-step rulethe precedence list, rendered as a numbered list after the quote
anchor.childTitle / anchor.childIntro / anchor.childPrioritiesbuilt-inoverride all three for the child reading — each defaults to wording that says "your delegated task" rather than "the user's latest instruction"

Nudge config lives under nudge: and is also all optional:

keydefaultmeaning
nudge.enabledtruestage the intent judgement at all; false denies the first offence, as 0.4 did
nudge.dryRunfalseobserve only: count what it would inject, inject nothing
nudge.grace1unexplained actions allowed through with a reminder before any denial
nudge.maxPerTurn3reminders per turn before it stops injecting (the deny budget is separate)
nudge.afterSteps12step count that triggers the once-per-turn drift check; 0 disables it