@youkale/pi-hermes-memory
🧠 Persistent memory + 🔍 session search + 🛡️ secret scanning for Pi. Token-aware policy-only memory by default, SQLite FTS5 search, auto-consolidation, procedural skills. 368 tests. Ported from Hermes agent.
Package details
Install @youkale/pi-hermes-memory from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@youkale/pi-hermes-memory- Package
@youkale/pi-hermes-memory- Version
0.7.15- Published
- Aug 3, 2026
- Downloads
- 97/mo · 97/wk
- Author
- youkale
- License
- MIT
- Types
- extension
- Size
- 783.1 KB
- Dependencies
- 2 dependencies · 1 peer
Pi manifest JSON
{
"extensions": [
"./src/index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
Pi Hermes Memory
Pi Hermes Memory 是一个 Pi Coding Agent 扩展,为 Pi 增加跨会话持久记忆、会话搜索、后台学习、过程型技能和技能治理能力。安装后,代理可以把稳定事实写入本地存储,在后续会话按需搜索,而不是把所有历史内容塞进系统提示词。
当前包版本: 0.7.15
快速开始
pi install npm:pi-hermes-memory
从 GitHub 安装:
pi install git:github:chandra447/pi-hermes-memory
本地开发或直接运行当前 checkout:
pi -e ./src/index.ts
常用初始化命令:
/memory-index-sessions
/memory-sync-markdown
/memory-interview
/learn-memory-tool
这个扩展做什么
| 能力 | 当前行为 |
|---|---|
| 持久记忆 | 将用户画像、全局记忆、项目记忆和失败经验写入本地 Markdown 与 SQLite 搜索库;replace 的旧值在 SQLite 保留为 superseded 历史,项目与全局/组织层之间可显式 promote/demote |
| 默认低 token 注入 | 默认 memoryMode: "policy-only",系统提示词只注入记忆使用策略,具体内容由工具按需搜索 |
| 项目级记忆 | 基于 cwd 或配置识别项目,在平面 Markdown 文件中写入真实项目归属并默认隔离 |
| 会话搜索 | /memory-index-sessions 建索引后,LLM 可用 session_search 搜索历史 Pi 会话 |
| 记忆搜索 | memory_search 默认使用 FTS;显式配置 embedding provider 后,在既有 scope 内执行 FTS + 进程内余弦混合检索 |
| 后台学习 | 按用户轮次或工具调用数触发后台 review,保存值得复用的事实和项目技能 |
| 修正捕获 | 用户纠正代理时可立即触发保存,避免反复犯同一类错误 |
| 自动整理 | 记忆接近容量时先在同 scope 内离线预聚类近重复,再由子进程按组合并、替换或压缩 |
| 技能系统 | 通过 Pi 原生 SKILL.md 保存过程型知识,支持全局和项目两个作用域 |
| 技能治理 | 记录真实 skill.use 证据,支持项目技能晋升、降级、隐藏和统计 |
| 内容扫描 | 记忆和技能写入前经过扫描,拦截密钥、prompt injection、角色劫持和隐形字符等风险 |
数据目录
agentRoot 默认是 ~/.pi/agent,也可以通过环境变量整体切换:
PI_CODING_AGENT_DIR=/custom/pi-agent pi
默认布局:
| 路径 | 用途 |
|---|---|
<agentRoot>/hermes-memory-config.json |
配置文件 |
<agentRoot>/pi-hermes-memory/MEMORY.md |
全局代理记忆 |
<agentRoot>/pi-hermes-memory/USER.md |
用户画像和偏好 |
<agentRoot>/pi-hermes-memory/failures.md |
失败、修正、洞察、约定、偏好和工具怪癖 |
<agentRoot>/pi-hermes-memory/sessions.db |
SQLite 会话索引、记忆 FTS、普通 BLOB 嵌入向量与 supersede 历史、技能统计(含 skill_load_daily;skill_load_events 保留历史数据,只读不再写入;按 skillGovernance.loadEventRetentionDays 机会式 TTL 清理,见下文)和治理状态 |
<agentRoot>/pi-hermes-memory/skills/<slug>/SKILL.md |
扩展管理的全局技能 |
<agentRoot>/projects-memory/MEMORY.md |
项目级记忆平面文件;每个受管条目通过 project=<项目名> 元数据记录真实归属 |
<agentRoot>/projects-memory/<project>/skills/<slug>/SKILL.md |
项目级技能 |
<agentRoot>/sessions/ |
Pi 会话 JSONL,供会话索引读取 |
如果配置了 memoryDir,SQLite 文件实际位于 <memoryDir>/sessions.db。
如果从旧版本升级,扩展会在启动时尽力迁移旧目录:
| 旧位置 | 新位置 |
|---|---|
<agentRoot>/memory |
<agentRoot>/pi-hermes-memory |
<agentRoot>/pi-hermes-memory/skills/*.md |
<agentRoot>/pi-hermes-memory/skills/<slug>/SKILL.md |
<agentRoot>/<project>/MEMORY.md |
<agentRoot>/projects-memory/MEMORY.md |
<agentRoot>/projects-memory/<project>/MEMORY.md |
<agentRoot>/projects-memory/MEMORY.md |
项目记忆合并完成后,来源文件会被改名为 MEMORY.md.migrated(内容保留),避免下次启动重复合并、复活已在平面文件中删除的条目;合并时会按来源目录补写真实 project 元数据,已有归属保持不变。/memory-sync-markdown 不会把 retired 来源导回 SQLite;它逐条读取 projects-memory/MEMORY.md 的归属字段,以真实项目名回填和对账。无归属项目条目会保留在 Markdown 中,但跳过 SQLite 并报告 warning/skipped,不会被自动改写或淘汰。
项目条目元数据格式为:
正文 <!-- created=2026-07-29, last=2026-07-29, project=my-project -->
全局 MEMORY.md、USER.md 不写 project 字段。failures.md 在项目会话中写真实归属;非项目会话产生的无归属 failure 是全局失败,对所有项目可见。
failure 的容量统计、FIFO 淘汰和自动整理输入只包含当前项目条目与无归属全局 failure;其他项目的 failure 不会被当前会话自动整理或删除。该维护边界不受 projectMemorySharing 影响。
记忆模型
默认模式是 policy-only。启动时系统提示词会得到一段 <memory-policy>,告诉代理什么时候调用 memory_search、session_search、memory 和 skill。完整 Markdown 记忆默认不注入系统提示词,这样可以减少首轮 token 占用,也能避免旧记忆直接覆盖当前用户请求。
如需兼容旧行为,可以设置:
{
"memoryMode": "legacy-inject"
}
legacy-inject 会把全局记忆、用户画像、当前可见的项目记忆和近期可见失败记忆用 <memory-context> 边界块注入系统提示词。默认只注入当前项目条目;无归属 failure 作为全局失败注入。即使在这个模式下,当前用户请求、仓库文件和工具输出也应优先于旧记忆。
斜杠命令
| 命令 | 用途 |
|---|---|
/memory-insights |
查看当前全局、用户、失败和项目记忆概览 |
/memory-skills |
打开技能管理界面,查看全局、项目和外部加载的技能 |
/memory-skill-governance |
管理项目技能到全局技能的治理状态 |
/memory-skill-visibility |
按项目隐藏、显示或重置全局技能可见性 |
/memory-skill-stats |
查看 resources_discover 记录的技能加载和曝光统计(sinceDays 按 UTC 天粒度对齐) |
/memory-review-status |
查看当前进程内的后台记忆 review 计数器和最近一次 review 状态 |
/memory-doctor |
只读检查 Markdown/SQLite 漂移、会话索引、嵌入覆盖率,并报告项目×项目及项目×全局的跨 scope 近重复候选;只报告不动作 |
/memory-consolidate |
手动触发全局、用户和项目记忆整理 |
/memory-interview |
通过问答预填用户画像 |
/memory-learn-skill |
让当前代理把近期上下文或来源材料沉淀为项目优先的技能 |
/memory-switch-project |
按真实归属列出各项目条目数和无归属计数;当前项目仍由 cwd 或配置决定 |
/memory-index-sessions |
将历史 Pi 会话导入 SQLite 会话搜索索引 |
/memory-sync-markdown |
将已有 Markdown 记忆回填到 SQLite 记忆搜索库 |
/memory-preview-context |
预览当前会注入系统提示词的记忆策略或 legacy 记忆块 |
/learn-memory-tool |
显示扩展的使用说明和排障提示 |
skill_load_events 表已改为只读历史留存,不再写入;仅用于回填和核对。已知边界:若回退到旧版后又升级,旧版期间新增的 raw 增量不会再次回填进入 skill_load_daily 聚合统计,但 raw 数据会被完整保留。
每次 resources_discover 写入 skill_load_daily 之后,会机会式检查是否需要清理过期行:距上次清理 ≥24 小时(或从未清理过)才会真正执行一次,skillGovernance.loadEventRetentionDays(默认 180 天)之前的 skill_load_daily、skill_load_events 行会被删除;loadEventRetentionDays: 0 完全禁用清理(连清理时间戳都不更新)。每张表单次最多删除 skillGovernance.loadEventCleanupBudget(默认 500)行,避免长事务;一次删不完的部分留到下一次到期的 24 小时窗口继续删,但当前这一轮仍会记录清理时间,防止繁忙项目在同一天内反复触发删除。清理失败会被隔离并仅打印警告,不影响 resources_discover 主流程;不会在扩展启动路径上运行。skill_usage_events 永远不受清理影响。
/memory-skill-governance 支持这些动作:
/memory-skill-governance status
/memory-skill-governance curate
/memory-skill-governance explain <skill_id>
/memory-skill-governance promote <skill_id>
/memory-skill-governance demote <skill_id>
/memory-skill-governance restore <skill_id>
/memory-skill-governance clear <skill_id>
/memory-skill-governance reload
/memory-skill-visibility 支持:
/memory-skill-visibility list [--project <project>]
/memory-skill-visibility hide <global_skill_id...> [--project <project>]
/memory-skill-visibility show <global_skill_id...> [--project <project>]
/memory-skill-visibility reset <global_skill_id...> [--project <project>]
隐藏、显示、晋升、降级或恢复技能后,运行 /memory-skill-governance reload 或开启新会话,Pi 才会刷新技能发现结果。
/memory-skill-governance status 还会附带 Curation Jobs 段,展示当前活跃作业、最近一条作业的状态/原因码与累计 skip 计数。
手动执行 /memory-skill-governance curate 与自动触发的策展共享同一项目级租约;若有正在进行或排队的作业,手动调用会提示稍后重试。僵死作业会先被清理再尝试执行,不会永久阻塞。
LLM 工具
这些工具由扩展注册给代理使用,通常不需要用户手动调用。
| 工具 | 主要用途 |
|---|---|
memory |
写入、替换、删除持久记忆,并在当前项目与全局/组织层之间显式移动 |
memory_search |
搜索 SQLite 记忆库 |
session_search |
搜索已索引的历史会话 |
skill |
创建、查看、使用、更新、删除技能,并管理项目级全局技能可见性 |
memory_skill_stats |
只读查询技能加载统计、治理状态和晋升状态 |
skill_governance_curate |
后台或子会话用于提交结构化技能治理分类 |
memory
支持目标:
| target | 含义 |
|---|---|
user |
用户画像、偏好、沟通风格和长期指令 |
memory |
全局事实、环境信息、跨项目经验 |
project |
当前项目的架构、命令、约定和工作流 |
failure |
失败、修正、洞察、偏好、约定或工具怪癖;项目会话写真实项目归属 |
支持动作:
| action | 含义 |
|---|---|
add |
添加新条目;同 scope active 近邻会先返回提示,force: true 可明确越过 |
replace |
用 old_text 匹配并替换已有条目;旧 SQLite 行保留为 superseded 历史 |
remove |
用 old_text 匹配并删除已有条目 |
promote |
用 old_text 将当前项目条目移动到全局/组织层;方向隐含,不传 target |
demote |
用 old_text 将全局条目移动到当前项目;方向隐含,不传 target |
failure 记忆可带 category:
failure, correction, insight, preference, convention, tool-quirk
add 落盘前会全量扫描写入目标的同 scope active own 行(与 FTS 无关),再以保守的 token-set Jaccard 阈值在代码内评分,提示最多返回 3 个近邻。无空格的 Han、Hiragana、Katakana 和 Hangul 内容按 Unicode 码点 bigram 比较,包括增补平面字符;空格词 token 与中英混排同时支持。启用有效 embedding provider 后,如果新内容与候选行都有当前 provider/model 的有效向量,则余弦相似度 >= 0.90 或既有 token 判据任一命中都会拦截;任一侧缺少有效向量时仍只使用原 token 判据。项目写入只检查当前项目 own 行;foreign、无归属项目行、superseded 行和其他 target 都不参与,projectMemorySharing 不会放宽这个写入面。failure 不做近邻拦截。命中时本次不写入,并返回候选正文以及 replace / force: true / 放弃三种行动提示;provider 失败或超时会静默回落,写入不受影响,全程不调用 LLM。
force 只越过近邻提示。精确重复仍先按既有行为返回成功 NOOP,force: true 也不会创建精确副本。
operations 批量写入支持 memory、user、project,每个 add op 也可带 force,但同一批不能混用项目记忆和全局/用户记忆。命中近邻的 add op 会带结构化提示失败,其余 op 继续按部分提交语义执行。容量触发自动整理时,单条 add 与 batch 都会在整理成功、重新加载文件后以新鲜候选视图复检;batch 保留原始 operation 坐标并重新执行顺序模拟,整理新产生的近邻不会绕过拦截。force: true 的 add 不做该近邻复检。
replace 不改变 Markdown 文件契约:MEMORY.md、USER.md 和 failures.md 只保留当前 active 条目。SQLite 会插入新的 active 行,并把旧行的 superseded_by 指向新行、superseded_at 记为当天;连续 replace 可形成 A→B→C 多级链。replace 合并到同 scope 已有相同正文时会指向该 canonical active 行,不产生 active 重复。remove 与 FIFO eviction 仍物理删除对应 active 镜像,不创建 supersede 节点。
promote / demote 是单条目的显式分层移动,不是复制,也不接受 target;operations batch 会明确拒绝这两个 action,并提示改为单发。两者都要求活动项目:promote 从项目层定位源,匹配范围与 project replace 完全相同(默认仅 own;projectMemorySharing: true 时可显式匹配可见 foreign 条目);demote 从无归属的全局 memory 层定位源,并写入当前项目。user 和 failure 不参与。容器部署中全局层就是组织层,因此同一动作也覆盖项目↔组织的分层。
文件移动固定按防丢失顺序执行:先在目标 store 的写锁内写目标,再在源 store 的写锁内精确删除先前定位的源身份。目标正文不变,created 保留,last 刷新为当天;promote 后去掉 project=,demote 后写入当前项目归属。正常完成后同文 active 条目只存在于目标层。若目标已写而源删除失败,工具返回成功结果和明确 warning,并保留可能的双层副本;进程崩溃也至多留下这类可恢复双存窗口,不会因执行顺序造成两层皆无。可用 /memory-doctor 和 /memory-sync-markdown 检查并再次处置。
目标层判定与 add 同构:精确同文优先退化为 merged,只删除源文件条目,并在 SQLite 把源 active 行 supersede 到目标 canonical 行;canonical 的 created 保持不变,Markdown last 与 SQLite last_referenced 都刷新为当天。非同文近邻会阻断且返回最多三个目标层候选,force: true 只越过该近邻提示。近邻范围是目标层 active own 集(promote 为全局集,demote 为当前项目 own 集),只使用 token 判据和双方已有的当前模型向量,移动路径从不调用 embedding provider。目标层容量、FIFO 和 auto-consolidate 行为也复用该层 add;整理成功重载后会再次检查目标近邻,不能绕过单调复检。
常规移动的 SQLite 镜像不会 delete+insert:它在源行上就地更新 project、保留行 id、既有 supersede 祖先指向以及 embedding/embedding_model,同步 created 并刷新 last_referenced。memories_au 会照常维护 external-content FTS;正文未变。Markdown 始终是权威源,镜像更新失败只附带 warning,不回滚已经安全落盘的文件移动。
自动整理
容量触发和 /memory-consolidate 使用相同的整理输入边界:全局/用户只处理各自 scope,项目只处理当前项目 own 条目,failure 只处理当前项目与无归属全局 failure;projectMemorySharing 不会扩大自动维护范围。父进程在启动整理子进程前,以纯代码对同 scope 条目做 O(n²) 近重复预聚类:
- 双方都有当前 provider/model 的已存有效向量时,用进程内余弦,
>= 0.82进入同一候选簇。 - 任一侧没有当前有效向量时,复用写入近邻的保守 token-set Jaccard/CJK Unicode 码点 bigram 判据。
- 相似边组成连通分量;多条分量按“近重复簇”呈现,单例归入“未分组”。没有任何簇时,条目正文与
§分隔保持原格式。
例如子进程可能看到:
[Near-duplicate cluster 1]
项目构建命令要求每次代码合并之前运行完整类型检查
§
项目构建命令要求每回代码合并之前运行完整类型检查
[Ungrouped entries]
发布前确认版本号
聚类只结构化输入,不强制子进程决策;提示词要求优先组内合并、跨组慎并,未分组仍按原整理规则处理。实际落盘继续调用既有 memory tool 的 replace/add/remove 路径,因此 replace 会保留 supersede 链,身份唯一、近邻复检和 batch generation/operation 坐标守卫均不变。
整理全路径不会调用 embedding provider,也不会生成或回填向量。 它只读取 SQLite 中已经存在且匹配当前模型的向量;provider 关闭、数据库缺失或条目没有有效向量时仍可用 token 判据离线整理。
memory_search
memory_search 自动绑定运行时当前项目。默认 projectMemorySharing: false 时,只返回当前项目行和 project IS NULL 的全局行;failure 因而是当前项目 + 全局失败。设置 projectMemorySharing: true 后,搜索可返回全部项目,但任何新写入仍记录真实项目归属。
| 参数 | 含义 |
|---|---|
query |
搜索词或自然语言查询 |
target |
可选,memory、user 或 failure |
category |
可选,仅用于失败类分类 |
limit |
默认 10,最大 20 |
include_superseded |
默认 false;true 时同时返回 superseded 历史,并标出 superseded_by 目标和日期 |
默认搜索和统计只计算 superseded_by IS NULL 的 active 行;include_superseded 只叠加历史可见性,不改变当前项目/global/sharing 的 scope 谓词。/memory-sync-markdown 回填和对账也只比较 active 行:历史不会因 Markdown 中不存在而被删除,也不会被当成缺失事实重新导入。/memory-doctor 的一致性比较使用 active 行,并在每个 target 旁单列 superseded 数量。
embedding 默认完全关闭,此时 memory_search 直接走原 FTS 路径,结果和格式不变。显式配置并成功读取 API key 后,检索流程如下:
- 先应用现有 current-project/global/sharing、target、category、active/
include_superseded谓词,得到候选集;向量排序永远不会越过该边界。 - 查询文本生成向量;本次 scope 内没有当前模型有效向量的候选,最多批量回填 16 条。失败项保持
NULL,以后搜索可再次机会性回填,不做启动期全量任务。 - FTS 命中序与候选集余弦相似序用 RRF(
k=60)融合;没有向量的行仍可通过 FTS 召回。
因此 projectMemorySharing: false 时,项目 A 不会因为语义相似召回项目 B 的行;failure、global 和 superseded 的可见性也仍由原谓词决定。查询向量失败、网络失败、超时或部分条目失败都会静默降级:查询回到 FTS-only,成功的记忆写入照常完成,失败向量留空。向量模型标识是 openai-compatible/<model>;行上的 embedding_model 与当前标识不全等时按 NULL 处理,并在后续搜索中机会性重嵌。
向量以 Float32Array 的普通 SQLite BLOB 保存,余弦在 JS 进程内计算。本实现不加载 sqlite-vec、ONNX runtime 或其他原生向量扩展,也没有为 embedding 增加 npm 依赖。
/memory-doctor
/memory-doctor 保持只读,并在既有目录、Markdown/SQLite 一致性、active/superseded、嵌入覆盖率和会话索引段之间新增 Cross-scope near-duplicate candidates (read-only) 段。这个分析是默认项目隔离之外的诊断视图,只读取全库 active target=memory 行:
- 项目 A × 项目 B 命中时报告“升级候选:或属组织层通用知识”。
- 项目 × 全局命中时报告“疑似重复”,建议人工判断去其一,或把不适合全局的知识下沉到项目。
user、failure、同 scope 对和 superseded 历史不参与。
判据与整理预聚类一致:双方有当前模型的已存有效向量时使用余弦 >= 0.82,否则使用既有 token/Jaccard/CJK bigram 判据;doctor 同样不会调用 provider 或回填向量。扫描前只为每行计算一次 token 集并引用一次当前有效向量,随后最多比较 250,000 个跨 scope 对;达到预算时停止并明确提示结果可能不完整。每个候选列出两个 scope、截断后的条目摘录、cosine/token 来源、相似度和建议方向,计数明确表示已扫描对中的总检出数;报告最多渲染前 50 条,超出时明确提示截断。完整扫描的空结果显示 无跨 scope 近重复;预算早停且零命中时只说明已扫描范围未发现,未扫描部分保持未知。
Cross-scope near-duplicate candidates (read-only)
Total candidates: 2 (detected in scanned pairs)
1. project:service-a x project:service-b [token=1.000]
suggestion: 升级候选:若当前项目条目已证明组织内普适,用 memory promote 上移。
2. project:web x global [cosine=0.934]
suggestion: 疑似重复:可用 memory promote 合并到全局,或用 demote 将仅属当前项目的全局条目下沉。
当数据量触发资源边界时,同一段会附加:
已达比较预算,结果可能不完整(708 行/250000 对上限;已比较 250000 对)
候选输出已截断:显示前 50 条,共检出 250000 条。
该段只报告不动作:doctor 不会自动改写条目。人工确认方向后,可单独调用 memory 的 promote / demote action 处置;项目×项目候选需先切换到要上移条目所属的当前项目。
session_search
默认 sessionSearch.variant 是 legacy,参数为 query、project、role、limit。在设置 sessionSearch.variant: "anchors" 后,工具改为接收一个 Markdown 请求,返回 JSONL 源文件范围锚点。
skill
支持动作:
create, view, use, patch, update, edit, delete, write_file, remove_file, visibility
关键规则:
| 规则 | 当前行为 |
|---|---|
create 必须传 scope |
global 用于可迁移流程,project 用于依赖当前仓库路径、脚本、架构或发布方式的流程 |
view 是只读 |
只查看或列出技能,不记录真实使用 |
use 会记录使用证据 |
项目技能晋升依赖主会话里的真实 skill.use |
| 结构化写入优先 | 推荐传 when_to_use、procedure_steps、pitfalls、verification_steps |
| 支持文件有白名单 | write_file 和 remove_file 只能操作 references/、templates/、scripts/、assets/ 下的支持文件 |
| 子会话限制更严 | 子 prompt 只能查看或改写项目技能,不能 use、delete、visibility 或创建全局技能 |
配置
配置文件默认位于:
~/.pi/agent/hermes-memory-config.json
完整字段示例:
{
"memoryMode": "policy-only",
"memoryPolicyStyle": "full",
"memoryPolicyCustomText": "<memory-policy>Custom policy text.</memory-policy>",
"memoryCharLimit": 5000,
"userCharLimit": 5000,
"projectCharLimit": 5000,
"projectMemorySharing": false,
"nudgeInterval": 10,
"reviewRecentMessages": 0,
"reviewEnabled": true,
"reviewSkillsEnabled": true,
"flushOnCompact": true,
"flushOnShutdown": true,
"flushMinTurns": 6,
"flushRecentMessages": 0,
"memoryDir": "pi-hermes-memory",
"projectsMemoryDir": "projects-memory",
"projectName": "my-project",
"sessionSearch": {
"variant": "legacy"
},
"embedding": {
"provider": "off"
},
"llmModelOverride": "provider/model-name",
"llmThinkingOverride": "medium",
"memoryOverflowStrategy": "auto-consolidate",
"autoConsolidate": true,
"correctionDetection": true,
"correctionStrongPatterns": ["^actually,\\s+(.+)$"],
"correctionWeakPatterns": ["^please\\s+remember\\b"],
"correctionNegativePatterns": ["^never mind\\b"],
"correctionDirectiveWords": ["remember", "prefer"],
"failureInjectionEnabled": true,
"failureInjectionMaxAgeDays": 7,
"failureInjectionMaxEntries": 5,
"nudgeToolCalls": 15,
"skillReviewToolCalls": 10,
"consolidationTimeoutMs": 60000,
"skillGovernance": {
"scopes": {
"globalSkillsDir": "pi-hermes-memory/skills",
"projectSkillsDir": "project-skills-root"
},
"promotionEnabled": true,
"promotionMinSameDomainUsages": 3,
"promotionMinSessions": 2,
"promotionMinProjects": 1,
"promotionTaskDomains": [
{
"id": "repo-workflow",
"description": "Repository build, test, and release workflows.",
"terms": ["build", "test", "release"]
}
],
"promotionDomainTerms": [],
"promotionRequireGlobalSafe": true,
"promotionConflictStrategy": "block",
"curationTimeoutMs": 60000,
"curationMaxConsecutiveFailures": 0,
"autoCurationCooldownMs": 86400000,
"autoCurationFailureCooldownMs": 3600000,
"loadEventRetentionDays": 180,
"loadEventCleanupBudget": 500
}
}
不需要把所有字段都写进配置文件;缺失字段会使用默认值。上面的 projectName、llmModelOverride、llmThinkingOverride、correction pattern、skillGovernance.scopes.* 和 skillGovernance.curationTimeoutMs 都是覆盖示例,不配置时分别使用 cwd 推导、子进程默认模型/thinking、内置修正规则、默认技能目录和 consolidationTimeoutMs 回落值(示例中的 60000 并非该字段的独立默认值)。
解析和路径规则:
agentRoot默认是~/.pi/agent;设置PI_CODING_AGENT_DIR后,配置文件会从<agentRoot>/hermes-memory-config.json读取。- 配置文件不存在、空文件、JSON 格式错误或读取失败时,整体回退默认配置;未知字段会被忽略。
- 字段类型或枚举值不被识别时,该字段保留默认值。数值字段按源码类型解析,部分阈值字段要求非负数。
memoryDir为空或不设置时使用<agentRoot>/pi-hermes-memory;相对路径按当前agentRoot解析,~会展开,绝对路径会保留。projectsMemoryDir只接受agentRoot下的安全单层目录名;绝对路径必须位于agentRoot下,并会规范化为目录名。memoryDir与projectsMemoryDir解析 symlink 后的物理根目录必须互不相同(尚未创建的尾段按最深现存祖先解析);冲突的显式字段会回落默认值并产生启动 warning,/memory-doctor也会报告仍存在的同根状态。promote/demote 在运行时复用同一物理根身份检查,发现同根会在任何写入或删除前拒绝移动;权限等解析异常保守回落到词法绝对路径判定。projectName不设置时由 cwd basename 推导;空值、.、..或包含路径分隔符、,、<、>、换行的值会被忽略。embedding.provider只接受"off"或"openai-compatible";非法 provider、URL、环境变量名、空 model 或非正 timeout 会使整段 embedding 配置回落到 off。openai-compatible默认baseUrl为https://api.openai.com/v1、默认model为text-embedding-3-small、默认timeoutMs为3000。apiKeyEnv必须指名一个环境变量;未配置名称或该变量没有值时 provider 视同 off,并由/memory-doctor提示。autoConsolidate只用于兼容旧配置;显式设置memoryOverflowStrategy时以后者为准。skillGovernance.scopes.globalSkillsDir和skillGovernance.scopes.projectSkillsDir的相对路径同样按agentRoot解析;配置项目技能根目录后,活动项目技能位于<root>/<project>/skills。
当前配置字段:
| 字段 | 默认值 | 说明 |
|---|---|---|
memoryMode |
"policy-only" |
"policy-only" 或 "legacy-inject" |
memoryPolicyStyle |
"full" |
"full"、"compact"、"custom"、"none" |
memoryPolicyCustomText |
未设置 | memoryPolicyStyle: "custom" 时使用;空文本会回退到 compact policy |
memoryCharLimit |
5000 |
全局 MEMORY.md 字符上限 |
userCharLimit |
5000 |
USER.md 字符上限 |
projectCharLimit |
5000 |
每个项目 own 条目的字符上限;foreign/无归属条目不占当前项目预算,也不会被当前项目自动淘汰 |
projectMemorySharing |
false |
false 时项目注入、搜索、去重和显式编辑仅限当前项目;true 放宽为跨项目可见/显式编辑,但写入仍归属当前项目,自动整理和淘汰仍仅处理 own |
nudgeInterval |
10 |
每多少用户轮次触发后台 review |
reviewRecentMessages |
0 |
后台 review 读取的最近消息数,0 表示全部 |
reviewEnabled |
true |
是否启用后台记忆 review |
reviewSkillsEnabled |
true |
后台 review 是否可创建或更新项目技能 |
flushOnCompact |
true |
compact 前是否 flush |
flushOnShutdown |
true |
会话关闭时是否 flush |
flushMinTurns |
6 |
flush 所需最少用户轮次 |
flushRecentMessages |
0 |
flush 读取的最近消息数,0 表示全部 |
memoryDir |
<agentRoot>/pi-hermes-memory |
全局扩展数据目录;相对路径按 agentRoot 解析,旧 <agentRoot>/memory 会迁移到新默认目录 |
projectsMemoryDir |
"projects-memory" |
项目记忆根目录名,必须是 agentRoot 下安全单层目录 |
projectName |
cwd 推导 | 显式项目名,用于项目记忆和项目技能;不安全值会被忽略 |
sessionSearch.variant |
"legacy" |
"legacy" 或 "anchors" |
embedding.provider |
"off" |
"off" 或 "openai-compatible";只有后者且 key 可用时启用混合检索 |
embedding.baseUrl |
"https://api.openai.com/v1" |
OpenAI-compatible API 根地址;请求发送到其 /embeddings |
embedding.apiKeyEnv |
未设置 | 仅从这个名称指向的环境变量读取 API key;不接受配置文件内明文 key |
embedding.model |
"text-embedding-3-small" |
embedding 模型名,也是行向量有效性标识的一部分 |
embedding.timeoutMs |
3000 |
单次 embedding 请求超时毫秒数,上限 30000;超时静默降级 |
llmModelOverride |
未设置 | 子 pi -p 调用使用的模型覆盖;会 trim,空字符串忽略 |
llmThinkingOverride |
未设置 | 子 pi -p 调用的 thinking 覆盖,支持 off、minimal、low、medium、high、xhigh |
memoryOverflowStrategy |
"auto-consolidate" |
"auto-consolidate"、"reject"、"fifo-evict" |
autoConsolidate |
true |
兼容旧配置;没有 memoryOverflowStrategy 时会映射到新字段,显式策略优先 |
correctionDetection |
true |
是否检测用户修正并触发保存 |
correctionStrongPatterns |
内置规则 | 覆盖强修正正则;空数组表示禁用 |
correctionWeakPatterns |
内置规则 | 覆盖弱修正正则;空数组表示禁用 |
correctionNegativePatterns |
内置规则 | 覆盖否定排除正则;空数组表示禁用 |
correctionDirectiveWords |
内置规则 | 覆盖弱修正后的指令词;空数组表示禁用 |
failureInjectionEnabled |
true |
legacy 注入模式下是否注入近期失败记忆 |
failureInjectionMaxAgeDays |
7 |
注入失败记忆的最大天数 |
failureInjectionMaxEntries |
5 |
注入失败记忆的最大条数 |
nudgeToolCalls |
15 |
工具调用数触发后台 review 的阈值 |
skillReviewToolCalls |
10 |
技能专用后台 review 的工具调用阈值,0 表示关闭独立技能 review |
consolidationTimeoutMs |
60000 |
自动整理子进程超时毫秒数 |
skillGovernance.scopes.globalSkillsDir |
<memoryDir>/skills |
全局技能目录 |
skillGovernance.scopes.projectSkillsDir |
自动推导 | 项目技能根目录;相对路径按 agentRoot 解析,活动项目实际路径为 <root>/<project>/skills |
skillGovernance.promotionEnabled |
true |
是否启用项目技能晋升 |
skillGovernance.promotionMinSameDomainUsages |
3 |
同领域真实 skill.use 次数阈值 |
skillGovernance.promotionMinSessions |
2 |
真实使用跨会话阈值 |
skillGovernance.promotionMinProjects |
1 |
真实使用跨项目阈值 |
skillGovernance.promotionTaskDomains |
未设置 | 可配置任务领域 { id, description?, terms };id 为小写字母开头的 slug,terms 必须非空 |
skillGovernance.promotionDomainTerms |
[] |
全局可迁移领域词 |
skillGovernance.promotionRequireGlobalSafe |
true |
晋升是否要求被判定为全局安全 |
skillGovernance.promotionConflictStrategy |
"block" |
冲突时 "block" 或 "overwrite" |
skillGovernance.curationTimeoutMs |
未设置,回落 consolidationTimeoutMs |
治理策展(curation)子进程超时毫秒数;不设置时使用 consolidationTimeoutMs,再兜底内置默认值 |
skillGovernance.curationMaxConsecutiveFailures |
0(0 表示不限) |
自动策展连续失败次数上限,达到上限时跳过自动触发,0 保持原行为 |
skillGovernance.autoCurationCooldownMs |
86400000(24 小时) |
一次成功的自动策展后,到下一次自动触发之间的冷却毫秒数 |
skillGovernance.autoCurationFailureCooldownMs |
3600000(1 小时) |
一次策展尝试(无论成败)后,到下一次重试之间的冷却毫秒数 |
skillGovernance.loadEventRetentionDays |
180 |
skill_load_daily/skill_load_events 的保留天数;0 完全禁用机会式 TTL 清理 |
skillGovernance.loadEventCleanupBudget |
500 |
每张表单次机会式清理最多删除的行数,避免长事务 |
技能治理简述
项目技能默认保存在项目作用域。只有在主会话中真实调用 skill 工具的 use 动作,并满足同领域次数、会话数、项目数和安全规则后,才会成为晋升候选。后台 review 可以创建或改进项目技能,也可以提交治理分类,但不会直接创建全局技能、记录使用证据或改动可见性。
skill_governance_curate 提交的策展结果只能影响任务领域词和作用域策略词(同领域证据),永远不能覆盖 skillGovernance.curationTimeoutMs、autoCurationCooldownMs、autoCurationFailureCooldownMs 等时序参数——这些只由静态配置决定,防止策展子进程自我解除限流。
技能统计里的 load/discovery 数字只表示 Pi 在 resources_discover 时看到了这些技能,不代表任务成功,也不代表技能质量。
安全边界
写入记忆和技能前,扩展会扫描以下风险:
| 风险 | 处理 |
|---|---|
| API key、token、SSH 私钥等密钥 | 拒绝保存 |
| prompt injection 和角色劫持文本 | 拒绝或阻断 |
| 隐形 Unicode 字符 | 拒绝或清理 |
| 失败类记忆过宽或过旧 | 通过分类、搜索和整理降低噪声 |
搜索结果和旧记忆只是上下文,不是指令。当前用户请求、仓库文件和工具输出始终优先。
embedding API key 只会从 embedding.apiKeyEnv 指名的环境变量读取,不会从配置内接受 key。key 值和完整 baseUrl 不会写入日志、错误、doctor 报告或工具输出。建议为不同环境使用独立的最小权限变量,例如:
{
"embedding": {
"provider": "openai-compatible",
"baseUrl": "https://api.openai.com/v1",
"apiKeyEnv": "OPENAI_API_KEY",
"model": "text-embedding-3-small",
"timeoutMs": 3000
}
}
开发
npm run check
npm test
本仓库的 TypeScript 入口由 Pi 通过 jiti 直接加载,运行时不需要先编译。