DeepSeek Harness 插件:用 Git 支撑长期记忆与进化。
46.8/100
综合分
43
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/9/18 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
自动兼容检查有告警:未发布到 npm registry,仅可从源码安装。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add Kytolly/dsh-evolve-in-git该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:已验证
是什么
dsh 原生插件 · chat
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 62 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查⚠ 装前注意未发布到 npm registry,仅可从源码安装
展开查看检查明细 ↓
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✗npm 包dsh-evolve-in-git(未发布到 npm,仅可源码安装)
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明
验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/30 11:47:13
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 142 处,展示前 126 条)
- 读取本地文件lib/index.js:392
const raw = readFileSync(path, 'utf8'); - 发起网络请求lib/index.js:849
async fetch() { - 发起网络请求lib/index.js:850
this.core.fetch(); - 发起网络请求lib/types/index.d.ts:118
fetch(): Promise<void>; - 发起网络请求lib/client.js:675
const response = await fetch("/api/evolve-git/config"); - 发起网络请求lib/client.js:681
const response = await fetch("/api/evolve-git/config", { - 发起网络请求lib/client.js:704
const response = await fetch("/api/evolve-git/config"); - 发起网络请求lib/client.js:711
const response = await fetch("/api/evolve-git/config", { - 发起网络请求lib/types/core.d.ts:52
fetch(): void; - 发起网络请求lib/types/core.d.ts:100
fetch(): void; - 发起网络请求lib/core.js:169
fetch() { - 执行外部命令固定命令lib/git.js:41
const result = spawnSync('git', ['-C', repoPath, ...args], { encoding: 'utf8', env: { ...process.env, ...env } }); - 执行外部命令固定命令lib/git.js:52
const result = spawnSync('git', ['clone', '--branch', branch, '--single-branch', repoUrl, repoPath], { - 读取本地文件lib/git.js:66
if (!existsSync(join(resolved, '.git'))) { - 读取本地文件lib/git.js:112
if (existsSync(join(resolved, '.git'))) - 读取本地文件lib/git.js:114
if (existsSync(resolved) && readdirSync(resolved).length > 0) { - 读取本地文件lib/git.js:114
if (existsSync(resolved) && readdirSync(resolved).length > 0) { - 写入本地文件lib/git.js:117
mkdirSync(dirname(resolved), { recursive: true }); - 读取本地文件lib/git.js:171
head: existsSync(join(repoPath, '.git', 'HEAD')) ? currentHead(repoPath) : undefined, - 执行外部命令固定命令lib/git.js:199
const staged = spawnSync('git', ['-C', repoPath, 'diff', '--cached', '--quiet'], { encoding: 'utf8' }); - 写入本地文件lib/git.js:225
mkdirSync(dirname(filePath), { recursive: true }); - 写入本地文件lib/git.js:245
writeFileSync(filePath, body, 'utf8'); - 写入本地文件lib/git.js:270
mkdirSync(dirname(filePath), { recursive: true }); - 写入本地文件lib/git.js:272
writeFileSync(filePath, rendered.content, 'utf8'); - 读取本地文件lib/config.js:24
if (!existsSync(path)) - 读取本地文件lib/config.js:27
const raw = readFileSync(path, 'utf8'); - 写入本地文件lib/config.js:38
mkdirSync(dirname(path), { recursive: true }); - 写入本地文件lib/config.js:39
writeFileSync(path, JSON.stringify(config, null, 2) + '\n', 'utf8'); - 读取本地文件lib/skill.js:42
lstatSync(p); - 写入本地文件lib/skill.js:57
mkdirSync(dirname(link), { recursive: true }); - 删除本地文件递归lib/skill.js:60
rmSync(link, { recursive: true, force: true }); - 读取本地文件lib/skill.js:73
const st = lstatSync(link); - 删除本地文件递归lib/skill.js:82
rmSync(link, { recursive: true, force: true }); - 读取本地文件lib/skill.js:120
if (!existsSync(root)) - 读取本地文件lib/skill.js:123
for (const entry of readdirSync(root, { withFileTypes: true })) { - 读取本地文件lib/skill.js:127
if (!existsSync(skillPath)) - 读取本地文件lib/skill.js:129
const fm = parseFrontmatter(readFileSync(skillPath, 'utf8')); - 写入本地文件lib/skill.js:162
mkdirSync(join(repoPath, config.skillsRoot, to), { recursive: true }); - 写入本地文件lib/skill.js:221
mkdirSync(join(targetRoot, entry.name), { recursive: true }); - 写入本地文件lib/skill.js:222
writeFileSync(target, content, 'utf8'); - 写入本地文件lib/skill.js:226
writeFileSync(target, content, 'utf8'); - 读取本地文件lib/config-route.js:81
const exists = existsSync(path); - 读取本地文件lib/config-route.js:82
const raw = exists ? readFileSync(path, 'utf8') : ''; - 写入本地文件lib/config-route.js:108
mkdirSync(dirname(path), { recursive: true }); - 写入本地文件lib/config-route.js:109
writeFileSync(path, raw, 'utf8'); - 读取本地文件lib/memory.js:36
const raw = readFileSync(path, 'utf8'); - 读取本地文件lib/memory.js:58
if (!existsSync(dir)) - 读取本地文件lib/memory.js:60
for (const entry of readdirSync(dir, { withFileTypes: true })) { - 读取本地文件lib/memory.js:121
const raw = readFileSync(path, 'utf8'); - 读取本地文件lib/update.js:16
const raw = readFileSync(path, 'utf8'); - 读取本地文件lib/update.js:25
const raw = readFileSync(path, 'utf8'); - 写入本地文件lib/update.js:54
writeFileSync(path, '---\n' + lines.join('\n') + '\n---' + body, 'utf8'); - 读取本地文件lib/forget.js:21
if (!existsSync(dir)) - 读取本地文件lib/forget.js:23
for (const entry of readdirSync(dir, { withFileTypes: true })) { - 读取本地文件lib/forget.js:33
if (!existsSync(root)) - 读取本地文件lib/forget.js:38
const fm = parseFrontmatterFields(readFileSync(file, 'utf8')); - 写入本地文件lib/forget.js:68
mkdirSync(dirname(to), { recursive: true }); - 写入本地文件lib/forget.js:70
renameSync(from, to); - 读取本地文件lib/memory-index.js:47
const raw = readFileSync(path, 'utf8'); - 读取本地文件lib/memory-index.js:67
if (!existsSync(dir)) - 读取本地文件lib/memory-index.js:69
for (const entry of readdirSync(dir, { withFileTypes: true })) { - 读取本地文件lib/memory-index.js:98
if (!existsSync(root)) - 读取本地文件lib/memory-index.js:103
const filePart = files.map((file) => file + ':' + String(statSync(file).mtimeMs)).join('|'); - 发起网络请求lib/client/ConfigFileEditor.js:17
const response = await fetch('/api/evolve-git/config'); - 发起网络请求lib/client/ConfigFileEditor.js:25
const response = await fetch('/api/evolve-git/config', { - 发起网络请求lib/client/config-file-scope.js:175
const response = await fetch('/api/evolve-git/config'); - 发起网络请求lib/client/config-file-scope.js:182
const response = await fetch('/api/evolve-git/config', { - 发起网络请求src/client/config-file-scope.ts:198
const response = await fetch('/api/evolve-git/config') - 发起网络请求src/client/config-file-scope.ts:205
const response = await fetch('/api/evolve-git/config', { - 读取本地文件src/config-route.ts:89
const exists = existsSync(path) - 读取本地文件src/config-route.ts:90
const raw = exists ? readFileSync(path, 'utf8') : '' - 写入本地文件src/config-route.ts:114
mkdirSync(dirname(path), { recursive: true }) - 写入本地文件src/config-route.ts:115
writeFileSync(path, raw, 'utf8') - 读取本地文件src/config.ts:53
if (!existsSync(path)) return {} - 读取本地文件src/config.ts:55
const raw = readFileSync(path, 'utf8') - 写入本地文件src/config.ts:66
mkdirSync(dirname(path), { recursive: true }) - 写入本地文件src/config.ts:67
writeFileSync(path, JSON.stringify(config, null, 2) + '\n', 'utf8') - 发起网络请求src/core.ts:140
fetch(): void - 发起网络请求src/core.ts:293
fetch(): void { - 读取本地文件src/forget.ts:35
if (!existsSync(dir)) return - 读取本地文件src/forget.ts:36
for (const entry of readdirSync(dir, { withFileTypes: true })) { - 读取本地文件src/forget.ts:45
if (!existsSync(root)) return undefined - 读取本地文件src/forget.ts:49
const fm = parseFrontmatterFields(readFileSync(file, 'utf8')) - 写入本地文件src/forget.ts:81
mkdirSync(dirname(to), { recursive: true }) - 写入本地文件src/forget.ts:83
renameSync(from, to) - 执行外部命令固定命令src/git.ts:44
const result = spawnSync('git', ['-C', repoPath, ...args], { encoding: 'utf8', env: { ...process.env, ...env } }) - 执行外部命令固定命令src/git.ts:56
const result = spawnSync('git', ['clone', '--branch', branch, '--single-branch', repoUrl, repoPath], { - 读取本地文件src/git.ts:71
if (!existsSync(join(resolved, '.git'))) { - 读取本地文件src/git.ts:126
if (existsSync(join(resolved, '.git'))) return resolved - 读取本地文件src/git.ts:127
if (existsSync(resolved) && readdirSync(resolved).length > 0) { - 读取本地文件src/git.ts:127
if (existsSync(resolved) && readdirSync(resolved).length > 0) { - 写入本地文件src/git.ts:130
mkdirSync(dirname(resolved), { recursive: true }) - 读取本地文件src/git.ts:195
head: existsSync(join(repoPath, '.git', 'HEAD')) ? currentHead(repoPath) : undefined, - 执行外部命令固定命令src/git.ts:224
const staged = spawnSync('git', ['-C', repoPath, 'diff', '--cached', '--quiet'], { encoding: 'utf8' }) - 写入本地文件src/git.ts:265
mkdirSync(dirname(filePath), { recursive: true }) - 写入本地文件src/git.ts:285
writeFileSync(filePath, body, 'utf8') - 写入本地文件src/git.ts:311
mkdirSync(dirname(filePath), { recursive: true }) - 写入本地文件src/git.ts:313
writeFileSync(filePath, rendered.content, 'utf8') - 读取本地文件src/index.ts:472
const raw = readFileSync(path, 'utf8') - 发起网络请求src/index.ts:964
async fetch(): Promise<void> { - 发起网络请求src/index.ts:965
this.core.fetch() - 读取本地文件src/memory-index.ts:64
const raw = readFileSync(path, 'utf8') - 读取本地文件src/memory-index.ts:85
if (!existsSync(dir)) return - 读取本地文件src/memory-index.ts:86
for (const entry of readdirSync(dir, { withFileTypes: true })) { - 读取本地文件src/memory-index.ts:115
if (!existsSync(root)) return 'empty:' + config.repoPath - 读取本地文件src/memory-index.ts:119
const filePart = files.map((file) => file + ':' + String(statSync(file).mtimeMs)).join('|') - 读取本地文件src/memory.ts:58
const raw = readFileSync(path, 'utf8') - 读取本地文件src/memory.ts:81
if (!existsSync(dir)) return - 读取本地文件src/memory.ts:82
for (const entry of readdirSync(dir, { withFileTypes: true })) { - 读取本地文件src/memory.ts:174
const raw = readFileSync(path, 'utf8') - 读取本地文件src/skill.ts:73
try { lstatSync(p); return true } catch { return false } - 写入本地文件src/skill.ts:93
mkdirSync(dirname(link), { recursive: true }) - 删除本地文件递归src/skill.ts:96
rmSync(link, { recursive: true, force: true }) - 读取本地文件src/skill.ts:115
const st = lstatSync(link) - 删除本地文件递归src/skill.ts:120
rmSync(link, { recursive: true, force: true }) - 读取本地文件src/skill.ts:162
if (!existsSync(root)) return [] - 读取本地文件src/skill.ts:164
for (const entry of readdirSync(root, { withFileTypes: true })) { - 读取本地文件src/skill.ts:167
if (!existsSync(skillPath)) continue - 读取本地文件src/skill.ts:168
const fm = parseFrontmatter(readFileSync(skillPath, 'utf8')) - 写入本地文件src/skill.ts:202
mkdirSync(join(repoPath, config.skillsRoot, to), { recursive: true }) - 写入本地文件src/skill.ts:251
mkdirSync(join(targetRoot, entry.name), { recursive: true }) - 写入本地文件src/skill.ts:252
writeFileSync(target, content, 'utf8') - 写入本地文件src/skill.ts:255
writeFileSync(target, content, 'utf8') - 读取本地文件src/update.ts:29
const raw = readFileSync(path, 'utf8') - 读取本地文件src/update.ts:39
const raw = readFileSync(path, 'utf8') - 写入本地文件src/update.ts:66
writeFileSync(path, '---\n' + lines.join('\n') + '\n---' + body, 'utf8')
扫描于 2026/11/3(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/schemastery@deepseek-ai/dsh-client-locale@deepseek-ai/dsh-client-runtime@deepseek-ai/dsh-client-ui-settings@deepseek-ai/dsh-client-ui-slots@deepseek-ai/dsh-host-webserver@deepseek-ai/dsh-settings@deepseek-ai/dsh-commands@deepseek-ai/dsh-invariants@deepseek-ai/dsh-system-prompt@deepseek-ai/dsh-tools给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 自定义Git仓库存储
- 支撑长期记忆
- 支持智能体进化
一个 deepseek-harness 插件,让你的智能体在自定义 git 仓库里进化。
README
由 DeepSeek 最新模型翻译生成dsh-evolve-in-git
English · 中文
DeepSeek Harness 插件:用 Git 支撑长期记忆与进化。
目录
- 它能做什么
- 安装
- 用法
- 架构
- 数据布局
- 配置
- Harness 入口
- 浏览器端
- 开发
- 交付说明
- 协议
它能做什么
这个插件把用户选定或预先配置好的 Git 仓库当作记忆存储。
它能把会话笔记、分支专属记录、可复用技能草稿写进仓库,再作为普通 Git 历史提交。
安装
example: install into the web profile
dsh plugin --profile web add github:Kytolly/dsh-evolve-in-git
安装包会插入一行 dsh-evolve-in-git,使用插件默认值。
后续的配置档补丁可以覆盖 repoPath、repoUrl、auth 以及各个存储根目录。
用法
自然语言
你不用记工具名——把想要的结果说出来,模型会自己挑对应的 evolve_ / memory_ 工具:
| 你说的话(或类似说法) | 模型会用的工具 |
| 「记住:只要 X 发生,就做 Y」 | evolve_remember / memory_save |
| 「有关于部署流程的记忆吗?
展开完整文档(README 剩余 1 节)
dsh-evolve-in-git
English · 中文
DeepSeek Harness 插件:用 Git 支撑长期记忆与进化。
目录
- 它能做什么
- 安装
- 用法
- 架构
- 数据布局
- 配置
- Harness 入口
- 浏览器端
- 开发
- 交付说明
- 协议
它能做什么
这个插件把用户选定或预先配置好的 Git 仓库当作记忆存储。
它能把会话笔记、分支专属记录、可复用技能草稿写进仓库,再作为普通 Git 历史提交。
安装
example: install into the web profile
dsh plugin --profile web add github:Kytolly/dsh-evolve-in-git
安装包会插入一行 dsh-evolve-in-git,使用插件默认值。
后续的配置档补丁可以覆盖 repoPath、repoUrl、auth 以及各个存储根目录。
用法
自然语言
你不用记工具名——把想要的结果说出来,模型会自己挑对应的 evolve_ / memory_ 工具:
| 你说的话(或类似说法) | 模型会用的工具 |
| 「记住:只要 X 发生,就做 Y」 | evolve_remember / memory_save |
| 「有关于部署流程的记忆吗?」 | evolve_recall / memory_search |
| 「读一下我最近的记忆历史」 | evolve_timeline |
| 「把这条警告变成可复用的技能」 | evolve_skill_draft → evolve_skill_promote |
| 「记忆仓库现在是什么状态?」 | evolve_status / evolve_branches |
| 「撤销上一次记忆提交」 | evolve_rollback |
命令(/evolve)
想要明确、可控的操作,就输入 /evolve <subcommand>:
/evolve remember warning "pitfall" :: <content>
/evolve search deploy
/evolve skill list
/evolve skill promote evolve-process
/evolve status
/evolve help
完整命令参考见 Harness 入口。
架构
这个包分成两部分:不依赖框架的核心和一层薄薄的 DSH 适配器:
- src/core.ts(GitMemoryCore)是可移植性边界。它只依赖 Node 内置模块和同级的核心模块——绝不依赖 @deepseek-ai/——并从磁盘上的配置文件解析配置,覆盖宿主提供的基础配置。
- src/index.ts(GitEvolutionService)是适配器:它注册 Cordis 工具、/evolve 命令、系统提示词片段、技能服务商和配置文件路由,再把每个接口映射到 GitMemoryCore。
| 模块 | 职责 |
| src/git.ts | 启动 git:clone/open、status、分支操作、push/fetch、commit、git mv、冲突、回滚。 |
| src/memory.ts + src/memory-index.ts | 扫描 Markdown + YAML frontmatter,维护元数据索引缓存(HEAD + mtime 签名),按预算召回,生成时间线。 |
| src/update.ts | 带版本的更新:新增一条 active 记录,并写入 supersedes/supersededBy;旧文件永不删除。 |
| src/forget.ts | 软删除(移到 archiveRoot)与恢复。 |
| src/privacy.ts | 敏感内容检测、敏感度分级、脱敏、导出过滤。 |
| src/skill.ts | 在 drafts/ ↔ enabled/ 中发现技能;用 git mv 提升/降级;同步内置技能。 |
| src/strategy.ts | Slug/sanitize、从记忆生成草稿、演进建议、预览。 |
| src/harness.ts | /evolve 命令的规范化/解析,以及帮助、用法、安全提示文案。 |
| src/config.ts + src/defaults.ts | 配置文件的读、写、合并,以及插件默认值。 |
| src/invariant.ts | 空操作的不变量伴随模块(唯一事实来源是配置的 Git 仓库)。 |
| src/loopback.ts + src/config-route.ts | 仅限回环的 /api/evolve-git/config 路由,供配置文件编辑器使用。 |
| src/client/ | 浏览器设置区块(evolve-git 插槽)与配置文件编辑器。 |
数据布局
- 记忆 — <repo>/<memoryRoot>/<kind>/<timestamp>-<slug>-<id>.md,每条记录一个 Markdown 文件,带 YAML frontmatter(kind、title、branch、source、tags、createdAt、id、updatedAt、status、supersedes、supersededBy、expiresAt、sensitivity),后面是正文。
- 技能 — <repo>/<skillsRoot>/drafts/<name>/SKILL.md(可提升)与 <repo>/<skillsRoot>/enabled/<name>/SKILL.md(可发现)。提升就是在两者之间执行 git mv,绝不复制,因此始终可逆,也留在历史里。
- 归档 — <repo>/<archiveRoot>/…(相对布局与记忆相同);evolve_forget 把记录移到这里,于是它们退出召回和时间线,但仍可恢复。archiveRoot 必须保持在 memoryRoot 之外。
配置
Web 设置界面(v0.1.4+)。 插件带一个浏览器端部分,在 web 配置档的设置页上注册一级 Settings → 演进记忆 区块(通过 settings.section 插槽)。表单使用 SettingsScope 适配器,直接通过仅限回环的 /api/evolve-git/config 路由读写每用户配置文件,所以表单显示的就是实际生效的内容(默认值被文件覆盖),保存时立即写入文件。嵌套的 auth 作为一个合并对象写入,auth.token 字段只写(密钥,读回时脱敏)。安装后需要重启配置档,以便重新扫描客户端清单。
- repoPath - 本地 Git 检出目录,用来存放记忆和技能。默认是 ~/.dsh-evolve-in-git/remote-memory。
- repoUrl - 远程记忆仓库。插件不带个人默认值:内置默认值是占位符 https://github.com/<your-github-username>/<your-memory-repo>.git,所以请配置你自己的仓库(见下文「按用户配置文件」)。
- auth - 私有访问的 Git 认证设置。默认配置档优先用 SSH,也支持 token。
- memoryRoot - 记忆记录的写入位置,默认 .dsh-evolve/memory。
- skillsRoot - 技能草稿的写入位置,默认 .dsh-evolve/skills。
- defaultBranch - 创建新分支时从哪个分支演进,默认 main。
- remoteName - 拉取和推送的远程,默认 origin。
- autoCommit - 写入是否自动提交,默认 true。
- archiveRoot - evolve_forget 把记录移到哪里,默认 .dsh-evolve/archive。
- recallTopK - evolve_recall 返回的最大结果数,默认 10。
- recallMinScore - 保留结果的最低相关度分数,默认 0。
- recallMaxChars - 返回的召回内容累计字符预算,默认 8000。
- privacyMode - 敏感内容的写入路径隐私闸门,默认 ask。检测到敏感内容时,block 拒绝写入;redact 存储脱敏后的内容(绝不存明文);ask 原样存储内容并标记其 sensitivity,以便审查确认。
- digestEnabled - 是否在会话开始时注入 persona+warning 摘要,默认 true。
- digestMaxRecords - 会话开始摘要中 persona/warning 记录的最大条数,默认 5。
- digestMaxChars - 会话开始摘要的最大字符数,默认 2000。
认证
- auth.mode: "ssh" - 使用 ssh 或自定义 sshCommand。
- auth.mode: "token" - 使用 token,或从 tokenEnv 取 token,并带上 GitHub 风格的 Authorization 头。
隐私写入闸门
每次写入记忆都要过隐私闸门(邮箱、电话、身份证、信用卡、AWS 密钥、GitHub token、私钥,以及 password: 这类机密)。privacyMode 控制响应方式:
- block - 检测到敏感内容时拒绝写入。
- redact - 把检测到的片段替换为 <REDACTED>,存储替换后的内容,而不是明文。
- ask(默认)- 原样存储内容,并记录其 sensitivity,以便审查确认。
evolve_show/evolve_export 会遵循记录的 sensitivity 级别,导出默认排除 secret 记录。没有记录 sensitivity 的记录(在闸门出现之前写入的)一律视为 secret,这样它们绝不会被误导出。
闸门只覆盖记忆写入(writeMemoryRecord/updateMemory,即 evolve_remember/memory_save/evolve_update/memory_update)。技能草稿写入(writeSkillDraft/saveSkillDraftFromRecord)在本版本中刻意不过隐私闸门;提升草稿之前,请先检查其中是否有机密。
召回打分。 evolve_recall/memory_search 会把查询与记录只读元数据(title、kind、tags、branch、source);正文按需加载,只对排名靠前的匹配项加载,但不计入相关性评分。人类命令 /evolve search 用的是同一套元数据索引召回,所以返回的排名结果完全一致,而不是换一套匹配器。
归档约束。 archiveRoot 必须留在 memoryRoot 之外(默认的 .dsh-evolve/archive 就在外面)。如果你把 archiveRoot 指向 memoryRoot 里面,已遗忘的记录仍会被扫描,不会消失。
每用户配置文件
每个 DSH 用户在本地保留一份配置文件,路径为 $DSH_HOME/evolve-in-git.json(默认是 ~/.dsh/evolve-in-git.json)。它只属于本机用户,永远不进任何 Git 仓库——不要提交它。这个文件是唯一的用户配置层:Web 端「Settings → 演进记忆」表单读写的正是这个文件(显示时用你的文件值覆盖默认值,保存时立即写入文件),/evolve config show|open|refresh|set <key> <value> 命令改的也是它。内嵌的配置文件编辑器打开的是原始 JSON。
示例:
{
"repoPath": "/absolute/path/to/your/local-memory-checkout",
"repoUrl": "https://github.com/<your-github-username>/<your-memory-repo>.git"
}
千万不要把访问令牌写进这个文件——用 auth.tokenEnv 指定环境变量名,或者用 Web 设置里的 token 字段(只写)。
Web 端「Settings → 演进记忆」还内嵌了一个配置文件编辑器,直接打开这个文件,按原始 JSON 编辑,通过仅限回环地址的 /api/evolve-git/config 路由保存(保存立即生效)。
Harness 入口点
插件面向当前 Harness 0.1.1-rc.2 宿主契约,涵盖命令、工具、系统提示词和不变量(peerDependencies 为 ^0.1.1-rc.2)。把它装进某个配置档,然后重启该配置档,让 bundle 层完成组装。
工具:
- evolve_connect
- evolve_status
- evolve_remember
- evolve_update
- evolve_forget
- evolve_restore
- evolve_show
- evolve_export
- evolve_branches
- evolve_branch_switch
- evolve_branch_diff
- evolve_skill_draft
- evolve_skill_list
- evolve_skill_promote
- evolve_skill_demote
- evolve_rollback
- evolve_conflicts
- evolve_resolve
- evolve_timeline
- evolve_recall
- evolve_help
- memory_search(evolve_recall 的别名)
- memory_save(evolve_remember 的别名)
- memory_update(evolve_update 的别名)
- memory_delete(evolve_forget 的别名)
人类命令:
- /evolve connect
- /evolve status
- /evolve branches
- /evolve remember <kind> [--expires <iso>] :: <content>
- /evolve update <id> [--merge] :: <content>
- /evolve forget <id>
- /evolve restore <id>
- /evolve config show|open|refresh|set <key> <value>
- /evolve skill draft <kind> :: <content>
- /evolve skill list
- /evolve skill promote <name>
- /evolve skill demote <name>
- /evolve skill sync
- /evolve rollback <ref> [--dry]
- /evolve conflicts
- /evolve resolve <path> <ours|theirs|both>
- /evolve timeline
- /evolve search [--kind k] [--tag t]
- /evolve branch switch <name> \| /evolve branch diff [b] \| /evolve branch revert <ref>
- /evolve help
安装完成后,先验证组合是否正确,再启动长时间运行的配置档:
dsh --profile web --dump-config
dsh --profile web
第一条命令应当显示插件包里的 evolve-git 行。第二条命令启动配置档;加载完成后,模型就能看到 evolve_ 工具,UI 命令注册表也会暴露 /evolve。
内置技能
包里在 skills/ 下附带 evolve-process 技能。加载时,插件会把它实体化到仓库的 <skillsRoot>/drafts/evolve-process/(只在缺失时创建);/evolve skill sync 会按需覆盖内置副本。用 /evolve skill promote evolve-process 提升它。适配器把仓库的 <skillsRoot>/enabled/ 目录注册为 DSH 技能服务商,所以提升后的技能无需复制到 ~/.dsh/skills 就能调用。
浏览器端
- src/client/ - 浏览器包(lib/client.js),由 tsc -p tsconfig.client.json && tsdown 编译(见 tsdown.config.ts);注册为 settings.section 插槽,让 Web 设置页渲染配置表单。
- package.json - exports["./client"] + dsh.client(platform: "web")是清单契约,dsh-client-modules 扫描它,把包纳入 window.__DSH_BOOT__。
开发
需要 Node.js 和 pnpm。工作区设置 nodeLinker: hoisted,并允许 esbuild 构建。
pnpm install
pnpm build # tsc (server) + tsc (client) + tsdown browser bundle
npx pnpm test # regenerates the @deepseek-ai/dsh-tools stub, then runs tests
npx pnpm typecheck # tsc --noEmit for both projects
npx pnpm check # build + test (CI uses this)
prepack 脚本会运行 pnpm build,所以发布的 lib/ 产物始终是最新的。测试放在 tests/.spec.ts 下,通过 tsx 用 node --test 运行。
交付说明
v0.6.3 敲定了 MVP:带预算的元数据索引召回、版本化更新(supersedes/supersededBy)、软删除/恢复加过期、可回滚的技能草稿(仓库 enabled/ 目录注册为 DSH 技能服务商)、block/redact/ask 隐私写入门禁,以及 memory_ 别名和会话启动时的 persona+warning 摘要。
验证:npx pnpm check(构建 + 测试;build 也会做类型检查)通过。
已知的非阻塞 TODO
- getMemoryIndex 在缓存命中时仍会重新遍历记忆根目录(正确性优先于速度);基于 watcher 的廉价签名是后续工作。
- 隐私门禁覆盖记忆写入(writeMemoryRecord/updateMemory);技能草稿写入(writeSkillDraft/saveSkillDraftFromRecord)有意放在门禁之外(已记录为仅限记忆的范围)。
- classifySensitivity 从不分配 internal;只有手工编写记录、把 frontmatter 写成该值时,才能触达 internal 导出级别。
许可证
MIT —— 见 LICENSE。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
Kytolly/dsh-evolve-in-git
DeepSeek Harness 插件:用 Git 支撑长期记忆与进化。
相关插件 · 对话 / 记忆
上下文中枢oceanbase/powercontext
上下文跟着工作走 —— 跨会话、跨智能体、跨人。
★ 1,487已汉化DSH
73
智能体记忆库plastic-labs/honcho
Honcho 是记忆基础设施,用来构建有状态的智能体。这些智能体能理解不断变化的人、智能体、群组、项目和想法。
★ 7,894已汉化DSH
71.7
长程智能体控制面loopx-project/loopx
给 Agent 一个目标,让工作持续向前。
★ 6,358已汉化DSH
71.3
智能体上下文数据库volcengine/OpenViking
给 AI 智能体用的上下文数据库
★ 41,379已汉化DSH
71.3
长效机器人团队Fei2411/DS-Bot
DS Bot 是一个基于 DeepSeek Harness简称 dsh的 bot 插件,插件将 dsh 改造为 bot…
★ 5,084已汉化DSH
71.1
可携带记忆层EverMind-AI/EverOS
为什么选择 EverOS
★ 13,778已汉化DSH
71.1