Install any skill in seconds. Free to start, no credit card required.
Get Started Free →管理組織成員(家人、同事、親戚等)的個人資料、農曆/新曆生日及紀念日,並用 OpenClaw cron 設置自動提醒。Use when: (1) 添加/編輯成員資料, (2) 設置生日或紀念日提醒, (3) 更新農曆對應的新曆日期, (4) 查看即將到來的重要日子, (5) 管理多個組織的成員。NOT for: 一般日程安排(用 calendar skill)。
.claude/skills/leoyeai-member-manager/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-06 | ✗→✓ | ▲ Improved | 240% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 527% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 416% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 453% | 0% |
| case-13 | ✗→✓ | ▲ Improved | 487% | 0% |
管理多個組織(家庭、同事、親戚等)中成員的個人資料、農曆/新曆生日及各類紀念日,並透過 OpenClaw scheduled-tasks 自動發送提醒。
此 skill 支持多用戶共享同一個 OpenClaw(例如 Telegram bot 場景)。每個用戶的數據存放在以用戶 session key 命名的獨立目錄,互不干擾。
~/.openclaw/workspace/users/{SESSION_KEY}/members.json
~/.openclaw/workspace/users/{SESSION_KEY}/reminders.json{SESSION_KEY} 是 OpenClaw 的當前 session 標識符(Telegram DM 場景即為 Telegram user ID)。
在使用任何成員數據前,必須先確定當前用戶的路徑。
讀取環境變數或 session context 取得用戶 ID,必須先清洗以防止目錄遍歷攻擊,然後初始化數據目錄:
pythonimport os, json, re def sanitize_session_key(raw_key: str) -> str: """清洗 session key,只允許字母數字、連字號和底線,防止目錄遍歷""" sanitized = re.sub(r'[^a-zA-Z0-9_-]', '', raw_key) if not sanitized: raise ValueError(f"Invalid session key: {raw_key!r}") return sanitized # 方法 1:從環境變數取得 raw_id = os.environ.get("OPENCLAW_SESSION_KEY", "default") # 方法 2:如果是在 Telegram bot 場景,嘗試讀取 session 檔案 session_file = os.path.expanduser("~/.openclaw/session.json") if os.path.exists(session_file): with open(session_file) as f: session = json.load(f) raw_id = session.get("user_id", session.get("session_key", "default")) user_id = sanitize_session_key(str(raw_id)) WORKSPACE_ROOT = os.path.expanduser("~/.openclaw/workspace/users") base_dir = os.path.join(WORKSPACE_ROOT, user_id) # 二次驗證:確保解析後的路徑仍在 workspace 目錄內 real_base = os.path.realpath(base_dir) real_root = os.path.realpath(WORKSPACE_ROOT) if not real_base.startswith(real_root + os.sep): raise ValueError(f"Path traversal detected: {base_dir}") members_path = os.path.join(base_dir, "members.json") reminders_path = os.path.join(base_dir, "reminders.json") # 初始化新用戶 os.makedirs(base_dir, exist_ok=True) if not os.path.exists(members_path): with open(members_path, "w") as f: json.dump([], f) if not os.path.exists(reminders_path): with open(reminders_path, "w") as f: json.dump([], f)
json[ { "id": "uuid-v4", "name": "張三", "group": "家庭", "relationship": "父親", "phone": "0912345678", "birthday_solar": "1955-03-15", "birthday_lunar": { "month": 2, "day": 13, "is_leap_month": false }, "birthday_lunar_solar_this_year": "2025-03-12", "anniversaries": [ { "id": "uuid-v4", "label": "結婚紀念日", "date_solar": "1980-06-20", "recurring": true } ], "notes": "喜歡喝普洱茶", "created_at": "2025-01-01T00:00:00Z", "updated_at": "2025-01-01T00:00:00Z" } ]
欄位說明:
id:UUID v4,成員唯一標識name:姓名(必填)group:組別/組織名稱,如「家庭」「公司」「大學同學」(必填)relationship:與用戶的關係,如「父親」「主管」「同學」phone:電話號碼birthday_solar:新曆生日,格式 YYYY-MM-DDbirthday_lunar:農曆生日,含 month/day/is_leap_monthbirthday_lunar_solar_this_year:農曆生日在當年對應的新曆日期(每年需更新)anniversaries:紀念日列表,每個紀念日有獨立 idnotes:備註created_at / updated_at:時間戳json[ { "id": "uuid-v4", "member_id": "對應 member 的 id", "type": "birthday_solar", "label": "張三 新曆生日", "advance_days": 3, "scheduled_task_id": "member-birthday-張三-solar", "enabled": true } ]
欄位說明:
type:birthday_solar | birthday_lunar | anniversaryadvance_days:提前幾天提醒(默認 3 天)scheduled_task_id:對應 OpenClaw scheduled-task 的 IDenabled:是否啟用農曆轉新曆每年都會變,因此需要每年更新農曆生日對應的新曆日期。
python# pip install lunardate from lunardate import LunarDate from datetime import date, timedelta def lunar_to_solar(year: int, lunar_month: int, lunar_day: int, is_leap: bool = False) -> date: """將農曆日期轉換為新曆日期""" try: lunar = LunarDate(year, lunar_month, lunar_day, is_leap) return lunar.toSolarDate() except ValueError: # 若該年無此農曆日期(例如閏月不存在),嘗試非閏月 if is_leap: lunar = LunarDate(year, lunar_month, lunar_day, False) return lunar.toSolarDate() raise
pythondef calculate_reminder_date(target_date: date, advance_days: int) -> date: """計算提前提醒的日期,正確處理跨月情況""" return target_date - timedelta(days=advance_days)
pythondef update_all_lunar_birthdays(base_dir: str, year: int): """更新所有成員農曆生日在指定年份的新曆日期""" members_path = os.path.join(base_dir, "members.json") with open(members_path) as f: members = json.load(f) updated = [] for m in members: lunar = m.get("birthday_lunar") if lunar: try: solar = lunar_to_solar( year, lunar["month"], lunar["day"], lunar.get("is_leap_month", False) ) m["birthday_lunar_solar_this_year"] = str(solar) updated.append(m["name"]) except ValueError as e: # 記錄錯誤但繼續處理其他成員 pass m["updated_at"] = datetime.utcnow().isoformat() + "Z" with open(members_path, "w") as f: json.dump(members, f, ensure_ascii=False, indent=2) return updated
當用戶要求添加成員時:
pythonimport json, os, uuid from datetime import datetime def add_member(base_dir, name, group, relationship="", birthday_solar=None, birthday_lunar=None, phone="", notes=""): path = os.path.join(base_dir, "members.json") with open(path) as f: members = json.load(f) # 檢查是否已有同名同組成員 for existing in members: if existing["name"] == name and existing["group"] == group: return None, f"已存在同名成員:{name}({group})" now = datetime.utcnow().isoformat() + "Z" member = { "id": str(uuid.uuid4()), "name": name, "group": group, "relationship": relationship, "phone": phone, "birthday_solar": birthday_solar, "birthday_lunar": birthday_lunar, "birthday_lunar_solar_this_year": None, "anniversaries": [], "notes": notes, "created_at": now, "updated_at": now } # 如果有農曆生日,計算當年新曆日期 if birthday_lunar: from lunardate import LunarDate from datetime import date try: solar = lunar_to_solar( date.today().year, birthday_lunar["month"], birthday_lunar["day"], birthday_lunar.get("is_leap_month", False) ) member["birthday_lunar_solar_this_year"] = str(solar) except ValueError: pass members.append(member) with open(path, "w") as f: json.dump(members, f, ensure_ascii=False, indent=2) return member, None
pythondef update_member(base_dir, member_id, **updates): """更新成員資料。支持更新任意欄位。""" path = os.path.join(base_dir, "members.json") with open(path) as f: members = json.load(f) for m in members: if m["id"] == member_id: for key, value in updates.items(): if key in m and key not in ("id", "created_at"): m[key] = value m["updated_at"] = datetime.utcnow().isoformat() + "Z" # 如果更新了農曆生日,重新計算新曆日期 if "birthday_lunar" in updates and updates["birthday_lunar"]: from datetime import date try: lunar = updates["birthday_lunar"] solar = lunar_to_solar( date.today().year, lunar["month"], lunar["day"], lunar.get("is_leap_month", False) ) m["birthday_lunar_solar_this_year"] = str(solar) except ValueError: pass with open(path, "w") as f: json.dump(members, f, ensure_ascii=False, indent=2) return m return None
刪除成員時必須同步清理提醒:
pythondef delete_member(base_dir, member_id): """刪除成員及其所有提醒""" # 刪除成員 members_path = os.path.join(base_dir, "members.json") with open(members_path) as f: members = json.load(f) member = None new_members = [] for m in members: if m["id"] == member_id: member = m else: new_members.append(m) if not member: return None, [] with open(members_path, "w") as f: json.dump(new_members, f, ensure_ascii=False, indent=2) # 清理該成員的所有提醒 reminders_path = os.path.join(base_dir, "reminders.json") with open(reminders_path) as f: reminders = json.load(f) removed_task_ids = [] new_reminders = [] for r in reminders: if r["member_id"] == member_id: removed_task_ids.append(r.get("scheduled_task_id")) else: new_reminders.append(r) with open(reminders_path, "w") as f: json.dump(new_reminders, f, ensure_ascii=False, indent=2) return member, removed_task_ids
重要:刪除成員後,需要用 mcp__scheduled-tasks__update_scheduled_task 停用對應的 scheduled tasks(將 removed_task_ids 中的 task 設為 disabled)。
pythondef add_anniversary(base_dir, member_id, label, date_solar, recurring=True): """為成員添加紀念日""" path = os.path.join(base_dir, "members.json") with open(path) as f: members = json.load(f) for m in members: if m["id"] == member_id: anniversary = { "id": str(uuid.uuid4()), "label": label, "date_solar": date_solar, "recurring": recurring } m["anniversaries"].append(anniversary) m["updated_at"] = datetime.utcnow().isoformat() + "Z" with open(path, "w") as f: json.dump(members, f, ensure_ascii=False, indent=2) return anniversary return None
pythondef remove_anniversary(base_dir, member_id, anniversary_id): """刪除成員的某個紀念日""" path = os.path.join(base_dir, "members.json") with open(path) as f: members = json.load(f) for m in members: if m["id"] == member_id: m["anniversaries"] = [ a for a in m["anniversaries"] if a["id"] != anniversary_id ] m["updated_at"] = datetime.utcnow().isoformat() + "Z" with open(path, "w") as f: json.dump(members, f, ensure_ascii=False, indent=2) return True return False
pythonfrom datetime import date, timedelta import calendar def _safe_replace_year(d: date, year: int) -> date: """安全替換年份,處理 2/29 在非閏年的情況(fallback 到 2/28)""" if d.month == 2 and d.day == 29 and not calendar.isleap(year): return date(year, 2, 28) return d.replace(year=year) def upcoming_events(base_dir, days_ahead=30): """查詢未來 N 天內的生日和紀念日""" path = os.path.join(base_dir, "members.json") with open(path) as f: members = json.load(f) today = date.today() end_date = today + timedelta(days=days_ahead) events = [] for m in members: # 新曆生日 if m.get("birthday_solar"): bday = date.fromisoformat(m["birthday_solar"]) this_year = _safe_replace_year(bday, today.year) # 處理跨年情況 if this_year < today: this_year = _safe_replace_year(bday, today.year + 1) if today <= this_year <= end_date: age = this_year.year - bday.year events.append({ "date": str(this_year), "name": m["name"], "group": m["group"], "type": "新曆生日", "label": f"{m['name']} 的生日({age} 歲)", "member_id": m["id"] }) # 農曆生日(使用預計算的當年新曆日期) if m.get("birthday_lunar_solar_this_year"): lunar_solar = date.fromisoformat(m["birthday_lunar_solar_this_year"]) if today <= lunar_solar <= end_date: events.append({ "date": str(lunar_solar), "name": m["name"], "group": m["group"], "type": "農曆生日", "label": f"{m['name']} 的農曆生日(農曆{m['birthday_lunar']['month']}月{m['birthday_lunar']['day']}日)", "member_id": m["id"] }) # 紀念日 for ann in m.get("anniversaries", []): if ann.get("recurring") and ann.get("date_solar"): aday = date.fromisoformat(ann["date_solar"]) this_year = _safe_replace_year(aday, today.year) if this_year < today: this_year = _safe_replace_year(aday, today.year + 1) if today <= this_year <= end_date: years = this_year.year - aday.year events.append({ "date": str(this_year), "name": m["name"], "group": m["group"], "type": "紀念日", "label": f"{m['name']} — {ann['label']}(第 {years} 年)", "member_id": m["id"] }) return sorted(events, key=lambda e: e["date"])
pythondef search_members(base_dir, query=None, group=None): """搜索成員。支持按名字模糊搜索和按組別篩選。""" path = os.path.join(base_dir, "members.json") with open(path) as f: members = json.load(f) results = members if group: results = [m for m in results if m["group"] == group] if query: query_lower = query.lower() results = [m for m in results if query_lower in m["name"].lower() or query_lower in m.get("relationship", "").lower() or query_lower in m.get("notes", "").lower()] return results def list_groups(base_dir): """列出所有組別及成員數量""" path = os.path.join(base_dir, "members.json") with open(path) as f: members = json.load(f) groups = {} for m in members: g = m["group"] groups[g] = groups.get(g, 0) + 1 return groups
提醒使用 OpenClaw 的 mcp__scheduled-tasks__create_scheduled_task 工具來創建持久化的定時任務。
為成員設置生日提醒時,需要計算提醒日期並創建 scheduled task:
步驟:
1. 確定生日日期(新曆或農曆轉新曆)
2. 計算提醒日期 = 生日日期 - advance_days
3. 使用 mcp__scheduled-tasks__create_scheduled_task 創建任務
4. 將提醒信息寫入 reminders.json新曆生日提醒(每年固定日期):
taskId: "member-birthday-{member_name}-solar"
cronExpression: "0 9 {remind_day} {remind_month} *"
prompt: "🎂 提醒:{member_name} 的生日在 {advance_days} 天後({birthday_month}/{birthday_day})!請準備祝福!\n\n成員資料:\n- 關係:{relationship}\n- 組別:{group}\n- 備註:{notes}"
description: "{member_name} 生日提醒(提前 {advance_days} 天)"農曆生日提醒(日期每年變化,需配合年度更新):
taskId: "member-birthday-{member_name}-lunar"
cronExpression: "0 9 {remind_day} {remind_month} *"
prompt: "🎂 提醒:{member_name} 的農曆生日在 {advance_days} 天後(農曆{lunar_month}月{lunar_day}日,今年新曆{solar_date})!\n\n成員資料:\n- 關係:{relationship}\n- 組別:{group}\n- 備註:{notes}"
description: "{member_name} 農曆生日提醒(提前 {advance_days} 天)"紀念日提醒:
taskId: "member-anniversary-{member_name}-{anniversary_label}"
cronExpression: "0 9 {remind_day} {remind_month} *"
prompt: "💝 提醒:{member_name} 的{anniversary_label}在 {advance_days} 天後({date})!\n\n成員資料:\n- 關係:{relationship}\n- 備註:{notes}"
description: "{member_name} {anniversary_label}提醒"重要:不能簡單用 day - advance_days,必須用日期運算處理跨月情況:
pythonfrom datetime import date, timedelta import calendar def get_reminder_cron(target_month, target_day, advance_days): """計算提醒的 cron expression,正確處理跨月和跨年""" today = date.today() year = today.year m, d = int(target_month), int(target_day) # 處理 2/29 非閏年 fallback if m == 2 and d == 29 and not calendar.isleap(year): d = 28 target = date(year, m, d) # 如果今年的目標日期已過,使用明年 if target < today: year += 1 if m == 2 and int(target_day) == 29 and not calendar.isleap(year): d = 28 target = date(year, m, d) remind_date = target - timedelta(days=advance_days) # 返回 cron: 分 時 日 月 星期 return f"0 9 {remind_date.day} {remind_date.month} *"
pythondef save_reminder(base_dir, member_id, reminder_type, label, advance_days, task_id): """保存提醒記錄""" path = os.path.join(base_dir, "reminders.json") with open(path) as f: reminders = json.load(f) reminder = { "id": str(uuid.uuid4()), "member_id": member_id, "type": reminder_type, "label": label, "advance_days": advance_days, "scheduled_task_id": task_id, "enabled": True } reminders.append(reminder) with open(path, "w") as f: json.dump(reminders, f, ensure_ascii=False, indent=2) return reminder
應設置一個每年 1 月 1 日執行的 scheduled task,自動更新所有農曆生日的新曆日期:
taskId: "member-lunar-annual-update"
cronExpression: "0 10 1 1 *"
prompt: "執行 member-manager 年度農曆更新:
1. 讀取 members.json 中所有有農曆生日的成員
2. 使用 lunardate 將每個農曆生日轉換為今年的新曆日期
3. 更新 birthday_lunar_solar_this_year 欄位
4. 更新所有農曆生日提醒的 cron expression(因為新曆日期變了)
5. 回報更新結果"
description: "每年自動更新農曆生日對應的新曆日期"📋 {group} 成員列表(共 N 人)
1. {name}({relationship})
🎂 生日:{birthday_solar}(新曆)/ 農曆{lunar_month}月{lunar_day}日
📞 {phone}
📝 {notes}
2. ...📅 未來 {days} 天的重要日子:
🎂 {date} — {name} 的生日({age} 歲)
💝 {date} — {name} — {anniversary_label}(第 N 年)
...
共 N 個事件。✅ 已添加成員:{name}({group} / {relationship})
生日:{birthday_info}
已設置提醒:提前 {advance_days} 天
✅ 已刪除成員:{name}
已清理 {N} 個相關提醒
✅ 已更新 {N} 位成員的農曆生日新曆日期以下是用戶可以對 AI 說的話,以及 skill 應如何回應:
| 用戶說 | AI 應執行 | |--------|-----------| | 幫我加一個成員:媽媽,農曆三月初五生日 | add_member(group 默認「家庭」) + lunar_to_solar + 存檔 + 詢問是否設置提醒 | | 加同事小王,5月3號生日 | add_member(group「同事」)+ 存檔 | | 查看這個月有哪些生日 | upcoming_events(days_ahead=30),以表格顯示 | | 幫我提前 3 天提醒張三的生日 | 計算提醒日期 + create_scheduled_task + save_reminder | | 更新今年所有農曆生日的新曆日期 | update_all_lunar_birthdays + 更新相關提醒的 cron | | 顯示家庭組的所有成員 | search_members(group="家庭"),以列表顯示 | | 幫張三加一個結婚紀念日 6/20 | add_anniversary + 詢問是否設置提醒 | | 刪除成員李四 | 確認後 delete_member + 清理提醒 + 停用 scheduled tasks | | 修改張三的電話 | update_member(phone=...) | | 列出所有組別 | list_groups 顯示組別及人數 | | 查看所有提醒 | 讀取 reminders.json 並用 list_scheduled_tasks 顯示狀態 | | 設置每年自動更新農曆 | 創建 member-lunar-annual-update scheduled task |
用戶:幫我加一個成員,我媽媽,農曆三月初五生日
AI:
1. 解析信息:姓名=媽媽,關係=母親,農曆生日=三月初五
2. 計算今年新曆日期
3. 確認:
「確認添加以下成員:
- 姓名:媽媽
- 組別:家庭
- 關係:母親
- 農曆生日:三月初五(今年新曆 {date})
是否正確?要設置生日提醒嗎?」
4. 用戶確認後存檔
5. 如果要提醒,詢問提前幾天(默認 3 天)
6. 創建 scheduled task + 保存 reminder用戶可能用多種方式表達農曆日期:
本 skill 存儲個人可識別信息(PII),包括姓名、電話、生日等。所有數據以明文 JSON 存儲在本地磁碟。
必要的安全措施:
chmod 700 ~/.openclaw/workspace/users/)gpg 或加密壓縮包)python# 初始化時設置目錄權限 import stat os.makedirs(base_dir, exist_ok=True) os.chmod(base_dir, stat.S_IRWXU) # 700: 僅 owner 可讀寫執行
Session key 必須經過清洗才能用於構建文件路徑,防止目錄遍歷攻擊(如 ../../etc/passwd)。參見上方 sanitize_session_key() 函數。
當此 skill 被 AI agent 自主調用時:
推薦使用 lunardate 套件(PyPI: lunardate):
pip-audit 掃描確認birthday_lunar.is_leap_month 標記是否為閏月,轉換時需傳入 is_leap=True。若該年無閏月,自動 fallback 到非閏月lunardate 已安裝(pip install lunardate),並用 pip-audit 掃描_safe_replace_year() 自動 fallback 到 2/28(非閏年)| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-06 | fail→pass | 16,824 | 13,354 | -21% | 1 | 1 | 0% | 3,060 | 10,402 | +240% | 0 | 0 | — |
case-05 | pass→pass | 14,932 | 12,722 | -15% | 1 | 1 | 0% | 2,807 | 10,194 | +263% | 0 | 0 | — |
case-01 | fail→fail | 3,910 | 13,349 | +241% | 1 | 1 | 0% | 475 | 8,470 | +1683% | 0 | 0 | — |
case-02 | fail→fail | 6,702 | 8,820 | +32% | 1 | 1 | 0% | 431 | 8,253 | +1815% | 0 | 0 | — |
case-03 | pass→pass | 12,064 | 13,767 | +14% | 1 | 1 | 0% | 2,485 | 11,106 | +347% | 0 | 0 | — |
case-04 | pass→pass | 20,911 | 20,493 | -2% | 1 | 1 | 0% | 3,205 | 11,557 | +261% | 0 | 0 | — |
case-07 | pass→pass | 9,684 | 5,900 | -39% | 1 | 1 | 0% | 1,675 | 8,903 | +432% | 0 | 0 | — |
case-08 | pass→pass | 8,850 | 5,629 | -36% | 1 | 1 | 0% | 1,580 | 8,813 | +458% | 0 | 0 | — |
case-09 | fail→pass | 8,348 | 4,941 | -41% | 1 | 1 | 0% | 1,392 | 8,728 | +527% | 0 | 0 | — |
case-10 | fail→pass | 13,003 | 9,564 | -26% | 1 | 1 | 0% | 1,821 | 9,391 | +416% | 0 | 0 | — |
case-11 | fail→pass | 9,493 | 2,939 | -69% | 1 | 1 | 0% | 1,508 | 8,344 | +453% | 0 | 0 | — |
case-12 | pass→pass | 6,185 | 8,228 | +33% | 1 | 1 | 0% | 1,347 | 9,456 | +602% | 0 | 0 | — |
case-13 | fail→pass | 9,129 | 2,707 | -70% | 1 | 1 | 0% | 1,415 | 8,304 | +487% | 0 | 0 | — |
case-14 | fail→pass | 9,578 | 4,089 | -57% | 1 | 1 | 0% | 1,394 | 8,624 | +519% | 0 | 0 | — |
case-20 | fail→fail | 9,753 | 6,986 | -28% | 1 | 1 | 0% | 1,604 | 9,213 | +474% | 0 | 0 | — |
case-15 | fail→pass | 8,237 | 3,779 | -54% | 1 | 1 | 0% | 1,399 | 8,688 | +521% | 0 | 0 | — |
case-16 | fail→pass | 7,746 | 3,571 | -54% | 1 | 1 | 0% | 1,274 | 8,486 | +566% | 0 | 0 | — |
case-17 | fail→pass | 13,041 | 8,204 | -37% | 1 | 1 | 0% | 2,016 | 9,154 | +354% | 0 | 0 | — |
case-18 | fail→pass | 10,826 | 11,761 | +9% | 1 | 1 | 0% | 2,039 | 10,123 | +396% | 0 | 0 | — |
case-19 | fail→pass | 7,935 | 5,177 | -35% | 1 | 1 | 0% | 1,475 | 8,820 | +498% | 0 | 0 | — |
case-21 | pass→pass | 11,501 | 8,918 | -22% | 1 | 1 | 0% | 1,827 | 9,539 | +422% | 0 | 0 | — |
case-22 | pass→pass | 10,384 | 5,354 | -48% | 1 | 1 | 0% | 1,929 | 8,955 | +364% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 20 counted toward the lift figure. The other 2 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +50 percentage points is the difference between those two pass rates over the 20 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.