work-ally 0.2.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +110 -0
- package/DASHBOARD.md +160 -0
- package/PRODUCT.md +113 -0
- package/README.md +403 -0
- package/ally.sh +171 -0
- package/bridge/src/approval-rules.ts +360 -0
- package/bridge/src/channel-delivery.ts +207 -0
- package/bridge/src/channel-types.ts +22 -0
- package/bridge/src/channels/fake/adapter.ts +31 -0
- package/bridge/src/channels/feishu/adapter.ts +411 -0
- package/bridge/src/channels/feishu/approvals.ts +6 -0
- package/bridge/src/channels/feishu/formatter.ts +276 -0
- package/bridge/src/channels/feishu/normalize.ts +368 -0
- package/bridge/src/codex-config.ts +52 -0
- package/bridge/src/config.ts +240 -0
- package/bridge/src/fake-runtime-client.ts +505 -0
- package/bridge/src/handoff-service.ts +494 -0
- package/bridge/src/logger.ts +194 -0
- package/bridge/src/memory-digest.ts +186 -0
- package/bridge/src/receiver-approval-autonomy.ts +158 -0
- package/bridge/src/receiver-control-core.ts +140 -0
- package/bridge/src/receiver-control-work-session.ts +218 -0
- package/bridge/src/receiver-control.ts +83 -0
- package/bridge/src/receiver-delivery.ts +136 -0
- package/bridge/src/receiver-helpers.ts +96 -0
- package/bridge/src/receiver-human-gate.ts +333 -0
- package/bridge/src/receiver-inbound-preflight.ts +162 -0
- package/bridge/src/receiver-recovery.ts +236 -0
- package/bridge/src/receiver-runtime-callbacks.ts +367 -0
- package/bridge/src/receiver-runtime-policy.ts +132 -0
- package/bridge/src/receiver-runtime-state.ts +124 -0
- package/bridge/src/receiver-support-actions.ts +189 -0
- package/bridge/src/receiver-thread-start.ts +57 -0
- package/bridge/src/receiver-turn-coordination.ts +94 -0
- package/bridge/src/receiver-turn-execution.ts +257 -0
- package/bridge/src/receiver-turn-failure.ts +143 -0
- package/bridge/src/receiver-turn-result.ts +185 -0
- package/bridge/src/receiver-turn-steer.ts +70 -0
- package/bridge/src/receiver-work-session.ts +76 -0
- package/bridge/src/receiver.ts +329 -0
- package/bridge/src/router.ts +62 -0
- package/bridge/src/runtime-client-agent-messages.ts +150 -0
- package/bridge/src/runtime-client-message-dispatch.ts +176 -0
- package/bridge/src/runtime-client-protocol.ts +411 -0
- package/bridge/src/runtime-client-request-ops.ts +56 -0
- package/bridge/src/runtime-client-run-turn.ts +158 -0
- package/bridge/src/runtime-client-thread-ops.ts +270 -0
- package/bridge/src/runtime-client-transport.ts +309 -0
- package/bridge/src/runtime-client-turn-poll.ts +224 -0
- package/bridge/src/runtime-client-turn-read.ts +185 -0
- package/bridge/src/runtime-client-turn-state.ts +105 -0
- package/bridge/src/runtime-client.ts +344 -0
- package/bridge/src/runtime-user-input.ts +403 -0
- package/bridge/src/scheduler.ts +239 -0
- package/bridge/src/server-handoff-command.ts +364 -0
- package/bridge/src/server-main.ts +80 -0
- package/bridge/src/server-routine-command.ts +60 -0
- package/bridge/src/server-routine-execution.ts +222 -0
- package/bridge/src/server-runtime-app-support.ts +107 -0
- package/bridge/src/server-runtime-app.ts +238 -0
- package/bridge/src/server-thread-sync-command.ts +63 -0
- package/bridge/src/server.ts +17 -0
- package/bridge/src/session-store-delivery.ts +220 -0
- package/bridge/src/session-store-human-gate.ts +380 -0
- package/bridge/src/session-store-inbound-acceptance.ts +66 -0
- package/bridge/src/session-store-meta.ts +134 -0
- package/bridge/src/session-store-turn-ledger.ts +272 -0
- package/bridge/src/session-store.ts +380 -0
- package/bridge/src/system-notify.ts +220 -0
- package/bridge/src/thread-sync.ts +200 -0
- package/bridge/src/translator.ts +494 -0
- package/bridge/src/types.ts +289 -0
- package/bridge/src/utils.ts +104 -0
- package/bridge/src/work-session-store.ts +471 -0
- package/docs/.gitkeep +0 -0
- package/docs/architecture/codex-feishu-bridge-proposal.md +2742 -0
- package/docs/completed/FEATURE-feishu-markdown-and-reply-support.md +327 -0
- package/docs/completed/README.md +21 -0
- package/docs/completed/SPEC-approval-autonomy-and-safe-defaults.md +205 -0
- package/docs/completed/SPEC-approval-batch-and-strict-reply-shortcuts.md +153 -0
- package/docs/completed/SPEC-conversation-noise-reduction-and-busy-input-gate.md +538 -0
- package/docs/completed/SPEC-engineering-sop-skillization.md +190 -0
- package/docs/completed/SPEC-faithful-bridge-core-thinning-v2.md +376 -0
- package/docs/completed/SPEC-faithful-bridge-core-thinning.md +1071 -0
- package/docs/completed/SPEC-group-chat-sender-identity.md +301 -0
- package/docs/completed/SPEC-middleware-exception-visibility.md +227 -0
- package/docs/completed/SPEC-nightly-memory-digest-visibility.md +121 -0
- package/docs/completed/SPEC-project-group-chat-human-centered-conversation-mapping.md +326 -0
- package/docs/completed/SPEC-remove-cli-persona-bootstrap.md +201 -0
- package/docs/developer-workflow.md +49 -0
- package/docs/implementation/SPEC-codex-same-machine-session-handoff-implementation.md +239 -0
- package/docs/implementation/test-coverage-map.md +363 -0
- package/docs/implementation/work-ally-implementation-guide.md +790 -0
- package/docs/issues/README.md +10 -0
- package/docs/issues/pending/ANALYSIS-ally-premature-recovery-notice-and-task-state-semantics-2026-03-18.md +295 -0
- package/docs/issues/resolved/ANALYSIS-approval-waiting-visible-but-approval-artifact-missing-2026-03-16.md +466 -0
- package/docs/issues/resolved/ANALYSIS-blocking-state-visible-without-user-actionable-artifact-2026-03-16.md +261 -0
- package/docs/issues/resolved/ANALYSIS-codex-app-server-transport-disconnect-semantics-2026-03-14.md +606 -0
- package/docs/issues/resolved/ANALYSIS-premature-terminalization-on-fresh-thread-poll-and-object-error-leak-2026-03-16.md +348 -0
- package/docs/issues/resolved/ANALYSIS-runtime-turn-delivery-and-recovery-2026-03-14.md +603 -0
- package/docs/issues/resolved/ANALYSIS-self-test-gap-approval-waiting-visible-but-approval-artifact-missing-2026-03-16.md +166 -0
- package/docs/issues/resolved/ANALYSIS-self-test-gap-blocking-state-visible-without-user-actionable-artifact-2026-03-16.md +186 -0
- package/docs/issues/resolved/ANALYSIS-self-test-gap-premature-terminalization-on-fresh-thread-poll-and-object-error-leak-2026-03-16.md +166 -0
- package/docs/issues/resolved/REPORT-ally-runtime-turn-delivery-3b42fb8-2026-03-15.md +373 -0
- package/docs/manual-acceptance.md +127 -0
- package/docs/ops-runbook.md +44 -0
- package/docs/planning/FEATURE-memory-system.md +748 -0
- package/docs/planning/SPEC-active-turn-steer-and-context-compaction-visibility.md +269 -0
- package/docs/planning/SPEC-approval-rules-inheritance-and-local-validation-lane.md +450 -0
- package/docs/planning/SPEC-assistant-persona-bootstrap.md +199 -0
- package/docs/planning/SPEC-assistant-rename.md +610 -0
- package/docs/planning/SPEC-bridge-app-server-protocol-alignment.md +667 -0
- package/docs/planning/SPEC-claude-runtime-host-for-work-ally.md +434 -0
- package/docs/planning/SPEC-cli-feishu-codex-session-unification.md +236 -0
- package/docs/planning/SPEC-codex-same-machine-session-handoff.md +873 -0
- package/docs/planning/SPEC-feishu-reaction-shortcuts.md +282 -0
- package/docs/planning/SPEC-local-stable-release-boundary.md +166 -0
- package/docs/planning/SPEC-managed-thread-entry-and-surface-mobility.md +862 -0
- package/docs/planning/SPEC-minimal-bridge-semantics-and-user-visible-surface.md +362 -0
- package/docs/planning/SPEC-npm-alpha-distribution-and-install-first-release.md +222 -0
- package/docs/planning/SPEC-remove-websocket-runtime-transport.md +364 -0
- package/docs/planning/SPEC-runtime-abstraction-phase-1.md +424 -0
- package/docs/planning/SPEC-runtime-connection-and-turn-recovery-semantics.md +274 -0
- package/docs/planning/SPEC-session-presence-and-state-visibility.md +397 -0
- package/docs/planning/SPEC-skill-first-capability-packaging.md +338 -0
- package/docs/planning/SPEC-stable-archive-contract.md +456 -0
- package/docs/planning/SPEC-supervised-start-boundary.md +127 -0
- package/docs/planning/SPEC-user-barrier-reduction-and-activation.md +832 -0
- package/docs/planning/ally-next.md +1278 -0
- package/docs/planning/assistant-workbench-spec.md +725 -0
- package/docs/planning/product-workbench.md +283 -0
- package/docs/product-onboarding.md +227 -0
- package/docs/product-spec-standard.md +528 -0
- package/docs/troubleshooting.md +45 -0
- package/docs/user-quickstart.md +46 -0
- package/internal/dispatch.sh +95 -0
- package/internal/lib/common.sh +1450 -0
- package/internal/modules/assistant/manage.sh +1312 -0
- package/internal/modules/bootstrap/setup.sh +144 -0
- package/internal/modules/config/init-env.sh +10 -0
- package/internal/modules/global/manage.sh +154 -0
- package/internal/modules/handoff/manage.sh +54 -0
- package/internal/modules/mcp/manage.sh +83 -0
- package/internal/modules/ops/logs.sh +76 -0
- package/internal/modules/routines/manage.sh +55 -0
- package/internal/modules/runtime/assistant-autosave.sh +26 -0
- package/internal/modules/runtime/restart.sh +6 -0
- package/internal/modules/runtime/start.sh +283 -0
- package/internal/modules/runtime/status.sh +194 -0
- package/internal/modules/runtime/stop.sh +55 -0
- package/internal/modules/runtime/supervisor.sh +216 -0
- package/internal/modules/runtime/update.sh +26 -0
- package/package.json +41 -0
- package/runtime/config/.gitkeep +0 -0
- package/runtime/host/.gitkeep +0 -0
- package/runtime/host/healthcheck-codex-app-server.ts +22 -0
- package/runtime/host/ping-pong-codex-app-server.ts +66 -0
- package/runtime/host/probe-codex-app-server.ts +115 -0
- package/skills/archive-reader/SKILL.md +9 -0
- package/skills/feishu-production-debug/SKILL.md +37 -0
- package/skills/feishu-production-debug/references/feishu-debug-order.md +49 -0
- package/skills/feishu-production-debug/references/platform-permission-baseline.md +23 -0
- package/skills/issue-to-spec-triage/SKILL.md +44 -0
- package/skills/issue-to-spec-triage/references/triage-rules.md +66 -0
- package/skills/memory-digest/SKILL.md +9 -0
- package/skills/post-implementation-closure/SKILL.md +39 -0
- package/skills/post-implementation-closure/references/closure-checklist.md +45 -0
- package/skills/post-implementation-closure/references/doc-drift-map.md +49 -0
- package/skills/product-spec/SKILL.md +244 -0
- package/templates/env.example +5 -0
- package/templates/routines/nightly-memory-digest.yaml +10 -0
- package/templates/workspace/AGENTS.md +26 -0
|
@@ -0,0 +1,2742 @@
|
|
|
1
|
+
# 以 Codex App Server 为中心的 Feishu Bridge 方案
|
|
2
|
+
|
|
3
|
+
> 当前已落地实现以 **assistant desk(办公桌)** 为中心。
|
|
4
|
+
>
|
|
5
|
+
> 当前 shipped model:
|
|
6
|
+
> - 一个运行中的 `ally` 进程对应一个 assistant desk
|
|
7
|
+
> - 当前项目目录是工作现场,不是 assistant 的家
|
|
8
|
+
> - assistant 的身份、记忆、对话、运行态默认进入 `~/.work-ally/assistants/<name>/`
|
|
9
|
+
> - 项目目录默认不再承载 `.work-ally/` 运行目录,也不默认承载 assistant 的长期记忆
|
|
10
|
+
> - assistant 办公桌根目录包含 `AGENTS.md`、`SOUL.md`、`NOW.md`、`MEMORY.md`、`MISTAKES.md`、`journal/`、`conversations/`
|
|
11
|
+
> - assistant 办公桌内部目录放在 `.system/`,包含 `config.env`、`codex-home/`、`runtime/`、`logs/`、`runs/`、`cache/`、`routines/`、`archive/`
|
|
12
|
+
> - 项目到 assistant 的绑定记录位于 `~/.work-ally/projects/registry.yaml`
|
|
13
|
+
> - assistant 注册表位于 `~/.work-ally/assistants/registry.yaml`
|
|
14
|
+
>
|
|
15
|
+
> 阅读本设计文档时,如后文仍出现早期的“项目目录内 `.work-ally/` 承载长期资产 / `memory/daily` / `memory/long-term` / `work-ally.workspace.yaml` 映射长期记忆”等表述,均应以本节描述的**当前 shipped model**为准。
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
> 目标:围绕同一个工作空间,让“电脑前使用官方 Codex”与“外出时通过飞书远程对话”连接到同一套官方 Codex runtime 能力,而不是再造一个新的 agent。
|
|
19
|
+
> 状态:方案 v1.0(可开工版)
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 0. 一页结论
|
|
24
|
+
|
|
25
|
+
这份方案的最终判断可以浓缩成一句话:
|
|
26
|
+
|
|
27
|
+
> **我们不再做一个新的 agent,而是做一层把飞书接到官方 Codex runtime 上的薄桥接系统。**
|
|
28
|
+
|
|
29
|
+
这意味着四个边界必须一次说清:
|
|
30
|
+
|
|
31
|
+
- **工作空间**:唯一事实来源,承载代码、`AGENTS.md`、记忆、知识库与长期上下文
|
|
32
|
+
- **Codex**:唯一大脑,负责 agent loop、工具调用、线程、审批、执行与恢复
|
|
33
|
+
- **飞书**:只是远程触达媒介,不承担智能职责
|
|
34
|
+
- **交付系统**:只是桥接层,负责消息接入、会话映射、事件转发、部署与最小运维
|
|
35
|
+
|
|
36
|
+
因此,当前最优方向不是:
|
|
37
|
+
|
|
38
|
+
- 继续把 `nanobot` 做成更强的大脑
|
|
39
|
+
- 自己再做一套通用 agent loop
|
|
40
|
+
- 用 `tmux` 或 TUI 文本转发拼出一个“看起来能用”的协议层
|
|
41
|
+
|
|
42
|
+
而是:
|
|
43
|
+
|
|
44
|
+
- 用 **Codex App Server** 承接真正的 agent 能力
|
|
45
|
+
- 用 **Feishu Bridge** 承接消息接入、事件翻译与审批回传
|
|
46
|
+
- 用 **Workspace** 承载这个 AI 伙伴的全部长期上下文
|
|
47
|
+
|
|
48
|
+
第一阶段最现实、最贴近目标的交付假设是:
|
|
49
|
+
|
|
50
|
+
- **一个工作空间 = 一个 assistant desk + 一个 bridge + 一套官方 Codex runtime 能力**
|
|
51
|
+
- 三者运行在**同一台机器**上(优先是你自己的个人电脑 / 常驻工作机,也可以是 VPS)
|
|
52
|
+
- 用户对外只看到一个统一的 **`ally`** 命令入口;它背后对应的是极薄的 `ally.sh` 门面
|
|
53
|
+
- 运行态默认使用**文件化 session store**,而不是数据库
|
|
54
|
+
- 网络入口优先走**飞书长连接**,而不是要求这台机器暴露公网回调地址
|
|
55
|
+
- **第一阶段明确优先服务个人用户**:长连接模式对个人最友好,因为它不要求公网地址、域名或反向代理
|
|
56
|
+
- 第一阶段虽然只接入飞书,但内部必须把 **Core Bridge** 与 **Channel Adapter** 分层;未来新增渠道应表现为新增 adapter,而不是改写 `session/runtime/memory` 主链路
|
|
57
|
+
- **未来可以迁移到公司内网常驻节点**:核心架构不变,变化的只是部署位置、服务托管方式与可联络身份范围
|
|
58
|
+
- 系统既支持**被动对话**,也支持**主动定时触发**;主动触发属于 `work-ally` 的编排层,而不是 App Server 本身
|
|
59
|
+
- **IM 入口与远程文档能力必须分层**:聊天入口继续由 bridge 负责;文档读写、总结、编辑这类能力优先由 Codex 直接通过 Feishu Remote MCP 获取
|
|
60
|
+
- **`work-ally` 不自建远程文档 provider 子系统**:它只保留薄的 MCP 配置辅助与使用规则,不在 bridge 内重做文档读写执行层
|
|
61
|
+
|
|
62
|
+
还要特别澄清三个容易混淆的点:
|
|
63
|
+
|
|
64
|
+
- 我们的**刚性目标**是:**同一个工作空间 + 同一类官方 Codex harness + 同一套工作空间上下文边界**
|
|
65
|
+
- 我们第一阶段**不把“桌面端和飞书端必须共用同一个 live runtime 进程 / 同一条实时 thread”**当作方案成立前提
|
|
66
|
+
- 我们第一阶段**不把数据库作为默认前提**;桥接状态优先以目录、JSON 与 Markdown 文件保存
|
|
67
|
+
|
|
68
|
+
也就是说,方案成立的关键不是“有没有额外平台、有没有数据库、是不是共享同一条实时进程”,而是:
|
|
69
|
+
|
|
70
|
+
> **无论从电脑还是飞书进入,你面对的都应当是同一个工作空间背后的官方 Codex 能力。**
|
|
71
|
+
|
|
72
|
+
在此基础上,这份方案现在再加一条硬约束:
|
|
73
|
+
|
|
74
|
+
- **使用者只做必要动作**:维护项目工作现场、准备 `ally` 命令入口、填写 desk 的最小本地运行配置、执行 `setup/start`
|
|
75
|
+
- **内部实现必须可整体替换**:实现缓存应被视为可删可重装的部件,而不是用户资产
|
|
76
|
+
- **需要长期保留的内容必须外置**:项目知识留在项目本身;assistant 的记忆、对话、主动任务定义与长期报告沉淀在 assistant desk;纯运行态只放在 `.system/` 中
|
|
77
|
+
- **记忆原材料必须自动采集**:原始对话与事件黑匣子应由系统自动落盘,不能依赖模型“记得写”,也不能依赖人手工补录
|
|
78
|
+
- **目录结构应低侵入接入**:`memory/`、`knowledge/` 等是推荐角色,不是对已有工程的强制重构要求
|
|
79
|
+
- **当前第一版的远程文档接法,默认采用官方 Feishu Remote MCP URL**:它已经足够轻、足够贴近目标,也与“桥接层做薄”一致;只有当未来进入公司内网常驻、多用户治理或统一应用托管场景时,再考虑升级到开发者远程模式
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 1. 背景:真正的问题是什么
|
|
84
|
+
|
|
85
|
+
当前最本质的需求,并不是“做一个飞书 bot”,而是获得这样一种工作方式:
|
|
86
|
+
|
|
87
|
+
- 始终围绕**同一个工作空间**工作
|
|
88
|
+
- 在电脑前时,直接使用**官方 Codex 工具**进行高质量 agent 交互
|
|
89
|
+
- 在外出时,通过**飞书**继续与这个工作空间背后的 AI 对话
|
|
90
|
+
- 人设、记忆、知识库、工作空间规则,都由这个工作空间自身承载
|
|
91
|
+
|
|
92
|
+
如果把问题理解成“我要一个飞书 bot”,思路很容易跑偏到:
|
|
93
|
+
|
|
94
|
+
- 我们要不要自己做 agent loop
|
|
95
|
+
- 要不要自己处理推理编排
|
|
96
|
+
- 要不要自己发明一套 memory 框架
|
|
97
|
+
- 要不要自己做工具调度系统
|
|
98
|
+
|
|
99
|
+
但这些都不是当前最值得投入的方向。
|
|
100
|
+
|
|
101
|
+
当前真正不可替代、且与你的使用场景最贴近的,是下面这条主线:
|
|
102
|
+
|
|
103
|
+
> **同一个工作空间,既能在电脑前通过官方 Codex 使用,也能在外出时通过飞书继续使用。**
|
|
104
|
+
|
|
105
|
+
因此,设计中心不应该是“做一个新的 agent”,而应该是:
|
|
106
|
+
|
|
107
|
+
> **如何让飞书成为官方 Codex 的一个远程入口。**
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## 2. 第一性原理
|
|
112
|
+
|
|
113
|
+
把需求拆开之后,真正不可替代的只有三样东西。
|
|
114
|
+
|
|
115
|
+
### 2.1 工作空间本身
|
|
116
|
+
|
|
117
|
+
工作空间目录是唯一事实来源,里面承载:
|
|
118
|
+
|
|
119
|
+
- 代码
|
|
120
|
+
- 工作空间根 `AGENTS.md`(主身份说明) / 行为指令 / 人设
|
|
121
|
+
- 记忆文件
|
|
122
|
+
- 知识库材料
|
|
123
|
+
- 文档、规则、资源索引
|
|
124
|
+
- 其他需要 agent 读取和修改的工作内容
|
|
125
|
+
|
|
126
|
+
这个工作空间不只是代码仓库,而是这个 AI 伙伴的完整工作场所。
|
|
127
|
+
|
|
128
|
+
### 2.2 官方 Codex runtime
|
|
129
|
+
|
|
130
|
+
真正应该交给官方 Codex 的能力包括:
|
|
131
|
+
|
|
132
|
+
- 推理与 agent loop
|
|
133
|
+
- 工具调用与命令执行
|
|
134
|
+
- 文件读取与编辑
|
|
135
|
+
- 线程管理
|
|
136
|
+
- 事件流输出
|
|
137
|
+
- 审批与继续执行
|
|
138
|
+
- 执行状态与恢复语义
|
|
139
|
+
|
|
140
|
+
结论很简单:
|
|
141
|
+
|
|
142
|
+
> **Codex 是大脑;桥接层不是大脑。**
|
|
143
|
+
|
|
144
|
+
### 2.3 可替换的交互媒介
|
|
145
|
+
|
|
146
|
+
交互媒介只应改变入口,不应改变大脑。
|
|
147
|
+
|
|
148
|
+
入口可以是:
|
|
149
|
+
|
|
150
|
+
- 官方 CLI / IDE / App(电脑前)
|
|
151
|
+
- 飞书(外出时)
|
|
152
|
+
- 未来的其他 IM 渠道(如 Telegram、Slack)
|
|
153
|
+
|
|
154
|
+
因此,最终系统应当满足:
|
|
155
|
+
|
|
156
|
+
> **同一个工作空间 + 同一个官方 Codex runtime + 多个入口媒介。**
|
|
157
|
+
|
|
158
|
+
但这里要多加一条工程约束:
|
|
159
|
+
|
|
160
|
+
> **第一阶段只实现 Feishu,也要从第一天把“渠道适配”和“桥接核心”分开。**
|
|
161
|
+
|
|
162
|
+
也就是说:
|
|
163
|
+
|
|
164
|
+
- 会话映射、Runtime 对接、黑匣子落盘、routine 调度属于 **Core Bridge**
|
|
165
|
+
- 飞书事件接入、消息发送、格式化、审批交互属于 **Channel Adapter**
|
|
166
|
+
|
|
167
|
+
这样未来如果新增 Telegram、Slack 或别的入口,新增的是一个 adapter,而不是把整条主链路重写一遍。
|
|
168
|
+
|
|
169
|
+
### 2.4 官方 Codex 的层级架构关系
|
|
170
|
+
|
|
171
|
+
这一点必须在方案前部就讲清楚,因为它直接决定我们到底该做什么、不该做什么。
|
|
172
|
+
|
|
173
|
+
对于本方案,应该把 Codex 体系理解成:
|
|
174
|
+
|
|
175
|
+
> **同一个官方发动机 + 不同的官方驾驶舱 / 接入面。**
|
|
176
|
+
|
|
177
|
+
推荐用下面这张图来理解:
|
|
178
|
+
|
|
179
|
+
```text
|
|
180
|
+
Workspace / AGENTS.md / memory-assets / knowledge-sources / docs / routine-definitions
|
|
181
|
+
▲
|
|
182
|
+
│
|
|
183
|
+
│ 提供长期上下文
|
|
184
|
+
│
|
|
185
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
186
|
+
│ Official Codex Core / Runtime │
|
|
187
|
+
│ - 官方 agent 行为框架 │
|
|
188
|
+
│ - 模型 / provider / 鉴权上下文 │
|
|
189
|
+
│ - thread / turn / approval / streamed events │
|
|
190
|
+
│ - tools / sandbox / MCP / conversation state │
|
|
191
|
+
└──────────────────────────────────────────────────────────────┘
|
|
192
|
+
▲ ▲ ▲
|
|
193
|
+
│ │ │
|
|
194
|
+
│ │ │
|
|
195
|
+
┌─────────────────┐ ┌─────────────────┐ ┌────────────────────┐
|
|
196
|
+
│ Codex CLI │ │ Codex App │ │ Codex App Server │
|
|
197
|
+
│ 官方命令行表面 │ │ 官方图形表面 │ │ 官方集成接口层 │
|
|
198
|
+
└─────────────────┘ └─────────────────┘ └────────────────────┘
|
|
199
|
+
▲
|
|
200
|
+
│
|
|
201
|
+
┌────────────────────────────────┐
|
|
202
|
+
│ work-ally + Feishu Bridge │
|
|
203
|
+
│ 我们自己的桥接 / 编排 / 交付层 │
|
|
204
|
+
└────────────────────────────────┘
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
这张图要表达的核心判断是:
|
|
208
|
+
|
|
209
|
+
- `codex app-server` **不是另一套大脑**,而是官方 Codex 对外暴露的 runtime 接口
|
|
210
|
+
- `Codex CLI`、`Codex App`、`Codex App Server` 应被视为**同一家族、同一类能力内核上的不同表面**
|
|
211
|
+
- 我们真正要复用的是这套“官方发动机”,而不是自己再手搓一台发动机
|
|
212
|
+
|
|
213
|
+
这也是为什么本方案坚持:
|
|
214
|
+
|
|
215
|
+
- **不自研 agent loop**
|
|
216
|
+
- **不接管模型与鉴权**
|
|
217
|
+
- **不把 `tmux` 文本转发当成最终协议**
|
|
218
|
+
- **不把多渠道、多助手编排、群组角色系统当成第一阶段主线**
|
|
219
|
+
- **只做上层使用场景**:远程入口、主动调度、结果回传、工作空间闭环
|
|
220
|
+
|
|
221
|
+
这里再补一条防止误解的边界:
|
|
222
|
+
|
|
223
|
+
- **不做多渠道平台化**,不等于把飞书细节散落进所有模块
|
|
224
|
+
- 第一阶段仍应保留一层薄的 `Channel Adapter` 边界,只是不提前做“渠道注册中心 / 多渠道控制台 / 统一运营平台”这类过度抽象
|
|
225
|
+
|
|
226
|
+
### 2.5 共享边界:哪些是同源能力,哪些不是我们应该依赖的契约
|
|
227
|
+
|
|
228
|
+
站在工程设计层面,可以把下面这些内容视为官方 Codex 的共享内核边界:
|
|
229
|
+
|
|
230
|
+
- 同类 runtime 语义:`thread / turn / approval / events`
|
|
231
|
+
- 同类配置体系:`config.toml / CODEX_HOME / profiles / sandbox / MCP`
|
|
232
|
+
- 同类鉴权语义:本地登录缓存、provider 配置、`env_key` 引用
|
|
233
|
+
- 同类 agent 行为框架:官方基础指令层 + 用户输入 + `AGENTS.md` / 工作空间上下文的层叠
|
|
234
|
+
|
|
235
|
+
从开源实现角度看,也能进一步看到这一层共享内核的存在:
|
|
236
|
+
|
|
237
|
+
- Codex 协议模型元数据里明确存在 `base_instructions` 与可选的 `instructions_template`
|
|
238
|
+
- 开源仓库中也存在默认基础指令文件
|
|
239
|
+
|
|
240
|
+
这说明:
|
|
241
|
+
|
|
242
|
+
> **官方 Codex 确实不是“裸模型 + 各表面各自随便拼装”,而是存在统一打磨过的基础指令层。**
|
|
243
|
+
|
|
244
|
+
但方案上**不应依赖**下面这种过细、过脆弱的假设:
|
|
245
|
+
|
|
246
|
+
- “CLI / App / App Server 永远共享同一段逐字不变的系统提示词文本”
|
|
247
|
+
- “任何官方表面都一定公开暴露那段内部提示词”
|
|
248
|
+
- “我们可以通过覆写那段底层提示词来稳定构建产品能力”
|
|
249
|
+
|
|
250
|
+
正确做法是:
|
|
251
|
+
|
|
252
|
+
> **依赖官方稳定暴露的能力边界,不依赖某段未承诺公开稳定的内部提示词文本。**
|
|
253
|
+
|
|
254
|
+
也就是说,我们真正信赖的不是“我知道它底层 prompt 每个字怎么写”,而是:
|
|
255
|
+
|
|
256
|
+
- 它确实是官方长期打磨的 Codex 能力内核
|
|
257
|
+
- CLI / App / App Server 只是这个内核的不同接入形态
|
|
258
|
+
- 我们只需要围绕这个内核,做好自己的上层使用场景
|
|
259
|
+
|
|
260
|
+
### 2.6 身份层设计:`AGENTS.md`、Skills、Memory 与渠道补充
|
|
261
|
+
|
|
262
|
+
这里还必须把“它是谁”和“它会什么”分开,否则方案落地后很容易出现两个互相竞争的人格层。
|
|
263
|
+
|
|
264
|
+
推荐分层如下:
|
|
265
|
+
|
|
266
|
+
```text
|
|
267
|
+
~/.codex/AGENTS.md(可选:全局工作习惯)
|
|
268
|
+
↓
|
|
269
|
+
工作空间根 AGENTS.md(唯一主身份说明 / 宪法)
|
|
270
|
+
↓
|
|
271
|
+
记忆文件 / 知识源 / 文档(按需要读取的工作空间资产)
|
|
272
|
+
↓
|
|
273
|
+
Skills(按需加载的机制能力)
|
|
274
|
+
↓
|
|
275
|
+
developer_instructions / 渠道薄补充
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
#### A. 根 `AGENTS.md` 是主身份,而不是产品再造一份平级人格
|
|
279
|
+
|
|
280
|
+
第一阶段默认应直接复用工作空间根目录下的 `AGENTS.md` 作为主身份说明。
|
|
281
|
+
|
|
282
|
+
原因不是偏好问题,而是官方 Codex 的发现机制本来就是:
|
|
283
|
+
|
|
284
|
+
- 先读 `CODEX_HOME` 下的全局 `AGENTS.md` / `AGENTS.override.md`
|
|
285
|
+
- 再从工作空间根一路走到当前 `cwd`
|
|
286
|
+
- 每个目录最多纳入一个指令文件
|
|
287
|
+
|
|
288
|
+
这意味着,如果我们再人为塞进一份“产品自己的主 `AGENTS.md`”,它更像在制造第二个平级人格,而不是增强同一个伙伴。
|
|
289
|
+
|
|
290
|
+
#### B. `work-ally` 不默认拥有第二份主 `AGENTS.md`
|
|
291
|
+
|
|
292
|
+
`work-ally` 不应在工作空间旁边再造一份与根 `AGENTS.md` 竞争的“产品人格文件”。
|
|
293
|
+
|
|
294
|
+
更合理的做法是:
|
|
295
|
+
|
|
296
|
+
- 主身份仍由工作空间根 `AGENTS.md` 定义
|
|
297
|
+
- 产品机制通过 Skills 与运行编排补上
|
|
298
|
+
- 飞书表面差异通过极薄补充层表达
|
|
299
|
+
|
|
300
|
+
#### C. Skills 承担“机制能力”,不是承担“主身份”
|
|
301
|
+
|
|
302
|
+
黑匣子归档、archive 读取、nightly `memory-digest`、routine 执行辅助等,更适合落成 Skills。
|
|
303
|
+
|
|
304
|
+
原因是:
|
|
305
|
+
|
|
306
|
+
- 这些东西属于“遇到特定任务时怎么做”
|
|
307
|
+
- 不需要在每一轮对话都常驻展开
|
|
308
|
+
- Skills 天然支持渐进式上下文披露
|
|
309
|
+
|
|
310
|
+
因此,`work-ally` 应优先把这类机制性知识做成少量、边界清晰的产品级 skills,而不是把它们都塞进根 `AGENTS.md`。
|
|
311
|
+
|
|
312
|
+
#### D. Memory / Knowledge 是资产,不是常驻人格提示
|
|
313
|
+
|
|
314
|
+
记忆文件、知识源、文档索引是工作空间资产。
|
|
315
|
+
|
|
316
|
+
它们回答的是:
|
|
317
|
+
|
|
318
|
+
- 发生过什么
|
|
319
|
+
- 该工作空间有哪些长期事实
|
|
320
|
+
- 需要时该去哪里找上下文
|
|
321
|
+
|
|
322
|
+
它们不应承担“永远常驻的一大段人格说明”职责;更合理的方式是按任务需要读取、引用或由 routine / skill 聚合后再使用。
|
|
323
|
+
|
|
324
|
+
#### E. 渠道差异只用极薄补充层
|
|
325
|
+
|
|
326
|
+
飞书端与桌面端的差异,更多是:
|
|
327
|
+
|
|
328
|
+
- 回复长度与格式
|
|
329
|
+
- 审批提示语
|
|
330
|
+
- 长任务进度回报方式
|
|
331
|
+
|
|
332
|
+
这类差异不应改写主身份,更适合放在:
|
|
333
|
+
|
|
334
|
+
- App Server / session 的 `developer_instructions`
|
|
335
|
+
- Bridge 侧的翻译与格式化逻辑
|
|
336
|
+
|
|
337
|
+
也就是说,飞书改变的是“怎么表达”,不改变“它是谁”。
|
|
338
|
+
|
|
339
|
+
#### F. App Server 的稳定装配点是什么
|
|
340
|
+
|
|
341
|
+
从 `work-ally` 的角度,App Server 层面真正稳定、值得依赖的装配点是:
|
|
342
|
+
|
|
343
|
+
- 用 `cwd` 决定工作空间与官方 `AGENTS.md` 发现链
|
|
344
|
+
- 用 Skills 作为按需能力扩展点
|
|
345
|
+
- 用 `developer_instructions` 承担极薄的渠道补充
|
|
346
|
+
|
|
347
|
+
第一阶段不应假设 App Server 提供“显式指定另一份主 `AGENTS.md` 路径”的产品级能力,因此方案也不应围绕“双主身份文件”来设计。
|
|
348
|
+
|
|
349
|
+
#### G. 高级隔离模式只作为可选项
|
|
350
|
+
|
|
351
|
+
如果未来你明确想把“远程自动化助手”与“桌面手动助手”做成两种不同角色,可以再考虑:
|
|
352
|
+
|
|
353
|
+
- 单独的 `CODEX_HOME`
|
|
354
|
+
- 单独 profile / 配置
|
|
355
|
+
- 单独系统用户
|
|
356
|
+
|
|
357
|
+
但这属于刻意分叉身份的高级模式,不应作为第一阶段默认。默认方案仍应追求:
|
|
358
|
+
|
|
359
|
+
> **同一个工作空间根 `AGENTS.md`,就是同一个伙伴的主身份说明。**
|
|
360
|
+
|
|
361
|
+
#### H. 只需要约定最小骨架,不需要先写一份大模板
|
|
362
|
+
|
|
363
|
+
如果借用 OpenClaw / SOUL / USER 这类体系来帮助理解,第一阶段更推荐做下面这种映射:
|
|
364
|
+
|
|
365
|
+
- **工作空间根 `AGENTS.md`** ≈ 压缩后的 `SOUL + USER + 基本工作契约`
|
|
366
|
+
- **Skills** ≈ 机制性 workflow(如 archive 读取、memory-digest、routine 辅助)
|
|
367
|
+
- **Memory / Knowledge / Docs** ≈ 长期资产与原材料
|
|
368
|
+
- **渠道薄补充** ≈ 飞书这一表面的表达差异
|
|
369
|
+
|
|
370
|
+
这样更符合 Codex 的原生装配方式,也避免把多份“人格文件”长期并列常驻。
|
|
371
|
+
|
|
372
|
+
这里还要再强调一条执行原则:
|
|
373
|
+
|
|
374
|
+
> **当前真正必要的,不是一份很长、很完整的 `AGENTS.md` 模板,而是一份足够短、边界清楚的最小骨架。**
|
|
375
|
+
|
|
376
|
+
原因是:
|
|
377
|
+
|
|
378
|
+
- 主身份文件越长,越容易把机制说明、记忆摘要、渠道差异全部塞进去
|
|
379
|
+
- 一旦这些内容长期混住在一起,后续就很难把 Skills、Memory 与渠道补充独立出来
|
|
380
|
+
- 第一阶段更需要的是“什么该写进 `AGENTS.md`,什么不该写”的稳定边界
|
|
381
|
+
|
|
382
|
+
因此,方案只建议约定下面这四段最小结构:
|
|
383
|
+
|
|
384
|
+
```markdown
|
|
385
|
+
# Identity
|
|
386
|
+
- 你是谁
|
|
387
|
+
- 你服务的对象是谁
|
|
388
|
+
- 你最重要的目标是什么
|
|
389
|
+
|
|
390
|
+
# Boundaries
|
|
391
|
+
- 哪些事情可以直接做
|
|
392
|
+
- 哪些事情必须先征得确认
|
|
393
|
+
- 哪些事情不应擅自做
|
|
394
|
+
|
|
395
|
+
# Writeback
|
|
396
|
+
- 哪些结果应沉淀回工作空间文件
|
|
397
|
+
- 哪些结果只需要留在运行记录或对话里
|
|
398
|
+
|
|
399
|
+
# Context Pointers
|
|
400
|
+
- 记忆文件大致在哪里
|
|
401
|
+
- 知识源大致在哪里
|
|
402
|
+
- 主动任务定义大致在哪里
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
这不是要求所有工作空间都照抄同一份模板,而是要求主身份文件至少回答四类问题:
|
|
406
|
+
|
|
407
|
+
- **我是谁**
|
|
408
|
+
- **我能怎么做 / 不能怎么做**
|
|
409
|
+
- **哪些成果应该回到工作空间**
|
|
410
|
+
- **我需要时该去哪里找上下文**
|
|
411
|
+
|
|
412
|
+
超过这四类的机制性内容,第一阶段应优先考虑放进 Skills 或工作空间资产,而不是继续往根 `AGENTS.md` 里堆。
|
|
413
|
+
|
|
414
|
+
第一阶段尤其不建议写进根 `AGENTS.md` 的内容包括:
|
|
415
|
+
|
|
416
|
+
- 黑匣子 archive 的目录结构与落盘细节
|
|
417
|
+
- nightly `memory-digest` 的调度细节
|
|
418
|
+
- 飞书长消息分段、审批卡片之类的渠道格式规则
|
|
419
|
+
- provider / model / auth 的配置细节
|
|
420
|
+
|
|
421
|
+
这些内容要么属于机制能力,要么属于运行配置,要么属于渠道补充;它们都不应挤占主身份说明。
|
|
422
|
+
|
|
423
|
+
---
|
|
424
|
+
|
|
425
|
+
## 3. 什么是 Codex App Server
|
|
426
|
+
|
|
427
|
+
这部分必须先讲清楚,否则整个方案会很容易误判。
|
|
428
|
+
|
|
429
|
+
### 3.1 它不是“OpenAI 云上固定给你的一台服务器”
|
|
430
|
+
|
|
431
|
+
在本方案中,`Codex App Server` 更准确的理解是:
|
|
432
|
+
|
|
433
|
+
- 一套稳定的 Codex runtime 接入形态
|
|
434
|
+
- 一个承载线程、事件、审批与执行状态的运行时接口
|
|
435
|
+
- 一个可以由本地 bridge 以 stdio child-process 方式拉起和托管的官方运行面
|
|
436
|
+
|
|
437
|
+
它可以运行在:
|
|
438
|
+
|
|
439
|
+
- 本地开发机
|
|
440
|
+
- 常驻工作机
|
|
441
|
+
- 自托管 VPS
|
|
442
|
+
- 其他你控制的工作节点上
|
|
443
|
+
|
|
444
|
+
所以它在系统中的角色,本质上是:
|
|
445
|
+
|
|
446
|
+
> **官方 Codex runtime 的标准接入面**
|
|
447
|
+
|
|
448
|
+
而不是“必须由 OpenAI 托管给你的一台远程 Web 服务器”。
|
|
449
|
+
|
|
450
|
+
### 3.2 为什么它必须成为方案中心
|
|
451
|
+
|
|
452
|
+
如果飞书只是拿一段 CLI 文本来回转发,系统很快会遇到这些问题:
|
|
453
|
+
|
|
454
|
+
- 线程怎么表示
|
|
455
|
+
- 长任务怎么持续反馈
|
|
456
|
+
- 审批怎么中断与恢复
|
|
457
|
+
- 出错后怎么恢复
|
|
458
|
+
- 状态边界放在哪里
|
|
459
|
+
- 多入口如何共享同一套 runtime 语义
|
|
460
|
+
|
|
461
|
+
Codex App Server 的价值就在于:
|
|
462
|
+
|
|
463
|
+
- 它天然更接近**事件流 runtime**,不是简单的 request/response API
|
|
464
|
+
- 它天然具备 `thread / turn / item` 这一类结构化语义
|
|
465
|
+
- 它更适合作为桌面入口与远程入口共享的“中间运行层”
|
|
466
|
+
|
|
467
|
+
因此,这个方案的核心判断是:
|
|
468
|
+
|
|
469
|
+
> **飞书不应该接一个自定义 agent loop,而应该接到官方 Codex runtime。**
|
|
470
|
+
|
|
471
|
+
### 3.3 它和官方 CLI 的关系
|
|
472
|
+
|
|
473
|
+
这里还要说清一个实现层面的理解:
|
|
474
|
+
|
|
475
|
+
- 我们要接的是**官方 Codex runtime / harness 能力**
|
|
476
|
+
- 我们不要做的是:抓取 CLI 的 TUI 文本、模拟按键、解析终端输出
|
|
477
|
+
|
|
478
|
+
也就是说,本方案假定:
|
|
479
|
+
|
|
480
|
+
- 桌面端继续使用官方 CLI / IDE / App 这种原生表面
|
|
481
|
+
- 飞书端通过 Bridge 接入同一类官方 runtime 能力
|
|
482
|
+
- Bridge 对接的是 runtime 层,而不是 TUI 文本层
|
|
483
|
+
|
|
484
|
+
所以更准确的说法不是“飞书去操控一个 CLI 界面”,而是:
|
|
485
|
+
|
|
486
|
+
> **飞书是官方 Codex runtime 的另一个入口。**
|
|
487
|
+
|
|
488
|
+
---
|
|
489
|
+
|
|
490
|
+
## 4. 设计目标与非目标
|
|
491
|
+
|
|
492
|
+
### 4.1 设计目标
|
|
493
|
+
|
|
494
|
+
本方案的目标是:
|
|
495
|
+
|
|
496
|
+
1. **同一个工作空间就是同一个 AI 伙伴**
|
|
497
|
+
2. **飞书只是入口,不是另一套 agent**
|
|
498
|
+
3. **电脑端与飞书端共享同一类官方 Codex 能力边界**
|
|
499
|
+
4. **尽量少造轮子,把复杂智能职责交给官方 Codex**
|
|
500
|
+
5. **既支持被动对话,也支持围绕工作空间的主动触发**
|
|
501
|
+
6. **最终交付物对用户保持简单:一个 `work-ally` 即可完成安装、启动、更新与运维**
|
|
502
|
+
7. **用户只做必要事情,不承担实现者心智负担**
|
|
503
|
+
8. **用户资产与内部实现分离,系统应能被整体替换后重建**
|
|
504
|
+
|
|
505
|
+
### 4.2 非目标
|
|
506
|
+
|
|
507
|
+
本方案当前不追求:
|
|
508
|
+
|
|
509
|
+
- 自己重新实现一套 agent loop
|
|
510
|
+
- 把 `nanobot` 继续强化成最终大脑
|
|
511
|
+
- 在本方案里做多 agent 编排平台
|
|
512
|
+
- 在一套运行系统里人为切很多“群组 / 角色 / 助手身份”
|
|
513
|
+
- 一开始就做复杂多工作空间 / 多租户 SaaS 化
|
|
514
|
+
- 一开始就做多渠道并行接入
|
|
515
|
+
- 用 `tmux` 作为最终协议层
|
|
516
|
+
- 一开始就引入数据库来承载桥接状态
|
|
517
|
+
- 追求桌面端与飞书端从第一天起共享同一个 live runtime 进程或实时 thread
|
|
518
|
+
|
|
519
|
+
这些方向不是永远不能做,而是:
|
|
520
|
+
|
|
521
|
+
> **它们都不属于当前最优主线。**
|
|
522
|
+
|
|
523
|
+
---
|
|
524
|
+
|
|
525
|
+
## 5. 总体方案
|
|
526
|
+
|
|
527
|
+
### 5.1 系统总图
|
|
528
|
+
|
|
529
|
+
```text
|
|
530
|
+
电脑前用户 ──> 官方 Codex 表面 ──> Codex Runtime Host ──> Project Workspace
|
|
531
|
+
▲
|
|
532
|
+
│
|
|
533
|
+
飞书用户 ──> Feishu IM ──> Feishu Bridge ──┘
|
|
534
|
+
│
|
|
535
|
+
├────> Runtime Session Store (assistant desk .system/runtime/)
|
|
536
|
+
├────> Black-box Archive (assistant desk .system/archive/)
|
|
537
|
+
│ │
|
|
538
|
+
│ └────> memory-digest routine -> journal / MEMORY / NOW / MISTAKES
|
|
539
|
+
└────> Codex Tools / MCP
|
|
540
|
+
└────> Feishu Remote MCP -> Docs Read / Write / Update
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
### 5.2 四层分工
|
|
544
|
+
|
|
545
|
+
#### A. Workspace Layer(工作空间层)
|
|
546
|
+
|
|
547
|
+
负责:
|
|
548
|
+
|
|
549
|
+
- 代码
|
|
550
|
+
- 人设
|
|
551
|
+
- 长期记忆文件
|
|
552
|
+
- 黑匣子归档原材料
|
|
553
|
+
- 知识源材料
|
|
554
|
+
- 长期上下文材料
|
|
555
|
+
- 主动例行任务定义
|
|
556
|
+
|
|
557
|
+
它是唯一事实来源,不承载桥接运行态。
|
|
558
|
+
|
|
559
|
+
#### B. Runtime Layer(Codex 层)
|
|
560
|
+
|
|
561
|
+
由官方 Codex App Server / Runtime Host 承载,负责:
|
|
562
|
+
|
|
563
|
+
- agent loop
|
|
564
|
+
- 工具调用
|
|
565
|
+
- 线程管理
|
|
566
|
+
- 审批
|
|
567
|
+
- 事件流
|
|
568
|
+
- 执行与恢复
|
|
569
|
+
|
|
570
|
+
它是唯一应被视为“AI 正在工作的地方”。
|
|
571
|
+
|
|
572
|
+
#### C. Orchestration Layer(`work-ally` 编排层)
|
|
573
|
+
|
|
574
|
+
由 `work-ally` 背后的内部实现承载,负责:
|
|
575
|
+
|
|
576
|
+
- 被动入口与主动入口的统一调度
|
|
577
|
+
- 定时触发、计划触发与手动试跑
|
|
578
|
+
- `routine -> thread / turn` 的创建、复用与防重
|
|
579
|
+
- 失败重试、恢复、幂等、运行记录
|
|
580
|
+
- 自动落黑匣子原材料,并在合适时机触发记忆压缩
|
|
581
|
+
- 将结果路由到飞书、日志、本地状态文件与工作空间记忆文件
|
|
582
|
+
|
|
583
|
+
它**不替代 Codex 思考**,只负责回答三件事:
|
|
584
|
+
|
|
585
|
+
- **什么时候触发**
|
|
586
|
+
- **触发哪条例行任务**
|
|
587
|
+
- **把结果送到哪里**
|
|
588
|
+
|
|
589
|
+
#### D. Channel Layer(飞书层)
|
|
590
|
+
|
|
591
|
+
由 Feishu Bridge 承载,负责:
|
|
592
|
+
|
|
593
|
+
- 收消息
|
|
594
|
+
- 发消息
|
|
595
|
+
- 映射会话
|
|
596
|
+
- 订阅与转发 runtime 事件
|
|
597
|
+
- 把 runtime 语义翻译成飞书可理解的反馈
|
|
598
|
+
|
|
599
|
+
它不思考,只翻译和路由。
|
|
600
|
+
|
|
601
|
+
### 5.2.1 为什么“聊天入口”与“文档产物表面”必须分开
|
|
602
|
+
|
|
603
|
+
在真实使用场景里,飞书至少承载两类完全不同的需求:
|
|
604
|
+
|
|
605
|
+
- **即时对话**:你在飞书里提问、追问、审批、打断
|
|
606
|
+
- **远程可读产物**:AI 写出长文、方案、审批稿、日报后,你希望直接收到一个可打开的链接,而不是被迫回到电脑前看本地文件
|
|
607
|
+
|
|
608
|
+
这两类需求不应由同一个 adapter 直接混做一层。
|
|
609
|
+
|
|
610
|
+
更合理的拆法是:
|
|
611
|
+
|
|
612
|
+
- `Channel Adapter` 只负责 **IM 入口**
|
|
613
|
+
- `Channel Adapter` 只负责 **IM 入口**
|
|
614
|
+
- 文档读写与编辑能力优先由 **Codex 直接通过 Feishu Remote MCP** 获得
|
|
615
|
+
- Skill / routine 只负责 **在合适场景下提示使用这些能力**,而不是在 bridge 内内建一套文档后端
|
|
616
|
+
|
|
617
|
+
当前第一版的 IM 实现是 `channels/feishu/`,但这只是实现层选择,不应上升为抽象层命名。
|
|
618
|
+
|
|
619
|
+
这意味着:
|
|
620
|
+
|
|
621
|
+
- **飞书聊天 ≠ 飞书文档读写**
|
|
622
|
+
- **文档能力属于 Codex 的工具层,不属于 bridge 的聊天 adapter**
|
|
623
|
+
- **即使后续扩展更多文档场景,也应优先扩在 MCP / tool 使用策略层,而不是重回 bridge 自建 provider**
|
|
624
|
+
|
|
625
|
+
第一阶段即使只是把结果发回飞书文本,也不应把后续文档读写逻辑硬塞进 `channels/feishu/adapter.ts` 里。
|
|
626
|
+
|
|
627
|
+
### 5.3 `nanobot` 在新方案中的位置
|
|
628
|
+
|
|
629
|
+
`nanobot` 在这个新方向里最多承担两类价值:
|
|
630
|
+
|
|
631
|
+
- 飞书渠道接入经验
|
|
632
|
+
- 已有交互形态或实现上的参考
|
|
633
|
+
|
|
634
|
+
但它不再承担最终大脑职责。
|
|
635
|
+
|
|
636
|
+
换句话说:
|
|
637
|
+
|
|
638
|
+
- **可以借鉴 `nanobot` 的渠道层经验**
|
|
639
|
+
- **不再把它的 agent loop 视为系统中心**
|
|
640
|
+
|
|
641
|
+
### 5.3.1 当前最值得直接借鉴 `nanobot` 的实现点
|
|
642
|
+
|
|
643
|
+
这里可以明确写出来,避免后续实现时重复摸索:
|
|
644
|
+
|
|
645
|
+
- **长连接接入**:当前飞书实现优先复用“本机主动连出、不要求公网回调”的思路
|
|
646
|
+
- **消息即时回执**:用户发来消息后,先给一个轻量 reaction / receipt,立即让用户知道“系统收到了”
|
|
647
|
+
- **Markdown 输出策略**:按内容复杂度在普通文本、富文本、卡片之间切换,而不是强行一种格式打天下
|
|
648
|
+
- **表格 / 长内容分片**:对渠道限制做显示层降级与切分,不把这些复杂度泄漏给 core bridge
|
|
649
|
+
- **消息去重**:对入站消息做 message-id 级去重,避免长连接重投导致重复执行
|
|
650
|
+
- **文件化会话与记忆**:会话、黑匣子、长期记忆尽量保持可读、可修复、可 grep
|
|
651
|
+
|
|
652
|
+
借鉴的边界也要写清楚:
|
|
653
|
+
|
|
654
|
+
- **借渠道层实现经验,不借 agent loop 中心架构**
|
|
655
|
+
- **借文件化状态思路,不把现有产品边界重新收缩回 `nanobot`**
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
|
|
659
|
+
### 5.4 为什么不做“多渠道 + 多组 + 多角色助手”抽象
|
|
660
|
+
|
|
661
|
+
这一点也需要尽早写清楚,否则后续实现很容易被“平台化想象”带偏。
|
|
662
|
+
|
|
663
|
+
从本方案的目标出发,最自然、最稳定的助手边界其实不是:
|
|
664
|
+
|
|
665
|
+
- 在一套运行中的系统里切很多组
|
|
666
|
+
- 在一套助手里再分很多角色
|
|
667
|
+
- 让一个长期运行的总助手同时服务很多互不相干的工作对象
|
|
668
|
+
|
|
669
|
+
而是:
|
|
670
|
+
|
|
671
|
+
> **一个工作空间,就是一个助手。**
|
|
672
|
+
|
|
673
|
+
这背后的判断非常朴素:
|
|
674
|
+
|
|
675
|
+
- 一个工作空间天然就有自己的人设、记忆、知识库、规则与目标
|
|
676
|
+
- 不同工作空间之间,本来就应该相互隔离
|
|
677
|
+
- 如果真的需要多个助手,最自然的方式就是:**多个工作空间 = 多个助手实例**
|
|
678
|
+
|
|
679
|
+
因此,本方案明确不走下面这条路:
|
|
680
|
+
|
|
681
|
+
- 在单实例里抽象出复杂 group / role / assistant registry
|
|
682
|
+
- 让一个总助手同时兼职很多份彼此无关的工作
|
|
683
|
+
|
|
684
|
+
因为那会带来几类明显问题:
|
|
685
|
+
|
|
686
|
+
- 心智模型变复杂
|
|
687
|
+
- 状态边界变模糊
|
|
688
|
+
- 权限与上下文更容易串味
|
|
689
|
+
- 最后容易变成“一个助手什么都管,但什么都做不精”
|
|
690
|
+
|
|
691
|
+
这很像现实世界里让同一个人同时承担很多份彼此无关、上下文高度冲突的工作:
|
|
692
|
+
|
|
693
|
+
> **看起来节省,实际上往往会让每一份工作都做不好。**
|
|
694
|
+
|
|
695
|
+
所以,这份方案在助手边界上的坚定选择是:
|
|
696
|
+
|
|
697
|
+
- **单工作空间 = 单助手**
|
|
698
|
+
- **多工作空间 = 多助手**
|
|
699
|
+
- **多助手问题通过多实例自然解决,而不是在单实例内部做复杂人格 / 群组切分**
|
|
700
|
+
|
|
701
|
+
这也是为什么 `work-ally` 的命名与结构都围绕“工作空间伙伴”展开,而不是围绕“多助手平台”展开。
|
|
702
|
+
|
|
703
|
+
---
|
|
704
|
+
|
|
705
|
+
## 6. 最终交付形态与命名
|
|
706
|
+
|
|
707
|
+
这一节只回答两个问题:
|
|
708
|
+
|
|
709
|
+
1. **最后用户拿到的到底是什么?应该怎么用?**
|
|
710
|
+
2. **这个东西在用户眼里应该叫什么?**
|
|
711
|
+
|
|
712
|
+
### 6.1 它更像一个新产品实现,而不是当前仓库的小修小补
|
|
713
|
+
|
|
714
|
+
从方案本质上看,这更像一个新的实现仓库,而不是把当前 `nanobot-deploy` 继续强行演化。
|
|
715
|
+
|
|
716
|
+
原因是:
|
|
717
|
+
|
|
718
|
+
- 目标已经从“部署 nanobot”转向“桥接 Feishu 到官方 Codex runtime”
|
|
719
|
+
- 运行时中心已经从 `nanobot` 变成 `Codex Runtime Host`
|
|
720
|
+
- 用户心智已经从“部署一个 bot”变成“给一个工作空间接入远程 Codex 伙伴”
|
|
721
|
+
|
|
722
|
+
所以更合理的实现方式是:
|
|
723
|
+
|
|
724
|
+
- **把这份文档作为最终方案设计稿**
|
|
725
|
+
- **后续以新的仓库来承接真正实现**
|
|
726
|
+
- 当前仓库更多承担讨论、参考与历史材料的角色
|
|
727
|
+
|
|
728
|
+
### 6.2 命名原则
|
|
729
|
+
|
|
730
|
+
这个名字不是给实现者看的,而是给使用者看的。
|
|
731
|
+
|
|
732
|
+
因此,命名应满足四个原则:
|
|
733
|
+
|
|
734
|
+
1. **体现本质**:它是工作空间的伙伴,不是一个渠道 bot
|
|
735
|
+
2. **用户可理解**:用户看到名字就能明白“它是陪我围绕自己的工作空间开展工作的东西”
|
|
736
|
+
3. **足够简短**:需要被频繁输入,不能太长
|
|
737
|
+
4. **保持稳定**:门面名一旦公开,就尽量不要频繁变化
|
|
738
|
+
|
|
739
|
+
### 6.3 当前推荐工作名:`work-ally`
|
|
740
|
+
|
|
741
|
+
基于上面的原则,当前最推荐的工作名是:
|
|
742
|
+
|
|
743
|
+
> **`work-ally`**
|
|
744
|
+
|
|
745
|
+
理由是:
|
|
746
|
+
|
|
747
|
+
- 它强调的是“工作中的伙伴 / 协作者”而不是“机器人”
|
|
748
|
+
- 它不把对象限制为软件项目,也适用于秘书、运营、研究等非开发工作空间
|
|
749
|
+
- 它足够短,适合作为工作目录下的日常命令
|
|
750
|
+
- 它不会把用户注意力带偏到飞书 bot、部署框架或容器管理上
|
|
751
|
+
|
|
752
|
+
因此,后续文档里的**推荐外部命令入口**统一写为:
|
|
753
|
+
|
|
754
|
+
```bash
|
|
755
|
+
ally <command>
|
|
756
|
+
```
|
|
757
|
+
|
|
758
|
+
这里要把三个名字分开:
|
|
759
|
+
|
|
760
|
+
- **产品 / 实现仓库名**:`work-ally`
|
|
761
|
+
- **实现仓库里的门面文件名**:`ally.sh`
|
|
762
|
+
- **用户日常使用的命令名**:`ally`
|
|
763
|
+
|
|
764
|
+
也就是说:
|
|
765
|
+
|
|
766
|
+
- 当前 shipped workflow 优先是把实现仓库里的 `ally.sh` 通过 PATH / alias 暴露成 `ally`
|
|
767
|
+
- 如果某些环境确实更适合放一个 workspace 本地 shim,也仍可兼容
|
|
768
|
+
- 但用户文档与交付心智应统一收敛到 `ally` 这一条主路径
|
|
769
|
+
|
|
770
|
+
与此对应,工作空间内隐藏目录也建议统一为:
|
|
771
|
+
|
|
772
|
+
```text
|
|
773
|
+
.work-ally/
|
|
774
|
+
```
|
|
775
|
+
|
|
776
|
+
### 6.4 对用户的最终交付物
|
|
777
|
+
|
|
778
|
+
对用户来说,最终交付物应该非常简单:
|
|
779
|
+
|
|
780
|
+
- 一个统一可调用的 `ally` 命令(背后通常来自实现仓库里的极薄 `ally.sh`)
|
|
781
|
+
- 一个由它初始化出来的隐藏目录 `.work-ally/`
|
|
782
|
+
- 一组稳定的日常命令:`setup / start / stop / status / logs / update / routine ...`
|
|
783
|
+
- 一个清晰的助手边界:**这个工作空间里的这一个伙伴,只服务这一个工作空间**
|
|
784
|
+
- 一条未来可升级但不改边界的交付路线:**今天优先通过 PATH / alias 提供全局 `ally`,未来也可以做 Homebrew / 安装器分发;必要时仍兼容 workspace 本地 shim,但无论怎么安装,作用域都仍然由“当前绝对工作空间路径”决定**
|
|
785
|
+
|
|
786
|
+
用户不应该被迫理解:
|
|
787
|
+
|
|
788
|
+
- App Server 协议细节
|
|
789
|
+
- `thread / turn / item` 内部对象
|
|
790
|
+
- Bridge 内部模块拆分
|
|
791
|
+
- 运行态状态文件的组织方式
|
|
792
|
+
|
|
793
|
+
对用户来说,正确心智应该是:
|
|
794
|
+
|
|
795
|
+
> **准备好 `ally` 命令,在我的工作空间里运行一次 `setup`,这个工作空间背后的远程飞书入口与主动例行能力就有了承载外壳。**
|
|
796
|
+
|
|
797
|
+
### 6.5 assistant desk 与项目工作现场的推荐形态
|
|
798
|
+
|
|
799
|
+
```text
|
|
800
|
+
your-project/
|
|
801
|
+
├── ally.sh # 用户面对的统一入口
|
|
802
|
+
├── AGENTS.md # 项目规则
|
|
803
|
+
├── docs/ / specs/ / src/ ...
|
|
804
|
+
|
|
805
|
+
~/.work-ally/
|
|
806
|
+
├── assistants/
|
|
807
|
+
│ ├── registry.yaml
|
|
808
|
+
│ └── <name>/
|
|
809
|
+
│ ├── AGENTS.md
|
|
810
|
+
│ ├── SOUL.md
|
|
811
|
+
│ ├── NOW.md
|
|
812
|
+
│ ├── MEMORY.md
|
|
813
|
+
│ ├── MISTAKES.md
|
|
814
|
+
│ ├── journal/
|
|
815
|
+
│ ├── conversations/
|
|
816
|
+
│ └── .system/
|
|
817
|
+
│ ├── config.env
|
|
818
|
+
│ ├── codex-home/
|
|
819
|
+
│ ├── runtime/
|
|
820
|
+
│ ├── logs/
|
|
821
|
+
│ ├── runs/
|
|
822
|
+
│ ├── cache/
|
|
823
|
+
│ ├── routines/
|
|
824
|
+
│ └── archive/
|
|
825
|
+
└── projects/
|
|
826
|
+
└── registry.yaml
|
|
827
|
+
```
|
|
828
|
+
|
|
829
|
+
这其中:
|
|
830
|
+
|
|
831
|
+
- `ally` 是用户真正面对的统一命令入口;`ally.sh` 是背后的极薄门面文件
|
|
832
|
+
- 项目目录继续承载项目自己的代码、文档、规范与知识源
|
|
833
|
+
- assistant 自身的身份、记忆、对话与运行资产全部进入独立 desk
|
|
834
|
+
- assistant desk 根目录是长期资产目录,并默认初始化为独立 Git 仓库
|
|
835
|
+
- `.system/config.env` 只放机器本地 bridge/runtime 配置,不承载长期记忆、知识或业务规则
|
|
836
|
+
- `.system/runtime/`、`runs/`、`logs/`、`cache/` 是 desk 内部运行台账与本地状态
|
|
837
|
+
- 需要长期保留、迁移或进入版本历史的内容,应优先留在项目目录或 assistant desk 根目录的可见资产中,而不是藏进内部实现缓存
|
|
838
|
+
|
|
839
|
+
### 6.5.1 已有工程的低侵入接入原则
|
|
840
|
+
|
|
841
|
+
当前 shipped model 仍保留这条原则,但实现方式已经收敛:
|
|
842
|
+
|
|
843
|
+
> **assistant desk 承担 assistant 自身资产;项目仓库继续只承载项目自己的资产。**
|
|
844
|
+
|
|
845
|
+
也就是说:
|
|
846
|
+
|
|
847
|
+
- assistant 身份、记忆、对话、运行态进入 assistant desk
|
|
848
|
+
- 项目级知识、规范、源码、文档继续留在项目目录
|
|
849
|
+
- assistant 通过读取项目现有文件来遵守项目制度,而不是要求项目配合一套新的记忆目录结构
|
|
850
|
+
- 当前产品默认不再要求额外的项目级路径映射文件来声明 assistant 记忆或黑匣子路径
|
|
851
|
+
|
|
852
|
+
因此,接入已有工程的低侵入方式不再是“映射项目内记忆目录”,而是“把 assistant home 放到项目之外,把项目本身当作工作现场”。
|
|
853
|
+
|
|
854
|
+
### 6.6 `work-ally` 应该承担什么职责
|
|
855
|
+
|
|
856
|
+
`work-ally` 现在的职责应理解为:
|
|
857
|
+
|
|
858
|
+
1. 通过 `ally.sh` 暴露统一入口
|
|
859
|
+
2. 管理 assistant desk 的初始化、绑定、启动、停止、日志、例行任务与 MCP 封装
|
|
860
|
+
3. 把聊天桥接到官方 Codex runtime
|
|
861
|
+
4. 保持“一进程 = 一 assistant desk”的运行边界
|
|
862
|
+
|
|
863
|
+
也就是说:
|
|
864
|
+
|
|
865
|
+
- `ally.sh` 是稳定门面
|
|
866
|
+
- 真正的配置、运行、管理逻辑都在产品内部实现里
|
|
867
|
+
- assistant desk 是用户长期资产
|
|
868
|
+
- 内部实现缓存是可替换件,不应被误当成长期资产目录
|
|
869
|
+
|
|
870
|
+
### 6.7 用户的日常使用路径
|
|
871
|
+
|
|
872
|
+
用户应当只需要理解下面这条路径:
|
|
873
|
+
|
|
874
|
+
#### 第一次接入
|
|
875
|
+
|
|
876
|
+
```bash
|
|
877
|
+
ally setup <assistant-name>
|
|
878
|
+
```
|
|
879
|
+
|
|
880
|
+
它负责:
|
|
881
|
+
|
|
882
|
+
- 创建并初始化 `~/.work-ally/assistants/<assistant-name>/`
|
|
883
|
+
- 拉取或安装内部实现
|
|
884
|
+
- 生成最小配置模板
|
|
885
|
+
- 初始化 desk 所需的 `conversations/`、`.system/runtime/`、`.system/logs/` 等目录
|
|
886
|
+
- 记录项目到 assistant 的绑定关系并检查 runtime 前置条件
|
|
887
|
+
|
|
888
|
+
#### 启动服务
|
|
889
|
+
|
|
890
|
+
```bash
|
|
891
|
+
ally start
|
|
892
|
+
```
|
|
893
|
+
|
|
894
|
+
它负责:
|
|
895
|
+
|
|
896
|
+
- 启动 Feishu Bridge
|
|
897
|
+
- 启动或拉起 Runtime Host
|
|
898
|
+
- 让当前项目的远程入口进入可用状态
|
|
899
|
+
|
|
900
|
+
#### 日常维护
|
|
901
|
+
|
|
902
|
+
```bash
|
|
903
|
+
ally status
|
|
904
|
+
ally logs
|
|
905
|
+
ally stop
|
|
906
|
+
ally update
|
|
907
|
+
ally routine list
|
|
908
|
+
ally routine run morning-brief
|
|
909
|
+
```
|
|
910
|
+
|
|
911
|
+
它们分别负责:
|
|
912
|
+
|
|
913
|
+
- 查看运行状态
|
|
914
|
+
- 查看日志
|
|
915
|
+
- 停止服务
|
|
916
|
+
- 更新内部实现并重启必要组件
|
|
917
|
+
- 查看当前 assistant desk 下有哪些主动例行任务
|
|
918
|
+
- 对某条例行任务做一次手动试跑
|
|
919
|
+
|
|
920
|
+
### 6.8 这是不是“一键部署”
|
|
921
|
+
|
|
922
|
+
是,但这里的“一键部署”要理解成:
|
|
923
|
+
|
|
924
|
+
- **对用户一键**
|
|
925
|
+
- **对内部模块化**
|
|
926
|
+
|
|
927
|
+
也就是说,用户只面对一个 `ally` 命令;但内部实现仍应拆分成:
|
|
928
|
+
|
|
929
|
+
- 配置模块
|
|
930
|
+
- runtime 管理模块
|
|
931
|
+
- Bridge 管理模块
|
|
932
|
+
- 会话状态模块
|
|
933
|
+
- 运维模块
|
|
934
|
+
|
|
935
|
+
这样既保证外部体验简单,也避免内部变成一个巨大的黑盒脚本。
|
|
936
|
+
|
|
937
|
+
|
|
938
|
+
### 6.9 用户使用闭环
|
|
939
|
+
|
|
940
|
+
从使用者视角,这套系统最终应形成下面这个闭环:
|
|
941
|
+
|
|
942
|
+
1. **准备命令入口**
|
|
943
|
+
- 通过 PATH / alias 暴露 `ally` 命令
|
|
944
|
+
- 必要时也可使用 workspace 本地 shim,但这只是兼容路径
|
|
945
|
+
|
|
946
|
+
2. **初始化外壳**
|
|
947
|
+
- 运行 `ally setup`
|
|
948
|
+
- 生成 `.work-ally/`、配置模板与内部实现
|
|
949
|
+
|
|
950
|
+
3. **启动远程入口**
|
|
951
|
+
- 运行 `ally start`
|
|
952
|
+
- 本机拉起 Runtime Host 与 Feishu Bridge
|
|
953
|
+
- 从这一刻开始,飞书已经可以作为这个工作空间的远程入口
|
|
954
|
+
|
|
955
|
+
4. **电脑前直接工作**
|
|
956
|
+
- 在同一个工作空间内继续使用官方 Codex CLI / App / IDE
|
|
957
|
+
- 这是主工作方式,也是最高保真的原生体验
|
|
958
|
+
|
|
959
|
+
5. **外出时通过飞书继续工作**
|
|
960
|
+
- 同一个人、同一个工作空间、同一套 Runtime 边界
|
|
961
|
+
- 飞书只是入口变化,不是背后换了一个大脑
|
|
962
|
+
|
|
963
|
+
6. **定义主动例行任务**
|
|
964
|
+
- 把需要长期执行的任务定义为工作空间内的主动任务文件;绿地默认放在 `routines/`,已有工程则由 `routines_path` 映射
|
|
965
|
+
- 例如:晨报、晚报、每日 issue 巡检、知识库整理、异常巡查
|
|
966
|
+
|
|
967
|
+
7. **先手动试跑,再进入定时执行**
|
|
968
|
+
- 通过 `ally routine run <name>` 先验证任务是否合理
|
|
969
|
+
- 验证通过后再由 `work-ally` 编排层按计划主动触发
|
|
970
|
+
|
|
971
|
+
8. **结果回流到同一个工作空间闭环里**
|
|
972
|
+
- 运行结果写入 assistant desk 的 `.system/runs/` 与日志
|
|
973
|
+
- 关键摘要主动推送到飞书
|
|
974
|
+
- 需要时可以在电脑前继续追问、修正、跟进
|
|
975
|
+
|
|
976
|
+
因此,这套系统对用户的真正承诺不是“我给你一个飞书 bot”,而是:
|
|
977
|
+
|
|
978
|
+
> **我给你的工作空间接上一个既能被动对话、又能主动工作的官方 Codex 伙伴。**
|
|
979
|
+
|
|
980
|
+
### 6.10 从使用者视角的最小必要动作
|
|
981
|
+
|
|
982
|
+
如果从使用者视角反推,这套系统长期只应要求他做四类事:
|
|
983
|
+
|
|
984
|
+
1. **维护项目与 desk 各自资产**
|
|
985
|
+
- 项目内维护 `AGENTS.md`、源码、`docs/` / `specs/` / `notes/` 等项目知识
|
|
986
|
+
- desk 内维护 `SOUL.md`、`NOW.md`、`MEMORY.md`、`MISTAKES.md`、`journal/`、`conversations/`
|
|
987
|
+
2. **放入或更新门面**
|
|
988
|
+
- 保持项目根目录可调用 `ally.sh`;若门面丢失,重新放回即可
|
|
989
|
+
3. **填写最小本地运行配置**
|
|
990
|
+
- 只填写 assistant desk 的飞书接入、allowlist、远端仓库这类本地配置
|
|
991
|
+
4. **运行少量稳定命令**
|
|
992
|
+
- `setup`、`start`、`status`、`logs`、`update`、`routine ...`
|
|
993
|
+
|
|
994
|
+
除此之外,用户不应再承担:
|
|
995
|
+
|
|
996
|
+
- 理解内部实现仓库怎么组织
|
|
997
|
+
- 理解 App Server 协议细节
|
|
998
|
+
- 理解 session 文件结构与调度器内部状态
|
|
999
|
+
- 手动维护 bridge 与 runtime 之间的内部依赖关系
|
|
1000
|
+
- 手工记录每次对话的原始材料
|
|
1001
|
+
|
|
1002
|
+
换句话说,任何超出这四类的动作,都应该尽量被系统内部自动吸收。
|
|
1003
|
+
|
|
1004
|
+
### 6.11 可整体替换与重建原则
|
|
1005
|
+
|
|
1006
|
+
这套系统必须从设计上满足“实现可替换、用户资产不跟着丢”的要求。
|
|
1007
|
+
|
|
1008
|
+
第一阶段建议明确四层分离:
|
|
1009
|
+
|
|
1010
|
+
1. **项目工作现场资产**
|
|
1011
|
+
- 项目 `AGENTS.md`、源码、`docs/` / `specs/` / `notes/`、被 `writeback` 沉淀回项目的长期成果文件
|
|
1012
|
+
2. **assistant desk 资产**
|
|
1013
|
+
- `AGENTS.md`、`SOUL.md`、`NOW.md`、`MEMORY.md`、`MISTAKES.md`、`journal/`、`conversations/`、`.system/routines/`
|
|
1014
|
+
3. **官方 Codex 本地家目录**
|
|
1015
|
+
- `~/.codex/config.toml`、`auth.json`、provider/model 配置与登录态
|
|
1016
|
+
4. **可替换的内部实现与纯运行态**
|
|
1017
|
+
- 实现缓存、assistant desk 下的 `.system/runtime/`、`.system/runs/`、`.system/logs/`、`.system/cache/`
|
|
1018
|
+
|
|
1019
|
+
这四层里,前三层属于真正必须长期保留的资产;最后一层不应成为不可替换黑盒。
|
|
1020
|
+
|
|
1021
|
+
因此,系统应满足下面这些重建预期:
|
|
1022
|
+
|
|
1023
|
+
- 如果实现缓存被删除,`ally setup` 或 `ally update` 应能把它重新装回
|
|
1024
|
+
- 如果运行中的实现仓库整个丢失,只要项目资产与 assistant desk 还在,重新恢复 `ally` 命令入口后,就应能重新完成 `setup/start`
|
|
1025
|
+
- 如果 assistant desk 下的 `.system/runtime/`、`.system/logs/`、`.system/cache/` 丢失,系统应能通过下一次 `start` 自动重建最小运行外壳
|
|
1026
|
+
- 如果某段结果真的需要长期保留,就不应只留在运行态目录里,而应写回项目文件或 desk 根目录可见资产
|
|
1027
|
+
- 如果项目资产或 assistant desk 资产本身被误删,恢复路径应依赖版本管理、同步盘或常规备份策略保护
|
|
1028
|
+
|
|
1029
|
+
这条原则的本质是:
|
|
1030
|
+
|
|
1031
|
+
> **用户拥有的是项目资产与 assistant desk 资产;`work-ally` 只是可重装的承载外壳。**
|
|
1032
|
+
|
|
1033
|
+
---
|
|
1034
|
+
|
|
1035
|
+
## 7. 系统边界与职责分配
|
|
1036
|
+
|
|
1037
|
+
### 7.1 实现仓库负责什么
|
|
1038
|
+
|
|
1039
|
+
最终实现仓库负责:
|
|
1040
|
+
|
|
1041
|
+
- Feishu 接入
|
|
1042
|
+
- 会话与线程映射
|
|
1043
|
+
- Runtime 连接与事件订阅
|
|
1044
|
+
- 审批回传
|
|
1045
|
+
- 主动例行任务调度
|
|
1046
|
+
- 单工作空间边界内的最小状态存储
|
|
1047
|
+
- 部署脚本、运行说明、运维边界
|
|
1048
|
+
|
|
1049
|
+
### 7.2 官方 Codex 负责什么
|
|
1050
|
+
|
|
1051
|
+
官方 Codex 负责:
|
|
1052
|
+
|
|
1053
|
+
- 模型与推理质量
|
|
1054
|
+
- agent loop
|
|
1055
|
+
- 工具执行语义
|
|
1056
|
+
- `thread / turn / event / approval` 等 runtime 机制
|
|
1057
|
+
- 运行时协议的稳定能力
|
|
1058
|
+
|
|
1059
|
+
### 7.3 工作空间所有者负责什么
|
|
1060
|
+
|
|
1061
|
+
使用者负责:
|
|
1062
|
+
|
|
1063
|
+
- 维护工作空间内的 `AGENTS.md`
|
|
1064
|
+
- 维护长期记忆文件与知识源材料
|
|
1065
|
+
- 决定允许 AI 读取 / 修改 / 执行的边界
|
|
1066
|
+
- 决定 provider、模型、审批策略与部署环境
|
|
1067
|
+
|
|
1068
|
+
但使用者**不负责**手工撰写每轮对话的黑匣子记录;那部分应由系统自动采集。
|
|
1069
|
+
|
|
1070
|
+
### 7.4 一个最重要的边界原则
|
|
1071
|
+
|
|
1072
|
+
> **工作空间负责上下文,Codex 负责智能,飞书负责触达,`work-ally` 负责桥接与编排。**
|
|
1073
|
+
|
|
1074
|
+
后续所有设计细节都不能越过这条边界。
|
|
1075
|
+
|
|
1076
|
+
---
|
|
1077
|
+
|
|
1078
|
+
## 8. 一致性模型:同一大脑、同一环境、同一线程,到底分别是什么意思
|
|
1079
|
+
|
|
1080
|
+
这是整份方案里最容易被误解的地方,必须专门讲清楚。
|
|
1081
|
+
|
|
1082
|
+
### 8.1 什么叫“同一大脑”
|
|
1083
|
+
|
|
1084
|
+
这里的“同一大脑”指的是:
|
|
1085
|
+
|
|
1086
|
+
- 两个入口都接入同一类官方 Codex runtime / harness 能力
|
|
1087
|
+
- 飞书端不是另一套自研 agent
|
|
1088
|
+
- 桌面端与飞书端都以同一个工作空间为上下文中心
|
|
1089
|
+
|
|
1090
|
+
所以,“同一大脑”首先是:
|
|
1091
|
+
|
|
1092
|
+
> **同一类官方 Codex 能力边界。**
|
|
1093
|
+
|
|
1094
|
+
### 8.2 什么叫“同一环境”
|
|
1095
|
+
|
|
1096
|
+
“同一环境”指的是:
|
|
1097
|
+
|
|
1098
|
+
- 同一个工作空间目录
|
|
1099
|
+
- 同一台 Runtime Host
|
|
1100
|
+
- 同一组工具、依赖、凭据与本地资源
|
|
1101
|
+
|
|
1102
|
+
这一点很重要,因为:
|
|
1103
|
+
|
|
1104
|
+
- **同一大脑** 不自动等于 **同一环境**
|
|
1105
|
+
- 如果桌面端和飞书端接到不同机器,它们即使都使用官方 Codex,也可能拥有不同工具边界
|
|
1106
|
+
|
|
1107
|
+
因此,如果希望桌面端与飞书端能力尽量一致,第一阶段最推荐的做法是:
|
|
1108
|
+
|
|
1109
|
+
> **把 Workspace、Runtime Host 与 Feishu Bridge 放在同一台机器上。**
|
|
1110
|
+
|
|
1111
|
+
### 8.3 什么叫“同一 live 进程 / 同一实时 thread”
|
|
1112
|
+
|
|
1113
|
+
这指的是更强的一层一致性:
|
|
1114
|
+
|
|
1115
|
+
- 桌面端与飞书端共用同一个正在运行的 runtime 进程
|
|
1116
|
+
- 两个入口同时连接同一条实时 thread
|
|
1117
|
+
- 双方看到的是同一条正在增长的会话时间线
|
|
1118
|
+
|
|
1119
|
+
这当然很好,但它不是第一阶段成立的前提。
|
|
1120
|
+
|
|
1121
|
+
### 8.4 第一阶段真正需要保证的是什么
|
|
1122
|
+
|
|
1123
|
+
第一阶段真正要保证的是:
|
|
1124
|
+
|
|
1125
|
+
- **同一个工作空间**
|
|
1126
|
+
- **同一类官方 Codex runtime / harness**
|
|
1127
|
+
- **尽量同一台 Runtime Host**
|
|
1128
|
+
- **飞书会话与 Codex thread 之间存在稳定映射**
|
|
1129
|
+
|
|
1130
|
+
只要这四点成立:
|
|
1131
|
+
|
|
1132
|
+
- 飞书就能形成持续对话
|
|
1133
|
+
- 桌面端与飞书端面对的就是同一个工作空间背后的同一类大脑
|
|
1134
|
+
- 工具边界也更容易尽量保持一致
|
|
1135
|
+
|
|
1136
|
+
### 8.5 会话作用域:聊天窗口、thread 与 session 到底分别是什么
|
|
1137
|
+
|
|
1138
|
+
这一点必须单独讲清楚,因为它直接决定远程入口是不是“像一个真正的工作伙伴”,而不是一台每次都重新开始的问答机。
|
|
1139
|
+
|
|
1140
|
+
先说结论:
|
|
1141
|
+
|
|
1142
|
+
- **聊天窗口 / 会话窗口**:用户从哪里说话的通道范围
|
|
1143
|
+
- **Codex thread**:官方 Runtime 原生的上下文连续性单元
|
|
1144
|
+
- **`work-ally` session store**:桥接层对“当前默认 thread 绑到了哪个聊天窗口”的本地台账
|
|
1145
|
+
|
|
1146
|
+
推荐用下面这张图理解:
|
|
1147
|
+
|
|
1148
|
+
```text
|
|
1149
|
+
IM Chat / DM / Group Window
|
|
1150
|
+
│
|
|
1151
|
+
│ transport scope(从哪里说话)
|
|
1152
|
+
▼
|
|
1153
|
+
work-ally session mapping
|
|
1154
|
+
- conversation_ref -> current thread_id
|
|
1155
|
+
- active_turn_id
|
|
1156
|
+
- pending_approvals
|
|
1157
|
+
│
|
|
1158
|
+
│ context routing(当前默认上下文)
|
|
1159
|
+
▼
|
|
1160
|
+
Codex thread
|
|
1161
|
+
- 连续对话上下文
|
|
1162
|
+
- turn 时间线
|
|
1163
|
+
- approval / stop / resume 归属
|
|
1164
|
+
```
|
|
1165
|
+
|
|
1166
|
+
这里最重要的判断是:
|
|
1167
|
+
|
|
1168
|
+
> **thread 不是 `work-ally` 自己发明的第二套“大脑会话”;thread 是官方 Codex Runtime 本来就存在的原生上下文单元。**
|
|
1169
|
+
|
|
1170
|
+
`work-ally` 新增的不是另一层人格,而只是一个很薄的桥接动作:
|
|
1171
|
+
|
|
1172
|
+
> **把 IM 会话窗口映射到一个“当前默认 thread”。**
|
|
1173
|
+
|
|
1174
|
+
### 8.6 为什么这个概念一定要有
|
|
1175
|
+
|
|
1176
|
+
如果没有 thread / session 这层边界,下面这些事情就会马上变得含糊:
|
|
1177
|
+
|
|
1178
|
+
- 上一轮在说什么
|
|
1179
|
+
- `/status` 查的是哪件事
|
|
1180
|
+
- `/stop` 要停掉哪一次执行
|
|
1181
|
+
- 某条审批到底属于哪个上下文
|
|
1182
|
+
- 重启之后应该恢复哪条连续对话
|
|
1183
|
+
|
|
1184
|
+
也就是说,远程入口一旦不是“一问一答”,而是一个能持续协作的工作伙伴,就一定需要一种**工作上下文作用域**。
|
|
1185
|
+
|
|
1186
|
+
这个作用域既不能大到“整个飞书里所有事情都混在一起”,也不能小到“每条消息都像第一次见面”。
|
|
1187
|
+
|
|
1188
|
+
因此第一阶段的最小正确建模是:
|
|
1189
|
+
|
|
1190
|
+
- **通道窗口**负责天然分流不同事项
|
|
1191
|
+
- **thread** 负责承载某个事项的连续上下文
|
|
1192
|
+
- **session store** 负责记住“这个窗口当前默认接着哪条 thread”
|
|
1193
|
+
|
|
1194
|
+
### 8.7 面向使用者的实际语义
|
|
1195
|
+
|
|
1196
|
+
从使用者视角,这套模型应当非常直觉:
|
|
1197
|
+
|
|
1198
|
+
- **同一个窗口里,同一件事继续聊**:默认继续当前 thread
|
|
1199
|
+
- **同一个窗口里,想彻底开新话题**:使用 `/new`,下一条消息进入新的 thread
|
|
1200
|
+
- **多个长期并行事项**:最自然的做法仍然是放在不同聊天窗口 / 会话里,各自维护自己的默认 thread
|
|
1201
|
+
|
|
1202
|
+
这背后的原则不是“为了引入 thread 而引入 thread”,而是:
|
|
1203
|
+
|
|
1204
|
+
> **既要连续,又要隔离。**
|
|
1205
|
+
|
|
1206
|
+
没有连续性,助手每次都像刚进来的实习生;没有隔离性,不同事情又会相互污染。
|
|
1207
|
+
|
|
1208
|
+
### 8.8 原生状态优先原则
|
|
1209
|
+
|
|
1210
|
+
在“用户是否会误以为卡死”这个问题上,`work-ally` 的默认策略应当是:
|
|
1211
|
+
|
|
1212
|
+
- 优先相信官方 Runtime / App Server 已经定义好的状态语义
|
|
1213
|
+
- 优先消费它的 `thread status`、`turn` 生命周期、审批等待等原生信号
|
|
1214
|
+
- 不在桥接层长期维护一套越来越厚的“自造状态机”
|
|
1215
|
+
|
|
1216
|
+
目前从协议能力上看,官方 Runtime 已经至少提供:
|
|
1217
|
+
|
|
1218
|
+
- `thread/status/changed` 这类线程状态通知
|
|
1219
|
+
- `thread/read` 返回的线程当前状态
|
|
1220
|
+
- `waitingOnApproval`、`waitingOnUserInput` 这类 active flags
|
|
1221
|
+
- `turn/start`、`turn/completed`、`turn/interrupt`、`turn/steer` 这类 turn 级语义
|
|
1222
|
+
- `thread/tokenUsage/updated`:线程 token usage 更新,且包含 `modelContextWindow`
|
|
1223
|
+
- `thread/compact/start`:主动发起一次原生 compact
|
|
1224
|
+
- `contextCompaction` item,以及兼容通知 `thread/compacted`
|
|
1225
|
+
|
|
1226
|
+
这说明“上下文进度”和“主动 compact”从原则上都应该沿着 Runtime 原生协议做薄透传,而不是让 `work-ally` 自己估 token、自己总结压缩。
|
|
1227
|
+
|
|
1228
|
+
因此,第一阶段正确的方向不是在 `work-ally` 里不断加厚“还在处理、排队中、继续等待”之类的人造提示层,而是:
|
|
1229
|
+
|
|
1230
|
+
- 只保留必要的渠道级 receipt(如 reaction)
|
|
1231
|
+
- 让正式回复、审批等待、turn 完成尽量由 Runtime 原生语义驱动
|
|
1232
|
+
- 把桥接层的补充提示限制在少量降级兜底场景
|
|
1233
|
+
|
|
1234
|
+
### 8.8 第一阶段不做什么
|
|
1235
|
+
|
|
1236
|
+
第一阶段不把问题复杂化为:
|
|
1237
|
+
|
|
1238
|
+
- 命名 thread 列表管理器
|
|
1239
|
+
- 在一个窗口里手工切换十几个历史 thread
|
|
1240
|
+
- 多助手、多人格、多角色会话编排
|
|
1241
|
+
|
|
1242
|
+
这些都不是第一版成立所必需的。
|
|
1243
|
+
|
|
1244
|
+
第一版只需要把下面这条路径做扎实:
|
|
1245
|
+
|
|
1246
|
+
- 一个聊天窗口有一个当前默认 thread
|
|
1247
|
+
- `/new` 可以显式切换到新的 thread
|
|
1248
|
+
- `/status`、`/approve`、`/deny`、`/stop` 都明确落在当前上下文上
|
|
1249
|
+
- `/status` 展示的是“本地 bridge 会话状态 + Runtime 原生线程状态”的合并视图,而不是桥接层自造的一套厚状态机
|
|
1250
|
+
- session 台账可恢复、可观察、可排障
|
|
1251
|
+
|
|
1252
|
+
---
|
|
1253
|
+
|
|
1254
|
+
## 9. 状态模型、黑匣子归档与文件化 session store
|
|
1255
|
+
|
|
1256
|
+
这一节回答四个问题:
|
|
1257
|
+
|
|
1258
|
+
1. 哪些状态应该放在工作空间里?
|
|
1259
|
+
2. 哪些状态应该放在桥接层?
|
|
1260
|
+
3. 黑匣子原材料由谁来记录?
|
|
1261
|
+
4. 这些状态第一阶段到底该不该进数据库?
|
|
1262
|
+
|
|
1263
|
+
这里先把答案说死:
|
|
1264
|
+
|
|
1265
|
+
> **运行连续性由 session store 负责;黑匣子原材料由系统自动归档;长期记忆由独立的 memory-digest 过程提炼。**
|
|
1266
|
+
|
|
1267
|
+
### 9.1 工作空间上下文与运行态必须分开
|
|
1268
|
+
|
|
1269
|
+
工作空间上下文应继续放在工作空间里,用文件管理:
|
|
1270
|
+
|
|
1271
|
+
- `AGENTS.md`
|
|
1272
|
+
- 记忆文件(如每日记忆、长期记忆)
|
|
1273
|
+
- 知识源文件(如 `docs/`、`specs/`、`notes/`、`README.md`)
|
|
1274
|
+
- `routines_path` 指向的主动例行任务定义
|
|
1275
|
+
- 其他需要长期保留、可版本化的工作材料
|
|
1276
|
+
|
|
1277
|
+
当前 shipped model 对这段的收敛是:
|
|
1278
|
+
|
|
1279
|
+
- “这个 AI 伙伴是谁” 主要由 assistant desk 承载
|
|
1280
|
+
- “当前项目要求什么” 仍由项目工作空间文件承载
|
|
1281
|
+
- “这次远程对话进行到哪里” 由 assistant desk 下的 `.system/runtime/`、`conversations/`、`runs/` 等目录承载
|
|
1282
|
+
|
|
1283
|
+
也就是说,长期 assistant 资产与瞬时运行状态都已经进入 assistant desk,而不是继续放在项目目录内的 `.work-ally/`。
|
|
1284
|
+
|
|
1285
|
+
> **`.work-ally/` 不是长期记忆仓库;真正需要长期保留、迁移或进入版本历史的内容,必须回到工作空间本身。**
|
|
1286
|
+
|
|
1287
|
+
### 9.2 为什么第一阶段不默认引入数据库
|
|
1288
|
+
|
|
1289
|
+
第一阶段不默认引入数据库,理由非常充分:
|
|
1290
|
+
|
|
1291
|
+
- 桥接状态本身并不重
|
|
1292
|
+
- 文件目录对普通开发者更透明、更可理解
|
|
1293
|
+
- 调试时可以直接进入目录查看会话与 turn 记录
|
|
1294
|
+
- 后续做记忆压缩、摘要沉淀、人工整理时,文件更容易衔接
|
|
1295
|
+
- 过早引入数据库会增加黑盒感与维护成本
|
|
1296
|
+
|
|
1297
|
+
因此,当前推荐原则是:
|
|
1298
|
+
|
|
1299
|
+
> **默认使用文件化 session store;只有在并发、恢复、查询复杂度真正上来时,才再考虑可替换的数据库实现。**
|
|
1300
|
+
|
|
1301
|
+
### 9.3 运行 session 与黑匣子 archive 是两回事
|
|
1302
|
+
|
|
1303
|
+
这一点必须单独讲清楚,否则后续实现很容易混淆。
|
|
1304
|
+
|
|
1305
|
+
#### A. assistant desk 的 `.system/runtime/` 是运行连续性台账
|
|
1306
|
+
|
|
1307
|
+
它负责:
|
|
1308
|
+
|
|
1309
|
+
- conversation -> thread 映射
|
|
1310
|
+
- turn 开始/结束状态
|
|
1311
|
+
- 审批待处理状态
|
|
1312
|
+
- 当前线程、最近一次摘要、事件追加日志
|
|
1313
|
+
|
|
1314
|
+
它回答的是:
|
|
1315
|
+
|
|
1316
|
+
> **这次远程对话现在进行到哪里了?**
|
|
1317
|
+
|
|
1318
|
+
#### B. `archive_path` 是黑匣子原材料
|
|
1319
|
+
|
|
1320
|
+
它负责:
|
|
1321
|
+
|
|
1322
|
+
- 保存完整的原始对话材料与关键事件材料
|
|
1323
|
+
- 作为后续记忆压缩的输入源
|
|
1324
|
+
- 让人可以在文件系统中回看某天到底发生了什么
|
|
1325
|
+
|
|
1326
|
+
它回答的是:
|
|
1327
|
+
|
|
1328
|
+
> **这段协作历史原始发生过什么?**
|
|
1329
|
+
|
|
1330
|
+
#### C. 记录黑匣子的不是人,也不是靠模型自觉
|
|
1331
|
+
|
|
1332
|
+
第一阶段必须坚持:
|
|
1333
|
+
|
|
1334
|
+
- 黑匣子由系统自动落盘
|
|
1335
|
+
- 不能依赖模型“顺手写一下”
|
|
1336
|
+
- 不能依赖人类手工整理后再补录
|
|
1337
|
+
|
|
1338
|
+
也就是说,只要一段交互经过 `work-ally` 的管道,它的原材料就应当被自动归档。
|
|
1339
|
+
|
|
1340
|
+
#### D. 第一阶段能稳定自动采集哪些原材料
|
|
1341
|
+
|
|
1342
|
+
第一阶段能硬保证自动黑匣子化的,是:
|
|
1343
|
+
|
|
1344
|
+
- 经过 Feishu Bridge 的对话
|
|
1345
|
+
- 由 `work-ally` 主动触发的 routine 执行
|
|
1346
|
+
- `ally` 这一层可观测到的关键事件流
|
|
1347
|
+
|
|
1348
|
+
第一阶段**不应假装承诺**自动采集下面这类材料:
|
|
1349
|
+
|
|
1350
|
+
- 用户直接在官方 Codex CLI / App 中进行、但没有经过 `work-ally` 管道的全部桌面会话
|
|
1351
|
+
|
|
1352
|
+
对于这部分桌面端协作,第一阶段更稳妥的原则是:
|
|
1353
|
+
|
|
1354
|
+
- 重要结果应沉淀回工作空间文件
|
|
1355
|
+
- 一旦官方后续暴露稳定的 thread/event 导出边界,再考虑做统一采集
|
|
1356
|
+
|
|
1357
|
+
### 9.4 第一阶段推荐的 session 目录结构
|
|
1358
|
+
|
|
1359
|
+
```text
|
|
1360
|
+
~/.work-ally/assistants/<name>/.system/runtime/
|
|
1361
|
+
└── sessions/
|
|
1362
|
+
└── <feishu_conversation_id>/
|
|
1363
|
+
├── meta.json
|
|
1364
|
+
├── current-thread.json
|
|
1365
|
+
├── turns/
|
|
1366
|
+
│ ├── 2026-03-06T10-00-01.json
|
|
1367
|
+
│ └── 2026-03-06T10-05-12.json
|
|
1368
|
+
├── approvals/
|
|
1369
|
+
│ └── <approval_id>.json
|
|
1370
|
+
├── summary.md
|
|
1371
|
+
└── events.ndjson
|
|
1372
|
+
```
|
|
1373
|
+
|
|
1374
|
+
这一套文件各自负责:
|
|
1375
|
+
|
|
1376
|
+
- `meta.json`:会话级元信息与去重信息
|
|
1377
|
+
- `current-thread.json`:当前默认绑定的 Codex thread
|
|
1378
|
+
- `turns/*.json`:每一轮用户输入及桥接侧记录
|
|
1379
|
+
- `approvals/*.json`:待处理或已处理审批记录
|
|
1380
|
+
- `summary.md`:可读摘要,供人工查看与后续压缩整理
|
|
1381
|
+
- `events.ndjson`:可选的追加式事件日志
|
|
1382
|
+
|
|
1383
|
+
### 9.5 这些文件到底存什么
|
|
1384
|
+
|
|
1385
|
+
第一阶段只存桥接必须知道的最小状态,例如:
|
|
1386
|
+
|
|
1387
|
+
#### `meta.json`
|
|
1388
|
+
|
|
1389
|
+
- `feishu_conversation_id`
|
|
1390
|
+
- `project_id`
|
|
1391
|
+
- `last_user_message_id`
|
|
1392
|
+
- `last_bridge_message_id`
|
|
1393
|
+
- `updated_at`
|
|
1394
|
+
|
|
1395
|
+
#### `current-thread.json`
|
|
1396
|
+
|
|
1397
|
+
- `thread_id`
|
|
1398
|
+
- `created_at`
|
|
1399
|
+
- `last_used_at`
|
|
1400
|
+
- `status`
|
|
1401
|
+
|
|
1402
|
+
#### `turns/<timestamp>.json`
|
|
1403
|
+
|
|
1404
|
+
- `turn_id`
|
|
1405
|
+
- `user_message`
|
|
1406
|
+
- `thread_id`
|
|
1407
|
+
- `started_at`
|
|
1408
|
+
- `ended_at`
|
|
1409
|
+
- `status`
|
|
1410
|
+
- `final_summary`
|
|
1411
|
+
- `pending_approval_id`(可选)
|
|
1412
|
+
|
|
1413
|
+
#### `approvals/<id>.json`
|
|
1414
|
+
|
|
1415
|
+
- `approval_id`
|
|
1416
|
+
- `turn_id`
|
|
1417
|
+
- `status`
|
|
1418
|
+
- `requested_at`
|
|
1419
|
+
- `resolved_at`
|
|
1420
|
+
- `resolver`
|
|
1421
|
+
|
|
1422
|
+
### 9.6 第一阶段推荐的黑匣子 archive 目录结构
|
|
1423
|
+
|
|
1424
|
+
为了让记忆系统真正有稳定原材料,当前 shipped model 把 archive 收敛进 assistant desk:
|
|
1425
|
+
|
|
1426
|
+
```text
|
|
1427
|
+
~/.work-ally/assistants/<name>/.system/archive/
|
|
1428
|
+
```
|
|
1429
|
+
|
|
1430
|
+
它的作用不变:
|
|
1431
|
+
|
|
1432
|
+
- 自动沉淀黑匣子原材料
|
|
1433
|
+
- 供 nightly memory digest 使用
|
|
1434
|
+
- 供调试、追溯、回放使用
|
|
1435
|
+
|
|
1436
|
+
只是资产归属已经不再是项目目录,而是 assistant 自己的办公桌。
|
|
1437
|
+
|
|
1438
|
+
#### 这些黑匣子文件的要求
|
|
1439
|
+
|
|
1440
|
+
- **以系统自动写入为准**,而不是让模型或人手工补写
|
|
1441
|
+
- **以人可读文本为准**,优先 Markdown 或同类可直接查看的格式
|
|
1442
|
+
- **按时间天然切分**,便于夜间按日汇总
|
|
1443
|
+
- **尽量完整保留原始上下文**,不要在入库时过早压缩
|
|
1444
|
+
|
|
1445
|
+
#### 一个黑匣子文件至少应包含什么
|
|
1446
|
+
|
|
1447
|
+
- 来源:`feishu` / `routine`
|
|
1448
|
+
- 会话标识或 routine 名称
|
|
1449
|
+
- 时间戳
|
|
1450
|
+
- 用户输入 / 触发原因
|
|
1451
|
+
- 关键中间事件摘要(若有)
|
|
1452
|
+
- 最终回复或最终结果
|
|
1453
|
+
- 相关 thread_id / turn_id(若可得)
|
|
1454
|
+
|
|
1455
|
+
### 9.7 记忆压缩与长期记忆的形成方式
|
|
1456
|
+
|
|
1457
|
+
当前 shipped model 下,这条链路已经明确收敛为:
|
|
1458
|
+
|
|
1459
|
+
```text
|
|
1460
|
+
assistant desk archive -> nightly memory-digest -> journal -> MEMORY.md
|
|
1461
|
+
```
|
|
1462
|
+
|
|
1463
|
+
其中 `NOW.md` 的 owner 是 assistant 本身,工作中随手更新;`MISTAKES.md` 以 assistant 明确犯错后的即时更新为主,digest 在 V1 不强制回写。
|
|
1464
|
+
|
|
1465
|
+
推荐做法是:
|
|
1466
|
+
|
|
1467
|
+
- `work-ally` 常驻后,按计划触发系统级 routine
|
|
1468
|
+
- 例行任务读取 assistant desk 下当天的 archive 原材料
|
|
1469
|
+
- 在独立的 Codex thread 中完成提炼,而不是复用业务对话 thread
|
|
1470
|
+
- 输出到 assistant desk:
|
|
1471
|
+
- `journal/YYYY-MM-DD.md`
|
|
1472
|
+
- `MEMORY.md`
|
|
1473
|
+
|
|
1474
|
+
这条链的关键意义不变:
|
|
1475
|
+
|
|
1476
|
+
- 原材料完整且自动
|
|
1477
|
+
- 提炼动作独立且可重复
|
|
1478
|
+
- 长期记忆属于 assistant desk 资产,而不是项目运行态副产品
|
|
1479
|
+
|
|
1480
|
+
#### 版本管理建议
|
|
1481
|
+
|
|
1482
|
+
- `journal/`、`MEMORY.md`、`MISTAKES.md`、`NOW.md`、`SOUL.md` 建议进入 assistant desk Git 历史
|
|
1483
|
+
- `.system/archive/` 是否进入远端版本历史,由用户是否配置远端以及自身偏好决定
|
|
1484
|
+
|
|
1485
|
+
### 9.8 为什么这种方式更贴近目标
|
|
1486
|
+
|
|
1487
|
+
这种文件化方案的好处是:
|
|
1488
|
+
|
|
1489
|
+
- 它足够轻量
|
|
1490
|
+
- 它足够透明
|
|
1491
|
+
- 它与工作空间里的 Markdown / 文档思维一致
|
|
1492
|
+
- 它更适合你后续叠加摘要、压缩、记忆整理能力
|
|
1493
|
+
|
|
1494
|
+
也就是说,第一阶段的状态层最好像一本“可翻看的工作台账”,而不是一块普通开发者不愿碰的数据库黑盒。
|
|
1495
|
+
|
|
1496
|
+
### 9.9 Bridge 内部仍然需要统一事件语义
|
|
1497
|
+
|
|
1498
|
+
虽然状态优先文件化,但 Bridge 内部仍然应该统一一组最小事件语义,避免实现过程东拼西凑。
|
|
1499
|
+
|
|
1500
|
+
#### 从飞书进入 Bridge 的命令/事件
|
|
1501
|
+
|
|
1502
|
+
- `user_message`
|
|
1503
|
+
- `new_thread`
|
|
1504
|
+
- `status_query`
|
|
1505
|
+
- `approval_resolve`
|
|
1506
|
+
- `stop_task`
|
|
1507
|
+
|
|
1508
|
+
#### 从 Runtime 返回给 Bridge 的事件
|
|
1509
|
+
|
|
1510
|
+
- `message`
|
|
1511
|
+
- `progress`
|
|
1512
|
+
- `approval_required`
|
|
1513
|
+
- `approval_resolved`
|
|
1514
|
+
- `final`
|
|
1515
|
+
- `error`
|
|
1516
|
+
- `status`
|
|
1517
|
+
|
|
1518
|
+
这些事件是程序内部的语义边界,不是给用户看的协议术语。
|
|
1519
|
+
|
|
1520
|
+
---
|
|
1521
|
+
|
|
1522
|
+
## 10. 整体交互流程
|
|
1523
|
+
|
|
1524
|
+
这一节只讲系统怎么跑,不陷入协议细节。
|
|
1525
|
+
|
|
1526
|
+
### 10.1 场景一:电脑前工作
|
|
1527
|
+
|
|
1528
|
+
```text
|
|
1529
|
+
用户 → 官方 Codex 工具 → Codex Runtime → 工作空间目录
|
|
1530
|
+
```
|
|
1531
|
+
|
|
1532
|
+
含义:
|
|
1533
|
+
|
|
1534
|
+
- 这是主工作方式
|
|
1535
|
+
- 不需要飞书参与
|
|
1536
|
+
- 用户继续享受官方 Codex 的原生体验
|
|
1537
|
+
|
|
1538
|
+
### 10.2 场景二:外出时通过飞书持续对话
|
|
1539
|
+
|
|
1540
|
+
```text
|
|
1541
|
+
用户 → 飞书 → Feishu Bridge → Codex Runtime → 工作空间目录
|
|
1542
|
+
│
|
|
1543
|
+
└-> 系统自动落黑匣子原材料
|
|
1544
|
+
```
|
|
1545
|
+
|
|
1546
|
+
含义:
|
|
1547
|
+
|
|
1548
|
+
- 飞书收到消息
|
|
1549
|
+
- Bridge 将消息转成 Runtime 可以消费的输入
|
|
1550
|
+
- 同一个飞书会话默认进入同一个 Codex thread
|
|
1551
|
+
- Codex 基于同一个工作空间进行思考与执行
|
|
1552
|
+
- 结果再以飞书消息形式返回
|
|
1553
|
+
- 与此同时,系统自动把这一轮交互写入黑匣子 archive
|
|
1554
|
+
|
|
1555
|
+
这里飞书不是一次性问答入口,而是一个可持续的远程入口。
|
|
1556
|
+
|
|
1557
|
+
### 10.3 场景三:长任务执行
|
|
1558
|
+
|
|
1559
|
+
```text
|
|
1560
|
+
飞书发起任务 → Bridge 转给 Runtime → Runtime 持续执行 → 关键进度回传飞书
|
|
1561
|
+
```
|
|
1562
|
+
|
|
1563
|
+
含义:
|
|
1564
|
+
|
|
1565
|
+
- 用户不只看最终答案
|
|
1566
|
+
- 对于长任务,飞书要能看到阶段性进度摘要
|
|
1567
|
+
- 飞书因此是远程观察窗,而不只是一次性问答入口
|
|
1568
|
+
|
|
1569
|
+
### 10.4 场景四:需要审批的任务
|
|
1570
|
+
|
|
1571
|
+
```text
|
|
1572
|
+
Runtime 需要审批 → Bridge 转译成飞书可操作消息 → 用户批准/拒绝 → Bridge 回送 Runtime
|
|
1573
|
+
```
|
|
1574
|
+
|
|
1575
|
+
含义:
|
|
1576
|
+
|
|
1577
|
+
- 审批能力属于 Runtime
|
|
1578
|
+
- 飞书只是审批交互载体
|
|
1579
|
+
- 用户外出时仍可控制高风险操作
|
|
1580
|
+
|
|
1581
|
+
### 10.5 场景五:回到电脑继续工作
|
|
1582
|
+
|
|
1583
|
+
理想目标是:
|
|
1584
|
+
|
|
1585
|
+
- 用户回到电脑后,仍围绕同一个工作空间继续工作
|
|
1586
|
+
- 桌面端与飞书端面对的是同一类官方 Codex 能力边界
|
|
1587
|
+
- 如果两端接在同一台 Runtime Host 上,工具环境也更容易一致
|
|
1588
|
+
- 即使第一阶段不共享同一条实时 thread,也不影响“它是不是同一个 AI 伙伴”这个核心判断
|
|
1589
|
+
|
|
1590
|
+
---
|
|
1591
|
+
|
|
1592
|
+
### 10.6 场景六:主动例行任务
|
|
1593
|
+
|
|
1594
|
+
```text
|
|
1595
|
+
计划触发器 / 定时器 -> work-ally 编排层 -> Codex Runtime -> 项目工作现场
|
|
1596
|
+
│
|
|
1597
|
+
├-> 飞书结果推送 + assistant desk `.system/runs/` 记录
|
|
1598
|
+
└-> 系统自动落 assistant desk 黑匣子原材料
|
|
1599
|
+
```
|
|
1600
|
+
|
|
1601
|
+
含义:
|
|
1602
|
+
|
|
1603
|
+
- **主动能力不属于 App Server 本身**
|
|
1604
|
+
- App Server 只负责接住一次被触发的 thread / turn 并执行
|
|
1605
|
+
- “什么时候触发、执行哪条例行任务、结果推送到哪里”属于 `work-ally` 的编排层
|
|
1606
|
+
- routine 执行后的原始过程材料也应自动进入黑匣子 archive,而不是靠模型额外再写一份
|
|
1607
|
+
- 主动任务执行后,用户既可以在飞书里继续追问,也可以回到电脑前围绕同一个工作空间继续工作
|
|
1608
|
+
|
|
1609
|
+
这样,被动对话与主动触发就形成了统一闭环:
|
|
1610
|
+
|
|
1611
|
+
- 被动时:人来找它
|
|
1612
|
+
- 主动时:它按计划来找人
|
|
1613
|
+
- 无论哪一种,背后都还是同一个工作空间与同一类官方 Codex 能力边界
|
|
1614
|
+
|
|
1615
|
+
### 10.7 场景七:夜间记忆压缩
|
|
1616
|
+
|
|
1617
|
+
```text
|
|
1618
|
+
夜间计划触发 -> work-ally memory-digest routine -> 读取当天黑匣子 archive
|
|
1619
|
+
│
|
|
1620
|
+
└-> 写入 daily memory / long-term memory
|
|
1621
|
+
```
|
|
1622
|
+
|
|
1623
|
+
含义:
|
|
1624
|
+
|
|
1625
|
+
- 这是一条系统级主动能力,而不是要求模型在白天“顺手记忆”
|
|
1626
|
+
- 它读取当天所有已自动落盘的黑匣子材料
|
|
1627
|
+
- 在独立 thread 中完成总结、提炼与记忆更新
|
|
1628
|
+
- 最终把结果写回工作空间侧的每日记忆与长期记忆文件
|
|
1629
|
+
|
|
1630
|
+
这一步完成后,“黑匣子原材料 -> 记忆提炼 -> 第二天继续协作”才形成真正闭环。
|
|
1631
|
+
|
|
1632
|
+
---
|
|
1633
|
+
|
|
1634
|
+
## 11. IM 侧交互约定(第一版当前由 Feishu 实现)
|
|
1635
|
+
|
|
1636
|
+
为了让远程入口可用且可解释,第一版建议只约定一组最小命令语义。
|
|
1637
|
+
|
|
1638
|
+
### 11.1 普通文本
|
|
1639
|
+
|
|
1640
|
+
- 默认进入当前 IM 会话绑定的 Codex Thread
|
|
1641
|
+
- 作为该线程中的连续输入
|
|
1642
|
+
|
|
1643
|
+
### 11.1.1 收到即确认(Immediate Ack)
|
|
1644
|
+
|
|
1645
|
+
这一点应当作为第一版的明确交互要求,而不是锦上添花。
|
|
1646
|
+
|
|
1647
|
+
当一条合法消息进入 `Channel Adapter` 并通过最小校验后,应立即返回一个**轻量 receipt**,告诉用户“系统已经收到,正在处理”。
|
|
1648
|
+
|
|
1649
|
+
抽象上,这个能力应被理解为:
|
|
1650
|
+
|
|
1651
|
+
- `ack_received(conversation_ref, message_ref)`
|
|
1652
|
+
|
|
1653
|
+
而不是某个特定平台的私有行为。
|
|
1654
|
+
|
|
1655
|
+
当前第一版若由飞书实现,最合适的方式就是:
|
|
1656
|
+
|
|
1657
|
+
- 优先使用 **reaction emoji** 作为即时回执
|
|
1658
|
+
- emoji 类型可配置,当前默认使用 `Typing`
|
|
1659
|
+
- 默认先用 reaction emoji 做即时回执;若桥接层在短阈值内仍无可见进度,会补一条“已收到,开始处理。”系统状态
|
|
1660
|
+
- 长耗时期间优先依赖 App Server / Runtime 的原生状态与进度事件;若暂时没有原生进度,再由 bridge 补最小 heartbeat,避免用户误判为卡住
|
|
1661
|
+
- 只有当实施者显式开启降级兜底时,才在长时间没有原生进度事件的情况下补一条如“仍在处理,请稍候。”的心跳提示
|
|
1662
|
+
- 如果未来某个渠道不支持 reaction,再降级为一条极短状态消息
|
|
1663
|
+
|
|
1664
|
+
这里还要明确边界:
|
|
1665
|
+
|
|
1666
|
+
- 这个回执只表示 **bridge 已收到并接受处理**
|
|
1667
|
+
- 它不表示 runtime 已完成,也不表示高风险动作已获批准
|
|
1668
|
+
- 它属于 **Channel Adapter 的职责**,不属于 core bridge 或 runtime-client 的职责
|
|
1669
|
+
|
|
1670
|
+
### 11.2 `/new`
|
|
1671
|
+
|
|
1672
|
+
- 在当前飞书会话下创建新的 Codex Thread
|
|
1673
|
+
- 用于切换话题,避免继续污染旧线程
|
|
1674
|
+
|
|
1675
|
+
### 11.3 `/status`
|
|
1676
|
+
|
|
1677
|
+
- 查询当前会话是否存在运行中的任务
|
|
1678
|
+
- 返回最近任务状态、是否等待审批、最后更新时间
|
|
1679
|
+
|
|
1680
|
+
### 11.4 `/approve` / `/deny`
|
|
1681
|
+
|
|
1682
|
+
- 响应当前待处理审批
|
|
1683
|
+
- 第一版不必追求复杂交互卡片,文本命令即可形成闭环
|
|
1684
|
+
|
|
1685
|
+
### 11.5 `/stop`
|
|
1686
|
+
|
|
1687
|
+
- 请求停止当前长任务
|
|
1688
|
+
- 作为远程中断入口
|
|
1689
|
+
|
|
1690
|
+
这套交互之所以合适,是因为它刚好覆盖了第一版真正关键的三类能力:
|
|
1691
|
+
|
|
1692
|
+
- thread 管理
|
|
1693
|
+
- 长任务观察
|
|
1694
|
+
- 审批闭环
|
|
1695
|
+
|
|
1696
|
+
---
|
|
1697
|
+
|
|
1698
|
+
## 12. 组件设计
|
|
1699
|
+
|
|
1700
|
+
为了避免一个巨大的“万能脚本 / 万能服务”,Bridge 层应该保持模块化。
|
|
1701
|
+
|
|
1702
|
+
### 12.1 Bridge Service 的模块拆分(当前接入 Feishu)
|
|
1703
|
+
|
|
1704
|
+
虽然第一阶段只交付飞书,但内部结构不应写成一团“飞书直连 Runtime”的紧耦合逻辑。
|
|
1705
|
+
|
|
1706
|
+
更合理的拆法是先把 Bridge 分成两层:
|
|
1707
|
+
|
|
1708
|
+
- **Core Bridge**:`receiver / session mapper / runtime client / archive store / scheduler / translator`
|
|
1709
|
+
- **Channel Adapter**:某个渠道自己的收消息、发消息、格式化、审批交互
|
|
1710
|
+
|
|
1711
|
+
第一阶段只实现 `channels/feishu/`;未来如果新增其他渠道,新增的应是另一个 adapter,而不是把 core bridge 改写一遍。
|
|
1712
|
+
|
|
1713
|
+
第一阶段的 `channels/feishu/adapter.ts` 负责飞书长连接事件接入、基础验签、消息发送与适配;它先把飞书事件转换成标准化 channel message,再交给下面这些 core bridge 模块处理。
|
|
1714
|
+
|
|
1715
|
+
#### A. Receiver
|
|
1716
|
+
|
|
1717
|
+
负责:
|
|
1718
|
+
|
|
1719
|
+
- 接收标准化后的入站消息
|
|
1720
|
+
- 提取统一的会话标识、用户标识与消息体
|
|
1721
|
+
- 把消息交给 session / runtime / archive 主链路
|
|
1722
|
+
|
|
1723
|
+
#### B. Session Mapper
|
|
1724
|
+
|
|
1725
|
+
负责:
|
|
1726
|
+
|
|
1727
|
+
- 找到 `Feishu Conversation -> Assistant Desk -> Codex Thread` 的映射
|
|
1728
|
+
- 管理 `/new` 等线程切换动作
|
|
1729
|
+
- 读写 assistant desk `.system/runtime/sessions/` 下的状态文件
|
|
1730
|
+
|
|
1731
|
+
#### C. Runtime Client
|
|
1732
|
+
|
|
1733
|
+
负责:
|
|
1734
|
+
|
|
1735
|
+
- 与 Codex Runtime Host 建立连接
|
|
1736
|
+
- 创建 / 恢复 / 选择 thread
|
|
1737
|
+
- 提交用户输入
|
|
1738
|
+
- 订阅事件流
|
|
1739
|
+
- 回送审批响应与中断请求
|
|
1740
|
+
|
|
1741
|
+
#### D. Event Translator
|
|
1742
|
+
|
|
1743
|
+
负责:
|
|
1744
|
+
|
|
1745
|
+
- 将 Runtime 事件翻译成 Bridge 内部统一的表现语义
|
|
1746
|
+
- 区分 `progress`、`final`、`approval_required`、`error` 等事件
|
|
1747
|
+
- 不直接决定飞书文本排版;具体渠道格式化留给对应的 channel adapter
|
|
1748
|
+
|
|
1749
|
+
#### E. Formatter
|
|
1750
|
+
|
|
1751
|
+
负责:
|
|
1752
|
+
|
|
1753
|
+
- 飞书消息格式化
|
|
1754
|
+
- 长消息分段
|
|
1755
|
+
- 输出截断与续传策略
|
|
1756
|
+
|
|
1757
|
+
#### F. Approval Adapter
|
|
1758
|
+
|
|
1759
|
+
负责:
|
|
1760
|
+
|
|
1761
|
+
- 将 Runtime 的审批请求变成飞书可操作形态
|
|
1762
|
+
- 接收用户批准/拒绝并回写 Runtime
|
|
1763
|
+
|
|
1764
|
+
在代码组织上,`E` / `F` 以及飞书事件接入逻辑都应落在 `channels/feishu/` 这一层;Bridge Core 只依赖标准 channel contract,而不直接耦合飞书 SDK 类型。
|
|
1765
|
+
|
|
1766
|
+
#### G. Ops / Health
|
|
1767
|
+
|
|
1768
|
+
负责:
|
|
1769
|
+
|
|
1770
|
+
- 健康检查
|
|
1771
|
+
- 结构化日志
|
|
1772
|
+
- 错误记录与简单恢复
|
|
1773
|
+
|
|
1774
|
+
#### H. Scheduler / Routine Engine
|
|
1775
|
+
|
|
1776
|
+
负责:
|
|
1777
|
+
|
|
1778
|
+
- 扫描 assistant desk `.system/routines/` 下的任务定义
|
|
1779
|
+
- 计算下一次触发时间
|
|
1780
|
+
- 负责防重、并发控制、手动试跑与失败重试
|
|
1781
|
+
- 为主动任务创建或复用 thread
|
|
1782
|
+
- 将主动任务结果写入 assistant desk `.system/runs/` 并决定是否推送飞书
|
|
1783
|
+
|
|
1784
|
+
#### I. Remote Docs Capability(Codex Tool Layer)
|
|
1785
|
+
|
|
1786
|
+
这一层不是 bridge 自己的实现模块,而是 **Codex 直接消费的工具能力层**。
|
|
1787
|
+
|
|
1788
|
+
它负责的事情应该理解为:
|
|
1789
|
+
|
|
1790
|
+
- 读取用户给出的飞书文档链接
|
|
1791
|
+
- 在用户明确同意时创建、更新、补写飞书文档
|
|
1792
|
+
- 把文档内容作为上下文继续交给 Codex 思考
|
|
1793
|
+
- 在 Codex 已具备对应 MCP 工具时,直接复用该能力,而不是在 `work-ally` 里重写一套
|
|
1794
|
+
|
|
1795
|
+
`work-ally` 在这一层只做两类事情:
|
|
1796
|
+
|
|
1797
|
+
- 帮当前用户把 Feishu Remote MCP 安装到 Codex 配置里
|
|
1798
|
+
- 把使用规则写清楚,尤其是:**已有远程文档链接默认只读,除非用户明确要求修改**
|
|
1799
|
+
|
|
1800
|
+
它不负责:
|
|
1801
|
+
|
|
1802
|
+
- 处理飞书 IM 事件
|
|
1803
|
+
- 决定什么时候一定要写回文档
|
|
1804
|
+
- 在 bridge 内部维护另一套文档读写 SDK / provider / 链接发布栈
|
|
1805
|
+
- 绕过用户授权直接获得更高文档权限
|
|
1806
|
+
|
|
1807
|
+
因此,本方案现在的定型判断是:
|
|
1808
|
+
|
|
1809
|
+
- **Feishu 文档能力优先走 Codex + Feishu Remote MCP**
|
|
1810
|
+
- **`work-ally` 不再保留自建文档发布子系统实现**
|
|
1811
|
+
- **文档能力的扩展优先发生在 Codex 工具层与提示策略层,而不是 bridge 内部**
|
|
1812
|
+
|
|
1813
|
+
这同样解释了为什么“个人版 URL”与“开发者版远程调用”在产品层不应被放大成两套桥接架构:
|
|
1814
|
+
|
|
1815
|
+
- 它们本质上都是 **Feishu Remote MCP 的接入形态差异**
|
|
1816
|
+
- 对 `work-ally` 来说,当前最有价值的是保持一个薄封装:`ally mcp ...`
|
|
1817
|
+
- 只要 Codex 侧能正确读取该 MCP,文档读写场景就已经成立
|
|
1818
|
+
|
|
1819
|
+
真正需要长期稳定的,不是 provider 抽象树,而是三条规则:
|
|
1820
|
+
|
|
1821
|
+
- **具备写能力 ≠ 默认允许写**
|
|
1822
|
+
- **用户给出已有文档链接时,默认按只读参考处理,除非他明确要求更新那个文档**
|
|
1823
|
+
- **Codex 针对 Feishu MCP 工具调用弹出的那类确认提示,默认由 ally 自动处理;但 Runtime 的命令 / 文件审批仍保留人工边界**
|
|
1824
|
+
|
|
1825
|
+
### 12.2 官方 Runtime 的职责边界
|
|
1826
|
+
|
|
1827
|
+
官方 Codex runtime 只做一件事:
|
|
1828
|
+
|
|
1829
|
+
> **作为唯一的大脑与协议事实来源,为 Bridge 和桌面入口提供统一的 agent 能力边界。**
|
|
1830
|
+
|
|
1831
|
+
它不负责:
|
|
1832
|
+
|
|
1833
|
+
- 飞书协议
|
|
1834
|
+
- 渠道格式化
|
|
1835
|
+
- 会话去重
|
|
1836
|
+
- 业务侧部署说明
|
|
1837
|
+
|
|
1838
|
+
### 12.3 Workspace 的最小约定
|
|
1839
|
+
|
|
1840
|
+
为了让“一个工作空间 = 一个 AI 伙伴”真正成立,第一版建议明确以下约定。
|
|
1841
|
+
|
|
1842
|
+
#### 主身份、机制能力与工作空间资产的分工
|
|
1843
|
+
|
|
1844
|
+
在工作空间这一层,第一阶段应把四种东西明确分开:
|
|
1845
|
+
|
|
1846
|
+
- **根 `AGENTS.md`**:唯一主身份说明,定义角色、边界、做事原则
|
|
1847
|
+
- **Skills**:按需加载的机制能力,承载 `memory-digest`、archive 读取、routine 辅助等 workflow
|
|
1848
|
+
- **Memory / Knowledge / Docs**:被记住、被检索、被引用的工作空间资产
|
|
1849
|
+
- **渠道薄补充**:只处理飞书这一表面的表达差异,不改写主身份
|
|
1850
|
+
|
|
1851
|
+
因此,`work-ally` 不应再生成另一份与根 `AGENTS.md` 平级竞争的主身份文件。
|
|
1852
|
+
|
|
1853
|
+
补一条更落地的原则:根 `AGENTS.md` 应尽量保持**短、稳、长期有效**;凡是会频繁变化、只在特定任务触发、或只属于某个渠道表面的内容,都应优先外移。
|
|
1854
|
+
|
|
1855
|
+
#### 第一版先约定“资产归属”,再约定“目录角色”
|
|
1856
|
+
|
|
1857
|
+
当前 shipped model 下,真正需要被约定的是:
|
|
1858
|
+
|
|
1859
|
+
- assistant desk 根目录哪些文件承载 assistant 的身份与长期记忆(如 `AGENTS.md`、`SOUL.md`、`NOW.md`、`MEMORY.md`、`MISTAKES.md`)
|
|
1860
|
+
- `.system/archive/` 承载哪些黑匣子原材料
|
|
1861
|
+
- `journal/`、`conversations/`、`MEMORY.md` 之间如何形成记忆闭环
|
|
1862
|
+
- 项目目录里哪些既有文件算知识源(如 `docs/`、`README.md`、源码与规范文件)
|
|
1863
|
+
- `.system/routines/` 承载哪些主动任务定义
|
|
1864
|
+
|
|
1865
|
+
因此,第一阶段的关键不再是给项目再设计一份路径映射文件,而是把 assistant 的家和项目工作现场严格分开。
|
|
1866
|
+
|
|
1867
|
+
#### 绿地推荐约定
|
|
1868
|
+
|
|
1869
|
+
对于一个新 assistant,推荐直接初始化标准办公桌:
|
|
1870
|
+
|
|
1871
|
+
- desk root 可见资产:`AGENTS.md`、`SOUL.md`、`NOW.md`、`MEMORY.md`、`MISTAKES.md`
|
|
1872
|
+
- `journal/`:每日沉淀与可审阅流水账
|
|
1873
|
+
- `conversations/`:对话可读视图层
|
|
1874
|
+
- `.system/archive/`:黑匣子原材料
|
|
1875
|
+
- `.system/routines/`:主动任务定义
|
|
1876
|
+
|
|
1877
|
+
#### 项目侧的低侵入约定
|
|
1878
|
+
|
|
1879
|
+
对于任何项目,不应强迫其为 assistant 改目录结构;更合理的做法是:
|
|
1880
|
+
|
|
1881
|
+
- 复用现有 `docs/`、`specs/`、`notes/`、`README.md`、源码与测试作为项目知识源
|
|
1882
|
+
- 通过项目自己的文件与规则(如 `AGENTS.md`)约束 assistant 行为
|
|
1883
|
+
- 把 assistant 私有资产完全收口到项目外的 desk 中
|
|
1884
|
+
|
|
1885
|
+
#### 应进入版本管理的内容
|
|
1886
|
+
|
|
1887
|
+
- desk 根目录下的身份文件与长期记忆文件
|
|
1888
|
+
- `journal/`、`conversations/`、`.system/routines/` 中需要长期保留的文本资产
|
|
1889
|
+
- 由 routine 或人工整理后沉淀到 desk 的长期成果
|
|
1890
|
+
- 项目本身已有、且本就应该进入项目版本历史的知识与规则文件
|
|
1891
|
+
|
|
1892
|
+
#### 视工作空间策略决定是否进入版本管理的内容
|
|
1893
|
+
|
|
1894
|
+
- 黑匣子原材料 archive
|
|
1895
|
+
|
|
1896
|
+
原因很简单:
|
|
1897
|
+
|
|
1898
|
+
- 它属于工作空间侧应保留的资产
|
|
1899
|
+
- 但它可能体积较大、敏感度较高,不一定适合默认进入 Git
|
|
1900
|
+
|
|
1901
|
+
#### 不应进入版本管理的内容
|
|
1902
|
+
|
|
1903
|
+
- 飞书凭据
|
|
1904
|
+
- assistant desk 下的 `.system/runtime/`
|
|
1905
|
+
- Bridge 本地状态
|
|
1906
|
+
- Runtime 本地运行态
|
|
1907
|
+
- 审批缓存、临时日志、调试输出
|
|
1908
|
+
|
|
1909
|
+
推荐原则是:
|
|
1910
|
+
|
|
1911
|
+
> **能作为工作空间长期上下文的内容,尽量进工作空间;只有敏感信息与纯运行态留在忽略目录或宿主机本地。**
|
|
1912
|
+
|
|
1913
|
+
再进一步说:
|
|
1914
|
+
|
|
1915
|
+
> **如果某项内容在你重装 `work-ally` 内部实现之后还必须保留,那它就不应该只存在于 `.work-ally/implementation/` 或纯运行态目录中。**
|
|
1916
|
+
|
|
1917
|
+
---
|
|
1918
|
+
|
|
1919
|
+
## 13. 部署形态
|
|
1920
|
+
|
|
1921
|
+
### 13.1 第一阶段推荐形态:个人用户友好的单机 Long Connection 模式
|
|
1922
|
+
|
|
1923
|
+
第一版最推荐的形态是:
|
|
1924
|
+
|
|
1925
|
+
- **单 assistant desk**
|
|
1926
|
+
- **单 Runtime Host**
|
|
1927
|
+
- **单 Feishu Bridge**
|
|
1928
|
+
- **单文件化 session store**
|
|
1929
|
+
|
|
1930
|
+
也就是一台机器同时承载:
|
|
1931
|
+
|
|
1932
|
+
- Project workspace
|
|
1933
|
+
- Assistant desk
|
|
1934
|
+
- Codex Runtime Host
|
|
1935
|
+
- Feishu Bridge
|
|
1936
|
+
- desk 下的 `.system/runtime/`、日志与本地运行态
|
|
1937
|
+
|
|
1938
|
+
这是最短路径,也最贴近真实使用场景。
|
|
1939
|
+
|
|
1940
|
+
这里还要明确一个非常关键的部署前提:
|
|
1941
|
+
|
|
1942
|
+
> **这台机器优先就是使用者自己的个人电脑 / 家里的常驻工作机;它不需要暴露公网入口,而是通过飞书长连接主动接入飞书平台。**
|
|
1943
|
+
|
|
1944
|
+
这其实就是第一阶段默认的产品画像:
|
|
1945
|
+
|
|
1946
|
+
- 面向个人用户
|
|
1947
|
+
- 优先解决“没有公网地址也能远程联络”
|
|
1948
|
+
- 让用户先在自己的电脑 / 常驻工作机上把闭环跑起来
|
|
1949
|
+
|
|
1950
|
+
也就是说,第一阶段的默认交付形态不是“先学会部署公网服务”,而是:
|
|
1951
|
+
|
|
1952
|
+
> **把同一个工作空间、同一个 Codex runtime、同一个 Feishu 入口先在个人机器上稳定跑通。**
|
|
1953
|
+
|
|
1954
|
+
#### 个人模式为什么优先
|
|
1955
|
+
|
|
1956
|
+
原因很简单:
|
|
1957
|
+
|
|
1958
|
+
- 对个人用户最友好
|
|
1959
|
+
- 对真实需求最贴近
|
|
1960
|
+
- 最不依赖公网基础设施
|
|
1961
|
+
- 最能先验证“同一个工作空间的远程入口”这一主命题
|
|
1962
|
+
|
|
1963
|
+
#### 未来的公司内网常驻模式
|
|
1964
|
+
|
|
1965
|
+
未来如果要把它部署在公司内网机器上,成为一个更像“真正常驻员工”的节点,方案也不应该分裂成另一套架构。
|
|
1966
|
+
|
|
1967
|
+
更合理的理解是:
|
|
1968
|
+
|
|
1969
|
+
- **核心不变**:仍然是 `work-ally + Feishu Bridge + Codex Runtime + Workspace`
|
|
1970
|
+
- **变化一:部署位置** 从个人电脑 / 家用常驻机,变成公司内网的稳定工作节点
|
|
1971
|
+
- **变化二:可联络身份范围** 从“主要是所有者本人”,扩展到“同一信任边界内被授权的人”
|
|
1972
|
+
- **变化三:运维托管方式** 从偏个人使用,升级为更正式的服务托管、日志、审计与值守
|
|
1973
|
+
|
|
1974
|
+
但无论是哪一种:
|
|
1975
|
+
|
|
1976
|
+
> **它都不是两种产品,而是同一套产品在不同部署位置、不同联络边界下的两种运行画像。**
|
|
1977
|
+
|
|
1978
|
+
只要公司内网机器能够主动访问飞书平台,这个“内网常驻模式”仍然可以继续优先使用飞书长连接,而不必被迫改造成暴露公网回调地址的服务。
|
|
1979
|
+
|
|
1980
|
+
### 13.2 这台机器可以是什么
|
|
1981
|
+
|
|
1982
|
+
可以是:
|
|
1983
|
+
|
|
1984
|
+
- 你的开发机
|
|
1985
|
+
- 一台常驻工作机
|
|
1986
|
+
- 一台自托管 VPS
|
|
1987
|
+
|
|
1988
|
+
本质上,它是:
|
|
1989
|
+
|
|
1990
|
+
> **承载工作空间与 Codex runtime 的工作节点。**
|
|
1991
|
+
|
|
1992
|
+
### 13.3 当前明确推荐的实现决策
|
|
1993
|
+
|
|
1994
|
+
为了避免后续实施反复摇摆,第一阶段建议直接收敛到以下决策:
|
|
1995
|
+
|
|
1996
|
+
#### A. Runtime 接法
|
|
1997
|
+
|
|
1998
|
+
- **以 Codex App Server 为唯一 runtime 接口**
|
|
1999
|
+
- **不走 `tmux`,不解析 TUI 文本,不把 CLI stdout 当协议层**
|
|
2000
|
+
|
|
2001
|
+
#### B. Bridge 语言
|
|
2002
|
+
|
|
2003
|
+
- 第一版优先选择 **TypeScript / Node.js** 或同类更擅长长连接与 JSON 事件流的语言
|
|
2004
|
+
- 判断标准不是语言偏好,而是:协议处理成本、事件流实现难度、调试效率、部署便利性
|
|
2005
|
+
|
|
2006
|
+
#### C. 状态存储
|
|
2007
|
+
|
|
2008
|
+
- 第一版使用**文件化 session store**
|
|
2009
|
+
- 不引入外部数据库依赖
|
|
2010
|
+
- 如果未来复杂度上升,再考虑把状态层抽象成可替换实现
|
|
2011
|
+
|
|
2012
|
+
#### D. 模型配置与鉴权归属
|
|
2013
|
+
|
|
2014
|
+
- **`work-ally` 不负责模型 provider、模型选择、API key 管理**
|
|
2015
|
+
- **这部分默认交给官方 Codex / App Server 自身处理**
|
|
2016
|
+
- `ally.sh` 不去解析 `~/.codex/config.toml`,也不复制其中的配置到 assistant desk 的 `.system/config.env`
|
|
2017
|
+
- 正确做法是:让 `work-ally` 在**同一个系统用户 / 同一个 HOME / 同一套环境变量可见性**下拉起 `codex app-server`
|
|
2018
|
+
- assistant desk 使用自己的 `.system/codex-home/` 承载运行所需的 Codex Home,同时继续遵守官方 Codex 的配置与鉴权边界
|
|
2019
|
+
|
|
2020
|
+
这里现在可以明确下来:
|
|
2021
|
+
|
|
2022
|
+
- `codex app-server` 本身就是官方 `codex` CLI 的一个子命令,而官方 CLI 文档明确说明:**Codex CLI 会继承 `~/.codex/config.toml` 中的大部分默认配置**
|
|
2023
|
+
- 官方配置文档明确说明:Codex 的本地配置与状态默认放在 `CODEX_HOME`(默认 `~/.codex`)下,其中包括 `config.toml` 与 `auth.json`
|
|
2024
|
+
- 官方 App Server 文档进一步说明:App Server 提供 `config/read`、`config/value/write`、`config/batchWrite` 等 RPC,并且这些操作直接面向用户磁盘上的 `config.toml`
|
|
2025
|
+
|
|
2026
|
+
因此,虽然官方文档未必用一句话直接写成“App Server 会读取 `~/.codex/config.toml`”,但从官方产品边界上已经足够清楚:
|
|
2027
|
+
|
|
2028
|
+
> **`codex app-server` 运行时就处在官方 Codex 的同一套配置 / 鉴权体系里。**
|
|
2029
|
+
|
|
2030
|
+
这意味着:
|
|
2031
|
+
|
|
2032
|
+
- 如果你现在通过 OpenRouter 使用 Codex,并且相关 provider/model 配置已经写在 `~/.codex/config.toml` 里,那么 App Server 应当沿用这套配置
|
|
2033
|
+
- 如果你的 provider 通过 `env_key` 引用环境变量,那么真正要保证的是:**启动 App Server 的那个服务进程也能看见同一个环境变量**
|
|
2034
|
+
- 如果你使用的是官方登录态,官方文档说明 Codex 会把登录缓存保存在 `~/.codex/auth.json` 或操作系统凭据存储中;只要 App Server 运行在同一用户上下文,它就应当复用这套登录态
|
|
2035
|
+
|
|
2036
|
+
因此,方案层面的正确边界是:
|
|
2037
|
+
|
|
2038
|
+
> **飞书和运维配置归 `work-ally`;模型与鉴权配置归 Codex / App Server。**
|
|
2039
|
+
|
|
2040
|
+
#### E. 网络接入方式
|
|
2041
|
+
|
|
2042
|
+
- 第一阶段优先采用飞书的**长连接(WebSocket)事件订阅**模式
|
|
2043
|
+
- 这意味着本地机器只需要具备**主动访问公网**的能力
|
|
2044
|
+
- **不要求公网 IP、域名或回调 URL**
|
|
2045
|
+
- 因此,`work-ally` 的目标不是把家里的电脑暴露到公网,而是让它通过长连接接入飞书平台
|
|
2046
|
+
- 这一接法同样适用于未来的公司内网常驻节点:只要内网机器允许主动连出,就仍可沿用同一接入模式
|
|
2047
|
+
|
|
2048
|
+
#### F. 运维方式
|
|
2049
|
+
|
|
2050
|
+
- Runtime Host 与 Bridge 都作为常驻服务运行
|
|
2051
|
+
- 通过 `systemd`、`launchd`、`pm2` 或同类方式托管
|
|
2052
|
+
- 必须有基本日志与健康检查
|
|
2053
|
+
|
|
2054
|
+
#### G. 安全策略
|
|
2055
|
+
|
|
2056
|
+
- 只允许预设飞书身份访问
|
|
2057
|
+
- 高风险操作必须走 Runtime 的审批闭环
|
|
2058
|
+
- Bridge 不自行放宽 Codex 的安全边界
|
|
2059
|
+
|
|
2060
|
+
### 13.3.1 第一阶段安全基线
|
|
2061
|
+
|
|
2062
|
+
如果我们要避免把家里的个人电脑变成一个“可被远程操控的肉鸡”,第一阶段必须把安全基线定得足够死。
|
|
2063
|
+
|
|
2064
|
+
建议默认执行以下规则:
|
|
2065
|
+
|
|
2066
|
+
- **默认拒绝**:`FEISHU_ALLOWED_USER_IDS` 不能为空;为空就 `start` 失败,而不是开放运行
|
|
2067
|
+
- **只做受控信任边界**:默认只服务 allowlist 内的授权对象;群聊仅接受显式呼叫、控制命令或直接 reply assistant,不做开放问答入口,也不做多租户共享。
|
|
2068
|
+
- **未来扩展到公司内网常驻模式时,也只允许扩到同一信任边界内的被授权人员**,而不是把它变成开放问答入口
|
|
2069
|
+
- **不暴露本地控制面**:Bridge 与 Runtime 的本地控制接口默认仅绑定 `127.0.0.1`,不对公网监听
|
|
2070
|
+
- **优先长连接,不开公网回调**:通过飞书长连接主动连出,而不是在家用电脑上开一个可被外部直接打到的入口
|
|
2071
|
+
- **区分 Runtime 审批 与 文档工具确认**:命令执行、文件修改、外部副作用等 Runtime 高风险动作默认仍不 auto-approve;但像 Feishu Remote MCP 这类已受上游权限与工具面约束的文档工具调用确认,可以在 ally 层默认自动处理,避免把重复噪音转嫁给用户
|
|
2072
|
+
- **Bridge 不直接执行用户命令**:飞书消息先进入 Bridge,再进入 Codex Runtime;Bridge 自己不把聊天文本直接拼成 shell 命令执行
|
|
2073
|
+
- **技能默认只信任内置/自管内容**:第一阶段不接远程技能市场,不支持在线拉第三方 skill;`skills/` 目录应视为受审计代码
|
|
2074
|
+
- **敏感配置最小化**:assistant desk 的 `.system/config.env` 只放飞书与本地运行配置,不重复保存模型鉴权秘密
|
|
2075
|
+
- **日志默认保守**:日志与会话台账要可排障,但应默认做敏感信息脱敏、限制保留周期
|
|
2076
|
+
- **必须有一键止血能力**:`ally stop`、allowlist 收紧、禁用 scheduler,应构成最小 incident-response 开关
|
|
2077
|
+
- **文档读写与聊天入口必须分离**:未来若启用远程文档发布面,必须通过独立 publisher/provider 收口,不能把文档写入能力直接绑进 IM adapter
|
|
2078
|
+
- **最小工具曝光**:如果启用文档平台 MCP,必须以最小工具集运行,不为方便而默认暴露全部工具
|
|
2079
|
+
|
|
2080
|
+
### 13.3.1.1 当前文档平台 MCP 的真实权限边界(以飞书为例)
|
|
2081
|
+
|
|
2082
|
+
这里必须避免一个常见误解:飞书 MCP 不是我们产品外面天然再套了一层“独立安全沙箱”。
|
|
2083
|
+
|
|
2084
|
+
更准确的理解是:
|
|
2085
|
+
|
|
2086
|
+
- **个人远程 MCP 服务**:以当前登录用户身份访问飞书数据;对云文档的可见 / 可写边界,本质上仍等于这个用户自己本来就拥有的权限
|
|
2087
|
+
- **开发者远程调用模式**:以 UAT / TAT 调用官方 MCP 服务,可通过应用权限、目标文档 / 知识空间授权,以及 `X-Lark-MCP-Allowed-Tools` 进一步收紧工具面
|
|
2088
|
+
- **MCP 不会凭空创造新的细粒度安全模型**:真正的边界仍来自“谁的身份”“开了哪些工具”“对哪些知识空间节点有授权”“我们产品本地是否再次做 allowlist”
|
|
2089
|
+
|
|
2090
|
+
因此,方案上的正确判断应写死为:
|
|
2091
|
+
|
|
2092
|
+
1. **当前第一版、单机单人工作模式下,个人远程 MCP URL 就是默认推荐路径**
|
|
2093
|
+
- 它最轻、最直接,也最符合“桥接层做薄”的目标
|
|
2094
|
+
- 官方已经维护好远程 MCP 服务;当前用户自己在飞书后台控制工具集与文档权限边界
|
|
2095
|
+
- 对 `work-ally` 来说,最正确的封装就是很薄的 `ally mcp ...`,而不是再造 provider
|
|
2096
|
+
|
|
2097
|
+
2. **如果未来进入公司内网常驻、多用户治理或统一应用托管,再升级到开发者远程模式**
|
|
2098
|
+
- 使用自建应用
|
|
2099
|
+
- 使用 UAT / TAT
|
|
2100
|
+
- 把工具集压到最小
|
|
2101
|
+
- 只对明确授权的知识空间节点 / 文档范围开放
|
|
2102
|
+
|
|
2103
|
+
3. **产品内仍要再加一层自己的收口**
|
|
2104
|
+
- 聊天入口 allowlist 与文档能力边界分开考虑
|
|
2105
|
+
- 默认继续坚持“已有文档链接只读,明确要求后才改写”
|
|
2106
|
+
- 默认自动处理的仅是受信任 MCP(当前默认 Feishu)工具确认与对应 elicitation;Runtime 的高风险审批仍保留显式人工边界
|
|
2107
|
+
|
|
2108
|
+
也就是说,飞书侧权限是**上限边界**,`work-ally` 还要再加自己的**产品边界**,两者叠加后才是我们真正愿意交付的安全面。
|
|
2109
|
+
|
|
2110
|
+
### 13.3.2 为什么像 OpenClaw 这类系统容易被批评“安全性”
|
|
2111
|
+
|
|
2112
|
+
这里要把问题看本质,而不是只看“代码量大不大”。
|
|
2113
|
+
|
|
2114
|
+
这类系统容易被批评安全性,根源通常有四类:
|
|
2115
|
+
|
|
2116
|
+
1. **它拿到的能力太真**:能执行 shell、读写文件、访问网络、代表你发消息;一旦边界失手,后果不是“聊天出错”,而是主机与账户风险
|
|
2117
|
+
2. **它接触的是不可信输入**:别人发来的消息、外部网页内容、第三方技能、群聊上下文,天然都可能带 prompt injection 或社会工程
|
|
2118
|
+
3. **很多部署者会把它当成通用公网服务**:但这类 agent 更接近“个人助手 + 委托执行器”,不是天然安全的多租户公网网关
|
|
2119
|
+
4. **大家容易高估模型本身的安全性**:真正决定风险的,往往不是模型聪不聪明,而是 access control、工具权限、网络暴露、默认配置是不是保守
|
|
2120
|
+
|
|
2121
|
+
所以,我们的方案必须明确采用**access control before intelligence** 的思路:
|
|
2122
|
+
|
|
2123
|
+
- 先决定谁能跟它说话
|
|
2124
|
+
- 再决定它能在哪些边界里行动
|
|
2125
|
+
- 最后才谈模型怎么回答更聪明
|
|
2126
|
+
|
|
2127
|
+
这也是为什么第一阶段我们要刻意收敛为:
|
|
2128
|
+
|
|
2129
|
+
- 单工作空间
|
|
2130
|
+
- 单信任边界
|
|
2131
|
+
- 单渠道(先 Feishu)
|
|
2132
|
+
- 默认 allowlist
|
|
2133
|
+
- 默认本地绑定
|
|
2134
|
+
- 默认不开 Runtime 自动高权限;受信任 MCP 工具确认与对应 elicitation 可按独立规则自动处理
|
|
2135
|
+
- 不做第三方技能市场
|
|
2136
|
+
|
|
2137
|
+
### 13.4 可替换实现与重建预期
|
|
2138
|
+
|
|
2139
|
+
为了让系统真正符合“用户资产与产品机制分离”的要求,部署形态上必须明确:
|
|
2140
|
+
|
|
2141
|
+
- **项目与 assistant desk 是用户资产容器**:项目知识在项目里,assistant 的长期记忆、对话、规则、主动任务定义与长期成果在 desk 里
|
|
2142
|
+
- **`~/.codex/` 是官方配置容器**:provider、模型、登录态、鉴权配置都在这里
|
|
2143
|
+
- **实现缓存是可替换件**:它负责承载产品内部逻辑,但不应成为用户资产唯一存放地
|
|
2144
|
+
- **assistant desk 下的 `.system/runtime/`、`.system/runs/`、`.system/logs/`、`.system/cache/` 是运行台账**:可观察、可清理、可重建,但不应被误当成长期知识库
|
|
2145
|
+
|
|
2146
|
+
因此,最终交付形态必须满足下面的恢复闭环:
|
|
2147
|
+
|
|
2148
|
+
1. 保住项目、assistant desk 与 `~/.codex/`
|
|
2149
|
+
2. 即使实现缓存丢失,也能通过 `ally setup` / `ally update` 重新拉回内部实现
|
|
2150
|
+
3. 即使 desk 本地运行态部分损坏,也能通过 `start` 重新拉起最小可用系统
|
|
2151
|
+
4. 若需要跨机器迁移长期资产,只迁移项目、assistant desk 与官方 Codex 配置,不依赖实现缓存目录
|
|
2152
|
+
5. 如果项目或 desk 资产本身被误删,恢复路径应回到版本管理、同步盘或备份,而不是假设 `work-ally` 能反向重建用户内容
|
|
2153
|
+
|
|
2154
|
+
这样,`work-ally` 才真正像一层可拆可装的外壳,而不是把用户绑死在内部工程结构上。
|
|
2155
|
+
|
|
2156
|
+
---
|
|
2157
|
+
|
|
2158
|
+
## 14. 建议仓库骨架
|
|
2159
|
+
|
|
2160
|
+
这一节开始把方案继续往“可实施”方向拆到仓库结构级别。
|
|
2161
|
+
|
|
2162
|
+
### 14.1 建议的新仓库命名
|
|
2163
|
+
|
|
2164
|
+
从技术实现角度,仓库名不必与用户命令完全一致。
|
|
2165
|
+
|
|
2166
|
+
推荐做法是:
|
|
2167
|
+
|
|
2168
|
+
- **实现仓库**:`work-ally`
|
|
2169
|
+
- **用户日常命令**:`ally`(背后门面文件仍是 `ally.sh`)
|
|
2170
|
+
|
|
2171
|
+
这样做的好处是:
|
|
2172
|
+
|
|
2173
|
+
- 用户侧命令简短、自然
|
|
2174
|
+
- 实现仓库名清楚表达它的技术职责
|
|
2175
|
+
- 交付层与实现层的命名可以各自服务于不同对象
|
|
2176
|
+
- 后续若要通过全局 `ally` 命令、Homebrew 或安装器分发,也只是在交付层换一种包装;**单工作空间 = 单助手 = 绝对路径作用域** 这条边界不变
|
|
2177
|
+
|
|
2178
|
+
### 14.2 实现仓库的推荐目录结构
|
|
2179
|
+
|
|
2180
|
+
```text
|
|
2181
|
+
work-ally/
|
|
2182
|
+
├── README.md
|
|
2183
|
+
├── AGENTS.md
|
|
2184
|
+
├── ally.sh # 用户拿走放到项目根目录的极薄门面
|
|
2185
|
+
├── internal/
|
|
2186
|
+
│ ├── dispatch.sh # 内部命令路由
|
|
2187
|
+
│ ├── lib/
|
|
2188
|
+
│ │ └── common.sh # 公共 shell 工具函数
|
|
2189
|
+
│ └── modules/
|
|
2190
|
+
│ ├── bootstrap/
|
|
2191
|
+
│ │ └── setup.sh # 初始化 assistant desk 与 registry
|
|
2192
|
+
│ ├── config/
|
|
2193
|
+
│ │ └── init-env.sh # 生成 desk 配置模板
|
|
2194
|
+
│ ├── runtime/
|
|
2195
|
+
│ │ ├── start.sh
|
|
2196
|
+
│ │ ├── stop.sh
|
|
2197
|
+
│ │ ├── status.sh
|
|
2198
|
+
│ │ └── update.sh
|
|
2199
|
+
│ ├── assistant/
|
|
2200
|
+
│ │ └── manage.sh # assistant 绑定、desk 管理、checkpoint
|
|
2201
|
+
│ ├── routines/
|
|
2202
|
+
│ │ └── manage.sh # 例行任务的 list/run/enable/disable
|
|
2203
|
+
│ └── ops/
|
|
2204
|
+
│ └── logs.sh
|
|
2205
|
+
├── bridge/
|
|
2206
|
+
│ ├── package.json
|
|
2207
|
+
│ └── src/
|
|
2208
|
+
│ ├── server.ts
|
|
2209
|
+
│ ├── receiver.ts
|
|
2210
|
+
│ ├── router.ts
|
|
2211
|
+
│ ├── runtime-client.ts
|
|
2212
|
+
│ ├── session-store.ts
|
|
2213
|
+
│ ├── scheduler.ts
|
|
2214
|
+
│ ├── translator.ts
|
|
2215
|
+
│ ├── channel-types.ts
|
|
2216
|
+
│ ├── channels/
|
|
2217
|
+
│ │ └── feishu/
|
|
2218
|
+
│ │ ├── adapter.ts
|
|
2219
|
+
│ │ ├── formatter.ts
|
|
2220
|
+
│ │ └── approvals.ts
|
|
2221
|
+
│ └── types.ts
|
|
2222
|
+
├── runtime/
|
|
2223
|
+
│ ├── config/
|
|
2224
|
+
│ └── host/
|
|
2225
|
+
├── skills/
|
|
2226
|
+
│ ├── archive-reader/
|
|
2227
|
+
│ │ └── SKILL.md
|
|
2228
|
+
│ └── memory-digest/
|
|
2229
|
+
│ └── SKILL.md
|
|
2230
|
+
├── templates/
|
|
2231
|
+
│ ├── env.example
|
|
2232
|
+
│ └── workspace/
|
|
2233
|
+
│ └── AGENTS.md
|
|
2234
|
+
└── docs/
|
|
2235
|
+
```
|
|
2236
|
+
|
|
2237
|
+
### 14.3 这个骨架背后的分层原则
|
|
2238
|
+
|
|
2239
|
+
这个目录结构背后的原则非常简单:
|
|
2240
|
+
|
|
2241
|
+
- `ally.sh`:给用户用,只做门面
|
|
2242
|
+
- `internal/`:给 shell 管理逻辑用,做本地安装与运维编排
|
|
2243
|
+
- `bridge/`:给常驻服务用,做 bridge core、channel adapter、scheduler、memory 与 runtime 对接
|
|
2244
|
+
- `runtime/`:给 Codex runtime 包装与配置用
|
|
2245
|
+
- `skills/`:给产品级机制能力用,承载按需加载的 `SKILL.md` 工作流
|
|
2246
|
+
- `templates/`:给初始化工作空间时生成默认内容用(绿地推荐模板,而不是对既有工程的强制结构)
|
|
2247
|
+
- `templates/workspace/AGENTS.md`:仅作为绿地工作空间的最小主身份骨架,不代表产品再生成第二份平级人格文件
|
|
2248
|
+
|
|
2249
|
+
也就是说:
|
|
2250
|
+
|
|
2251
|
+
> **用户命令、shell 编排、常驻 bridge 服务、runtime 包装,必须明确分层。**
|
|
2252
|
+
|
|
2253
|
+
### 14.3.1 两类 `AGENTS.md` 的职责必须分开
|
|
2254
|
+
|
|
2255
|
+
真正开工时,实施仓库根目录也必须从第一天就有自己的 `AGENTS.md`,但它和工作空间根 `AGENTS.md` 不是同一个东西。
|
|
2256
|
+
|
|
2257
|
+
应当明确区分:
|
|
2258
|
+
|
|
2259
|
+
- **实施仓库根 `AGENTS.md`**:写给开发这套产品的工程师 / coding agent,内容是仓库目的、模块边界、文档同步规则、验证命令、代码改动约束
|
|
2260
|
+
- **工作空间根 `AGENTS.md`**:写给实际执行工作的 Codex 伙伴,内容是身份、边界、写回原则、上下文入口
|
|
2261
|
+
|
|
2262
|
+
这两者的关系不是“二选一”,而是:
|
|
2263
|
+
|
|
2264
|
+
- 前者服务于**造产品的人**
|
|
2265
|
+
- 后者服务于**使用产品工作的助手**
|
|
2266
|
+
|
|
2267
|
+
因此,实施仓库里的 `AGENTS.md` 不应夹带最终助手的人设;工作空间里的 `AGENTS.md` 也不应承担实施仓库的开发规范。
|
|
2268
|
+
|
|
2269
|
+
如果团队同时还要兼容其他 agent 工具链,可以再维护镜像文件(例如 `CLAUDE.md`),但从设计上应把实施仓库根 `AGENTS.md` 视为这套工程协作规范的 canonical source。
|
|
2270
|
+
|
|
2271
|
+
### 14.3.2 实施仓库根 `AGENTS.md` 的最小合同
|
|
2272
|
+
|
|
2273
|
+
为了让真正开工的实现仓库从第一天就具备可协作性,建议直接把仓库根 `AGENTS.md` 定成一份**最小但刚性的开发合同**。
|
|
2274
|
+
|
|
2275
|
+
推荐它至少覆盖下面这些内容:
|
|
2276
|
+
|
|
2277
|
+
```md
|
|
2278
|
+
# AGENTS.md
|
|
2279
|
+
|
|
2280
|
+
## Repository purpose
|
|
2281
|
+
|
|
2282
|
+
This repository implements `work-ally`: a thin delivery and orchestration layer that connects one workspace to the official Codex runtime through Feishu.
|
|
2283
|
+
|
|
2284
|
+
Core rule: do not build another brain.
|
|
2285
|
+
|
|
2286
|
+
## Product contract
|
|
2287
|
+
|
|
2288
|
+
- The only user-facing entrypoint is `ally.sh`.
|
|
2289
|
+
- Runtime state lives under `.work-ally/`.
|
|
2290
|
+
- Assistant desks and implementation cache live under `~/.work-ally/`.
|
|
2291
|
+
- The current project directory remains the worksite, not the assistant home.
|
|
2292
|
+
- One running ally process maps to one assistant desk.
|
|
2293
|
+
|
|
2294
|
+
## Architecture boundaries
|
|
2295
|
+
|
|
2296
|
+
- `ally.sh` is facade only.
|
|
2297
|
+
- `internal/` handles local bootstrap and ops orchestration.
|
|
2298
|
+
- `bridge/` handles bridge core and channel adapters.
|
|
2299
|
+
- `runtime/` wraps the Codex runtime host only.
|
|
2300
|
+
- `skills/` carry mechanism workflows, not the main identity.
|
|
2301
|
+
- `templates/workspace/AGENTS.md` is only a greenfield skeleton.
|
|
2302
|
+
|
|
2303
|
+
## Channel boundary
|
|
2304
|
+
|
|
2305
|
+
- The first shipped implementation targets Feishu only.
|
|
2306
|
+
- Channel-specific logic lives under `bridge/src/channels/feishu/`.
|
|
2307
|
+
- Bridge core depends on normalized channel contracts, not Feishu SDK types.
|
|
2308
|
+
|
|
2309
|
+
## Editing guidance
|
|
2310
|
+
|
|
2311
|
+
- Fix root causes; do not add compatibility shims.
|
|
2312
|
+
- Keep facade and scripts small; split modules by responsibility.
|
|
2313
|
+
- Keep user assets outside implementation internals.
|
|
2314
|
+
- Do not generate a second competing main `AGENTS.md`.
|
|
2315
|
+
- Prefer file-based, inspectable state over opaque storage.
|
|
2316
|
+
|
|
2317
|
+
## Validation and TDD
|
|
2318
|
+
|
|
2319
|
+
- New behavior should start from the smallest useful contract or test, not from an unverified end-to-end guess.
|
|
2320
|
+
- Shell changes need syntax checks plus temp-workspace smoke tests.
|
|
2321
|
+
- Bridge changes need unit tests around normalized contracts, session state, scheduling, translation, and immediate ack semantics.
|
|
2322
|
+
- End-to-end human verification is the final gate, not the first gate.
|
|
2323
|
+
- If a change cannot be automatically verified yet, the gap must be written down explicitly in the handoff and kept small.
|
|
2324
|
+
|
|
2325
|
+
## Docs sync
|
|
2326
|
+
|
|
2327
|
+
- If external commands, workspace contract, memory behavior, or directory layout changes, update `README.md` and design docs in the same task.
|
|
2328
|
+
|
|
2329
|
+
## Validation
|
|
2330
|
+
|
|
2331
|
+
- Start with the smallest useful checks.
|
|
2332
|
+
- Validate shell syntax, bridge startup path, and the minimal end-to-end flow when practical.
|
|
2333
|
+
- If a full Feishu / Runtime loop cannot be verified locally, state the gap clearly.
|
|
2334
|
+
```
|
|
2335
|
+
|
|
2336
|
+
如果实施仓库还要兼容其他 agent 工具链,可以再维护 `CLAUDE.md` 等镜像文件;但这些镜像文件应与根 `AGENTS.md` 保持同义同步,而不是各写各的。
|
|
2337
|
+
|
|
2338
|
+
### 14.4 使用者工作空间里的最终落地形态
|
|
2339
|
+
|
|
2340
|
+
当使用者在某个项目里接入当前 shipped product 后,更准确的落地形态应理解为:
|
|
2341
|
+
|
|
2342
|
+
```text
|
|
2343
|
+
your-project/
|
|
2344
|
+
├── AGENTS.md
|
|
2345
|
+
├── docs/ / specs/ / notes/ / src/ ...
|
|
2346
|
+
└── ally.sh
|
|
2347
|
+
|
|
2348
|
+
~/.work-ally/
|
|
2349
|
+
├── assistants/
|
|
2350
|
+
│ ├── registry.yaml
|
|
2351
|
+
│ └── <name>/
|
|
2352
|
+
│ ├── AGENTS.md
|
|
2353
|
+
│ ├── SOUL.md
|
|
2354
|
+
│ ├── NOW.md
|
|
2355
|
+
│ ├── MEMORY.md
|
|
2356
|
+
│ ├── MISTAKES.md
|
|
2357
|
+
│ ├── journal/
|
|
2358
|
+
│ ├── conversations/
|
|
2359
|
+
│ └── .system/
|
|
2360
|
+
│ ├── config.env
|
|
2361
|
+
│ ├── codex-home/
|
|
2362
|
+
│ ├── runtime/
|
|
2363
|
+
│ ├── logs/
|
|
2364
|
+
│ ├── runs/
|
|
2365
|
+
│ ├── cache/
|
|
2366
|
+
│ ├── routines/
|
|
2367
|
+
│ └── archive/
|
|
2368
|
+
└── projects/
|
|
2369
|
+
└── registry.yaml
|
|
2370
|
+
```
|
|
2371
|
+
├── runtime/
|
|
2372
|
+
├── sessions/
|
|
2373
|
+
├── runs/
|
|
2374
|
+
├── logs/
|
|
2375
|
+
└── cache/
|
|
2376
|
+
```
|
|
2377
|
+
|
|
2378
|
+
这保证了三点:
|
|
2379
|
+
|
|
2380
|
+
- 项目资产与 assistant 资产边界清楚,不再混放
|
|
2381
|
+
- assistant desk 根目录是长期资产目录,内部 `.system/` 是运行台账目录
|
|
2382
|
+
- 产品内部实现仍是可替换件,便于观察、清理与重建
|
|
2383
|
+
|
|
2384
|
+
---
|
|
2385
|
+
|
|
2386
|
+
## 15. 实施落地与执行文档边界
|
|
2387
|
+
|
|
2388
|
+
到这里,方案层面的核心边界、产品形态、状态模型、交互流程、部署原则与安全基线已经基本明确。
|
|
2389
|
+
|
|
2390
|
+
从这里开始,文档职责需要主动拆开:
|
|
2391
|
+
|
|
2392
|
+
- `codex-feishu-bridge-proposal.md` 继续作为**灯塔文档**
|
|
2393
|
+
- 负责第一性原理
|
|
2394
|
+
- 负责产品边界
|
|
2395
|
+
- 负责架构分层
|
|
2396
|
+
- 负责状态模型与交互闭环
|
|
2397
|
+
- 负责最终验收标准
|
|
2398
|
+
- `work-ally-implementation-guide.md` 作为**实施指南**(位于 `../implementation/`)
|
|
2399
|
+
- 负责把完整产品拆成多个实施阶段
|
|
2400
|
+
- 负责定义每个阶段的范围、依赖、任务、验证方式与 DoD
|
|
2401
|
+
- 负责给工程师或 coding agent 一个可以直接照着推进的执行主线
|
|
2402
|
+
|
|
2403
|
+
也就是说:
|
|
2404
|
+
|
|
2405
|
+
> **本提案负责回答“为什么这样做、系统应当长成什么样”;实施指南负责回答“先做什么、后做什么、做到什么算这一阶段完成”。**
|
|
2406
|
+
|
|
2407
|
+
这样拆开的原因很简单:
|
|
2408
|
+
|
|
2409
|
+
- 灯塔文档不应变成一份巨大的施工日志
|
|
2410
|
+
- 实施指南必须能被单独拿给别人执行与对齐进度
|
|
2411
|
+
- 后续真正开工后,进度同步应当以“阶段完成情况”而不是以“提案里某一大段文字是否读过”为准
|
|
2412
|
+
|
|
2413
|
+
因此,从这一节开始,**完整产品的逐阶段实施主线以 `work-ally-implementation-guide.md` 为准**。
|
|
2414
|
+
|
|
2415
|
+
但这并不意味着灯塔文档失效。相反,后续所有实现都必须继续受本提案约束,尤其是下面这些不允许偏离的点:
|
|
2416
|
+
|
|
2417
|
+
- 一个工作空间 = 一个助手
|
|
2418
|
+
- 同一个工作空间的 bridge 生命周期也必须服从这个边界:`start` / `stop` / `status` 不能只信 pid 文件,而要按工作空间归属识别真正活着的 bridge
|
|
2419
|
+
- 官方 Codex runtime 是唯一大脑
|
|
2420
|
+
- `ally.sh` 是薄编排层,不重写 agent loop
|
|
2421
|
+
- IM 入口与远程文档产物表面必须分离
|
|
2422
|
+
- 用户长期资产与 `.work-ally/` 运行态必须分离
|
|
2423
|
+
- 文件优先,不把数据库当成第一默认解
|
|
2424
|
+
- 当前 IM 通道只是实现层,不污染抽象层命名
|
|
2425
|
+
- 主动能力必须建立在黑匣子原材料与记忆压缩闭环之上
|
|
2426
|
+
|
|
2427
|
+
如果后续实施中出现下面任一情况,就不能只改代码或只改实施指南:
|
|
2428
|
+
|
|
2429
|
+
- 需要改变产品边界
|
|
2430
|
+
- 需要改变状态模型
|
|
2431
|
+
- 需要改变用户交付形态
|
|
2432
|
+
- 需要改变安全基线
|
|
2433
|
+
- 需要改变“谁负责大脑、谁负责编排”的核心分工
|
|
2434
|
+
|
|
2435
|
+
此时必须先回到本提案更新灯塔,再继续实施。
|
|
2436
|
+
|
|
2437
|
+
---
|
|
2438
|
+
|
|
2439
|
+
## 16. 实施阶段总览
|
|
2440
|
+
|
|
2441
|
+
完整产品的实施阶段已经独立整理到:
|
|
2442
|
+
|
|
2443
|
+
```text
|
|
2444
|
+
docs/implementation/work-ally-implementation-guide.md
|
|
2445
|
+
```
|
|
2446
|
+
|
|
2447
|
+
为了保证灯塔文档与实施指南之间的关系清晰,这里只保留**阶段总览**,而不再在本提案中重复整份施工细节。
|
|
2448
|
+
|
|
2449
|
+
### 16.1 阶段地图
|
|
2450
|
+
|
|
2451
|
+
| 阶段 | 主题 | 关键结果 |
|
|
2452
|
+
| --- | --- | --- |
|
|
2453
|
+
| Stage 0 | 开工合同与验收基线 | 灯塔文档、实施指南、协作准则与验收口径统一 |
|
|
2454
|
+
| Stage 1 | 实现仓库骨架与开发地基 | 实现仓库、测试骨架、开发地基成立 |
|
|
2455
|
+
| Stage 2 | 门面、Bootstrap 与运行态外壳 | `ally.sh` 与 assistant desk 初始化闭环成立 |
|
|
2456
|
+
| Stage 3 | Bridge Core 与假闭环 | 统一事件流、session、archive 在本地跑通 |
|
|
2457
|
+
| Stage 4 | 当前 IM 通道实现接入 | 当前 IM 通道真实收发、即时回执成立 |
|
|
2458
|
+
| Stage 5 | 官方 Codex Runtime 集成 | 真实 Runtime 闭环成立 |
|
|
2459
|
+
| Stage 6 | 连续对话、审批与恢复 | thread 连续性、审批、停止、恢复成立 |
|
|
2460
|
+
| Stage 7 | 主动能力与记忆闭环 | routines、scheduler、nightly digest 成立 |
|
|
2461
|
+
| Stage 8 | Codex 直连远程文档能力 | 远程文档读写由 Codex 直接通过 MCP 提供,`work-ally` 仅保留薄封装 |
|
|
2462
|
+
| Stage 9 | 运维、安全与交付封装 | 更新、常驻、排障、恢复与硬化成立 |
|
|
2463
|
+
| Stage 10 | 发布验收与完工出门 | 全链路验收通过,可以对外宣布产品完成 |
|
|
2464
|
+
|
|
2465
|
+
### 16.2 执行方式
|
|
2466
|
+
|
|
2467
|
+
后续真正开工时,应严格按下面的顺序推进:
|
|
2468
|
+
|
|
2469
|
+
1. 先完成前置阶段的 DoD,再进入下一阶段主线
|
|
2470
|
+
2. 每一阶段都必须同步交付:
|
|
2471
|
+
- 代码
|
|
2472
|
+
- 测试
|
|
2473
|
+
- 文档
|
|
2474
|
+
- 可人工验证的验收结果
|
|
2475
|
+
3. 每一阶段都必须遵守本提案中的边界,而不是为了快先把抽象打穿
|
|
2476
|
+
4. 如果实施指南与灯塔文档冲突,以灯塔文档为准;若灯塔需要修改,先修灯塔
|
|
2477
|
+
|
|
2478
|
+
### 16.3 何时才能说“第一阶段产品开发完成”
|
|
2479
|
+
|
|
2480
|
+
只有当下面两件事同时成立时,才可以说第一阶段产品开发完成:
|
|
2481
|
+
|
|
2482
|
+
1. `work-ally-implementation-guide.md` 中全部阶段的 DoD 都已经达成
|
|
2483
|
+
2. 本提案第 17 节“验收标准”中的要求已经成立
|
|
2484
|
+
|
|
2485
|
+
当前这两个条件都已成立,因此本提案对应的第一阶段已经收口。
|
|
2486
|
+
|
|
2487
|
+
换句话说:
|
|
2488
|
+
|
|
2489
|
+
> **实施指南负责把事情一步一步做完;本提案负责定义“做完以后它到底算不算那个我们一开始要的产品”。**
|
|
2490
|
+
|
|
2491
|
+
---
|
|
2492
|
+
|
|
2493
|
+
## 17. 验收标准
|
|
2494
|
+
|
|
2495
|
+
当方案进入“可照着实施”的状态时,至少应满足以下验收标准:
|
|
2496
|
+
|
|
2497
|
+
1. **单工作空间一致性**
|
|
2498
|
+
- 同一个工作空间目录就是唯一上下文来源
|
|
2499
|
+
|
|
2500
|
+
2. **单大脑一致性**
|
|
2501
|
+
- 飞书端不使用独立 agent loop
|
|
2502
|
+
- 真正思考与执行都由官方 Codex runtime 完成
|
|
2503
|
+
|
|
2504
|
+
3. **双入口成立**
|
|
2505
|
+
- 电脑端继续使用官方 Codex
|
|
2506
|
+
- 飞书端可以作为远程对话入口
|
|
2507
|
+
|
|
2508
|
+
4. **持续对话成立**
|
|
2509
|
+
- 同一个飞书会话能够稳定绑定并延续一个默认 Codex thread
|
|
2510
|
+
|
|
2511
|
+
5. **工具边界尽量一致**
|
|
2512
|
+
- 在推荐部署形态下,桌面端与飞书端尽量共享同一台 Runtime Host 与工具环境
|
|
2513
|
+
|
|
2514
|
+
6. **长任务可观察**
|
|
2515
|
+
- 飞书端能收到阶段性进度反馈
|
|
2516
|
+
|
|
2517
|
+
7. **高风险操作可审批**
|
|
2518
|
+
- 飞书端能完成批准 / 拒绝闭环
|
|
2519
|
+
|
|
2520
|
+
8. **系统可恢复**
|
|
2521
|
+
- 断线、重启、报错后,系统能继续工作或给出清晰恢复路径
|
|
2522
|
+
|
|
2523
|
+
9. **桥接层保持薄**
|
|
2524
|
+
- Bridge 不重新承担 agent loop、memory engine 或推理编排职责
|
|
2525
|
+
|
|
2526
|
+
10. **交付形态简单**
|
|
2527
|
+
- 用户只需要理解 `ally`、项目工作现场,以及 assistant desk 这一独立办公桌
|
|
2528
|
+
|
|
2529
|
+
11. **主动能力成立**
|
|
2530
|
+
- 例行任务定义属于工作空间
|
|
2531
|
+
- `ally` 能主动触发、记录并回传结果
|
|
2532
|
+
|
|
2533
|
+
12. **主动 / 被动形成闭环**
|
|
2534
|
+
- 用户可以在飞书接收主动结果后继续追问
|
|
2535
|
+
- 也可以回到电脑前围绕同一工作空间继续工作
|
|
2536
|
+
|
|
2537
|
+
13. **助手边界清晰**
|
|
2538
|
+
- 单个 `work-ally` 实例只服务单个工作空间
|
|
2539
|
+
- 不在单实例内部引入复杂 group / role / multi-assistant 抽象
|
|
2540
|
+
|
|
2541
|
+
14. **多助手路径自然**
|
|
2542
|
+
- 如果需要多个助手,直接通过多个工作空间 / 多个实例来承载
|
|
2543
|
+
- 不通过一个总助手去兼职很多份彼此无关的工作
|
|
2544
|
+
|
|
2545
|
+
15. **用户动作最小化**
|
|
2546
|
+
- 用户只需维护项目资产、assistant desk 资产、最少的机器本地运行配置,以及 `ally` 这一层命令入口
|
|
2547
|
+
- 不需要理解内部实现仓库结构或 runtime 协议细节
|
|
2548
|
+
|
|
2549
|
+
16. **实现可整体替换**
|
|
2550
|
+
- 删除内部实现缓存后,可以通过 `setup` / `update` 恢复
|
|
2551
|
+
- 若连命令入口也丢失,重新恢复 `ally`(背后仍可来自新的 `ally.sh`)后仍能接回同一个项目与 assistant desk 绑定
|
|
2552
|
+
|
|
2553
|
+
17. **长期资产外置**
|
|
2554
|
+
- 项目知识、规则与代码留在项目本身;assistant 记忆、对话与长期沉淀留在 assistant desk
|
|
2555
|
+
- 任何纯运行态目录都不应成为这些长期资产的唯一存放地
|
|
2556
|
+
|
|
2557
|
+
18. **黑匣子自动成立**
|
|
2558
|
+
- 经过 `work-ally` 管道的对话与主动任务过程,会被系统自动落为原材料
|
|
2559
|
+
- 不依赖模型“顺手记录”,也不依赖人手工补录
|
|
2560
|
+
|
|
2561
|
+
19. **记忆闭环成立**
|
|
2562
|
+
- 系统能按计划基于黑匣子原材料产出每日记忆与长期记忆
|
|
2563
|
+
- `sessions/` 与 archive / memory 的语义边界清晰,不相互混淆
|
|
2564
|
+
|
|
2565
|
+
20. **已有工程低侵入接入**
|
|
2566
|
+
- 既有工程可以通过可选的路径映射文件复用现有 `docs/`、`specs/`、`notes/` 等目录
|
|
2567
|
+
- 方案不强制所有工程都重构成同一套物理目录树
|
|
2568
|
+
|
|
2569
|
+
21. **身份层清晰**
|
|
2570
|
+
- 工作空间根 `AGENTS.md` 是唯一主身份说明
|
|
2571
|
+
- Skills 承载机制能力,Memory / Knowledge 承载资产,渠道薄补充不改写主身份,也不存在第二份平级产品 `AGENTS.md`
|
|
2572
|
+
|
|
2573
|
+
22. **实施仓库协作规则清晰**
|
|
2574
|
+
- 实施仓库根目录从第一天就具备自己的 `AGENTS.md`,用于约束开发协作
|
|
2575
|
+
- 它与工作空间根 `AGENTS.md` 职责分离,不混淆开发规范与助手身份
|
|
2576
|
+
|
|
2577
|
+
23. **渠道抽象边界清晰**
|
|
2578
|
+
- 第一阶段虽然只实现 Feishu,但渠道特有的接入、发送、格式化与审批交互被隔离在 channel adapter 中
|
|
2579
|
+
- core bridge 不被飞书 SDK / 消息格式硬绑定,未来新增渠道时不需要重写 `session/runtime/memory` 主链路
|
|
2580
|
+
|
|
2581
|
+
24. **实施过程可阶段验收**
|
|
2582
|
+
- 每个阶段都有自动化优先的最小验收面:shell smoke、Bridge unit、fake integration、真实人工闭环
|
|
2583
|
+
- 不允许把“第一次验证”推迟到所有功能写完之后
|
|
2584
|
+
|
|
2585
|
+
25. **安全基线默认成立**
|
|
2586
|
+
- 默认 allowlist、默认本地绑定、默认不开 Runtime 自动高权限、默认不接第三方技能市场;受信任 MCP 工具确认与对应 elicitation 单独收口
|
|
2587
|
+
- 配置缺失或安全前提不满足时,系统应失败关闭,而不是开放运行
|
|
2588
|
+
|
|
2589
|
+
26. **失败默认安全**
|
|
2590
|
+
- allowlist 为空、绑定地址过宽、关键凭据缺失、审批状态不明等场景下,系统应拒绝启动、拒绝执行或要求人工确认
|
|
2591
|
+
- 不允许为了“更方便可用”而把高风险动作默默放行
|
|
2592
|
+
|
|
2593
|
+
27. **部署画像可统一迁移**
|
|
2594
|
+
- 第一阶段默认是“个人用户 + 飞书长连接 + 无公网地址”的友好形态
|
|
2595
|
+
- 未来迁移到公司内网常驻节点时,不需要改写核心架构;变化的只是部署位置、托管方式与可联络身份范围
|
|
2596
|
+
|
|
2597
|
+
---
|
|
2598
|
+
|
|
2599
|
+
## 18. 风险、取舍与为什么这是当前最佳方案
|
|
2600
|
+
|
|
2601
|
+
### 18.1 已知风险
|
|
2602
|
+
|
|
2603
|
+
当前仍需重点验证的技术点包括:
|
|
2604
|
+
|
|
2605
|
+
> **这些点已经不再构成方向不确定性,而是开工后的工程验证项。**
|
|
2606
|
+
|
|
2607
|
+
- App Server 接入方式的具体实现形态
|
|
2608
|
+
- Bridge 与 Runtime 之间的事件流消费模型
|
|
2609
|
+
- 审批请求在飞书上的最小可用交互形式
|
|
2610
|
+
- 长输出在飞书中的分段与截断策略
|
|
2611
|
+
- 桌面端与飞书端如何表达“同一个工作空间、不同入口”的一致体验
|
|
2612
|
+
- 第一阶段如何界定“可自动采集的黑匣子范围”与“桌面端直连官方 Codex 的未采集范围”
|
|
2613
|
+
|
|
2614
|
+
### 18.2 明确不选的路径
|
|
2615
|
+
|
|
2616
|
+
#### 为什么不是 `nanobot` 做大脑
|
|
2617
|
+
|
|
2618
|
+
因为那会让我们重新承担:
|
|
2619
|
+
|
|
2620
|
+
- agent loop 质量
|
|
2621
|
+
- 工具编排质量
|
|
2622
|
+
- 长期调优成本
|
|
2623
|
+
- 推理与行为一致性成本
|
|
2624
|
+
|
|
2625
|
+
而这并不是当前最有胜算的方向。
|
|
2626
|
+
|
|
2627
|
+
#### 为什么不是 `tmux` 转发 CLI
|
|
2628
|
+
|
|
2629
|
+
因为那更像一个过渡技巧,而不是终局方案。它会让我们自己承担:
|
|
2630
|
+
|
|
2631
|
+
- TUI 文本边界处理
|
|
2632
|
+
- 长任务状态恢复
|
|
2633
|
+
- 审批流程表达
|
|
2634
|
+
- 会话与线程语义建模
|
|
2635
|
+
|
|
2636
|
+
最终很容易变成“手搓一层不稳定协议”。
|
|
2637
|
+
|
|
2638
|
+
#### 为什么不是一开始就引入数据库
|
|
2639
|
+
|
|
2640
|
+
因为当前桥接状态仍然偏轻量:
|
|
2641
|
+
|
|
2642
|
+
- 文件目录更透明
|
|
2643
|
+
- 对普通开发者更友好
|
|
2644
|
+
- 更容易人工检查与调试
|
|
2645
|
+
- 更容易与摘要、记忆压缩、会话整理衔接
|
|
2646
|
+
|
|
2647
|
+
数据库不是不能用,而是:
|
|
2648
|
+
|
|
2649
|
+
> **它不应该成为第一阶段成立的前提。**
|
|
2650
|
+
|
|
2651
|
+
#### 为什么不是自己做通用 agent 框架
|
|
2652
|
+
|
|
2653
|
+
因为当前目标不是做平台,而是:
|
|
2654
|
+
|
|
2655
|
+
> **围绕一个工作空间,让同一个 AI 伙伴在电脑与飞书两端都能工作。**
|
|
2656
|
+
|
|
2657
|
+
#### 为什么不是一开始就做多渠道 / 多组 / 多角色系统
|
|
2658
|
+
|
|
2659
|
+
因为这些抽象会过早把系统推向“助手平台”,而不是“工作空间伙伴”。
|
|
2660
|
+
|
|
2661
|
+
对当前目标来说,最自然的边界其实已经存在:
|
|
2662
|
+
|
|
2663
|
+
- 一个工作空间,就是一个助手
|
|
2664
|
+
- 多个工作空间,就是多个助手
|
|
2665
|
+
|
|
2666
|
+
这条边界比“在一个实例里切很多组、很多角色、很多助手身份”更稳定,也更符合真实工作方式。
|
|
2667
|
+
|
|
2668
|
+
#### 为什么像 OpenClaw 这样的项目会反复卷入安全争议
|
|
2669
|
+
|
|
2670
|
+
把这件事说透,其实反而更能帮助我们定边界。
|
|
2671
|
+
|
|
2672
|
+
这类项目被批评,通常不是因为“用了 agent 就原罪”,而是因为它们同时具备几件高风险特征:
|
|
2673
|
+
|
|
2674
|
+
- 对外暴露消息入口
|
|
2675
|
+
- 背后握有真实工具权限
|
|
2676
|
+
- 会持续接触不可信内容
|
|
2677
|
+
- 很多人会把它误部署成更开放的公网服务或多人共用服务
|
|
2678
|
+
|
|
2679
|
+
官方 OpenClaw 的安全文档本身就把它定义为个人助手型的单一信任边界系统,而不是给互不信任的人共享的一般性多租户边界;它反复强调 access control 应先于 intelligence,技能目录应视为可信代码,部署时需要持续做安全审视。
|
|
2680
|
+
|
|
2681
|
+
换句话说,OpenClaw 被批评的“安全性”,很大程度上其实是在提醒一件事:
|
|
2682
|
+
|
|
2683
|
+
> **一个能执行工具的 agent,如果被当成普通聊天机器人或普通公网 SaaS 去部署,就很容易越过它真正适合的信任边界。**
|
|
2684
|
+
|
|
2685
|
+
我们的方案之所以刻意保守,就是为了从第一天避免踩进同一类坑里。
|
|
2686
|
+
|
|
2687
|
+
### 18.3 为什么这仍然是当前最佳方案
|
|
2688
|
+
|
|
2689
|
+
在当前认知下,这是最佳方向,因为:
|
|
2690
|
+
|
|
2691
|
+
- 它最符合第一性原理
|
|
2692
|
+
- 它把复杂度放在最有胜算的一侧(官方 Codex)
|
|
2693
|
+
- 它最贴合真实使用场景
|
|
2694
|
+
- 它避免了“为了做远程入口,结果又造了一个新 agent”
|
|
2695
|
+
- 它的交付形态对用户足够简单
|
|
2696
|
+
- 它的状态存储对开发者足够透明
|
|
2697
|
+
|
|
2698
|
+
---
|
|
2699
|
+
|
|
2700
|
+
## 19. 最终结论
|
|
2701
|
+
|
|
2702
|
+
这份方案最终要表达的不是某个实现技巧,而是一个稳定的产品与实现判断:
|
|
2703
|
+
|
|
2704
|
+
### 19.1 方向判断
|
|
2705
|
+
|
|
2706
|
+
最终方向不是:
|
|
2707
|
+
|
|
2708
|
+
- 继续把 `nanobot` 做成更强的 agent
|
|
2709
|
+
- 用桥接层去承担本不该承担的智能职责
|
|
2710
|
+
|
|
2711
|
+
而是:
|
|
2712
|
+
|
|
2713
|
+
- **把这件事做成一个围绕工作空间的 Codex Feishu Bridge 交付系统**
|
|
2714
|
+
|
|
2715
|
+
### 19.2 系统本质
|
|
2716
|
+
|
|
2717
|
+
这个系统的本质是:
|
|
2718
|
+
|
|
2719
|
+
> **以工作空间为中心,以 Codex 为大脑,以飞书为入口,以 `work-ally` 为交付门面的一层薄系统。**
|
|
2720
|
+
|
|
2721
|
+
### 19.3 后续所有实现都应服从的总原则
|
|
2722
|
+
|
|
2723
|
+
- 项目负责项目上下文;assistant desk 负责 assistant 的黑匣子原材料与长期资产
|
|
2724
|
+
- Codex 负责智能与官方鉴权体系
|
|
2725
|
+
- 飞书负责触达
|
|
2726
|
+
- `ally` / `ally.sh` 这一层负责统一入口、自动归档与主动编排
|
|
2727
|
+
- 主动任务定义文件(绿地默认可放在 `routines/`)负责承载版本化的主动任务定义
|
|
2728
|
+
- 每个工作空间天然对应一个独立助手边界
|
|
2729
|
+
- `.work-ally/implementation/` 必须始终是可替换件
|
|
2730
|
+
- 隐藏目录负责本地运行态,不负责长期知识归档
|
|
2731
|
+
- 实现仓库负责桥接
|
|
2732
|
+
|
|
2733
|
+
只要后续实施不偏离这几条,这个方案就不会走歪。
|
|
2734
|
+
|
|
2735
|
+
---
|
|
2736
|
+
|
|
2737
|
+
## 20. 参考资料
|
|
2738
|
+
|
|
2739
|
+
- OpenAI, *Unlocking the Codex harness: how we built the App Server*
|
|
2740
|
+
- OpenRouter, *Integration with Codex CLI*
|
|
2741
|
+
- HKUDS/nanobot GitHub repository
|
|
2742
|
+
- OpenClaw architecture and deployment materials
|