Codex + Affinity Personal:让 AI 真正进入可编辑设计工作流
之所以给 Codex 搭配 Affinity 而非 Adobe 旗下 Photoshop、Illustrator、InDesign,核心原因是 Affinity 面向个人用户可直接使用,无需订阅付费;而 PS、AI、ID 均采用订阅制才能合法使用。Codex 环境内无法运行盗版软件,因此选用 Affinity 作为合规平替方案,二者能够完美适配协同工作。
很多 AI 设计工具擅长生成一张看起来不错的图片,但真正进入设计生产流程后,仅有图片通常并不够。设计师还需要可选择的文字、形状和图层,需要修改尺寸、检查画布方向、保留历史版本,并在 Affinity 中继续编辑。

affinity-personal 正是为这类工作设计的:它把 Codex 与本机运行的 Affinity 连接起来,让 Codex 不只是“描述一张图”,而是能够读取 Affinity 的当前状态、执行脚本、生成原生对象、渲染画布并验证结果。
本文记录这个个人插件的架构、功能、使用方法、真实测试结果,以及开发过程中遇到的关键问题。


Q:Codex为什么搭配Affinity,不使用Photoshop、Illustrator、InDesign?
A:主要出于正版合规与使用成本两大核心考量:

Q:Codex为何选用Affinity替代PS、AI、ID?
A:Adobe三款软件需订阅付费,Codex无法运行盗版;Affinity个人版免费使用,迁移上手门槛低,可与Codex无缝兼容,是合规低成本的理想平替。
Q:Codex 已有 Affinity 插件,为何不用?
A:原插件是企业版,个人用户无法安装连接账户使用。

Q:自制 Affinity Personal 插件和插件商店已有的企业版 Affinity 插件,有何不同?
A:原企业插件采用专有许可证,企业扩展源码:许可证明确禁止未经授权的复制、修改和分发。
因此我们已通过 clean-room 方法实现功能等价代理,并增加了企业代理没有提供的诊断、重连、错误规范化和安全元数据,制作了适配本地的 Affinity Personal (个人版)插件。采用 MIT 许可,你可以自由修改。
关键词:Codex搭配Affinity、Codex平替PS、不用Photoshop接入Codex、Affinity替代Illustrator InDesign、Codex禁止盗版软件、Affinity免费版适配Codex
一、它解决了什么问题
传统的 AI 图片生成流程通常是:
这种方式适合灵感草图,却不适合需要持续修改的正式项目。
通过 Affinity 的脚本和 MCP 能力,工作流可以变成:
关键差异在于:最终交付物可以是由 Affinity 原生对象组成的设计,而不只是嵌入文档的一张位图。
AI 用自然语言操纵 Affinity 生成店招可编辑文件的成功流程复盘
AI 操纵 Affinity 生成可编辑店招海报设计流程复盘 v1.0
Windows 本地配置记录:Codex 重启后识别 Affinity MCP
绕过 Claude Desktop!Affinity MCP 直连 WorkBuddy/Cursor 完整配置指南(Windows)
Windows 本地配置记录:把 Affinity by Canva 的 MCP 连接到 Codex
二、整体架构
Affinity 桌面应用在启用 MCP 后,会在本机提供一个 SSE 服务:
http://localhost:6767/sse
affinity-personal 则运行在 Codex 一侧,把 Codex 使用的标准输入输出 MCP 通信转换成本机 SSE 连接:
用户
↓
Codex
↓ stdio MCP
affinity-personal
↓ local SSE
Affinity desktop MCP
↓
Affinity 文档、图层、画布和脚本库
这里需要明确区分两层:
- Affinity 内置 MCP 服务属于 Affinity 桌面应用,负责真正执行设计操作;
- affinity-personal 是个人开发的 Codex 插件,负责连接、能力发现、安全元数据、重连、错误处理和工作流约束。
个人插件不会修改 Affinity 内部服务,也不会绕过 Affinity 的产品许可或用户权限。

三、插件提供的能力
在真实 Affinity 会话中,插件动态发现了 11 个上游工具。
1. 文档脚本
execute_script 可以执行 Affinity JavaScript SDK 脚本。它是创建图层、文字、矢量形状、调整文档和构建设计工具的核心入口。
Affinity SDK 类并不是默认全局变量。正确写法需要显式导入:
const { Document } = require('/document');
const doc = Document.current;
console.log(JSON.stringify({
hasDocument: !!doc,
sessionUuid: doc ? doc.sessionUuid : null
}));
脚本需要使用 console.log() 输出诊断信息。仅仅在代码末尾写 return 并不是可靠的结果通道。

2. 画布与选区渲染
render_spread 会直接从 Affinity 文档渲染完整画布,render_selection 则渲染当前选区。
这两项能力非常重要,因为桌面截图可能受到设置窗口、导出窗口或进度提示遮挡。MCP 渲染得到的是干净的文档内容,更适合作为最终视觉验收依据。
桌面截图仍然有价值,但它主要用于判断:
- 是否有窗口遮挡;
- 当前位于哪个文档标签;
- Affinity 是否处于等待或下载状态;
- 用户界面是否出现异常。
它不能替代干净的画布渲染。
3. SDK 文档
插件可以列出和读取 Affinity 当前提供的 SDK 文档。
每个新的脚本会话都应先读取 preamble。其中包含当前版本的导入规则、参数范围、渲染要求、权限限制和已知实践。个人插件会在每次连接的第一个脚本调用前自动加载 preamble,但自动加载只是安全网,Codex 仍然需要真正阅读内容后再编写脚本。
4. Affinity 脚本库
插件可以:
- 列出本地脚本;
- 读取已有脚本;
- 在用户确认后保存新的可复用脚本。
这意味着一次成功的设计操作可以被整理成 Affinity 中长期使用的工具,而不必每次重新生成。
5. SDK 提示和问题反馈
Affinity 还提供共享提示搜索、添加提示和报告 SDK 问题的能力。
这些工具与纯本地操作不同:
- 搜索共享提示属于联网读取;
- 添加提示和报告问题会向本机以外发送信息。
affinity-personal 会为它们标记明确的联网和写入属性。除非用户明确要求,否则不应自动提交提示或问题报告。
四、个人版增加的能力
个人插件没有简单复制某个固定工具列表,而是每次连接时从 Affinity 动态读取当前能力。这样 Affinity 更新工具后,插件不需要依赖过期的硬编码清单。
此外,它还增加了两个本地工具。
affinity_personal_status
用于检查:
- 当前连接地址;
- 是否成功连接;
- 连接建立时间;
- SDK preamble 是否已加载;
- 重连次数;
- 已转发调用次数;
- Affinity 当前暴露的工具清单。
affinity_personal_reconnect
当 Affinity 重启、MCP 被重新启用或连接失效时,可以主动释放旧连接并重新发现工具。
代理还会在普通调用失败后进行一次受控的自动重连,避免短暂断线直接导致整个任务失败。
五、最重要的改进:不能把“执行过”当作“完成了”
插件测试中出现过一个很典型的问题:用户要求 600 × 240 px 的横版海报,任务报告也声称已经创建横版画布,但 Affinity 中实际显示的文档是竖版。
这说明脚本虽然运行了,但任务没有验证真实结果。
现在,尺寸和方向会被视为硬性验收条件:
横版:actualWidth > actualHeight
竖版:actualHeight > actualWidth
方形:actualWidth == actualHeight
对于 600 × 240 px 横版,最低验收条件是:
actualWidth == 600
actualHeight == 240
actualWidth > actualHeight
正确流程是:
如果文字写着“横版”,但给出的尺寸却是高度大于宽度,插件工作流应先请用户确认,而不是自行猜测。
六、错误处理为什么需要增强
真实审计中还发现,Affinity 上游有时会返回类似下面的内容:
ReferenceError: Document is not defined
但 MCP 结果未必会同时设置 isError: true。如果代理只检查状态字段,Codex 就可能把失败脚本当成成功结果继续执行。
个人版会识别以下失败信号:
- ReferenceError
- TypeError
- SyntaxError
- RangeError
- 普通 Error:
- NOT_ALLOWED
当这些内容出现在脚本响应中时,代理会把结果规范化为真正的 MCP 错误。
NOT_ALLOWED 通常意味着 Affinity 设置限制了文件、网络或 AI 权限。遇到这种情况应尊重权限配置,而不是尝试绕过。
七、安全元数据
个人插件为工具补充了明确的行为分类。
只读本地操作包括:
- 读取 SDK 文档;
- 列出和读取本地脚本;
- 渲染画布;
- 渲染选区;
- 查询连接状态。
可能修改文档或本地状态的操作包括:
- 执行任意 Affinity 脚本;
- 保存脚本到 Affinity 脚本库。
涉及外部系统的操作包括:
- 搜索共享 SDK 提示;
- 添加共享提示;
- 报告 SDK 问题。
这种分类可以帮助 Codex 更准确地决定何时需要用户确认。
八、安装与使用
插件源码目录为:
C:\\Users\\love\\plugins\\affinity-personal
个人市场配置为:
C:\\Users\\love\\.agents\\plugins\\marketplace.json
首次使用前:
可以先使用以下指令检查连接:
@<插件> 使用 Affinity Personal 检查当前 MCP 状态,列出实时工具,但不要修改文档。
或者直接在对话框中 @ 插件名 + 指令内容测试:
@affinity-personal 检查当前 MCP 状态,列出实时工具,但不要修改文档。

测试设计任务可以写成:
在 Affinity 中创建一张 600 × 240 px 的横版海报。
横版和尺寸是硬性约束。
创建后读取实际画布尺寸并验证宽度大于高度;不符合就修正。
使用 render_spread 渲染完整画布,确认内容无遮挡后再报告完成。
除非我明确确认,不要覆盖已有文件。
九、如何迭代插件
更新插件时,不应直接修改个人市场配置来制造刷新。正确流程是:
核心测试命令对应的文件包括:
scripts/affinity-personal.mjs
scripts/smoke-test.mjs
scripts/capability-audit.mjs
skills/affinity-personal/SKILL.md
能力审计应至少覆盖:
- 连接;
- 工具发现;
- preamble;
- SDK 文档;
- 脚本库读取;
- 只读脚本执行;
- 文档会话 UUID;
- 完整画布渲染;
- 选区渲染;
- 主动重连;
- 脚本错误规范化;
- 插件与技能清单验证。
不要为了测试而随意提交 SDK 问题、上传共享提示、覆盖用户文档或往脚本库写入垃圾脚本。确认工具结构与实际执行写入操作是两件不同的事。
十、源码和许可边界
affinity-personal 是独立编写的通用 MCP 代理,使用 MIT 许可,可以自由阅读、修改和继续开发。
它不包含 Canva 企业扩展的专有源码、图标、身份信息或凭据,也不尝试绕过 Affinity 的许可和权限。实现功能等价的正确方法,是观察公开可见的工具行为和协议,然后独立编写代码并进行真实测试,而不是复制受限制的实现。
十一、真实测试结果
截至 2026 年 7 月 13 日,实机审计结果如下:
| 本机 MCP 连接 | 通过 |
| 动态发现 11 个 Affinity 工具 | 通过 |
| 读取 SDK preamble | 通过 |
| 列出 SDK 文档 | 通过 |
| 列出本地脚本库 | 通过 |
| 使用显式 /document 导入执行只读脚本 | 通过 |
| 获取当前文档会话 UUID | 通过 |
| 渲染完整画布 JPEG | 通过 |
| 渲染选区 JPEG | 通过 |
| 主动断线重连 | 通过 |
| 将脚本异常规范化为 MCP 错误 | 通过 |
| Codex 插件验证 | 通过 |
| Codex 技能验证 | 通过 |
这套插件目前已经不只是“让 Codex 连上 Affinity”的桥接器,而是一层面向真实设计工作的控制和验收系统:它知道怎样连接、怎样读取当前 SDK、怎样识别失败、怎样验证画布,以及什么时候不能擅自写入或向外发送信息。
对于需要可编辑图层、持续迭代、真实尺寸和可验证交付的设计任务,这比单纯生成一张图片更接近完整的生产工作流。

