Files
wehub-resource-sync 1d6fd29cda
tests / test (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:36:27 +08:00

373 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Mem-Sys 实现规划书
> 分支:`Mem-Sys` | 创建于 2026-04-12
## 一、现状分析
现有文件结构:
```
crushes/{slug}/
├── profile.md ← 纯 Markdown 散文,无结构化字段,Claude 读写靠理解
├── strategy.md ← 同上
├── meta.json ← 有结构,但字段稀疏(仅 stage、score、mode
├── memories/chats/ ← 原始聊天记录
└── versions/ ← 手动备份,不自动维护
```
**核心问题**
1. `profile.md` 没有 YAML frontmatterClaude 无法可靠提取/更新单个字段
2. 没有"当前状态快照",每次 `/simp progress` 都要重新推断阶段
3. 没有事件日志,历史演变不可追溯,`/simp quit` 无法看"感情轨迹"
4. `versions/` 是手动备份,不是真正的历史记录
---
## 二、新文件结构
```
crushes/{slug}/
├── profile.md # 【升级】稳定层 — YAML frontmatter + 叙述体
├── state.md # 【新增】动态层 — 当前快照,每次会话后覆盖
├── events.jsonl # 【新增】事件流 — 只追加,永不删除
├── strategy.md # 【保留】追求策略(不动)
├── meta.json # 【扩展】元数据,新增索引字段
├── memories/
│ ├── chats/
│ ├── social/
│ └── photos/
└── snapshots/ # 【新增】定期快照目录
└── YYYY-MM-DD.json
```
**读取优先级**context window 分配):
| 文件 | 加载时机 | 预估 tokens |
|------|----------|------------|
| `profile.md` | 每次必读 | ~300 |
| `state.md` | 每次必读 | ~200 |
| `events.jsonl` 最近5条 | progress/analyze/quit | ~150 |
| `strategy.md` | message/confess/analyze | ~400 |
| `events.jsonl` 全部 | 用户明确要求回顾时 | 按需 |
---
## 三、文件 Schema 定义
### 3.1 `profile.md`(稳定层)
```markdown
---
nickname: 小雨
slug: xiaoyu
gender: 女
age: 23
occupation: 设计师
city: 上海
mbti: ENFP
zodiac: 双鱼
personality_type: 感性型
how_met: 同学介绍
created_at: "2026-04-10"
---
## 性格画像
ta 话很多,喜欢用颜文字,情绪外露,容易被细节打动。
见面时会不自觉靠近,但如果感觉被冷落会直接不回消息。
## 最打动ta的方式
具体的画面感 > 泛泛的夸奖。说"你刚才皱眉的样子"比"你很可爱"更有效。
## 用户自身风格
说话偏幽默,短句为主,偶尔用表情包,追求混合模式。
## 注意事项
ta 对"套路感"敏感,一旦感觉被设计会直接拉远距离。
```
**规则**
- YAML frontmatter 存结构化字段,Claude 更新时用字段名精确修改
- 正文存叙述性内容,只追加,不覆盖
- `personality_type` 枚举值:`感性型 | 理性型 | 傲娇型 | 温柔型`
---
### 3.2 `state.md`(动态层)
```markdown
---
current_stage: 暧昧期
signal_score: 17
last_signal_score: 14
score_trend: up
recommended_mode: 混合
last_updated: "2026-04-12T10:30:00"
milestones_done: 7
---
## 当前状态(一句话)
关系持续升温,ta 开始主动制造见面机会。
## 最近信号(最新3条)
- 🟢 2026-04-11 ta 主动问周末有没有空
- 🟢 2026-04-10 深夜发了消息说"突然想到你"
- 🟡 2026-04-08 回复比往常慢了一些
## 当前策略方向
暧昧期推进:制造1v1心跳时刻,评估表白时机是否成熟。
## 下一步建议
本周制造一次晚间1v1见面,用 /simp message 准备好开场话题。
```
**规则**
- 每次 `/simp analyze``/simp progress` 结束后**全量覆盖**
- `score_trend` 枚举:`up | down | stable`
- `current_stage` 枚举:`破冰期 | 升温期 | 暧昧期 | 表白前 | 表白后-成功 | 表白后-被拒 | 友谊区 | 重启期`
---
### 3.3 `events.jsonl`(事件流)
每行一个独立 JSON 对象,严格只追加:
```jsonl
{"ts":"2026-04-10T14:00:00","v":1,"type":"profile_created","slug":"xiaoyu","data":{"nickname":"小雨","personality_type":"感性型"}}
{"ts":"2026-04-11T20:30:00","v":1,"type":"signal_recorded","slug":"xiaoyu","data":{"direction":"green","content":"深夜主动发消息说突然想到你","score_delta":3}}
{"ts":"2026-04-12T10:30:00","v":1,"type":"stage_changed","slug":"xiaoyu","data":{"from":"升温期","to":"暧昧期","trigger":"连续3天主动联系 + 深夜消息"}}
{"ts":"2026-04-12T10:30:00","v":1,"type":"analysis_done","slug":"xiaoyu","data":{"score":17,"stage":"暧昧期","summary":"ta 主动性明显增强,信号偏绿"}}
```
**事件类型字典**
| type | 触发指令 | data 必填字段 |
|------|---------|--------------|
| `profile_created` | `/simp create` | nickname, personality_type |
| `profile_updated` | `/simp update` | field, old_value, new_value |
| `stage_changed` | analyze/progress | from, to, trigger |
| `signal_recorded` | `/simp analyze` | direction(green/red/neutral), content, score_delta |
| `analysis_done` | `/simp analyze` | score, stage, summary |
| `progress_evaluated` | `/simp progress` | score, stage, milestones_done, next_actions |
| `strategy_updated` | 阶段变化时 | old_stage, new_stage, reason |
| `crisis_handled` | `/simp crisis` | crisis_type, resolution |
| `quit_evaluated` | `/simp quit` | verdict(continue/reconsider/let_go), reason |
| `confess_prepared` | `/simp confess` | method, readiness_score |
---
### 3.4 `meta.json`(扩展)
```json
{
"slug": "xiaoyu",
"nickname": "小雨",
"created_at": "2026-04-10T14:00:00",
"updated_at": "2026-04-12T10:30:00",
"version": "v1",
"current_stage": "暧昧期",
"signal_score": 17,
"mode": "hybrid",
"event_count": 4,
"last_snapshot": "2026-04-12"
}
```
新增字段:`nickname`(用于 list 展示)、`event_count`(快速统计)、`last_snapshot`
---
## 四、每条指令的 Memory Protocol
```
指令 读取 写入
─────────────────────────────────────────────────────────
/simp create 无 profile.md(新建)
state.md(空模板)
events.jsonl(新建)
meta.json(新建)
/simp analyze profile.md state.md(覆盖)
state.md events.jsonl(追加:
signal_recorded
analysis_done
stage_changed 若变化)
/simp message profile.md 无
state.md
strategy.md
/simp progress profile.md state.md(覆盖)
state.md events.jsonl(追加:
events.jsonl 最近5条 progress_evaluated)
meta.json(更新score/stage)
/simp update profile.md profile.md(更新frontmatter)
events.jsonl(追加:
profile_updated)
/simp confess profile.md events.jsonl(追加:
state.md confess_prepared)
strategy.md
/simp crisis profile.md state.md(更新状态)
state.md events.jsonl(追加:
crisis_handled)
/simp daily state.md 仅此 无
/simp quit profile.md events.jsonl(追加:
state.md quit_evaluated)
events.jsonl 全部
/simp list meta.json(所有slug) 无
```
---
## 五、新增 Python 工具:`tools/memory.py`
### 5.1 模块职责
`memory.py` 是记忆系统的唯一入口,`skill_writer.py` 调用它,Claude 通过 shell 调用它。
### 5.2 CLI 接口
```bash
# 追加事件
python3 tools/memory.py append <slug> <event_type> '<json_data>'
# 读取最近N条事件
python3 tools/memory.py events <slug> --last 5
# 读取当前上下文(profile.md + state.md 合并输出)
python3 tools/memory.py context <slug>
# 从事件流重建 state.md
python3 tools/memory.py rebuild <slug>
# 生成日快照
python3 tools/memory.py snapshot <slug>
# 查看事件时间线
python3 tools/memory.py timeline <slug>
```
### 5.3 核心函数签名
```python
def append_event(
slug: str,
event_type: str,
data: dict,
base_dir: Path = DEFAULT_BASE_DIR
) -> None:
"""追加一条事件到 events.jsonl,同时更新 meta.json 的 event_count"""
def get_recent_events(
slug: str,
n: int = 5,
event_types: list[str] | None = None,
base_dir: Path = DEFAULT_BASE_DIR
) -> list[dict]:
"""返回最近 N 条事件,可按 type 过滤"""
def load_context(
slug: str,
include_strategy: bool = False,
base_dir: Path = DEFAULT_BASE_DIR
) -> str:
"""拼装 profile.md + state.md,供 Claude 直接注入 context"""
def update_state(
slug: str,
frontmatter_updates: dict,
sections: dict[str, str],
base_dir: Path = DEFAULT_BASE_DIR
) -> None:
"""全量覆盖 state.mdfrontmatter_updates 更新 YAML 字段"""
def take_snapshot(
slug: str,
base_dir: Path = DEFAULT_BASE_DIR
) -> Path:
"""将 meta.json + state.md frontmatter 合并写入 snapshots/YYYY-MM-DD.json"""
def rebuild_state_from_events(
slug: str,
base_dir: Path = DEFAULT_BASE_DIR
) -> dict:
"""从 events.jsonl 重放,返回推断的当前状态(用于校验或恢复)"""
```
---
## 六、`skill_writer.py` 改动
`init_crush()` 新增三步:
1.`profile.md` 模板顶部加 YAML frontmatter
2. 创建 `state.md`(空模板)
3. 创建 `events.jsonl`(空文件)
4. 创建 `snapshots/` 目录
5. `meta.json` 新增 `nickname``event_count: 0``last_snapshot: null` 字段
`backup_crush()` 扩展:同步备份 `state.md`events.jsonl 不备份,它是不可变历史)。
`update_meta()` 扩展:支持更新 `nickname``event_count``last_snapshot`
---
## 七、`SKILL.md` 改动(Phase 3
在「运行规则」之前新增「记忆操作协议」章节,定义每条指令的读写规则。
---
## 八、实施步骤
### Phase 1Schema 落地(基础)✅
- [x] 更新 `init_crush()` — 新增 `state.md``events.jsonl``snapshots/` 的创建
- [x] 更新 `profile.md` 模板 — 加 YAML frontmatter
- [x] 扩展 `meta.json` schema — 新增字段
- [x] 更新测试
### Phase 2memory.py 工具 ✅
- [x] 实现 `append_event()`
- [x] 实现 `get_recent_events()`
- [x] 实现 `update_state()`
- [x] 实现 `load_context()`
- [x] 实现 `take_snapshot()`
- [x] 实现 `rebuild_state_from_events()`
- [x] CLI 入口
- [x] 测试覆盖(见 `tests/test_memory.py`
### Phase 3SKILL.md 集成 ✅
- [x] 新增「记忆操作协议」章节
- [x] 每条指令补充 Memory Protocol 说明
- [x] `progress_tracker.md` 更新读取路径
### Phase 4:迁移工具 · ❌ 不再计划
早期阶段无存量用户档案,迁移工具的实际价值低于维护成本。新档案统一通过 `init_crush()` 创建,已自带 YAML frontmatter / `state.md` / `events.jsonl`,无需迁移。若未来出现存量数据需要升级,再单独立项。
---
## 九、测试计划
```
tests/
├── test_skill_writer.py # 已有,补充新字段断言 ✅
└── test_memory.py # 新增(Phase 2)✅
```
---
## 十、一句话原则备忘
| 文件 | 一句话规则 |
|------|-----------|
| `profile.md` | 只增不减,YAML 字段可更新,正文只追加 |
| `state.md` | 代表"现在",每次全量覆盖 |
| `events.jsonl` | 代表"历史",只追加,永不删除 |
| `strategy.md` | 阶段变化时更新,其他时候只读 |
| `snapshots/` | 每日自动生成,用于跨会话快速恢复 |