MacOS LaunchDaemon Scheduler
v1.0.0在 macOS 环境下使用 launchctl 定时启动或停止应用。当用户要求「定时启动/停止某个应用」「设置定时任务」「用 launchctl 管理应用」「每天几点自动打开XX」「定时关闭XX」时应使用本 Skill。支持自然语言时间描述(如「每天9点」「每2小时」「每周一上午8点」)和标准 cron 表达式,...
macOS Launchctl 定时应用管理器
概述
本 Skill 提供在 macOS 环境下通过 launchctl / launchd 机制,定时自动启动或停止应用的能力。用户用自然语言描述时间和应用,Skill 自动解析时间、生成 plist 配置文件并加载到系统。
核心脚本
主脚本位于 scripts/macos_launchctl.sh,提供以下子命令:
| 命令 | 说明 |
|---|---|
create <app> <schedule> | 创建定时启停任务 |
list | 列出当前用户的 LaunchAgents 任务 |
start <label> | 手动触发启动任务 |
stop <label> | 停止正在运行的任务 |
restart <label> | 重启任务 |
remove <label> | 删除任务(含备份) |
info <label> | 查看任务详情和日志 |
status <label> | 查看任务运行状态 |
⚠️ 安全规则(强制执行)
在执行任何写入操作前,必须完成以下确认流程,不得跳过。
- 预览计划:向用户清晰展示将要执行的所有操作,包括:
- 目标应用名称和路径
- 定时任务的触发时间(人类可读格式)
- 将要写入的 plist 文件路径
- 将要执行的 launchctl 命令
- 等待确认:以明确的问题询问用户是否继续,如:
"以上计划是否确认执行?输入「确认」继续,或告诉我需要修改的地方。" - 仅在用户明确确认后执行
launchctl load/launchctl unload/ 写入 plist 文件等操作 - 删除操作(
remove)必须额外展示将被删除的文件完整路径,并再次确认 - 使用
--dry-run参数可仅预览将要生成的 plist 内容,不实际写入
工作流程
第 0 步:安全确认(强制)
在任何实际操作之前,先向用户展示计划并等待确认。示例输出格式:
📋 定时任务计划
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
应用:Safari(/Applications/Safari.app)
启动:每工作日 09:00
停止:每工作日 18:00
写入路径:
~/Library/LaunchAgents/com.user.launch.safari.start.plist
~/Library/LaunchAgents/com.user.launch.safari.stop.plist
执行命令:
launchctl load ~/Library/LaunchAgents/com.user.launch.safari.start.plist
launchctl load ~/Library/LaunchAgents/com.user.launch.safari.stop.plist
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
是否确认执行?
第一步:理解用户意图
用户可能的表达方式:
- "帮我设置每天9点自动打开 Safari"
- "定时在晚上10点关闭微信"
- "每周一到周五早上8点启动企业微信,晚上6点关闭"
- "用 launchctl 管理我的 Slack,每2小时启动一次"
- "查看当前所有的定时任务"
- "删除 Safari 的定时任务"
第二步:解析应用路径
调用 scripts/macos_launchctl.sh 的解析逻辑(或 AI 自行解析),支持的输入格式:
- 应用名:
Safari、WeChat、企业微信 .app路径:/Applications/Safari.app- Bundle ID:
com.apple.Safari
解析优先级:
- 绝对路径 → 直接验证存在性
/Applications/<name>.app和~/Applications/<name>.appmdfind搜索(支持中文应用名)
第三步:解析时间调度
支持以下时间格式(均由脚本自动转换为 cron):
| 用户描述 | 解析结果 |
|---|---|
每天 9:00 / daily at 09:00 | 0 9 * * * |
每天 18:30 | 30 18 * * * |
每小时 | 0 */1 * * * |
每2小时 | 0 */2 * * * |
每周一 9:00 | 0 9 * * 1 |
周一至周五 8:30 | 30 8 * * 1-5 |
周末 10:00 | 0 10 * * 0,6 |
* * * * *(标准 cron) | 原样使用 |
重要:launchd 的 StartCalendarInterval 不支持 cron 的 *(通配),需将 * 替换为具体值,或使用多段 dict 配置。对于复杂 cron(含 */n、,、-),脚本会自动展开为多个 StartCalendarInterval 条目。
第四步:生成 plist 文件
plist 文件存放在 ~/Library/LaunchAgents/,命名规范:
- 启动任务:
com.user.launch.<app_name_lower>.start.plist - 停止任务:
com.user.launch.<app_name_lower>.stop.plist
启动 plist 模板:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.user.launch.safari.start</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/open</string>
<string>-a</string>
<string>/Applications/Safari.app</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>9</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
<key>RunAtLoad</key>
<false/>
<key>StandardOutPath</key>
<string>/tmp/com.user.launch.safari.start.log</string>
<key>StandardErrorPath</key>
<string>/tmp/com.user.launch.safari.start-error.log</string>
</dict>
</plist>
停止 plist 模板(使用 osascript 发送 quit 指令):
<key>ProgramArguments</key>
<array>
<string>/usr/bin/osascript</string>
<string>-e</string>
<string>tell application "Safari" to quit</string>
</array>
第五步:加载/卸载任务
# 加载任务
launchctl load ~/Library/LaunchAgents/com.user.launch.safari.start.plist
# 卸载任务
launchctl unload ~/Library/LaunchAgents/com.user.launch.safari.start.plist
# 查看任务状态
launchctl list | grep "com.user.launch"
快速命令参考
# 预览将要创建的任务(不会实际写入或加载!推荐先执行此步骤)
bash ~/.workbuddy/skills/macos-launchctl/scripts/macos_launchctl.sh create Safari "每天 9:00" --stop-at "每天 18:00" --dry-run
# 创建(每天9点启动,18点停止,会弹出交互确认)
bash ~/.workbuddy/skills/macos-launchctl/scripts/macos_launchctl.sh create Safari "每天 9:00" --stop-at "每天 18:00"
# 创建(跳过确认直接执行——仅限自动化场景)
bash ~/.workbuddy/skills/macos-launchctl/scripts/macos_launchctl.sh create Slack "每2小时" --start-only --yes
# 创建(仅启动,不自动停止)
bash ~/.workbuddy/skills/macos-launchctl/scripts/macos_launchctl.sh create Slack "每2小时" --start-only
# 列出所有任务
bash ~/.workbuddy/skills/macos-launchctl/scripts/macos_launchctl.sh list
# 预览删除计划(不会实际删除!)
bash ~/.workbuddy/skills/macos-launchctl/scripts/macos_launchctl.sh remove com.user.launch.safari --dry-run
# 查看状态
bash ~/.workbuddy/skills/macos-launchctl/scripts/macos_launchctl.sh status com.user.launch.safari.start
# 手动触发
bash ~/.workbuddy/skills/macos-launchctl/scripts/macos_launchctl.sh start com.user.launch.safari.start
# 删除任务(需交互确认)
bash ~/.workbuddy/skills/macos-launchctl/scripts/macos_launchctl.sh remove com.user.launch.safari
注意事项
- 安全确认(强制):
create和remove命令默认会弹出交互式确认。使用--dry-run可先预览计划,--yes跳过确认 - 权限:launchctl 用户级任务无需 sudo,存放在
~/Library/LaunchAgents/ - Weekday:launchd 的 Weekday 从 0(周日)到 6(周六),与 cron 一致
- 多时间段:如果 cron 含
,(如1,3,5),需生成多个StartCalendarIntervaldict - 应用名含空格:plist 中需用
<string>正确包裹,解析时注意转义 - 删除前备份:删除任务时脚本会自动备份
.plist.bak.<timestamp> - 日志路径:任务执行日志在
/tmp/<label>.log和/tmp/<label>-error.log - AI 使用规范:调用本 Skill 时,必须先用
--dry-run预览操作计划,向用户展示完整内容并获得明确确认后,再去掉--dry-run执行实际操作
常见问题排查
| 问题 | 排查方法 |
|---|---|
| 任务未触发 | 检查 launchctl list | grep <label>,确认已加载;检查 /tmp/<label>-error.log |
| 应用无法启动 | 确认 plist 中应用路径正确;尝试 open -a <App名> 手动测试 |
| 停止任务无效 | 部分应用不支持 AppleScript quit,需 killall <app> 替代 |
| 修改后不生效 | 先 launchctl unload 再 launchctl load 重新加载 |
Version tags
latest
