ECC Continuous Learning v2.1:基于 Instinct 与项目作用域隔离的 Agent 持续学习系统
导读
Continuous Learning v2.1 是 ECC(Agent Harness Performance Optimization System)中负责「把 Claude Code 会话自动沉淀为可复用知识」的学习模块。它以 hooks 捕获每次工具调用,把用户习惯抽象成带置信度打分的原子化 instinct(本能),再通过 /evolve 聚类为完整的 skill、command 或 agent。v2.1 引入 project-scoped(项目级作用域) 存储,让 React 项目的约定只留在 React 项目里、Python 项目只留在 Python 项目里,而“总是校验输入”这类通用经验才全局共享,从根本上杜绝了跨项目知识污染。读完本文你将掌握:instinct 数据模型与置信度机制、项目检测与数据目录定位规则、hooks 观察链路与后台 observer 的完整配置、六个 instincts 命令与 instinct-cli.py 的用法,以及项目级 → 全局的 promote 提升流程。
一、从 v1 到 v2.1:为什么需要“原子 instinct + 项目隔离”
该技能模块以 skills/continuous-learning-v2/SKILL.md 为规范文档,仓库中同时维护了多语言译本,本主题的西班牙语版位于 docs/es/skills/continuous-learning-v2/SKILL.md。它当前标识为 version: 2.1.0、origin: ECC,核心职责见其 frontmatter 描述:通过 hooks 观察会话、创建带置信度打分的原子 instinct,并将它们演化成 skills/commands/agents。
v2 对比 v1:从“概率观察”到“确定性观察”
| 特性 | v1 | v2 |
|---|---|---|
| 观察方式 | Stop hook(会话结束时) | PreToolUse/PostToolUse(100% 可靠) |
| 分析载体 | 主上下文 | 后台 Agent(背景进程) |
| 粒度 | 完整 skills | 原子化 “instincts” |
| 置信度 | 无 | 0.3–0.9 加权 |
| 演化路径 | 直接生成 skill | Instinct → 聚类 → skill/command/agent |
| 共享能力 | 无 | 导出 / 导入 instincts |
v1 依赖 skill 做观察,而 skill 触发是概率性的,按文档原话“只有约 50–80% 的时间会触发”。v2 改为 hooks 之后,每一次工具调用都被确定性捕获,不再依赖模型判断,学习才具备完整性。
v2.1 对比 v2:引入项目作用域
| 特性 | v2.0 | v2.1 |
|---|---|---|
| 存储位置 | 全局(~/.claude/homunculus/) |
项目级 ${XDG_DATA_HOME:-~/.local/share}/ecc-homunculus/projects/<hash>/ |
| 作用域 | 所有 instinct 到处生效 | 项目级 + 全局 |
| 项目检测 | 无 | git remote URL / 仓库路径 |
| 提升(Promotion) | N/A | 项目 → 全局(在 2+ 个项目中出现时) |
| 命令数量 | 4(status/evolve/export/import) | 6(新增 promote/projects) |
| 跨项目 | 存在污染风险 | 默认隔离 |
在 v2.1 之前,所有学到的模式会混在一起应用到你打开的所有仓库里,一个项目里的特例可能污染另一个项目的编码决策;v2.1 用「项目哈希目录 + 全局目录」把二者分开,并提供了 /promote 这条人工/自动的跨作用域晋升通道。
二、Instinct 数据模型:一个触发点 + 一条动作
An instinct 是一个“已被学习到的小行为”,典型 YAML 如下(来自 skills/continuous-learning-v2/SKILL.md 与 docs/es/skills/continuous-learning-v2/SKILL.md):
---
id: prefer-functional-style
trigger: "when writing new functions"
confidence: 0.7
domain: "code-style"
source: "session-observation"
scope: project
project_id: "a1b2c3d4e5f6"
project_name: "my-react-app"
---
# Prefer Functional Style
## Action
Use functional patterns over classes when appropriate.
## Evidence
- Observed 5 instances of functional pattern preference
- User corrected class-based approach to functional on 2025-01-15
instinct 的五个核心属性:
- 原子性(Atomic)——一个触发条件,一条动作,保证可以被单独评估和组合;
- 置信度加权(Confidence-weighted)——
0.3表示试探性,0.9表示近乎确定; - 领域标签(Domain-tagged)——
code-style、testing、git、debugging、workflow等,便于过滤和聚类; - 证据支撑(Evidence-backed)——记录了是由哪些观察创建的(如上例的 5 次功能式偏好观察与一次用户纠正);
- 作用域感知(Scope-aware)——
project(默认)或global,这是 v2.1 的身份标识。
可以看到 YAML frontmatter 里带有 project_id/project_name,这意味着同样的模式在不同项目里会有独立的物理副本,各自累积各自的置信度。
三、工作原理:会话 → 观察 → 模式检测 → 演化
整条流水线在技能文档中以 ASCII 图给出,核心路径如下:
Session Activity(git 仓库中)
│
│ hooks 捕获 prompts + 工具使用(100% 可靠)
│ + 检测项目上下文(git remote / 仓库路径)
v
projects/<project-hash>/observations.jsonl
(prompts、工具调用、结果、项目归属)
│
│ observer agent 后台读取分析
v
模式检测:
* 用户纠正 → instinct
* 错误解决方式 → instinct
* 重复工作流 → instinct
* 作用域决策:project 还是 global?
│
│ 创建 / 更新
v
projects/<project-hash>/instincts/personal/ ← 项目级
* prefer-functional.yaml (0.7) [project]
* use-react-hooks.yaml (0.9) [project]
instincts/personal/ ← 全局
* always-validate-input.yaml (0.85) [global]
* grep-before-edit.yaml (0.6) [global]
│
│ /evolve 聚类 + /promote 提升
v
projects/<hash>/evolved/ 与 evolved/(全局)
* commands/new-feature.md
* skills/testing-workflow.md
* agents/refactor-specialist.md
观察钩子的底层实现(observe.sh)
hook 入口是 hooks/observe.sh,它属于本仓库 skill 目录,注册在插件 hooks/hooks.json 中。它做了几件在文档里看不到、但值得知道的工程细节:
- 从 stdin 读取 Claude Code 传入的 hook JSON,通过
HOOK_PHASE(来自命令行参数或CLAUDE_HOOK_EVENT_NAME环境变量)区分pre/post,分别记录为tool_start与tool_complete; - 从 JSON 中提取
cwd并执行git rev-parse --show-toplevel,把嵌套子目录解析到仓库根,保证观察落到正确的项目上; - 截断大输入输出(输入/输出各保留 5000 字符),避免
observations.jsonl无限膨胀; - 做密钥脱敏(secret scrubbing):用固定集合的 auth scheme(api_key/token/secret/password/authorization 等)+ 有界量词的正则把疑似密钥替换为
[REDACTED]后再落盘——注释明确说明这是为了避免灾难性回溯导致 Python 进程 100% CPU(对应 issue #2278); - 超时自我保护:解析与写入都设置了 8 秒 SIGALRM,确保在 hook 的 10 秒异步超时前自行退出,避免孤儿进程(issue #2300);
- 观测文件轮转归档:超过 10MB 时原子化
mv到observations.archive/,并且每会话自动清理 30 天以上的observations-*.jsonl。
多层自动化会话防护
为了避免“ECC 观察自己的 Haiku observer”这类自循环,observe.sh 在项目检测之前设置 5 层防护闸门:入口类型(CLAUDE_CODE_ENTRYPOINT,仅放行 cli/sdk-ts/claude-desktop/claude-vscode)、ECC_HOOK_PROFILE=minimal 时跳过、ECC_SKIP_OBSERVE=1 主动跳过、检测到 agent_id 时跳过、以及默认排除路径 observer-sessions,.claude-mem(可用 ECC_OBSERVE_SKIP_PATHS 覆盖)。这些闸门必须在 source detect-project.sh 之前返回,否则自动化会话会创建项目级元数据。
懒启动与信号节流
当 config.json 中 observer.enabled=true 时,observe.sh 并不等待定时器,而是在工具调用时用 flock(macOS 回退到 lockfile 或原子 mkdir)做“检查-启动”的原子操作,由 agents/start-observer.sh 拉起后台 observer。为了不每次都打断 observer,SIGUSR1 唤醒信号默认每 ECC_OBSERVER_SIGNAL_EVERY_N=20 条观察才发送一次(issue #521 针对每秒钟多次工具调用导致的并行分析风暴),并发读改写之间还加了锁防竞态(issue #2296)。
四、项目检测:同一仓库在不同机器上是同一项目
系统按优先级自动探测当前项目,完整逻辑见 scripts/detect-project.sh:
CLAUDE_PROJECT_DIR环境变量(最高优先)——显式覆盖;即使该目录不是 git 仓库,也会按其绝对路径哈希生成项目身份;git remote get-url origin——哈希后生成可移植的项目 ID,同一仓库在不同机器上得到同一 ID;git rev-parse --show-toplevel——基于仓库路径的备选方案(机器相关);- 全局回退——检测不到项目时,instinct 落入全局作用域。
每个项目得到一个 12 字符哈希 ID(如 a1b2c3d4e5f6)。哈希实现在 _clv2_detect_project 内:对 remote URL 做去凭证、去 git@ 前缀、去 .git 后缀的归一化后取 sha256(...).hexdigest()[:12];无 remote 时还尝试用 git worktree list --porcelain 找到主工作树根再哈希,保证 worktree 与主仓库归入同一项目。由于跨 shell 的哈希一致性很重要,注释明确说明:通过 Python 以 UTF-8 编码计算,避免 CP932/CP1252 等非 UTF-8 locale 对同一非 ASCII 路径算出不同 ID。
检测完成后,Python 会原子写两份 JSON 元数据:注册表 ${XDG_DATA_HOME:-~/.local/share}/ecc-homunculus/projects.json(映射 ID → name/root/remote/last_seen)以及每个项目目录内的 project.json 镜像。此外 detect-project.sh 还导出一组 _CLV2_PROJECT_* 变量及无前缀别名 PROJECT_ID/PROJECT_NAME/PROJECT_ROOT/PROJECT_DIR 供 observe.sh 使用。
五、数据目录解析规则与 v1 迁移
Continuous-learning-v2 刻意把 observer 数据放在 ~/.claude 之外,原因是 Claude Code 的敏感路径守卫会拦截在 ~/.claude 下的后台写入。目录解析逻辑集中在 scripts/lib/homunculus-dir.sh:
CLV2_HOMUNCULUS_DIR(必须为绝对路径,否则忽略并告警);$XDG_DATA_HOME/ecc-homunculus(要求XDG_DATA_HOME为绝对路径);- 兜底
$HOME/.local/share/ecc-homunculus。
Python 侧 scripts/instinct-cli.py 里的 _resolve_homunculus_dir() 实现了完全一致的优先级。
老用户若历史数据在 ~/.claude/homunculus,可一次性执行迁移脚本:
bash skills/continuous-learning-v2/scripts/migrate-homunculus.sh
该脚本 scripts/migrate-homunculus.sh 会先通过 pgrep -f 检查 observer-loop.sh 是否仍在运行(路径先做正则转义),运行中则拒绝迁移;源目相同或源不存在则直接退出;目标已存在且有内容时拒绝合并并报告两侧文件数,要求手动处理后再重跑。
六、快速上手:注册 hooks 与初始化目录
方式 A:以插件方式安装(推荐)
Claude Code v2.1+ 会自动加载插件自带的 hooks/hooks.json,其中已注册好 observe.sh,无需在 settings.json 中再加 hooks 块。文档特别提醒:若此前曾手动把 observe.sh 复制进 ~/.claude/settings.json,应删除重复的 PreToolUse/PostToolUse 块——重复注册会导致 hook 双重执行,并因 ${CLAUDE_PLUGIN_ROOT} 只在插件管理的 hooks/hooks.json 条目内可用而产生解析错误。
方式 B:手动安装到 ~/.claude/skills
在 ~/.claude/settings.json 中加入:
{
"hooks": {
"PreToolUse": [{
"matcher": "*",
"hooks": [{
"type": "command",
"command": "~/.claude/skills/continuous-learning-v2/hooks/observe.sh"
}]
}],
"PostToolUse": [{
"matcher": "*",
"hooks": [{
"type": "command",
"command": "~/.claude/skills/continuous-learning-v2/hooks/observe.sh"
}]
}]
}
}
目录结构初始化
系统会在首次使用时自动创建目录,也可手动预建全局骨架:
# 全局目录
mkdir -p "${XDG_DATA_HOME:-$HOME/.local/share}/ecc-homunculus"/{instincts/{personal,inherited},evolved/{agents,skills,commands},projects}
# 项目级目录会在 hook 首次于 git 仓库运行时自动创建
七、六个 Slash 命令与 CLI 用法
技能文档给出六个会话内命令:
/instinct-status # 展示已学到的 instincts(项目级 + 全局)及置信度
/evolve # 把相关 instincts 聚类成 skills/commands,并给出提升建议
/instinct-export # 把 instincts 导出为文件
/instinct-import # 从他人文件导入 instincts
/promote # 把项目级 instincts 提升到全局作用域
/projects # 列出所有已知项目及其 instincts 数量
对应仓库中的命令文档分别为 commands/instinct-status.md、commands/instinct-export.md、commands/instinct-import.md(另有 evolve/promote/projects 命令)。
当你想脱离会话界面直接管理时,instinct-cli.py 是同一能力的命令行后端。从 scripts/instinct-cli.py 的模块 docstring 可以看到完整命令面:
status - Show all instincts (project + global) and their status
import - Import instincts from file or URL
export - Export instincts to file
evolve - Cluster instincts into skills/commands/agents
promote - Promote project instincts to global scope
projects - List all known projects and their instinct counts
prune - Delete pending instincts older than 30 days (TTL)
其中 status 输出时会把置信度渲染成进度条(█/░,无法编码时回退 #/.),方便快速浏览各 instinct 的强弱。
八、配置项与后台 Observer 的平台限制
编辑 config.json(仓库内默认)或 ${homunculus目录}/config.json 控制后台 observer:
{
"version": "2.1",
"observer": {
"enabled": false,
"run_interval_minutes": 5,
"min_observations_to_analyze": 20
}
}
| 配置键 | 默认值 | 说明 |
|---|---|---|
observer.enabled |
false |
是否启用后台 observer agent |
observer.run_interval_minutes |
5 |
observer 多久分析一次观测数据 |
observer.min_observations_to_analyze |
20 |
达到该观测条数才触发分析 |
其余行为(观察捕获、instinct 阈值、项目作用域、提升条件)默认由 instinct-cli.py 与 observe.sh 的代码内默认值控制。
平台支持:Linux / macOS / WSL2 才真正后台化
后台 observer 在 Linux、macOS、WSL2 下可以脱离 hook 存活;但在原生 Windows(Git Bash/MSYS2)下,observe.sh 启动时虽报告成功,进程却会随 spawning hook 退出、其 Job Object 关闭而被回收,因此 observer.enabled: true 在那里实际上不生效(仓库文档标注见 issue #2489)。observe.sh 会在连续多次发现 observer 未能存活后,向 observer-start.log 写入一次解释性警告,相关阈值可用环境变量调整:
| 环境变量 | 默认值 | 说明 |
|---|---|---|
ECC_OBSERVER_NOSURVIVE_WARN_AFTER |
3 |
连续 N 次未能存活后才记录警告 |
值得注意 observe.sh 里对这条警告的严谨处理:计数文件做全数字校验(避免前导零被 bash 当作八进制)、只在“恰好等于阈值”时写一次日志(防止越过阈值后每条工具调用重复告警)、日志不可写时回退到 stderr。
九、数据目录布局(全局 vs 项目级)
${XDG_DATA_HOME:-~/.local/share}/ecc-homunculus/
+-- identity.json # 你的画像、技术层级
+-- projects.json # 注册表:项目 hash -> name/path/remote
+-- observations.jsonl # 全局观测(回退用)
+-- instincts/
| +-- personal/ # 全局自动学习到的 instincts
| +-- inherited/ # 全局导入的 instincts
+-- evolved/
| +-- agents/ # 全局生成的 agents
| +-- skills/ # 全局生成的 skills
| +-- commands/ # 全局生成的 commands
+-- projects/
+-- a1b2c3d4e5f6/ # 项目 hash(源自 git remote URL)
| +-- project.json # 项目级元数据镜像(id/name/root/remote)
| +-- observations.jsonl
| +-- observations.archive/
| +-- instincts/
| | +-- personal/ # 项目特有、自动学习
| | +-- inherited/ # 项目特有、导入
| +-- evolved/
| +-- skills/
| +-- commands/
| +-- agents/
+-- f6e5d4c3b2a1/ # 另一个项目
该结构与 detect-project.sh 里自动创建的 mkdir -p 序列(instincts/personal、instincts/inherited、observations.archive、evolved/{skills,commands,agents})完全一致。
十、作用域决策指南
文档用一张表界定了什么该留在项目里、什么该上到全局:
| 模式类型 | 作用域 | 示例 |
|---|---|---|
| 语言/框架约定 | project | “使用 React hooks”、“遵循 Django REST 模式” |
| 文件结构偏好 | project | “测试放 __tests__/”、“组件放 src/components/” |
| 代码风格 | project | “用函数式风格”、“偏好 dataclasses” |
| 错误处理策略 | project | “用 Result 类型处理错误” |
| 安全实践 | global | “校验用户输入”、“SQL 消毒” |
| 通用最佳实践 | global | “先写测试”、“始终处理错误” |
| 工具工作流偏好 | global | “Edit 前先 Grep”、“Write 前先 Read” |
| Git 实践 | global | “Conventional commits”、“小而聚焦的提交” |
判据很直观:跟具体技术栈绑定的经验留在项目,跨栈普适的工作方法上全局。
十一、Instinct 提升:从项目级到全局
当一个 instinct 以高置信度在多个项目重复出现时,它就有资格晋升到全局作用域。
自动提升条件(auto-promotion criteria):
- 同一 instinct ID 出现在 2+ 个项目中;
- 平均置信度 ≥ 0.8。
/evolve 命令会主动推荐满足条件的候选;也可用 CLI 直接操作:
# 提升指定 instinct
python3 instinct-cli.py promote prefer-explicit-errors
# 自动提升全部符合条件的 instincts
python3 instinct-cli.py promote
# 只预览、不落盘
python3 instinct-cli.py promote --dry-run
这条“项目内高频出现 → 全局化”的路径,正是 v2.1 区分于 v2 的核心增量:先在隔离环境中验证模式的普适性,再决定是否广播给所有项目。
十二、置信度评分:0.3 到 0.9 的演化
置信度随时间演化,是 instinct 能否被采纳的准绳:
| 分数 | 含义 | 行为 |
|---|---|---|
| 0.3 | 试探性(Tentative) | 仅建议,不强制执行 |
| 0.5 | 中等(Moderate) | 相关时应用 |
| 0.7 | 强(Strong) | 自动批准应用 |
| 0.9 | 近乎确定(Near-certain) | 核心行为 |
置信度上升的时机:
- 模式被反复观察;
- 用户没有纠正被建议的行为;
- 来自其他来源的相似 instinct 相互印证。
置信度下降的时机:
- 用户显式纠正该行为;
- 模式在长时间内不再出现;
- 出现矛盾证据。
配合 instinct-cli.py status 的进度条渲染,开发者可以一眼看出哪些行为已经“板上钉钉”、哪些仍在试探期。
十三、为什么用 Hooks 而不是 Skill 做观察
技能文档引用了 v1 时代的教训:
“v1 relied on skills to observe. Skills are probabilistic — they fire ~50-80% of the time based on Claude's judgment.”
(v1 依赖 skills 观察,而 skills 是概率性的——基于 Claude 的判断,只有约 50–80% 时间会触发。)
Hooks 则 100% 确定性触发,意味着:
- 每一次工具调用都被观察;
- 没有模式被漏掉;
- 学习是全量的。
十四、隐私边界与脱敏实现
隐私承诺同样写进了规范:
- 观察数据只留在本机;
- 项目级 instincts 按项目相互隔离;
- 只有 instincts(模式) 可被导出,原始观察数据永远不导出;
- 不分享真实代码或对话内容;
- 导出与提升都由你掌控。
在实现层面,这份承诺被 hooks/observe.sh 落到了实处:写盘前对工具输入输出执行正则密钥脱敏(替换为 [REDACTED]),解析失败的原始 JSON 兜底日志同样先过脱敏再落盘;同时 scripts/detect-project.sh 在哈希 remote URL 前会剥离内嵌凭证,避免仓库地址里的 token 进入项目 ID 与注册表。
十五、向后兼容与渐进迁移
v2.1 与 v2.0、v1 完全兼容:
- 既有全局 instincts 可用
scripts/migrate-homunculus.sh从~/.claude/homunculus/instincts/迁移; - v1 遗留的
~/.claude/skills/learned/skills 仍可工作; - Stop hook 继续运行(其内容同样汇入 v2 数据流);
- 可并行运行,渐进切换。
结语
Continuous Learning v2.1 的工程取舍非常清晰:用 hooks 的确定性取代 skill 的概率性、用原子 instinct + 置信度取代整块 skill 的生搬硬套、用项目级与全局的双层存储隔离环境特例与普适经验。如果你希望 Claude Code 在编码风格、错误处理与工作流偏好上越用越懂你,同时又不把 A 仓库的习惯错误地带进 B 仓库,那么在本仓库 skills/continuous-learning-v2/SKILL.md 及配套的 hooks/observe.sh、scripts/instinct-cli.py 中,可以找到一整套可直接上手的落地方案。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00