Arslan Docs 基于 v0.1.63中文
把 Arslan 讲清楚。从最早原型到 v0.1.63 的设计、实现与演进
一个本地优先、开源的 Mac 个人 AI 助手:它的产品选择、运行机制、数据与权限,以及五十多个版本积累下来的工程经验。正文区分已发布实现、历史设计和后续方向;每个结论都链接到 v0.1.63 的源码。
Git 可追溯的最早开发起点
不等同于最早构思或开源日
v0.1.0–v0.1.63 连续齐全
其中 63 个是公开正式 Release
专家分身编排 → 统一 Agent 循环
能力保留,执行路径更短
01 / 项目概览让自然语言接上真实工作
Arslan 是一个开源、Mac 优先、本地优先的个人 AI 工作助手。用户描述想完成的任务,Arslan 组织上下文、调用模型、使用工具、记录执行过程,并交付可以检查的答案或文件。它把聊天、记忆、文件处理、终端、网页、部分原生应用操作与后台任务放在同一个工作入口中。
项目由作者独立通过 AI 辅助开发,也就是通常所说的 vibe coding,持续构建和迭代。本文从产品目标讲到实际代码边界,介绍它为什么这样设计、怎样运行,以及从最早原型到 v0.1.63 经历了哪些变化。
理解任务
结合本轮要求、近期对话、允许使用的个人记忆和相关资料,决定下一步需要什么信息与工具。
执行并观察
模型提出结构化动作,代码校验参数与权限,工具返回真实结果,再由模型决定继续、换方法或收尾。
交付可检查的结果
文件、工具返回、任务状态和来源构成结果依据。用户可以查看进度、处理审批、停止任务,或从已有记录继续工作。
一个入口,几类工作
| 任务类型 | 典型工作 | 使用条件与结果边界 |
|---|---|---|
| 研究与阅读 | 搜索网页、提取内容、阅读附件、汇总带来源的资料 | 受网页可访问性、提取完整性和模型能力影响;引用可供核对,但不自动证明结论正确 |
| 文件与产物 | 处理工作区中的文本或数据,运行转换命令,生成可打开的结果文件 | 读写范围取决于工具、工作区与授权;保存记录和实际文件应互相对应 |
| Mac 上的操作 | 通过系统接口、Shortcuts、Apple Events 或 Hands 读取与操作支持的应用 | 路径各有系统权限和应用兼容要求;敏感动作可能需要额外确认 |
| 持续任务 | 把耗时工作留在聊天中,或在你或模型选择时交到后台;运行定时任务(0.1.63 中定时任务不运行终端命令);接收进度与结果 | 依赖本机进程可运行;Mac 休眠、离线或关机时,不能按云服务的可用性理解 |
| 个性化协作 | 记住称呼、格式偏好、项目规则和这台机器上已验证的方法 | 记忆有范围、敏感性、来源与使用许可;经验不会给工具追加权限 |
“本地优先”具体意味着什么
本地优先描述数据主存储和执行位置:桌面界面、本地服务、数据库、工作区及 Mac 工具主要运行在用户机器上。模型由用户配置;使用云模型时,请求中的对话、资料片段和获准使用的记忆会发送到相应模型供应商。兼容的本地模型端点也可以接入,但具体工具调用与视觉能力仍取决于模型和服务实现。
因此,Arslan 的架构需要同时回答两个问题:工作在哪台机器上发生,哪些内容会发往哪个模型端点。本地数据持久化、云端记忆许可和工具权限承担不同职责,不能用一个“本地”开关概括。
本文对应哪个版本
正文以正式发布的 v0.1.63 为基线,发布时间为北京时间 2026 年 10 月 27 日 22:26:31;核对截止 2026 年 10 月 27 日。代码链接固定到发布提交 9bbb6ad653b4。发布后开发、历史功能和后续工程方向会单独标明。
02 / 独立开发与开源一个人,借助 AI,把应用做成系统
Arslan 是我独立通过 AI 辅助开发做出来的项目,也就是通常所说的 vibe coding。从最初的原型到后续版本,项目一直由我独立推进。
这里的“独立开发”指项目整体由作者独立推进,AI 是实现过程中的协作工具。Arslan 同时建立在开源框架、系统 API、外部模型与第三方组件之上。开发方式、项目责任和组件来源各有清晰含义;下文讨论的,是最终进入产品的设计与实现。
从生成代码到维护一个可用产品
一段代码能运行,只覆盖产品的一小部分。桌面应用还要解决服务如何启动、窗口怎样连接、旧数据库怎样升级、进程被结束后如何清理、系统权限由谁持有,以及安装包在没有开发环境的机器上能否工作。Agent 又增加了新的不确定性:模型会超时、工具参数会截断、网页可能读不全,执行到一半也可能需要用户批准。
这些问题把 Arslan 的迭代逐渐推向四个方向:用明确契约约束输入与状态,用可观察的工具结果核对完成情况,用权限边界控制实际副作用,用测试与发布验收检查更改是否成立。AI 辅助可以加快实现与排查,但最终交付需要这些约束共同支撑。
敢于删掉早期假设
早期围绕专家分身组织能力,后来收敛到一个统一的 Arslan。工具和方法可以继续复用,用户入口与执行主路径则随着真实问题重新设计。0.1.63 在代码层面完成了这件事:删除了已没有任何回复能走到的专家时代代码(创建专家、专家模板和引擎),Arslan 的产品代码比 0.1.62 少了 12,514 行。
保留没有改善的证据
增加审阅层、学习经验或并行能力,并不必然提高任务效果。项目记录过审阅失败、研究任务落后和学习后未提速的结果,为下一轮修改提供具体方向。0.1.63 删除了研究审阅、进化与整理机制以及对话菜单里的“Distill”(提炼),而不是继续保留它们运行。
哪些工作属于 Arslan,哪些来自依赖
| 组成 | 在项目中的角色 |
|---|---|
| 应用与运行系统 | Arslan 将界面、模型适配、统一循环、任务状态、记忆、工具权限和桌面交付组织为可安装的个人应用。 |
| 基础框架 | React、Tauri、FastAPI、SQLAlchemy、SQLite 等承担通用界面、宿主、服务与持久化能力。 |
| 模型 | 模型通过用户配置的端点调用。Arslan 提供应用运行环境与执行链路,没有在此项目中训练一个新的基础模型。 |
| 桌面自动化组件 | Hands 使用 agent-desktop(Apache-2.0)上游 v0.9.4 之后再加四个提交的版本,从一个 fork 构建:fork 内置其依赖,并带有 Arslan 的一处修改(进程已不存在的 app 不再列入 app 清单),这处修改已提交给上游;Arslan 在外层实现独立 helper、身份验证和权限策略。 |
| 终端规则来源 | Arslan 自己读取 shell 命令的模块,以及终端规则的安全底线,改编自 Hermes Agent 的 MIT 许可代码;在其之上的各层规则(禁止、仅这一次、沙箱)以及对外行为与凭证规则是 Arslan 自己的。直到 0.1.62 仍随版本附带一份 Hermes 代码的内置副本;0.1.63 用 Arslan 改编的模块取而代之,并删除了该副本。 |
项目以 Apache-2.0 开源,第三方组件的许可和归属见 THIRD_PARTY_NOTICES.md,这份文件也随 App 一起发布;Arslan 读取终端命令的代码改编自 Hermes Agent(MIT),出处也写在里面。开源让实现、限制和演进过程可被检查,也让“为什么这么做”成为文档的一部分。
03 / 技术栈界面、宿主、执行与数据的分工
Arslan 的技术栈围绕桌面交付与个人 Agent 的职责划分。下面的精确版本来自 v0.1.63 的锁文件,代表该源码的依赖解析结果;不是要求用户机器安装的工具版本,也不是项目的发行版本。
| 层次 | 实际技术 | 承担的工作与选型意义 |
|---|---|---|
| 界面 | React 19.2.7 TypeScript 5.8.3 Vite 6.4.3 | 组件化聊天、任务卡、审批卡、设置与记忆页面;类型约束帮助维护跨页面状态和事件协议;Vite 负责开发与构建。 |
| 界面状态与样式 | Zustand 5.0.14 Tailwind CSS 4.3.1 i18next 26.3.1 | 共享 UI 状态、样式组织和六语言资源。ECharts 渲染聊天中由 render_chart 工具生成的图表及运行对比图,D3 用于记忆关系图;这些不是后端推理框架。 |
| 桌面宿主 | Tauri 2.11.5 / Rust 系统 WebView / objc2 | 负责窗口、托盘、启动、退出、状态岛、更新及 macOS API。Rust 工程声明最低版本 1.77.2、edition 2021,不应当成实际构建器版本。 |
| 本地服务 | Python ≥ 3.11 FastAPI 0.141.1 Uvicorn 0.51.0 | 接口、WebSocket、Agent 循环、异步 I/O、工具执行和调度。选择 Python 方便复用模型与文档处理生态。 |
| 数据模型 | Pydantic 2.13.4 SQLAlchemy 2.0.51 aiosqlite 0.22.1 / SQLite | 输入与任务契约校验、异步数据库访问、本地持久化。SQLite 降低个人桌面产品的部署成本,但不是多租户分布式数据平台。 |
| 检索与记忆 | SQLite FTS5 Embedding / cosine / RRF 可选 fastembed 0.8.0 | 全文和语义检索互补;没有 embedding 路径时仍可用关键词检索。个人记忆另有范围、敏感性和使用权限。 |
| 模型传输 | httpx 0.28.1 OpenAI-compatible / Anthropic / Gemini 适配器 | 统一模型调用接口,保留各家工具调用、推理延续和使用量语义。自 0.1.63 起,OpenAI-compatible 提供商、Claude 和 Gemini 的回答会随模型书写而流式显示;提供商不再接受的参数会被去掉,并按模型记住。模型能力仍受具体模型与端点限制。 |
| 扩展 | MCP Python SDK 1.28.1 SKILL.md / arslan.plugin.json | MCP 提供工具协议,Skill 提供操作方法,插件清单描述如何组合能力。三者不是同一个概念。已启用的 MCP 服务在后台启动,各有一个模型与“能力”页面都读取的状态;自 0.1.63 起,MCP 工具和很少用到的工具按需查找,而不是随每次请求一起发送。 |
| 附件与本地 OCR | pypdf / pypdfium2 python-docx / python-pptx / Pillow macOS Vision + PyObjC | 读取文档内容和图片文字。OCR 是识字,不等于理解图表或保证整篇文档被完整读取;要披露部分读取和语言限制。 |
| 原生 Mac 应用 | Arslan Hands(Rust helper) agent-desktop(v0.9.4 + 上游 4 个提交,固定的 fork) Accessibility / Unix socket | 读取辅助功能树,自 0.1.60 起还可以读取它正在操作的那一个窗口的画面,并按规则执行动作。agent-desktop 是 Apache-2.0 依赖;fork 带有 Arslan 的一处修改,随附的 NOTICE 写明了这一点。 |
| 跨设备 | Mac Swift Bridge(本仓库) CloudKit / CryptoKit / Keychain iPhone 端 SwiftUI 位于独立的 iOS 工程,不在本仓库 | Mac 与 iPhone 的密文消息、审批和结果同步;移动端的工程进展与正式上架状态分别陈述。 |
| 打包与质量 | uv.lock / npm lock / Cargo.lock PyInstaller 6.21.0 pytest / Vitest / Rust / Swift tests GitHub Actions | 可复现依赖、冻结本地服务、跨语言测试、平台检查、签名公证和真实安装包验收。桌面安装包是交付路径;Docker 部署路径已在 0.1.63 中移除。 |
为什么保留 Python 执行核心
Python 承担模型适配、文档处理、Agent 循环和任务服务,已有生态和现有实现能直接复用;Tauri 与 Rust 承担窗口、进程生命周期及原生集成。公开架构决策记录了保留这一执行核心的选择。将核心迁往另一种语言,会同时改变工具、数据迁移、打包和测试边界,不能只用“更原生”判断收益。
这种结构在逻辑上分层,在部署上仍以本地服务为主体。内部 Python 模块没有各自成为远端微服务,也不依赖 Redis、Celery、Docker 或 Kubernetes 才能运行。Hands、Bridge、MCP 服务和终端子进程在需要独立权限或独立运行环境的位置形成进程边界。
锁定依赖:前端锁文件;桌面锁文件;Python 锁文件。设计与归属:运行核心决策;第三方归属。
04 / 项目如何走到今天从生成专家,到一个能持续工作的 Arslan
Arslan 由作者以 AI 辅助的 vibe coding 方式持续独立开发。它的演进过程既有新能力,也有收回的设计:有些功能需要补齐运行条件,有些复杂度则需要删除。理解这些变化,比把所有历史功能并列在一张清单上,更能说明今天的架构。
六月:先建立“通过对话生成 Agent”的闭环
2026 年 6 月 7 日最早保留的提交从数据模型开始。当时的方向是 Meta-Agent:让不熟悉技术的用户通过对话创建领域专家,再由这些专家完成任务。随后出现模型适配器、工具注册表、需求对话状态机、模板、Spawn Manager 和 CLI。6 月 8 日,FastAPI、异步数据库、认证、WebSocket 与 React 界面接起来,原型有了可交互、可保存和可恢复连接的入口。
随着工具开始真正运行,系统需要知道“执行过什么”,也需要给回答提供资料。6 月 23 日加入 Runs、Steps、Evaluations,以及文档分块和 SQLite FTS5;6 月 27 日接入 MCP 的 stdio 与 HTTP 传输。这些变化把项目从生成一段专家提示词,推进到管理一次完整执行:调用模型、运行工具、保存过程、检索资料,再把结果交回用户。
最早数据模型;Runs 数据模型;FTS5 知识索引;MCP HTTP 传输。
七月:把记忆和交付变成工程问题
7 月 5 日,Second Brain 加入 embedding 与按作用域过滤的混合检索,结合全文搜索、向量相似度和 RRF 排序融合。随后补上事实来源、有效状态、替代与撤销、整理提案和使用记录。记忆由此不只是聊天摘要:资料是否相关、是否仍有效、属于哪个范围,都要影响它能否进入模型上下文。
把更多历史放进上下文会带来新的取舍:检索范围过大可能混入无关资料,旧事实可能覆盖新事实,外部文本也可能影响长期行为。因此七月的实现开始给事实补来源和时序,区分自动追加、需要审阅的修改与敏感内容,并让整理结果进入提案收件箱。后续记忆功能沿着这些约束继续演进,用户能看见、纠正和撤回,成为比“记住更多”更明确的工程目标。
这一阶段也开始处理长期维护。7 月 14 日,数据库迁移切换到自有版本化 runner,移除 Alembic 依赖。7 月 10 日改用 Apache-2.0 许可证,并加入 NOTICE 与 SECURITY.md;7 月 25 日出现明确的开源准备提交;到 7 月 27 日,v0.1.0 作为首个桌面安装版发布,Tauri 外壳与冻结的 Python 后端一起交付,签名、公证、更新和首次安装检查进入发布链路。
真实安装环境随即暴露了开发测试看不到的缺口:v0.1.0–0.1.6 的安装包缺少 WebSocket 运行依赖,健康接口正常,聊天却无法建立连接。0.1.7 修复依赖层与 PyInstaller 隐式导入,并把真实握手加入安装验收。这个故障解释了为什么“后端启动了”必须进一步验证为“用户的整条路径可用”。
混合检索;版本化迁移;开源准备;安装包 WebSocket 故障复盘。
八月:能力可接入,还要让用户看懂
0.1.20 把凭据状态区分为未配置、可解密和不可解密,稳定盐与密钥迁移;搜索增加来源与错误说明,模型开始按任务分工。随后,MCP OAuth、OpenRouter 登录、首次引导、扩展清单、本地工作区读写、定时任务与 SSH 逐步加入。扩展能力变多后,系统也必须准确说明:当前连接能否调用工具、装备是否生效、哪次动作需要授权。
本地执行能力也开始分层。工作区读取与写入分开,写入需要相应授权;定时任务有自己的调度许可;SSH 可以记住机器,但每次远程执行仍需要确认。工具清单由此同时描述能力和使用条件。对用户而言,“已经连接”与“这次可以执行”是不同状态,界面与模型上下文都需要表达这个区别。
0.1.23 的 turn journal 让切换对话后正在生成的回答仍能接回来;安装版找到 npx 的修复则再次说明,桌面应用拿到的环境与终端不同。八月的主线不只是接更多服务,而是把连接、状态和授权变成用户能理解的操作。
九月:从一次回答,走向可追溯的工作
0.1.38 集中补可靠性:默认拒绝的 Python 执行沙箱、独立计算运行时、持久化 Runs、产物、检查点和共享执行预算。0.1.40 的预览与稳定化继续推进项目记忆、文档来源、任务延续和迁移前备份,同时保留跨语言、多文档比较的已知失败。来源可点击,只说明资料能被找到,并不能证明模型的结论正确。
更早一些,8 月 31 日到 9 月 3 日,语音从朗读(0.1.32)、按住说话(0.1.36)推进到半双工对话(0.1.37),同时修复麦克风权限与语言选择。与此同时,0.1.40 的研究验收没有把跨语言比较失败改写成成功;0.1.41 的来源审阅在校准不理想后保持默认关闭(0.1.63 后来删除了这项研究审阅)。这些记录限定了“系统做过检查”的含义,也让下一步改进可以围绕真实失败展开。
0.1.41 让关闭窗口变为留在菜单栏继续工作;0.1.42 把长任务放到后台,用户可以继续聊天;0.1.43 再区分预算软限与硬停:到达软限先利用已有材料收尾,避免研究做到一半却没有交付物。任务逐渐拥有独立于界面的生命周期,但这不意味着任意外部动作都能在崩溃后安全自动重放。
九月末到十月:收敛为一条执行循环
早期设计把专家作为长期存在的角色,用户和系统都需要处理选择、邀请与路由。0.1.44 停止创建和调度专家,旧专家的方法可以转为 Skill;0.1.46 停止已无消费路径的专家后台演化;0.1.48 移除前置 router,每条消息直接进入 Agent 循环。发布说明指出,某些“我不能做”的固定回答来自路由判断,而不是实际能力。这次收敛把工具选择放回拥有真实工具和状态的执行过程。
收敛后,改进集中到共同的执行层:0.1.49 完善原生工具协议、截断与失败恢复;0.1.50 增加当前工作状态、计划与替代路线;0.1.51 增加命令沙箱和 Island;0.1.52 让用户记忆与 learned practices 进入后续工作。这里的“学习”是保存和使用可管理的经验,不是更新基础模型权重。
0.1.53 进一步通过独立 Hands helper 读取辅助功能树、操作 Mac 应用,并纳入 Mac 侧 iPhone Bridge。0.1.54 为 iPhone App 补齐这一 Mac 侧(Touch ID 审批、一台手机一个条目、移除手机后清理),并补上终端闸门的四处缺口,每一处都只会多问、不会少问。0.1.55 让所有需要你回答的卡片统一样式、排进同一个队列:可以在收件箱里回答,不涉及风险的步骤也可以直接在 Island 里回答。0.1.56 把项目分成两层:一块看板放所有项目,每个项目有自己的关卡和检查点,Arslan 只凭能说出来源的证据打勾。0.1.57 让能力自己长:某一步需要 Arslan 还不会的事时,它会去找合适的服务或 Skill,问你,固定版本并在沙箱里安装,测试通过后重试那一步。0.1.58 让回复和文件读得懂:做过的事收成一行,写出的文件以卡片返回,有了阅读器,每个对话可选任意模型。0.1.59 让对话在长回答中保持连接、用用户的语言回答,并把做完的后台工作算作完成。0.1.60 带来 Hands v2:可以看它正在操作的那一个窗口,短暂借用前台,并且只有在你同意后才接管屏幕。0.1.61 把同一张审批卡带到聊天窗口、收件箱、灵动岛和 iPhone,让 MCP 服务自行启动,并修复了拒绝 temperature 设置的 Claude 模型。0.1.62 让较长的终端命令运行到各自的限制,把“需要你检查”收窄到确实可能留下痕迹的动作,重塑 MCP 工具描述,使某一家提供商的拒绝不会让所有聊天失败,并使文件写入不再顺着链接跑出工作文件夹。0.1.63 允许在回复运行时追加消息,让回答随书写流式显示,最多同时运行四个读取,保存检查点以便撤销一个回合,只在需要时发送很少用到的工具,新增每个任务的美元上限(默认开启),并在每条新命令前先询问,而对无害命令的判断留待之后完善。它还删除了代码:已没有回复能走到的专家时代代码、进化与整理机制、研究审阅、“Distill”、Docker 部署路径以及内置的 Hermes 副本。旧的专家编排已经属于历史,辅助功能操作也不能外推为所有应用都可靠可控。当前版本仍以可见的状态、明确的权限和可检查的结果,约束模型能够实际完成的工作。
05 / 系统架构界面、执行和权限,各自负责什么
一句通俗解释:React 是用户看到的工作台,Tauri 是连接 macOS 的外壳,Python 是协调工作的引擎,模型提供判断,工具产生实际动作,数据库和磁盘保存过程与结果。这些职责组合在同一个桌面产品里,但不属于同一个进程。
图 1 · 当前架构。纯文本读法:工作台 ↔ 本地服务 → 统一 Agent 循环 ↔ 模型;执行循环 → 工具 → 系统/文件;状态落 SQLite 和磁盘。iPhone 通过 CloudKit 与 Mac Bridge 通信,不是直接连接 Mac 的公网 API。
为什么选这种分层
| 边界 | 获得什么 | 需要付出什么 |
|---|---|---|
| React ↔ 本地服务 | 聊天、设置、图谱等界面与执行逻辑分离;回答随模型书写而流式显示,工具事件可实时展示 | 要维护协议、断线重连、流式状态和认证,不能以页面仍打开判断任务仍活着 |
| Tauri ↔ Python sidecar | 保留 Python 的模型与文档生态,同时提供普通 Mac 安装体验 | 多语言打包、动态依赖、端口发现、进程退出和签名都要管 |
| 模型 ↔ 工具执行器 | 模型负责提出动作;确定性代码负责校验、授权、执行和记录 | 必须处理畸形参数、未知工具、截断响应、重复失败和取消。很少用到的工具和 MCP 工具按需查找,而不是随每次请求一起发送;某一步需要审批时,会显示一张审批卡 |
| Hands 独立 helper | Accessibility 权限由独立进程持有,并有应用级和动作级规则 | 代码签名、进程身份、系统权限和应用差异成为额外维护成本 |
| Mac ↔ iPhone | Mac 开机、联网且唤醒时,离开电脑后仍能发起请求、查看结果、处理支持的审批 | Mac 不可用时消息在 iCloud 等待;还需处理重试、乱序、恢复与终态一致性 |
一次启动怎样把这些进程接起来
- Tauri 启动冻结后的 Python sidecar,在服务就绪前显示启动界面。
- sidecar 优先绑定本地端口
47317,冲突时使用临时端口,再通过标准输出返回ARSLAN_PORT握手。 - 桌面壳收到端口后,让系统 WebView 加载本地服务提供的 React 页面。优先固定端口有助于保持 WebKit origin 与本地界面存储稳定;服务端会话目录支持端口变化后重新找到历史。
- 界面通过 HTTP 管理资源,通过 WebSocket 接收文本流、工具状态、审批与任务进度。本地连接仍需要 token 和来源检查;桌面应用的服务始终要求它的 token,不接受其他网站作为调用方,并忽略从启动它的环境中继承来的设置。
- 壳保留标准输入管道作为生命周期联系;父进程退出造成 EOF 时,sidecar 可以清理退出。输出管道也需要持续消费,避免阻塞或失去连接后留下孤儿进程。
这些细节共同保证窗口、服务和数据库生命周期保持一致。只检查 HTTP health 返回成功,无法证明 WebSocket、附件、静态资源和原生 helper 都已可用;它们在发布验收中还需要分别检查。
启动细节:冻结服务入口与端口策略;sidecar 握手与管道管理;WebSocket 接入。
旧架构与新架构:保留复用,退役专家调度
多专家/Meta-Agent
用户 → 前置 Router → 选择/创建 Spawn → 专家执行 → 汇总;专家提示词可进入留出评测和人工 Promote。产品需要用户理解专家身份、装备、名册和演进。
One Arslan/统一循环
用户 → 同一个 Agent loop → 按需加载 Skill 和调用工具 → 输出结果;普通事实在回答后提取。旧专家可转成 Skill,保留历史记录,由旧专家启动的任务在恢复时由 Arslan 接着做。专家路由不再是主执行路径,自 0.1.63 起,已没有回复能走到的专家时代代码、进化与整理机制以及研究审阅都已删除。
“统一循环”不等于“一切串行”或“永远不委派”。代码仍有受约束的只读 worker 能力;它不等于早期那套有独立人格、装备、演进与路由的专家产品系统。
代码入口:桌面壳与 sidecar 生命周期;统一入口;执行循环;保留 Python 原生执行核心的决策;Bridge 进程监督;本地 Bridge 控制通道;跨设备协议。
06 / 执行运行时让一次请求有过程、有边界、有结果
Arslan 的执行核心负责把用户意图变成一连串可观察的动作:准备上下文、调用模型、校验工具请求、执行获准的操作、读取真实结果,再决定继续还是交付。自 v0.1.60 起,默认入口采用统一循环;消息直接进入答复流程,长期事实的提取放在答复之后。主流程不会先经过一次模型路由,已没有任何回复能走到的专家时代代码(创建专家、专家模板和引擎)已在 v0.1.63 中移除。
源码:消息入口与上下文组装;可信任务上下文;统一工具循环。
图 2 · 执行闭环。纯文本读法:输入 → 上下文 → 模型 → 参数校验 → 授权 → 工具执行 → 结果回流,再继续循环;模型也可直接回答。答案与产物须经检查,再交付或如实说明未完成;禁止和拒绝不会被模型意愿覆盖。
模型负责提出下一步,运行时负责执行条件
模型看到的工具是一组名称、用途与参数 schema。它返回结构化 tool_calls 后,运行时先解析 JSON、验证参数,再重新确认工具是否仍可用、当前预算是否允许以及是否需要用户授权。内建工具由注册表映射到执行函数,mcp_ 前缀的工具转入 MCP 调用,模型只会看到此刻已就绪的 MCP 服务。一个工具出现在注册表中,并不意味着它会在每轮对话里开放:自 v0.1.63 起,一次请求只携带常用工具,外加两个查找器 find_tools 和 use_tool;很少用到的工具和 MCP 工具按需查找并调用,所受的审批和记录与直接调用相同。一个对话按需用过的工具列表最多增长到 12 个,且只保存在内存中。
自 v0.1.63 起,回答随书写即时显示(在下文列出的端点上),原先会拦下回答的检查改为在必要时于回答之后追加更正;如果流在中途失败,Arslan 会保留你已看到的内容并说明这次回复被中断,而不是从头再来。当模型连续请求多个读取(网页、搜索、其服务标记为只读的 MCP 工具)时,最多四个同时运行;每个结果仍与发出请求的那次调用配对,任何不是读取的调用则在原位置单独运行。
一个关键边界是响应完整性:如果供应商因输出长度限制截断了工具调用,本批调用不会被执行,即使其中某项看起来已经完整。含有工具调用的模型文本只作为过程说明,不能提前充当最终交付。执行前后会记录检查点,真实工具结果带着对应调用身份返回模型;来自网页、文件或外部工具的内容仍作为数据处理。
因此,“我已经保存文件”要能对应实际保存结果和产物引用;一句自然语言承诺不会自动变成已经发生的操作。工具失败也会成为下一轮输入,循环可以调整路线,但须继续遵守相同的权限与预算。
以“读取指定目录并生成清单”为例,目录路径先作为输入进入任务范围;模型提出读取请求,工具返回实际文件信息,随后才有依据生成清单。若进一步要求移动或删除文件,运行时还要根据对应操作判断授权。最后的交付应指向已经生成的文件,并说明检查结果。这个过程中的文件列表、操作回执与产物引用,分别承担不同的证据作用。
统一入口之下保留模型协议差异
LLMAdapter 提供统一调用接口,具体 Provider 处理请求格式、流式事件、工具调用与 usage。Provider 实现通过 httpx 发送 HTTP 请求;OpenAI 兼容端点也可配置为本地模型服务。选择云端模型时,对应请求上下文会发往用户配置的供应商。
| 协议路径 | v0.1.63 的实际处理 |
|---|---|
| OpenAI 兼容 | 支持 native trajectory:将 assistant 工具调用、调用 ID 和 tool result 渲染为原生消息历史;特定协议拒绝可触发有限降级。在 DeepSeek、OpenAI 和 OpenRouter 端点上,回复随书写而流式显示,这些端点已知其流式工具调用是完整的;其他端点则整段返回。 |
| Anthropic | 自 v0.1.63 起也使用 native trajectory。在 Anthropic 自己的主机(或列入名单的第一方代理)上,回复随书写而流式显示,并请 API 自行清理旧的工具结果;其他使用 Anthropic 协议的端点则整段返回。 |
| Gemini | 保留自身的工具调用与历史表示,并维护所需的供应商续接信息;自 v0.1.63 起也使用 native trajectory,且只在 Google 自己的主机上流式显示。 |
Trajectory 是循环中的结构化轨迹,作用是保留“哪个调用产生了哪个结果”的关系。它使内部记录统一,同时允许不同供应商使用各自协议,避免把工具交互压成一段难以核对的普通文本。如果某个端点拒绝原生历史,这一回合的其余部分会改用旧式渲染。
这一层有两处修复。自 0.1.61 起,当提供商拒绝某个可选的请求设置(例如较新 Claude 模型上的 temperature)时,Arslan 会去掉该设置重新发送,或改用错误信息要求的名称,并为该模型记住这一点直到重启。自 0.1.62 起,MCP 工具描述会被重塑为 Anthropic、OpenAI-compatible 提供商和 Gemini 都接受的形式;如果提供商仍拒绝某个工具,该工具在这条回复剩余的部分被排除在外(第二次拒绝,或拒绝时没有指明工具,则这条回复排除所有 MCP 工具)。内建工具按原样发送。
源码:模型门面;轨迹数据结构;Provider 能力约定;去掉被拒绝的设置后重发;MCP 工具描述重塑;按需工具;执行层变更说明。
临时协作者与后台任务各有职责
delegate_work 把独立研究拆给临时 worker:一批最多 4 项,最多同时运行 2 项。当前 worker 只开放 web_search 与 web_extract,不能写文件或个人记忆,也不能继续递归委派。主执行者接回材料后负责核对和整合。这个设计保留了并行研究的价值,同时让执行责任集中在原任务上。
后台 job 则用于较长的完整任务:它拥有独立上下文和预算,复用工具循环、产物检查与修复流程,进度通过任务卡回到会话,默认最多同时运行 3 个。网络连接、聊天窗口和后台执行有各自生命周期;切换会话不等于取消任务。本机休眠或进程退出时,后台工作也不会转交给云端继续运行。
先进入收尾,再触及硬限制
预算同时统计模型请求数、工具调用数、累计 token、执行时间,以及自 v0.1.63 起的美元。聊天回复和后台任务现在适用相同的限制:设置中选定的档位,默认是 standard。达到 soft limit 时,循环应停止扩张研究范围并组织现有成果;hard limit 防止继续失控消耗。嵌套执行和重试也要计入任务预算,无进展的重复调用另有检测,避免反复尝试同一条失败路径。
| 档位(聊天回复和后台任务) | 模型请求 | 工具调用 | 累计 token | 执行时间 |
|---|---|---|---|---|
| lean | 60 | 40 | 300,000 | 900 秒 |
| standard(默认) | 120 | 80 | 600,000 | 1,800 秒 |
| ample | 240 | 160 | 1,200,000 | 3,600 秒 |
表中是 soft 默认值,四项 hard 值为其 1.5 倍。单次输出上限与产物大小限制另行计算。token 用量在响应返回后记账,因此这些阈值是调度边界,不能理解为精确费用上限或完成时长承诺。等待审批卡的时间不计入执行时间。在这些档位之外,每个任务还有美元上限,默认开启,为 $2(设置 › 后台与主动 › 每个任务的美元上限):运行达到其三分之二时开始收尾,达到上限时停止。只有已知价格的模型的响应才计入,所以本地模型或价格表里没有的模型不会增加金额,token 上限依然有效;检查在下一次请求之前进行,因此一次运行可能超出一个响应的量。恢复任务会继承已用计数、执行时间和美元,停机等待时间不作为重新执行时长,也不会清零预算。
长时间的工作留在聊天中:Arslan 不再自己把它推到后台;后台任务是在你或模型选择时,把同样的工作换到别处去做。十分钟后,回复会告诉你它仍在工作。终端命令按它所请求的时长运行(默认 2 分钟,最多 10 分钟),但不会超过这条回复剩余的时间;如果时间限制让它停止,Arslan 仍能看到到那时为止的输出,并会被告知这一点,输出泛滥的命令则保留开头和结尾。默认情况下,每条新命令都会先显示一张卡(v0.1.63),而定时任务在这个版本中不运行命令:该步骤被跳过,并列在收件箱中。无人回应的卡片在 30 分钟后过期,Arslan 会被告知这不是拒绝。
源码:预算规则;命令时间限制与输出上限;审批卡及其过期;临时协作者;后台任务。
任务、尝试与验收分别记录
TaskSpec 保存任务约定:指令、输入、范围、验收项与预算,并带有修订版本。一个 task 可经历多次 attempt;attempt 是一次具体执行尝试。修改约定、取消后返回的旧结果或恢复后的新尝试,不能互相混写状态。持久化更新同时检查 attempt 身份与 row version,防止过期执行覆盖新状态。
| 状态 | 含义 |
|---|---|
queued / running | 等待开始 / 正在执行。 |
waiting_user | 需要用户操作或显式继续;状态本身不代表成果已完成。 |
verifying | 根据任务约定检查证据与产物。 |
succeeded / failed / cancelled | 通过验收 / 执行失败 / 已取消。 |
验收结果区分通过、失败、未运行、不适用等情形。判定需要对应证据,不能漏掉约定的检查,也不能全部只依靠模型自评。文件存在性、所属任务与摘要等可以确定性校验,主观质量才适合补充模型或人工评价。仍有准备中、进行中或效果未知的动作时,仓库层也会阻止任务直接变成成功。
这也解释了为什么任务修订必须保留身份:针对旧要求生成的结果,不能自动证明新要求已经满足。验收要对应同一版任务约定、同一次有效尝试,以及该任务拥有的证据。关键检查不能随意标成“不适用”;只有符合契约规则的非关键项才有这种处理空间。缺少证据时,应保留未验证或未完成的结果,等待补充检查。
恢复从已有证据继续
检查点保存进度、已用预算、证据与产物引用,运行事件供界面重连后查看。进程内的 run registry 持有实际异步任务和取消入口,并把事件分发给已连接窗口;重连时同步取得快照并附着事件流,减少连接交接处的丢帧或重复。
进程重启后,尚未结束的执行会被识别为中断,由用户显式继续。已经发送出去、却没有收到回执的外部动作,其效果属于未知,必须先核对,不能直接重复提交。恢复备份还会撤销旧动作授权、把相关动作标成不确定。检查点解决的是“从哪里安全继续”,并不能撤回已经产生的外部结果。
另有一种检查点用于“撤回这一轮”(v0.1.63)。一个回合第一次写文件或运行命令时,Arslan 会把工作文件夹按当时的样子保存一次。撤销会把文件放回去,并把这一回合及之后的每一回合从对话中移除,连同它们教给 Arslan 的事实;摘要会保留,消息 id 绝不会被重复使用。只有当文件夹最多有 20,000 个文件和 5 GB、剩余磁盘空间足够,并且与 Arslan 的数据在同一块磁盘上时,才会保存该文件夹。可重建的文件夹(Python 环境、node_modules、构建输出、__pycache__)和形似机密的文件不会被保存,也绝不会被放回;撤销框会说明哪些没有保存。回合之后被改动的文件会保留并列出,而在某次运行仍在改动该文件夹时,撤销会被拒绝。
停止也有两个层面:运行注册表负责取消正在等待或执行的异步工作,持久化状态负责阻止迟到结果继续提交。对外部系统已经接受的请求,取消本地等待无法证明对方没有执行。因此动作表区分准备、已开始、已确认、失败、效果未知与已取消等状态,恢复流程先处理这些状态,再决定哪些步骤可以再次尝试。
源码:任务与验收契约;持久化状态与并发检查;产物校验;执行与显式继续;连接与运行分离;备份恢复边界;用于撤销的文件夹检查点;撤销一个回合。
一轮运行中持续告知窗口
自 0.1.59 起,一轮运行期间,服务端至少每 15 秒向窗口发送一次“工作中”事件,即使模型要花几分钟写一个长文件也是如此;因此“已中断”现在只表示连接本身断了。自 0.1.63 起,在 Arslan 仍在回答时发来的消息,会在那条回复的下一步就到达它,而不必等它结束:尚未开始的步骤会被跳过,回复先读这条消息,窗口会说明它已被追加。正在写最终答案的回复已经没有下一步,所以这条消息在它之后立即运行。当审批卡在等待时,一条消息会以该消息为备注回答它“否”,然后接着运行。回答语言跟随用户最新的一条消息:判断时忽略路径、网址和代码,没有文字的消息跟随界面语言。窗口连接已关闭时发出的审批不再让这一轮失败;卡片会在收件箱、Island 或重新连上的窗口里等待。
源码:工作中事件、排队与重连后的卡片;追加到运行中回复的消息;回答语言。
项目:看板、关卡,以及要凭证据才打勾的检查点
自 0.1.56 起,一个项目有一份按关卡组织的计划,每一关都有清楚的过关条件和几个检查点。选定类型(游戏、app、网站、研究、写作、视频、技能、旅行、工作或其他)后,关卡按模板起草,不调用模型;“让 Arslan 细化”用用户自己的模型调用一次,把关卡贴合到终点线上,用户点“创建”之前什么都不保存。看板的四栏——想法、成形、在做、完成——由当前关卡推导,不靠拖动;“完成”和“放弃”只由用户来定。
Arslan 只凭能说出来源的证据推进计划,而且只针对当前关卡:写明文件的检查点,在这些文件出现在项目文件夹里时打勾;用户自己发完一轮后,由判断层判断这条消息是否说明某件事做完了;从项目“交给 Arslan 起头”开始的后台任务以完成结束时,为对应检查点打勾。小勾可以撤销;过关只是卡片上的提议,不发通知、不进收件箱。只有连续猜对十次之后,Arslan 才会问一次能否自己推进关卡。它学到的计划规则、用户的节奏和“停滞”提示都留在本机,只在用户自己发起的起草请求里才会进入模型。
07 / 数据与记忆保留可用的上下文,也保留清晰的数据边界
Arslan 把主要状态保存在本机 SQLite:会话、运行记录、任务、个人记忆、模型配置及用量都有对应数据模型。文件产物写在磁盘;过长的工具输出全文另存于应用数据目录(保留 7 天),模型按结果里给出的路径分段读取。这样,关闭一个窗口不会抹掉任务过程;也能分别管理“当时说了什么”“实际做了什么”和“以后可以记住什么”。
数据访问采用异步 SQLAlchemy 与 aiosqlite。连接启用 WAL、外键检查、5 秒忙等待,并使用 synchronous=NORMAL。这些选择服务于本机单用户应用:减少部署依赖,并改善读写并存时的体验。数据目录还有协作式进程锁,避免遵守同一协议的实例同时使用同一份数据。
图 3 · 记忆闭环。纯文本:来源 → 判断 → 生效/提案 → 保存 → 按范围与权限过滤 → 召回 → 记录使用;记住“用 EventKit”不等于获得提醒事项权限。
数据对象按职责分层
| 数据组 | 主要对象 | 回答的问题 |
|---|---|---|
| 对话与运行 | ArslanMessage、ArslanSummary、Run、RunStep、UsageLedger | 用户说了什么、调用过什么、消耗了多少。 |
| 持久任务 | companion_tasks、task_revisions、task_attempts、task_checkpoints、task_events、task_actions | 任务采用哪版约定、处于哪次尝试、有哪些动作与证据。 |
| 个人记忆 | memory_entries、memory_revisions、memory_sources | 记住哪条信息、当前是哪一版、依据来自哪里。 |
| 使用与删除记录 | context_receipts、memory_deletions、memory_suppressions | 哪版记忆进入过上下文,以及哪些删除需要继续生效。 |
| 权限与审批 | permission_rules、permission_grants、approval_events | 有哪些长期生效的回答(“始终”)和按任务或按对话的回答,以及每一次越过边界的决定:谁做出的、卡片等了多久。 |
| 资料与经验 | KnowledgeChunk、Lesson、Judgment | 可检索的资料、可复用的经验及小判断的结果。 |
任务表保存当前状态,修订表保存任务约定,attempt 表记录执行尝试,event 表提供有序事件,action 表记录实际动作及效果状态。它们共同支撑检查和恢复。个人记忆则把稳定身份、内容修订和来源拆开,便于编辑、溯源与删除;它没有直接复用全部聊天内容作为永久记忆。
源码:SQLite 连接;运行、资料与配置模型;任务模型;个人上下文与记忆模型。
工作上下文:控制本轮输入,保留原始历史
模型每次能接收的内容有限,Arslan 会用有上限的滚动摘要加上近期消息构成工作上下文。自 v0.1.63 起,历史窗口的大小按这一回合所用的模型来定:估算为其上下文窗口的 40%,但不低于 3,000、不高于 24,000 token(未知模型按 32,000 计,本地模型按 8,192 计),摘要本身也受长度限制。这是历史装配的预算,不代表整个模型请求只有 3,000 token:系统指令、工具 schema、资料和结果还会占用其他空间。
对话变长后,最近四个用户回合保留原文(只要它们能放进预算的一半),较早回合的工具摘要最先被遮蔽,这不花任何代价;一旦历史超过其预算的四分之三,较早的消息就被折叠进摘要,摘要保留“目标、进展、决定、涉及的文件、下一步”这几节。逐回合变化的内容(事实、摘要、资料、回复语言)放在该回合请求开头的一个参考块里,而不是系统提示中,也绝不会被存成用户说的话。压缩影响下一次装配哪些内容,不等于删除数据库中的完整会话;压缩失败也会保留原始记录。过长工具输出另有落盘机制:模型得到头尾摘要和文件路径,需要时再分段读取,完整输出按保留策略清理。
这种分层让模型优先看到当前任务所需的信息,同时给后续核对留下原始依据。摘要只是已有内容的压缩表示,不能代替某个外部动作的真实回执。
个人记忆:先决定能不能用,再决定是否相关
记忆条目包含类型、范围、敏感级别、使用策略、状态、置信信息与版本。范围可以是全局或某个项目(另有领域、专家等内部范围),条目同时归属所有者;local_only 等使用策略进一步决定内容能否进入云模型请求。每轮的可信上下文从数据库载入会话设置,普通用户文本、网页或模型输出不能自行改写这些权限。
“关于你”和“Mac 笔记”有受限的基础注入,其余内容按相关性选择。自 v0.1.52 起,默认开启的“记住我并在对话中使用”可允许普通、cloud_allowed 条目用于已配置的云模型。敏感内容还需要额外许可;local_only 不会因为总开关开启而变成可上云内容。
ContextReceipt 记录使用了哪些条目和修订、为何使用以及估算计数,不复制记忆正文。用户能追溯一次上下文选择的依据,系统也不必为此再制造一份敏感内容副本。
编辑记忆会产生新的修订,条目的当前修订指针随之更新;来源记录继续说明这版内容是如何形成的。暂停、过期、被替代和删除等状态,也会影响是否进入后续上下文。版本化有利于核对变化,但删除流程会清除需要抹去的正文,所以不能把它理解成所有历史内容永久不可删除的事件库。
源码:历史与摘要;长工具输出;按模型窗口确定历史大小;逐回合的参考块;会话许可;范围与隐私过滤、回执。
资料检索:关键词与向量可以组合使用
知识资料的检索模块支持 SQLite FTS5 全文搜索和向量余弦相似度搜索。前者找词面匹配,后者利用 embedding 寻找语义相关片段;两路都可用时,通过 RRF 把排名融合。RRF 比较的是排名位置,不直接混用不同量纲的原始分数。未配置 embedding 或缺少向量时,仍可走全文检索。
检索所得片段附带来源进入模型上下文,由模型结合当前问题组织答复,这就是此处的 RAG。资料检索只在绑定了资料集的项目中进行;使用云模型时,还需该对话单独开启云端记忆许可(默认的“记住我”开关不覆盖资料)。结果作为 recall 工具的返回值进入上下文。它无需修改基础模型权重,也不依赖单独部署的向量数据库。个人记忆 v2 的选择主要使用权限过滤、全文与本地相关性逻辑,不能据此推断所有记忆都经过同一套向量管线。
经验学习:把纠正变成可审阅的规则
Lesson 用于保存用户纠正、失败后成功的绕行方法以及机器环境特点。例如,某个命令在当前 Mac 上需要不同参数,可以形成有来源的经验,供相似任务参考。召回最多 5 条、总计约 800 字符,放入动态的 agent status,不污染稳定系统前缀;召回、遵循、成功与失败都有计数。
是否值得保存、是否与已有内容重复或冲突,可以由 judgment 层提出范围很小的判断,并记录概率与后续结果。用户纠正或未受外部内容影响的经验,在设置允许且判断有价值时可以直接生效;其他需要审阅的内容进入提案。含凭证的候选会被直接丢弃;“推断出的敏感信息需要审阅”这条规则属于个人记忆,而不是经验。判断缺失或超时时有回退路径。
自 0.1.55 起,纠正必须针对 Arslan 在对话里先前做过的事才算纠正:第一条消息是请求,不会被当成纠正。与同一轮里刚刚成功的路线相矛盾的纠正,不会立即生效,而是变成等你同意的提案;需要用户自己解决的失败(例如 macOS 拒绝授权)也不会被学成改走别的路线的理由。Arslan 在对话中保存记忆时,会在对话里说明,并提供撤销。
这些机制修改应用保存与召回的知识,不训练模型权重。judgment 的启用范围也各不相同:记忆、经验和项目这几个判断点在回答之后运行,而一个已登记的判断点(回合完成)处于关闭状态。没有任何判断会决定一条命令能否运行:命令卡片的影子判断已在 v0.1.63 中移除,只有授权流程来决定。
删除需要跨过摘要和旧备份
删除一条记忆时,系统会提高 deletion epoch,清除该条的旧修订正文与来源,并清空所有会话的滚动摘要和运行记录中缓存的提示词,防止旧的派生内容把已删记忆带回来。删除记录只保留用于匹配的内容指纹(本地密钥 HMAC)和范围等元数据,避免在账本里重新保存已删除正文;suppression 记录防止仍在聊天历史中的同一来源再次自动生成这条记忆。删除记忆与删除原始会话是不同的数据操作。“撤回这一轮”是第三种更窄的操作:它删除所有来源都是被撤销回合的条目(另有其他来源支撑的条目只失去这些来源),不留下文本墓碑,并保留摘要。
独立删除账本和删除清单用于在启动及恢复路径继续落实删除。恢复旧备份前,系统检查存储身份,在激活数据前对照删除信息整理暂存数据,降低旧备份让已删除记忆重新出现的可能。这个保证依赖恢复流程与可用删除记录,不能解释成能撤回所有已经导出到外部的副本。
备份里的其余记忆也不会立即恢复全部使用许可:恢复处理会将其隔离待审,收紧使用策略,清掉缓存上下文,停用全部定时任务,并收回会话级的云端与敏感许可、归档进行中的项目。恢复数据与重新批准使用数据分开完成,避免旧会话许可在新的运行环境中静默生效。
迁移先完成,应用再开始使用数据
当前数据库升级使用显式迁移 runner:检查 schema 版本、准备升级备份、创建缺少的表、按顺序执行待运行迁移,然后处理密钥兼容和记忆 v2 激活。未知或过新的 schema 会被拒绝,避免较旧程序盲目修改较新数据。v0.1.63 的显式登记已到 0070;早期 Alembic 历史不应当作当前运行机制。自 v0.1.60 起新增了 0067(权限表)、0068(每个 MCP 服务一个状态以及每个工具的提示)、0069(消息 id 绝不重复使用,因此撤销一个回合不会把已删除的 id 再发出去)和 0070(已存的“只对有风险的命令询问”一次性改为“每条命令前都询问”)。
记忆 v2 激活时,旧事实与学习表改名为 legacy 表并加只读触发器,兼容视图将旧读入口映射到新结构,全文索引也在这一过程中建立。模型 API 密钥、MCP 环境变量与 OAuth 令牌、SSH 密钥等秘密字段使用 Fernet 字段级加密(PBKDF2 + 每次安装独立的盐值);普通会话和任务表并未因此变成整库加密。持久化、秘密保护与备份恢复各有具体边界。
源码:记忆删除与版本;长期回答与按任务的回答;撤销一个回合;删除账本;恢复前删除核对;备份恢复协调;恢复数据隔离;存储启动顺序;显式迁移;权限表;记忆结构激活;密钥字段保护。
08 / 工具、Skill 与扩展让能力可复用,也让执行有边界
Arslan 把“能够做什么”和“知道怎样做”分开组织。工具负责实际动作,Skill 保存方法和参考,MCP 连接外部能力,插件清单把这些资源组合起来。模型拿到的是本轮可用的能力集合;某个工具存在于源码注册表中,并不代表它默认启用或已经获得执行许可。
四个概念怎样配合
| 组成 | 提供什么 | 不能替代什么 |
|---|---|---|
| Tool | 有名称、参数约定与执行器的动作,例如搜索、读文件或运行命令 | 工具描述不能替代参数校验、权限判定和实际返回值 |
| Skill | SKILL.md 中的工作方法,以及可选脚本和参考材料 | 它本身不获得系统权限,也不是单独训练的模型 |
| MCP | 通过 stdio 或 HTTP 发现、调用外部工具的协议 | 统一接口不保证服务可信;连接、暴露与授权仍由应用控制 |
| Plugin manifest | arslan.plugin.json 声明 MCP 启动方式、secret 槽位及关联 Skills | 安装和解析清单不等于立即运行其中的任意服务器 |
从声明到执行,中间有哪些检查
内建工具由注册执行器承接,带 mcp_ 前缀的调用进入 MCP 代理。工具结果回到统一循环,模型可以据此补充参数、选择替代方法或结束任务。即使模型已经读过一份 Skill,文件、命令和应用操作仍要通过各自权限边界。
自 0.1.63 起,一次请求不再携带所有工具。它携带一组常驻的日常工具(网页搜索与页面读取、文件读取/写入/编辑、终端、计划、后台工作、记忆、read_skill、能力清单,以及 Hands 的桌面工具),外加两个查找器:find_tools 对这一回合可以调用、但没有展示给模型的工具排序,use_tool 则按真实名称调用其中一个,因此参数按该工具自己的参数校验,所受的审批、追踪和回执与直接调用相同。MCP 工具、attach_file 和浏览器工具都通过这种方式使用。按需使用过的工具,从下一回合起加入该对话的列表(每个对话最多 12 个,保存在内存里,所以重启后模型要重新查找)。find_tools 返回的来自 MCP 服务的文字,会被包装成外部数据,绝不当作指令。
当模型连续请求多个读取时,最多四个同时运行:网页搜索和页面读取、read_skill、文件读取和列目录等,以及其服务标记为只读的 MCP 工具(一组中每个服务一个)。每个调用仍按这条回复的顺序通过所有闸门,每个结果仍与发出请求的那次调用配对;任何不是读取的调用则在原位置单独运行。
Skill 采用按需读取:索引告诉模型有什么方法,read_skill 再从已注册的 SkillPack 或允许的参考路径取出正文。这样可以让方法库增长,同时控制每轮上下文体积。Arslan 自带两个 Skill:一份设计过的 HTML 报告,和 Skill 创建器。自 0.1.63 起,专家时代的种子、预设的 MCP 连接器清单以及模型的连接器建议工具都已移除(寻找新的 MCP 服务改由下文的 find_capability 完成),而你以已退役名称导入的 Skill 也不再被删除。
自 0.1.55 起,“能力”页把 Arslan 能做的事列成开关:每一项是开、关、差一步,或在此处不可用,并写明原因。关闭就意味着根本不提供给模型,read_skill 也会拒绝读取已关闭的 Skill。各行状态读自决定每轮可用工具的同一组闸门,因此不会出现显示“开”而工具其实缺失的情况。新增的 whats_new 工具用随应用发布的版本说明回答“你是哪个版本、改了什么”,而不是凭模型记忆。
扩展服务是新的信任边界
本地 stdio MCP 通常意味着启动一个独立进程,HTTP MCP 则可能连接远端服务。Arslan 需要分别管理连接、主助手是否可用、工具是否暴露,以及凭证怎样保存和展示。插件清单中声明的 HTTP MCP 服务 URL 必须使用 HTTPS;secret 槽位声明参数形状,不在清单中内嵌真实凭证。已配置环境值会加密保存,读取显示时掩码处理。
自 0.1.61 起,你开启的每个 MCP 服务都会在 Arslan 打开时于后台启动,一次最多四个,聊天从不等待其中任何一个。每个服务只有一个状态,“能力”页和模型都读取它,模型只会看到此刻已就绪的服务;对其他服务的调用,会得到它的状态和原因作为回答,其中的 key 和 token 已被掩码。首次启动有 120 秒;失败的服务在 30 秒后重试,之后间隔变长(最长每 10 分钟一次)。
自 0.1.62 起,Arslan 在发送之前,会把 MCP 工具的参数描述重塑为 Anthropic、OpenAI-compatible 提供商和 Gemini 都接受的形式;内建工具按原样发送。如果某个提供商仍然拒绝其中一个,该工具在这条回复剩余的部分被排除在外,回复继续进行(如果拒绝没有指明工具,或第二个工具被拒绝,则这条回复排除所有 MCP 工具)。
自 0.1.63 起,对 MCP 调用的询问方式取决于服务声明该工具做什么:服务标记为只读的工具无需卡片即可运行;标记为破坏性的工具每次都要询问,且只对这一次有效;其他工具会询问,可以只对这一次或对这个对话生效,绝不提供“始终”。参数太长、卡片无法完整显示的调用会被拒绝,而不是被截断。这些标记是服务自己的声明,Arslan 不核实。在无人可问的地方(定时运行),只运行只读工具。
这些约束降低了意外暴露和误执行的机会,但实际 MCP 服务仍可能访问它获得的资源。工具来源、所需权限、发送到远端的数据和操作副作用,都属于扩展能力需要解释的部分。
能力自己长:找、问、装、扫、测
自 0.1.57 起,某一步需要 Arslan 还做不到的事时,find_capability 会同时搜索官方 MCP Registry、GitHub 和经过审核的 Skill 库。propose_capability 只能提名本次对话里已经展示过的候选,卡片由服务端根据那次搜索结果生成,而不是照搬模型的话:要添加什么、来自哪里、许可证(从项目自己的许可证文件读取)、怎样运行、可以使用哪些文件夹、需要什么 key。只有发起询问的那个 Arslan 窗口能批准;后台任务或无人可问的一轮,只把找到的结果记到“能力”页的“Arslan 找到的”里。
批准后,它以固定版本、默认关闭的状态安装:带哈希的锁文件、发布方给出的校验和或某个提交,运行在 Arslan 自己固定版本的 uv 或 Node 上;安装过程中不执行任何包代码(Python 只装预编译 wheel,npm 不跑安装脚本)。扫描会查找已知的危险写法——Skill 里藏着的指令、下载并运行更多代码的代码、写入 macOS 启动程序位置的操作——发现高危项就会把它移除;扫描无法证明任何东西安全,所以服务之后在自己的沙箱里运行(见第 09 章)。它必须能启动并列出至少一个工具才会被启用,工具循环随后重新读取工具列表,失败的那一步可以在同一次回复里重试。从 GitHub 导入的 Skill 固定到某个提交,每个文件都有校验和,其文字按外部内容读取,不能授予权限。
源码:询问、安装、扫描、测试、启用;固定版本安装与源头许可证;已知模式扫描;MCP Registry、GitHub 与 Skill 库。
文件以文件的形式返回:工作台阅读器
自 0.1.58 起,一轮中写出的文件会在回复下方显示为卡片,回复里的路径可以在 Arslan 或文件浏览器中打开。工作台里的阅读器只读取 Arslan 自己的读取工具能读的位置:工作区,默认读取开启时的桌面、文稿和下载,活跃项目的文件夹,以及 Arslan 自己的产出。符号链接先解析;隐藏文件和形似凭据的文件名从不列出也不读取;文件内容以附件形式加 nosniff 发送;HTML 显示在 sandbox 为空的 iframe 里,其中的脚本无法运行。
自 0.1.63 起,当你要一个文件(截图、图表、导出文件或文档)时,attach_file 会把它附在回答上:窗口中是一张文件卡片,配对的 iPhone 上则是文件本身。它不需要自己的卡片,因为它只读取阅读器可以读的位置,适用同样的规则:不含隐藏或形似凭据的文件名,没有指向可读文件夹之外的链接。它也绝不会取 Arslan 自己的数据、钥匙串或 SSH 密钥下的任何内容,不取超过 20 MB 的文件,也不取超过一次运行所能容纳的文件数。
源码:attach_file;阅读器的范围与隐藏文件名;文件内容;沙箱中的 HTML。
Hands v2:单个窗口的画面、批量、借用前台、接管
Hands 仍然以辅助功能树读取窗口。自 0.1.60 起,每次查看还可以附上那一个窗口的 JPEG 画面——从不截整个屏幕——只保存在内存里,只发送给模型;不会写入磁盘、运行记录或界面。模型不能接收图片时,改由 macOS Vision 在本地读出文字。可以在 设置 → Hands 里关闭,或对你列出的应用只读文字。同一个应用里的几个步骤作为一批执行,最多八步;菜单项即使在应用不在前台时也能直接选择;应用在后台打开。0.1.62 及以前,聊天回复里最多执行五个动作,且都在同一个应用里;自 0.1.63 起,聊天回复没有 Hands 自己的上限,和后台任务一样只受这次运行的上限约束。定时任务在 Mac 上完全不能执行动作:没有人在场批准。
有些操作只有应用在前台才能完成,比如弹出菜单。这时 Hands 会等你打字停顿一秒,借用前台约一秒,期间所有显示器的边缘亮起蓝光,你这时按下的键先被保留,等你的应用回到前台后再补上。如果应用的窗口在另一个桌面上,Hands 会按同样的规则去那里,在工作结束、15 秒没有动作或你第一次输入时回来。较长的工作可以由后台任务请求接管屏幕,最多 30 分钟;任何键盘或鼠标输入都会让它暂停,直到你让它继续。“我离开时”默认关闭;打开后,三分钟没有输入,接管可以不经卡片开始。借用前台可以关闭,关闭后 Hands 会拒绝而不是借用。
源码:只取一个窗口,不写入任何地方;借用前台;另一个桌面;接管与输入暂停;聊天回复里的动作、批量与菜单;设置 → Hands。
搜索与读取网页
自 0.1.63 起,web_search 首先使用这一回合所跑的模型自己的搜索:Anthropic 自己 API 上的 Claude 对话用 Anthropic 自己的网页搜索,DeepSeek 模型用 DeepSeek 的搜索。使用本地模型的对话绝不会把查询发给提供商自己的搜索。在设置中选择的 Tavily 或自托管 SearXNG,要么是唯一的搜索,要么是模型自己的搜索之后的备用;没有明确选择时,尽力而为的 DuckDuckGo 抓取排在最后。当某个搜索服务拒绝 Arslan 时,结果会说明搜索被拦截、什么也没有搜到,绝不会说“没有结果”。
页面读取和浏览器保留对外访问的防护:本地名称、真实的私有地址以及含控制字符的主机会被拒绝。自 0.1.61 起,在代理或 VPN 用假地址(198.18.0.0/15)回答 DNS 的 Mac 上,通过 https 在 443 端口请求、且所有地址都落在该段内的名称会被放行,而对这类名称使用普通 http 或其他端口则被拒绝。对这样的名称,由代理决定请求实际去往哪里;仍然有效的是 TLS,它按真实名称校验。
源码:搜索顺序与被拦截的搜索;各提供商的搜索;对外访问防护与假 IP 例外。
并行研究为何仍然存在
统一 Agent 循环保留了受限的临时只读 workers。v0.1.63 中,一批最多 4 项,最多同时运行 2 个;工具限定为搜索与网页提取,不写入文件和个人记忆,也不能递归创建更多 workers。主助手负责检查并综合它们的结果。
这类委派适合拆开互相独立的资料查询。它与早期永久专家分身的生命周期不同:没有要求用户先挑选或管理一个专家团队,也没有把每条消息强制路由给另一位“专家”。是否使用并行,仍应取决于任务是否能有效拆分以及额外调用成本。
后台、定时与 heartbeat
后台 job 将耗时执行与当前聊天分开,复用同一套模型、工具和验收逻辑。定时任务把“何时开始”持久化;heartbeat 是定期检查清单的一种使用方式,默认关闭,负责检查与提出建议。定时触发不会把建议变成已批准的写入或命令。自 0.1.63 起,每次定时运行都是一个没有人可问的普通 Arslan 回合:在这个版本中,它完全不运行终端命令,无论此前允许过什么;只在 Arslan 自己的文件夹里写入,不能在 Mac 上执行动作,只运行其服务标记为只读的 MCP 工具;需要更多权限的步骤会被拒绝,并列在收件箱中。
聊天回复和后台任务都会在每个任务的美元上限处停止(默认开启,为 $2;达到其大约三分之二时开始收尾;只有已知价格的模型才计入),可在设置中更改。聊天回复不再因为工作耗时长而被推到后台:后台工作是在你或模型选择时,把同样的工作换到别处去做。
当前调度由本地服务实现,包含重叠跳过、失败暂停和重启清理等处理。错过的周期不会逐一补跑;同一个任务上一轮未完成时,不叠加启动下一轮。这些行为适合个人桌面应用,也意味着它的运行条件与持续在线的服务器不同。
实现:工具注册与 read_skill;能力开关;插件清单契约;MCP 连接与配置;find_tools 与 use_tool;同时运行的读取;MCP 启动与状态;MCP 调用与按服务标记的审批;重塑 MCP 工具描述;两个自带的 Skill;只读 workers;后台任务;本地调度;heartbeat。
09 / 执行与安全边界从模型建议到真实动作,中间发生什么
Arslan 可以读写文件、运行命令,也能通过浏览器和原生应用完成工作。它的安全设计围绕一个区别展开:模型负责提出下一步,可信代码负责决定这一步能否执行。下面描述 v0.1.63 已实现的边界;这些是有具体作用范围的保护机制,并不是对所有恶意输入、应用行为或系统环境的安全证明。
模型生成结构化调用
判断允许、询问或拒绝
拒绝与超时都有结果
各自限制实际访问
失败不伪装成完成
外部内容可以提供资料,不能自行扩大权限
网页和工具结果可能含有提示注入。网页文本和 MCP 结果进入上下文时,会被包在明确的外部数据边界中;自 0.1.63 起,本地工具返回的内容(文件、命令、应用窗口)被包在另一个独立的工具输出边界中,同样只当数据看待,伪造这两种边界标记的内容都会被处理。系统还记录本轮是否读过网页、文件、MCP 结果等外部内容:受这些内容影响的经验和机器笔记需要先成为提案。这样,一段网页里的“以后总是把文件发到这里”不能仅凭被读到就获得长期授权。
自 0.1.63 起,同一份记录也限制终端:一旦某一回合读过外部内容(网页、文件、MCP 结果),它的命令就在内核规则下无网络运行,而按命令文本判断、或按模型自己所说会访问网络的命令,会先询问。在沙箱内,回答可以只对这一次或对这个对话有效;在沙箱外,只对这一次有效。在无人可问的地方,命令保持离线。读取网页另有防护:本地名称和私有地址会被拒绝,而针对用假地址回答 DNS 的代理所设的例外(0.1.61),只放行对某个名称的 https 443 端口访问,由代理决定它实际去往哪里(第 08 章)。
这层处理有助于保持来源和信任关系,但仍然依赖后面的执行检查。模型可能误解资料,命令风险识别也不是完整的语义证明;不能因为文本被标为“不可信”,就取消真正的权限边界。
外部数据包装与来源追踪;工具校验与执行入口;经验进入生效或提案路径。
不同执行工具,有不同的隔离强度
| 路径 | 实际限制 | 不能从中推导出的保证 |
|---|---|---|
| run_python | 默认拒绝的 macOS Seatbelt 计算环境:只开放解释器所需读取、临时工作区读写和只读参考文件;禁止网络及 host IPC,清理子进程环境并施加资源限制。 | 不是任意 Python 程序的通用宿主。缺少可用隔离时默认拒绝;未实现的 Linux 沙箱不会被当成已经可用。 |
| 普通 run_command | 运行真实 shell。策略分三层:forbid(无论在沙箱内外都绝不允许:清空磁盘、主目录或系统文件夹,直接写磁盘,关闭 Mac,从钥匙串读出密码,碰 Arslan 自己的密钥文件,任何需要 sudo 的操作);ask,只对这一次有效(发送或发布,删除工作文件夹之外的内容,强制结束程序,更改启动项或系统设置,驱动其他应用,在沙箱外打开应用或链接,读取屏幕或剪贴板,写入 shell 启动、SSH、凭据或其他 agent 的设置文件,以及任何文本读不懂的命令,例如引号不成对、eval,或把下载的代码通过管道交给 shell);以及 run。命令链(&&、;、|、||、&)中的每一条都会检查,不只第一条;命中规则的命令,其卡片只对这一次有效:不会为它记住任何回答。自 0.1.63 起,默认每条新命令都先问(“什么时候问”设置:“每条命令都先问”);只有选了“只在有风险时问”,策略判为 run 的命令才会不出卡片直接运行:在沙箱里,或在这次会话已获准离开沙箱时于沙箱外运行。默认工作区沙箱限制写入工作目录、临时与缓存目录,禁止发送 Apple Events,另行关闭 Arslan 的数据和密钥、Hands socket 以及用户凭据所在的路径(SSH 密钥、Keychain 文件、AWS、gcloud、kube、gh、GnuPG、npm、netrc 等云和命令行工具凭据,浏览器配置文件、Safari 和 cookies)。自 0.1.59 起,“桌面、文稿、下载”关闭时,这三个文件夹也对读写关闭,经由 /System/Volumes/Data 和符号链接也一样;位于其中的工作文件夹仍可读写,活跃项目的文件夹仍可只读。 | 其他位置的读取、程序运行与网络仍开放;用户允许在沙箱外运行的命令不受这个文件夹开关约束,也不受已关闭的凭据路径约束(ssh、git push 和 gh 需要它们);它在一份最小配置下运行,该配置仍然关闭 Arslan 自己的数据、密钥和 Hands 文件夹,并禁止 Apple Events。沙箱不可用时,命令会先问(选了“只在有风险时问”时,对“本对话内”的同意也覆盖这次会话之后策略判为 run 的命令);获准后在沙箱外运行并返回 sandbox=unavailable,因此不是统一的 fail-closed 路径。 |
| 安装的 MCP 服务(0.1.57) | 在默认拒绝的 Seatbelt 配置下启动:只能用自己的文件夹和临时目录、你授权的文件夹,以只读方式使用 Arslan 固定版本的运行时;即使在授权文件夹里,你的受保护路径也保持关闭。它的 HOME 指向自己的文件夹。 | 只有声明需要某个在线服务的 key 时才开放网络,而且此时可以访问任何主机(Seatbelt 无法限定到单个主机)。0.1.57 不会把你手动添加的服务移进这个沙箱。自 0.1.63 起,它的工具调用按服务声明该工具做什么来询问(第 08 章),而这一声明是服务自己的,未经核实。 |
| 离线收尾命令 | 任务进入收尾后,允许处理已取得的数据并保存交付物,同时额外阻断网络。 | 所需沙箱不可用则拒绝执行,不能套用普通命令的降级规则。 |
| AppleScript / Shortcuts | 在终端命令中,osascript 和 shortcuts run 以常见写法(带路径、经 command、exec 或 xargs、带重定向)出现时,始终询问,且只对这一次有效。沙箱禁止 Apple Events,所以 Arslan 不认识的写法会在其中失败。只有一个已获批准的普通调用会不带沙箱包装运行:与提醒事项、日历、备忘录或通讯录对话、且没有其他风险动作的脚本,或文件只留在 Arslan 文件夹里的普通 shortcuts run;它只能通过在 Mac 窗口里点击来批准。Hands 自己的 AppleScript 工具每次都询问并展示完整脚本,只提供给后台工作,并拒绝指名了被禁用应用、或用计算出的名称选择应用的脚本。 | 已获批准的快捷指令以用户身份在沙箱外运行,Arslan 看不到它做了什么。命令本身在文件沙箱中,不代表被调用的应用也受同一文件范围约束。 |
| Arslan Hands | 独立 helper 持有 Accessibility;helper 内再次检查应用、动作、字段和停止状态。自 0.1.60 起,一次查看可以附上那一个窗口的画面,只保存在内存里。 | 辅助功能树不是完整的业务语义,窗口画面由模型读取,而不是由代码检查。应用是否提供可操作节点会影响可用性;另一个桌面上的窗口只能按借用前台的规则前往(见第 08 章)。 |
离开命令沙箱需要用户点击批准:可以为当前动作申请,也可以由用户选择本次会话内允许;后者随会话保存(重启后仍在),也适用于该会话的后台任务,可在设置里收回。源码开发环境另有显式的 Python 无沙箱逃生设置,桌面版会关闭这条逃生路径。两者都不应被误读为模型可以自行关闭保护。
自 0.1.62 起,write_file 和 edit_file 绝不顺着链接写到工作文件夹之外:通过指向外部的链接写入会被拒绝;在别处有第二个名字的文件(硬链接)会在工作文件夹里被替换,而另一个名字保留旧内容;新建的文件从不可执行,已有文件保留它的权限。文件先写成旁边的一个新文件再换入,所以写入失败时旧文件原封不动。自 0.1.63 起,一个回合第一次改动工作文件夹时会保存一个检查点,“撤回这一轮”会把文件放回去,并把这一回合从对话中移除。这是恢复用的保障网,不是边界:它只保存最多 20,000 个文件、5 GB 的文件夹(不计 Python 环境、node_modules、构建输出和缓存,这些被排除在外且绝不会被放回),从不复制形似机密的文件,只覆盖工作文件夹,不会撤销任何已离开这台 Mac 的东西,并在无法保存时显示“未保存”。检查点保留七天。
受限计算环境与开发逃生设置;工作区与保护目录规则;安装服务的沙箱;普通命令降级和离线拒绝;命令策略;写入时不跟随链接;检查点;撤回这一轮。
审批绑定具体动作,后台工作不继承所有便利授权
审批卡通过 call_id 与动作种类关联,错误种类的回复不能批准另一张卡。Mac 窗口和手机共同看到的卡采用首个有效回答,并向其余视图广播关闭结果;无人回答则保持开启 30 分钟,时间到了也不算拒绝(自 0.1.61 起;更早的版本在 300 秒后过期)。自 0.1.61 起,同一张卡在窗口、收件箱、Island 和 iPhone 上看起来一样:“一次”(或“本任务内”,以卡片列在第一位的为准)、“本对话内”、“始终”,以及附带一条会交给 Arslan 的备注的“否”;卡片等待期间在聊天中输入的消息,会以这条消息为备注回答它“否”,而且一次点击只回答一张卡。有些种类的选项更少:命中规则的命令、涉及金钱的、接管、以及应用里有风险的步骤,只对这一次有效;离开沙箱、站点、快捷指令和 MCP 工具则从不提供“始终”。后台任务的卡片与窗口的卡片提供相同的选项;自 0.1.63 起(S4a),从会话发起的任务使用该会话的授权,包括离开沙箱。没有人可问的运行(定时运行)不走这些步骤:那里不计任何先前的回答,该步骤立即被拒绝,它没能做的事会列在收件箱中。在这个版本中,定时运行完全不运行终端命令。模型建议连上 MCP、登记远程机器或访问其他执行入口时,提案与真正启用连接分开处理。
对于外部副作用,发送请求也不等于完成动作。任务恢复会把结果不明的在途动作标为不确定,不能仅因为进程重启就自动重放。这里的目标是让重试与恢复有明确语义,而不是许诺任意外部系统都能撤销。
自 0.1.55 起,所有等待中的卡片——无论来自窗口、后台任务还是 iPhone——都排在同一个队列里,也出现在收件箱中,可以凭 call_id 在那里回答;回复按卡片自身的种类构造,只能确认或取消这一张卡,更宽的选项(本对话内、始终)只能在提供它们的卡片上选择:iPhone 和 Island 只给出卡片的第一个选项,绝不给“始终”,而收件箱可以给出卡片本身提供的任何选项。Island 可以回答文件夹、应用、屏幕、MCP 工具、定时、站点和快捷指令的卡片,以及不属于有风险类别的命令或工作区写入。它不能批准涉及金钱、发送、删除、应用里有风险的步骤、接管、离开沙箱、命中终端 ask 规则或读不懂的命令、同时要求访问网络的命令、远程主机上的任何操作、系统更改、其他 agent 的设置、安装能力、AppleScript、会在没有沙箱包裹的情况下运行的命令,或检查不认识的卡片种类。这类卡片显示“在 Arslan 中打开”,而且服务端会拒绝来自 Island 的批准,不只是 Island 页面不显示按钮。会不带沙箱包装运行已获批准的普通 AppleScript 或快捷指令的卡片,以及安装能力的卡片,只能在 Mac 窗口里批准;iPhone 对这类卡片点的“是”会被吞掉。在窗口里,⌘⏎ 允许、Esc 拒绝;单独按 ⏎ 永远不会回答卡片。
收件箱与 Island 的回答;卡片关联、过期和多端回答;恢复时的不确定副作用;连接提案和授权入口。
Hands 将系统权限收在一个更小的进程中
Accessibility 授予 Arslan Hands.app,而非主 App。签名发行包通过受保护 Unix socket、每次启动生成的 token 和 peer 签名检查接收请求。helper 自己执行规则,底层 agent-desktop 不单独持有该权限。自 0.1.61 起,查看一个应用和在其中执行动作合为每个应用一张卡片,并把“本任务内”列在第一位。自 0.1.60 起,聊天回复也可以执行动作:0.1.62 及以前最多五步、限于同一个应用;自 0.1.63 起只受这次运行本身的上限约束,和后台任务一样,可以跨多个应用,而且“停止”能让它停下(定时任务不能执行动作:没有人在场批准);从对话发起的任务继承该对话的同意。在浏览器中执行动作、运行快捷指令和 AppleScript 仍然只提供给后台工作。应用按其身份判断,所以用 .app 或完整路径、或用不同的大小写来称呼它,都绕不过禁用名单或缺失的批准。删除、发送、支付、购买、转账和提交等敏感按钮按实际标签每次询问;密码字段不输入,密码管理器、系统安全界面等应用在禁用名单中。
停止入口会设置停止闩锁,后续动作要经过该检查;活动记录保留操作线索,输入文字只记录长度。限制同样公开:另一个 Space 上的窗口只能按借用前台的规则前往,不提供按屏幕位置点击和拖拽,大窗口读取可能需要 10–20 秒;Stop 截断的调用可能没有对应 trace 行,审计记录并非对所有中断情况的完整取证保证。
自 0.1.56 起,Hands 每个请求最多只执行一次:同一请求 ID 的回答保留十分钟,重复的 ID 直接用保留的回答答复;后端丢了某次回复时,会去取回那次的回答,而不是再发一次动作。读不到原有文字的字段不会被“追加”覆盖,而是拒绝;只有该字段获得焦点时才按回车;动作已发出但没有读回结果时,报告为“已发送,未确认”,而不是已完成。Hands 运行的是从 Arslan 的 fork 按固定提交构建的 agent-desktop;Cua Driver 引擎已在 0.1.63 中从 Hands 摘除,因此 helper 不再查找或启动它(其未使用的模块仍留在 helper 的源码里)。自 0.1.60 起,一张卡片可以为一项工作覆盖最多八个应用,从对话发起的后台任务继承该对话的同意,应用也可以在 设置 → Hands 里永久允许。标签含删除、发送、付款、购买、提交、转账、签署、发帖、发布或确认(多种语言)的点击、选择或最后一个菜单项,对应的快捷键,在按回车即发送的应用里按回车,接管,以及任何 AppleScript,仍然每次询问。
* 或 null 的主机或 origin 变量现在会拒绝启动;“只监听本机”与“已经通过认证”不是同一件事。与当前用户同权限且已被攻陷的宿主环境,也不能靠一个本地 token 自动变成可信环境。socket、token、peer 与停止检查;禁用应用与分级;始终询问的词与快捷键;Hands 实测和限制;API 与 WebSocket 认证。
10 / iPhone 与 Mac Bridge手机负责交代和查看,Mac 负责执行
移动桥接让已经配对的 iPhone 查看 Mac 的任务、发起工作、回答审批并读取结果。执行仍由 Mac 上的 Arslan 完成;手机既不是另一套云端 Agent 服务,也不直接暴露或调用 Mac 的 HTTP 接口。本章以 Mac v0.1.63 的公开协议和源码为基准。Mac Bridge 在更早的版本中已经发布;其公开发行说明仍将 iPhone App 标为即将上架,本文不据此声称已完成 App Store 发布或完整生产链路验收。自 0.1.60 以来的变化会在出现之处标明版本;0.1.61 的说明称 Mac 端可与 Arslan for iPhone 1.0 配合使用,而该 App 仍被描述为即将上架。
加密、发件箱、状态视图
异步保存密文信封
本地 HTTP / WebSocket
结构化结果沿原路返回
CloudKit 是信箱,设备身份仍由协议确认
v1 使用同一 Apple ID 下的 CloudKit 私有数据库。Mac 必须开机、在线并处于可运行状态;否则消息等待处理,手机并不能让一台已经关机的 Mac 继续工作。局域网 Bonjour 是后续方向,不是本版的备用直连通道。Mac helper 是随应用运行的独立 ArslanBridge.app,通过 stdin 获得本地 API token,再连接后端;手机不持有该 token,也不接收模型 API key。
信封在云端公开的索引字段包括收发设备、序号、粗粒度 kind、通知标记和时间。真正的消息类型、正文和文件内容位于应用层密文中。因此“端到端加密”描述的是配对设备之间的消息保护,不表示没有元数据,也不表示后端模型调用完全不经过用户配置的 AI 服务。
传输、信封和 Mac 接线协议;CloudKit 存储实现;Bridge 运行入口。
扫描二维码只是配对的开始
二维码携带一次性 pairing_id、Mac 的签名与交换公钥、32 字节配对密钥、固定容器标识和期限。有效期不超过 600 秒;手机拒绝过期信息、错误容器和不符合约束的内容,并固定二维码里的 Mac 公钥。随后手机生成自己的身份与交换密钥,发出加密配对请求。Mac 验证请求后仍要展示给用户,由 Mac 上的点击决定接受或拒绝。
同一请求重试应得到相同决定,不能产生第二次授权。接受后使用设备身份通信,配对码被消耗;Mac 可以撤销手机。同一台 iPhone 再次配对时会带上它以前的 ID,Mac 移除这些旧条目,而不是并存两条。移除手机还会删除 Mac 留在 iCloud 里给它的消息;启动时 Mac 也会清理仍在等待已不再配对的手机的记录。设置 › 连接 › iPhone 中,每台手机在 Mac 读到它的第一条已认证消息前显示正在连接…,之后显示已连接及最后在线时间。设备私钥由各自 Keychain 保存。这里的信任来自一次性配对材料与用户确认的组合,而非“同在一个 iCloud 账户,所以任何消息都可信”。自 0.1.60 起,iPhone 自己解除配对时,Mac 会像在 设置 › 移除 之后那样忘掉这台手机,忽略它之后发来的任何内容,并更新列表。
消息同时校验内容、来源与上下文
每条新消息使用临时 X25519 密钥协商共享秘密,以 HKDF-SHA256 派生 32 字节密钥,由 ChaCha20-Poly1305 加密认证,再以 Ed25519 签名。消息头使用按长度编码的 UTF-8 字段,避免跨语言 JSON 排序差异影响验证;头字段同时被签名和 AEAD 认证绑定。这是以 CryptoKit 原语实现的应用协议,没有实现 Signal 双棘轮,也不应仅凭临时密钥就宣称所有场景的前向保密。
接收顺序有明确要求:检查形状与收件人,验证签名,再解密;随后检查明文与头字段是否一致,有文件时再验证附件。任一步失败都不应留下部分业务效果。文件上限为 20 MiB,密文摘要、认证标签、明文大小和摘要都要匹配后才能缓存或预览。
配对、密码套件和验证顺序;Mac 编解码与密码协议;一次性配对与用户决定。
投递成功、动作完成、界面终态是三件事
| 机制 | 负责什么 | 边界 |
|---|---|---|
| 持久化与同包重试 | 重试复用同一信封 ID、seq 和密文;序号等关键状态先保存,避免网络失败导致状态倒退。 | 投递日志不能代替外部业务系统的事务。 |
| 重放窗口 | 按发送者保留最近 1,024 个序号,接收窗口内的新乱序包,拒绝重复或过旧包。 | 合法新序号不一定代表业务状态更新,旧进度也可能较晚才发送。 |
| ACK | 确认信封投递;重复包可再次得到 ACK。原记录确认后删除,ACK 自身不再被 ACK。 | ACK 不表示任务成功,也不表示审批动作执行完成。 |
| 业务标识与结果 | client_msg_id、client_task_id 用于防重;approval.result、任务事件和结果承载业务状态。 | v0.1.63 的业务 ID 映射有内存状态,不能承诺任意崩溃下的全局 exactly-once。 |
Mac 状态快照只列仍在运行的任务;正常心跳间隔为 60 秒,手机按 90 秒未见更新判断离线。进度会节流合并,终态应及时发送。客户端因此既要处理消息重复和乱序,也要让任务列表、审批卡与历史记录收敛;不能只用“最后收到的文本覆盖前一条”维护状态。
序号、处理记录、ACK 与清理;业务防重与结果映射;快照与心跳。
手机审批复用 Mac 的授权与执行链
手机展示具体 action、target 和 risk。批准需要本机生物识别,拒绝不需要;发送回答后还要等待 Mac 的 approval.result。Mac 检查卡片是否仍有效,映射为原来的 confirm / cancel 操作,手机不会授予命令“永远允许”。语音入口可以形成待确认的文字,不能代替批准。
自 0.1.61 起,各处都是同一张审批卡(聊天窗口、收件箱、Island 和 iPhone)。手机显示卡片自己的问题(取自卡片的标题)以及它的“是”所涵盖的范围。它只回答一次,或者在卡片的第一个选项是“本任务内”时对本任务生效(针对应用、站点或快捷指令的卡片:此时标题以“(本任务内)”结尾),绝不提供“本对话内”或“始终”。卡片在 Mac 上等待 30 分钟(0.1.61 之前是 5 分钟);超时会以 expired 报告,Arslan 把它当作没有人回答,而不是拒绝。要求安装新能力的卡片永远不会到达手机。当 Mac 先回答时(在窗口、收件箱或 Island 中),手机的 approval.result 会带上 answered_on_mac。
faceid 或 touchid 标记(iPhone SE 用 Touch ID)时把回答算作批准,并在能力声明中告知手机;其他标记一律视为拒绝。0.1.54 之前,Touch ID 的批准会被当作取消。协议中的 high_risk_mac_only 在此版固定为 false,尚不是用户可配置的开关。共享协议与测试向量能验证互操作和负例,不能替代最终分发包、真实 iCloud、推送与设备认证的端到端验收。文件、实时对话和从手机改变方向
这些是新增的协议类型(协议文档第 5.7 节);没有它们的 Mac 会回答 unknown_type,而 Mac 只会把新事件发给其 hello 能力声明里要求了它们的手机。
- 来自手机的文件(0.1.61)。从 Arslan for iPhone 发来的文件或照片(最大 20 MiB,每条消息最多 10 个)会像其他资源一样被检查,并保存在 Mac 上工作文件夹的
Inbox/iPhone下,每个日期一个文件夹。Arslan 会连同消息一起读取它;图片可以作为图像交给模型。如果一条消息的文件没有在 120 秒内全部到达,这条消息就不会运行,手机可以再次发送。 - 实时对话(0.1.61)。Mac 把最新的 20 个对话,以及任何有任务在运行的对话,保持为关联状态,所以手机会列出它们,并在 Arslan 工作时跟随回答、进度和卡片。手机可以删除一个对话(Remote 对话永远不会被删除)。历史太长、一条消息放不下时,会丢掉最早的消息,并说明已被截断。
- 回答随书写显示(0.1.63)。对要求了它的手机,回复以
partial事件到达,每个事件带着到目前为止的整条回复,最多每秒一次,且不超过 100 KB;最终消息会取代它们。在 Mac 上输入的文字会显示在手机上,并标明来自 Mac,且绝不会让手机响铃。 - 改变方向(0.1.63)。回复运行期间发出的消息,会在那条回复的下一步就到达它,而不必等待;iPhone、Mac 窗口和按住说话都是如此。回复正在写最终答案时已经没有下一步,所以这条消息在它之后立即运行。0.1.63 中已知的限制:在回复期间于 Mac 窗口中追加的消息,只会从下一条回复起显示在 iPhone 上;iPhone 自己的消息被追加之后,它仍然显示“排在当前回合之后”。
- 发到手机的文件(0.1.63)。当你要一个文件(截图、图表、导出文件、文档)时,Arslan 会把它附在回答上:Mac 窗口里是一张文件卡片,iPhone 上是文件本身,不超过 20 MiB 的限制。
批准标记与原有动作的映射;移除或重新配对手机时的清理;状态、功能字段、手机文件和实时对话的收件箱;实时关联、来自手机的文件和部分回复;独立协议参考实现;0.1.54 公开交付状态。
11 / 验证与软件交付从能运行的源码,到可以安装和更新的应用
桌面软件的交付单位是应用包。源码环境中存在的 Python 模块、系统工具和旧数据库,都可能让一个缺少资源的安装包看起来正常。Arslan 将验证分成源码、平台、冻结产物、全新用户环境和分发几个层次。本章记录 v0.1.63 的流程及对应发布证据。
CI 同时检查行为、平台与依赖边界
| 检查组 | 主要内容 | 设计目的 |
|---|---|---|
| Linux 后端 | Python 3.11、uv frozen lock、Ruff、pytest;显式安装并检查 OCR 测试依赖。 | 执行完整后端测试,保留“缺少 macOS 隔离时必须拒绝”的平台负例。 |
| macOS | Swift 语音 helper 类型检查、Bridge 构建与测试、Rust fmt/test/clippy、Hands 检查、原生 Python 用例。 | 让最终交付平台上的 Vision、Seatbelt 和宿主代码进入常规验证。 |
| 前端 | Node 22、npm ci、TypeScript 类型检查、Vitest、生产构建。 | 覆盖状态与组件行为,并确认生产资源可以生成。 |
| 历史与供应链 | gitleaks 扫完整 Git 历史并脱敏输出;Hands 固定上游 commit、校验 vendored 文件,以 cargo-deny 检查依赖。 | 避免只检查最新 diff,或让构建悄然使用变动的外部源码。 |
其中 macOS 测试并不只接受 pytest 的退出码。流水线解析 JUnit,要求 60 个指定平台用例实际执行、零跳过且无失败;缺依赖导致全部跳过也会拒绝通过。Python 与 Rust 共享 Hands 契约样例,Mac、iOS 与独立 Python 参考实现共享 Bridge 向量,使参数映射、签名、收件人、篡改和重放的边界可以跨语言核对。
这些结果仍有范围:Swift 类型检查不验证麦克风授权,Linux 单元测试不验证 macOS 内核,模拟信箱不验证生产 CloudKit。测试数量也不是整体覆盖率;重叠套件不能相加成独立场景数。
四组 CI 与实际执行门禁;跨语言 Hands 契约样例;Bridge 参考实现。
发布从精确的源码提交开始
已有成功 CI
Swift / Rust helpers
notarize、staple、Gatekeeper
认证、资源和运行通路
Draft 审阅后正式发布
Release workflow 查询将发布的 SHA 是否有成功 CI,另一个提交通过不能替代。构建使用受锁文件约束的依赖;Python 明确选择 uv 管理的独立解释器,防止 runner 偶然选中 framework build。后端以 PyInstaller onedir 冻结,前端静态资源和 Swift/Rust helper 随 Tauri 应用一起装配。
签名与公证各有作用。内嵌 Mach-O 需要先签名,再由外层应用封装;Developer ID、hardened runtime 和时间戳用于发行。DMG 提交 Apple 公证,随后 staple 票据并用 Gatekeeper 检查。构建脚本保留无签名开发包以及缺少部分凭据时的警告路径,所以“能构建”不自动等于“已经满足公开分发条件”;正式发布应核对真正得到的产物。
更新清单还有独立约束:tag 必须与 Tauri 版本一致;有 updater 签名才生成对应 manifest。流程生成 GitHub Draft Release,正式发布后,已安装应用才会在后续检查中看到该更新。
精确 SHA 门禁、版本检查与 Draft Release;冻结、装配、签名、公证与降级分支;PyInstaller 依赖与资源。
全新安装验收直接启动应用包
fresh_install_check.py 使用临时 HOME 和最小环境启动包内真正的 arslan-desktop,不是在源码 venv 中替它启动服务。检查包含包内没有混入用户数据库或秘密文件、首启初始化、token 的生成与文件权限、未认证请求拒绝、真实 WebSocket 101 握手,以及前端 JavaScript 能被正确取得。HTTP 200 可能只是 SPA 的兜底页面,因此资源检查不能只看状态码。
同一脚本还检查原生 OCR、嵌入 helper、Bridge 自检和相关签名。历史上冻结包曾漏掉动态加载的 WebSocket 依赖:健康接口正常,聊天却不能升级连接。这个问题说明,导入成功、服务存活和核心功能随包交付是三种不同的证据。
应用启动与包内验收;动态 WebSocket 依赖的显式收集。
更新由用户触发安装,并验证下载内容
Tauri updater 从公开的 latest.json 发现更新,用编译在应用中的公钥验证归档签名。应用启动检查一次,菜单也可以手动检查;本版没有周期检查 timer。发现新版本显示提示,用户点击安装后才下载、验签、替换并重启。自动检查失败可以是暂时离线,安装失败则需要向用户明确反馈。
早期 0.1.0/0.1.1 只注册了 updater 插件,没有主动调用检查函数,不能自动发现版本。当前实现把检查、可安装状态、下载失败与重启串成显式流程;有签名配置并不等于流程已经被触发。
0.1.63 的交付证据对应哪个对象
发布提交的 GitHub Actions 记录显示:发布源码为 main 上的 9bbb6ad6;main 上的 CI 首次尝试即通过(run 40502155919),其中 macOS 任务的 60 个指定平台用例零跳过,后端测试 9,469 项通过、124 项跳过。推送 tag 并没有自己启动一次 CI 运行,所以发布门禁使用了 main 上针对同一提交的那次运行。发布流程(run 40505601007)通过了源码验证、构建和发布;DMG 公证被接受并 staple,Gatekeeper 接受。发布应用的 fresh-install 检查 92 项通过、0 项失败,包括 Hands 接受签名后端的连接和 Bridge 自检。
它之前的两个版本:0.1.61 是从 main 上的 fb6d7230 打出的(main 上的 CI run 38489348597、tag CI run 38498094635、发布 run 38498094628;54 个平台用例;后端 8,466 项通过、124 项跳过;fresh install 89/0)。0.1.62 是从 release/0.1.62 的 a4fca23b 打出的(分支 CI run 39112567104、tag CI run 39114206598、发布 run 39114206588;55 个平台用例;后端 8,747 项通过、125 项跳过;fresh install 89/0)。两者都是首次尝试即通过,并经过公证、staple 和 Gatekeeper 接受。
验证对象各不相同,记录也要分开说。0.1.63 的公开说明称,在一个发布候选版上手工过了一小份检查清单,其中两项没有通过(第三次后续编辑改动超出要求,以及通过终端对长文件做的一行改动);说明中没有说精确的 0.1.63 DMG 被手动安装并完整操作过,本文也不这样声称,也不声称用发布版完成过 iPhone 到 Mac 的完整链路。0.1.61 和 0.1.62 的说明中没有本文所依赖的真实 Mac 上的手工实测记录。作为对照,0.1.53 的 Verification 记录过一次真实 Mac 实测:通过 Hands 创建并读回 Notes、审批等待 36 秒——用的是 43751254 的 build-only 包,而非最终 DMG。自动包验收、较早构建的功能实测与精确发行包手工验收应分别陈述,不能互相替代。
12 / 测试与验证如何判断任务做得对
一个任务结束、一份文件能打开、一份报告内容正确,是三种不同的判断。Arslan 用运行记录说明发生了什么,用产物与契约检查验证能够确定的部分,再用真实任务评测观察模型表现。任何一层通过,都不能替代其他层。
先把“完成”拆成可检查的证据
执行是否发生
工具调用有没有返回?退出码是什么?动作结果是明确成功、明确失败,还是未知?模型写下“已完成”不能替代工具证据;结果未知的副作用也不能当作可以安全再执行一次。
交付物是否成立
文件是否存在、属于本任务、字节数与哈希是否匹配、格式能否解析?表格能打开不等于数据正确,图片尺寸正确也不等于排版合格。
任务要求是否满足
要求十条有效结果,六条就没有满足要求。引用来源必须与结论对应;读过网页不能证明其中支持某个说法。这一层仍需要任务专用校验与人工判断。
任务验收体系保留规则检查、模型评估和人工复核的区别。文本、JSON、文件完整性、图像尺寸和实际执行结果可以采用确定性检查;模型评估只能覆盖适合它判断的部分,不能把没有运行的检查改成成功。产物解析成功证明结构可读,来源读取记录证明系统拿到过内容,它们都不自动证明事实或视觉质量。
验收规则与产物检查的边界;0.1.53:未完成任务明确显示 Not done。
测试分层:每层回答一个问题
| 证据层 | 检查对象与例子 | 不能据此推出什么 |
|---|---|---|
| 单元与契约 | 参数校验、状态转换、错误分类、序列化、权限决策;合法输入与篡改、重放等负例 | 真实模型必然选择正确工具,或所有第三方服务永远兼容 |
| 服务集成 | 数据库、运行记录、取消、产物导出、恢复与权限回调真正连通;模型可用确定性替身 | 替身跑通就是自然语言任务被真实模型完成 |
| 平台运行 | macOS 沙箱和系统接口在指定环境实际运行,缺依赖或跳过不能算通过 | 所有系统版本、权限组合与应用都兼容 |
| 最终安装包 | 冻结依赖、前端资源、认证、真实 WebSocket 握手和 helper 随安装包交付 | 所有真实任务的完成率与交互品质已验证 |
| 真实任务评测 | 固定模型、任务、授权与检查规则,多次运行并保存成功和失败 | 小样本代表总体成功率,或普遍优于其他产品 |
| 精确产物的实机验收 | 指定分发包在真实设备、权限状态与服务中完成链路 | 相邻构建或模拟器通过可以替代本次分发包的全部实机检查 |
例如,2026 年 9 月可靠性工作提供了 30 项固定的零外部模型费用契约,真实执行存储、取消、产物、备份和权限等代码,但使用确定性 provider 替身。这是工程契约证据,不是 30 个真实模型端到端任务。后来的付费评测属于另一层证据,二者不能混成同一个成功率。
测试还需要证明自己确实执行了。v0.1.63 的 macOS CI 解析 JUnit 报告,要求 60 个指定平台用例实际执行且零跳过。Hands 的 Python 与 Rust 端使用共享契约样例;Bridge 两端使用共享协议向量。对于关键保护,变异检查会临时破坏规则并确认测试变红,以发现只验证实现表象、没有约束行为的用例。
工程契约与模型质量的区分;平台用例数量与跳过门禁;来源审阅的回归与变异检查。
发布验证必须绑定到源码和产物
完整历史凭据扫描
有对应成功 CI
应用与安装包
隔离配置实际启动
更新产物签名
Fresh-install 检查使用隔离的全新 HOME 启动应用,覆盖认证、WebSocket 的真实 101 握手、前端资源、OCR 和 helper。只检查健康接口返回 200 不够:早期安装包曾在 HTTP 服务正常时完全无法建立聊天连接。
v0.1.63 的发布对应提交 9bbb6ad6:main 上的 CI 首次尝试即成功(run 40502155919;推送 tag 并没有自己启动一次 CI 运行);发布流程(run 40505601007)的源码验证、构建与 Release 步骤成功;DMG 公证被接受并 staple,Gatekeeper 接受。发布应用的 fresh-install 检查 92 项通过、0 项失败,包括 Hands 启动和 Bridge 自检。(0.1.61 和 0.1.62 各自以 89 项全部通过:运行 run 38498094628 和 run 39114206588。0.1.53 因一次顺序相关波动需要第二次 CI 尝试;0.1.54 修复了根因——测试泄漏共享的数据库会话——并加了一道守卫,任何这样做的测试都会失败。)
实机交互证据来自另一份明确标识的构建。Notes 测试中,后台任务通过 Hands 创建并读回笔记,第一次审批卡等待 36 秒后仍能继续;文件重命名任务使用 mv,没有操作 Finder 窗口。这些测试使用较早的 build-only 包,提交为 43751254,与正式发布提交的差异为版本号及说明文档。它不是最终发布的同一个 SHA;0.1.60 的发布说明也明确披露,发布前没有手动安装精确的最终 DMG 完整操作一次。安装检查和较早构建的 Notes 实测应分别陈述。
0.1.63 自己的发布前测试错过了两项标准,说明里也这样写了。九个任务,每个跑三次,分别在 DeepSeek 和 Claude 上,并开启“只在有风险的命令时询问”:任务“删除被拒绝后另找办法”在 Claude 上 3 次中通过 0 次(0.1.62 中是 3 次全过),因为切换到工作文件夹后按名称删除的命令是有意不出卡片直接运行的,原因是“撤回这一轮”可以把文件找回来;而任务“对同一份文档做三次后续编辑”在 DeepSeek 上 3 次中通过 1 次,在 Claude 上 0 次,因为检查器要求把某一节缩短到原长度的 60% 以下,而任务只要求把它改短一些(检查器予以保留)。随版本发布的默认设置,即在每条新命令前都询问,并不是那几轮所跑的配置。这类结果用来找出薄弱处,不是排名。
0.1.63 的发布说明;发布流水线;安装检查;打包与签名。
真实任务数据:保留对照,也保留短板
2026 年 10 月 3 日的 0.1.51 评测使用 deepseek-v4-pro,与当轮 Hermes 对照,四类任务各运行三次。“验收通过”指 checker score=3,不等于运行状态为 done。费用与时间为每类三次运行的均值,包含失败结果;费用按当轮低峰价。时间是首个模型请求开始至最后请求结束的跨度,既不是完整任务端到端耗时,也不是纯模型推理时间。
| 任务 | Arslan 验收通过 / 3 | Hermes 验收通过 / 3 | 均值费用与模型调用区间:Arslan / Hermes | 这组证据说明什么 |
|---|---|---|---|---|
| 提醒事项 | 3/3 | 2/3 | $0.025、76 s / $0.058、142 s | 这轮结果较好,样本仍很小 |
| 职位研究表 | 1/3 | 3/3 | $0.167、313 s / $0.093、160 s | 结果数量与研究完整性仍有缺口 |
| Apple 财务表 | 3/3 | 3/3 | $0.041、77 s / $0.026、36 s | 都通过;对照请求区间更短、费用更低 |
| 整理下载目录 | 3/3 | 3/3 | $0.053、113 s / $0.046、100 s | 验收通过数相同 |
这组实验适合定位改进方向,不适合形成总体产品排名。模型、任务、环境和审批策略都会影响结果。该轮还经历余额用尽与续跑;四次零费用失败请求从计时用的 usage log 中移除,原日志被保留。公开实验记录保留了这些过程条件,读取汇总时也应一并考虑。
版本比较同样需要限制解释:提醒事项样本从 0.1.49 的 1/3 变为 0.1.50 的 3/3,恢复路线和上下文状态在这一阶段得到改进。但版本之间有多项变化,不能把全部差异严格归因于某一条提示词或单个模块。
0.1.51 实验方法与过程;四任务汇总;恢复路线的阶段评测。
模型评审也需要被评审
0.1.41 来源审阅校准中,13 份报告产生 14 个提示:1 个正确、2 个边缘、11 个错误,同时漏掉两项预先登记的已知错误。该能力因此保持默认关闭。调用另一个模型并没有自动获得可靠的事实核查器;格式合法、锚点存在,也不能保证批评内容成立。
0.1.52 的经验学习验证则呈现另一种边界:一次 AppleScript 被拒后,经验被保存、召回,下一次直接选择 EventKit,证明经验能够影响执行。但是后续脚本编辑与检查产生更多调用,没有测出提速。要判断经验本身是否提高效率,需要在相同任务上进行有经验/无经验的配对重复实验;当时的记录明确说明这项公平速度对照尚未运行。
更强的质量结论需要预先冻结任务、交付物和检查标准,记录模型与配置、调用轨迹、实际费用及失败原因,并用独立人工标注校准模型评分。格式不合法的评分、没有运行的检查、无法取得的证据,都应保留自己的状态,不能为了汇总好看而计为通过。
13 / 工程方向从已有能力,走向更可靠的交付
Arslan 已建立执行、持续任务与记忆三条基础。下一阶段值得验证的,是这些能力在更复杂场景中能否保持正确状态、给出可靠结果,并让用户保有控制。下图将已有实现、需要继续验证的环节和可选工程方向分开;它是一份技术讨论,不是带日期的发布承诺。本章反映 v0.1.63;计划在 0.1.64 中做的事会标明是计划,而不是已经做成。
计划在 0.1.64 中做(只是计划,尚未实现;来自已批准的 0.1.64 计划):先做一个默认拒绝的沙箱,管住命令、Python 和安装的工具。然后恢复“只在有风险时问”。再之后是一个可选的“自动”模式:由一个审查模型替你回答一部分卡片;它默认关闭,只有达到事先定好的合格线才会发布,而且绝不批准任何离开沙箱、向外发送或联网的操作。届时会有五种模式,在输入框旁按对话选择:计划、每步都问、自动编辑、完全访问和自动;设置里只保留新对话的默认模式。定时任务会重新可以运行只读命令。在此之前,每条新命令都先询问,定时任务不运行命令。一个列出并可撤销已记住回答的页面,以及一个允许文件夹的设置,目前仍在考虑中,不在计划里。0.1.63 的说明还列出了针对已知限制的两项修复:在同一条命令里切换文件夹之后再删除,被错误地当作在工作文件夹之内;以及对长文件的一行改动是通过终端而不是编辑工具完成的。
图 4 · 能力蓝图。纯文本:已有执行、持续任务、记忆三条基础 → 跨设备和可靠性验收 → 以真实完成率、恢复契约、学习对照实验为优先建议。建议不是已上线承诺。
真实任务效果
固定任务集应覆盖搜索完整性、引用与结论对应、文件可打开性、系统操作的真实落点,以及失败后是否诚实收尾。已有对照暴露了研究任务的差距,而 0.1.63 的发布前运行(九个任务,每个跑三次,在 DeepSeek 和 Claude 上)错过了自己的两项标准:被拒绝的删除之后另找办法(Claude 3 次中 0 次,因为在“只在有风险的命令时询问”下,工作文件夹内的删除不出卡片直接运行)以及对同一份文档做三次后续编辑(DeepSeek 3 次中 1 次,Claude 0 次);扩大工具列表之前,先定位“没找到、没读全、没验证、没正确交付”分别发生在哪一步,更有助于改善完成率。
恢复与跨设备一致性
网络重试、消息重复、应用重启和用户取消可能同时发生。后续验证可以围绕稳定业务 ID、终态不可被旧消息覆盖、审批取消后的行为,以及副作用未知时的核对路径展开。通过崩溃注入与协议负例,明确哪些情况可自动处理,哪些必须回到用户确认。有一块已经做出:自 0.1.63 起,一个回合第一次改动工作文件夹之前会保存一个检查点,“撤回这一轮”会恢复文件并把这一回合移除。它有局限:只保存最多 20,000 个文件、5 GB 的文件夹(不计 Python 环境、node_modules、构建输出和 Python 缓存),保存不了时显示“未保存”;它只覆盖工作文件夹,不覆盖其外的效果。
可测量的学习收益
经验被记住只是起点。需要在相同任务和模型条件下,反复比较有经验与无经验的完成率、调用成本、耗时和错误行为。也要检验过时经验是否会被纠正、外部文本是否可能污染经验,以及删除后是否仍被召回。
平台与扩展的代价
Tauri 提供跨平台宿主基础,但 Seatbelt、Vision、Accessibility、Apple Events 与 CloudKit 都有平台特性。扩展到其他桌面系统,需要替换并验证这些能力,不能把一次跨平台编译当成产品功能已经迁移。更多外部工具同样意味着更多凭证、权限和失败模式。
以上为基于现有实现与测试结果整理的工程方向。具体优先级和排期,以后续正式发布说明为准。
14 / 术语表从术语回到具体实现
术语用于区分不同机制。下表给出简明定义,并把每个概念放回 Arslan 的实现中;历史机制会明确标注。
AI 与上下文
| 术语 | 通俗解释 | 在 Arslan 里怎么用 |
|---|---|---|
| LLM | 理解与生成语言的大模型 | 来自用户配置的供应商;Arslan 负责应用与执行系统 |
| Agent | 会根据结果决定下一步的执行过程 | 调用模型、运行工具、看结果、继续或收尾 |
| Orchestrator | 把不同能力安排到一起的协调者 | 协调模型、上下文、工具、权限与任务状态 |
| Tool calling | 模型用结构化方式请求一个工具 | 工具名和 JSON 参数经过校验才执行 |
| Native tool protocol | 使用供应商正式定义的工具消息格式 | 保持 tool call ID、结果和推理延续正确对应 |
| Trajectory | 模型与工具交互的结构化轨迹 | OpenAI 兼容采用 native history,其他 Provider 保留各自路径 |
| Context window | 模型单次能看到的信息范围 | 不能把所有历史、所有记忆和完整长输出无限塞入 |
| Compaction | 把旧上下文压缩成有界摘要 | 控制请求体,保留近期内容;不等于删除原始会话 |
| RAG | 先找相关资料,再让模型回答 | 从导入知识里检索片段,并带上来源 |
| FTS5 | SQLite 的全文检索 | 擅长找词面匹配,即使没有向量也能查资料 |
| Embedding | 把文本意思转换为数字向量 | 帮助找措辞不同但语义相近的内容 |
| Cosine similarity | 比较向量方向是否相近 | 语义检索的一种相似度计算方法 |
| RRF | 把多种检索结果按名次合并 | 融合 FTS 和向量排名,不直接混合不同单位的分数 |
| Skill | 可复用的“怎么做”说明 | SKILL.md、可选脚本与参考;不是另一个模型 |
| MCP | Agent 与外部工具之间的标准接口 | 通过 stdio 或 HTTP 接外部能力,授权仍需应用控制。自 0.1.63 起,其服务标记为只读的工具无需卡片即可运行,标记为破坏性的工具每次都询问,其余的每个对话询问一次 |
| On-demand tools | 不随每次请求发送、而是在需要时查找的工具 | 自 0.1.63 起,很少用到的工具和 MCP 工具不在每次请求中;模型用 find_tools 找到它们,并按真实名称用 use_tool 调用,所受的审批相同 |
| Streaming | 在模型书写的同时显示回答 | 自 0.1.63 起适用于 OpenAI-compatible 提供商、Claude 和 Gemini;如果流在中途中断,你已看到的内容会保留,回复被标为已中断。原先会拦下回答的检查,现在改为在回答之后追加更正 |
| Steering | 在任务运行时改变它的方向 | 自 0.1.63 起,回复期间输入的消息会在下一步到达它;在最终答案书写期间发出的消息,会在它之后立即运行 |
| Dollar limit per task | 对一个任务的模型花费设的上限 | 自 0.1.63 起默认开启:每个聊天回复或后台任务 $2,约三分之二时开始收尾;只有已知价格的模型才计入;可在 设置 › 后台与主动 中更改 |
| BYOK | 用户自带模型 API 密钥 | 由用户选供应商并承担对应模型调用费用 |
| Prompt injection | 把网页或工具内容伪装成给 Agent 的新指令 | 外部内容按数据处理,未经确认的外部影响经验通常进入提案;这不是彻底免疫证明 |
| Learned practice | 从纠正或成功绕路中记下的方法 | “此机 AppleScript 不通,尝试 EventKit”;不修改模型权重 |
| Shadow mode | 只记录判断,暂不让它改变实际行为 | 判断层为小决定保留它的账本;命令卡片的影子审批建议已在 0.1.63 中移除,每张卡片都等用户点 |
| Held-out evaluation | 留出没用于改提示词的题目来考试 | 早期专家演进的历史设计,不是当前每轮对话的固定步骤 |
软件架构、状态与可靠性
| 术语 | 通俗解释 | 在 Arslan 里怎么用 |
|---|---|---|
| SPA | 在一个 Web 应用里切换页面与状态 | React 工作台由本地服务提供静态资源 |
| Sidecar | 随主应用一起启动的辅助进程 | Tauri 旁边运行的 Python 本地后端 |
| IPC | 同一电脑上进程之间的通信 | 管道、Unix socket;不是所有模块都通过云通信 |
| REST / HTTP | 一次请求获取或修改一个资源 | 设置、历史、任务与文件管理接口 |
| WebSocket | 保持双向连接持续推送信息 | 回复流、工具状态、审批与进度事件 |
| Async I/O | 等待 I/O 时让出事件循环,供其他任务推进 | Python asyncio、异步 API 与数据库访问;不等于 CPU 任务无限并行 |
| Schema / Contract | 输入、输出和合法状态的明确约定 | Pydantic、工具参数与任务验收契约 |
| State machine | 用有限状态描述一个流程走到哪 | queued、running、waiting_user、verifying、succeeded 等 |
| Checkpoint | 记录走到哪、做过什么、还剩什么 | 任务恢复用引用、证据和预算,不盲目重播未知副作用。自 0.1.63 起有第二种:在一个回合第一次改动工作文件夹之前保存的该文件夹副本,“撤回这一轮”会恢复它(只针对最多 20,000 个文件、5 GB 的文件夹;否则撤销窗口显示“未保存”) |
| Attempt | 任务的一次执行尝试 | 恢复产生新尝试,旧异步结果不能覆盖新轮状态 |
| Optimistic concurrency | 写入前确认数据还是自己刚才看到的版本 | row version 和 attempt ID 防止旧结果覆盖取消或更新 |
| Idempotency | 重复请求不应造成意外重复操作 | 消息/任务 ID 防重;外部未知效果还需要核对 |
| ACK | 接收方说“这个包我收到了” | 不表示任务做成,也不表示审批已经生效 |
| Single-flight | 上一轮没结束,就不重叠启动同一项 | 定时任务避免一层层堆积重复执行 |
| Backoff | 失败后逐渐拉长重试间隔 | 限流/服务错误退避,尊重 Retry-After;认证错误不盲重试 |
| WAL | SQLite 先写日志,改善读写共存 | 本机数据持久化;仍有写并发边界 |
| Migration | 把旧数据库结构安全升级到新结构 | 显式版本 runner、升级前备份、拒绝未知 schema |
| Provenance | 一条信息从哪里来 | 文档来源、记忆来源、真实运行轨迹 |
| Observability | 出现问题时能看见发生了什么 | Run/Step、Activity、usage、错误与产物关联 |
操作系统、安全与交付
| 术语 | 通俗解释 | 在 Arslan 里怎么用 |
|---|---|---|
| Sandbox / Seatbelt | 由操作系统限制进程可访问的资源 | 计算沙箱和命令沙箱规则不同,网络与降级行为分别说明 |
| Fail-closed | 保护层不可用就拒绝执行 | 适用于默认 Python 沙箱和离线收尾路径;不能套用全部普通命令 |
| Accessibility tree | 系统暴露的窗口、按钮、文本等结构 | Hands 读取和定位控件,不依赖截图像素识别 |
| TCC | macOS 的隐私权限管理体系 | 辅助功能、麦克风、Apple Events 等不是应用自己点个开关就获准 |
| SSRF | 诱导服务访问不该访问的内部地址 | 网页提取和外部 URL 需要校验目标、重定向与网络边界 |
| AEAD | 同时保护内容秘密性和完整性的加密方式 | Bridge 使用 ChaCha20-Poly1305,篡改后验证失败 |
| Key agreement / Signature | 前者协商加密材料,后者验证发送者身份 | X25519 与 Ed25519 职责不同,不要混说 |
| Replay protection | 不让攻击者重复投递旧消息再次生效 | 签名、收件人、序号滑窗、持久去重共同作用 |
| CI / CD | 把构建、检查与分发流程自动化 | 成功 CI 必须对应待发布 SHA,最后产物还要检查 |
| Contract test | 验证边界两端遵守同一协议 | Python/Rust、Mac/iPhone 共享正例和负例向量 |
| Mutation testing | 故意弄坏保护逻辑,看测试能否抓住 | 用于证明特定断言有区分度,不是换个名字的普通单元测试 |
| Code signing | 验证软件来源与产物未被修改 | App 与内嵌 helper 都需要正确签名 |
| Notarization / Staple | Apple 检查发行包,再把票据附到包里 | 与签名不同,还要用 Gatekeeper 验收结果 |
| Fresh-install acceptance | 模拟没有开发环境、没有旧数据的新用户 | 验证真正安装包的认证、WebSocket、资源与 helper |
当前系统主要是本地分层单体加独立 helper。SQLite 与进程内异步调度适配个人桌面产品的安装和运行方式;相关术语都应在这一部署规模下理解。
15 / 常见问题使用与理解 Arslan 时,最容易混淆什么
Arslan 与直接在模型网页里聊天有什么区别?
Arslan 在模型之外提供本地文件、工具、任务状态、记忆、授权和桌面集成。模型负责判断与生成,应用负责把工具请求变成受控执行,并记录结果。它的价值取决于整个过程能否完成具体任务。
项目是一个人用 AI 做的吗?
是。Arslan 由作者独立通过 AI 辅助开发,也就是 vibe coding,持续构建和迭代。产品使用开源框架、第三方组件和外部模型,相关来源与许可分别记录在项目文档中。
所有内容都留在本机吗?
数据主存储和执行编排在本机。使用云模型、搜索、远端 MCP 等能力时,相关请求会发往对应服务。记忆还有独立的云端使用许可和敏感性规则;本地优先不等于全程断网。自 0.1.63 起,Anthropic 自己 API 上的 Claude 对话用 Anthropic 自己的网页搜索。使用本地模型的对话绝不会把查询发给提供商自己的搜索;在设置中选择的 Tavily 或 SearXNG 可以作为唯一的搜索,也可以作为备用;没有明确选择时,尽力而为的 DuckDuckGo 抓取排在最后。
可以换模型或接本地模型吗?
可以配置支持的供应商或兼容端点,包括 OpenAI 兼容的本地服务。端点可连接只证明传输可用;工具调用、图片、推理延续和上下文长度还要符合该模型与适配路径的能力。
为什么早期文档里有很多专家分身,现在只看到一个 Arslan?
项目经历了产品收敛。0.1.44 停止专家创建与调度,0.1.46 关闭旧自动演进循环,0.1.48 移除前置路由。随后 0.1.63 删除了已没有任何回复能走到的专家时代代码(创建专家、专家模板和引擎、进化与整理机制、研究审阅,以及对话菜单里的“Distill”);由旧专家启动的任务在恢复时由 Arslan 接着做。旧方法可转为 Skill,历史数据保留兼容,受限只读 workers 仍用于独立研究。
记忆、知识库和聊天历史是一回事吗?
不是。聊天历史记录对话,工作上下文选取近期内容与摘要;个人记忆保存带来源和权限的偏好、事实与规则;知识检索从导入资料中找相关片段。三者的存储、召回与删除语义不同。
“学习经验”会训练模型,或者让它自行获得更多权限吗?
不会。当前学习记录可复用的方法并在后续任务中召回,不修改基础模型权重,也不改变执行授权。已有记录显示经验可以被捕获、召回和遵循;普遍提速或节省成本仍需要更多对照实验。
所有命令都在断网沙箱里执行吗?
不是。默认 Python 计算沙箱拒绝网络;普通终端的工作区沙箱通常保留网络访问,并有单独的降级行为。工具权限、命令策略、系统权限和沙箱是不同层,具体差异见安全章节。自 0.1.63 起,默认情况下每条新的终端命令都先显示一张卡(“只在有风险时问”是一个明确的选择,并会说明它会漏掉什么),而定时任务完全不运行命令:这样的步骤会被跳过,并列在收件箱中。
关掉聊天窗口后,任务会怎样?
连接和任务分开管理,后台 job 可以在应用服务继续运行时执行;窗口关闭也不能直接等同于进程退出。自 0.1.63 起,长时间的工作留在聊天中,而不是被自动转到后台,十分钟后回复会告诉你它仍在工作。若服务退出或 Mac 休眠,任务不能继续依赖本地执行。重启后通过记录检查中断情况,再按支持的路径显式恢复。
恢复会自动重新执行先前的每个动作吗?
不会。恢复需要检查已有步骤与外部效果,未知副作用先核对。任务尝试、动作状态、检查点和版本约束帮助防止旧结果覆盖新状态,但不能为所有外部系统提供恰好执行一次的保证。
Hands 可以操作任何 Mac 应用吗?
兼容性依赖应用暴露的 Accessibility 结构、系统授权和 Arslan 的动作规则。可读取控件不等于可安全完成所有业务操作。敏感按钮与按键会触发更细的确认,部分应用或控件仍可能不支持。自 0.1.61 起,Hands 对查看一个应用和在其中执行动作只询问一次(先是“本任务内”);删除、发送、支付和提交仍然每次询问,Hands 的 AppleScript 工具也是如此。
iPhone 能在 Mac 关机时替它完成任务吗?
Mac Bridge 路径仍由 Mac 执行,Mac 不可用时消息会在 iCloud 等待。v0.1.53 发布了 Mac 侧 Bridge,v0.1.54 为 iPhone App 做好了准备,0.1.61 在 Mac 一侧增加了来自手机的文件和实时对话;发行说明仍将 Arslan for iPhone 1.0 描述为即将上架,这不等于它已经在那里。手机显示消息已收到,也不等于任务已做成。
我能撤销 Arslan 对我文件做的事吗?
部分可以。自 0.1.63 起,Arslan 会在一个回合第一次改动你的工作文件夹之前保存一个检查点,“撤回这一轮”(在回复的 ⋯ 下)会把文件放回去,并把这一回合从对话中移除。只有当文件夹最多有 20,000 个文件和 5 GB(不计环境、node_modules、构建输出和缓存)时才会保存,保存不了时撤销窗口会显示“未保存”。它覆盖工作文件夹,不覆盖别处的效果,例如已经发出的消息。
我能防止任务花费过多吗?
自 0.1.63 起,每个聊天回复和每个后台任务默认在模型花费 $2 时停止,约三分之二时开始收尾。可在 设置 › 后台与主动 › 每个任务的美元上限 中更改。只有已知价格的模型才计入。
Arslan 工作时我能改变方向吗?
可以,自 0.1.63 起。在 Mac 窗口里、iPhone 上或按住说话输入的消息,会在下一步到达正在运行的回复,尚未开始的步骤会被跳过。如果回复已经在写最终答案,你的消息会在它之后立即运行。
测试都通过,就意味着任意真实任务都能完成吗?
测试只覆盖各自的条件:单元测试检查局部逻辑,协议测试检查边界一致性,安装验收检查产物,真实任务对照检查指定模型与任务下的效果。模型、网页、系统权限和外部应用都可能改变结果。
为什么版本号还在 0.1.x?
项目仍处于 pre-v1 的持续迭代阶段。五十多个编号反映了迭代历程;判断成熟度应结合具体能力、失败处理、测试范围与发布状态。本文的完整版本附录保留了这些差别。
16 / 版本附录从 0.1.0 到 0.1.63 的完整变化记录
本附录覆盖 v0.1.0–v0.1.63 共 64 个稳定格式版本标签,以及 0.1.40 的预览支线和 0.1.59 的 beta。以 2026 年 10 月 27 日核对的公开发布记录为准,GitHub 当前可见 63 个正式 Release 和 6 个预发布 Release,共 69 个。v0.1.39 有版本标签,但当前没有对应公开 Release。
最新正式版 v0.1.63 发表于北京时间 2026 年 10 月 27 日 22:26:31;原始 UTC 时间是 10 月 27 日 14:26:31。下表统一使用北京时间的日期。除明确标出的 v0.1.39 标签日期外,日期均来自 Release 的 published_at,不以提交日期代替发布日期。
正式版 · 高度=距上一个标签的提交数(对数刻度)预发布只有标签,没有公开 Release最新
鼠标移到线上,看版本、日期和提交数;点击打开该版本的 Release。
| 版本 | 北京时间 | 发布状态 | 主要变化 |
|---|---|---|---|
| v0.1.63 | 2026-10-27 | 正式发布 | 回复中途改变方向、回答随书写显示、撤销一个回合 每条新的终端命令默认先询问,定时任务不运行命令;回复期间输入的消息会在下一步到达它;回答随书写流式显示(OpenAI-compatible 提供商、Claude、Gemini);最多四个连续的读取同时运行;“撤回这一轮”从检查点把工作文件夹放回去;文件以附件形式返回,iPhone 上也一样;先用模型自己的搜索;每次请求携带的工具更少;MCP 工具按它们的作用来询问;每个任务 $2 的上限;桌面应用的服务被锁紧;专家时代的代码被移除(产品代码比 0.1.62 少 12,514 行)。说明中列出了被挪到 0.1.64 的事项,以及两项没有达到的发布前标准。 |
| v0.1.62 | 2026-10-18 | 正式发布 | 长命令能跑完、更少的“需要你检查”、MCP 工具不会让聊天失败 一次修复版本。终端命令按它所请求的时长运行(默认 2 分钟,最多 10 分钟),时间限制会保留它已打印的内容;“需要你检查”只用于动作可能在 Mac 之外留下痕迹、而 Arslan 无法判断的情形;MCP 工具描述被重塑为 Anthropic、OpenAI-compatible 提供商和 Gemini 都接受的形式,提供商仍然拒绝的工具会被排除,而不是让回复失败;常见终端写法的 osascript 和 shortcuts run 每次都询问;写入文件绝不顺着链接跑出工作文件夹。更正了 0.1.61 说明里的两行。 |
| v0.1.61 | 2026-10-14 | 正式发布 | 同一张审批卡通行各处、MCP 服务自行启动、Claude 重新可用 从 Claude Opus 4.7 起的模型不再因为它们拒绝的 temperature 设置而收到 400 错误(该设置只发给接受它的模型,提供商不再接受某个可选设置时,会被去掉并记住);你开启的每个 MCP 服务都在后台启动(一次最多四个),“能力”页和模型读取同一个状态;聊天、收件箱、Island 和 iPhone 上是同一张审批卡,选项为“一次”或“本任务内”、“本对话内”、“始终”,以及附带备注的“否…”,有 30 分钟可以回答,超时不算“否”;iPhone 的文件保存在 Mac 的 Inbox/iPhone 下,手机上有实时对话;在假 IP 代理之后也能读取网页,页面读取会表明自己的身份。 |
| v0.1.60 | 2026-10-11 | 正式发布 | Hands v2:像你一样使用 Mac 应用 可以看它正在操作的那一个窗口的画面(从不截整个屏幕、从不保存);批量执行、直接选菜单、在后台打开应用;一张卡片覆盖多个应用,信任的应用可以永久允许,而删除、发送、付款和提交每次仍要询问;借用前台约一秒、去另一个桌面(两者都可以关闭),以及只有你同意时才接管屏幕、最多 30 分钟;新的首次启动;在 iPhone 上解除配对,Mac 上也会移除。 |
| v0.1.59 | 2026-10-11 | 正式发布 | 对话跟得上、用你的语言回答、做完的工作算完成 长回答不再显示“已中断”,回答中发来的第二条消息排队等待;用你写的语言回答;做成了的后台工作算完成(落盘的文件夹在磁盘上核对,读过的文件计入);“桌面、文稿、下载:关”对命令同样生效;Arslan 不在前台时发出的审批会等待,而不是让这一轮失败。此前有四个 beta。 |
| v0.1.58 | 2026-10-09 | 正式发布 | 回复读得懂、文件打得开、模型随你选 Arslan 做过的事收成回复下方一行,展开是白话句子;写出的文件以卡片返回;右侧统一的工作台(任务、文件、浏览器),阅读器支持文本、表格、图片、PDF 和沙箱中的 HTML;每个对话可选任意服务商的任意模型,可设为默认,并显示上下文占用;还有未完成检查点时不再直接过关。 |
| v0.1.57 | 2026-10-09 | 正式发布 | 能力自己长 某一步需要 Arslan 还不会的事时,它搜索 MCP Registry、GitHub 和经审核的 Skill 库,用卡片询问,固定版本安装且安装时不运行代码,扫描后在默认拒绝的沙箱里运行,测试一次再重试那一步。“能力”页新增发现、“Arslan 找到的”和每项能力的档案;GitHub 上的 Skill 固定到某个提交。 |
| v0.1.56 | 2026-10-09 | 正式发布 | 项目分两层 所有项目一块看板(想法、成形、在做、完成),每个项目各有关卡,按项目类型起草、不调用模型。Arslan 凭文件、你说的话和做完的运行为检查点打勾;过关只是提议,“完成”和“放弃”由你来定。Hands 每个请求最多执行一次,如实报告“已发送,未确认”。 |
| v0.1.55 | 2026-10-08 | 正式发布 | 所有需要回答的地方,一个样子 卡片、对话框和提示统一设计;卡片排进同一个队列;⌘⏎ 允许、Esc 拒绝。Island v2 可直接回答卡片,有风险的步骤改为在 Arslan 中打开。收件箱集中放等你决定的事;设置收成七处;记忆合为一页;能力改成开关;Arslan 知道自己的版本。 |
| v0.1.54 | 2026-10-08 | 正式发布 | 为 iPhone 版就绪,终端闸门更严 Touch ID 审批生效;同一台 iPhone 重新配对替换旧条目;移除手机会删除 iCloud 中留给它的消息;设置显示正在连接…/已连接。终端闸门检查命令链中的每一条,“不再询问”须覆盖命中的全部规则,访问 token 只给已持有它的调用方,后台任务保持在沙箱内。iPhone App 仍标注即将上架。 |
| v0.1.53 | 2026-10-06 | 正式发布 | Arslan Hands 与 iPhone Mac 端 以独立 macOS helper 持有 Accessibility 权限,读取 AX 树并操作 Mac 应用;按应用授权、敏感动作逐次确认、可停止与追踪。Mac 侧 Bridge 纳入,iPhone App 标注即将上线。 |
| v0.1.52 | 2026-10-03 | 正式发布 | 记忆真正进入模型 “关于你”与“Arslan 对这台 Mac 的备注”两组条目常驻上下文;可搜过去对话;纠正和成功替代路线形成可撤销 learned practices;普通沙箱脚本少打扰。 |
| v0.1.51 | 2026-10-03 | 正式发布 | 刘海岛与命令沙箱 Island 在刘海处显示任务与进度,悬停可看计划,需要确认时自动展开,并提示完成或已停止;run_command 默认限制写入工作目录/临时/缓存,保护 key 文件,越界需用户授权。 |
| v0.1.50 | 2026-10-03 | 正式发布 | 上下文与交付收尾 加入 agent_status、update_plan、失败替代路线、能力真实性修正、链接校验和更可靠的文件落盘;重做 Activity 统计。 |
| v0.1.49 | 2026-10-02 | 正式发布 | 原生工具协议执行层 OpenAI-compatible 使用 native tool calling 和规范工具历史;保留 reasoning、处理截断、退避重试、流式 watchdog,长输出完整落盘,搜索修复。 |
| v0.1.48 | 2026-10-01 | 正式发布 | 统一 Agent 回路 删除前置 router 和专家执行链路,每条消息直接交给 agent;默认工作目录 ~/Arslan、终端、浏览器自动准备、Activity 和任务工作区统一。 |
| v0.1.47 | 2026-09-30 | 正式发布 | 主动收件箱 确定性检测未完成任务、失败调度、网页或目录变化,生成带证据的 Inbox 建议;用户选择去办才启动后台工作。 |
| v0.1.46 | 2026-09-30 | 正式发布 | 紧凑设置与停止无效花费 Settings 侧栏固定、右侧独立滚动;停止已退役专家的后台自我演化消耗。 |
| v0.1.45 | 2026-09-30 | 正式发布 | 浏览器与 Mac 动作 加入自己的浏览器动作、Shortcuts 和 AppleScript;动作放后台;网站与快捷指令各首次询问一次,AppleScript 每次都询问。 |
| v0.1.44 | 2026-09-30 | 正式发布 | One Arslan 停止创建和调度专家;旧专家可转成 Skill,定时任务统一由 Arslan 执行;只读失败不再终止整轮,副作用结果未知则避免重复。 |
| v0.1.43 | 2026-09-30 | 正式发布 | 预算到点先收尾 后台任务采用独立预算;达到软限后结束搜索并交付现有成果,真正失控才硬停。 |
| v0.1.42 | 2026-09-28 | 正式发布 | 后台工作与自由对话 长期工作放到后台 job,聊天可继续;展示完成标准、进度和 Stop,最多并行 3 个 job;重启后明确标记中断。 |
| v0.1.41 | 2026-09-27 | 正式发布 | 常驻菜单栏 关闭窗口改为隐藏并继续工作;加桌面通知和运行时防自动休眠;来源审阅改为默认关闭的保存后建议。 |
| v0.1.40 | 2026-09-26 | 正式发布 | 日常研究助手稳定版 把项目记忆、任务延续、文档来源证据和工作区整合到稳定版;迁移前自动校验备份,提供原生手动备份。 |
| v0.1.39 | 2026-09-14(标签日期) | 有标签;当前无公开 Release | 聚焦桌面设置(tag) 改进桌面 Settings 布局、侧导航和 API key 显示。版本标签存在,但当前公开 Release 清单没有该版本;日期为标签日期。 |
| v0.1.38 | 2026-09-14 | 正式发布 | 可靠性地基 加强 Python 默认拒绝沙箱、独立计算运行时、持久 Runs/检查点/产物、共享执行预算、recipes 与恢复;加入 Gemini 原生工具调用;增加非回环 HTTP/WebSocket 认证防护与受限 MCP 环境。 |
| v0.1.37 | 2026-09-03 | 正式发布 | 半双工语音对话 加入说完即发送的语音对话;修复麦克风权限和朗读语言选择。 |
| v0.1.36 | 2026-09-02 | 正式发布 | 按住说话 加入按住录音的语音输入。 |
| v0.1.35 | 2026-09-02 | 正式发布 | 安装版代理发现 修复打包应用发现系统代理的路径。 |
| v0.1.34 | 2026-09-01 | 正式发布 | 迁移修复 修复曾记录成功却没有实际完成的迁移。 |
| v0.1.33 | 2026-09-01 | 正式发布 | 连接状态以实测为准 统一 provider 连接状态并在启动时检测,让绿色状态代表实际可用。 |
| v0.1.32 | 2026-08-31 | 正式发布 | 语音输出 可把回复朗读出来。 |
| v0.1.31 | 2026-08-31 | 正式发布 | 默认可读常用文件夹 扩大默认只读范围到 Desktop、Documents、Downloads。 |
| v0.1.30 | 2026-08-31 | 正式发布 | 解释模型服务拒绝 把三类 provider 拒绝转换为可理解的原因。 |
| v0.1.29 | 2026-08-23 | 正式发布 | 已拥有内容搜索 搜索现有资源;记忆收件箱支持键盘处理并防止误删除;依据验证解除 FastAPI/Starlette 版本上限。 |
| v0.1.28 | 2026-08-23 | 正式发布 | 装备处解释不生效原因 在装备入口解释 provider 无法调用工具的限制;修复多个页标题泄露 i18n key。 |
| v0.1.27 | 2026-08-21 | 正式发布 | 网络发现与 SSH 增加网络发现、远程机器记录与 SSH 执行;每次远程执行都询问,并修复 aiosqlite 并发错误归因。 |
| v0.1.26 | 2026-08-21 | 正式发布 | 自然语言定时工作 让 Arslan 创建定时任务、列出已建任务,并可设置一份按周期自行重读的清单(默认关闭);加入调度授权卡、输出预算和错误说明。 |
| v0.1.25 | 2026-08-20 | 正式发布 | 本地工作区读写 可读取工作区,写入经会话授权后执行;改善 Discover 结果说明。 |
| v0.1.24 | 2026-08-20 | 正式发布 | 扩展清单与装备可见性 识别 arslan.plugin.json;以 MCP server 为粒度确认装备,显示扩展作者提供的配置并让 Arslan 知道自己实际能力。 |
| v0.1.23 | 2026-08-17 | 正式发布 | 切换聊天仍继续执行 通过 turn journal 和重新挂接回放保留正在回答的轮次;打包应用能找到 npx。 |
| v0.1.22 | 2026-08-16 | 正式发布 | OAuth 与首次引导 打通远程 MCP OAuth、OpenRouter 登录和四步首次引导;更新检查状态可见,桌面 shell 在每次 push 编译。 |
| v0.1.21 | 2026-08-13 | 正式发布 | 模型槽 UI 与连接修复 为按任务模型槽提供可操作界面;修复 Anthropic 工具 schema 传输,支持受 SSRF 约束的自托管 SearXNG。 |
| v0.1.20 | 2026-08-09 | 正式发布 | 密钥三态、搜索与模型分工 区分未配置、可解密、不可解密的密钥状态,稳定数据库盐迁移;加入零 key 搜索兜底、搜索来源和错误、按任务模型槽与回答模型展示。 |
| v0.1.19 | 2026-08-04 | 正式发布 | 启动动画与新会话 加载后端时播放启动动画;启动进入新会话,清理未使用空会话,改用 blob URL 解决启动视频在 WebKit 中不播放,并修正打包检查。 |
| v0.1.18 | 2026-08-03 | 正式发布 | 界面回归和设置完善 修复浮层自行消失;完善 LLM 布局、系统主题、OCR 选择和相关提示。 |
| v0.1.17 | 2026-08-03 | 正式发布 | 旧专家沙盒会话连续性 返回主对话不再销毁专家试用会话;旧专家可读取主对话最后一轮作为只读背景。 |
| v0.1.16 | 2026-08-03 | 正式发布 | 浮层交互一致性 修复菜单越界和关闭方式;防止编辑弹层静默丢修改,并修正端口探测。 |
| v0.1.15 | 2026-08-02 | 正式发布 | 会话重启恢复 保证会话在重启后保留,澄清回答后继续保留旧专家邀请状态。 |
| v0.1.14 | 2026-08-01 | 正式发布 | 设置重组 重新分组 Settings,把消耗控制集中到一处。 |
| v0.1.13 | 2026-08-01 | 正式发布 | 空状态、国际化与预算/截断修复 修复 Skill 注入截断、并发演化预算归还问题;补齐空状态和后端国际化。 |
| v0.1.12 | 2026-07-31 | 正式发布 | 能力与界面补全 加入能力适配矩阵、Brain 搜索、OCR 语言选择、Playwright MCP 预设;约束演化评估消耗并增加打包存活检查。 |
| v0.1.11 | 2026-07-29 | 正式发布 | 系统 OCR 兜底 视觉模型无法读取时,使用 macOS Vision OCR 兜底;补齐系统语言过滤与打包验收。 |
| v0.1.10 | 2026-07-28 | 正式发布 | 保留模型错误详情 将 provider 原始错误正文传递到异常,避免只给笼统失败。 |
| v0.1.9 | 2026-07-28 | 正式发布 | 图片与扫描 PDF 将图片贯通输入、三类 provider、聊天及旧专家路径;扫描 PDF 按受限页数栅格化供视觉模型读取。 |
| v0.1.8 | 2026-07-28 | 正式发布 | 聊天与窗口回归修复 修复空白聊天、失效拖放区和不可拖动窗口三项回归。 |
| v0.1.7 | 2026-07-28 | 正式发布 | 打包后的 WebSocket 热修复 修复安装版无法连接 WebSocket 导致聊天不可用;文件未实际存入时不再显示已喂入成功。 |
| v0.1.6 | 2026-07-27 | 正式发布 | 布局与可访问性 修复 Skills 溢出、重复标题、交互名称和布局细节。 |
| v0.1.5 | 2026-07-27 | 正式发布 | 非阻塞更新提示 增加角落更新胶囊,不用阻塞对话框;修复更新检查前状态。 |
| v0.1.4 | 2026-07-27 | 正式发布 | 桌面优先与国际化 安装叙事改为桌面优先;后端输出稳定翻译 key,清理剩余硬编码中文并增加回归约束。 |
| v0.1.3 | 2026-07-27 | 正式发布 | 安装与浮窗 阻止从 DMG 直接运行;修复浮窗标题栏与拖动权限。 |
| v0.1.2 | 2026-07-27 | 正式发布 | 自动更新真正检查 补齐更新检查调用;此前已有更新管道但没有实际发起检查。 |
| v0.1.1 | 2026-07-27 | 正式发布 | 首启聊天与草稿 修复首次启动发送、保留聊天草稿,整理 Settings 布局并补齐 Brain/Diagnostics 本地化。 |
| v0.1.0 | 2026-07-27 | 正式发布 | 首个桌面安装版 把此前的 Meta-Agent、记忆、工具和研究能力打包为 Tauri 桌面应用;Python 后端以 PyInstaller sidecar 随应用发布,建立签名、公证、安装验收和自动更新产物。 |
0.1.40 的预览支线:编号存在不代表已经发布
公开预发布版是 beta.3、beta.5 和 beta.6。beta.1、beta.2 保留候选标签与相关记录;beta.4 未单独发布,改动并入 beta.5。不能把六个编号理解为六次面向用户的公开预发布。
| 预览版本 | 北京时间 | 证据状态 | 变化与范围 |
|---|---|---|---|
| v0.1.40-beta.1 记录 | —(无公开发布日期) | 未发布候选;保留标签 | personal companion 预览候选 项目/记忆/任务工作区、可调整侧面板、只读公共网页与受限文件输入。beta.2 文稿明确 beta.1 未发布,其云构建因 AnyIO 公告取消;tag 保留。 |
| v0.1.40-beta.2 记录 | —(无公开发布日期) | 未发布候选;保留标签 | 安全补丁候选,CI 阻挡发布 AnyIO 锁定版本修复;签名构建/65 fresh-install 通过,但同 tag CI 未通过,文稿明确 DO NOT PUBLISH。不能以打包成功替代同一提交的 CI。 |
| v0.1.40-beta.3 | 2026-09-20 | 公开预发布 | 首个当前可见公开预览 整合工作区、只读浏览、文件来源、六语言资源和安全修复;发布开始强制 exact-source CI 先通过再签名。仍非 companion v1.2 完成。 |
| v0.1.40-beta.4 记录 | —(无公开发布日期) | 未单独发布;说明文稿 | 未单独发布的身份与信任澄清 设置显示真正运行的客户端版本和稳定/预览通道;可复制精简身份摘要。beta.5 明确将 unpublished beta.4 改动包含进去,无需单独安装。 |
| v0.1.40-beta.5 | 2026-09-23 | 公开预发布 | 研究证据与连续性 已读/未读/部分读取标签、受限来源链接、Word 当前文本抽取与修订披露、损坏轨迹容错;有受限模型 pilot,但不是 12/12 完整通过。 |
| v0.1.40-beta.6 | 2026-09-23 | 公开预发布 | 视觉和应用身份打磨 更新图标,允许磨砂橙/纯单色选择;修复 WebKit 启动圆角和排版。手动安装预览,稳定自动更新通道保持原样。 |
beta.2 是发布状态需要单独记录的一个例子:签名构建与安装检查成功,但该标签的 CI 没有通过,文稿明确要求不发布。beta.3 随后加入“待发布提交必须有成功 CI”的门禁。beta.5 又明确说明其包含未发布 beta.4 的改动,不需要先安装 beta.4。
如何追溯一项变化
正式发布条目链接到对应 Release;v0.1.39 链接到版本标签。更新摘要综合正式发布说明和相邻标签的提交,不把仅存在于计划文档的功能写成已交付。需要检查具体实现时,应固定到该版标签或发布提交,避免使用不断变化的 main 解释过去版本。
仓库中的部分发布文稿仍保留构建前的 HOLD 或草稿说明。这些文件能够说明当时的发布过程,但不应单独用于判断当前是否公开发布;公开 Release 的状态与最终验证记录需要一并核对。此处“当前无公开 Release”描述本次可见状态;发布文稿显示 v0.1.39 与 beta.2 曾有未发布的 Release 草稿,目前已不在 Release 列表中。
全部公开 Releases;版本标签;beta.3 的同提交 CI 验证;beta.5 对未发布 beta.4 的说明;当前正式版本。
17 / 版本基线与源码入口让文档中的结论可以回到证据
本文按固定版本说明实现,交叉核对公开发布记录、Git 标签与历史、发布提交源码、架构决策和公开验收材料。较早设计用于解释演进;已经被后续代码替换的行为,会标为历史。作者的独立 AI 辅助开发方式来自作者说明。
| 对象 | 采用的基线 |
|---|---|
| 正式版 | v0.1.63 · 9bbb6ad653b48f8c1e63c649b6f7217f074d6dad |
| 发布时间 | 北京时间 2026-10-27 22:26:31;UTC 2026-10-27 14:26:31 |
| 核对截止 | 2026-10-27。日期字段默认使用北京时间;Git 实现节点与 Release 发布日期分开标注。 |
| 发布后开发 | 9bbb6ad6 之后 main 上的改动,在随正式版发布前不计入 v0.1.63。 |
| 版本范围 | v0.1.0–v0.1.63 共 64 个连续标签;63 个当前公开正式 Release;0.1.39 单独标明为仅标签。另列 0.1.40 的六个 beta 编号和 0.1.59 的四个 beta 及其不同发布状态。 |
按问题找到对应实现
- 项目怎样演变:公开 Release;最早可追溯提交;One Arslan;统一循环。
- 程序怎样开始工作:桌面生命周期;本地服务入口;Agent 入口;工具循环。
- 模型怎样接入:适配器;工具轨迹;执行预算。
- 任务怎样落盘与恢复:任务契约;状态、持久化、尝试隔离与检查点;验收;备份还原后的审批作废与任务隔离。
- 记忆怎样使用与清除:个人上下文;资料检索;经验;记忆持久化;版本化迁移。
- 能力怎样扩展:内建执行器;插件清单;MCP;只读 workers。
- 权限由谁执行:终端策略;命令沙箱;执行与降级;Hands helper。
- 手机怎样连接:Bridge 协议;Bridge 生命周期;事件与审批映射。
- 怎样评估与发布:0.1.51 真实任务对照;0.1.52 验收;安装验收;发布工作流。
- 开源来源与反馈:许可证;第三方归属;安全反馈政策;项目 Issues。
这份文档描述特定版本及其可核对边界。对于后续版本,应同时阅读对应 Release 和源码;架构方向、设计意图、测试覆盖与正式交付分别说明,方便读者判断每个结论适用于哪里。
Arslan 技术文档 · 基于 v0.1.63(源码 9bbb6ad653b4),核对 2026-10-27。内容会随新版本更新;源文件在仓库的 docs-site/ 目录。