
前阵子在回家路上我盯着手机里那条“明天上线前记得把登录接口补上”的消息忽然意识到一个挺反直觉的事实代码其实不用我坐在电脑前写。我们天天讨论 AI 编程、Cursor、Agent可大部分人还是把 AI 当了个高级补全工具——打开编辑器光标停在哪它补到哪。但 Cursor 真正值钱的地方是它能把一个完整的任务接过去自己干。那如果这条任务不是我在电脑前敲进去的而是我躺在通勤路上用手机发出去的呢这篇文章就是把我实际搭起来的一套“手机发消息 → 电脑上 Cursor 自动写代码”的链路完整拆给你看包括它到底解决了什么问题、每一步怎么落地、踩了哪些坑、以及安全底线设在哪里。1. “手机消息驱动写代码”这个玩法解决的到底是什么问题1.1 不是炫技是碎片时间复用先说个真实场景。那天我在外面客户临时提了个需求首页的活动倒计时要在今晚 12 点准点切换。这个改动其实不复杂无非是判断一下当前时间把活动状态从“进行中”翻到“已结束”。但问题是我手头没带电脑等回到家再改虽然也来得及但那一整晚的休息时间就没了。这时候我想起 Cursor 的 Agent 模式。它不像普通补全那样只读光标附近的上下文而是能自己打开文件、跨文件搜索、改完代码再跑一遍测试。既然它能替我在电脑上“执行任务”那我缺的就只是一个把“任务描述”从手机送到电脑上的通道。于是链路就变成了我在手机上写清楚“改哪个文件、改成什么逻辑、怎么验证”发给一个中转通道电脑上一个常驻脚本收到消息后把它变成一个任务文件Cursor 的 Agent 读到这个任务文件开始干活干完再通过同一套通道发回执到我手机。这套玩法的本质是把“写代码”这件事从“坐在电脑前手工驱动”变成“发任务给 Agent 执行”。它节省的不是那几分钟打字时间而是你从“想到需求”到“能开始动手”之间的整个转移成本。碎片时间、远程救急、多个项目同时维护的时候这种复用价值非常明显。1.2 这条链路到底适不适合你先说结论不是所有人都需要这套东西但它适合下面这几类人。第一类是远程救急型。代码不在手边但服务器上的问题不等人。比如业务报了个错日志已经导出来了你只需要让 Agent 按日志去查根因、改代码、补测试。第二类是批量任务型。你手里有十几个小的模板化改动比如给所有接口统一加参数校验、给一堆组件换主题变量。这种活一个个手动做很烦但打包发给 Agent 排队执行反而高效。第三类是定时巡检型。你想让电脑在每天凌晨自动跑一轮代码检查把报告发到你手机第二天起床直接看结果。不适合的人也很明显如果你写代码靠的是手感和对上下文极其精细的掌控或者你的项目有大量无法自动验证的隐式逻辑那远程喂任务给 Agent 只会让你更焦虑。初次尝试的人我建议先从一个“只加日志不改逻辑”的简单任务开始等你对它的输出风格有了把握再逐步放大权限。1.3 说清楚边界自动写代码不是无人值守我必须先把一个容易误会的点讲明白这套链路不是把 Cursor 变成什么“无人值守的永久 Agent”不是你在手机上下个命令它就能无限循环地自己改代码、自己部署、自己上线。我搭的这套方案本质上是一个“任务管道 单次 Agent 会话”的组合。你发一条消息过去电脑上的脚本收到后生成任务文件再通过自动化手段唤起一次 Cursor Agent 会话让它在这次会话里专注处理这个任务。处理完会话就结束。下次再来新任务再唤起一次。这样做的好处是职责清晰、出错可追溯不会出现 Agent 自己脑补出一堆后续任务、把仓库改得面目全非的情况。记住这个边界很重要因为只有当你承认“它不是全自动的”你才愿意去设计好每一环的确认点和安全阀而不是天真地一键把整个项目交给一个脑回路偶尔飘逸的模型。2. 把整条链路拆开每一层都负责什么2.1 四段式链路的核心职责整套系统我拆成五段手机端指令输入、转发层消息中转、任务管道指令落地成文件、执行端Cursor Agent、回执通道结果通知手机。手机端没什么好说的你只需要一个能发邮件或者能调用 Webhook 的应用。转发层是消息进入到电脑的入口。我选了邮件 IMAP 拉取也有朋友用企业微信群机器人。任务管道是整条链路里最关键的一段它负责把邮件内容转成结构化的任务文件放到一个 Cursor Agent 固定监视的目录里。执行端负责真正读任务、改代码、跑验证。回执通道负责把执行结果压缩成一条简短消息发回手机。这五段里真正跑代码的只有 Cursor 那一段其余四段做的都是“消息的搬运和结构化”。所以这套系统并不需要很强的服务器资源一台普通电脑挂着就行接收脚本极其轻量真正消耗电力和算力的是 Cursor 背后的大模型推理。2.2 为什么我选“手机邮件IMAP”而不是直接读微信记录你可能第一反应是既然标题说“手机发一条消息”那我直接微信发消息到文件传输助手电脑端读聊天记录不就行了我一开始也是这么想的后来放弃了。原因有三一是微信电脑端聊天记录数据库是加密存储的程序化读取既不稳定也容易碰到底层数据结构的兼容问题二是我并不想为了一个自动化脚本去碰个人社交软件的本地数据这涉及隐私边界三是微信消息是“即时推送”语义缺少一个天然的“任务持久化”环节你发过去的消息一不小心就淹没在聊天流里了脚本很难判断哪条是任务、哪条是闲扯。邮件就没有这些问题。手机邮件客户端是独立存在的IMAP 协议是标准协议邮件天然带主题、发件人、时间、正文这种结构化信息。最关键的是邮件可以长期保存脚本漏处理了一条还能回来补不用像即时消息那样时刻盯着。所以我最终的转发层用的是 QQ 邮箱的 IMAP 服务手机发邮件电脑上脚本定时拉取未读邮件。2.3 任务消息的格式约定就是你和 Agent 之间的合同远程喂任务最大的不确定性是 Agent 能不能准确理解你的意图。如果不做任何格式约束你发“帮我看下登录的问题”Agent 可能要猜半天是哪个文件、什么问题、怎么算解决。所以我在邮件正文里定义了一套非常简单的“任务合同”。格式大概是项目market-web 目标文件src/api/user.ts, src/pages/login.tsx 任务描述为登录接口补充错误码处理当返回 1002 时提示“账号已锁定”并在页面停留 3 秒后跳转找回密码页 验证方式运行 npm run test:login保证新增用例通过 约束不要改动任何后端代码这里每个字段都不是拍脑袋定的。项目字段决定 Cursor 打开哪个工作区目标文件字段能大幅减少 Agent 的全局搜索范围任务描述要写成“在什么条件下做什么改动期望什么结果”验证方式是安全底线没有它Agent 很容易改完就跑到底对没对只有它自己知道约束字段相当于给 Agent 上了护栏防止它顺手把不相干的文件也改了。这个格式看起来简单但它把所有歧义压缩到最低。同一套格式你既可以让 Claude 写也可以让 ChatGPT 写关键是 Agent 的执行协议稳定它每次看到这种格式的任务文件就知道该按刚才那套规则来。2.4 三种中间层方案对比邮件、机器人、HTTP接口我做这套系统的时候中间层一共试过三种邮件、企业微信群机器人、自建 HTTP 接口。这里直接把它们的差异列出来。方案上手难度是否需要公网回执能力适用场景邮箱 IMAP 轮询低不需要强可发邮件回执个人使用最稳企业微信/钉钉机器人中需要内网穿透或部署在公网强可直接机器人回复团队协作多人发任务自建 HTTP API 脚本高需要取决于实现想深度集成 CI/CD 的场景我自己日常用的是第一种原因很直接它不要求电脑有公网 IP不需要在内网穿透工具上折腾只需要一个能收信的邮箱。如果你是想让整个团队都能往这台机器发任务那就用第二种群机器人在消息里带出任务编号和项目名脚本收到后同样转成任务文件。第三种适合已经有一套自动化平台的团队不推荐个人玩家一开始就上。3. 执行端才是主角把 Cursor 调教成能看懂手机任务的 Agent3.1 Cursor 到底哪来的“代理”能力很多人用 Cursor 还是停留在“对着一段代码问问题”的阶段这确实浪费了它一半的功力。简单说Coder 现在的 Agent 模式不再只是分析你选中的那几句代码而是可以执行“多步操作链”它自己决定先打开哪个文件、读取哪些相关模块、修改哪里、再运行什么命令去验证。这背后依赖的是长上下文能力和工具调用机制模型可以把一个复杂任务拆解成若干子步骤并逐步验证。这和“发一条消息让 Cursor 写代码”有什么关系关系很大。因为只有当 Cursor 具备“独立完成多步操作”的能力你才可能把一个相对完整的任务文本丢给它而不是一句一句去引导。否则所谓远程写代码就变成了远程打一个字、等完成、再打一个字完全没有效率可言。3.2 中文使用这件事要拆成三个层面处理“cursor 怎么设置中文”在搜索热词里出现频率很高但很多人把这件事想成一键切换语言包。实际上 Cursor 的“中文”要分三个层面看。第一层是界面文字。Cursor 本质上是基于 VS Code 的界面语言跟随编辑器设置。比较直接的方法是安装中文语言包扩展然后把显示语言切换为简体中文。这一步解决的是菜单、按钮、右键选项这些界面文字的中文化。第二层是 AI 回复语言。这一步和界面语言无关是在 Cursor 的设置里找 AI 相关的 Rules 或者自定义指令显式加上一句“Always reply in Simplified Chinese”。不写这个模型默认会根据提问语言切换但你远程发过去的任务可能是中英混合的回复也可能中英夹杂所以最好写死规则。第三层是代码注释和提交信息。这个很多人容易忽略。你希望 AI 生成的注释、commit message 也用中文就要在规则里单独说明。注意代码注释的语言和代码本身的规范没有关系但团队协作时最好统一。我的做法是在 Cursor 的全局规则里写三句All UI response text must be in Simplified Chinese. Code comments and commit messages should be in Chinese unless the target file already uses English. DO NOT translate identifier names, variable names, or API names.最后一句尤其重要否则模型可能把变量名也顺手翻译了整个项目直接崩。3.3 Rules 文件里必须写清楚的五件事要让 Cursor 在接收到手机转来的任务文件后不乱来光靠一个任务格式还不够你需要在 Rules 文件里约定好执行协议。我的 Rules 里固定了五件事第一任务入口怎么识别。我约定任务文件统一放在D:\cursor_tasks目录下以.new后缀作为“待处理”标记。Agent 每次会话启动时第一件事是去这个目录找最新的.new文件。第二一个会话只处理一个任务。处理完之前不得主动扩展任务范围。这个约束避免了 Agent 在改登录接口的时候顺手把注册接口也重构了。第三步骤必须是可回滚的。修改代码前先用 Git 创建分支或者本地提交点改动结束后能通过 diff 快速查看变更。第四必须自证完成。任务文件要求“运行某条验证命令”Agent 必须真的跑完命令把输出关键结果写进回执而不是说一句“应该没问题了”。第五处理完要留下痕迹。执行完毕后在任务文件旁边生成DONE_任务名.md里面写清改动了哪些文件、验证结果、还有哪些遗留风险。这五条不是锦上添花是远程无人值守场景下的底线。没有它们你第二天醒来看到的是一个“任务已修复”的消息但代码仓库已经变成一团谁都看不懂的乱麻。3.4 两种会话启动方式自动唤醒和半自动确认Cursor 的 Agent 模式并不会 24 小时挂在一个进程里等你喂新任务。所以任务文件落地后怎么让 Cursor 真正“睁开眼”看它就成了工程实现上最有意思的一环。我见过两种做法。第一种是“GUI 自动化唤醒”用一个本地自动化脚本模拟快捷键检测到新任务文件后自动切到 Cursor 窗口新建一个 Composer 或 Agent 会话把一段标准提示词粘贴进去按下回车。Cursor 就开始读任务、干活。这条路最稳因为本质上是模拟你自己在电脑前操作兼容性最强缺点是机器上必须跑一个自动化辅助程序。第二种是“半自动确认”不模拟键盘鼠标而是让 Cursor 的 Agent 会话预先进入一个“持续监听”状态——但其实一次会话没法真正挂机循环所以更实用的做法是当你回到电脑前手动在 Cursor 里新建会话然后 Agent 按 Rules 自动读取最新任务文件。这种方式适合对“全自动”需求没那么强的人至少任务从手机端传送和落盘是全自动的只有最后一步需要你回到电脑前按一下“接受”。我个人的建议是如果你第一次搭先做第二种。跑一个月、确认 Agent 的输出可信度足够高之后再升级成第一种全自动唤醒。千万别一开始就把机器调成全自动否则模型犯一次错你可能得花半天收拾残局。4. 手把手搭一套可落地的消息管道4.1 目录结构与权限准备我实际在电脑上用的目录结构是这样的D:\cursor_tasks\ ├─ inbox\ # 新任务文件带 .new 后缀 ├─ running\ # 正在处理中的任务 ├─ done\ # 已完成任务及 DONE 回执 └─ logs\ # 所有动作的日志inbox 目录就是手机消息落盘的地方。脚本每收到一封新邮件就按任务格式生成inbox\task_20240218_2105_001.md.new。Cursor Agent 处理时会把任务文件移动到 running 目录防止重复处理。处理完在 done 目录生成DONE_xxx.md并把.new标记删除。这套目录设计的核心是“状态可见”。任何一个时间点你都能看到有多少任务在排队、哪个正在跑、哪个已完成。远程场景下你没法随时打开电脑看只能靠这种文件状态来推断执行进度。关于权限有一个容易被忽略的细节负责收发邮件的 Python 脚本平时应该以最小权限运行不需要管理员权限也不需要访问系统目录。它只需要对cursor_tasks目录有读写权限即可。避免脚本被异常邮件内容攻击时导致更严重的系统级问题。4.2 邮件接收脚本骨架这一段是整套系统的核心代码。我用的 Python imaplib没有引入任何重量级依赖一个标准的 Python 3.10 环境就能跑。下面是骨架代码import imaplib import email import os import time import re from email.header import decode_header from email.utils import parsedate_to_datetime IMAP_HOST imap.qq.com IMAP_PORT 993 USERNAME your_accountqq.com PASSWORD your_smtp_auth_code # QQ邮箱里的授权码不是登录密码 TASK_ROOT rD:\cursor_tasks INBOX_DIR os.path.join(TASK_ROOT, inbox) SAFE_SUBJECT_PATTERN re.compile(r[\w\u4e00-\u9fff\-]) def decode_mime_header(value): if not value: return parts decode_header(value) result [] for content, charset in parts: if isinstance(content, bytes): result.append(content.decode(charset or utf-8, errorsignore)) else: result.append(content) return .join(result) def parse_email_body(raw_body): # 简单处理只取纯文本部分 if raw_body.is_multipart(): for part in raw_body.walk(): if part.get_content_type() text/plain: payload part.get_payload(decodeTrue) charset part.get_content_charset() or utf-8 return payload.decode(charset, errorsignore) return else: payload raw_body.get_payload(decodeTrue) return payload.decode(utf-8, errorsignore) if payload else def fetch_unseen_messages(): conn imaplib.IMAP4_SSL(IMAP_HOST, IMAP_PORT) conn.login(USERNAME, PASSWORD) conn.select(INBOX) status, msg_nums conn.search(None, UNSEEN) tasks [] if status ! OK: conn.logout() return tasks for num in msg_nums[0].split(): status, msg_data conn.fetch(num, (RFC822)) if status ! OK: continue raw_email email.message_from_bytes(msg_data[0][1]) subject decode_mime_header(raw_email.get(Subject)) sender decode_mime_header(raw_email.get(From)) body parse_email_body(raw_email) # 只有发件人匹配才处理白名单机制 if your_phone_emailexample.com not in sender: conn.store(num, FLAGS, \\Seen) continue tasks.append({ subject: subject, body: body, date: parsedate_to_datetime(raw_email.get(Date)), }) conn.store(num, FLAGS, \\Seen) conn.logout() return tasks def save_task_to_inbox(task): safe_subject SAFE_SUBJECT_PATTERN.sub(_, task[subject])[:40] timestamp time.strftime(%Y%m%d_%H%M%S) filename ftask_{timestamp}_{safe_subject}.md.new filepath os.path.join(INBOX_DIR, filename) with open(filepath, w, encodingutf-8) as f: f.write(f# 任务文件\n\n) f.write(f- 来源: {task[date]}\n\n) f.write(f## 任务描述\n\n{task[body]}\n) with open(os.path.join(TASK_ROOT, logs, receive.log), a, encodingutf-8) as log: log.write(f[{time.strftime(%Y-%m-%d %H:%M:%S)}] {filename}\n) def main_loop(): while True: try: tasks fetch_unseen_messages() for task in tasks: save_task_to_inbox(task) except Exception as exc: with open(os.path.join(TASK_ROOT, logs, error.log), a, encodingutf-8) as log: log.write(f[{time.strftime(%Y-%m-%d %H:%M:%S)}] {exc}\n) time.sleep(60) if __name__ __main__: os.makedirs(INBOX_DIR, exist_okTrue) os.makedirs(os.path.join(TASK_ROOT, logs), exist_okTrue) main_loop()这个脚本里有几个细节值得解释。一个是发件人白名单脚本里显式判断了发件人必须是your_phone_emailexample.com防止任何陌生邮件成了 Cursor 的执行指令。另一个是授权码的使用QQ 邮箱的 IMAP 登录不能用原始密码必须去邮箱设置里生成授权码。最后是日志所有收到的任务都会记录后面排查问题时非常有用。要注意这只是一个演示骨架生产环境里还需要加上任务去重、异常重试等逻辑。比如同一封邮件被 IMAP 重复拉取时你用 Message-ID 或者邮件时间戳做幂等判断避免生成两个一模一样的任务文件。4.3 自动化唤醒器示例说完了邮件接收接下来是让 Cursor 动起来的那一环。我已经说了两种方式这里给一个最实用的“GUI 自动化唤醒”示例。Windows 上用 AutoHotkey 是最轻量的方案一个脚本就能搞定。#Persistent SetTimer, CheckForNewTask, 5000 return CheckForNewTask: ; 检测 inbox 目录下是否存在 .new 文件 FoundTask : false Loop, Files, D:\cursor_tasks\inbox\*.md.new { FoundTask : true Global NewTaskFile : A_LoopFileFullPath break } if (FoundTask) { ; 激活 Cursor 窗口 WinActivate, ahk_exe Cursor.exe WinWaitActive, ahk_exe Cursor.exe, , 5 ; 新建 Agent 会话的快捷键根据你本机 Cursor 版本调整 Send, ^l Sleep, 800 ; 粘贴标准提示词 SendInput, {Text}请读取 D:\cursor_tasks\inbox 下最新的 .md.new 文件按照文件中的任务描述开始工作。工作前先检查项目路径是否存在所有改动必须创建 git 分支工作完成后删除 .new 后缀并在 done 目录生成 DONE 文件。 Sleep, 300 Send, {Enter} Sleep, 1000 } return这段脚本的逻辑很直白每 5 秒扫一次 inbox 目录发现新任务就激活 Cursor、唤出 Agent 会话、粘贴提示词、回车执行。有几个坑我必须提醒你。第一个坑是快捷键不是固定的。不同版本的 Cursor 唤出 Agent 会话的快捷键可能不一样有的版本用CtrlL有的版本还要先CtrlI打开 Composer。你在跑这个脚本之前先手动测清楚自己版本的实际快捷键。第二个坑是自动粘贴中文的问题。AutoHotkey 的SendInput {Text}对中文支持还不错但如果你的系统语言环境特殊建议把那段标准提示词写在一个文本文件里脚本用FileRead读出来再粘贴更稳定。第三个坑是最隐蔽的WinActivate 到 WinWaitActive 之间如果 Cursor 窗口最小化了激活可能失败。我建议给脚本加一层兜底激活失败时把任务留在 inbox 里下次循环再试而不是继续往下走。这样最多延迟 5 秒但不会误触发。4.4 结果回传让手机收到一封“干完了”的邮件任务执行完如果你的手机没有收到任何消息那这套“远程发任务”的体验就少了一半。Cursor 完成任务后按 Rules 约定会在 done 目录生成一个DONE_任务名.md文件。这个文件里写了改动摘要、验证结果、遗留风险。但要让它真正通知到你手机还需要在 Python 脚本里加一个“回执发送”函数。我一般用 smtplib 发一封简洁的邮件回执到手机邮箱标题叫[Cursor Task Done] 登录接口错误码处理完成正文就是 DONE 文件的内容。这样手机的消息推送就能直接弹出任务完成通知。import smtplib from email.mime.text import MIMEText from email.header import Header SMTP_HOST smtp.qq.com SMTP_PORT 465 SMTP_USERNAME your_accountqq.com SMTP_PASSWORD your_smtp_auth_code def send_done_email(subject, content, to_addryour_phone_emailexample.com): msg MIMEText(content, plain, utf-8) msg[Subject] Header(subject, utf-8) msg[From] SMTP_USERNAME msg[To] to_addr with smtplib.SMTP_SSL(SMTP_HOST, SMTP_PORT) as server: server.login(SMTP_USERNAME, SMTP_PASSWORD) server.sendmail(SMTP_USERNAME, [to_addr], msg.as_string())这个函数的核心是“把完成状态显性化”。你看到的不只是一句“干完了”而是改了什么文件、跑了什么测试、测试过了没有。后续你可以把回执内容升级成包含 diff 统计、测试覆盖率变化等更丰富的信息但对第一版来说有一封“干完邮件”已经足够形成闭环了。5. 升级玩法定时、队列、多项目并行5.1 定时任务让电脑在凌晨自动跑一轮巡检前端消息通道跑通之后我很快发现一个更香的用法定时任务。既然 Cursor 可以接收来自文件系统的任务那我为什么不让脚本在固定时间自动生成任务把它丢进 inbox 呢我举一个实际例子。我参与维护的一个项目里接口返回的数据结构偶尔会被前端字段名不一致的问题破坏。以前是等用户反馈后来我让电脑每天晚上 2 点自动生成一个任务文件内容是“跑一遍所有接口的 schema 校验脚本把失败项整理成报告”。Cursor 凌晨收到任务后开始干活4 点左右把报告发到我邮箱。第二天早上我在地铁上就能先看报告到工位直接改问题。这个玩法本质上把“手机发消息”变成了“定时器发消息”。对个人开发者来说它能让你睡一觉起来就拿到一份代码巡检报告对团队来说它相当于一个轻量级的夜间 CI。5.2 任务队列一次性丢五个需求排队执行邮件脚本本身处理的是单任务模式但我把任务文件设计成.md.new后缀之后天然就支持队列了。你在手机上一次发五封邮件或者一封邮件里写清楚五个子任务脚本会把它们生成五个.new文件。Cursor 那边的 Rules 我写了一条每次会话只处理 inbox 目录里时间最早的一个.new文件处理完删除.new后缀回到队列外然后会话自动结束。这时候自动化唤醒器会再次检测到 inbox 里还有新的.new于是再唤起一次会话处理下一个。这么做的效果是五个任务会按顺序一个一个执行不会出现一个巨型会话把五个任务全塞进上下文的混乱局面。队列模式的好处是每个任务都有独立的上下文窗口模型不会因为上下文太长而“忘记”前面的任务要点。代价是每个任务之间有一点会话重启开销但对绝大多数代码任务来说这个开销可以忽略。5.3 多项目隔离不同收件目录路由到不同代码仓库第二个让我眼前一亮的升级是“多项目路由”。一开始我只有一个 Cursor 工作区所有任务都在同一个项目里跑。后来我有两个项目要同时维护总不能两个项目混在一起让 Agent 找错目录。我的做法是给脚本增加了一个简单的路由规则根据邮件主题里的项目标记把任务文件放到不同的子目录比如inbox\market-web\、inbox\admin-api\。每个 Cursor 工作区只打开对应的项目目录Rules 里也分别声明“只允许读取本工作区内的文件”。这个升级还有一个附带好处不同项目可以配置不同的验证命令和代码规范。比如前端项目跑npm run lint后端项目跑pytest互不干扰。你不需要在任务描述里每次都写一遍这些约定路由到对应目录后Cursor 自动加载对应的 Rules 文件即可。5.4 一次真实任务的完整回放讲到这里我放一个我实际跑通过的任务回放这样你会有更直观的感觉。那天晚上我在外面手机收到服务器告警某个接口在 19:00 之后返回 500 的概率明显上升。我先看了一眼错误日志片段确认是指针空引用。于是我用手机发了封邮件主题是[bugfix] order-service 空指针排查正文按照任务格式写了目标文件、错误堆栈、验证方式。半个小时后我打开邮件收到了 Cursor 的回执。它先定位到OrderServiceImpl.java第 178 行附近发现订单状态为“已取消”时deliveryAddress字段为 null后续代码没有做空判断。它新建了分支fix/null-pointer-on-cancelled-order加上了空值保护并把相关单元测试补全mvn test跑完 37 个用例全部通过。整个过程大概 20 分钟。那个晚上我唯一做的事就是在手机上发了一封邮件以及后来在电脑上 review 了一下 diff。这个回放想说明的是这套系统真正节约的不是“机器帮你写代码”的那段时间而是“你不用为了一个 500 错误专门跑到电脑前”的那段路程和时间。任务本身可能只值 20 分钟但没有了来回奔波你省下的可能是一整个晚上。6. 把“远程触发”权限交给 AI 之前先想清楚安全底线6.1 这个链路真正暴露的攻击面聊完了玩法必须泼一盆冷水。任何“远程触发本地执行”的系统本质上都是在本地机器上开了一扇门。你的门后面坐着一个能改文件、能跑命令的 Agent这比你平时手动执行命令的风险面大得多。攻击面主要来自三处。第一处是消息通道本身如果邮件发件人白名单校验不够严格任何知道你这个邮箱地址的人都可以往里面塞任务第二处是任务文件解析邮件正文被解析成任务文件时如果脚本没有做好过滤恶意内容可能通过路径穿越、命令注入等方式影响后续流程第三处是 Agent 的自主性模型可能被恶意任务诱导去操作非预期文件或者在理解偏差下执行破坏性命令。我见过很多人搭这类系统时只关注“能不能跑通”完全不关注“哪些情况下它会暴走”。这不是模型能力问题而是工程问题。6.2 哪些指令设计上就应该被拦截有些事不管任务文件写得多么像模像样都不应该被远程自动执行。我给自己立了几条铁律。第一不准删除目录。像“把旧版本目录整个删掉”这种操作哪怕是任务合理我也要求 Agent 只做“移动到 backup 目录”而不是rm -rf。第二不自动合并到主干。所有远程任务的改动都停留在独立分支合并操作只能由我在电脑前手动完成。第三不自动安装依赖。能让 Agent 改代码但它装了什么依赖、改了哪些 lockfile必须最终由我 review。第四不碰生产环境。涉及线上数据库、生产环境的任何操作即使只是执行一条查询也一律排除在远程任务范围外。这些拦截既可以通过 Rules 文件告诉 Cursor也可以在自动化唤醒器的标准提示词里再次强调。双保险比单保险可靠。6.3 六条可落地的安全防护措施具体的落地措施我按优先级排了个清单。发件人白名单。脚本只信任你预先声明的发件邮箱这是第一道闸门。任务令牌。在邮件正文里加一个自定义令牌字段脚本解析到令牌才生成任务文件进一步降低被伪造邮件的风险。独立工作区。为远程任务准备一个独立的项目副本或者独立 git 分支绝不直接在主目录上让 Agent 乱改。命令白名单。在 Rules 里声明哪些命令允许 Agent 执行比如npm test、pytest、git diff禁止rm、curl | sh、sudo这类高危命令。日志审计。所有收到邮件、生成任务、启动 Agent、完成回执都要有日志方便事后排查。人工确认开关。这是最重要的一条在自动化链路里保留一个状态默认情况下 Agent 改完之后不自动合并、不自动推送必须有你手动批准。这套组合下来即使某一个环节被攻破攻击者也很难造成真正不可逆的破坏。6.4 人工确认开关全自动不是唯一目标最后聊一个理念问题。很多人搭这种系统时会陷入一个误区追求全链路无人值守手机发完消息就彻底不管了。我搭完第一版也这么想后来发现全自动并不是最好的方案。我在邮件回执链路里加了一个强制确认步骤任务完成后Cursor 在本地生成一份PENDING_REVIEW.md里面包含了改动文件列表、关键 diff、测试输出。只有我点击“确认”后后台脚本才会把这个分支推送到远端或合并到主分支。这个开关看似多了一步操作但它换来的是你永远有机会在灾难发生前把它拦住。用了一年多这套系统我最深的体会是手机消息驱动的 Cursor它的价值不在于“AI 完全替我写代码”而在于“它让我对零散时间的利用效率高了一个量级”。但所有自动化都有一个前提就是你能控制它什么时候停。所以我的建议始终是链路尽量自动化决策尽量留给人。