npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@youkale/pi-hermes-memory

v0.7.15

Published

🧠 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.

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_dailyskill_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.mdUSER.md 不写 project 字段。failures.md 在项目会话中写真实归属;非项目会话产生的无归属 failure 是全局失败,对所有项目可见。 failure 的容量统计、FIFO 淘汰和自动整理输入只包含当前项目条目与无归属全局 failure;其他项目的 failure 不会被当前会话自动整理或删除。该维护边界不受 projectMemorySharing 影响。

记忆模型

默认模式是 policy-only。启动时系统提示词会得到一段 <memory-policy>,告诉代理什么时候调用 memory_searchsession_searchmemoryskill。完整 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_dailyskill_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 批量写入支持 memoryuserproject,每个 add op 也可带 force,但同一批不能混用项目记忆和全局/用户记忆。命中近邻的 add op 会带结构化提示失败,其余 op 继续按部分提交语义执行。容量触发自动整理时,单条 add 与 batch 都会在整理成功、重新加载文件后以新鲜候选视图复检;batch 保留原始 operation 坐标并重新执行顺序模拟,整理新产生的近邻不会绕过拦截。force: true 的 add 不做该近邻复检。

replace 不改变 Markdown 文件契约:MEMORY.mdUSER.mdfailures.md 只保留当前 active 条目。SQLite 会插入新的 active 行,并把旧行的 superseded_by 指向新行、superseded_at 记为当天;连续 replace 可形成 A→B→C 多级链。replace 合并到同 scope 已有相同正文时会指向该 canonical active 行,不产生 active 重复。remove 与 FIFO eviction 仍物理删除对应 active 镜像,不创建 supersede 节点。

promote / demote 是单条目的显式分层移动,不是复制,也不接受 targetoperations batch 会明确拒绝这两个 action,并提示改为单发。两者都要求活动项目:promote 从项目层定位源,匹配范围与 project replace 完全相同(默认仅 own;projectMemorySharing: true 时可显式匹配可见 foreign 条目);demote 从无归属的全局 memory 层定位源,并写入当前项目。userfailure 不参与。容器部署中全局层就是组织层,因此同一动作也覆盖项目↔组织的分层。

文件移动固定按防丢失顺序执行:先在目标 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_referencedmemories_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 | 可选,memoryuserfailure | | category | 可选,仅用于失败类分类 | | limit | 默认 10,最大 20 | | include_superseded | 默认 falsetrue 时同时返回 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 后,检索流程如下:

  1. 先应用现有 current-project/global/sharing、target、category、active/include_superseded 谓词,得到候选集;向量排序永远不会越过该边界。
  2. 查询文本生成向量;本次 scope 内没有当前模型有效向量的候选,最多批量回填 16 条。失败项保持 NULL,以后搜索可再次机会性回填,不做启动期全量任务。
  3. 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 命中时报告“升级候选:或属组织层通用知识”。
  • 项目 × 全局命中时报告“疑似重复”,建议人工判断去其一,或把不适合全局的知识下沉到项目。
  • userfailure、同 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 不会自动改写条目。人工确认方向后,可单独调用 memorypromote / demote action 处置;项目×项目候选需先切换到要上移条目所属的当前项目。

session_search

默认 sessionSearch.variantlegacy,参数为 queryprojectrolelimit。在设置 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_useprocedure_stepspitfallsverification_steps | | 支持文件有白名单 | write_fileremove_file 只能操作 references/templates/scripts/assets/ 下的支持文件 | | 子会话限制更严 | 子 prompt 只能查看或改写项目技能,不能 usedeletevisibility 或创建全局技能 |

配置

配置文件默认位于:

~/.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
  }
}

不需要把所有字段都写进配置文件;缺失字段会使用默认值。上面的 projectNamellmModelOverridellmThinkingOverride、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 下,并会规范化为目录名。
  • memoryDirprojectsMemoryDir 解析 symlink 后的物理根目录必须互不相同(尚未创建的尾段按最深现存祖先解析);冲突的显式字段会回落默认值并产生启动 warning,/memory-doctor 也会报告仍存在的同根状态。promote/demote 在运行时复用同一物理根身份检查,发现同根会在任何写入或删除前拒绝移动;权限等解析异常保守回落到词法绝对路径判定。
  • projectName 不设置时由 cwd basename 推导;空值、... 或包含路径分隔符、,<>、换行的值会被忽略。
  • embedding.provider 只接受 "off""openai-compatible";非法 provider、URL、环境变量名、空 model 或非正 timeout 会使整段 embedding 配置回落到 off。
  • openai-compatible 默认 baseUrlhttps://api.openai.com/v1、默认 modeltext-embedding-3-small、默认 timeoutMs3000apiKeyEnv 必须指名一个环境变量;未配置名称或该变量没有值时 provider 视同 off,并由 /memory-doctor 提示。
  • autoConsolidate 只用于兼容旧配置;显式设置 memoryOverflowStrategy 时以后者为准。
  • skillGovernance.scopes.globalSkillsDirskillGovernance.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 覆盖,支持 offminimallowmediumhighxhigh | | 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.curationTimeoutMsautoCurationCooldownMsautoCurationFailureCooldownMs 等时序参数——这些只由静态配置决定,防止策展子进程自我解除限流。

技能统计里的 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 直接加载,运行时不需要先编译。