Send User Message
TinyAGI/tinyagi
Send a proactive message to a paired user via their channel (Discord, Telegram, or WhatsApp).
管理組織成員(家人、同事、親戚等)的個人資料、農曆/新曆生日及紀念日,並用 OpenClaw cron 設置自動提醒。Use when: (1) 添加/編輯成員資料, (2) 設置生日或紀念日提醒, (3) 更新農曆對應的新曆日期, (4) 查看即將到來的重要日子, (5) 管理多個組織的成員。NOT for: 一般日程安排(用 calendar skill)。
$ npx skills add LeoYeAI/openclaw-master-skills --skill member-manager -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install LeoYeAI/openclaw-master-skills member-manager --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/LeoYeAI/openclaw-master-skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/mybirthday .claude/skills/member-manager && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "member-manager" agent skill from https://github.com/LeoYeAI/openclaw-master-skills/tree/main/skills/mybirthday into .claude/skills/member-manager/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "member-manager", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/LeoYeAI/openclaw-master-skills/tree/main/skills/mybirthdayType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add LeoYeAI/openclaw-master-skills --skill member-manager -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install LeoYeAI/openclaw-master-skills member-manager --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/LeoYeAI/openclaw-master-skills.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/mybirthday .agents/skills/member-manager && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "member-manager" agent skill from https://github.com/LeoYeAI/openclaw-master-skills/tree/main/skills/mybirthday into .agents/skills/member-manager/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "member-manager", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add LeoYeAI/openclaw-master-skills --skill member-manager -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install LeoYeAI/openclaw-master-skills member-manager --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/LeoYeAI/openclaw-master-skills.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/mybirthday .cursor/skills/member-manager && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "member-manager" agent skill from https://github.com/LeoYeAI/openclaw-master-skills/tree/main/skills/mybirthday into .cursor/skills/member-manager/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "member-manager", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/LeoYeAI/openclaw-master-skills.git --path skills/mybirthday--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add LeoYeAI/openclaw-master-skills --skill member-manager -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install LeoYeAI/openclaw-master-skills member-manager --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/LeoYeAI/openclaw-master-skills.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/mybirthday .gemini/skills/member-manager && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "member-manager" agent skill from https://github.com/LeoYeAI/openclaw-master-skills/tree/main/skills/mybirthday into .gemini/skills/member-manager/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "member-manager", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install LeoYeAI/openclaw-master-skills member-managerInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add LeoYeAI/openclaw-master-skills --skill member-manager -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/LeoYeAI/openclaw-master-skills.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/mybirthday .github/skills/member-manager && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "member-manager" agent skill from https://github.com/LeoYeAI/openclaw-master-skills/tree/main/skills/mybirthday into .github/skills/member-manager/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "member-manager", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add LeoYeAI/openclaw-master-skills --skill member-manager -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install LeoYeAI/openclaw-master-skills member-manager --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/LeoYeAI/openclaw-master-skills.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/mybirthday .opencode/skills/member-manager && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "member-manager" agent skill from https://github.com/LeoYeAI/openclaw-master-skills/tree/main/skills/mybirthday into .opencode/skills/member-manager/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "member-manager", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
member-manager管理組織成員(家人、同事、親戚等)的個人資料、農曆/新曆生日及紀念日,並用 OpenClaw cron 設置自動提醒。Use when: (1) 添加/編輯成員資料, (2) 設置生日或紀念日提醒, (3) 更新農曆對應的新曆日期, (4) 查看即將到來的重要日子, (5) 管理多個組織的成員。NOT for: 一般日程安排(用 calendar skill)。
Member Manager is an agent skill from LeoYeAI/openclaw-master-skills. 管理組織成員(家人、同事、親戚等)的個人資料、農曆/新曆生日及紀念日,並用 OpenClaw cron 設置自動提醒。Use when: (1) 添加/編輯成員資料, (2) 設置生日或紀念日提醒, (3) 更新農曆對應的新曆日期, (4) 查看即將到來的重要日子, (5) 管理多個組織的成員。NOT for: 一般日程安排(用 calendar skill)。
Its SKILL.md is about 5.4k tokens, which your agent loads only when the skill is triggered. The skill folder holds 1 other file (for example `_meta.json`).
It sits in Productivity & Automation, covering Scheduled and recurring tasks. It works with Telegram. The repository describes itself as: 🧠 Curated collection of 1209+ best OpenClaw skills — weekly updated by MyClaw.ai. The licence is MIT-0.
7 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit e5199b5. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
pipFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md. Its commands use pip, which can reach the network depending on how they are called.
From URLs in SKILL.md, links to its own repository left out.
Names these keys or tokens, usually read from environment variables:
SESSION_KEYOPENCLAW_SESSION_KEYFrom names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Member Manager loads about 5.4k tokens when it runs. Until then it costs about 49 tokens; SKILL.md has 342 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from LeoYeAI/openclaw-master-skills at commit e5199b5, republished under its MIT-0 licence (© LeoYeAI). 342 words, ~5,371 tokens.
.claude/skills/member-manager/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.管理多個組織(家庭、同事、親戚等)中成員的個人資料、農曆/新曆生日及各類紀念日,並透過 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,必須先清洗以防止目錄遍歷攻擊,然後初始化數據目錄:
import 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)[
{
"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:時間戳[
{
"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:是否啟用農曆轉新曆每年都會變,因此需要每年更新農曆生日對應的新曆日期。
# 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()
raisedef calculate_reminder_date(target_date: date, advance_days: int) -> date:
"""計算提前提醒的日期,正確處理跨月情況"""
return target_date - timedelta(days=advance_days)def 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當用戶要求添加成員時:
import 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, Nonedef 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刪除成員時必須同步清理提醒:
def 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)。
def 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 Nonedef 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 Falsefrom 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"])def 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,必須用日期運算處理跨月情況:
from 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} *"def 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 或加密壓縮包)# 初始化時設置目錄權限
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(非閏年)© LeoYeAI, MIT-0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 1 other file in skills/mybirthday of LeoYeAI/openclaw-master-skills.
Open the folder on GitHubat commit e5199b5
Member Manager next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Member Manager this skillLeoYeAI/openclaw-master-skills | 2.2k | — | ~5.4k | Automated safety check: Pass | MIT-0 | |
| Send User MessageTinyAGI/tinyagi | 3.6k | — | ~829 | Automated safety check: Pass | MIT | |
| Cortext Self Diagnosisgrandamenium/cortextos | 101 | — | ~3.7k | Automated safety check: Pass | MIT | |
| Actionizeinfranodus/skills | 119 | — | ~3.8k | Automated safety check: Notes | None | |
| Cronsmixs/agent-second-brain | 393 | — | ~856 | Automated safety check: Pass | MIT | |
| Task Manager0xranx/golembot | 322 | — | ~694 | Automated safety check: Pass | MIT |
TinyAGI/tinyagi
Send a proactive message to a paired user via their channel (Discord, Telegram, or WhatsApp).
grandamenium/cortextos
Diagnose cortextOS itself when the framework misbehaves — an agent has gone silent or wedged, agents are crash-looping, Telegram or agent-to-agent messages are not arriving, crons did not fire, an…
infranodus/skills
Turn insights, findings, or research into an actionable plan with deadlines and scheduled Telegram reminders.
smixs/agent-second-brain
Управление собственным расписанием — напоминания, рутины, периодические задачи.
0xranx/golembot
Creates and manages scheduled tasks, cron jobs, recurring reminders, and timers via the Task HTTP API.
sickn33/agentic-awesome-skills
Send Telegram messages, files, and alerts via bot API; ask questions with inline buttons and wait for the answer.
LeoYeAI/openclaw-master-skills
Manages pipelines on a DevOps quality and efficiency platform through its OpenAPI: list workspaces and templates, create, update, run and cancel pipelines, and read run records.
LeoYeAI/openclaw-master-skills
Patches OpenClaw's Feishu extension so an edited document triggers an isolated agent session that reads the doc and replies inline, turning it into a live chat space.
LeoYeAI/openclaw-master-skills
Multi-context memory management system for OpenClaw agents with group-isolated storage, global shared memory, workspace organization, and group-specific skills isolation.
LeoYeAI/openclaw-master-skills
Runs a brand's AI-search visibility work end to end: diagnosing how AI platforms represent it, repositioning it, producing AI-optimized content and monitoring ongoing mentions.
LeoYeAI/openclaw-master-skills
Installs and authenticates the gws CLI, then automates Gmail, Drive, Sheets, Calendar, Docs, Chat and Tasks with ready-made recipes, persona bundles and security audits.
LeoYeAI/openclaw-master-skills
Runs four advisor roles, a fitness coach, nutritionist, data analyst and TCM practitioner, to build a health profile and track workouts, diet and wellness over time.
Works with
Categories
管理組織成員(家人、同事、親戚等)的個人資料、農曆/新曆生日及紀念日,並用 OpenClaw cron 設置自動提醒。Use when: (1) 添加/編輯成員資料, (2) 設置生日或紀念日提醒, (3) 更新農曆對應的新曆日期, (4) 查看即將到來的重要日子, (5) 管理多個組織的成員。NOT for: 一般日程安排(用 calendar skill)。. Member Manager is an agent skill from LeoYeAI/openclaw-master-skills.
Member Manager fits situations like: 管理多個組織的成員。NOT for: 一般日程安排(用 calendar skill); tasks that involve Scheduled and recurring tasks.
Run `npx skills add LeoYeAI/openclaw-master-skills --skill member-manager -a claude-code`. Or copy the skill folder (skills/mybirthday in LeoYeAI/openclaw-master-skills) into .claude/skills/member-manager in your project. Claude Code loads it when a task matches its description.
Run `npx skills add LeoYeAI/openclaw-master-skills --skill member-manager -a codex`. Or copy the skill folder (skills/mybirthday in LeoYeAI/openclaw-master-skills) into .agents/skills/member-manager in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add LeoYeAI/openclaw-master-skills --skill member-manager -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/member-manager, .gemini/skills/member-manager, .github/skills/member-manager and .opencode/skills/member-manager in your project.
Going by SKILL.md and its folder, Member Manager needs the command-line tools its instructions call (pip) and credentials named SESSION_KEY and OPENCLAW_SESSION_KEY. Our summary lists: Python 3; A credential in OPENCLAW_SESSION_KEY; A credential in SESSION_KEY.
SKILL.md contains no URLs. Its commands use pip, which can reach the network depending on how they are called. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Member Manager is published under the MIT-0 licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.
About 5.4k tokens (SKILL.md is roughly 21k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Member Manager: Send User Message (TinyAGI/tinyagi, 3.6k stars), Cortext Self Diagnosis (grandamenium/cortextos, 101 stars), Actionize (infranodus/skills, 119 stars) and Cron (smixs/agent-second-brain, 393 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
LeoYeAI (a GitHub user) maintains it in LeoYeAI/openclaw-master-skills, which has 2,161 GitHub stars. The repository holds 1,235 skills in this directory. The repository was last updated on July 20, 2026.
Source: LeoYeAI/openclaw-master-skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.