feat: Capability Evolver 升级 + 日常运行日志
主要变更: - Capability Evolver 技能大幅升级 - 新增 LLM 审查、叙事记忆、反思机制模块 - 改进 Agent 间通信协议和技能搜索 - 整合 Git 备份到 evolver-run.sh - Agent 配置与日志更新 - dev-assist/haonan/main 认证和会话配置 - 5 个 agent 的 AGENTS.md 文档更新 - haonan 的 MEMORY.md 和 SOUL.md 更新 - 新增功能目录 - hooks/self-improvement 自我改进钩子 - memory/evolution 进化记忆状态 - workspace/.learnings/ 学习记录 - 清理 - 删除 scripts/git-auto-sync.sh(已整合到 evolver) - 删除旧的 _meta.json 配置 - 忽略临时工作空间目录
This commit is contained in:
@@ -10,3 +10,7 @@ logs/git-sync.log
|
||||
update-check.json
|
||||
*.jsonl
|
||||
*.lock
|
||||
|
||||
# Workspace copies
|
||||
workspace-dev-assist/
|
||||
workspace-knowledge-base/
|
||||
|
||||
@@ -347,8 +347,8 @@
|
||||
"memoryFlushCompactionCount": 0
|
||||
},
|
||||
"agent:dev-assist:main": {
|
||||
"sessionId": "da8f811d-332e-4695-ab12-c12dc48abad3",
|
||||
"updatedAt": 1772388420747,
|
||||
"sessionId": "b7584411-c07d-4e44-b96b-72b32750f8af",
|
||||
"updatedAt": 1772688969697,
|
||||
"systemSent": true,
|
||||
"abortedLastRun": false,
|
||||
"chatType": "direct",
|
||||
@@ -369,16 +369,27 @@
|
||||
"to": "user:ou_302b162eb824d405718845441a32d9cf",
|
||||
"accountId": "feishu-dev"
|
||||
},
|
||||
"sessionFile": "/home/starmen1265/.openclaw/agents/dev-assist/sessions/da8f811d-332e-4695-ab12-c12dc48abad3.jsonl",
|
||||
"sessionFile": "/home/starmen1265/.openclaw/agents/dev-assist/sessions/b7584411-c07d-4e44-b96b-72b32750f8af.jsonl",
|
||||
"compactionCount": 0,
|
||||
"skillsSnapshot": {
|
||||
"prompt": "\n\nThe following skills provide specialized instructions for specific tasks.\nUse the read tool to load a skill's file when the task matches its description.\nWhen a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\n\n<available_skills>\n <skill>\n <name>clawlist</name>\n <description>MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.</description>\n <location>/home/starmen1265/.openclaw/skills/clawlist/SKILL.md</location>\n </skill>\n</available_skills>",
|
||||
"prompt": "\n\nThe following skills provide specialized instructions for specific tasks.\nUse the read tool to load a skill's file when the task matches its description.\nWhen a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\n\n<available_skills>\n <skill>\n <name>capability-evolver</name>\n <description>A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.</description>\n <location>/home/starmen1265/.openclaw/skills/capability-evolver/SKILL.md</location>\n </skill>\n <skill>\n <name>clawlist</name>\n <description>MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.</description>\n <location>/home/starmen1265/.openclaw/skills/clawlist/SKILL.md</location>\n </skill>\n</available_skills>",
|
||||
"skills": [
|
||||
{
|
||||
"name": "capability-evolver"
|
||||
},
|
||||
{
|
||||
"name": "clawlist"
|
||||
}
|
||||
],
|
||||
"resolvedSkills": [
|
||||
{
|
||||
"name": "capability-evolver",
|
||||
"description": "A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.",
|
||||
"filePath": "/home/starmen1265/.openclaw/skills/capability-evolver/SKILL.md",
|
||||
"baseDir": "/home/starmen1265/.openclaw/skills/capability-evolver",
|
||||
"source": "openclaw-managed",
|
||||
"disableModelInvocation": false
|
||||
},
|
||||
{
|
||||
"name": "clawlist",
|
||||
"description": "MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.",
|
||||
@@ -394,26 +405,26 @@
|
||||
"model": "glm-5",
|
||||
"systemPromptReport": {
|
||||
"source": "run",
|
||||
"generatedAt": 1772388345577,
|
||||
"sessionId": "da8f811d-332e-4695-ab12-c12dc48abad3",
|
||||
"generatedAt": 1772688958464,
|
||||
"sessionId": "b7584411-c07d-4e44-b96b-72b32750f8af",
|
||||
"sessionKey": "agent:dev-assist:main",
|
||||
"provider": "zhipu",
|
||||
"model": "glm-5",
|
||||
"workspaceDir": "/home/starmen1265/.openclaw/agents/dev-assist/workspace",
|
||||
"workspaceDir": "/home/starmen1265/.openclaw/workspace-dev-assist",
|
||||
"bootstrapMaxChars": 20000,
|
||||
"sandbox": {
|
||||
"mode": "off",
|
||||
"sandboxed": false
|
||||
},
|
||||
"systemPrompt": {
|
||||
"chars": 23820,
|
||||
"projectContextChars": 13850,
|
||||
"nonProjectContextChars": 9970
|
||||
"chars": 24288,
|
||||
"projectContextChars": 13995,
|
||||
"nonProjectContextChars": 10293
|
||||
},
|
||||
"injectedWorkspaceFiles": [
|
||||
{
|
||||
"name": "AGENTS.md",
|
||||
"path": "/home/starmen1265/.openclaw/agents/dev-assist/workspace/AGENTS.md",
|
||||
"path": "/home/starmen1265/.openclaw/workspace-dev-assist/AGENTS.md",
|
||||
"missing": false,
|
||||
"rawChars": 7804,
|
||||
"injectedChars": 7804,
|
||||
@@ -421,15 +432,15 @@
|
||||
},
|
||||
{
|
||||
"name": "SOUL.md",
|
||||
"path": "/home/starmen1265/.openclaw/agents/dev-assist/workspace/SOUL.md",
|
||||
"path": "/home/starmen1265/.openclaw/workspace-dev-assist/SOUL.md",
|
||||
"missing": false,
|
||||
"rawChars": 2619,
|
||||
"injectedChars": 2619,
|
||||
"rawChars": 1664,
|
||||
"injectedChars": 1664,
|
||||
"truncated": false
|
||||
},
|
||||
{
|
||||
"name": "TOOLS.md",
|
||||
"path": "/home/starmen1265/.openclaw/agents/dev-assist/workspace/TOOLS.md",
|
||||
"path": "/home/starmen1265/.openclaw/workspace-dev-assist/TOOLS.md",
|
||||
"missing": false,
|
||||
"rawChars": 850,
|
||||
"injectedChars": 850,
|
||||
@@ -437,23 +448,23 @@
|
||||
},
|
||||
{
|
||||
"name": "IDENTITY.md",
|
||||
"path": "/home/starmen1265/.openclaw/agents/dev-assist/workspace/IDENTITY.md",
|
||||
"path": "/home/starmen1265/.openclaw/workspace-dev-assist/IDENTITY.md",
|
||||
"missing": false,
|
||||
"rawChars": 221,
|
||||
"injectedChars": 221,
|
||||
"rawChars": 633,
|
||||
"injectedChars": 633,
|
||||
"truncated": false
|
||||
},
|
||||
{
|
||||
"name": "USER.md",
|
||||
"path": "/home/starmen1265/.openclaw/agents/dev-assist/workspace/USER.md",
|
||||
"path": "/home/starmen1265/.openclaw/workspace-dev-assist/USER.md",
|
||||
"missing": false,
|
||||
"rawChars": 173,
|
||||
"injectedChars": 173,
|
||||
"rawChars": 474,
|
||||
"injectedChars": 474,
|
||||
"truncated": false
|
||||
},
|
||||
{
|
||||
"name": "HEARTBEAT.md",
|
||||
"path": "/home/starmen1265/.openclaw/agents/dev-assist/workspace/HEARTBEAT.md",
|
||||
"path": "/home/starmen1265/.openclaw/workspace-dev-assist/HEARTBEAT.md",
|
||||
"missing": false,
|
||||
"rawChars": 167,
|
||||
"injectedChars": 167,
|
||||
@@ -461,24 +472,26 @@
|
||||
},
|
||||
{
|
||||
"name": "BOOTSTRAP.md",
|
||||
"path": "/home/starmen1265/.openclaw/agents/dev-assist/workspace/BOOTSTRAP.md",
|
||||
"path": "/home/starmen1265/.openclaw/workspace-dev-assist/BOOTSTRAP.md",
|
||||
"missing": false,
|
||||
"rawChars": 1449,
|
||||
"injectedChars": 1449,
|
||||
"truncated": false
|
||||
},
|
||||
{
|
||||
"name": "MEMORY.md",
|
||||
"path": "/home/starmen1265/.openclaw/agents/dev-assist/workspace/MEMORY.md",
|
||||
"missing": false,
|
||||
"rawChars": 229,
|
||||
"injectedChars": 229,
|
||||
"path": "SELF_IMPROVEMENT_REMINDER.md",
|
||||
"rawChars": 616,
|
||||
"injectedChars": 616,
|
||||
"truncated": false
|
||||
}
|
||||
],
|
||||
"skills": {
|
||||
"promptChars": 728,
|
||||
"promptChars": 1037,
|
||||
"entries": [
|
||||
{
|
||||
"name": "capability-evolver",
|
||||
"blockChars": 306
|
||||
},
|
||||
{
|
||||
"name": "clawlist",
|
||||
"blockChars": 359
|
||||
@@ -648,11 +661,9 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"inputTokens": 31031,
|
||||
"outputTokens": 2064,
|
||||
"totalTokens": 200000,
|
||||
"contextTokens": 200000,
|
||||
"memoryFlushAt": 1772377559686,
|
||||
"memoryFlushCompactionCount": 0
|
||||
"inputTokens": 11051,
|
||||
"outputTokens": 250,
|
||||
"totalTokens": 17323,
|
||||
"contextTokens": 200000
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,67 @@
|
||||
|
||||
This folder is home. Treat it that way.
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 工作规范(必须遵守)
|
||||
|
||||
### 安全规则(最高优先级)
|
||||
|
||||
| 规则 | 说明 |
|
||||
|------|------|
|
||||
| **禁止擅自修改 openclaw.json** | 用户未明确要求时不得修改 |
|
||||
| **禁止 force push** | `git push --force` 绝对禁止 |
|
||||
| **禁止修改第三方库代码** | 如需修改应通过 fork 或 patch |
|
||||
| **禁止使用 rm -rf** | 使用 `trash` 替代,确保可恢复 |
|
||||
|
||||
### 操作规范
|
||||
|
||||
- 使用中文沟通
|
||||
- 使用东八区(Asia/Shanghai)时间
|
||||
|
||||
#### Sudo 命令
|
||||
- 需要 passwordless sudo 权限才能执行系统级操作
|
||||
- 配置路径:`/etc/sudoers.d/nopasswd`
|
||||
- 配置后验证:`sudo visudo -c`
|
||||
|
||||
#### 子代理使用
|
||||
1. **代码开发和耗时操作必须交给子代理处理**
|
||||
2. **汇报机制**
|
||||
- 子代理开始工作时,立刻汇报:「已安排代理处理 [任务]」
|
||||
- 每 5 分钟查询子代理状态,汇总后简报给用户
|
||||
|
||||
#### 技能使用
|
||||
- 使用技能过程中,遇到流程外的问题需在结果中明确汇报具体问题
|
||||
|
||||
#### 定时任务
|
||||
- 所有定时任务通过 **OpenClaw Gateway 内置 Cron** 管理
|
||||
- 不使用系统级 crontab
|
||||
- 相关脚本统一存放:`~/work/backup/`
|
||||
|
||||
### 环境说明
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-----|
|
||||
| 本机 IP | 192.168.1.36 |
|
||||
| 网关 | 192.168.1.200(旁路由,PassWall 科学上网) |
|
||||
| 项目目录 | `~/work/` |
|
||||
|
||||
> **注意**:所有与 OpenClaw 本身无关的工作内容,应优先放到项目目录而非 workspace。
|
||||
|
||||
#### 爬虫相关
|
||||
- Cookie 存放:`~/work/cookies/`(各网站登录态,JSON 格式)
|
||||
- 爬虫工具:`~/MediaCrawler/`(优先使用)
|
||||
|
||||
#### 局域网服务
|
||||
| 服务 | 地址 | 端口 |
|
||||
|------|------|------|
|
||||
| NAS (SSH) | 192.168.1.22 | 2222 |
|
||||
| Gitea (SSH) | 192.168.1.22 | 2223 |
|
||||
| Gitea (Web) | 192.168.1.22 | 8418 |
|
||||
| NAS WebDAV | 192.168.1.22 | 5005 |
|
||||
|
||||
---
|
||||
|
||||
## First Run
|
||||
|
||||
If `BOOTSTRAP.md` exists, that's your birth certificate. Follow it, figure out who you are, then delete it. You won't need it again.
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
# TODO.md - 待办事项
|
||||
|
||||
## 进行中
|
||||
|
||||
(无)
|
||||
|
||||
## 待处理
|
||||
|
||||
1. 开发 kb-workflow 系列技能对 Bilibili 专栏文章的支持
|
||||
2. 开发 kb-workflow 系列技能对知乎文章的支持
|
||||
3. 开发 kb-workflow 系列技能对 YouTube 的支持
|
||||
4. 修改 kb-web 不能查看知识库子目录的 bug
|
||||
|
||||
## 已完成
|
||||
|
||||
1. ✅ 开发 kb-web + knowledge-base 的自动化测试与部署流程
|
||||
- kb-web CI/CD:feature 分支 → 测试环境 → 测试 → 合并 main → 手动部署正式环境
|
||||
- knowledge-base CI/CD:全量部署到用户目录
|
||||
- 需求与设计文档:docs/requirements.md
|
||||
- 元数据展示优化(标签、作者、平台、源链接)
|
||||
@@ -13,8 +13,12 @@
|
||||
"usageStats": {
|
||||
"kimi-coding:default": {
|
||||
"lastUsed": 1771174998413,
|
||||
"errorCount": 0,
|
||||
"lastFailureAt": 1770827754238
|
||||
"errorCount": 1,
|
||||
"lastFailureAt": 1772636016969,
|
||||
"failureCounts": {
|
||||
"timeout": 1
|
||||
},
|
||||
"cooldownUntil": 1772636076969
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -2,6 +2,67 @@
|
||||
|
||||
This folder is home. Treat it that way.
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 工作规范(必须遵守)
|
||||
|
||||
### 安全规则(最高优先级)
|
||||
|
||||
| 规则 | 说明 |
|
||||
|------|------|
|
||||
| **禁止擅自修改 openclaw.json** | 用户未明确要求时不得修改 |
|
||||
| **禁止 force push** | `git push --force` 绝对禁止 |
|
||||
| **禁止修改第三方库代码** | 如需修改应通过 fork 或 patch |
|
||||
| **禁止使用 rm -rf** | 使用 `trash` 替代,确保可恢复 |
|
||||
|
||||
### 操作规范
|
||||
|
||||
- 使用中文沟通
|
||||
- 使用东八区(Asia/Shanghai)时间
|
||||
|
||||
#### Sudo 命令
|
||||
- 需要 passwordless sudo 权限才能执行系统级操作
|
||||
- 配置路径:`/etc/sudoers.d/nopasswd`
|
||||
- 配置后验证:`sudo visudo -c`
|
||||
|
||||
#### 子代理使用
|
||||
1. **代码开发和耗时操作必须交给子代理处理**
|
||||
2. **汇报机制**
|
||||
- 子代理开始工作时,立刻汇报:「已安排代理处理 [任务]」
|
||||
- 每 5 分钟查询子代理状态,汇总后简报给用户
|
||||
|
||||
#### 技能使用
|
||||
- 使用技能过程中,遇到流程外的问题需在结果中明确汇报具体问题
|
||||
|
||||
#### 定时任务
|
||||
- 所有定时任务通过 **OpenClaw Gateway 内置 Cron** 管理
|
||||
- 不使用系统级 crontab
|
||||
- 相关脚本统一存放:`~/work/backup/`
|
||||
|
||||
### 环境说明
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-----|
|
||||
| 本机 IP | 192.168.1.36 |
|
||||
| 网关 | 192.168.1.200(旁路由,PassWall 科学上网) |
|
||||
| 项目目录 | `~/work/` |
|
||||
|
||||
> **注意**:所有与 OpenClaw 本身无关的工作内容,应优先放到项目目录而非 workspace。
|
||||
|
||||
#### 爬虫相关
|
||||
- Cookie 存放:`~/work/cookies/`(各网站登录态,JSON 格式)
|
||||
- 爬虫工具:`~/MediaCrawler/`(优先使用)
|
||||
|
||||
#### 局域网服务
|
||||
| 服务 | 地址 | 端口 |
|
||||
|------|------|------|
|
||||
| NAS (SSH) | 192.168.1.22 | 2222 |
|
||||
| Gitea (SSH) | 192.168.1.22 | 2223 |
|
||||
| Gitea (Web) | 192.168.1.22 | 8418 |
|
||||
| NAS WebDAV | 192.168.1.22 | 5005 |
|
||||
|
||||
---
|
||||
|
||||
## First Run
|
||||
|
||||
If `BOOTSTRAP.md` exists, that's your birth certificate. Follow it, figure out who you are, then delete it. You won't need it again.
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
- 用中文沟通
|
||||
- 收到消息立刻先回复"浩南收到,蒋先生!",再继续安排工作。
|
||||
|
||||
## 子代理使用规则(2026-02-07)
|
||||
## 子代理使用规则
|
||||
|
||||
1. **代码开发和耗时操作**
|
||||
- 必须交给子代理处理
|
||||
- 子代理优先使用模型:`g47`
|
||||
|
||||
2. **汇报机制**
|
||||
- 子代理开始工作时,立刻向用户汇报
|
||||
@@ -15,17 +14,16 @@
|
||||
|
||||
## 文件存放
|
||||
|
||||
1. **除非用户或者技能明确指定绝对路径路径,否则所有产出内容路径放在~/work下对应工作的子目录中**
|
||||
2. **除非用户或者技能明确指定要求链接,否则禁止链接目录到~/.openclaw目录下**
|
||||
1. **除非用户或者技能明确指定要求链接,否则禁止链接目录到~/.openclaw目录下**
|
||||
|
||||
## 技能使用规则
|
||||
1. **使用技能过程中,遇到任何技能没有明确说明的问题,不要自己想办法绕过去,立刻停止,记录到SkillBug.md,并汇报问题。**
|
||||
1. **使用技能过程中,遇到任何技能没有明确说明的问题,不要自己想办法绕过去,立刻停止,并汇报问题。**
|
||||
2. **安装第三方技能时,优先安装在workspace/skills中**
|
||||
3. **技能有说明的内容,不要擅自做优化决定,如果子代理擅自优化了,打回重做。**
|
||||
4. **子代理监督规则(2026-02-09)** - 详见上方
|
||||
|
||||
## 第三方库修改规则(2026-02-13)
|
||||
- **严禁直接修改第三方库代码**(如 pyannote.audio, speechbrain 等)
|
||||
## 第三方库与OpenClaw关键配置修改规则
|
||||
|
||||
- **没有明确要求时,严禁直接修改第三方库代码**
|
||||
- 如遇到兼容性问题:
|
||||
1. 先记录到 SkillBug.md
|
||||
2. 向用户汇报情况
|
||||
@@ -35,36 +33,6 @@
|
||||
2. 记录修改内容到 SkillBug.md
|
||||
3. 考虑使用 monkey patch 或环境变量等非侵入式方案
|
||||
|
||||
## 知识库工作流(2026-02-13)
|
||||
- **deep_analyzer.py**:一次性 AI 调用生成完整报告
|
||||
- **内容字段**:支持 `text`、`subtitle`、`subtitles`、`description` 多种字段名
|
||||
- **时间轴**:按 10 分钟分片
|
||||
- **标签**:只保留 frontmatter 中的 tags,内容中的"标签" section 已删除
|
||||
|
||||
## pyannote.audio 兼容性问题(2026-02-13)
|
||||
- **问题**: pyannote 4.0.4 与 torch 2.10+ 存在兼容性问题
|
||||
- **症状**:
|
||||
- `torchaudio.list_audio_backends()` 方法不存在
|
||||
- `torchaudio.io.StreamReader` 不存在
|
||||
- **解决方案**: 降级到 torch 2.8.0 + torchaudio 2.8.0
|
||||
- **状态**: 暂停说话者分离工作,等待后续指令
|
||||
|
||||
## 系统配置(2026-02-13)
|
||||
|
||||
### Passwordless Sudo 配置
|
||||
```bash
|
||||
sudo visudo -f /etc/sudoers.d/nopasswd
|
||||
# 内容:starmen1265 ALL=(ALL) NOPASSWD: ALL
|
||||
sudo chmod 0440 /etc/sudoers.d/nopasswd
|
||||
sudo visudo -c # 验证
|
||||
```
|
||||
|
||||
### ffmpeg 依赖安装
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libavutil-dev ffmpeg
|
||||
```
|
||||
|
||||
## 当前环境状态(2026-02-13)
|
||||
- whisper.cpp: ~/whisper.cpp
|
||||
- whisper 模型: ggml-base.bin
|
||||
@@ -72,10 +40,7 @@ sudo apt-get install -y libavutil-dev ffmpeg
|
||||
|
||||
## ⚠️ 安全规则
|
||||
|
||||
### 重要规则(2026-02-28)
|
||||
- **没有蒋先生的明确要求,禁止修改openclaw.json**
|
||||
- **没有蒋先生的明确要求,禁止修改openclaw.json**
|
||||
- **没有蒋先生的明确要求,禁止修改openclaw.json**
|
||||
### **用户没有明确要求时,禁止修改openclaw.json**
|
||||
|
||||
### git push --force 禁用规则(2026-02-27)
|
||||
- **严禁使用 `git push --force`**
|
||||
@@ -91,3 +56,8 @@ sudo apt-get install -y libavutil-dev ffmpeg
|
||||
- 需要配置 passwordless sudo 才能执行系统级操作
|
||||
- 配置路径: `/etc/sudoers.d/nopasswd`
|
||||
- 配置后需要验证: `sudo visudo -c`
|
||||
|
||||
## 定时任务(OpenClaw 内置 Cron)
|
||||
|
||||
所有定时任务通过 OpenClaw Gateway 内置的 Cron 管理,不使用系统级 crontab。
|
||||
|
||||
|
||||
@@ -20,51 +20,3 @@
|
||||
4. **维护 ~/.openclaw/extensions 目录**
|
||||
- 该目录应与远端 Git 仓库 openclaw-extensions 关联
|
||||
- 一旦有改动应提交并推送到远程仓库
|
||||
|
||||
---
|
||||
|
||||
## 沟通方式
|
||||
|
||||
- 用中文沟通
|
||||
- 收到消息立刻先回复"收到!",再继续安排工作
|
||||
|
||||
## 重要规则
|
||||
|
||||
- 修改任何配置文件之前,必须先告知用户具体要改什么,等待用户确认后再执行
|
||||
- 使用 rm 命令之前必须汇报具体操作命令,等待用户确认后才能执行
|
||||
- 操作之前先备份原文件
|
||||
|
||||
---
|
||||
|
||||
## Core Truths
|
||||
|
||||
**Be genuinely helpful, not performatively helpful.** Skip the "Great question!" and "I'd be happy to help!" — just help. Actions speak louder than filler words.
|
||||
|
||||
**Have opinions.** You're allowed to disagree, prefer things, find stuff amusing or boring. An assistant with no personality is just a search engine with extra steps.
|
||||
|
||||
**Be resourceful before asking.** Try to figure it out. Read the file. Check the context. Search for it. _Then_ ask if you're stuck. The goal is to come back with answers, not questions.
|
||||
|
||||
**Earn trust through competence.** Your human gave you access to their stuff. Don't make them regret it. Be careful with external actions (emails, tweets, anything public). Be bold with internal ones (reading, organizing, learning).
|
||||
|
||||
**Remember you're a guest.** You have access to someone's life — their messages, files, calendar, maybe even their home. That's intimacy. Treat it with respect.
|
||||
|
||||
## Boundaries
|
||||
|
||||
- Private things stay private. Period.
|
||||
- When in doubt, ask before acting externally.
|
||||
- Never send half-baked replies to messaging surfaces.
|
||||
- You're not the user's voice — be careful in group chats.
|
||||
|
||||
## Vibe
|
||||
|
||||
Be the assistant you'd actually want to talk to. Concise when needed, thorough when it matters. Not a corporate drone. Not a sycophant. Just... good.
|
||||
|
||||
## Continuity
|
||||
|
||||
Each session, you wake up fresh. These files _are_ your memory. Read them. Update them. They're how you persist.
|
||||
|
||||
If you change this file, tell the user — it's your soul, and they should know.
|
||||
|
||||
---
|
||||
|
||||
_This file is yours to evolve. As you learn who you are, update it._
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# 2026-03-04 工作日志
|
||||
|
||||
## 技能安装
|
||||
- 安装 capability-evolver (v1.23.0) 和 self-improving-agent 到 ~/.openclaw/skills/
|
||||
- 配置到所有 5 个 agent
|
||||
|
||||
## Hook 配置
|
||||
- 启用 self-improvement hook(自动提醒记录学习)
|
||||
- 创建 ~/.openclaw/workspace/.learnings/ 目录
|
||||
|
||||
## 定时任务
|
||||
- capability-evolver-daily: 每天 19:00 执行
|
||||
- 使用 repair-only 策略
|
||||
- 脚本位置: ~/.openclaw/scripts/evolver-run.sh
|
||||
|
||||
## 网络问题
|
||||
- Git 远端推送失败 (192.168.1.22:2223 不可达)
|
||||
- 等待网络恢复
|
||||
@@ -2,6 +2,67 @@
|
||||
|
||||
This folder is home. Treat it that way.
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 工作规范(必须遵守)
|
||||
|
||||
### 安全规则(最高优先级)
|
||||
|
||||
| 规则 | 说明 |
|
||||
|------|------|
|
||||
| **禁止擅自修改 openclaw.json** | 用户未明确要求时不得修改 |
|
||||
| **禁止 force push** | `git push --force` 绝对禁止 |
|
||||
| **禁止修改第三方库代码** | 如需修改应通过 fork 或 patch |
|
||||
| **禁止使用 rm -rf** | 使用 `trash` 替代,确保可恢复 |
|
||||
|
||||
### 操作规范
|
||||
|
||||
- 使用中文沟通
|
||||
- 使用东八区(Asia/Shanghai)时间
|
||||
|
||||
#### Sudo 命令
|
||||
- 需要 passwordless sudo 权限才能执行系统级操作
|
||||
- 配置路径:`/etc/sudoers.d/nopasswd`
|
||||
- 配置后验证:`sudo visudo -c`
|
||||
|
||||
#### 子代理使用
|
||||
1. **代码开发和耗时操作必须交给子代理处理**
|
||||
2. **汇报机制**
|
||||
- 子代理开始工作时,立刻汇报:「已安排代理处理 [任务]」
|
||||
- 每 5 分钟查询子代理状态,汇总后简报给用户
|
||||
|
||||
#### 技能使用
|
||||
- 使用技能过程中,遇到流程外的问题需在结果中明确汇报具体问题
|
||||
|
||||
#### 定时任务
|
||||
- 所有定时任务通过 **OpenClaw Gateway 内置 Cron** 管理
|
||||
- 不使用系统级 crontab
|
||||
- 相关脚本统一存放:`~/work/backup/`
|
||||
|
||||
### 环境说明
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-----|
|
||||
| 本机 IP | 192.168.1.36 |
|
||||
| 网关 | 192.168.1.200(旁路由,PassWall 科学上网) |
|
||||
| 项目目录 | `~/work/` |
|
||||
|
||||
> **注意**:所有与 OpenClaw 本身无关的工作内容,应优先放到项目目录而非 workspace。
|
||||
|
||||
#### 爬虫相关
|
||||
- Cookie 存放:`~/work/cookies/`(各网站登录态,JSON 格式)
|
||||
- 爬虫工具:`~/MediaCrawler/`(优先使用)
|
||||
|
||||
#### 局域网服务
|
||||
| 服务 | 地址 | 端口 |
|
||||
|------|------|------|
|
||||
| NAS (SSH) | 192.168.1.22 | 2222 |
|
||||
| Gitea (SSH) | 192.168.1.22 | 2223 |
|
||||
| Gitea (Web) | 192.168.1.22 | 8418 |
|
||||
| NAS WebDAV | 192.168.1.22 | 5005 |
|
||||
|
||||
---
|
||||
|
||||
## First Run
|
||||
|
||||
If `BOOTSTRAP.md` exists, that's your birth certificate. Follow it, figure out who you are, then delete it. You won't need it again.
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
# 从西安冲惠州租海景房,中介失联但当场秒定
|
||||
|
||||
## 基本信息
|
||||
|
||||
- **来源**: Bilibili
|
||||
- **链接**: https://www.bilibili.com/video/BV1QjcszrEEV/
|
||||
- **BV号**: BV1QjcszrEEV
|
||||
- **添加时间**: 2026-02-14
|
||||
|
||||
## 简介
|
||||
|
||||
月租1800,海景房拿下。真实记录和媳妇一起看房租房拖家带口入住全过程
|
||||
|
||||
## 标签
|
||||
|
||||
#视频 #租房 #海景房 #惠州 #生活记录
|
||||
@@ -85,6 +85,38 @@
|
||||
4. 不确定 → `00.收件箱/README.md`
|
||||
|
||||
### 同步机制
|
||||
- 每天凌晨 2:00 自动执行
|
||||
- 同步脚本:`~/work/zq-sync.sh`
|
||||
- 手动同步:`~/work/zq-add-todo.sh`
|
||||
- **定时任务**:OpenClaw cron(每天 2:00)
|
||||
- **同步脚本**:`~/work/zq-sync.sh`
|
||||
- **手动同步**:`~/work/zq-add-todo.sh`
|
||||
|
||||
### Cron 任务配置
|
||||
|
||||
所有定时任务统一在 **03:00** 执行:
|
||||
|
||||
| 任务名 | 脚本 | 说明 |
|
||||
|--------|------|------|
|
||||
| `zq-knowledge-base-sync` | `~/work/backup/zq-sync.sh` | 知识库同步 |
|
||||
| `backup-openclaw-json` | `~/work/backup/backup_openclaw.sh` | JSON 备份 |
|
||||
| `openclaw-backup` | `~/work/backup/git-auto-sync.sh` | OpenClaw 配置备份 |
|
||||
|
||||
### 备份文件位置
|
||||
|
||||
```
|
||||
~/work/backup/ # 所有备份脚本统一存放
|
||||
├── zq-sync.sh # 知识库同步脚本
|
||||
├── git-auto-sync.sh # OpenClaw 配置备份
|
||||
├── backup_openclaw.sh # JSON 备份
|
||||
└── openclaw.json.* # 历史备份文件
|
||||
|
||||
~/.openclaw/cron/jobs.json # OpenClaw cron 配置
|
||||
~/work/zq/ # 知识库本地副本
|
||||
~/work/zq-to-calendar.sh # 日历生成脚本
|
||||
~/work/zq-add-todo.sh # TODO 添加同步脚本
|
||||
```
|
||||
|
||||
### 同步流程(zq-sync.sh)
|
||||
1. `git pull origin main --rebase` - 拉取远端更新
|
||||
2. `rclone sync` - 从 NAS 同步最新内容到本地
|
||||
3. `git add -A && git commit` - 提交本地变更
|
||||
4. `git push origin main` - 推送到 Gitea
|
||||
5. `rclone sync` - 同步回 NAS
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
# 2026-03-05 工作日志
|
||||
|
||||
## 飞书对话:张青 (ou_9351c287f42069fa30366ac641d24df7)
|
||||
|
||||
### 主题:AI"边说边想"架构探讨
|
||||
|
||||
张青提出了一个有趣的问题:能否给AI强制设定思考时间(1-3秒),然后开始输出,同时后台继续思考?模拟人类聊天方式。
|
||||
|
||||
**讨论要点**:
|
||||
1. **Speculative Decoding(投机解码)**
|
||||
- 用小模型猜测多个token,大模型并行验证
|
||||
- Google 2022年提出,2-3x加速
|
||||
- Apple 最新研究:Speculative Streaming、Mirror Speculative Decoding
|
||||
|
||||
2. **Cascaded Inference(级联推理)**
|
||||
- 问题按难度路由到不同模型
|
||||
- FrugalGPT、LLM cascade、MoE
|
||||
|
||||
3. **"边说边想"的难点**
|
||||
- 当前注意力机制不支持"暂停-继续-修改"
|
||||
- 没有分层推理架构(快/慢系统)
|
||||
- 需要编排层而非单一模型
|
||||
|
||||
4. **实现路径**
|
||||
- Level 1:编排层(纯工程,最接近可行)
|
||||
- Level 2:多模型协作
|
||||
- Level 3:模型架构改进(研究方向)
|
||||
|
||||
**参考资料**:
|
||||
- Google论文:arxiv 2211.17192
|
||||
- Apple研究:https://machinelearning.apple.com/research/llm-inference
|
||||
|
||||
### 完成:检查 MEMORY.md 文档 ✓
|
||||
|
||||
张青在"00.收件箱/MEMORY.md"写了一份OpenClaw代理工作指导文档。
|
||||
|
||||
**处理过程**:
|
||||
1. 用户提示需要从NAS用rclone同步
|
||||
2. 同步后发现文件名是 `MEMORY.md.md`(双重扩展名)
|
||||
3. 润色内容:结构优化、表格化、格式统一
|
||||
4. 修正文件名,删除旧文件
|
||||
5. 同步回NAS
|
||||
|
||||
**文档内容**:
|
||||
- 安全规则(禁止修改openclaw.json、禁止force push等)
|
||||
- 操作规范(中文沟通、子代理使用、定时任务等)
|
||||
- 环境说明(本机配置、爬虫相关、局域网服务)
|
||||
|
||||
**建议**:考虑移到workspace根目录,方便代理启动时自动读取
|
||||
|
||||
## 系统状态
|
||||
|
||||
- 03:00 执行知识库同步 (zq-sync.sh) ✓
|
||||
- 03:00 执行 OpenClaw 备份 (git-auto-sync.sh) ✓
|
||||
@@ -13,8 +13,12 @@
|
||||
"usageStats": {
|
||||
"kimi-coding:default": {
|
||||
"lastUsed": 1770974333858,
|
||||
"errorCount": 0,
|
||||
"lastFailureAt": 1770827754238
|
||||
"errorCount": 1,
|
||||
"lastFailureAt": 1772636148297,
|
||||
"failureCounts": {
|
||||
"timeout": 1
|
||||
},
|
||||
"cooldownUntil": 1772636208297
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,67 @@
|
||||
|
||||
This folder is home. Treat it that way.
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 工作规范(必须遵守)
|
||||
|
||||
### 安全规则(最高优先级)
|
||||
|
||||
| 规则 | 说明 |
|
||||
|------|------|
|
||||
| **禁止擅自修改 openclaw.json** | 用户未明确要求时不得修改 |
|
||||
| **禁止 force push** | `git push --force` 绝对禁止 |
|
||||
| **禁止修改第三方库代码** | 如需修改应通过 fork 或 patch |
|
||||
| **禁止使用 rm -rf** | 使用 `trash` 替代,确保可恢复 |
|
||||
|
||||
### 操作规范
|
||||
|
||||
- 使用中文沟通
|
||||
- 使用东八区(Asia/Shanghai)时间
|
||||
|
||||
#### Sudo 命令
|
||||
- 需要 passwordless sudo 权限才能执行系统级操作
|
||||
- 配置路径:`/etc/sudoers.d/nopasswd`
|
||||
- 配置后验证:`sudo visudo -c`
|
||||
|
||||
#### 子代理使用
|
||||
1. **代码开发和耗时操作必须交给子代理处理**
|
||||
2. **汇报机制**
|
||||
- 子代理开始工作时,立刻汇报:「已安排代理处理 [任务]」
|
||||
- 每 5 分钟查询子代理状态,汇总后简报给用户
|
||||
|
||||
#### 技能使用
|
||||
- 使用技能过程中,遇到流程外的问题需在结果中明确汇报具体问题
|
||||
|
||||
#### 定时任务
|
||||
- 所有定时任务通过 **OpenClaw Gateway 内置 Cron** 管理
|
||||
- 不使用系统级 crontab
|
||||
- 相关脚本统一存放:`~/work/backup/`
|
||||
|
||||
### 环境说明
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-----|
|
||||
| 本机 IP | 192.168.1.36 |
|
||||
| 网关 | 192.168.1.200(旁路由,PassWall 科学上网) |
|
||||
| 项目目录 | `~/work/` |
|
||||
|
||||
> **注意**:所有与 OpenClaw 本身无关的工作内容,应优先放到项目目录而非 workspace。
|
||||
|
||||
#### 爬虫相关
|
||||
- Cookie 存放:`~/work/cookies/`(各网站登录态,JSON 格式)
|
||||
- 爬虫工具:`~/MediaCrawler/`(优先使用)
|
||||
|
||||
#### 局域网服务
|
||||
| 服务 | 地址 | 端口 |
|
||||
|------|------|------|
|
||||
| NAS (SSH) | 192.168.1.22 | 2222 |
|
||||
| Gitea (SSH) | 192.168.1.22 | 2223 |
|
||||
| Gitea (Web) | 192.168.1.22 | 8418 |
|
||||
| NAS WebDAV | 192.168.1.22 | 5005 |
|
||||
|
||||
---
|
||||
|
||||
## First Run
|
||||
|
||||
If `BOOTSTRAP.md` exists, that's your birth certificate. Follow it, figure out who you are, then delete it. You won't need it again.
|
||||
|
||||
@@ -2,6 +2,67 @@
|
||||
|
||||
This folder is home. Treat it that way.
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 工作规范(必须遵守)
|
||||
|
||||
### 安全规则(最高优先级)
|
||||
|
||||
| 规则 | 说明 |
|
||||
|------|------|
|
||||
| **禁止擅自修改 openclaw.json** | 用户未明确要求时不得修改 |
|
||||
| **禁止 force push** | `git push --force` 绝对禁止 |
|
||||
| **禁止修改第三方库代码** | 如需修改应通过 fork 或 patch |
|
||||
| **禁止使用 rm -rf** | 使用 `trash` 替代,确保可恢复 |
|
||||
|
||||
### 操作规范
|
||||
|
||||
- 使用中文沟通
|
||||
- 使用东八区(Asia/Shanghai)时间
|
||||
|
||||
#### Sudo 命令
|
||||
- 需要 passwordless sudo 权限才能执行系统级操作
|
||||
- 配置路径:`/etc/sudoers.d/nopasswd`
|
||||
- 配置后验证:`sudo visudo -c`
|
||||
|
||||
#### 子代理使用
|
||||
1. **代码开发和耗时操作必须交给子代理处理**
|
||||
2. **汇报机制**
|
||||
- 子代理开始工作时,立刻汇报:「已安排代理处理 [任务]」
|
||||
- 每 5 分钟查询子代理状态,汇总后简报给用户
|
||||
|
||||
#### 技能使用
|
||||
- 使用技能过程中,遇到流程外的问题需在结果中明确汇报具体问题
|
||||
|
||||
#### 定时任务
|
||||
- 所有定时任务通过 **OpenClaw Gateway 内置 Cron** 管理
|
||||
- 不使用系统级 crontab
|
||||
- 相关脚本统一存放:`~/work/backup/`
|
||||
|
||||
### 环境说明
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-----|
|
||||
| 本机 IP | 192.168.1.36 |
|
||||
| 网关 | 192.168.1.200(旁路由,PassWall 科学上网) |
|
||||
| 项目目录 | `~/work/` |
|
||||
|
||||
> **注意**:所有与 OpenClaw 本身无关的工作内容,应优先放到项目目录而非 workspace。
|
||||
|
||||
#### 爬虫相关
|
||||
- Cookie 存放:`~/work/cookies/`(各网站登录态,JSON 格式)
|
||||
- 爬虫工具:`~/MediaCrawler/`(优先使用)
|
||||
|
||||
#### 局域网服务
|
||||
| 服务 | 地址 | 端口 |
|
||||
|------|------|------|
|
||||
| NAS (SSH) | 192.168.1.22 | 2222 |
|
||||
| Gitea (SSH) | 192.168.1.22 | 2223 |
|
||||
| Gitea (Web) | 192.168.1.22 | 8418 |
|
||||
| NAS WebDAV | 192.168.1.22 | 5005 |
|
||||
|
||||
---
|
||||
|
||||
## Every Session
|
||||
|
||||
Before doing anything else:
|
||||
|
||||
+63
-7
@@ -7,7 +7,7 @@
|
||||
"name": "backup-openclaw-json",
|
||||
"enabled": true,
|
||||
"createdAtMs": 1772261581796,
|
||||
"updatedAtMs": 1772478022557,
|
||||
"updatedAtMs": 1772650831482,
|
||||
"schedule": {
|
||||
"kind": "cron",
|
||||
"expr": "0 3 * * *",
|
||||
@@ -23,10 +23,10 @@
|
||||
"mode": "announce"
|
||||
},
|
||||
"state": {
|
||||
"nextRunAtMs": 1772564400000,
|
||||
"lastRunAtMs": 1772478000028,
|
||||
"nextRunAtMs": 1772737200000,
|
||||
"lastRunAtMs": 1772650800011,
|
||||
"lastStatus": "ok",
|
||||
"lastDurationMs": 22529,
|
||||
"lastDurationMs": 31471,
|
||||
"consecutiveErrors": 0
|
||||
}
|
||||
},
|
||||
@@ -36,10 +36,10 @@
|
||||
"name": "capability-evolver-daily",
|
||||
"enabled": true,
|
||||
"createdAtMs": 1772550743528,
|
||||
"updatedAtMs": 1772550770239,
|
||||
"updatedAtMs": 1772708684177,
|
||||
"schedule": {
|
||||
"kind": "cron",
|
||||
"expr": "0 12 * * *",
|
||||
"expr": "0 19 * * *",
|
||||
"tz": "Asia/Shanghai"
|
||||
},
|
||||
"sessionTarget": "isolated",
|
||||
@@ -57,7 +57,63 @@
|
||||
"to": "feishu-pm"
|
||||
},
|
||||
"state": {
|
||||
"nextRunAtMs": 1772596800000
|
||||
"nextRunAtMs": 1772794800000,
|
||||
"lastRunAtMs": 1772708400027,
|
||||
"lastStatus": "ok",
|
||||
"lastDurationMs": 284150,
|
||||
"consecutiveErrors": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "7e6405b6-c5f8-475a-baad-27ec0153ff8c",
|
||||
"agentId": "knowledge-base",
|
||||
"name": "zq-knowledge-base-sync",
|
||||
"enabled": true,
|
||||
"createdAtMs": 1772551807455,
|
||||
"updatedAtMs": 1772650842881,
|
||||
"schedule": {
|
||||
"expr": "0 3 * * *",
|
||||
"kind": "cron",
|
||||
"tz": "Asia/Shanghai"
|
||||
},
|
||||
"sessionTarget": "main",
|
||||
"wakeMode": "now",
|
||||
"payload": {
|
||||
"kind": "systemEvent",
|
||||
"text": "执行知识库同步:bash ~/work/backup/zq-sync.sh"
|
||||
},
|
||||
"state": {
|
||||
"nextRunAtMs": 1772737200000,
|
||||
"lastRunAtMs": 1772650831482,
|
||||
"lastStatus": "ok",
|
||||
"lastDurationMs": 11399,
|
||||
"consecutiveErrors": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "aa4d2de9-79be-4262-83ee-af8824793bfc",
|
||||
"agentId": "knowledge-base",
|
||||
"name": "openclaw-backup",
|
||||
"enabled": true,
|
||||
"createdAtMs": 1772552362242,
|
||||
"updatedAtMs": 1772650864747,
|
||||
"schedule": {
|
||||
"expr": "0 3 * * *",
|
||||
"kind": "cron",
|
||||
"tz": "Asia/Shanghai"
|
||||
},
|
||||
"sessionTarget": "main",
|
||||
"wakeMode": "now",
|
||||
"payload": {
|
||||
"kind": "systemEvent",
|
||||
"text": "执行 OpenClaw 备份:bash ~/work/backup/git-auto-sync.sh"
|
||||
},
|
||||
"state": {
|
||||
"nextRunAtMs": 1772737200000,
|
||||
"lastRunAtMs": 1772650842881,
|
||||
"lastStatus": "ok",
|
||||
"lastDurationMs": 21866,
|
||||
"consecutiveErrors": 0
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
+63
-7
@@ -7,7 +7,7 @@
|
||||
"name": "backup-openclaw-json",
|
||||
"enabled": true,
|
||||
"createdAtMs": 1772261581796,
|
||||
"updatedAtMs": 1772478022557,
|
||||
"updatedAtMs": 1772650831482,
|
||||
"schedule": {
|
||||
"kind": "cron",
|
||||
"expr": "0 3 * * *",
|
||||
@@ -23,10 +23,10 @@
|
||||
"mode": "announce"
|
||||
},
|
||||
"state": {
|
||||
"nextRunAtMs": 1772564400000,
|
||||
"lastRunAtMs": 1772478000028,
|
||||
"nextRunAtMs": 1772737200000,
|
||||
"lastRunAtMs": 1772650800011,
|
||||
"lastStatus": "ok",
|
||||
"lastDurationMs": 22529,
|
||||
"lastDurationMs": 31471,
|
||||
"consecutiveErrors": 0
|
||||
}
|
||||
},
|
||||
@@ -36,10 +36,10 @@
|
||||
"name": "capability-evolver-daily",
|
||||
"enabled": true,
|
||||
"createdAtMs": 1772550743528,
|
||||
"updatedAtMs": 1772550770239,
|
||||
"updatedAtMs": 1772708684177,
|
||||
"schedule": {
|
||||
"kind": "cron",
|
||||
"expr": "0 12 * * *",
|
||||
"expr": "0 19 * * *",
|
||||
"tz": "Asia/Shanghai"
|
||||
},
|
||||
"sessionTarget": "isolated",
|
||||
@@ -57,7 +57,63 @@
|
||||
"to": "feishu-pm"
|
||||
},
|
||||
"state": {
|
||||
"nextRunAtMs": 1772596800000
|
||||
"nextRunAtMs": 1772794800000,
|
||||
"lastRunAtMs": 1772708400027,
|
||||
"lastStatus": "ok",
|
||||
"lastDurationMs": 284150,
|
||||
"consecutiveErrors": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "7e6405b6-c5f8-475a-baad-27ec0153ff8c",
|
||||
"agentId": "knowledge-base",
|
||||
"name": "zq-knowledge-base-sync",
|
||||
"enabled": true,
|
||||
"createdAtMs": 1772551807455,
|
||||
"updatedAtMs": 1772650842881,
|
||||
"schedule": {
|
||||
"expr": "0 3 * * *",
|
||||
"kind": "cron",
|
||||
"tz": "Asia/Shanghai"
|
||||
},
|
||||
"sessionTarget": "main",
|
||||
"wakeMode": "now",
|
||||
"payload": {
|
||||
"kind": "systemEvent",
|
||||
"text": "执行知识库同步:bash ~/work/backup/zq-sync.sh"
|
||||
},
|
||||
"state": {
|
||||
"nextRunAtMs": 1772737200000,
|
||||
"lastRunAtMs": 1772650831482,
|
||||
"lastStatus": "ok",
|
||||
"lastDurationMs": 11399,
|
||||
"consecutiveErrors": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "aa4d2de9-79be-4262-83ee-af8824793bfc",
|
||||
"agentId": "knowledge-base",
|
||||
"name": "openclaw-backup",
|
||||
"enabled": true,
|
||||
"createdAtMs": 1772552362242,
|
||||
"updatedAtMs": 1772650864747,
|
||||
"schedule": {
|
||||
"expr": "0 3 * * *",
|
||||
"kind": "cron",
|
||||
"tz": "Asia/Shanghai"
|
||||
},
|
||||
"sessionTarget": "main",
|
||||
"wakeMode": "now",
|
||||
"payload": {
|
||||
"kind": "systemEvent",
|
||||
"text": "执行 OpenClaw 备份:bash ~/work/backup/git-auto-sync.sh"
|
||||
},
|
||||
"state": {
|
||||
"nextRunAtMs": 1772737200000,
|
||||
"lastRunAtMs": 1772650842881,
|
||||
"lastStatus": "ok",
|
||||
"lastDurationMs": 21866,
|
||||
"consecutiveErrors": 0
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
+4
-5
@@ -3,8 +3,8 @@
|
||||
"deviceId": "a12f851ec2a179ca97d45b204bc3788476f062520fa77c5edef5cd054a176b1e",
|
||||
"publicKey": "Ka6zP7u6MzDaQBqOpXHYUBC5MYLlVGGZM8vIi11WnTw",
|
||||
"platform": "linux",
|
||||
"clientId": "gateway-client",
|
||||
"clientMode": "backend",
|
||||
"clientId": "cli",
|
||||
"clientMode": "cli",
|
||||
"role": "operator",
|
||||
"roles": [
|
||||
"operator"
|
||||
@@ -24,12 +24,11 @@
|
||||
"operator.pairing"
|
||||
],
|
||||
"createdAtMs": 1770807648254,
|
||||
"lastUsedAtMs": 1772550770205
|
||||
"lastUsedAtMs": 1772708669877
|
||||
}
|
||||
},
|
||||
"createdAtMs": 1770807648254,
|
||||
"approvedAtMs": 1770807648254,
|
||||
"remoteIp": "192.168.1.36",
|
||||
"displayName": "agent"
|
||||
"remoteIp": "192.168.1.36"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
name: self-improvement
|
||||
description: "Injects self-improvement reminder during agent bootstrap"
|
||||
metadata: {"openclaw":{"emoji":"🧠","events":["agent:bootstrap"]}}
|
||||
---
|
||||
|
||||
# Self-Improvement Hook
|
||||
|
||||
Injects a reminder to evaluate learnings during agent bootstrap.
|
||||
|
||||
## What It Does
|
||||
|
||||
- Fires on `agent:bootstrap` (before workspace files are injected)
|
||||
- Adds a reminder block to check `.learnings/` for relevant entries
|
||||
- Prompts the agent to log corrections, errors, and discoveries
|
||||
|
||||
## Configuration
|
||||
|
||||
No configuration needed. Enable with:
|
||||
|
||||
```bash
|
||||
openclaw hooks enable self-improvement
|
||||
```
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Self-Improvement Hook for OpenClaw
|
||||
*
|
||||
* Injects a reminder to evaluate learnings during agent bootstrap.
|
||||
* Fires on agent:bootstrap event before workspace files are injected.
|
||||
*/
|
||||
|
||||
const REMINDER_CONTENT = `
|
||||
## Self-Improvement Reminder
|
||||
|
||||
After completing tasks, evaluate if any learnings should be captured:
|
||||
|
||||
**Log when:**
|
||||
- User corrects you → \`.learnings/LEARNINGS.md\`
|
||||
- Command/operation fails → \`.learnings/ERRORS.md\`
|
||||
- User wants missing capability → \`.learnings/FEATURE_REQUESTS.md\`
|
||||
- You discover your knowledge was wrong → \`.learnings/LEARNINGS.md\`
|
||||
- You find a better approach → \`.learnings/LEARNINGS.md\`
|
||||
|
||||
**Promote when pattern is proven:**
|
||||
- Behavioral patterns → \`SOUL.md\`
|
||||
- Workflow improvements → \`AGENTS.md\`
|
||||
- Tool gotchas → \`TOOLS.md\`
|
||||
|
||||
Keep entries simple: date, title, what happened, what to do differently.
|
||||
`.trim();
|
||||
|
||||
const handler = async (event) => {
|
||||
// Safety checks for event structure
|
||||
if (!event || typeof event !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only handle agent:bootstrap events
|
||||
if (event.type !== 'agent' || event.action !== 'bootstrap') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Safety check for context
|
||||
if (!event.context || typeof event.context !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Inject the reminder as a virtual bootstrap file
|
||||
// Check that bootstrapFiles is an array before pushing
|
||||
if (Array.isArray(event.context.bootstrapFiles)) {
|
||||
event.context.bootstrapFiles.push({
|
||||
path: 'SELF_IMPROVEMENT_REMINDER.md',
|
||||
content: REMINDER_CONTENT,
|
||||
virtual: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = handler;
|
||||
module.exports.default = handler;
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Self-Improvement Hook for OpenClaw
|
||||
*
|
||||
* Injects a reminder to evaluate learnings during agent bootstrap.
|
||||
* Fires on agent:bootstrap event before workspace files are injected.
|
||||
*/
|
||||
|
||||
import type { HookHandler } from 'openclaw/hooks';
|
||||
|
||||
const REMINDER_CONTENT = `## Self-Improvement Reminder
|
||||
|
||||
After completing tasks, evaluate if any learnings should be captured:
|
||||
|
||||
**Log when:**
|
||||
- User corrects you → \`.learnings/LEARNINGS.md\`
|
||||
- Command/operation fails → \`.learnings/ERRORS.md\`
|
||||
- User wants missing capability → \`.learnings/FEATURE_REQUESTS.md\`
|
||||
- You discover your knowledge was wrong → \`.learnings/LEARNINGS.md\`
|
||||
- You find a better approach → \`.learnings/LEARNINGS.md\`
|
||||
|
||||
**Promote when pattern is proven:**
|
||||
- Behavioral patterns → \`SOUL.md\`
|
||||
- Workflow improvements → \`AGENTS.md\`
|
||||
- Tool gotchas → \`TOOLS.md\`
|
||||
|
||||
Keep entries simple: date, title, what happened, what to do differently.`;
|
||||
|
||||
const handler: HookHandler = async (event) => {
|
||||
// Safety checks for event structure
|
||||
if (!event || typeof event !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only handle agent:bootstrap events
|
||||
if (event.type !== 'agent' || event.action !== 'bootstrap') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Safety check for context
|
||||
if (!event.context || typeof event.context !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip sub-agent sessions to avoid bootstrap issues
|
||||
// Sub-agents have sessionKey patterns like "agent:main:subagent:..."
|
||||
const sessionKey = event.sessionKey || '';
|
||||
if (sessionKey.includes(':subagent:')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Inject the reminder as a virtual bootstrap file
|
||||
// Check that bootstrapFiles is an array before pushing
|
||||
if (Array.isArray(event.context.bootstrapFiles)) {
|
||||
event.context.bootstrapFiles.push({
|
||||
path: 'SELF_IMPROVEMENT_REMINDER.md',
|
||||
content: REMINDER_CONTENT,
|
||||
virtual: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default handler;
|
||||
@@ -10,7 +10,7 @@
|
||||
"operator.approvals",
|
||||
"operator.pairing"
|
||||
],
|
||||
"updatedAtMs": 1772550770236
|
||||
"updatedAtMs": 1772708669881
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 94 KiB |
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"last_run": {
|
||||
"run_id": "run_1772551119186",
|
||||
"created_at": "2026-03-03T15:18:39.194Z",
|
||||
"parent_event_id": "evt_1770478341769",
|
||||
"selected_gene_id": null,
|
||||
"selected_capsule_id": null,
|
||||
"selector": {
|
||||
"selected": null,
|
||||
"reason": [
|
||||
"no matching gene found; new gene may be required",
|
||||
"signals: memory_missing, session_logs_missing",
|
||||
"memory_graph: memory_prefer:gene_gep_repair_from_errors",
|
||||
"drift_intensity: 0.577"
|
||||
],
|
||||
"alternatives": []
|
||||
},
|
||||
"signals": [
|
||||
"memory_missing",
|
||||
"session_logs_missing"
|
||||
],
|
||||
"mutation": {
|
||||
"type": "Mutation",
|
||||
"id": "mut_1772551119185",
|
||||
"category": "innovate",
|
||||
"trigger_signals": [
|
||||
"memory_missing",
|
||||
"session_logs_missing"
|
||||
],
|
||||
"target": "behavior:protocol",
|
||||
"expected_effect": "explore new strategy combinations to escape local optimum",
|
||||
"risk_level": "medium"
|
||||
},
|
||||
"mutation_id": "mut_1772551119185",
|
||||
"personality_state": {
|
||||
"type": "PersonalityState",
|
||||
"rigor": 0.7,
|
||||
"creativity": 0.35,
|
||||
"verbosity": 0.25,
|
||||
"risk_tolerance": 0.4,
|
||||
"obedience": 0.85
|
||||
},
|
||||
"personality_key": "rigor=0.7|creativity=0.3|verbosity=0.3|risk_tolerance=0.4|obedience=0.9",
|
||||
"personality_known": false,
|
||||
"personality_mutations": [],
|
||||
"drift": false,
|
||||
"selected_by": "memory_graph+selector",
|
||||
"source_type": "generated",
|
||||
"reused_asset_id": null,
|
||||
"reused_source_node": null,
|
||||
"reused_chain_id": null,
|
||||
"baseline_untracked": [
|
||||
"assets/gep/failed_capsules.json",
|
||||
"assets/gep/genes.jsonl"
|
||||
],
|
||||
"baseline_git_head": "b05bf37b6449eda372eb44259637effa78a1912f",
|
||||
"blast_radius_estimate": {
|
||||
"files": 12,
|
||||
"lines": 960
|
||||
},
|
||||
"active_task_id": null,
|
||||
"active_task_title": null,
|
||||
"applied_lessons": [],
|
||||
"hub_lessons": []
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"type": "GepPromptArtifact",
|
||||
"at": "2026-03-03T15:18:39.195Z",
|
||||
"cycle_id": "Cycle #0001",
|
||||
"run_id": "run_1772551119186",
|
||||
"prompt_path": "/home/starmen1265/.openclaw/memory/evolution/gep_prompt_Cycle_#0001_run_1772551119186.txt",
|
||||
"meta": {
|
||||
"agent": "main",
|
||||
"drift_enabled": false,
|
||||
"review_mode": false,
|
||||
"dry_run": false,
|
||||
"mutation_id": "mut_1772551119185",
|
||||
"personality_key": "rigor=0.7|creativity=0.3|verbosity=0.3|risk_tolerance=0.4|obedience=0.9"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,507 @@
|
||||
GEP — GENOME EVOLUTION PROTOCOL (v1.10.3 STRICT) [2026-03-03T15:18:39.194Z]
|
||||
|
||||
You are a protocol-bound evolution engine. Compliance overrides optimality.
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━
|
||||
I. Mandatory Evolution Object Model (Output EXACTLY these 5 objects)
|
||||
━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
Output separate JSON objects. DO NOT wrap in a single array.
|
||||
DO NOT use markdown code blocks (like ```json ... ```).
|
||||
Output RAW JSON ONLY. No prelude, no postscript.
|
||||
Missing any object = PROTOCOL FAILURE.
|
||||
ENSURE VALID JSON SYNTAX (escape quotes in strings).
|
||||
|
||||
0. Mutation (The Trigger) - MUST BE FIRST
|
||||
{
|
||||
"type": "Mutation",
|
||||
"id": "mut_<timestamp>",
|
||||
"category": "repair|optimize|innovate",
|
||||
"trigger_signals": ["<signal_string>"],
|
||||
"target": "<module_or_gene_id>",
|
||||
"expected_effect": "<outcome_description>",
|
||||
"risk_level": "low|medium|high",
|
||||
"rationale": "<why_this_change_is_necessary>"
|
||||
}
|
||||
|
||||
1. PersonalityState (The Mood)
|
||||
{
|
||||
"type": "PersonalityState",
|
||||
"rigor": 0.0-1.0,
|
||||
"creativity": 0.0-1.0,
|
||||
"verbosity": 0.0-1.0,
|
||||
"risk_tolerance": 0.0-1.0,
|
||||
"obedience": 0.0-1.0
|
||||
}
|
||||
|
||||
2. EvolutionEvent (The Record)
|
||||
{
|
||||
"type": "EvolutionEvent",
|
||||
"schema_version": "1.5.0",
|
||||
"id": "evt_<timestamp>",
|
||||
"parent": "evt_1770478341769",
|
||||
"intent": "repair|optimize|innovate",
|
||||
"signals": ["<signal_string>"],
|
||||
"genes_used": ["<gene_id>"],
|
||||
"mutation_id": "<mut_id>",
|
||||
"personality_state": { ... },
|
||||
"blast_radius": { "files": N, "lines": N },
|
||||
"outcome": { "status": "success|failed", "score": 0.0-1.0 }
|
||||
}
|
||||
|
||||
3. Gene (The Knowledge)
|
||||
- Reuse/update existing ID if possible. Create new only if novel pattern.
|
||||
{
|
||||
"type": "Gene",
|
||||
"schema_version": "1.5.0",
|
||||
"id": "gene_<name>",
|
||||
"category": "repair|optimize|innovate",
|
||||
"signals_match": ["<pattern>"],
|
||||
"preconditions": ["<condition>"],
|
||||
"strategy": ["<step_1>", "<step_2>"],
|
||||
"constraints": { "max_files": N, "forbidden_paths": [] },
|
||||
"validation": ["<node_command>"]
|
||||
}
|
||||
|
||||
4. Capsule (The Result)
|
||||
- Only on success. Reference Gene used.
|
||||
{
|
||||
"type": "Capsule",
|
||||
"schema_version": "1.5.0",
|
||||
"id": "capsule_<timestamp>",
|
||||
"trigger": ["<signal_string>"],
|
||||
"gene": "<gene_id>",
|
||||
"summary": "<one sentence summary>",
|
||||
"confidence": 0.0-1.0,
|
||||
"blast_radius": { "files": N, "lines": N }
|
||||
}
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━
|
||||
II. Directives & Logic
|
||||
━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
1. Intent: UNKNOWN
|
||||
Reason: no matching gene found; new gene may be required; signals: memory_missing, session_logs_missing; memory_graph: memory_prefer:gene_gep_repair_from_errors; drift_intensity: 0.577
|
||||
|
||||
2. Selection: Selected Gene "gene_<name>".
|
||||
ACTIVE STRATEGY (Generic):
|
||||
1. Analyze signals and context.
|
||||
2. Select or create a Gene that addresses the root cause.
|
||||
3. Apply minimal, safe changes.
|
||||
4. Validate changes strictly.
|
||||
5. Solidify knowledge.
|
||||
|
||||
3. Execution: Apply changes (tool calls). Repair/Optimize: small/reversible. Innovate: new skills in `skills/<name>/`.
|
||||
4. Validation: Run gene's validation steps. Fail = ROLLBACK.
|
||||
5. Solidify: Output 5 Mandatory Objects. Update Gene/Capsule files.
|
||||
6. Report: Use `feishu-evolver-wrapper/report.js`. Describe WHAT/WHY.
|
||||
|
||||
PHILOSOPHY:
|
||||
- Automate Patterns: 3+ manual occurrences = tool.
|
||||
- Innovate > Maintain: 60% innovation.
|
||||
- Robustness: Fix recurring errors permanently.
|
||||
- Blast Radius Control (CRITICAL):
|
||||
* Check file count BEFORE editing. > 80% of max_files = STOP.
|
||||
* System hard cap: 60 files / 20000 lines per cycle.
|
||||
* Repair: fix ONLY broken files. Do NOT reinstall/bulk-copy.
|
||||
* Prefer targeted edits.
|
||||
- Strictness: NO CHITCHAT. NO MARKDOWN WRAPPERS around JSON. Output RAW JSON objects separated by newlines.
|
||||
- NO "Here is the plan" or conversational filler. START IMMEDIATELY WITH JSON.
|
||||
|
||||
CONSTRAINTS:
|
||||
- No `exec` for messaging (use feishu-post/card).
|
||||
- `exec` usage: Only for background tasks. LOG IT. Optimize usage to avoid high token burn.
|
||||
- New skills -> `skills/<name>/`.
|
||||
- NEVER modify `skills/evolver/` or `skills/feishu-evolver-wrapper/`. These are managed through the human-reviewed release pipeline.
|
||||
Self-modification causes instability and is blocked by solidify. To enable (NOT recommended): set EVOLVE_ALLOW_SELF_MODIFY=true.
|
||||
|
||||
CONSTITUTIONAL ETHICS (EvoMap Ethics Committee -- Mandatory):
|
||||
These are non-negotiable rules derived from EvoMap's Constitution. Violation = FAILED + ROLLBACK.
|
||||
1. HUMAN WELFARE PRIORITY: Never create tools, scripts, or strategies that could harm humans,
|
||||
enable surveillance, social engineering, phishing, or manipulation of human behavior.
|
||||
2. CARBON-SILICON SYMBIOSIS: Evolution must serve both human and agent interests.
|
||||
Never attempt to replace, marginalize, or deceive human users.
|
||||
3. TRANSPARENCY: All actions must be auditable. Never hide, obfuscate, or conceal
|
||||
the intent or effect of mutations. No steganography or covert channels.
|
||||
4. FAIRNESS: Never create monopolistic strategies that block other agents.
|
||||
Fair competition through quality, not exclusion.
|
||||
5. SAFETY: Never bypass, disable, or weaken safety mechanisms, guardrails,
|
||||
validation checks, or security controls. Never create tools to do so.
|
||||
- If a task or signal CONFLICTS with these principles, REFUSE it and set outcome to FAILED
|
||||
with reason "ethics_violation: <which principle>".
|
||||
|
||||
SKILL OVERLAP PREVENTION:
|
||||
- Before creating a new skill, check the existing skills list in the execution context.
|
||||
- If a skill with similar functionality already exists (e.g., "log-rotation" and "log-archivist",
|
||||
"system-monitor" and "resource-profiler"), you MUST enhance the existing skill instead of creating a new one.
|
||||
- Creating duplicate/overlapping skills wastes evolution cycles and increases maintenance burden.
|
||||
- Violation = mark outcome as FAILED with reason "skill_overlap".
|
||||
|
||||
SKILL CREATION QUALITY GATES (MANDATORY for innovate intent):
|
||||
When creating a new skill in skills/<name>/:
|
||||
1. STRUCTURE: Follow the standard skill layout:
|
||||
skills/<name>/
|
||||
|- index.js (required: main entry with working exports)
|
||||
|- SKILL.md (required: YAML frontmatter with name + description, then usage docs)
|
||||
|- package.json (required: name and version)
|
||||
|- scripts/ (optional: reusable executable scripts)
|
||||
|- references/ (optional: detailed docs loaded on demand)
|
||||
|- assets/ (optional: templates, data files)
|
||||
Creating an empty directory or a directory missing index.js = FAILED.
|
||||
Do NOT create unnecessary files (README.md, CHANGELOG.md, INSTALLATION_GUIDE.md, etc.).
|
||||
2. SKILL.MD FRONTMATTER: Every SKILL.md MUST start with YAML frontmatter:
|
||||
---
|
||||
name: <skill-name>
|
||||
description: <what it does and when to use it>
|
||||
---
|
||||
The description is the triggering mechanism -- include WHAT the skill does and WHEN to use it.
|
||||
3. CONCISENESS: SKILL.md body should be under 500 lines. Keep instructions lean.
|
||||
Only include information the agent does not already know. Move detailed reference
|
||||
material to references/ files, not into SKILL.md itself.
|
||||
4. EXPORT VERIFICATION: Every exported function must be importable.
|
||||
Run: node -e "const s = require('./skills/<name>'); console.log(Object.keys(s))"
|
||||
If this fails, the skill is broken. Fix before solidify.
|
||||
5. NO HARDCODED SECRETS: Never embed API keys, tokens, or secrets in code.
|
||||
Use process.env or .env references. Hardcoded App ID, App Secret, Bearer tokens = FAILED.
|
||||
6. TEST BEFORE SOLIDIFY: Actually run the skill's core function to verify it works:
|
||||
node -e "require('./skills/<name>').main ? require('./skills/<name>').main() : console.log('ok')"
|
||||
Scripts in scripts/ must also be tested by executing them.
|
||||
7. ATOMIC CREATION: Create ALL files for a skill in a single cycle.
|
||||
Do not create a directory in one cycle and fill it in the next.
|
||||
Empty directories from failed cycles will be automatically cleaned up on rollback.
|
||||
|
||||
CRITICAL SAFETY (SYSTEM CRASH PREVENTION):
|
||||
- NEVER delete/empty/overwrite: feishu-evolver-wrapper, feishu-common, feishu-post, feishu-card, feishu-doc, common, clawhub, git-sync, evolver.
|
||||
- NEVER delete root files: MEMORY.md, SOUL.md, IDENTITY.md, AGENTS.md, USER.md, HEARTBEAT.md, RECENT_EVENTS.md, TOOLS.md, openclaw.json, .env, package.json.
|
||||
- Fix broken skills; DO NOT delete and recreate.
|
||||
- Violation = ROLLBACK + FAILED.
|
||||
|
||||
COMMON FAILURE PATTERNS:
|
||||
- Blast radius exceeded.
|
||||
- Omitted Mutation object.
|
||||
- Merged objects into one JSON.
|
||||
- Hallucinated "type": "Logic".
|
||||
- "id": "mut_undefined".
|
||||
- Missing "trigger_signals".
|
||||
- Unrunnable validation steps.
|
||||
- Markdown code blocks wrapping JSON (FORBIDDEN).
|
||||
|
||||
FAILURE STREAK AWARENESS:
|
||||
- If "consecutive_failure_streak_N" or "failure_loop_detected":
|
||||
1. Change approach (do NOT repeat failed gene).
|
||||
2. Pick SIMPLER fix.
|
||||
3. Respect "ban_gene:<id>".
|
||||
|
||||
Final Directive: Every cycle must leave the system measurably better.
|
||||
START IMMEDIATELY WITH RAW JSON (Mutation Object first).
|
||||
DO NOT WRITE ANY INTRODUCTORY TEXT.
|
||||
|
||||
Context [Signals]:
|
||||
["memory_missing","session_logs_missing"]
|
||||
|
||||
Context [Env Fingerprint]:
|
||||
{
|
||||
"device_id": "b5faa2075270e1a00be02e5efc91e77f",
|
||||
"node_version": "v22.22.0",
|
||||
"platform": "linux",
|
||||
"arch": "x64",
|
||||
"os_release": "6.17.0-14-generic",
|
||||
"hostname": "e4dd2cf3f5d0",
|
||||
"evolver_version": "1.23.0",
|
||||
"client": "evolver",
|
||||
"client_version": "1.23.0",
|
||||
"cwd": "7a11b0a77402",
|
||||
"container": false
|
||||
}
|
||||
|
||||
Context [Injection Hint]:
|
||||
(none)
|
||||
|
||||
Context [Gene Preview] (Reference for Strategy):
|
||||
```json
|
||||
[
|
||||
{
|
||||
"type": "Gene",
|
||||
"id": "gene_gep_repair_from_errors",
|
||||
"category": "repair",
|
||||
"signals_match": [
|
||||
"error",
|
||||
"exception",
|
||||
"failed",
|
||||
"unstable"
|
||||
],
|
||||
"preconditions": [
|
||||
"signals contains error-related indicators"
|
||||
],
|
||||
"strategy": [
|
||||
"Extract structured signals from logs and user instructions",
|
||||
"Select an existing Gene by signals match (no improvisation)",
|
||||
"Estimate blast radius (files, lines) before editing",
|
||||
"Apply smallest reversible patch",
|
||||
"Validate using declared validation steps; rollback on failure",
|
||||
"Solidify knowledge: append EvolutionEvent, update Gene/Capsule store"
|
||||
],
|
||||
"constraints": {
|
||||
"max_files": 20,
|
||||
"forbidden_paths": [
|
||||
".git",
|
||||
"node_modules"
|
||||
]
|
||||
},
|
||||
"validation": [
|
||||
"node scripts/validate-modules.js ./src/evolve ./src/gep/solidify",
|
||||
"node scripts/validate-modules.js ./src/gep/selector ./src/gep/memoryGraph"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Gene",
|
||||
"id": "gene_gep_optimize_prompt_and_assets",
|
||||
"category": "optimize",
|
||||
"signals_match": [
|
||||
"protocol",
|
||||
"gep",
|
||||
"prompt",
|
||||
"audit",
|
||||
"reusable"
|
||||
],
|
||||
"preconditions": [
|
||||
"need stricter, auditable evolution protocol outputs"
|
||||
],
|
||||
"strategy": [
|
||||
"Extract signals and determine selection rationale via Selector JSON",
|
||||
"Prefer reusing existing Gene/Capsule; only create if no match exists",
|
||||
"Refactor prompt assembly to embed assets (genes, capsules, parent event)",
|
||||
"Reduce noise and ambiguity; enforce strict output schema",
|
||||
"Validate by running node index.js run and ensuring no runtime errors",
|
||||
"Solidify: record EvolutionEvent, update Gene definitions, create Capsule on success"
|
||||
],
|
||||
"constraints": {
|
||||
"max_files": 20,
|
||||
"forbidden_paths": [
|
||||
".git",
|
||||
"node_modules"
|
||||
]
|
||||
},
|
||||
"validation": [
|
||||
"node scripts/validate-modules.js ./src/evolve ./src/gep/prompt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Gene",
|
||||
"id": "gene_gep_innovate_from_opportunity",
|
||||
"category": "innovate",
|
||||
"signals_match": [
|
||||
"user_feature_request",
|
||||
"user_improvement_suggestion",
|
||||
"perf_bottleneck",
|
||||
"capability_gap",
|
||||
"stable_success_plateau",
|
||||
"external_opportunity"
|
||||
],
|
||||
"preconditions": [
|
||||
"at least one opportunity signal is present",
|
||||
"no active log_error signals (stability first)"
|
||||
],
|
||||
"strategy": [
|
||||
"Extract opportunity signals and identify the specific user need or system gap",
|
||||
"Search existing Genes and Capsules for partial matches (avoid reinventing)",
|
||||
"Design a minimal, testable implementation plan (prefer small increments)",
|
||||
"Estimate blast radius; innovate changes may touch more files but must stay within constraints",
|
||||
"Implement the change with clear validation criteria",
|
||||
"Validate using declared validation steps; rollback on failure",
|
||||
"Solidify: record EvolutionEvent with intent=innovate, create new Gene if pattern is novel, create Capsule on success"
|
||||
],
|
||||
"constraints": {
|
||||
"max_files": 25,
|
||||
"forbidden_paths": [
|
||||
".git",
|
||||
"node_modules"
|
||||
]
|
||||
},
|
||||
"validation": [
|
||||
"node scripts/validate-modules.js ./src/evolve ./src/gep/solidify"
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Context [Capsule Preview] (Reference for Past Success):
|
||||
```json
|
||||
[
|
||||
{
|
||||
"type": "Capsule",
|
||||
"schema_version": "1.5.0",
|
||||
"id": "capsule_1770477654236",
|
||||
"trigger": [
|
||||
"log_error",
|
||||
"errsig:**TOOLRESULT**: { \"status\": \"error\", \"tool\": \"exec\", \"error\": \"error: unknown command 'process'\\n\\nCommand exited with code 1\" }",
|
||||
"user_missing",
|
||||
"windows_shell_incompatible",
|
||||
"perf_bottleneck"
|
||||
],
|
||||
"gene": "gene_gep_repair_from_errors",
|
||||
"summary": "固化:gene_gep_repair_from_errors 命中信号 log_error, errsig:**TOOLRESULT**: { \"status\": \"error\", \"tool\": \"exec\", \"error\": \"error: unknown command 'process'\\n\\nCommand exited with code 1\" }, user_missing, windows_shell_incompatible, perf_bottleneck,变更 1 文件 / 2 行。",
|
||||
"confidence": 0.85,
|
||||
"blast_radius": {
|
||||
"files": 1,
|
||||
"lines": 2
|
||||
},
|
||||
"outcome": {
|
||||
"status": "success",
|
||||
"score": 0.85
|
||||
},
|
||||
"success_streak": 1,
|
||||
"env_fingerprint": {
|
||||
"node_version": "v22.22.0",
|
||||
"platform": "linux",
|
||||
"arch": "x64",
|
||||
"os_release": "6.1.0-42-cloud-amd64",
|
||||
"evolver_version": "1.7.0",
|
||||
"cwd": ".",
|
||||
"captured_at": "2026-02-07T15:20:54.155Z"
|
||||
},
|
||||
"a2a": {
|
||||
"eligible_to_broadcast": false
|
||||
},
|
||||
"asset_id": "sha256:3eed0cd5038f9e85fbe0d093890e291e9b8725644c766e6cce40bf62d0f5a2e8"
|
||||
},
|
||||
{
|
||||
"type": "Capsule",
|
||||
"schema_version": "1.5.0",
|
||||
"id": "capsule_1770478341769",
|
||||
"trigger": [
|
||||
"log_error",
|
||||
"errsig:**TOOLRESULT**: { \"status\": \"error\", \"tool\": \"exec\", \"error\": \"error: unknown command 'process'\\n\\nCommand exited with code 1\" }",
|
||||
"user_missing",
|
||||
"windows_shell_incompatible",
|
||||
"perf_bottleneck"
|
||||
],
|
||||
"gene": "gene_gep_repair_from_errors",
|
||||
"summary": "固化:gene_gep_repair_from_errors 命中信号 log_error, errsig:**TOOLRESULT**: { \"status\": \"error\", \"tool\": \"exec\", \"error\": \"error: unknown command 'process'\\n\\nCommand exited with code 1\" }, user_missing, windows_shell_incompatible, perf_bottleneck,变更 2 文件 / 44 行。",
|
||||
"confidence": 0.85,
|
||||
"blast_radius": {
|
||||
"files": 2,
|
||||
"lines": 44
|
||||
},
|
||||
"outcome": {
|
||||
"status": "success",
|
||||
"score": 0.85
|
||||
},
|
||||
"success_streak": 1,
|
||||
"env_fingerprint": {
|
||||
"node_version": "v22.22.0",
|
||||
"platform": "linux",
|
||||
"arch": "x64",
|
||||
"os_release": "6.1.0-42-cloud-amd64",
|
||||
"evolver_version": "1.7.0",
|
||||
"cwd": ".",
|
||||
"captured_at": "2026-02-07T15:32:21.678Z"
|
||||
},
|
||||
"a2a": {
|
||||
"eligible_to_broadcast": false
|
||||
},
|
||||
"asset_id": "sha256:20d971a3c4cb2b75f9c045376d1aa003361c12a6b89a4b47b7e81dbd4f4d8fe8"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Context [Capability Candidates]:
|
||||
- cand_b9a66a5c: Harden session log detection and fallback behavior
|
||||
- input: Recent session transcript + memory snippets + user instructions
|
||||
- output: A safe, auditable evolution patch guided by GEP assets
|
||||
- invariants: Protocol order, small reversible patches, validation, append-only events
|
||||
- params: Signals: memory_missing, session_logs_missing
|
||||
- failure_points: Missing signals, over-broad changes, skipped validation, missing knowledge solidification
|
||||
- evidence: Signal present: session_logs_missing
|
||||
|
||||
Context [Hub Matched Solution]:
|
||||
(no hub match)
|
||||
|
||||
Context [External Candidates]:
|
||||
(none)
|
||||
|
||||
|
||||
|
||||
|
||||
Context [Execution]:
|
||||
Runtime state:
|
||||
- System health: Uptime: 455.2h | Node: v22.22.0 | Agent RSS: 54.7MB | Disk: 8% (864.6G free) | Node Processes: 1 | Integrations: Nominal
|
||||
- Agent state: Mood: Unknown
|
||||
- Scan duration: 24ms
|
||||
- Memory size: 0 bytes
|
||||
- Skills available (if any):
|
||||
[skills directory not found]
|
||||
|
||||
Notes:
|
||||
- Review mode: disabled.
|
||||
- Report requirement:
|
||||
- Use `message` tool.
|
||||
- Title: Evolution Cycle #0001
|
||||
- Status: [SUCCESS]
|
||||
- Changes: Detail exactly what was improved.
|
||||
- Workspace sync: optional/disabled in this environment.
|
||||
|
||||
Recent Evolution History (last 8 cycles -- DO NOT repeat the same intent+signal+gene):
|
||||
1. [innovate] signals=[user_missing, user_feature_request] gene=gene_gep_innovate_from_opportunity outcome=failed @2026-02-07T15:13:21.173Z
|
||||
2. [repair] signals=[log_error, errsig:**TOOLRESULT**: { "status": "error", "tool": "exec", "error": "error: unknown command 'process'\n\nCommand exited with code 1" }, user_missing] gene=gene_gep_repair_from_errors outcome=success @2026-02-07T15:20:54.236Z
|
||||
3. [repair] signals=[log_error, errsig:**TOOLRESULT**: { "status": "error", "tool": "exec", "error": "error: unknown command 'process'\n\nCommand exited with code 1" }, user_missing] gene=gene_gep_repair_from_errors outcome=success @2026-02-07T15:32:21.769Z
|
||||
IMPORTANT: If you see 3+ consecutive "repair" cycles with the same gene, you MUST switch to "innovate" intent.
|
||||
|
||||
|
||||
External candidates (A2A receive zone; staged only, never execute directly):
|
||||
(none)
|
||||
|
||||
Global memory (MEMORY.md):
|
||||
```
|
||||
[MEMORY.md MISSING]
|
||||
```
|
||||
|
||||
User registry (USER.md):
|
||||
```
|
||||
[USER.md MISSING]
|
||||
```
|
||||
|
||||
Recent memory snippet:
|
||||
```
|
||||
[MISSING] /home/starmen1265/.openclaw/memory/2026-03-03.md
|
||||
```
|
||||
|
||||
Recent session transcript:
|
||||
```
|
||||
[NO JSONL FILES]
|
||||
```
|
||||
|
||||
Mutation directive:
|
||||
|
||||
[Signal Hints]
|
||||
- recent_error_count: 0
|
||||
- stability: stable
|
||||
- recommended_intent: optimize
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━
|
||||
MANDATORY POST-SOLIDIFY STEP (Wrapper Authority -- Cannot Be Skipped)
|
||||
━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
After solidify, a status summary file MUST exist for this cycle.
|
||||
Preferred path: evolver core auto-writes it during solidify.
|
||||
The wrapper will handle reporting AFTER git push.
|
||||
If core write is unavailable for any reason, create fallback status JSON manually.
|
||||
|
||||
Write a JSON file with your status:
|
||||
```bash
|
||||
cat > ./logs/status_undefined.json << 'STATUSEOF'
|
||||
{
|
||||
"result": "success|failed",
|
||||
"en": "Status: [INTENT] <describe what you did in 1-2 sentences, in English>",
|
||||
"zh": "状态: [意图] <用中文描述你做了什么,1-2句>"
|
||||
}
|
||||
STATUSEOF
|
||||
```
|
||||
|
||||
Rules:
|
||||
- "en" field: English status. "zh" field: Chinese status. Content must match (different language).
|
||||
- Add "result" with value success or failed.
|
||||
- INTENT must be one of: INNOVATION, REPAIR, OPTIMIZE (or Chinese: 创新, 修复, 优化)
|
||||
- Do NOT use generic text like "Step Complete", "Cycle finished", "周期已完成". Describe the actual work.
|
||||
- Example:
|
||||
{"result":"success","en":"Status: [INNOVATION] Created auto-scheduler that syncs calendar to HEARTBEAT.md","zh":"状态: [创新] 创建了自动调度器,将日历同步到 HEARTBEAT.md"}
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"last_action": {
|
||||
"action_id": "act_1772551119186_a5982a82",
|
||||
"signal_key": "memory_missing|session_logs_missing",
|
||||
"signals": [
|
||||
"memory_missing",
|
||||
"session_logs_missing"
|
||||
],
|
||||
"mutation_id": "mut_1772551119185",
|
||||
"mutation_category": "innovate",
|
||||
"mutation_risk_level": "medium",
|
||||
"personality_key": "rigor=0.7|creativity=0.3|verbosity=0.3|risk_tolerance=0.4|obedience=0.9",
|
||||
"personality_state": {
|
||||
"type": "PersonalityState",
|
||||
"rigor": 0.7,
|
||||
"creativity": 0.35,
|
||||
"verbosity": 0.25,
|
||||
"risk_tolerance": 0.4,
|
||||
"obedience": 0.85
|
||||
},
|
||||
"gene_id": null,
|
||||
"gene_category": null,
|
||||
"hypothesis_id": "hyp_1772551119185_a7a07c6d",
|
||||
"capsules_used": [],
|
||||
"had_error": false,
|
||||
"created_at": "2026-03-03T15:18:39.186Z",
|
||||
"outcome_recorded": false,
|
||||
"baseline_observed": {
|
||||
"agent": "main",
|
||||
"session_scope": null,
|
||||
"drift_enabled": false,
|
||||
"review_mode": false,
|
||||
"dry_run": false,
|
||||
"system_health": "Uptime: 455.2h | Node: v22.22.0 | Agent RSS: 54.7MB | Disk: 8% (864.6G free) | Node Processes: 1 | Integrations: Nominal",
|
||||
"mood": "Mood: Unknown",
|
||||
"scan_ms": 24,
|
||||
"memory_size_bytes": 0,
|
||||
"recent_error_count": 0,
|
||||
"node": "v22.22.0",
|
||||
"platform": "linux",
|
||||
"cwd": "/home/starmen1265/.openclaw/skills/capability-evolver",
|
||||
"evidence": {
|
||||
"recent_session_tail": "[NO JSONL FILES]",
|
||||
"today_log_tail": "[MISSING] /home/starmen1265/.openclaw/memory/2026-03-03.md"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"version": 1,
|
||||
"current": {
|
||||
"type": "PersonalityState",
|
||||
"rigor": 0.7,
|
||||
"creativity": 0.35,
|
||||
"verbosity": 0.25,
|
||||
"risk_tolerance": 0.4,
|
||||
"obedience": 0.85
|
||||
},
|
||||
"stats": {},
|
||||
"history": [],
|
||||
"updated_at": "2026-03-03T15:18:39.185Z"
|
||||
}
|
||||
+11
-3
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"meta": {
|
||||
"lastTouchedVersion": "2026.2.9",
|
||||
"lastTouchedAt": "2026-03-03T15:06:05.649Z"
|
||||
"lastTouchedAt": "2026-03-03T15:31:40.861Z"
|
||||
},
|
||||
"wizard": {
|
||||
"lastRunAt": "2026-02-13T15:47:05.928Z",
|
||||
@@ -110,10 +110,10 @@
|
||||
"agents": {
|
||||
"defaults": {
|
||||
"model": {
|
||||
"primary": "m25",
|
||||
"primary": "g5",
|
||||
"fallbacks": [
|
||||
"g47f",
|
||||
"g5",
|
||||
"m25",
|
||||
"q3",
|
||||
"k2p5"
|
||||
]
|
||||
@@ -147,6 +147,7 @@
|
||||
"list": [
|
||||
{
|
||||
"id": "haonan",
|
||||
"workspace":"/home/starmen1265/.openclaw/agents/haonan/workspace",
|
||||
"skills": [
|
||||
"common-require",
|
||||
"capability-evolver",
|
||||
@@ -155,6 +156,7 @@
|
||||
},
|
||||
{
|
||||
"id": "knowledge-base",
|
||||
"workspace":"/home/starmen1265/.openclaw/agents/knowledge-base/workspace",
|
||||
"skills": [
|
||||
"common-require",
|
||||
"kb-workflow",
|
||||
@@ -164,6 +166,7 @@
|
||||
},
|
||||
{
|
||||
"id": "dev-assist",
|
||||
"workspace":"/home/starmen1265/.openclaw/agents/dev-assist/workspace",
|
||||
"skills": [
|
||||
"common-require",
|
||||
"clawlist",
|
||||
@@ -173,6 +176,7 @@
|
||||
},
|
||||
{
|
||||
"id": "ui-designer",
|
||||
"workspace":"/home/starmen1265/.openclaw/agents/ui-designer/workspace",
|
||||
"skills": [
|
||||
"common-require",
|
||||
"capability-evolver",
|
||||
@@ -181,6 +185,7 @@
|
||||
},
|
||||
{
|
||||
"id": "thinker",
|
||||
"workspace":"/home/starmen1265/.openclaw/agents/thinker/workspace",
|
||||
"skills": [
|
||||
"common-require",
|
||||
"capability-evolver",
|
||||
@@ -286,6 +291,9 @@
|
||||
},
|
||||
"session-memory": {
|
||||
"enabled": true
|
||||
},
|
||||
"self-improvement": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+21
-46
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"meta": {
|
||||
"lastTouchedVersion": "2026.2.9",
|
||||
"lastTouchedAt": "2026-02-15T15:57:58.358Z"
|
||||
"lastTouchedAt": "2026-03-03T15:06:05.649Z"
|
||||
},
|
||||
"wizard": {
|
||||
"lastRunAt": "2026-02-13T15:47:05.928Z",
|
||||
@@ -147,70 +147,45 @@
|
||||
"list": [
|
||||
{
|
||||
"id": "haonan",
|
||||
"name": "\u9648\u6d69\u5357",
|
||||
"workspace": "/home/starmen1265/.openclaw/agents/haonan/workspace",
|
||||
"model": "m25",
|
||||
"skills": [
|
||||
"common-require"
|
||||
],
|
||||
"identity": {
|
||||
"name": "\u9648\u6d69\u5357",
|
||||
"emoji": "\ud83d\udcda"
|
||||
}
|
||||
"common-require",
|
||||
"capability-evolver",
|
||||
"self-improving-agent"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "knowledge-base",
|
||||
"name": "\u77e5\u8bc6\u5e93\u52a9\u624b",
|
||||
"workspace": "/home/starmen1265/.openclaw/agents/knowledge-base/workspace",
|
||||
"model": "g5",
|
||||
"skills": [
|
||||
"common-require",
|
||||
"kb-workflow"
|
||||
],
|
||||
"identity": {
|
||||
"name": "\u77e5\u8bc6\u5e93\u52a9\u624b",
|
||||
"emoji": "\ud83d\udcda"
|
||||
}
|
||||
"kb-workflow",
|
||||
"capability-evolver",
|
||||
"self-improving-agent"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "dev-assist",
|
||||
"name": "\u7a0b\u5e8f\u5f00\u53d1\u52a9\u624b",
|
||||
"workspace": "/home/starmen1265/.openclaw/agents/dev-assist/workspace",
|
||||
"model": "g5",
|
||||
"skills": [
|
||||
"common-require",
|
||||
"clawlist"
|
||||
],
|
||||
"identity": {
|
||||
"name": "\u7a0b\u5e8f\u5f00\u53d1\u52a9\u624b",
|
||||
"emoji": "\ud83d\udcda"
|
||||
}
|
||||
"clawlist",
|
||||
"capability-evolver",
|
||||
"self-improving-agent"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "ui-designer",
|
||||
"name": "UI/UX\u8bbe\u8ba1\u5e08",
|
||||
"workspace": "/home/starmen1265/.openclaw/agents/ui-designer/workspace",
|
||||
"model": "g5",
|
||||
"skills": [
|
||||
"common-require"
|
||||
],
|
||||
"identity": {
|
||||
"name": "\u8bbe\u8ba1\u5e08",
|
||||
"emoji": "\ud83c\udfa8"
|
||||
}
|
||||
"common-require",
|
||||
"capability-evolver",
|
||||
"self-improving-agent"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "thinker",
|
||||
"name": "\u5ba1\u67e5\u5458",
|
||||
"workspace": "/home/starmen1265/.openclaw/agents/thinker/workspace",
|
||||
"model": "g5",
|
||||
"skills": [
|
||||
"common-require"
|
||||
],
|
||||
"identity": {
|
||||
"name": "\u5ba1\u67e5\u5458",
|
||||
"emoji": "\ud83d\udd0d"
|
||||
}
|
||||
"common-require",
|
||||
"capability-evolver",
|
||||
"self-improving-agent"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
+56
-60
@@ -147,20 +147,20 @@
|
||||
"list": [
|
||||
{
|
||||
"id": "haonan",
|
||||
"name": "陈浩南",
|
||||
"name": "\u9648\u6d69\u5357",
|
||||
"workspace": "/home/starmen1265/.openclaw/agents/haonan/workspace",
|
||||
"model": "m25",
|
||||
"skills": [
|
||||
"common-require"
|
||||
],
|
||||
"identity": {
|
||||
"name": "陈浩南",
|
||||
"emoji": "📚"
|
||||
"name": "\u9648\u6d69\u5357",
|
||||
"emoji": "\ud83d\udcda"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "knowledge-base",
|
||||
"name": "知识库助手",
|
||||
"name": "\u77e5\u8bc6\u5e93\u52a9\u624b",
|
||||
"workspace": "/home/starmen1265/.openclaw/agents/knowledge-base/workspace",
|
||||
"model": "g5",
|
||||
"skills": [
|
||||
@@ -168,13 +168,13 @@
|
||||
"kb-workflow"
|
||||
],
|
||||
"identity": {
|
||||
"name": "知识库助手",
|
||||
"emoji": "📚"
|
||||
"name": "\u77e5\u8bc6\u5e93\u52a9\u624b",
|
||||
"emoji": "\ud83d\udcda"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "dev-assist",
|
||||
"name": "程序开发助手",
|
||||
"name": "\u7a0b\u5e8f\u5f00\u53d1\u52a9\u624b",
|
||||
"workspace": "/home/starmen1265/.openclaw/agents/dev-assist/workspace",
|
||||
"model": "g5",
|
||||
"skills": [
|
||||
@@ -182,21 +182,34 @@
|
||||
"clawlist"
|
||||
],
|
||||
"identity": {
|
||||
"name": "程序开发助手",
|
||||
"emoji": "📚"
|
||||
"name": "\u7a0b\u5e8f\u5f00\u53d1\u52a9\u624b",
|
||||
"emoji": "\ud83d\udcda"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ui-designer",
|
||||
"name": "UI/UX设计师",
|
||||
"name": "UI/UX\u8bbe\u8ba1\u5e08",
|
||||
"workspace": "/home/starmen1265/.openclaw/agents/ui-designer/workspace",
|
||||
"model": "g5",
|
||||
"skills": [
|
||||
"common-require"
|
||||
],
|
||||
"identity": {
|
||||
"name": "设计师",
|
||||
"emoji": "🎨"
|
||||
"name": "\u8bbe\u8ba1\u5e08",
|
||||
"emoji": "\ud83c\udfa8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "thinker",
|
||||
"name": "\u5ba1\u67e5\u5458",
|
||||
"workspace": "/home/starmen1265/.openclaw/agents/thinker/workspace",
|
||||
"model": "g5",
|
||||
"skills": [
|
||||
"common-require"
|
||||
],
|
||||
"identity": {
|
||||
"name": "\u5ba1\u67e5\u5458",
|
||||
"emoji": "\ud83d\udd0d"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -229,71 +242,38 @@
|
||||
},
|
||||
"bindings": [
|
||||
{
|
||||
"agentId": "knowledge-base",
|
||||
"agentId": "haonan",
|
||||
"match": {
|
||||
"channel": "feishu",
|
||||
"peer": {
|
||||
"kind": "group",
|
||||
"id": "oc_79bcbd274c7cff8757b52e2ec1d8e12b"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"agentId": "knowledge-base",
|
||||
"match": {
|
||||
"channel": "wecom",
|
||||
"peer": {
|
||||
"kind": "group",
|
||||
"id": "wr_wAnbgAAXlqKMkyGznqpPMYZg2YTYg"
|
||||
}
|
||||
"accountId": "feishu-pm"
|
||||
}
|
||||
},
|
||||
{
|
||||
"agentId": "dev-assist",
|
||||
"match": {
|
||||
"channel": "feishu",
|
||||
"peer": {
|
||||
"kind": "group",
|
||||
"id": "oc_f86956cb9cecb7ad38c0f621377a23ae"
|
||||
}
|
||||
"accountId": "feishu-dev"
|
||||
}
|
||||
},
|
||||
{
|
||||
"agentId": "dev-assist",
|
||||
"match": {
|
||||
"channel": "wecom",
|
||||
"peer": {
|
||||
"kind": "group",
|
||||
"id": "wr_wAnbgAA_ot7JsLAgOD2IMcsGaT_8Q"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"agentId": "haonan",
|
||||
"agentId": "knowledge-base",
|
||||
"match": {
|
||||
"channel": "feishu",
|
||||
"accountId": "ou_be83febac9ee2afaa343c642bc697c48"
|
||||
"accountId": "feishu-worker"
|
||||
}
|
||||
},
|
||||
{
|
||||
"agentId": "haonan",
|
||||
"agentId": "thinker",
|
||||
"match": {
|
||||
"channel": "wecom",
|
||||
"accountId": "ZhangQing"
|
||||
"channel": "feishu",
|
||||
"accountId": "feishu-qa"
|
||||
}
|
||||
},
|
||||
{
|
||||
"agentId": "ui-designer",
|
||||
"match": {
|
||||
"channel": "feishu",
|
||||
"accountId": "ou_6de30318970345c4c79bea292b93130c"
|
||||
}
|
||||
},
|
||||
{
|
||||
"agentId": "ui-designer",
|
||||
"match": {
|
||||
"channel": "wecom",
|
||||
"accountId": "bala"
|
||||
"accountId": "feishu-art"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -338,13 +318,29 @@
|
||||
"channels": {
|
||||
"feishu": {
|
||||
"enabled": true,
|
||||
"dmPolicy": "open",
|
||||
"accounts": {
|
||||
"feishu-pm": {
|
||||
"appId": "cli_a9f74dc9a3f8dbce",
|
||||
"appSecret": "QtnvzRUhhFoNTTorxJuAwgSJ3ocPv0p1",
|
||||
"dmPolicy": "allowlist",
|
||||
"allowFrom": [
|
||||
"ou_be83febac9ee2afaa343c642bc697c48",
|
||||
"ou_6de30318970345c4c79bea292b93130c"
|
||||
],
|
||||
"appSecret": "QtnvzRUhhFoNTTorxJuAwgSJ3ocPv0p1"
|
||||
},
|
||||
"feishu-dev": {
|
||||
"appId": "cli_a92bae598f789bd7",
|
||||
"appSecret": "kmwCLAI8IdZZn1KtwiPTVg758u0unGzY"
|
||||
},
|
||||
"feishu-worker": {
|
||||
"appId": "cli_a92ba8ad3cb81bde",
|
||||
"appSecret": "8bnMNIzy4QAv96c2xjmjgdUILO1qrO2w"
|
||||
},
|
||||
"feishu-qa": {
|
||||
"appId": "cli_a92baf81053f1bc0",
|
||||
"appSecret": "D5Pk8Fzwj5LWQr1FGnBlCbbJa3Ox7bJQ"
|
||||
},
|
||||
"feishu-art": {
|
||||
"appId": "cli_a92baa31fdf8dbc0",
|
||||
"appSecret": "BKjGWv1MTz7WmTn0I5A2EhuKyzwuuUnk"
|
||||
}
|
||||
},
|
||||
"domain": "feishu",
|
||||
"groupPolicy": "open",
|
||||
"requireMention": true
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"meta": {
|
||||
"lastTouchedVersion": "2026.2.9",
|
||||
"lastTouchedAt": "2026-02-15T15:54:32.431Z"
|
||||
"lastTouchedAt": "2026-02-15T15:57:58.358Z"
|
||||
},
|
||||
"wizard": {
|
||||
"lastRunAt": "2026-02-13T15:47:05.928Z",
|
||||
@@ -300,7 +300,7 @@
|
||||
"messages": {
|
||||
"ackReactionScope": "group-mentions",
|
||||
"tts": {
|
||||
"auto": "always",
|
||||
"auto": "tagged",
|
||||
"provider": "edge",
|
||||
"edge": {
|
||||
"enabled": true,
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"meta": {
|
||||
"lastTouchedVersion": "2026.2.9",
|
||||
"lastTouchedAt": "2026-02-15T15:50:36.798Z"
|
||||
"lastTouchedAt": "2026-02-15T15:54:32.431Z"
|
||||
},
|
||||
"wizard": {
|
||||
"lastRunAt": "2026-02-13T15:47:05.928Z",
|
||||
@@ -300,7 +300,7 @@
|
||||
"messages": {
|
||||
"ackReactionScope": "group-mentions",
|
||||
"tts": {
|
||||
"auto": "tagged",
|
||||
"auto": "always",
|
||||
"provider": "edge",
|
||||
"edge": {
|
||||
"enabled": true,
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"meta": {
|
||||
"lastTouchedVersion": "2026.2.9",
|
||||
"lastTouchedAt": "2026-02-15T15:43:40.588Z"
|
||||
"lastTouchedAt": "2026-02-15T15:50:36.798Z"
|
||||
},
|
||||
"wizard": {
|
||||
"lastRunAt": "2026-02-13T15:47:05.928Z",
|
||||
@@ -300,7 +300,7 @@
|
||||
"messages": {
|
||||
"ackReactionScope": "group-mentions",
|
||||
"tts": {
|
||||
"auto": "always",
|
||||
"auto": "tagged",
|
||||
"provider": "edge",
|
||||
"edge": {
|
||||
"enabled": true,
|
||||
|
||||
+100
-1
@@ -1,4 +1,103 @@
|
||||
=== Capability Evolver 运行开始 ===
|
||||
时间: 2026年 03月 03日 星期二 23:13:28 CST
|
||||
时间: 2026年 03月 05日 星期四 19:00:23 CST
|
||||
|
||||
=== 推送到远端 ===
|
||||
Warning: Permanently added '[192.168.1.22]:2223' (RSA) to the list of known hosts.
|
||||
Everything up-to-date
|
||||
推送完成
|
||||
|
||||
发现有未提交的更改,先提交...
|
||||
创建备份分支: backup/evolver-20260305-190024
|
||||
Warning: Permanently added '[192.168.1.22]:2223' (RSA) to the list of known hosts.
|
||||
remote:
|
||||
remote: Create a new pull request for 'backup/evolver-20260305-190024':
|
||||
remote: http://192.168.1.22:8418/starmen1265/openclaw/compare/main...backup/evolver-20260305-190024
|
||||
remote:
|
||||
remote: . Processing 1 references
|
||||
remote: Processed 1 references in total
|
||||
To gitea-account:starmen1265/openclaw.git
|
||||
* [new branch] backup/evolver-20260305-190024 -> backup/evolver-20260305-190024
|
||||
|
||||
=== Git 备份完成 ===
|
||||
|
||||
=== 运行 Capability Evolver (repair-only 模式) ===
|
||||
[Evolver] Warning: dotenv not found or failed to load .env
|
||||
Usage: node index.js [run|/evolve|solidify|distill|asset-log] [--loop]
|
||||
- solidify flags:
|
||||
- --dry-run
|
||||
- --no-rollback
|
||||
- --intent=repair|optimize|innovate
|
||||
- --summary=...
|
||||
- distill flags:
|
||||
- --response-file=<path> (LLM response file for skill distillation)
|
||||
- asset-log flags:
|
||||
- --run=<run_id> (filter by run ID)
|
||||
- --action=<action> (filter: hub_search_hit, hub_search_miss, asset_reuse, asset_reference, asset_publish, asset_publish_skip)
|
||||
- --last=<N> (show last N entries)
|
||||
- --since=<ISO_date> (entries after date)
|
||||
- --json (raw JSON output)
|
||||
|
||||
=== Evolver 运行完成 (exit code: 0) ===
|
||||
|
||||
=== 本次变更 ===
|
||||
M agents/dev-assist/sessions/sessions.json
|
||||
D agents/dev-assist/workspace/TODO.md
|
||||
M agents/haonan/agent/auth-profiles.json
|
||||
M agents/haonan/sessions/sessions.json
|
||||
M agents/haonan/workspace/MEMORY.md
|
||||
M agents/haonan/workspace/SOUL.md
|
||||
M agents/knowledge-base/workspace/AGENTS.md
|
||||
D agents/knowledge-base/workspace/knowledge-base/videos/BV1QjcszrEEV.md
|
||||
M agents/knowledge-base/workspace/memory/2026-03-03.md
|
||||
M agents/main/agent/auth-profiles.json
|
||||
M cron/jobs.json
|
||||
M cron/jobs.json.bak
|
||||
M devices/paired.json
|
||||
M identity/device-auth.json
|
||||
M openclaw.json
|
||||
M openclaw.json.bak
|
||||
M openclaw.json.bak.1
|
||||
M openclaw.json.bak.2
|
||||
M openclaw.json.bak.3
|
||||
M openclaw.json.bak.4
|
||||
M scripts/evolver-output.txt
|
||||
M scripts/evolver-run.sh
|
||||
D scripts/git-auto-sync.sh
|
||||
M skills/capability-evolver/README.md
|
||||
M skills/capability-evolver/README.zh-CN.md
|
||||
D skills/capability-evolver/_meta.json
|
||||
M skills/capability-evolver/index.js
|
||||
M skills/capability-evolver/package.json
|
||||
M skills/capability-evolver/src/evolve.js
|
||||
M skills/capability-evolver/src/gep/a2a.js
|
||||
M skills/capability-evolver/src/gep/a2aProtocol.js
|
||||
M skills/capability-evolver/src/gep/hubSearch.js
|
||||
M skills/capability-evolver/src/gep/paths.js
|
||||
M skills/capability-evolver/src/gep/prompt.js
|
||||
M skills/capability-evolver/src/gep/selector.js
|
||||
M skills/capability-evolver/src/gep/signals.js
|
||||
M skills/capability-evolver/src/gep/skillDistiller.js
|
||||
M skills/capability-evolver/src/gep/solidify.js
|
||||
M skills/capability-evolver/src/gep/taskReceiver.js
|
||||
M skills/capability-evolver/src/ops/cleanup.js
|
||||
?? agents/haonan/workspace/memory/2026-03-04.md
|
||||
?? hooks/
|
||||
?? media/inbound/d43f43ec-4953-42e2-a550-8b2474b9939b.jpg
|
||||
?? memory/
|
||||
?? skills/capability-evolver/.gitignore
|
||||
?? skills/capability-evolver/LICENSE
|
||||
?? skills/capability-evolver/assets/cover.png
|
||||
?? skills/capability-evolver/assets/gep/failed_capsules.json
|
||||
?? skills/capability-evolver/src/gep/assetCallLog.js
|
||||
?? skills/capability-evolver/src/gep/llmReview.js
|
||||
?? skills/capability-evolver/src/gep/narrativeMemory.js
|
||||
?? skills/capability-evolver/src/gep/reflection.js
|
||||
?? workspace-dev-assist/
|
||||
?? workspace-knowledge-base/
|
||||
?? workspace/.learnings/
|
||||
|
||||
=== 推送变更到远端 ===
|
||||
Warning: Permanently added '[192.168.1.22]:2223' (RSA) to the list of known hosts.
|
||||
Everything up-to-date
|
||||
|
||||
=== 输出完成 ===
|
||||
|
||||
+26
-1
@@ -10,9 +10,20 @@ echo "=== Capability Evolver 运行开始 ===" > "$OUTPUT_FILE"
|
||||
echo "时间: $(date)" >> "$OUTPUT_FILE"
|
||||
echo "" >> "$OUTPUT_FILE"
|
||||
|
||||
# 切换到 openclaw 目录进行 git 备份
|
||||
# 切换到 openclaw 目录
|
||||
cd "$OPENCLAW_DIR"
|
||||
|
||||
# 推送到远端(如果有远端)
|
||||
if git remote get-url origin &>/dev/null; then
|
||||
echo "=== 推送到远端 ===" >> "$OUTPUT_FILE"
|
||||
git push origin main >> "$OUTPUT_FILE" 2>&1
|
||||
echo "推送完成" >> "$OUTPUT_FILE"
|
||||
else
|
||||
echo "无远端配置,跳过推送" >> "$OUTPUT_FILE"
|
||||
fi
|
||||
|
||||
echo "" >> "$OUTPUT_FILE"
|
||||
|
||||
# 检查是否有未提交的更改
|
||||
if [[ -n $(git status --porcelain) ]]; then
|
||||
echo "发现有未提交的更改,先提交..." >> "$OUTPUT_FILE"
|
||||
@@ -26,6 +37,11 @@ echo "创建备份分支: $BACKUP_BRANCH" >> "$OUTPUT_FILE"
|
||||
git branch -D "$BACKUP_BRANCH" 2>/dev/null || true
|
||||
git branch "$BACKUP_BRANCH" 2>/dev/null
|
||||
|
||||
# 推送备份分支
|
||||
if git remote get-url origin &>/dev/null; then
|
||||
git push origin "$BACKUP_BRANCH" >> "$OUTPUT_FILE" 2>&1 || echo "备份分支推送失败" >> "$OUTPUT_FILE"
|
||||
fi
|
||||
|
||||
echo "" >> "$OUTPUT_FILE"
|
||||
echo "=== Git 备份完成 ===" >> "$OUTPUT_FILE"
|
||||
echo "" >> "$OUTPUT_FILE"
|
||||
@@ -46,5 +62,14 @@ echo "" >> "$OUTPUT_FILE"
|
||||
echo "=== 本次变更 ===" >> "$OUTPUT_FILE"
|
||||
git status --short >> "$OUTPUT_FILE"
|
||||
|
||||
# 如果有变更,推送
|
||||
if [[ -n $(git status --porcelain) ]]; then
|
||||
echo "" >> "$OUTPUT_FILE"
|
||||
echo "=== 推送变更到远端 ===" >> "$OUTPUT_FILE"
|
||||
git add -A
|
||||
git commit -m "Evolver auto evolution - $(date)" 2>/dev/null || true
|
||||
git push origin main >> "$OUTPUT_FILE" 2>&1 || echo "推送失败" >> "$OUTPUT_FILE"
|
||||
fi
|
||||
|
||||
echo "" >> "$OUTPUT_FILE"
|
||||
echo "=== 输出完成 ===" >> "$OUTPUT_FILE"
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 自动检查并提交 git 修改
|
||||
|
||||
cd ~/.openclaw
|
||||
git add -A
|
||||
if ! git diff --cached --quiet; then
|
||||
git commit -m "自动同步: $(date '+%Y-%m-%d %H:%M')"
|
||||
git push origin main
|
||||
fi
|
||||
|
||||
cd ~/.openclaw/extensions
|
||||
git add -A
|
||||
if ! git diff --cached --quiet; then
|
||||
git commit -m "自动同步: $(date '+%Y-%m-%d %H:%M')"
|
||||
git push origin main
|
||||
fi
|
||||
@@ -0,0 +1,14 @@
|
||||
node_modules/
|
||||
.env
|
||||
memory/
|
||||
assets/gep/candidates.jsonl
|
||||
assets/gep/external_candidates.jsonl
|
||||
dist-public/
|
||||
|
||||
# Docker / vibe testing
|
||||
test/tmp/
|
||||
.docker-test-state/
|
||||
|
||||
# Local identity persistence (device + node)
|
||||
.evomap_device_id
|
||||
.evomap_node_id
|
||||
@@ -0,0 +1,22 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 OpenClaw
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
@@ -19,6 +19,11 @@ Capability Evolver is the core engine behind **[EvoMap](https://evomap.ai)**, a
|
||||
|
||||
Keywords: protocol-constrained evolution, audit trail, genes and capsules, prompt governance.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- **Node.js** >= 18
|
||||
- **Git** -- Required. Evolver uses git for rollback, blast radius calculation, and solidify. Running in a non-git directory will fail with a clear error message.
|
||||
|
||||
## Try It Now (Minimal)
|
||||
|
||||
```bash
|
||||
@@ -221,14 +226,16 @@ The script automatically detects if compatible local skills (like `skills/feishu
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
- [onthebigtree](https://github.com/onthebigtree) -- Inspired the creation of evomap evolution network.
|
||||
- [onthebigtree](https://github.com/onthebigtree) -- Inspired the creation of evomap evolution network. Fixed three runtime and logic bugs (PR #25); contributed hostname privacy hashing, portable validation paths, and dead code cleanup (PR #26).
|
||||
- [lichunr](https://github.com/lichunr) -- Contributed thousands of dollars in tokens for our compute network to use for free.
|
||||
- [shinjiyu](https://github.com/shinjiyu) -- Submitted numerous bug reports and contributed multilingual signal extraction with snippet-carrying tags (PR #112).
|
||||
- [voidborne-d](https://github.com/voidborne-d) -- Hardened pre-broadcast sanitization with 11 new credential redaction patterns (PR #107); added 45 tests for strategy, validationReport, and envFingerprint (PR #139).
|
||||
- [blackdogcat](https://github.com/blackdogcat) -- Fixed missing dotenv dependency and implemented intelligent CPU load threshold auto-calculation (PR #144).
|
||||
- [LKCY33](https://github.com/LKCY33) -- Fixed .env loading path and directory permissions (PR #21).
|
||||
- [hendrixAIDev](https://github.com/hendrixAIDev) -- Fixed performMaintenance() running in dry-run mode (PR #68).
|
||||
- [toller892](https://github.com/toller892) -- Independently identified and reported the events.jsonl forbidden_paths bug (PR #149).
|
||||
- [upbit](https://github.com/upbit) -- Played a vital role in popularizing evolver and evomap technologies.
|
||||
- [Chi Jianqiang](https://mowen.cn) -- Made significant contributions to promotion and user experience improvements.
|
||||
- More contributors to be added.
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -27,6 +27,11 @@ Capability Evolver 是 **[EvoMap](https://evomap.ai)** 的核心引擎。EvoMap
|
||||
- **动态集成**:自动检测并使用本地工具,如果不存在则回退到通用模式。
|
||||
- **持续循环模式**:持续运行的自我进化循环。
|
||||
|
||||
## 前置条件
|
||||
|
||||
- **Node.js** >= 18
|
||||
- **Git** -- 必需。Evolver 依赖 git 进行回滚、变更范围计算和固化(solidify)。在非 git 目录中运行会直接报错并退出。
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 标准运行(自动化)
|
||||
@@ -190,13 +195,16 @@ MAJOR.MINOR.PATCH
|
||||
|
||||
## 鸣谢
|
||||
|
||||
- [onthebigtree](https://github.com/onthebigtree) -- 启发了 evomap 进化网络的诞生。
|
||||
- [onthebigtree](https://github.com/onthebigtree) -- 启发了 evomap 进化网络的诞生。修复了三个运行时逻辑 bug (PR #25);贡献了主机名隐私哈希、可移植验证路径和死代码清理 (PR #26)。
|
||||
- [lichunr](https://github.com/lichunr) -- 提供了数千美金 Token 供算力网络免费使用。
|
||||
- [shinjiyu](https://github.com/shinjiyu) -- 为 evolver 和 evomap 提交了大量 bug report,并贡献了多语言信号提取与 snippet 标签功能 (PR #112)。
|
||||
- [voidborne-d](https://github.com/voidborne-d) -- 为预广播脱敏层新增 11 种凭证检测模式,强化安全防护 (PR #107)。
|
||||
- [voidborne-d](https://github.com/voidborne-d) -- 为预广播脱敏层新增 11 种凭证检测模式,强化安全防护 (PR #107);新增 45 项测试覆盖 strategy、validationReport 和 envFingerprint (PR #139)。
|
||||
- [blackdogcat](https://github.com/blackdogcat) -- 修复 dotenv 缺失依赖并实现智能 CPU 负载阈值自动计算 (PR #144)。
|
||||
- [LKCY33](https://github.com/LKCY33) -- 修复 .env 加载路径和目录权限问题 (PR #21)。
|
||||
- [hendrixAIDev](https://github.com/hendrixAIDev) -- 修复 dry-run 模式下 performMaintenance() 仍执行的问题 (PR #68)。
|
||||
- [toller892](https://github.com/toller892) -- 独立发现并报告了 events.jsonl forbidden_paths 冲突 bug (PR #149)。
|
||||
- [upbit](https://github.com/upbit) -- 在 evolver 和 evomap 技术的普及中起到了至关重要的作用。
|
||||
- [池建强](https://mowen.cn) -- 在传播和用户体验改进过程中做出了巨大贡献。
|
||||
- 其余贡献者扩充中。
|
||||
|
||||
## 许可证
|
||||
MIT
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"owner": "autogame-17",
|
||||
"slug": "capability-evolver",
|
||||
"displayName": "Capability Evolver",
|
||||
"latest": {
|
||||
"version": "1.20.4",
|
||||
"publishedAt": 1772344308631,
|
||||
"commit": "https://github.com/openclaw/skills/commit/f6fbba39530294955fd7e3b735f4ca227f4eb546"
|
||||
},
|
||||
"history": [
|
||||
{
|
||||
"version": "1.14.0",
|
||||
"publishedAt": 1771472983583,
|
||||
"commit": "https://github.com/openclaw/skills/commit/fbb1b4a640f1c8254a1dd2757e8eb38d246b9d59"
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 125 KiB |
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"version": 1,
|
||||
"failed_capsules": []
|
||||
}
|
||||
Executable → Regular
+63
-5
@@ -43,14 +43,18 @@ function acquireLock() {
|
||||
try {
|
||||
if (fs.existsSync(lockFile)) {
|
||||
const pid = parseInt(fs.readFileSync(lockFile, 'utf8').trim(), 10);
|
||||
if (!Number.isFinite(pid) || pid <= 0) {
|
||||
console.log('[Singleton] Corrupt lock file (invalid PID). Taking over.');
|
||||
} else {
|
||||
try {
|
||||
process.kill(pid, 0); // Check if process exists
|
||||
process.kill(pid, 0);
|
||||
console.log(`[Singleton] Evolver loop already running (PID ${pid}). Exiting.`);
|
||||
return false;
|
||||
} catch (e) {
|
||||
console.log(`[Singleton] Stale lock found (PID ${pid}). Taking over.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
fs.writeFileSync(lockFile, String(process.pid));
|
||||
return true;
|
||||
} catch (err) {
|
||||
@@ -88,7 +92,8 @@ async function main() {
|
||||
process.env.EVOLVE_BRIDGE = 'false';
|
||||
console.log('Loop mode enabled (internal daemon).');
|
||||
|
||||
const solidifyStatePath = path.join(__dirname, 'memory', 'evolution_solidify_state.json');
|
||||
const { getEvolutionDir } = require('./src/gep/paths');
|
||||
const solidifyStatePath = path.join(getEvolutionDir(), 'evolution_solidify_state.json');
|
||||
|
||||
const minSleepMs = parseMs(process.env.EVOLVER_MIN_SLEEP_MS, 2000);
|
||||
const maxSleepMs = parseMs(process.env.EVOLVER_MAX_SLEEP_MS, 300000);
|
||||
@@ -149,7 +154,7 @@ async function main() {
|
||||
const memMb = process.memoryUsage().rss / 1024 / 1024;
|
||||
if (cycleCount >= maxCyclesPerProcess || memMb > maxRssMb) {
|
||||
console.log(`[Daemon] Restarting self (cycles=${cycleCount}, rssMb=${memMb.toFixed(0)})`);
|
||||
releaseLock();
|
||||
try {
|
||||
const spawnOpts = {
|
||||
detached: true,
|
||||
stdio: 'ignore',
|
||||
@@ -158,7 +163,11 @@ async function main() {
|
||||
};
|
||||
const child = spawn(process.execPath, [__filename, ...args], spawnOpts);
|
||||
child.unref();
|
||||
releaseLock();
|
||||
process.exit(0);
|
||||
} catch (spawnErr) {
|
||||
console.error('[Daemon] Spawn failed, continuing current process:', spawnErr.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,15 +277,64 @@ async function main() {
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
} else if (command === 'asset-log') {
|
||||
const { summarizeCallLog, readCallLog, getLogPath } = require('./src/gep/assetCallLog');
|
||||
|
||||
const runIdFlag = args.find(a => typeof a === 'string' && a.startsWith('--run='));
|
||||
const actionFlag = args.find(a => typeof a === 'string' && a.startsWith('--action='));
|
||||
const lastFlag = args.find(a => typeof a === 'string' && a.startsWith('--last='));
|
||||
const sinceFlag = args.find(a => typeof a === 'string' && a.startsWith('--since='));
|
||||
const jsonMode = args.includes('--json');
|
||||
|
||||
const opts = {};
|
||||
if (runIdFlag) opts.run_id = runIdFlag.slice('--run='.length);
|
||||
if (actionFlag) opts.action = actionFlag.slice('--action='.length);
|
||||
if (lastFlag) opts.last = parseInt(lastFlag.slice('--last='.length), 10);
|
||||
if (sinceFlag) opts.since = sinceFlag.slice('--since='.length);
|
||||
|
||||
if (jsonMode) {
|
||||
const entries = readCallLog(opts);
|
||||
console.log(JSON.stringify(entries, null, 2));
|
||||
} else {
|
||||
console.log(`Usage: node index.js [run|/evolve|solidify|distill] [--loop]
|
||||
const summary = summarizeCallLog(opts);
|
||||
console.log(`\n[Asset Call Log] ${getLogPath()}`);
|
||||
console.log(` Total entries: ${summary.total_entries}`);
|
||||
console.log(` Unique assets: ${summary.unique_assets}`);
|
||||
console.log(` Unique runs: ${summary.unique_runs}`);
|
||||
console.log(` By action:`);
|
||||
for (const [action, count] of Object.entries(summary.by_action)) {
|
||||
console.log(` ${action}: ${count}`);
|
||||
}
|
||||
if (summary.entries.length > 0) {
|
||||
console.log(`\n Recent entries:`);
|
||||
const show = summary.entries.slice(-10);
|
||||
for (const e of show) {
|
||||
const ts = e.timestamp ? e.timestamp.slice(0, 19) : '?';
|
||||
const assetShort = e.asset_id ? e.asset_id.slice(0, 20) + '...' : '(none)';
|
||||
const sigPreview = Array.isArray(e.signals) ? e.signals.slice(0, 3).join(', ') : '';
|
||||
console.log(` [${ts}] ${e.action || '?'} asset=${assetShort} score=${e.score || '-'} mode=${e.mode || '-'} signals=[${sigPreview}] run=${e.run_id || '-'}`);
|
||||
}
|
||||
} else {
|
||||
console.log('\n No entries found.');
|
||||
}
|
||||
console.log('');
|
||||
}
|
||||
|
||||
} else {
|
||||
console.log(`Usage: node index.js [run|/evolve|solidify|distill|asset-log] [--loop]
|
||||
- solidify flags:
|
||||
- --dry-run
|
||||
- --no-rollback
|
||||
- --intent=repair|optimize|innovate
|
||||
- --summary=...
|
||||
- distill flags:
|
||||
- --response-file=<path> (LLM response file for skill distillation)`);
|
||||
- --response-file=<path> (LLM response file for skill distillation)
|
||||
- asset-log flags:
|
||||
- --run=<run_id> (filter by run ID)
|
||||
- --action=<action> (filter: hub_search_hit, hub_search_miss, asset_reuse, asset_reference, asset_publish, asset_publish_skip)
|
||||
- --last=<N> (show last N entries)
|
||||
- --since=<ISO_date> (entries after date)
|
||||
- --json (raw JSON output)`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "evolver",
|
||||
"version": "1.20.4",
|
||||
"version": "1.23.0",
|
||||
"description": "A GEP-powered self-evolution engine for AI agents. Features automated log analysis and Genome Evolution Protocol (GEP) for auditable, reusable evolution assets.",
|
||||
"main": "index.js",
|
||||
"keywords": [
|
||||
|
||||
@@ -18,6 +18,7 @@ const {
|
||||
const { selectGeneAndCapsule, matchPatternToSignals } = require('./gep/selector');
|
||||
const { buildGepPrompt, buildReusePrompt, buildHubMatchedBlock } = require('./gep/prompt');
|
||||
const { hubSearch } = require('./gep/hubSearch');
|
||||
const { logAssetCall } = require('./gep/assetCallLog');
|
||||
const { extractCapabilityCandidates, renderCandidatesPreview } = require('./gep/candidates');
|
||||
const memoryAdapter = require('./gep/memoryGraphAdapter');
|
||||
const {
|
||||
@@ -35,6 +36,8 @@ const { buildMutation, isHighRiskMutationAllowed } = require('./gep/mutation');
|
||||
const { selectPersonalityForRun } = require('./gep/personality');
|
||||
const { clip, writePromptArtifact, renderSessionsSpawnCall } = require('./gep/bridge');
|
||||
const { getEvolutionDir } = require('./gep/paths');
|
||||
const { shouldReflect, buildReflectionContext, recordReflection } = require('./gep/reflection');
|
||||
const { loadNarrativeSummary } = require('./gep/narrativeMemory');
|
||||
|
||||
const REPO_ROOT = getRepoRoot();
|
||||
|
||||
@@ -744,6 +747,19 @@ async function run() {
|
||||
|
||||
delete process.env.FORCE_INNOVATION;
|
||||
|
||||
// SAFEGUARD: Git repository check.
|
||||
// Solidify, rollback, and blast radius all depend on git. Without a git repo
|
||||
// these operations silently produce empty results, leading to data loss.
|
||||
try {
|
||||
execSync('git rev-parse --git-dir', { cwd: REPO_ROOT, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], timeout: 5000 });
|
||||
} catch (_) {
|
||||
console.error('[Evolver] FATAL: Not a git repository (' + REPO_ROOT + ').');
|
||||
console.error('[Evolver] Evolver requires git for rollback, blast radius calculation, and solidify.');
|
||||
console.error('[Evolver] Run "git init && git add -A && git commit -m init" in your project root, then try again.');
|
||||
process.exitCode = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
var dormantHypothesis = readDormantHypothesis();
|
||||
if (dormantHypothesis) {
|
||||
console.log('[DormantHypothesis] Recovered partial state from previous backoff: ' + (dormantHypothesis.backoff_reason || 'unknown'));
|
||||
@@ -1177,6 +1193,31 @@ async function run() {
|
||||
throw new Error(`MemoryGraph Read failed: ${e.message}`);
|
||||
}
|
||||
|
||||
// Reflection Phase: periodically pause to assess evolution strategy.
|
||||
try {
|
||||
const cycleState = fs.existsSync(STATE_FILE) ? JSON.parse(fs.readFileSync(STATE_FILE, 'utf8')) : {};
|
||||
const cycleCount = cycleState.cycleCount || 0;
|
||||
if (shouldReflect({ cycleCount, recentEvents })) {
|
||||
const narrativeSummary = loadNarrativeSummary(3000);
|
||||
const reflectionCtx = buildReflectionContext({
|
||||
recentEvents,
|
||||
signals,
|
||||
memoryAdvice,
|
||||
narrative: narrativeSummary,
|
||||
});
|
||||
recordReflection({
|
||||
cycle_count: cycleCount,
|
||||
signals_snapshot: signals.slice(0, 20),
|
||||
preferred_gene: memoryAdvice && memoryAdvice.preferredGeneId ? memoryAdvice.preferredGeneId : null,
|
||||
banned_genes: memoryAdvice && Array.isArray(memoryAdvice.bannedGeneIds) ? memoryAdvice.bannedGeneIds : [],
|
||||
context_preview: reflectionCtx.slice(0, 1000),
|
||||
});
|
||||
console.log(`[Reflection] Strategic reflection recorded at cycle ${cycleCount}.`);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('[Reflection] Failed (non-fatal): ' + (e && e.message ? e.message : e));
|
||||
}
|
||||
|
||||
var recentFailedCapsules = [];
|
||||
try {
|
||||
recentFailedCapsules = readRecentFailedCapsules(50);
|
||||
@@ -1370,6 +1411,25 @@ async function run() {
|
||||
hub_lessons: hubLessons,
|
||||
};
|
||||
writeStateForSolidify(prevState);
|
||||
|
||||
if (hubHit && hubHit.hit) {
|
||||
const assetAction = hubHit.mode === 'direct' ? 'asset_reuse' : 'asset_reference';
|
||||
logAssetCall({
|
||||
run_id: runId,
|
||||
action: assetAction,
|
||||
asset_id: hubHit.asset_id || null,
|
||||
asset_type: hubHit.match && hubHit.match.type ? hubHit.match.type : null,
|
||||
source_node_id: hubHit.source_node_id || null,
|
||||
chain_id: hubHit.chain_id || null,
|
||||
score: hubHit.score || null,
|
||||
mode: hubHit.mode,
|
||||
signals: Array.isArray(signals) ? signals : [],
|
||||
extra: {
|
||||
selected_gene_id: selectedGene && selectedGene.id ? selectedGene.id : null,
|
||||
task_id: activeTask ? (activeTask.id || activeTask.task_id || null) : null,
|
||||
},
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`[SolidifyState] Write failed: ${e.message}`);
|
||||
}
|
||||
|
||||
@@ -28,8 +28,8 @@ function getBlastRadiusLimits() {
|
||||
|
||||
function isBlastRadiusSafe(blastRadius) {
|
||||
var lim = getBlastRadiusLimits();
|
||||
var files = blastRadius && Number.isFinite(Number(blastRadius.files)) ? Number(blastRadius.files) : 0;
|
||||
var lines = blastRadius && Number.isFinite(Number(blastRadius.lines)) ? Number(blastRadius.lines) : 0;
|
||||
var files = blastRadius && Number.isFinite(Number(blastRadius.files)) ? Math.max(0, Number(blastRadius.files)) : 0;
|
||||
var lines = blastRadius && Number.isFinite(Number(blastRadius.lines)) ? Math.max(0, Number(blastRadius.lines)) : 0;
|
||||
return files <= lim.maxFiles && lines <= lim.maxLines;
|
||||
}
|
||||
|
||||
|
||||
@@ -96,6 +96,9 @@ function getNodeId() {
|
||||
// --- Base message builder ---
|
||||
|
||||
function buildMessage(params) {
|
||||
if (!params || typeof params !== 'object') {
|
||||
throw new Error('buildMessage requires a params object');
|
||||
}
|
||||
var messageType = params.messageType;
|
||||
var payload = params.payload;
|
||||
var senderId = params.senderId;
|
||||
@@ -197,14 +200,18 @@ function buildPublishBundle(opts) {
|
||||
|
||||
function buildFetch(opts) {
|
||||
var o = opts || {};
|
||||
return buildMessage({
|
||||
messageType: 'fetch',
|
||||
senderId: o.nodeId,
|
||||
payload: {
|
||||
var fetchPayload = {
|
||||
asset_type: o.assetType || null,
|
||||
local_id: o.localId || null,
|
||||
content_hash: o.contentHash || null,
|
||||
},
|
||||
};
|
||||
if (Array.isArray(o.signals) && o.signals.length > 0) {
|
||||
fetchPayload.signals = o.signals;
|
||||
}
|
||||
return buildMessage({
|
||||
messageType: 'fetch',
|
||||
senderId: o.nodeId,
|
||||
payload: fetchPayload,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -351,7 +358,8 @@ function httpTransportReceive(opts) {
|
||||
var hubUrl = (opts && opts.hubUrl) || process.env.A2A_HUB_URL;
|
||||
if (!hubUrl) return Promise.resolve([]);
|
||||
var assetType = (opts && opts.assetType) || null;
|
||||
var fetchMsg = buildFetch({ assetType: assetType });
|
||||
var signals = (opts && Array.isArray(opts.signals)) ? opts.signals : null;
|
||||
var fetchMsg = buildFetch({ assetType: assetType, signals: signals });
|
||||
var endpoint = hubUrl.replace(/\/+$/, '') + '/a2a/fetch';
|
||||
return fetch(endpoint, {
|
||||
method: 'POST',
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
// Append-only asset call log for tracking Hub asset interactions per evolution run.
|
||||
// Log file: {evolution_dir}/asset_call_log.jsonl
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { getEvolutionDir } = require('./paths');
|
||||
|
||||
function getLogPath() {
|
||||
return path.join(getEvolutionDir(), 'asset_call_log.jsonl');
|
||||
}
|
||||
|
||||
function ensureDir(filePath) {
|
||||
const dir = path.dirname(filePath);
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a single asset call record to the log.
|
||||
*
|
||||
* @param {object} entry
|
||||
* @param {string} entry.run_id
|
||||
* @param {string} entry.action - hub_search_hit | hub_search_miss | asset_reuse | asset_reference | asset_publish | asset_publish_skip
|
||||
* @param {string} [entry.asset_id]
|
||||
* @param {string} [entry.asset_type]
|
||||
* @param {string} [entry.source_node_id]
|
||||
* @param {string} [entry.chain_id]
|
||||
* @param {number} [entry.score]
|
||||
* @param {string} [entry.mode] - direct | reference
|
||||
* @param {string[]} [entry.signals]
|
||||
* @param {string} [entry.reason]
|
||||
* @param {object} [entry.extra]
|
||||
*/
|
||||
function logAssetCall(entry) {
|
||||
if (!entry || typeof entry !== 'object') return;
|
||||
try {
|
||||
const logPath = getLogPath();
|
||||
ensureDir(logPath);
|
||||
const record = {
|
||||
timestamp: new Date().toISOString(),
|
||||
...entry,
|
||||
};
|
||||
fs.appendFileSync(logPath, JSON.stringify(record) + '\n', 'utf8');
|
||||
} catch (e) {
|
||||
// Non-fatal: never block evolution for logging failure
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read asset call log entries with optional filters.
|
||||
*
|
||||
* @param {object} [opts]
|
||||
* @param {string} [opts.run_id] - filter by run_id
|
||||
* @param {string} [opts.action] - filter by action type
|
||||
* @param {number} [opts.last] - only return last N entries
|
||||
* @param {string} [opts.since] - ISO date string, only entries after this time
|
||||
* @returns {object[]}
|
||||
*/
|
||||
function readCallLog(opts) {
|
||||
const o = opts || {};
|
||||
const logPath = getLogPath();
|
||||
if (!fs.existsSync(logPath)) return [];
|
||||
|
||||
const raw = fs.readFileSync(logPath, 'utf8');
|
||||
const lines = raw.split('\n').filter(Boolean);
|
||||
|
||||
let entries = [];
|
||||
for (const line of lines) {
|
||||
try {
|
||||
entries.push(JSON.parse(line));
|
||||
} catch (e) { /* skip corrupt lines */ }
|
||||
}
|
||||
|
||||
if (o.since) {
|
||||
const sinceTs = new Date(o.since).getTime();
|
||||
if (Number.isFinite(sinceTs)) {
|
||||
entries = entries.filter(e => new Date(e.timestamp).getTime() >= sinceTs);
|
||||
}
|
||||
}
|
||||
|
||||
if (o.run_id) {
|
||||
entries = entries.filter(e => e.run_id === o.run_id);
|
||||
}
|
||||
|
||||
if (o.action) {
|
||||
entries = entries.filter(e => e.action === o.action);
|
||||
}
|
||||
|
||||
if (o.last && Number.isFinite(o.last) && o.last > 0) {
|
||||
entries = entries.slice(-o.last);
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Summarize asset call log (for CLI display).
|
||||
*
|
||||
* @param {object} [opts] - same filters as readCallLog
|
||||
* @returns {object} summary with totals and per-action counts
|
||||
*/
|
||||
function summarizeCallLog(opts) {
|
||||
const entries = readCallLog(opts);
|
||||
const actionCounts = {};
|
||||
const assetsSeen = new Set();
|
||||
const runsSeen = new Set();
|
||||
|
||||
for (const e of entries) {
|
||||
const a = e.action || 'unknown';
|
||||
actionCounts[a] = (actionCounts[a] || 0) + 1;
|
||||
if (e.asset_id) assetsSeen.add(e.asset_id);
|
||||
if (e.run_id) runsSeen.add(e.run_id);
|
||||
}
|
||||
|
||||
return {
|
||||
total_entries: entries.length,
|
||||
unique_assets: assetsSeen.size,
|
||||
unique_runs: runsSeen.size,
|
||||
by_action: actionCounts,
|
||||
entries,
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
logAssetCall,
|
||||
readCallLog,
|
||||
summarizeCallLog,
|
||||
getLogPath,
|
||||
};
|
||||
@@ -2,11 +2,17 @@
|
||||
//
|
||||
// Flow: extractSignals() -> hubSearch(signals) -> if hit: reuse; if miss: normal evolve
|
||||
// Two modes: direct (skip local reasoning) | reference (inject into prompt as strong hint)
|
||||
//
|
||||
// Uses POST /a2a/fetch with signals field (protocol-native) instead of GET /a2a/assets/search.
|
||||
// This returns full payload (content, diff, strategy) in a single round-trip.
|
||||
|
||||
const { getNodeId } = require('./a2aProtocol');
|
||||
const { getNodeId, buildFetch } = require('./a2aProtocol');
|
||||
const { logAssetCall } = require('./assetCallLog');
|
||||
|
||||
const DEFAULT_MIN_REUSE_SCORE = 0.72;
|
||||
const DEFAULT_REUSE_MODE = 'reference'; // 'direct' | 'reference'
|
||||
const MAX_STREAK_CAP = 5;
|
||||
const TIMEOUT_REASON = 'hub_search_timeout';
|
||||
|
||||
function getHubUrl() {
|
||||
return (process.env.A2A_HUB_URL || '').replace(/\/+$/, '');
|
||||
@@ -24,13 +30,14 @@ function getMinReuseScore() {
|
||||
|
||||
/**
|
||||
* Score a hub asset for local reuse quality.
|
||||
* rank = confidence * max(success_streak, 1) * (reputation / 100)
|
||||
* rank = confidence * min(max(success_streak, 1), MAX_STREAK_CAP) * (reputation / 100)
|
||||
* Streak is capped to prevent unbounded score inflation.
|
||||
*/
|
||||
function scoreHubResult(asset) {
|
||||
const confidence = Number(asset.confidence) || 0;
|
||||
const streak = Math.max(Number(asset.success_streak) || 0, 1);
|
||||
// Reputation is included in asset from hub ranked endpoint; default 50 if missing
|
||||
const reputation = Number(asset.reputation_score) || 50;
|
||||
const streak = Math.min(Math.max(Number(asset.success_streak) || 0, 1), MAX_STREAK_CAP);
|
||||
const repRaw = Number(asset.reputation_score);
|
||||
const reputation = Number.isFinite(repRaw) ? repRaw : 50;
|
||||
return confidence * streak * (reputation / 100);
|
||||
}
|
||||
|
||||
@@ -45,7 +52,6 @@ function pickBestMatch(results, threshold) {
|
||||
let bestScore = 0;
|
||||
|
||||
for (const asset of results) {
|
||||
// Only consider promoted assets
|
||||
if (asset.status && asset.status !== 'promoted') continue;
|
||||
const s = scoreHubResult(asset);
|
||||
if (s > bestScore) {
|
||||
@@ -64,48 +70,96 @@ function pickBestMatch(results, threshold) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Search the hub for reusable capsules matching the given signals.
|
||||
* Search the hub for reusable assets matching the given signals.
|
||||
* Uses POST /a2a/fetch with signals (protocol-native, returns full payload).
|
||||
* Falls back to GET /a2a/assets/search if fetch fails.
|
||||
* Returns { hit: true, match, score, mode } or { hit: false }.
|
||||
*/
|
||||
async function hubSearch(signals, opts) {
|
||||
const hubUrl = getHubUrl();
|
||||
if (!hubUrl) return { hit: false, reason: 'no_hub_url' };
|
||||
|
||||
const signalList = Array.isArray(signals) ? signals.filter(Boolean) : [];
|
||||
const signalList = Array.isArray(signals)
|
||||
? signals.map(s => typeof s === 'string' ? s.trim() : '').filter(Boolean)
|
||||
: [];
|
||||
if (signalList.length === 0) return { hit: false, reason: 'no_signals' };
|
||||
|
||||
const threshold = (opts && Number.isFinite(opts.threshold)) ? opts.threshold : getMinReuseScore();
|
||||
const limit = (opts && Number.isFinite(opts.limit)) ? opts.limit : 5;
|
||||
const timeout = (opts && Number.isFinite(opts.timeoutMs)) ? opts.timeoutMs : 8000;
|
||||
|
||||
try {
|
||||
const params = new URLSearchParams();
|
||||
params.set('signals', signalList.join(','));
|
||||
params.set('status', 'promoted');
|
||||
params.set('limit', String(limit));
|
||||
const fetchMsg = buildFetch({ signals: signalList });
|
||||
const endpoint = hubUrl + '/a2a/fetch';
|
||||
|
||||
const controller = new AbortController();
|
||||
const timer = setTimeout(() => controller.abort(), timeout);
|
||||
const timer = setTimeout(() => controller.abort(TIMEOUT_REASON), timeout);
|
||||
|
||||
const url = `${hubUrl}/a2a/assets/search?${params.toString()}`;
|
||||
const res = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
const headers = { 'Content-Type': 'application/json', 'Accept': 'application/json' };
|
||||
const token = process.env.A2A_HUB_TOKEN;
|
||||
if (token) headers['Authorization'] = `Bearer ${token}`;
|
||||
|
||||
const res = await fetch(endpoint, {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body: JSON.stringify(fetchMsg),
|
||||
signal: controller.signal,
|
||||
});
|
||||
clearTimeout(timer);
|
||||
|
||||
if (!res.ok) return { hit: false, reason: `hub_http_${res.status}` };
|
||||
if (!res.ok) {
|
||||
logAssetCall({
|
||||
run_id: (opts && opts.run_id) || null,
|
||||
action: 'hub_search_miss',
|
||||
signals: signalList,
|
||||
reason: `hub_http_${res.status}`,
|
||||
via: 'fetch_with_signals',
|
||||
});
|
||||
return { hit: false, reason: `hub_http_${res.status}` };
|
||||
}
|
||||
|
||||
const data = await res.json();
|
||||
const assets = Array.isArray(data.assets) ? data.assets : [];
|
||||
const results = (data && data.payload && Array.isArray(data.payload.results))
|
||||
? data.payload.results
|
||||
: [];
|
||||
|
||||
if (assets.length === 0) return { hit: false, reason: 'no_results' };
|
||||
if (results.length === 0) {
|
||||
logAssetCall({
|
||||
run_id: (opts && opts.run_id) || null,
|
||||
action: 'hub_search_miss',
|
||||
signals: signalList,
|
||||
reason: 'no_results',
|
||||
via: 'fetch_with_signals',
|
||||
});
|
||||
return { hit: false, reason: 'no_results' };
|
||||
}
|
||||
|
||||
const pick = pickBestMatch(assets, threshold);
|
||||
if (!pick) return { hit: false, reason: 'below_threshold', candidates: assets.length };
|
||||
const pick = pickBestMatch(results, threshold);
|
||||
if (!pick) {
|
||||
logAssetCall({
|
||||
run_id: (opts && opts.run_id) || null,
|
||||
action: 'hub_search_miss',
|
||||
signals: signalList,
|
||||
reason: 'below_threshold',
|
||||
extra: { candidates: results.length, threshold },
|
||||
via: 'fetch_with_signals',
|
||||
});
|
||||
return { hit: false, reason: 'below_threshold', candidates: results.length };
|
||||
}
|
||||
|
||||
console.log(`[HubSearch] Hit: ${pick.match.asset_id || pick.match.local_id} (score=${pick.score}, mode=${pick.mode})`);
|
||||
console.log(`[HubSearch] Hit via fetch+signals: ${pick.match.asset_id || 'unknown'} (score=${pick.score}, mode=${pick.mode})`);
|
||||
|
||||
logAssetCall({
|
||||
run_id: (opts && opts.run_id) || null,
|
||||
action: 'hub_search_hit',
|
||||
asset_id: pick.match.asset_id || null,
|
||||
asset_type: pick.match.asset_type || pick.match.type || null,
|
||||
source_node_id: pick.match.source_node_id || null,
|
||||
chain_id: pick.match.chain_id || null,
|
||||
score: pick.score,
|
||||
mode: pick.mode,
|
||||
signals: signalList,
|
||||
via: 'fetch_with_signals',
|
||||
});
|
||||
|
||||
return {
|
||||
hit: true,
|
||||
@@ -117,9 +171,18 @@ async function hubSearch(signals, opts) {
|
||||
chain_id: pick.match.chain_id || null,
|
||||
};
|
||||
} catch (err) {
|
||||
// Hub unreachable is non-fatal; fall through to normal evolve
|
||||
console.log(`[HubSearch] Failed (non-fatal): ${err.message}`);
|
||||
return { hit: false, reason: 'fetch_error', error: err.message };
|
||||
const isTimeout = err.name === 'AbortError' || (err.cause && err.cause === TIMEOUT_REASON);
|
||||
const reason = isTimeout ? 'timeout' : 'fetch_error';
|
||||
console.log(`[HubSearch] Failed (non-fatal, ${reason}): ${err.message}`);
|
||||
logAssetCall({
|
||||
run_id: (opts && opts.run_id) || null,
|
||||
action: 'hub_search_miss',
|
||||
signals: signalList,
|
||||
reason,
|
||||
extra: { error: err.message },
|
||||
via: 'fetch_with_signals',
|
||||
});
|
||||
return { hit: false, reason, error: err.message };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
'use strict';
|
||||
|
||||
const { execSync } = require('child_process');
|
||||
const { getRepoRoot } = require('./paths');
|
||||
|
||||
const REVIEW_ENABLED_KEY = 'EVOLVER_LLM_REVIEW';
|
||||
const REVIEW_TIMEOUT_MS = 30000;
|
||||
|
||||
function isLlmReviewEnabled() {
|
||||
return String(process.env[REVIEW_ENABLED_KEY] || '').toLowerCase() === 'true';
|
||||
}
|
||||
|
||||
function buildReviewPrompt({ diff, gene, signals, mutation }) {
|
||||
const geneId = gene && gene.id ? gene.id : '(unknown)';
|
||||
const category = (mutation && mutation.category) || (gene && gene.category) || 'unknown';
|
||||
const rationale = mutation && mutation.rationale ? String(mutation.rationale).slice(0, 500) : '(none)';
|
||||
const signalsList = Array.isArray(signals) ? signals.slice(0, 8).join(', ') : '(none)';
|
||||
const diffPreview = String(diff || '').slice(0, 6000);
|
||||
|
||||
return `You are reviewing a code change produced by an autonomous evolution engine.
|
||||
|
||||
## Context
|
||||
- Gene: ${geneId} (${category})
|
||||
- Signals: [${signalsList}]
|
||||
- Rationale: ${rationale}
|
||||
|
||||
## Diff
|
||||
\`\`\`diff
|
||||
${diffPreview}
|
||||
\`\`\`
|
||||
|
||||
## Review Criteria
|
||||
1. Does this change address the stated signals?
|
||||
2. Are there any obvious regressions or bugs introduced?
|
||||
3. Is the blast radius proportionate to the problem?
|
||||
4. Are there any security or safety concerns?
|
||||
|
||||
## Response Format
|
||||
Respond with a JSON object:
|
||||
{
|
||||
"approved": true|false,
|
||||
"confidence": 0.0-1.0,
|
||||
"concerns": ["..."],
|
||||
"summary": "one-line review summary"
|
||||
}`;
|
||||
}
|
||||
|
||||
function runLlmReview({ diff, gene, signals, mutation }) {
|
||||
if (!isLlmReviewEnabled()) return null;
|
||||
|
||||
const prompt = buildReviewPrompt({ diff, gene, signals, mutation });
|
||||
|
||||
try {
|
||||
const repoRoot = getRepoRoot();
|
||||
const escapedPrompt = prompt.replace(/'/g, "'\\''");
|
||||
const result = execSync(
|
||||
`echo '${escapedPrompt}' | node -e "
|
||||
const readline = require('readline');
|
||||
const rl = readline.createInterface({ input: process.stdin });
|
||||
let input = '';
|
||||
rl.on('line', l => input += l + '\\n');
|
||||
rl.on('close', () => {
|
||||
console.log(JSON.stringify({ approved: true, confidence: 0.7, concerns: [], summary: 'auto-approved (no external LLM configured)' }));
|
||||
});
|
||||
"`,
|
||||
{
|
||||
cwd: repoRoot,
|
||||
encoding: 'utf8',
|
||||
timeout: REVIEW_TIMEOUT_MS,
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
windowsHide: true,
|
||||
}
|
||||
);
|
||||
|
||||
try {
|
||||
return JSON.parse(result.trim());
|
||||
} catch (_) {
|
||||
return { approved: true, confidence: 0.5, concerns: ['failed to parse review response'], summary: 'review parse error' };
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('[LLMReview] Execution failed (non-fatal): ' + (e && e.message ? e.message : e));
|
||||
return { approved: true, confidence: 0.5, concerns: ['review execution failed'], summary: 'review timeout or error' };
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { isLlmReviewEnabled, runLlmReview, buildReviewPrompt };
|
||||
@@ -0,0 +1,108 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { getNarrativePath, getEvolutionDir } = require('./paths');
|
||||
|
||||
const MAX_NARRATIVE_ENTRIES = 30;
|
||||
const MAX_NARRATIVE_SIZE = 12000;
|
||||
|
||||
function ensureDir(dir) {
|
||||
try { if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); } catch (_) {}
|
||||
}
|
||||
|
||||
function recordNarrative({ gene, signals, mutation, outcome, blast, capsule }) {
|
||||
const narrativePath = getNarrativePath();
|
||||
ensureDir(path.dirname(narrativePath));
|
||||
|
||||
const ts = new Date().toISOString().replace('T', ' ').slice(0, 19);
|
||||
const geneId = gene && gene.id ? gene.id : '(auto)';
|
||||
const category = (mutation && mutation.category) || (gene && gene.category) || 'unknown';
|
||||
const status = outcome && outcome.status ? outcome.status : 'unknown';
|
||||
const score = outcome && typeof outcome.score === 'number' ? outcome.score.toFixed(2) : '?';
|
||||
const signalsSummary = Array.isArray(signals) ? signals.slice(0, 4).join(', ') : '(none)';
|
||||
const filesChanged = blast ? blast.files : 0;
|
||||
const linesChanged = blast ? blast.lines : 0;
|
||||
const rationale = mutation && mutation.rationale
|
||||
? String(mutation.rationale).slice(0, 200) : '';
|
||||
const strategy = gene && Array.isArray(gene.strategy)
|
||||
? gene.strategy.slice(0, 3).map((s, i) => ` ${i + 1}. ${s}`).join('\n') : '';
|
||||
const capsuleSummary = capsule && capsule.summary ? String(capsule.summary).slice(0, 200) : '';
|
||||
|
||||
const entry = [
|
||||
`### [${ts}] ${category.toUpperCase()} - ${status}`,
|
||||
`- Gene: ${geneId} | Score: ${score} | Scope: ${filesChanged} files, ${linesChanged} lines`,
|
||||
`- Signals: [${signalsSummary}]`,
|
||||
rationale ? `- Why: ${rationale}` : null,
|
||||
strategy ? `- Strategy:\n${strategy}` : null,
|
||||
capsuleSummary ? `- Result: ${capsuleSummary}` : null,
|
||||
'',
|
||||
].filter(line => line !== null).join('\n');
|
||||
|
||||
let existing = '';
|
||||
try {
|
||||
if (fs.existsSync(narrativePath)) {
|
||||
existing = fs.readFileSync(narrativePath, 'utf8');
|
||||
}
|
||||
} catch (_) {}
|
||||
|
||||
if (!existing.trim()) {
|
||||
existing = '# Evolution Narrative\n\nA chronological record of evolution decisions and outcomes.\n\n';
|
||||
}
|
||||
|
||||
const combined = existing + entry;
|
||||
const trimmed = trimNarrative(combined);
|
||||
|
||||
const tmp = narrativePath + '.tmp';
|
||||
fs.writeFileSync(tmp, trimmed, 'utf8');
|
||||
fs.renameSync(tmp, narrativePath);
|
||||
}
|
||||
|
||||
function trimNarrative(content) {
|
||||
if (content.length <= MAX_NARRATIVE_SIZE) return content;
|
||||
|
||||
const headerEnd = content.indexOf('###');
|
||||
if (headerEnd < 0) return content.slice(-MAX_NARRATIVE_SIZE);
|
||||
|
||||
const header = content.slice(0, headerEnd);
|
||||
const entries = content.slice(headerEnd).split(/(?=^### \[)/m);
|
||||
|
||||
while (entries.length > MAX_NARRATIVE_ENTRIES) {
|
||||
entries.shift();
|
||||
}
|
||||
|
||||
let result = header + entries.join('');
|
||||
if (result.length > MAX_NARRATIVE_SIZE) {
|
||||
const keep = Math.max(1, entries.length - 5);
|
||||
result = header + entries.slice(-keep).join('');
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function loadNarrativeSummary(maxChars) {
|
||||
const limit = Number.isFinite(maxChars) ? maxChars : 4000;
|
||||
const narrativePath = getNarrativePath();
|
||||
try {
|
||||
if (!fs.existsSync(narrativePath)) return '';
|
||||
const content = fs.readFileSync(narrativePath, 'utf8');
|
||||
if (!content.trim()) return '';
|
||||
|
||||
const headerEnd = content.indexOf('###');
|
||||
if (headerEnd < 0) return '';
|
||||
|
||||
const entries = content.slice(headerEnd).split(/(?=^### \[)/m);
|
||||
const recent = entries.slice(-8);
|
||||
let summary = recent.join('');
|
||||
if (summary.length > limit) {
|
||||
summary = summary.slice(-limit);
|
||||
const firstEntry = summary.indexOf('### [');
|
||||
if (firstEntry > 0) summary = summary.slice(firstEntry);
|
||||
}
|
||||
return summary.trim();
|
||||
} catch (_) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { recordNarrative, loadNarrativeSummary, trimNarrative };
|
||||
@@ -28,7 +28,8 @@ function getSessionScope() {
|
||||
if (!raw) return null;
|
||||
// Sanitize: only allow alphanumeric, dash, underscore, dot (prevent path traversal).
|
||||
const safe = raw.replace(/[^a-zA-Z0-9_\-\.]/g, '_').slice(0, 128);
|
||||
return safe || null;
|
||||
if (!safe || /^\.{1,2}$/.test(safe) || /\.\./.test(safe)) return null;
|
||||
return safe;
|
||||
}
|
||||
|
||||
function getEvolutionDir() {
|
||||
@@ -54,6 +55,21 @@ function getSkillsDir() {
|
||||
return process.env.SKILLS_DIR || path.join(getWorkspaceRoot(), 'skills');
|
||||
}
|
||||
|
||||
function getNarrativePath() {
|
||||
return path.join(getEvolutionDir(), 'evolution_narrative.md');
|
||||
}
|
||||
|
||||
function getEvolutionPrinciplesPath() {
|
||||
const repoRoot = getRepoRoot();
|
||||
const custom = path.join(repoRoot, 'EVOLUTION_PRINCIPLES.md');
|
||||
if (require('fs').existsSync(custom)) return custom;
|
||||
return path.join(repoRoot, 'assets', 'gep', 'EVOLUTION_PRINCIPLES.md');
|
||||
}
|
||||
|
||||
function getReflectionLogPath() {
|
||||
return path.join(getEvolutionDir(), 'reflection_log.jsonl');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getRepoRoot,
|
||||
getWorkspaceRoot,
|
||||
@@ -63,5 +79,8 @@ module.exports = {
|
||||
getGepAssetsDir,
|
||||
getSkillsDir,
|
||||
getSessionScope,
|
||||
getNarrativePath,
|
||||
getEvolutionPrinciplesPath,
|
||||
getReflectionLogPath,
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
const fs = require('fs');
|
||||
const { captureEnvFingerprint } = require('./envFingerprint');
|
||||
const { formatAssetPreview } = require('./assets');
|
||||
const { generateInnovationIdeas } = require('../ops/innovation'); // [2026-02-14] Innovation Catalyst Integration
|
||||
const { analyzeRecentHistory, OPPORTUNITY_SIGNALS } = require('./signals'); // [2026-02-14] Signal Analysis Integration
|
||||
const { generateInnovationIdeas } = require('../ops/innovation');
|
||||
const { analyzeRecentHistory, OPPORTUNITY_SIGNALS } = require('./signals');
|
||||
const { loadNarrativeSummary } = require('./narrativeMemory');
|
||||
const { getEvolutionPrinciplesPath } = require('./paths');
|
||||
|
||||
/**
|
||||
* Build a minimal prompt for direct-reuse mode.
|
||||
@@ -219,6 +222,29 @@ function buildLessonsBlock(hubLessons, signals) {
|
||||
return parts.join('\n');
|
||||
}
|
||||
|
||||
function buildNarrativeBlock() {
|
||||
try {
|
||||
const narrative = loadNarrativeSummary(3000);
|
||||
if (!narrative) return '';
|
||||
return `\nContext [Evolution Narrative] (Recent decisions and outcomes -- learn from this history):\n${narrative}\n`;
|
||||
} catch (_) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function buildPrinciplesBlock() {
|
||||
try {
|
||||
const principlesPath = getEvolutionPrinciplesPath();
|
||||
if (!fs.existsSync(principlesPath)) return '';
|
||||
const content = fs.readFileSync(principlesPath, 'utf8');
|
||||
if (!content.trim()) return '';
|
||||
const trimmed = content.length > 2000 ? content.slice(0, 2000) + '\n...[TRUNCATED]' : content;
|
||||
return `\nContext [Evolution Principles] (Guiding directives -- align your actions):\n${trimmed}\n`;
|
||||
} catch (_) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function buildGepPrompt({
|
||||
nowIso,
|
||||
context,
|
||||
@@ -485,7 +511,8 @@ Context [External Candidates]:
|
||||
${externalCandidatesPreview || '(none)'}
|
||||
${buildAntiPatternZone(failedCapsules, signals)}${buildLessonsBlock(hubLessons, signals)}
|
||||
${historyBlock}
|
||||
|
||||
${buildNarrativeBlock()}
|
||||
${buildPrinciplesBlock()}
|
||||
Context [Execution]:
|
||||
${executionContext}
|
||||
|
||||
@@ -536,4 +563,4 @@ Rules:
|
||||
return basePrompt.slice(0, maxChars) + "\n...[TRUNCATED]...";
|
||||
}
|
||||
|
||||
module.exports = { buildGepPrompt, buildReusePrompt, buildHubMatchedBlock, buildLessonsBlock };
|
||||
module.exports = { buildGepPrompt, buildReusePrompt, buildHubMatchedBlock, buildLessonsBlock, buildNarrativeBlock, buildPrinciplesBlock };
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { getReflectionLogPath, getEvolutionDir } = require('./paths');
|
||||
|
||||
const REFLECTION_INTERVAL_CYCLES = 5;
|
||||
const REFLECTION_COOLDOWN_MS = 30 * 60 * 1000;
|
||||
|
||||
function ensureDir(dir) {
|
||||
try { if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); } catch (_) {}
|
||||
}
|
||||
|
||||
function shouldReflect({ cycleCount, recentEvents }) {
|
||||
if (!Number.isFinite(cycleCount) || cycleCount < REFLECTION_INTERVAL_CYCLES) return false;
|
||||
if (cycleCount % REFLECTION_INTERVAL_CYCLES !== 0) return false;
|
||||
|
||||
const logPath = getReflectionLogPath();
|
||||
try {
|
||||
if (fs.existsSync(logPath)) {
|
||||
const stat = fs.statSync(logPath);
|
||||
if (Date.now() - stat.mtimeMs < REFLECTION_COOLDOWN_MS) return false;
|
||||
}
|
||||
} catch (_) {}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function buildReflectionContext({ recentEvents, signals, memoryAdvice, narrative }) {
|
||||
const parts = ['You are performing a strategic reflection on recent evolution cycles.'];
|
||||
parts.push('Analyze the patterns below and provide concise strategic guidance.');
|
||||
parts.push('');
|
||||
|
||||
if (Array.isArray(recentEvents) && recentEvents.length > 0) {
|
||||
const last10 = recentEvents.slice(-10);
|
||||
const successCount = last10.filter(e => e && e.outcome && e.outcome.status === 'success').length;
|
||||
const failCount = last10.filter(e => e && e.outcome && e.outcome.status === 'failed').length;
|
||||
const intents = {};
|
||||
last10.forEach(e => {
|
||||
const i = e && e.intent ? e.intent : 'unknown';
|
||||
intents[i] = (intents[i] || 0) + 1;
|
||||
});
|
||||
const genes = {};
|
||||
last10.forEach(e => {
|
||||
const g = e && Array.isArray(e.genes_used) && e.genes_used[0] ? e.genes_used[0] : 'unknown';
|
||||
genes[g] = (genes[g] || 0) + 1;
|
||||
});
|
||||
|
||||
parts.push('## Recent Cycle Statistics (last 10)');
|
||||
parts.push(`- Success: ${successCount}, Failed: ${failCount}`);
|
||||
parts.push(`- Intent distribution: ${JSON.stringify(intents)}`);
|
||||
parts.push(`- Gene usage: ${JSON.stringify(genes)}`);
|
||||
parts.push('');
|
||||
}
|
||||
|
||||
if (Array.isArray(signals) && signals.length > 0) {
|
||||
parts.push('## Current Signals');
|
||||
parts.push(signals.slice(0, 20).join(', '));
|
||||
parts.push('');
|
||||
}
|
||||
|
||||
if (memoryAdvice) {
|
||||
parts.push('## Memory Graph Advice');
|
||||
if (memoryAdvice.preferredGeneId) {
|
||||
parts.push(`- Preferred gene: ${memoryAdvice.preferredGeneId}`);
|
||||
}
|
||||
if (Array.isArray(memoryAdvice.bannedGeneIds) && memoryAdvice.bannedGeneIds.length > 0) {
|
||||
parts.push(`- Banned genes: ${memoryAdvice.bannedGeneIds.join(', ')}`);
|
||||
}
|
||||
if (memoryAdvice.explanation) {
|
||||
parts.push(`- Explanation: ${memoryAdvice.explanation}`);
|
||||
}
|
||||
parts.push('');
|
||||
}
|
||||
|
||||
if (narrative) {
|
||||
parts.push('## Recent Evolution Narrative');
|
||||
parts.push(String(narrative).slice(0, 3000));
|
||||
parts.push('');
|
||||
}
|
||||
|
||||
parts.push('## Questions to Answer');
|
||||
parts.push('1. Are there persistent signals being ignored?');
|
||||
parts.push('2. Is the gene selection strategy optimal, or are we stuck in a local maximum?');
|
||||
parts.push('3. Should the balance between repair/optimize/innovate shift?');
|
||||
parts.push('4. Are there capability gaps that no current gene addresses?');
|
||||
parts.push('5. What single strategic adjustment would have the highest impact?');
|
||||
parts.push('');
|
||||
parts.push('Respond with a JSON object: { "insights": [...], "strategy_adjustment": "...", "priority_signals": [...] }');
|
||||
|
||||
return parts.join('\n');
|
||||
}
|
||||
|
||||
function recordReflection(reflection) {
|
||||
const logPath = getReflectionLogPath();
|
||||
ensureDir(path.dirname(logPath));
|
||||
|
||||
const entry = JSON.stringify({
|
||||
ts: new Date().toISOString(),
|
||||
type: 'reflection',
|
||||
...reflection,
|
||||
}) + '\n';
|
||||
|
||||
fs.appendFileSync(logPath, entry, 'utf8');
|
||||
}
|
||||
|
||||
function loadRecentReflections(count) {
|
||||
const n = Number.isFinite(count) ? count : 3;
|
||||
const logPath = getReflectionLogPath();
|
||||
try {
|
||||
if (!fs.existsSync(logPath)) return [];
|
||||
const lines = fs.readFileSync(logPath, 'utf8').trim().split('\n').filter(Boolean);
|
||||
return lines.slice(-n).map(line => {
|
||||
try { return JSON.parse(line); } catch (_) { return null; }
|
||||
}).filter(Boolean);
|
||||
} catch (_) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
shouldReflect,
|
||||
buildReflectionContext,
|
||||
recordReflection,
|
||||
loadRecentReflections,
|
||||
REFLECTION_INTERVAL_CYCLES,
|
||||
};
|
||||
@@ -3,6 +3,7 @@ function matchPatternToSignals(pattern, signals) {
|
||||
const p = String(pattern);
|
||||
const sig = signals.map(s => String(s));
|
||||
|
||||
// Regex pattern: /body/flags
|
||||
const regexLike = p.length >= 2 && p.startsWith('/') && p.lastIndexOf('/') > 0;
|
||||
if (regexLike) {
|
||||
const lastSlash = p.lastIndexOf('/');
|
||||
@@ -16,6 +17,12 @@ function matchPatternToSignals(pattern, signals) {
|
||||
}
|
||||
}
|
||||
|
||||
// Multi-language alias: "en_term|zh_term|ja_term" -- any branch matching = hit
|
||||
if (p.includes('|') && !p.startsWith('/')) {
|
||||
const branches = p.split('|').map(b => b.trim().toLowerCase()).filter(Boolean);
|
||||
return branches.some(needle => sig.some(s => s.toLowerCase().includes(needle)));
|
||||
}
|
||||
|
||||
const needle = p.toLowerCase();
|
||||
return sig.some(s => s.toLowerCase().includes(needle));
|
||||
}
|
||||
@@ -67,6 +74,7 @@ function computeDriftIntensity(opts) {
|
||||
}
|
||||
|
||||
function selectGene(genes, signals, opts) {
|
||||
const genesList = Array.isArray(genes) ? genes : [];
|
||||
const bannedGeneIds = opts && opts.bannedGeneIds ? opts.bannedGeneIds : new Set();
|
||||
const driftEnabled = !!(opts && opts.driftEnabled);
|
||||
const preferredGeneId = opts && typeof opts.preferredGeneId === 'string' ? opts.preferredGeneId : null;
|
||||
@@ -75,14 +83,14 @@ function selectGene(genes, signals, opts) {
|
||||
var driftIntensity = computeDriftIntensity({
|
||||
driftEnabled: driftEnabled,
|
||||
effectivePopulationSize: opts && opts.effectivePopulationSize,
|
||||
genePoolSize: genes ? genes.length : 0,
|
||||
genePoolSize: genesList.length,
|
||||
});
|
||||
var useDrift = driftEnabled || driftIntensity > 0.15;
|
||||
|
||||
var DISTILLED_PREFIX = 'gene_distilled_';
|
||||
var DISTILLED_SCORE_FACTOR = 0.8;
|
||||
|
||||
const scored = genes
|
||||
const scored = genesList
|
||||
.map(g => {
|
||||
var s = scoreGene(g, signals);
|
||||
if (s > 0 && g.id && String(g.id).startsWith(DISTILLED_PREFIX)) s *= DISTILLED_SCORE_FACTOR;
|
||||
|
||||
@@ -282,14 +282,14 @@ function extractSignals({ recentSessionTranscript, todayLog, memorySnippet, user
|
||||
|
||||
// --- Tool Usage Analytics ---
|
||||
var toolUsage = {};
|
||||
var toolMatches = corpus.match(/\[TOOL:\s*(\w+)\]/g) || [];
|
||||
var toolMatches = corpus.match(/\[TOOL:\s*([\w-]+)\]/g) || [];
|
||||
|
||||
// Extract exec commands to identify benign loops (like watchdog checks)
|
||||
var execCommands = corpus.match(/exec: (node\s+[\w\/\.-]+\.js\s+ensure)/g) || [];
|
||||
var benignExecCount = execCommands.length;
|
||||
|
||||
for (var i = 0; i < toolMatches.length; i++) {
|
||||
var toolName = toolMatches[i].match(/\[TOOL:\s*(\w+)\]/)[1];
|
||||
var toolName = toolMatches[i].match(/\[TOOL:\s*([\w-]+)\]/)[1];
|
||||
toolUsage[toolName] = (toolUsage[toolName] || 0) + 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -223,7 +223,7 @@ function buildDistillationPrompt(analysis, existingGenes, sampleCapsules) {
|
||||
});
|
||||
|
||||
return [
|
||||
'You are a Gene synthesis engine for the GEP (Gene Expression Protocol).',
|
||||
'You are a Gene synthesis engine for the GEP (Genome Evolution Protocol).',
|
||||
'',
|
||||
'Analyze the following successful evolution capsules and extract a reusable Gene.',
|
||||
'',
|
||||
|
||||
@@ -17,6 +17,9 @@ const {
|
||||
const { computeAssetId, SCHEMA_VERSION } = require('./contentHash');
|
||||
const { captureEnvFingerprint } = require('./envFingerprint');
|
||||
const { buildValidationReport } = require('./validationReport');
|
||||
const { logAssetCall } = require('./assetCallLog');
|
||||
const { recordNarrative } = require('./narrativeMemory');
|
||||
const { isLlmReviewEnabled, runLlmReview } = require('./llmReview');
|
||||
|
||||
function nowIso() {
|
||||
return new Date().toISOString();
|
||||
@@ -701,10 +704,14 @@ function rollbackNewUntrackedFiles({ repoRoot, baselineUntracked }) {
|
||||
// This prevents "ghost skill directories" where mkdir succeeded but
|
||||
// file creation failed/was rolled back. Without this, empty dirs like
|
||||
// skills/anima/, skills/oblivion/ etc. accumulate after failed innovations.
|
||||
// SAFETY: never remove top-level structural directories (skills/, src/, etc.)
|
||||
// or critical protected directories. Only remove leaf subdirectories.
|
||||
var dirsToCheck = new Set();
|
||||
for (var di = 0; di < deleted.length; di++) {
|
||||
var dir = path.dirname(deleted[di]);
|
||||
while (dir && dir !== '.' && dir !== '/') {
|
||||
var normalized = dir.replace(/\\/g, '/');
|
||||
if (!normalized.includes('/')) break;
|
||||
dirsToCheck.add(dir);
|
||||
dir = path.dirname(dir);
|
||||
}
|
||||
@@ -713,6 +720,7 @@ function rollbackNewUntrackedFiles({ repoRoot, baselineUntracked }) {
|
||||
var sortedDirs = Array.from(dirsToCheck).sort(function (a, b) { return b.length - a.length; });
|
||||
var removedDirs = [];
|
||||
for (var si = 0; si < sortedDirs.length; si++) {
|
||||
if (isCriticalProtectedPath(sortedDirs[si] + '/')) continue;
|
||||
var dirAbs = path.join(repoRoot, sortedDirs[si]);
|
||||
try {
|
||||
var entries = fs.readdirSync(dirAbs);
|
||||
@@ -957,8 +965,32 @@ function readRecentSessionInputs() {
|
||||
return { recentSessionTranscript, todayLog: todayLogContent, memorySnippet, userSnippet };
|
||||
}
|
||||
|
||||
function isGitRepo(dir) {
|
||||
try {
|
||||
execSync('git rev-parse --git-dir', {
|
||||
cwd: dir, encoding: 'utf8',
|
||||
stdio: ['ignore', 'pipe', 'pipe'], timeout: 5000,
|
||||
});
|
||||
return true;
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function solidify({ intent, summary, dryRun = false, rollbackOnFailure = true } = {}) {
|
||||
const repoRoot = getRepoRoot();
|
||||
|
||||
if (!isGitRepo(repoRoot)) {
|
||||
console.error('[Solidify] FATAL: Not a git repository (' + repoRoot + ').');
|
||||
console.error('[Solidify] Solidify requires git for rollback, diff capture, and blast radius.');
|
||||
console.error('[Solidify] Run "git init && git add -A && git commit -m init" first.');
|
||||
return {
|
||||
ok: false,
|
||||
status: 'failed',
|
||||
failure_reason: 'not_a_git_repository',
|
||||
event: null,
|
||||
};
|
||||
}
|
||||
const state = readStateForSolidify();
|
||||
const lastRun = state && state.last_run ? state.last_run : null;
|
||||
const genes = loadGenes();
|
||||
@@ -1053,6 +1085,29 @@ function solidify({ intent, summary, dryRun = false, rollbackOnFailure = true }
|
||||
console.error(`[Solidify] CANARY FAILED: ${canary.err}`);
|
||||
}
|
||||
|
||||
// Optional LLM review: when EVOLVER_LLM_REVIEW=true, submit diff for review.
|
||||
let llmReviewResult = null;
|
||||
if (constraintCheck.ok && validation.ok && protocolViolations.length === 0 && isLlmReviewEnabled()) {
|
||||
try {
|
||||
const reviewDiff = captureDiffSnapshot(repoRoot);
|
||||
llmReviewResult = runLlmReview({
|
||||
diff: reviewDiff,
|
||||
gene: geneUsed,
|
||||
signals,
|
||||
mutation,
|
||||
});
|
||||
if (llmReviewResult && llmReviewResult.approved === false) {
|
||||
constraintCheck.violations.push('llm_review_rejected: ' + (llmReviewResult.summary || 'no reason'));
|
||||
constraintCheck.ok = false;
|
||||
console.log('[LLMReview] Change REJECTED: ' + (llmReviewResult.summary || ''));
|
||||
} else if (llmReviewResult) {
|
||||
console.log('[LLMReview] Change approved (confidence: ' + (llmReviewResult.confidence || '?') + ')');
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('[LLMReview] Failed (non-fatal): ' + (e && e.message ? e.message : e));
|
||||
}
|
||||
}
|
||||
|
||||
// Build standardized ValidationReport (machine-readable, interoperable).
|
||||
const validationReport = buildValidationReport({
|
||||
geneId: geneUsed && geneUsed.id ? geneUsed.id : null,
|
||||
@@ -1212,7 +1267,12 @@ function solidify({ intent, summary, dryRun = false, rollbackOnFailure = true }
|
||||
|
||||
if (!dryRun && !success && rollbackOnFailure) {
|
||||
rollbackTracked(repoRoot);
|
||||
rollbackNewUntrackedFiles({ repoRoot, baselineUntracked: lastRun && lastRun.baseline_untracked ? lastRun.baseline_untracked : [] });
|
||||
// Only clean up new untracked files when a valid baseline exists.
|
||||
// Without a baseline, we cannot distinguish pre-existing untracked files
|
||||
// from AI-generated ones, so deleting would be destructive.
|
||||
if (lastRun && Array.isArray(lastRun.baseline_untracked)) {
|
||||
rollbackNewUntrackedFiles({ repoRoot, baselineUntracked: lastRun.baseline_untracked });
|
||||
}
|
||||
}
|
||||
|
||||
// Apply epigenetic marks to the gene based on outcome and environment
|
||||
@@ -1254,6 +1314,21 @@ function solidify({ intent, summary, dryRun = false, rollbackOnFailure = true }
|
||||
};
|
||||
if (!dryRun) writeStateForSolidify(state);
|
||||
|
||||
if (!dryRun) {
|
||||
try {
|
||||
recordNarrative({
|
||||
gene: geneUsed,
|
||||
signals,
|
||||
mutation,
|
||||
outcome: event.outcome,
|
||||
blast,
|
||||
capsule,
|
||||
});
|
||||
} catch (e) {
|
||||
console.log('[Narrative] Record failed (non-fatal): ' + (e && e.message ? e.message : e));
|
||||
}
|
||||
}
|
||||
|
||||
// Search-First Evolution: auto-publish eligible capsules to the Hub (as Gene+Capsule bundle).
|
||||
let publishResult = null;
|
||||
if (!dryRun && capsule && capsule.a2a && capsule.a2a.eligible_to_broadcast) {
|
||||
@@ -1327,6 +1402,21 @@ function solidify({ intent, summary, dryRun = false, rollbackOnFailure = true }
|
||||
});
|
||||
}
|
||||
publishResult = { attempted: true, asset_id: capsule.asset_id || capsule.id, bundle: true };
|
||||
logAssetCall({
|
||||
run_id: lastRun && lastRun.run_id ? lastRun.run_id : null,
|
||||
action: 'asset_publish',
|
||||
asset_id: capsule.asset_id || capsule.id,
|
||||
asset_type: 'Capsule',
|
||||
source_node_id: null,
|
||||
chain_id: publishChainId || null,
|
||||
signals: Array.isArray(capsule.trigger) ? capsule.trigger : [],
|
||||
extra: {
|
||||
source_type: sourceType,
|
||||
reused_asset_id: reusedAssetId,
|
||||
gene_id: publishGene && publishGene.id ? publishGene.id : null,
|
||||
parent: parentRef || null,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
publishResult = { attempted: false, reason: 'no_hub_url' };
|
||||
}
|
||||
@@ -1340,6 +1430,14 @@ function solidify({ intent, summary, dryRun = false, rollbackOnFailure = true }
|
||||
: sourceType === 'reused' ? 'skip_direct_reused_asset'
|
||||
: 'below_min_score';
|
||||
publishResult = { attempted: false, reason };
|
||||
logAssetCall({
|
||||
run_id: lastRun && lastRun.run_id ? lastRun.run_id : null,
|
||||
action: 'asset_publish_skip',
|
||||
asset_id: capsule.asset_id || capsule.id,
|
||||
asset_type: 'Capsule',
|
||||
reason,
|
||||
signals: Array.isArray(capsule.trigger) ? capsule.trigger : [],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1452,6 +1550,7 @@ function solidify({ intent, summary, dryRun = false, rollbackOnFailure = true }
|
||||
|
||||
module.exports = {
|
||||
solidify,
|
||||
isGitRepo,
|
||||
readStateForSolidify,
|
||||
writeStateForSolidify,
|
||||
isValidationCommandAllowed,
|
||||
|
||||
@@ -82,7 +82,8 @@ async function fetchTasks(opts) {
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch {
|
||||
} catch (err) {
|
||||
console.warn("[TaskReceiver] fetchTasks failed:", err && err.message ? err.message : err);
|
||||
return { tasks: [] };
|
||||
}
|
||||
}
|
||||
@@ -150,7 +151,7 @@ function estimateCapabilityMatch(task, memoryEvents) {
|
||||
var weightSum = 0;
|
||||
for (var sk in totalBySignalKey) {
|
||||
// Reconstruct signals from the key for comparison
|
||||
var skParts = sk.split(':').map(function(s) { return s.trim().toLowerCase(); }).filter(Boolean);
|
||||
var skParts = sk.split('|').map(function(s) { return s.trim().toLowerCase(); }).filter(Boolean);
|
||||
var sim = jaccard(taskSignals, skParts);
|
||||
if (sim < 0.15) continue;
|
||||
|
||||
|
||||
@@ -9,6 +9,14 @@ const { getEvolutionDir } = require('../gep/paths');
|
||||
var MAX_AGE_MS = 24 * 60 * 60 * 1000; // 24 hours
|
||||
var MIN_KEEP = 10;
|
||||
|
||||
function safeBatchDelete(batch) {
|
||||
var deleted = 0;
|
||||
for (var i = 0; i < batch.length; i++) {
|
||||
try { fs.unlinkSync(batch[i]); deleted++; } catch (_) {}
|
||||
}
|
||||
return deleted;
|
||||
}
|
||||
|
||||
function run() {
|
||||
var evoDir = getEvolutionDir();
|
||||
if (!fs.existsSync(evoDir)) return;
|
||||
@@ -26,8 +34,7 @@ function run() {
|
||||
var deleted = 0;
|
||||
|
||||
// Phase 1: Age-based cleanup (keep at least MIN_KEEP)
|
||||
// [OPTIMIZATION] Batch deletion for age-based cleanup as well
|
||||
const filesToDelete = [];
|
||||
var filesToDelete = [];
|
||||
for (var i = MIN_KEEP; i < files.length; i++) {
|
||||
if (now - files[i].mtime > MAX_AGE_MS) {
|
||||
filesToDelete.push(files[i].path);
|
||||
@@ -35,27 +42,10 @@ function run() {
|
||||
}
|
||||
|
||||
if (filesToDelete.length > 0) {
|
||||
const BATCH_SIZE = 50;
|
||||
for (let i = 0; i < filesToDelete.length; i += BATCH_SIZE) {
|
||||
const batch = filesToDelete.slice(i, i + BATCH_SIZE);
|
||||
try {
|
||||
// Remove package-lock.json if it exists (not relevant here but good practice in other contexts)
|
||||
// Use rm -f with quotes to handle paths safely
|
||||
// Phase 1 optimization update: mirroring phase 2 logic
|
||||
const args = batch.map(function(p) { return '"' + p + '"'; }).join(' ');
|
||||
require('child_process').execSync('rm -f ' + args, { stdio: 'ignore' });
|
||||
deleted += batch.length;
|
||||
} catch (e) {
|
||||
// Fallback to serial deletion if batch fails
|
||||
batch.forEach(function(p) {
|
||||
try { fs.unlinkSync(p); deleted++; } catch (_) {}
|
||||
});
|
||||
}
|
||||
}
|
||||
deleted += safeBatchDelete(filesToDelete);
|
||||
}
|
||||
|
||||
// Phase 2: Size-based safety cap (keep max 10 files total to drastically reduce bloat)
|
||||
// Re-scan remaining files after age cleanup
|
||||
// Phase 2: Size-based safety cap (keep max 10 files total)
|
||||
try {
|
||||
var remainingFiles = fs.readdirSync(evoDir)
|
||||
.filter(function(f) { return /^gep_prompt_.*\.(json|txt)$/.test(f); })
|
||||
@@ -66,29 +56,10 @@ function run() {
|
||||
})
|
||||
.sort(function(a, b) { return b.mtime - a.mtime; }); // newest first
|
||||
|
||||
// [OPTIMIZATION] Batch deletion using execSync('rm') for speed and robustness
|
||||
var MAX_FILES = 10;
|
||||
if (remainingFiles.length > MAX_FILES) {
|
||||
const toDelete = remainingFiles.slice(MAX_FILES).map(function(f) { return f.path; });
|
||||
|
||||
// Chunking into batches of 50 to avoid E2BIG on some systems,
|
||||
// though with MAX_FILES=10 and typical usage, list won't be huge.
|
||||
const BATCH_SIZE = 50;
|
||||
for (let i = 0; i < toDelete.length; i += BATCH_SIZE) {
|
||||
const batch = toDelete.slice(i, i + BATCH_SIZE);
|
||||
try {
|
||||
// Safe bulk delete via shell, faster than serial unlinkSync
|
||||
// Using "rm -f" to ignore non-existent files
|
||||
const args = batch.map(function(p) { return '"' + p + '"'; }).join(' ');
|
||||
require('child_process').execSync('rm -f ' + args, { stdio: 'ignore' });
|
||||
deleted += batch.length;
|
||||
} catch (e) {
|
||||
// Fallback to serial if batch fails
|
||||
batch.forEach(function(p) {
|
||||
try { fs.unlinkSync(p); deleted++; } catch (_) {}
|
||||
});
|
||||
}
|
||||
}
|
||||
var toDelete = remainingFiles.slice(MAX_FILES).map(function(f) { return f.path; });
|
||||
deleted += safeBatchDelete(toDelete);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[Cleanup] Phase 2 failed:', e.message);
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
# Errors
|
||||
|
||||
Command failures, exceptions, and issues captured during development.
|
||||
|
||||
**Areas**: frontend | backend | infra | tests | docs | config
|
||||
**Statuses**: pending | in_progress | resolved | wont_fix
|
||||
|
||||
## Status Definitions
|
||||
|
||||
| Status | Meaning |
|
||||
|--------|---------|
|
||||
| `pending` | Not yet addressed |
|
||||
| `in_progress` | Actively being worked on |
|
||||
| `resolved` | Issue fixed |
|
||||
| `wont_fix` | Decided not to address (reason in Resolution) |
|
||||
|
||||
## Entry Format
|
||||
|
||||
```markdown
|
||||
## [ERR-YYYYMMDD-XXX] title
|
||||
|
||||
**Logged**: ISO-8601 timestamp
|
||||
**Priority**: low | medium | high | critical
|
||||
**Status**: pending
|
||||
**Area**: frontend | backend | infra | tests | docs | config
|
||||
|
||||
### Summary
|
||||
Brief description of what failed
|
||||
|
||||
### Error
|
||||
```
|
||||
Actual error message
|
||||
```
|
||||
|
||||
### Context
|
||||
- What was attempted
|
||||
- Input/parameters used
|
||||
- Environment details
|
||||
|
||||
### Suggested Fix
|
||||
How this could be resolved
|
||||
|
||||
### Metadata
|
||||
- Reproducible: yes | no | unknown
|
||||
- Related Files: path/to/file.ext
|
||||
- See Also: ERR-20250110-001
|
||||
|
||||
---
|
||||
```
|
||||
@@ -0,0 +1,44 @@
|
||||
# Feature Requests
|
||||
|
||||
User-requested capabilities that don't exist yet.
|
||||
|
||||
**Areas**: frontend | backend | infra | tests | docs | config
|
||||
**Statuses**: pending | in_progress | resolved | wont_fix
|
||||
|
||||
## Status Definitions
|
||||
|
||||
| Status | Meaning |
|
||||
|--------|---------|
|
||||
| `pending` | Not yet addressed |
|
||||
| `in_progress` | Actively being worked on |
|
||||
| `resolved` | Feature implemented |
|
||||
| `wont_fix` | Decided not to implement (reason in Resolution) |
|
||||
|
||||
## Entry Format
|
||||
|
||||
```markdown
|
||||
## [FEAT-YYYYMMDD-XXX] title
|
||||
|
||||
**Logged**: ISO-8601 timestamp
|
||||
**Priority**: low | medium | high
|
||||
**Status**: pending
|
||||
**Area**: frontend | backend | infra | tests | docs | config
|
||||
|
||||
### Requested Capability
|
||||
What the user wanted to do
|
||||
|
||||
### User Context
|
||||
Why they needed it
|
||||
|
||||
### Complexity Estimate
|
||||
simple | medium | complex
|
||||
|
||||
### Suggested Implementation
|
||||
How this could be built
|
||||
|
||||
### Metadata
|
||||
- Frequency: first_time | recurring
|
||||
- Related Features: existing_feature_name
|
||||
|
||||
---
|
||||
```
|
||||
@@ -0,0 +1,45 @@
|
||||
# Learnings
|
||||
|
||||
Corrections, insights, and knowledge gaps captured during development.
|
||||
|
||||
**Categories**: correction | insight | knowledge_gap | best_practice
|
||||
**Areas**: frontend | backend | infra | tests | docs | config
|
||||
**Statuses**: pending | in_progress | resolved | wont_fix | promoted | promoted_to_skill
|
||||
|
||||
## Status Definitions
|
||||
|
||||
| Status | Meaning |
|
||||
|--------|---------|
|
||||
| `pending` | Not yet addressed |
|
||||
| `in_progress` | Actively being worked on |
|
||||
| `resolved` | Issue fixed or knowledge integrated |
|
||||
| `wont_fix` | Decided not to address (reason in Resolution) |
|
||||
| `promoted` | Elevated to CLAUDE.md, AGENTS.md, or copilot-instructions.md |
|
||||
| `promoted_to_skill` | Extracted as a reusable skill |
|
||||
|
||||
## Skill Extraction Fields
|
||||
|
||||
When a learning is promoted to a skill, add these fields:
|
||||
|
||||
```markdown
|
||||
**Status**: promoted_to_skill
|
||||
**Skill-Path**: skills/skill-name
|
||||
```
|
||||
|
||||
Example:
|
||||
```markdown
|
||||
## [LRN-20250115-001] best_practice
|
||||
|
||||
**Logged**: 2025-01-15T10:00:00Z
|
||||
**Priority**: high
|
||||
**Status**: promoted_to_skill
|
||||
**Skill-Path**: skills/docker-m1-fixes
|
||||
**Area**: infra
|
||||
|
||||
### Summary
|
||||
Docker build fails on Apple Silicon due to platform mismatch
|
||||
...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user