返回插件市场

dsh-maestro-memory

Agent 与工作流

ddtcorex/dsh-maestro-memory

DSH 插件,提供持久的跨会话记忆和待办事项,支持五个轨道(全局/用户/项目/关键/每日)、确认门控写入、Git 备份同步,并原地采用 ~/.dsh/memories。

  • ai-agents
  • cordis
  • deepseek-harness
  • dsh
  • dsh-plugin
  • memory
  • todos
GitHub Stars
1GitHub
浏览量
5DSH Plugin Hub
Forks
0GitHub
开放问题
0GitHub Issues
Manifest 版本
1.0.1@ddtcorex/dsh-maestro-memory
最近推送
2026年10月9日GitHub
许可证
MITTypeScript
插件类型
Host + Client同时运行于 Host 与 Web Client

验证与兼容性

这里展示目录实际采集到的证据;未声明的信息会明确标为未知。

静态检查通过
01精确来源: github · @ddtcorex/dsh-maestro-memory@1.0.102验证时间: 2026年8月26日03验证版本: 0.1.0-rc.7
当前版本兼容性
已在当前目录版本验证
声明的 Harness 范围
未声明
声明的平台
未声明
适用 Profile
web
构建授权
未知
权限声明
未声明
外部服务
未声明
遥测声明
未知
未发现已知风险标记

这不是安全背书;安装前仍应查看源码、权限和配置。

查看证据与判定范围

验证仅覆盖标出的来源、版本和 Harness 环境,不代表未来版本仍然兼容。

  • github:ddtcorex/dsh-maestro-memory#860d8fae76630fde19ebef068eb5cc8a7dbd28c0
  • 插件通过清单与静态结构检查,尚未完成运行时加载检查。

README

查看源文件

dsh-maestro-memory

Durable memory and todos for DeepSeek Harness (DSH) — preserves ~/.dsh/memories in place.

Give the AI cross-session durable memory and todos — the more you use it, the more it understands you.

  • Package: @ddtcorex/dsh-maestro-memory (cordis.patch.yml id maestro-memory)
  • Version: see package.json · Changelog: CHANGELOG.md

Requirements

  • Node.js ^22.19.0 || >=24.0.0, pnpm 11+ (packageManager in package.json)
  • A DSH release inside the @deepseek-ai/dsh-client-* peer range declared in package.json

Install

pnpm install
pnpm run build   # -> lib/
pnpm test        # vitest run

DSH profile (operator):

dsh plugin --profile web add link:<workspace-root>/packages/dsh-maestro-memory
# production: dsh plugin --profile web add github:ddtcorex/dsh-maestro-memory#<tag-or-sha>

cordis.patch.yml is shipped with the package, including a connection entry that declares webServer (DSH 0.2.x needs it before rpc.handle can register a channel). Do not duplicate it in the profile. Pin a release with @ddtcorex/dsh-maestro-memory@<version> when installing from npm, and run pnpm install && pnpm build after every git pull of a link: checkout.

- insert:
    - id: maestro-memory
      name: '@ddtcorex/dsh-maestro-memory'
      config:
        memoryDir: null      # -> ~/.dsh/memories
        snapshotOrder: 500
        autoMemory: { enabled: false, userMessage: true, desensitize: true } # opt-in
        writeGuard: { enabled: false, threshold: 2 }  # per-turn write watchdog, opt-in

writeGuard is read once at apply() time — changing it needs a profile edit and a host restart. threshold counts consecutive working human turns with no daily/project write; any value below 1 is read as 1.

Tools

ToolPurpose
memoryFive tracks memory/user/project/key/daily + archive/expand. key is gated via memory_suggest.
maestro_todoDurable cross-session todo store (four tracks life/work/project/daily with ids, smart view max 8). Named apart from the harness's own in-session task list todo_write.
memory_suggestGated proposals to SUGGESTIONS.jsonl — requires human approve.

memory sanitizes sensitive fragments ([Filtered:API key/password/token/ID/phone], pure credential → content filtered).

System Prompt Snapshot

memory:snapshot (order 500) injects bounded deterministic context:

USER + MEMORY + KEY (branch-filtered) + Project Context (auto-recall top-4, 600 chars each, cap 1024) + Recent Daily (last 2 days, 512) + header + discipline note

Caps: memory 2048 / user 4096 / key 6144 / recentDaily 512 / autoRecall 1024, plus per-section entry budgets memory 8 / user 8 / key 12 / recentDaily 2 / autoRecall 4.

A cap is hard in both dimensions. The newest entry is always kept — compacted to head + [summary:…] when it carries a summary tag. An untagged entry larger than twice its byte cap is truncated with an explicit …[truncated] marker instead of being kept whole: before that rule, a single 2,293-byte global entry owned the 2,048-byte section and pushed every other entry out of the prompt.

Cost reporting. renderSnapshotWithStats (the renderer behind memory:snapshot) reports the bytes, entry count and excluded-entry count of every section. The host keeps the last 50 renders in memory and returns them as cost on /dsh-maestro-memory-health: samples, last, medianTotalBytes, maxTotalBytes, medianBySection. Entry text is never retained — byte counts only.

Write watchdog. With writeGuard.enabled, the host counts consecutive human turns in which work happened but no daily/project entry was written (agent/turn-stopping). Three things must hold for a turn to count:

  1. it was opened by a direct human prompt — goal-continuation rounds (source.kind === 'goal') and injected context ('plugin', e.g. wake notices) carry no per-turn duty;
  2. it is not a subagent session;
  3. it dispatched at least one tool call. A turn that only answered a question is conversation, not work, so no debt accrues — otherwise the watchdog would push the model to write filler entries, exactly what the discipline note forbids.

Once the gap reaches threshold, the snapshot gains a # ⚠️ Memory Write Backlog section immediately before the discipline note, and it stays until a write succeeds. Only a write that actually recorded something counts — a deduplicated add does not. The alert text is static (threshold only, never the live count), so one open gap costs at most two tail snapshots: appear, then disappear.

Subagent sessions (session.header.origin === 'subagent') get a restrained per-achievement cadence instead of the per-turn duty, and never see the backlog alert. The shared memory context (MEMORY / USER / KEY / Project Context) is still injected for them.

The rendered snapshot collapses brace runs of two or more to a single brace: DSH interpolates each prompt context and fails the whole turn on a {{name}} group with a malformed or unregistered name, so free-form memory prose never reaches it as template syntax.

UI & RPC

One conversation.view slot (maestro-memory, order 40) with tabs Memory / Queue / Todo / Skills / Health. Health shows coverage, daily last 7d, longest + 5-dim score S/R/J/C/Safety (composite min*0.4+mean*0.6).

The Memory tab lists each track read-only and carries a manual add composer: pick a track, type an entry, press Add. It posts memory.mutate with action: 'add', so it needs no model round-trip; drafts are kept per track and the button stays disabled while the entry is empty or while key/project has no cwd. The model's key gate is exec.agent-scoped on the host, so it stays in force — a human writing key here is equivalent to approving a queued suggestion.

RPC: /dsh-maestro-memory + loopback /dsh-maestro-memory-health + /dsh-maestro-memory-propose.

Maintenance endpoints on /dsh-maestro-memory (both preview-first: dryRun defaults to true and an actual write needs confirm: true):

EndpointWhat it does
memory.repairSplits entries glued without the § delimiter, drops exact duplicates and moves a trailing [summary:…] to its canonical header position, across every store file. Reports files / changed / split / deduped / relocated.
memory.maintenancePlans (and optionally applies) the archive of the oldest entries of memory/user/key/project beyond DEFAULT_ARCHIVE_POLICY (keep-bytes + max-age). Overgrown entries move to the track's *-archive.md; they are never dropped.

Archive vs. the two-machine sync. sync/ merges MEMORY.md, KEY.md and KEY-archive.md as a union — it never drops a version, and project/global entries carry no [id:…], so a deletion on one machine is indistinguishable from "the other machine has not seen it yet". Consequences worth knowing before archiving:

  • Archiving on ONE machine only is not stable: the next union merge pulls the archived entries back into the live file, because the peer still carries them there. Archive on every machine (same policy) so both sides agree and the union is a no-op, or archive with sync disabled.
  • MEMORY-archive.md is not in the merge set (only KEY-archive.md is), so a project-track archive stays local. That is safe for the live file but means the two machines' archive files can legitimately differ.
  • The archive does not change what the prompt shows: # Project Key Memory is capped at 6,144 B and # Project Context at the newest 4 entries, both far below the archive policy's keep budget. Verified on the live store: rendering was byte-identical before and after the run.

One repair pass runs once at boot, gated by a flag file under <root>/.maestro-memory/ (maestroMetaDir): delimiter-repaired-v3 covers every store file and writes its run report into the flag. (v1 was a KEY-only pass that had been a silent no-op — it was called with a bogus cwd — and v2 covered the store without the stray-delimiter split; the versioned flag is what lets an existing machine pick up a new repair rule exactly once.)

Maintenance

Maintenance runs through the memory.repair and memory.maintenance RPC endpoints described under UI & RPC above (preview-first, confirm: true to write). There are no standalone maintenance scripts; scripts/ only holds the build helper.

评论

0
最新优先