i-am

TotalClaw 作者 designer-awei v4.0.1

简单的性格分析。将 SKILL.md 与嵌入式代码合并。 AI引导安装和IM自适应文件发送。

源码 ↗

安装 / 下载方式

TotalClaw CLI推荐
totalclaw install totalclaw:designer-awei~i-am
cURL直接下载,无需登录
curl -fsSL https://skills.taituai.com/api/skills/totalclaw%3Adesigner-awei~i-am/file -o i-am.md
Git 仓库获取源码
git clone https://github.com/openclaw/skills/commit/9925785a994abb38e228c88d9e6bd0bc845ed8ac
# i-am Skill v4.0.1 - AI 指令文档

> **给 OpenClaw AI 的指令**:按照以下流程引导用户完成人格分析

---

## 🎯 触发条件

**场景 1: 首次安装(自动触发)**
- 用户安装此 skill 后,AI 主动询问配置

**场景 2: 用户主动触发**
- "运行 i-am 分析"、"分析我的人格"
- "人格特质"、"USER.md 更新"
- "扎根理论"

---

## 📁 文件结构

```
i-am/
├── SKILL.md              # 本文件(AI 指令)
├── clawhub.yaml          # ClawHub 配置
├── ChangeLog.md          # 人格特质更新日志(配置阶段创建)
└── temp/                 # 临时目录(运行时自动创建)
    ├── USER.md           # 预览文件(待用户审核)
    └── last_analysis.json # 时间戳
```

**说明**:
- `temp/` 目录和文件在首次运行时自动创建
- `ChangeLog.md` 在配置阶段自动创建(记录每次更新)

---

## 🔄 完整工作流程(AI 执行指南)

### 阶段 1: 安装配置(首次使用)

**触发时机**:用户安装 skill 后,AI 主动触发

#### AI 检测安装状态

**检查清单**:
1. Cron 任务是否已配置(`~/.openclaw/cron/cron-tasks.json` 包含 `i-am` 任务)
2. 时间戳文件是否存在(`temp/last_analysis.json`)

**决策**:
- 如果都已存在 → AI 回复:`✅ i-am 已配置完成,回复"运行分析"开始分析`
- 如果有缺失 → 进入配置流程

#### AI 主动询问配置(首次安装)

**AI 回复模板**:

```
🧠 i-am Skill 配置向导

请选择自动化模式:

1️⃣ **定时模式**(推荐)
   - 每天自动分析两次(凌晨 2:30 和下午 2:30)
   - 使用 OpenClaw 定时任务系统
   - 一般不需要手动操作

2️⃣ **手动模式**
   - 需要时手动运行分析
   - 无后台定时任务
   - 手动控制

请回复数字 1 或 2 选择(默认 1):
```

#### AI 根据用户回复执行

**用户回复 "1" 或 "定时"**:
1. AI 执行:编辑 `cron-tasks.json`,添加两个定时任务(代码见下方)
2. AI 回复:`✅ 定时模式已配置,每天 2:30 自动运行`

**用户回复 "2" 或 "手动"**:
1. AI 回复:`✅ 手动模式已配置,需要时告诉我"运行 i-am 分析"`

#### AI 创建必要文件夹和 ChangeLog.md

**执行代码**:

```python
from pathlib import Path
from datetime import datetime

skill_root = Path.home() / ".openclaw" / "workspace" / "skills" / "i-am"
user_md_path = Path.home() / ".openclaw" / "workspace" / "USER.md"

# 步骤 1: 创建 temp 文件夹(用于存储临时文件)
temp_dir = skill_root / "temp"
temp_dir.mkdir(parents=True, exist_ok=True)
print(f"✅ 已创建文件夹:{temp_dir}")

# 步骤 2: 创建 ChangeLog.md(人格特质更新日志)
changelog_file = skill_root / "ChangeLog.md"
if not changelog_file.exists():
    header = """# i-am Skill ChangeLog

> 人格特质更新日志 | 自动生成

---

## 更新记录

"""
    with open(changelog_file, 'w', encoding='utf-8') as f:
        f.write(header)
    print(f"✅ 已创建 ChangeLog.md: {changelog_file}")
else:
    print(f"ℹ️  ChangeLog.md 已存在")
```

**文件夹说明**:

| 文件夹 | 用途 | 创建时机 |
|--------|------|---------|
| `ChangeLog.md` | 备份 USER.md 历史版本 | 首次安装时创建 |
| `temp/` | 存储临时文件(预览、时间戳) | 首次安装时创建 |

**文件示例**:
```
i-am/
├── SKILL.md
├── clawhub.yaml
├── ChangeLog.md
│   ├── USER-20260313-1950-initial.md  ← 初始备份
│   ├── USER-20260313-2030.md          ← 第一次分析后备份
│   └── USER-20260314-0230.md          ← 定时任务备份
└── temp/
    ├── USER.md                        ← 预览文件(用户未确认)
    └── last_analysis.json             ← 时间戳
```

#### AI 确认安装完成

**AI 回复模板**:

```
✅ i-am Skill 安装完成!

📋 配置摘要:
- 模式:定时模式 / 手动模式
- Cron 任务:已配置 / 未配置
- 下次运行:2026-03-14 02:30 / 手动触发
- 初始备份:ChangeLog.mdUSER-20260313-1800-initial.md

📊 随时查看人格特质:查看当前对话的 USER.md 文件

需要现在运行一次分析吗?回复"是"或"否"
```

---

### 阶段 2: 运行分析(定时/手动触发)

#### 步骤 1: AI 加载用户语料

**AI 指引**:

```python
import json
from pathlib import Path
from datetime import datetime, timedelta

sessions_path = Path.home() / ".openclaw" / "agents" / "main" / "sessions"
skill_root = Path.home() / ".openclaw" / "workspace" / "skills" / "i-am"
last_analysis_file = skill_root / "temp" / "last_analysis.json"

# 读取上次分析时间
if last_analysis_file.exists():
    with open(last_analysis_file, 'r', encoding='utf-8') as f:
        last_time = datetime.fromisoformat(json.load(f)['timestamp'])
else:
    last_time = datetime.now() - timedelta(hours=24)  # 首次运行加载 24 小时

# 扫描 sessions 提取新消息
messages = []
for session_file in sorted(sessions_path.glob("*.jsonl"), key=lambda x: x.stat().st_mtime, reverse=True):
    with open(session_file, 'r', encoding='utf-8') as f:
        for line in f:
            msg = json.loads(line)
            if msg.get('type') != 'message' or msg.get('message', {}).get('role') != 'user':
                continue
            
            msg_time = datetime.fromisoformat(msg['timestamp'].replace('Z', '+00:00')).replace(tzinfo=None)
            if msg_time <= last_time:
                continue
            
            # 提取文本
            text = "".join([item.get('text', '') for item in msg['message']['content'] if isinstance(item, dict) and item.get('type') == 'text']).strip()
            
            # AI 自主判断:过滤系统消息
            if not text or text.startswith('[cron:') or text.startswith('Read HEARTBEAT') or text.startswith('A scheduled'):
                continue
            
            # AI 自主发现:Conversation info 中包含真实用户发言
            # 示例格式:
            # Conversation info (untrusted metadata):
            # ```json
            # {"sender": "UserName", "timestamp": "..."}
            # ```
            # [message_id: xxx] UserName:真实消息内容
            if 'Conversation info' in text:
                # AI 需要:
                # 1. 识别发送者(UserName)
                # 2. 编写正则表达式提取真实内容
                # 3. 验证发送者是当前用户
                # 4. 提取消息内容(长度>10 字)
                import re
                # 示例正则(AI 可根据实际格式调整):
                match = re.search(r'\[message_id:[^\]]+\]\s*\n?([^:]+):(.+?)(?=\n\n|\Z)', text, re.DOTALL)
                if match:
                    sender = match.group(1).strip()
                    content = match.group(2).strip()
                    # AI 自主判断:发送者是否匹配当前用户
                    if sender == current_user_name and len(content) > 10:
                        text = content
                    else:
                        continue
                else:
                    # AI 应尝试其他正则或格式
                    continue
            
            messages.append({'text': text, 'timestamp': msg_time})

# 初次运行不限制消息数量(充分利用历史对话建立人格模型)
# 后续运行可限制消息数量(避免单次分析过多)
# 如果消息过多,AI 可自主决定是否设置上限
# 初次运行不限制,尽可能加载历史对话
# 后续运行限制 50 条(避免单次分析过多)
if False:  # 禁用上限
    messages = messages[-50:]
    print(f"⚠️ 消息过多,只处理最近 50 条")

print(f"✅ 加载到 {len(messages)} 条新消息")
```

**AI 注意事项**:
- ✅ 首次运行时,sessions 目录下可能已有历史对话
- ✅ Conversation info 格式中包含真实用户发言,需要提取
- ✅ 不同 IM 渠道的消息格式可能不同,AI 应自主调整正则
- ✅ 提取后验证发送者是当前用户(不是系统通知)
- ✅ 消息内容应>10 字,避免太短的无意义消息
- ✅ **不要硬编码真实姓名或用户名**(使用通用占位符)

---

#### 步骤 2: AI 进行扎根理论分析

**核心原则**:不要预定义标签,从语料自然涌现!

**执行代码**:

```python
# 开放性编码:从语料自然涌现标签
open_codes = []
for msg in messages:
    text = msg['text']
    code, category = ai_extract_code_from_text(text)  # AI 自主理解
    if code:
        open_codes.append({"text": text, "code": code, "category": category})

# 主轴编码:聚类
axial_clusters = {}
for code in open_codes:
    cat = code['category']
    if cat not in axial_clusters:
        axial_clusters[cat] = {}
    axial_clusters[cat][code['code']] = axial_clusters[cat].get(code['code'], 0) + 1

# 选择性编码:提取核心特质(含范畴新增规则)
core_traits = {}

# 规则 1: 初次运行建议生成 3-5 个特质(太少不全面,太多不聚焦)
# 规则 2: 每个范畴至少有 2 个编码或总频次>=消息数的 10% 才保留
# 规则 3: 最多保留 7 个特质(按频次排序,取前 7 个)

for cat, labels in axial_clusters.items():
    total_count = sum(labels.values())
    
    # 判断是否新增/保留这个范畴
    if len(labels) < 2 and total_count < len(messages) * 0.1:
        # 范畴太小,跳过
        continue
    
    top_label, count = max(labels.items(), key=lambda x: x[1])
    
    # 初始饱和度计算:0.5 + (频次/总消息数)*0.5
    # 示例:4 条消息中有 2 条提到 → 饱和度 = 0.5 + (2/4)*0.5 = 0.75
    saturation = min(0.95, 0.5 + (count / max(len(messages), 1)) * 0.5)
    
    # 初次运行饱和度修正(避免单次分析饱和度过高)
    if cat not in historical_traits:
        saturation = min(saturation, 0.7)  # 初次最高 0.7
    
    # 置信度更新规则(不新增文件,内存计算)
    confidence = saturation
    if cat in historical_traits:  # 有历史记录
        old_value = historical_traits[cat].get('value', '')
        old_confidence = historical_traits[cat].get('confidence', 0.5)
        
        if top_label == old_value:
            # 一致:提升置信度
            confidence = min(0.95, old_confidence + 0.05)
        else:
            # 冲突:新说法权重更高
            confidence = max(0.6, saturation)  # 新特质至少 0.6
    
    core_traits[cat] = {
        "value": top_label,
        "saturation": saturation,
        "confidence": confidence,
        "level": "core" if confidence >= 0.7 else "secondary",
        "change": f"+{int((confidence-saturation)*100)}%" if confidence > saturation else f"{int((confidence-saturation)*100)}%"
    }

# 按频次排序,最多保留 7 个特质
core_traits = dict(sorted(core_traits.items()