1. 为什么我要自己动手做一个工作台
1.1 从一次崩溃说起
去年有段时间我同时在跟三个项目,一个是公司的后台管理系统,一个是帮朋友做的数据采集工具,还有一个是自己折腾的自动化脚本集合。每天早上打开电脑的第一件事,就是在一堆窗口和标签页里翻找昨天干到哪儿了。浏览器开了三十多个标签,终端窗口叠了七八层,VS Code 里开着四五个不同的工作区,微信和飞书的未读消息红点永远消不完。
那天下午我正赶一个交付节点,需要把三个项目里的配置参数统一改一遍。结果切来切去,把一个测试环境的数据库地址改到了生产配置里,差点造成事故。虽然最后及时发现没有酿成大错,但那种“脑子不够用”的窒息感让我意识到,问题不在于我记性差,而在于我缺少一个能把所有工作上下文聚合到一起的地方。
市面上确实有类似 workbuddy 这样的工作台产品,理念很好,把任务、笔记、工具集成到一个界面里。但我用下来的感受是,要么功能太重,启动就要等半天;要么数据不在自己手里,总担心哪天服务停了或者涨价了;要么就是扩展性不够,想接一个自己写的脚本都费劲。于是我决定,干脆自己做一个开源版本,核心诉求就三个:轻量、数据自主、可扩展。
这个项目我断断续续写了大概四个月,中间重构了两次,踩了不少坑,也积累了一些心得。这篇文章不是官方文档,也不是什么“从入门到精通”的教程,就是我作为一个普通开发者,把自己造轮子的过程、技术选型的思考、以及实际使用中的经验教训整理出来,给同样有类似需求的朋友一个参考。
1.2 这个工作台到底能干什么
先把这个“魔力工作台”的能力边界说清楚,免得大家抱有不切实际的期待。它不是要替代你的 IDE,也不是要替代你的项目管理软件,它更像是一个个人工作流的调度中枢。
具体来说,它解决的是这几个问题:第一,把散落在不同工具里的任务聚合起来,你可以在一个面板里看到今天要做的所有事情,不管它们来自本地待办、GitHub Issue 还是你随手记的便签;第二,提供一个统一的入口来触发常用操作,比如一键打开某个项目的开发环境、运行测试脚本、部署到测试服务器;第三,通过 Agent 机制让一些重复性的工作自动化,比如每天定时抓取某个数据源、整理日报、检查服务健康状态。
适合谁来用呢?我觉得最适合的是独立开发者、全栈工程师、以及需要同时处理多个项目的技术负责人。如果你每天的工作就是在一个项目里写代码,那用不用这个工作台差别不大。但如果你像我一样,需要在多个上下文之间频繁切换,那这个东西能帮你省下不少脑力。
2. 整体架构与技术选型
2.1 为什么选择 Rust 作为核心语言
技术选型这件事,我纠结了挺久。最开始想用 Node.js 全栈搞定,毕竟生态成熟,开发速度快。但试了一个原型之后发现,工作台这类工具需要常驻后台,对内存占用和启动速度比较敏感。Node 的运行时开销在长时间运行后不太理想,而且打包分发也是个麻烦事。
后来考虑过 Go,编译快、部署简单、并发模型也适合这种场景。但最终让我转向 Rust 的原因有两个:一是性能的可预测性,Rust 没有 GC,在处理大量文件监听和进程管理时,延迟表现更稳定;二是类型系统带来的安全感,工作台要调用各种外部命令、处理不同格式的数据,Rust 的枚举和模式匹配让状态管理清晰很多,重构的时候不容易改出 bug。
当然,Rust 的学习曲线确实陡。我写这个项目之前已经有两年多的 Rust 使用经验,即便如此,在异步运行时和生命周期标注上还是花了不少时间。如果你对 Rust 不熟,用 Go 或者 TypeScript 也能做出可用的版本,只是长期维护的成本会有所不同。
核心架构上,我采用了前后端分离 + 本地服务的模式。后端是一个 Rust 编写的本地 HTTP 服务,负责文件系统操作、进程管理、数据持久化这些“重活”;前端是一个 Web 界面,用 Tauri 打包成桌面应用。这样设计的好处是,前端可以用 Web 技术快速迭代 UI,后端保持高性能和稳定性,两者通过定义良好的 API 通信。
2.2 Agent 机制的设计思路
Agent 是这个工作台的核心概念,也是我在设计上花心思最多的地方。简单来说,一个 Agent 就是一个可配置的自动化单元,它由三部分组成:触发器、执行器、以及上下文。
触发器决定了 Agent 什么时候运行,我实现了三种类型:定时触发(类似 cron)、事件触发(比如文件变化、Git 提交)、以及手动触发。执行器是 Agent 实际要做的事情,可以是一个 shell 命令、一段脚本、或者调用某个 MCP 服务。上下文则是 Agent 运行时可以访问的数据,比如当前项目路径、环境变量、以及前一步的输出。
为什么要把 Agent 设计成这种“三段式”结构?因为我在实际使用中发现,很多自动化需求的变化点在于“什么时候做”和“做什么”,而“怎么做”往往是固定的。把这三者解耦之后,你可以很方便地复用执行逻辑,只是换一个触发条件。比如我有一个“运行测试”的 Agent,手动触发时用于开发调试,定时触发时用于每日回归,事件触发时用于 Git push 前的检查,执行器完全不用改。
MCP 的集成是后来加的。MCP 本质上是一套标准化的协议,让不同的工具和服务能够互相调用。我在工作台里内置了一个 MCP 客户端,可以把外部 MCP 服务注册成 Agent 的执行器。这样一来,工作台的能力边界就大大扩展了——你可以接 Playwright MCP 做自动化测试,接 IDA MCP 做逆向分析,接各种数据库 MCP 做数据查询。我自己的用法是接了一个文件系统 MCP,让 Agent 能够安全地读写指定目录下的文件,而不用直接暴露 shell 权限。
2.3 数据存储与缓存目录的设计
数据存储这块,我选择了 SQLite 作为主存储,配合文件系统做附件管理。SQLite 的好处是零配置、单文件、事务支持完善,对于个人工作台这种单用户场景完全够用。任务、Agent 配置、执行日志这些结构化数据都存在 SQLite 里,而用户上传的附件、生成的报告这类大文件则放在文件系统的缓存目录下。
缓存目录的位置是可以配置的,默认放在用户主目录下的.magic-workbench文件夹里。为什么要让用户能改这个路径?因为我在实际使用中遇到过两个场景:一是公司电脑的 C 盘空间紧张,需要把缓存放到其他盘;二是用同步盘做多设备同步时,需要把数据目录放到同步文件夹里。配置方式很简单,在设置界面里选一下就行,或者直接改配置文件里的cache_dir字段。
这里有个坑我踩过:缓存目录不要放在网络驱动器上。SQLite 在网络文件系统上的锁机制经常出问题,轻则性能下降,重则数据库损坏。我一开始把缓存放在了 NAS 的挂载目录里,结果同步冲突导致任务数据丢失了一次。后来改成放在本地 SSD,然后用 Git 做配置文件的版本管理,数据安全多了。
3. 核心功能模块的实操解析
3.1 任务面板的聚合逻辑
任务面板是我每天打开工作台第一个看的界面。它的核心逻辑是多源聚合 + 统一视图。目前支持的数据源包括:本地待办(直接在工作台里创建的)、GitHub Issues(通过 API 拉取)、以及 Markdown 文件里的 TODO 标记(通过文件监听解析)。
聚合的策略是这样的:每个数据源有一个适配器,负责把原始数据转换成统一的 Task 格式。Task 格式包含这些字段:标题、描述、状态、优先级、截止时间、来源、以及一个external_id用于回写。适配器是插件式的,你可以自己写一个适配器来接 Jira、Linear 或者任何你有权限访问的任务系统。
我实际用下来,最实用的功能是跨源去重和关联。比如我在 GitHub Issue 里有一个任务,同时在本地待办里也记了一笔,工作台会自动识别它们可能是同一个任务(通过标题相似度和时间窗口判断),然后提示你合并。合并之后,你在任何一个地方更新状态,另一个地方也会同步。
这里有个设计上的取舍:要不要做双向同步?我一开始做了,但很快发现复杂度爆炸。因为不同系统的状态机不一样,GitHub Issue 有 open/closed,本地待办有 todo/doing/done,映射关系很难统一。后来我改成了单向拉取 + 手动回写的模式,工作台只负责展示和聚合,状态的变更还是回到原系统去操作。这样虽然多了一步,但避免了数据不一致的麻烦。
3.2 Agent 的配置与运行
配置一个 Agent 的流程大概是这样的:首先在 Agent 管理界面点击新建,然后选择触发器类型。如果是定时触发,你需要填一个 cron 表达式,我内置了一个可视化的编辑器,不用记那些星号和斜杠。接着配置执行器,可以选择 shell 命令、Python 脚本、或者 MCP 服务调用。最后设置上下文变量,比如工作目录、环境变量、超时时间这些。
我拿一个实际例子来说明。我有一个 Agent 叫“每日站会准备”,它的作用是每天早上九点自动收集昨天到今天的 Git 提交记录,生成一份 Markdown 报告,然后发到我的飞书群里。触发器是 cron 表达式0 9 * * 1-5,表示周一到周五早上九点。执行器是一个 Python 脚本,它调用 Git 命令获取提交日志,然后用模板生成报告。上下文里配置了仓库路径和飞书 Webhook 地址。
运行 Agent 的时候,工作台会启动一个子进程来执行,同时捕获标准输出和标准错误,实时显示在日志面板里。如果执行失败,会根据配置的重试策略决定是否重试。我建议给每个 Agent 设置合理的超时时间,特别是那些会调用外部服务的。我有一次写了一个 Agent 去抓取一个不稳定的 API,没设超时,结果它卡了半个小时,把后面的定时任务都堵住了。
注意:Agent 的执行环境默认是继承工作台进程的环境变量。如果你需要隔离,可以在配置里指定一个干净的环境,或者用容器来跑。我自己的做法是敏感操作都放在容器里,避免误操作影响宿主机。
3.3 MCP 服务的接入与调试
MCP 的接入是我觉得最有意思的部分。MCP 协议本质上定义了一套 JSON-RPC 的调用规范,让客户端可以发现服务端提供了哪些工具(tools),然后调用这些工具。工作台作为 MCP 客户端,可以同时连接多个 MCP 服务端,把它们提供的工具注册成 Agent 可用的执行器。
接入一个 MCP 服务的步骤:首先在设置里添加 MCP 服务端,填写它的启动命令或者连接地址。工作台会尝试连接并获取工具列表。如果连接成功,你就能在 Agent 的执行器选择里看到这些工具了。每个工具都有输入参数的 schema,工作台会根据 schema 自动生成表单,你填好参数就行。
调试 MCP 服务的时候,我遇到过几个典型问题。一个是工具名称冲突,两个不同的 MCP 服务提供了同名的工具,工作台会提示你重命名。另一个是参数类型不匹配,比如 MCP 服务期望一个整数,但表单里填的是字符串,调用就会失败。我的经验是,接入新服务时先用一个简单的测试 Agent 跑一遍,确认参数传递没问题再集成到正式流程里。
Playwright MCP 是我用得最多的一个。它提供了浏览器自动化的能力,可以打开页面、点击元素、截图、提取文本。我用它做了一个“竞品监控”的 Agent,每天定时去几个竞争对手的官网截图,然后对比前一天的变化。这个 Agent 帮我省了不少手动检查的时间。
4. 实际使用中的问题排查与优化
4.1 常见问题速查表
| 问题现象 | 可能原因 | 排查步骤 | 解决方案 |
|---|---|---|---|
| 工作台启动后界面空白 | 前端资源加载失败 | 打开开发者工具看控制台报错 | 检查安装目录是否完整,重新安装 |
| Agent 执行超时 | 外部服务响应慢或死循环 | 查看 Agent 日志的最后几行 | 增加超时时间,或优化脚本逻辑 |
| 任务数据不同步 | 适配器认证过期 | 检查数据源配置里的 Token | 重新授权,更新 Token |
| 缓存目录占用过大 | 日志和附件未清理 | 查看缓存目录各子文件夹大小 | 设置自动清理策略,定期归档 |
| MCP 服务连接失败 | 服务端未启动或端口占用 | 手动运行 MCP 服务端命令 | 检查端口,重启服务 |
| 界面卡顿 | 任务数量过多或渲染性能问题 | 打开性能面板看帧率 | 开启虚拟滚动,分页加载 |
这个表里的问题都是我实际遇到过的,有些还反复出现过好几次。比如“Agent 执行超时”这一条,我一开始总是把超时设得很长,觉得这样保险。后来发现,超时设太长反而掩盖了问题,一个卡住的 Agent 会占用资源,影响其他任务。现在我一般把超时设在预期执行时间的 1.5 倍左右,超时就报警,这样能及时发现异常。
4.2 性能优化的几个关键点
工作台用久了之后,任务和日志数据会越来越多,如果不做优化,界面会明显变卡。我做了几件事来解决这个问题。
第一是数据库索引优化。SQLite 默认只对主键建索引,但我的查询经常按状态、截止时间、来源这些字段过滤。加上复合索引之后,查询速度提升了一个数量级。具体来说,我在tasks表上建了(status, due_date)和(source, external_id)两个复合索引。
第二是前端虚拟滚动。任务列表可能有好几百条,如果全部渲染成 DOM 节点,浏览器会吃不消。我用了虚拟滚动的方案,只渲染可视区域内的任务,滚动时动态替换内容。这样即使有几千条任务,滚动也很流畅。
第三是日志分级存储。Agent 的执行日志如果全部存在 SQLite 里,数据库会膨胀得很快。我的做法是,最近七天的日志存在数据库里方便查询,更早的日志归档到文件系统,按月份分文件夹存放。需要的时候可以手动导入查看。
第四是缓存目录的清理策略。我设置了一个定时 Agent,每周日凌晨清理超过 30 天的临时文件和超过 90 天的归档日志。清理之前会先计算总大小,如果超过阈值就发通知提醒我手动确认。
4.3 数据安全与备份策略
数据安全这块我特别在意,因为工作台里存了我所有的任务和配置,丢了会很麻烦。我的备份策略是三层防护。
第一层是 SQLite 自带的 WAL 模式,保证写入的原子性和持久性。第二层是每日自动备份,工作台每天凌晨会把数据库文件复制一份到备份目录,保留最近 30 天的备份。第三层是异地同步,我用 Git 把配置文件和备份目录同步到一个私有仓库,这样即使本地硬盘坏了,也能从远程恢复。
这里有个细节要注意:备份的时候要先做 checkpoint。SQLite 的 WAL 模式下,数据可能还在 WAL 文件里没写入主数据库文件。直接复制主文件可能拿到不完整的数据。我的做法是备份前先执行PRAGMA wal_checkpoint(TRUNCATE),确保所有数据都落盘了再复制。
另外,配置文件里如果有敏感信息(比如 API Token),我会用环境变量引用,而不是直接写在配置文件里。工作台启动时从环境变量读取,这样配置文件可以安全地提交到 Git 仓库。
5. 扩展与二次开发指南
5.1 如何编写自定义适配器
适配器是用来对接外部数据源的模块。工作台内置了 GitHub、本地文件、以及手动创建三种适配器,但你可能需要对接自己的系统。编写一个适配器其实不难,核心就是实现几个接口方法。
首先,适配器需要提供一个fetch_tasks方法,返回一个 Task 列表。Task 是一个结构体,包含标题、描述、状态等字段。然后,如果需要支持回写,还要实现update_task方法。最后,适配器需要声明它支持哪些配置项,工作台会根据这个声明生成配置表单。
我用一个实际例子来说明。假设你要对接一个内部的工单系统,它的 API 返回 JSON 格式的工单列表。你的适配器需要做的是:调用 API 获取数据,把 JSON 映射成 Task 结构,然后返回。如果工单状态有变化,再实现一个update_task方法去调用 API 更新。
适配器可以用任何语言编写,只要它能作为一个独立的进程运行,并通过标准输入输出或者 HTTP 和工作台通信。我推荐用 Python 或者 Node.js 写适配器,因为处理 JSON 和 HTTP 请求比较方便。Rust 当然也可以,但开发效率会低一些。
5.2 Agent 脚本的编写技巧
Agent 的执行器支持 shell 命令和脚本文件。写 Agent 脚本的时候,有几个技巧能让你的脚本更可靠。
第一,总是处理错误。脚本里每一步操作都要检查返回值,失败了要输出明确的错误信息。工作台会根据退出码判断执行是否成功,非零退出码会被标记为失败。
第二,输出结构化日志。工作台会捕获脚本的标准输出,如果输出是 JSON 格式的,会解析后展示成表格。我习惯在脚本最后输出一个 JSON 对象,包含执行结果和关键指标,这样在日志面板里一目了然。
第三,使用环境变量传递配置。不要把路径、Token 这些硬编码在脚本里,而是通过 Agent 的上下文配置传入。这样同一个脚本可以在不同项目里复用。
第四,控制执行时间。长时间运行的脚本要定期输出进度,避免看起来像卡死了。工作台有超时机制,但主动输出进度能让排查问题更容易。
我写过一个比较复杂的 Agent,它的作用是自动部署一个 Web 应用到测试服务器。脚本流程是:拉取最新代码、运行测试、构建产物、上传到服务器、重启服务、健康检查。每一步都有错误处理和日志输出,整个流程跑下来大概三分钟,失败了会发通知给我。这个 Agent 帮我省了很多手动部署的时间。
5.3 界面定制的可能性
工作台的前端是用 React 写的,理论上你可以修改任何界面元素。但我不建议直接改源码,因为升级的时候会冲突。更好的方式是通过主题系统来定制。
主题系统支持修改颜色、字体、间距这些视觉变量。你可以在设置里切换预设主题,也可以自己写一个主题文件。主题文件是一个 JSON,定义了各种颜色值。我给自己配了一个暗色主题,把背景调成了深灰色,减少长时间盯屏幕的眼睛疲劳。
如果你需要更大幅度的定制,比如增加一个新的页面或者面板,那就需要写一个前端插件。工作台支持加载外部的前端插件,插件是一个独立的 JavaScript 包,通过工作台提供的 API 注册新的路由和组件。这个机制我还在完善中,目前文档比较少,但基本能用。
6. 一些踩坑之后的真心话
6.1 不要过度设计
这个项目我重构了两次,第一次重构就是因为过度设计。一开始我想做一个“万能工作台”,什么功能都想加进去:日历、看板、甘特图、时间追踪、团队协作……结果代码越来越复杂,自己都不想用了。后来我砍掉了百分之七十的功能,只保留最核心的任务聚合和 Agent 自动化,反而变得好用起来。
我的教训是:先解决自己的痛点,再考虑通用性。你不需要做一个适合所有人的产品,只需要做一个让自己每天愿意打开的工具。功能少一点没关系,关键是要稳定、快速、不添乱。
6.2 开源社区的反馈很宝贵
项目开源之后,陆续收到了一些 Issue 和 PR。有些反馈是我完全没想到的,比如有人用它来管理家庭事务,有人用它来监控服务器,还有人用它来做自动化交易。这些使用场景扩展了我对工作台的理解,也让我意识到,一个好的工具应该保持足够的灵活性,让用户能按自己的方式去用。
当然,也有让人头疼的时候。有人提了一个很复杂的需求,我评估之后觉得不适合加进核心功能,建议他用插件实现。他不太理解,觉得我在推卸责任。后来我花时间写了一个插件示例,他才明白扩展机制的价值。这件事让我学到,沟通和文档同样重要,光有好的架构不够,还要让用户知道怎么用。
6.3 后续可以扩展的方向
如果你对这个项目感兴趣,想自己扩展一些功能,我觉得这几个方向比较有价值。
一是移动端适配。目前工作台是桌面应用,但有时候我在外面用手机,也想快速查看任务或者触发一个 Agent。做一个响应式的 Web 版本,或者一个简单的移动端 App,会方便很多。
二是更丰富的 MCP 集成。MCP 生态还在快速发展,越来越多的工具开始支持这个协议。接入更多的 MCP 服务,能让工作台的能力边界不断扩展。我特别期待看到数据库、设计工具、以及 IoT 设备相关的 MCP 服务。
三是智能推荐。基于历史数据,工作台可以学习你的工作习惯,自动推荐任务的优先级排序,或者建议你什么时候该处理哪类任务。这个需要一些机器学习的能力,我还在探索中。
四是团队协作。目前工作台是单用户的,但有些场景下,小团队共享任务和 Agent 配置会很有用。这需要设计一套权限和同步机制,复杂度不低,但需求是真实存在的。
写这个工作台的过程,与其说是在做产品,不如说是在整理自己的工作方式。每一行代码背后,都是我对“如何更高效地工作”这个问题的思考。工具本身不是目的,它只是帮你把精力集中在真正重要的事情上。如果你也在被多任务切换困扰,不妨试试自己动手做一个,哪怕功能很简单,用起来也会比现成的产品更顺手。