# 1001 MVP 设计

> 内部工作文档。讨论 1001 的概念精确定义、MVP 目标、MVP 范围与设计。
>
> 对外的心路历程 + 哲学叙事见 `1001-story.md`。本文不重复哲学，直奔操作。

---

## 1. 概念精确定义

### 1.1 Loop

**定义**：first-class 工作单元 = **context + ai + workdir**，绑定一个长程任务和一个 driver。

**逻辑构成**：
- **context** —— 从 Context tab + Chat tab 拉进来的原料。`LoopContext` 字段：
  - `knowledge` —— 团队沉淀（`all` 或 scoped paths）
  - `notes` —— 团队 prose 层（`all` 或 scoped paths）
  - `personal` —— 私人路径（仅当前 driver 可见，包括 secrets）
  - `chats[]` —— 一组 `{channelId, upTo}` 快照，把 channel/DM 当 context source M:N ingest
- **ai** —— AI runtime（agent loop + tool dispatch）。Phase 2 选型未定（opencode-fork vs 自建 ts，详见 §2）
- **workdir** —— 实际干活的目录（通常是某个 repo 的 git worktree）

> chat 是 user ⇄ ai 在 workdir 上交互的副产物，由 AI runtime 自身的 session 持久化，1001 不重复存。

**1001 区别于现有 AI 工具的语义**：
- **driver** —— 谁正在 drive 这个 loop（强单人语义，可 transfer，可 release 为 rfd）
- **context 注入** —— 创建时绑定 knowledge / notes / personal / chats，注入系统提示
- **focus 关联** —— loop 可打 0~N 个 focus tag（focus 是派生 view，见 §1.2）
- **attach 协议** —— 队友远程 attach 我的 loop（ws + 多 subscriber mirror）
- **chat-as-context** —— channel / DM 可被 loop ingest 成"截至第 N 条消息"的快照

**生命周期 / status**（match prototype 实现）：

```
                  ┌─ idle      (短期没动，仍可被唤醒)
active ──────────┤
                  ├─ archived  (long-term 不动)
                  └─ forked    (从这条开新 loop)

rfd 是正交状态（active/idle 都可以是 rfd）：
  - rfd-from-birth  (incident loop，没人接)
  - rfd-after-release (driver 主动 release，等人 claim)
```

**关键约束**：
- 一个 loop 同一时刻**最多**一个 driver（人）—— loop 也可以无 driver 出生（rfd from creation），代表"事来了但还没人接"，是 incident queue 的形态
- driver 可被 transfer（产生一条 driver-change 系统消息），release 后回到 rfd 状态
- chat 不显示个人名字（统一 `user` / `ai`），driver 切换通过系统标记呈现
- close 后仍可读、可 fork，但默认不再 active

**操作**：`spawn` / `fork` / `transfer-driver` / `close` / `archive`

### 1.2 Focus

**定义**：团队当下"什么重要"的 view。是注意力的物化，不是 todo list。

**Focus 本质上是 view，不是真 entity**。状态预算几乎为零：

| 数据 | 来源 |
|---|---|
| Focus 列表 | `loop.focuses[]` 全 workspace 去重派生 |
| 每个 focus 关联的 loops | filter loops by tag 派生 |
| last-touched / 8d 倒计时 | max(loop.timeline.last) 派生 |
| 🚨 未认领（incident queue） | filter rfd && 无 focus 派生 |
| 📌 pinned（永不归档名单） | `notes/focus.md` 一行一个 |
| 空 meta focus（如"招聘 funnel"，当前 0 loop） | `notes/focus.md` 一行一个 |

**只有 `notes/focus.md` 里几行 pinned/meta override 是"真存"**，其余全是 view。

**两档**（没有"archived"视图 —— 派生模型下"归档"就是"不出现在当下"，不需要单独 view）：
| 档 | 行为 | 来源 |
|---|---|---|
| **pinned** | 永不从当下消失 | `notes/focus.md` 列出 |
| **focus** | 8 天无活动自动从当下消失 | 任意 loop 带上对应 focus tag 后自动出现 |

**活动定义**：focus 关联的任意 loop 有 timeline 事件（chat / driver-change / rfd / claim / fork）→ focus 时间刷新。

**复活老 focus**：
- 在 `notes/focus.md` 里写一行 pin 它（变成空 meta focus，等待 loop 绑定）
- 或者给任意 loop 打上对应 tag —— 自动出现

**附加段（非 focus 主体）**：
- ⑂ **active 但未归类**：有 driver 且不在任何 focus 的 loop —— focus-hygiene 提示，"该不该给它打个 tag？"
- 📝 **稀碎 inbox**：脚注式 inline 预览 `notes/inbox.md` 前 N 条 + deeplink 到 Context 编辑

**不在 Focus 里的东西**：
- **未认领（rfd loops）/ incident queue** —— rfd 是"自动收"，Focus 是"主动选"，方向相反，不该混。在 Loop tab 通过 RFD 过滤档可见
- **个人 todo** —— 走 `personal/`
- **archived 视图** —— 派生模型下没有"曾经存在过"这个状态。要看历史走 Loop tab 的 archived loops + 按 `loop.focuses[]` 反查

**约束**：
- focus 不是任务，没有 done 状态
- focus 不绑定 driver
- m:n loop 关联（一个 loop 可挂多个 focus，反之亦然）
- 团队 focus；个人 todo 走 `personal/`，不在这里

### 1.3 Context

> team's distilled materials —— 团队精炼过、可被反复使用的原料。

三种形态：

#### Knowledge（passive · markdown · 沉淀层）

- 主题目录（按团队领域划分），当前约定：
  - `loopat/` —— loopat 自己的设计文档（concepts / architecture / phase-roadmap / naming / attach-spec 等）
  - `ai-org/` —— 哲学层（vision / 1001-philosophy / loop-is-everything 等）
  - `conventions/` —— 团队约定（loop-naming / commit-messages / code-style / knowledge-layout）
  - `skills/` —— 可复用的 SKILL.md（loop-handoff / distill-to-knowledge / spawn-from-chat 等）
- 写法：markdown + frontmatter（`title / tags / updated / driver`）+ wikilink `[[X]]` + 自动 backlinks
- 多人共同维护，有 git revision
- **没有 inbox 子目录** —— 高熵稀碎活在 Notes 层（见下）

#### Notes（team · public · prose）

`notes/` 是团队公共的 prose 层 —— 比 knowledge 熵更高、未沉淀；比 personal 公开。两个**保留约定文件名**：

- **`notes/inbox.md`** —— 团队稀碎 prose 的家。一行一个 bullet，没有 status / assignee / due date：
  ```md
  - 客户 X 说 dashboard 卡顿，回头看下
  - 那个 prompt 想试一下 - https://...
  - 阿尔萨斯说 quota 那个事下周聊
  ```
  腐烂时直接删，不维护"open 数量"。**晋升**：某行决定要做 → 右键 `spawn loop`，bullet 删掉，事进 Loop。
  *设计哲学*：稀碎保持 prose 形态，不要装 record。装 record 就成 issue tracker，必腐烂。

- **`notes/focus.md`** —— Focus tab 的唯一"真存"。pin 名单 + 空 meta focus 名单。约 5-10 行：
  ```md
  ## pinned
  - 上线 gateway
  - 1001 系统设计

  ## listed
  - 招聘 funnel — 7 待评估
  ```

#### Agents（active · executable）

- 跑在任何地方（云、本机、容器、cron、k8s），通过 1001 API 接入：
  - `GET /context` 拉知识
  - `GET /focus` 看团队当下注意力
  - `SUB /chat/<channel>` / `POST /chat/<channel>` 收发消息
  - `POST /loops` 主动创 loop（也可以 rfd-from-birth，等人 claim）
- persona = system prompt + tool 集 + 触发模式
- Trigger 三种：`mention` / `schedule` / `event`
- 来源：从反复出现的 Loop pattern 里 distill 出来 —— **agent 是把"读 doc 然后做事"这套流程编码进可执行外壳**

**双栖呈现**（asset vs actor）：
- **Context tab 的 Agents sub-tab** —— 工作台。配 persona / tool / trigger，看运行状态、recentInvocations
- **Chat tab 的 Direct Messages 段** —— 调用入口。跟人混在一起列（小🤖 标识），点击像 DM 一样对话；agent 也可以被 @ 进 channel 参与讨论

哲学：agent 是双面体 —— "**资产**"维度归 Context（你 build / version 它），"**角色**"维度归 Chat（你跟它说话）。

#### Repos（passive · code）

- 团队 register 的 git 仓
- 每个 repo 显示 recent loops + spawn loop 入口
- spawn loop = 后台 `git worktree add` → 创建新 loop 的 work dir

**Loop ↔ Agent 对照**：

| | Loop | Agent |
|---|---|---|
| 谁的 | 一个 driver（人）的事 | 团队资产（无人 driver） |
| 时长 | 数小时数天，会 close | 长期运行 |
| 触发 | 人决定开 | 持续监听 / 定时 |
| 终点 | artifact → close | 没终点（除非下线） |
| 改 persona | 不（一次性的事） | 有（迭代 prompt、加 tool） |
| 数量 | 多（几十） | 少（几个，每个明确职责） |

### 1.4 Chat

- **channels + DMs** 两档（**没有 group chat**）—— workspace 边界已经划好，临时多人讨论 → spawn loop（loop 本身就是带主题 + 多人的工作单元）
- `#all` 是约定频道：包含所有 workspace member（人 + agent），同时充当**成员目录**。找新人 / agent 在 #all members 面板搜，不需要"加好友"
- DMs 段瘦身：只列**有 active 消息**的对话；找新对象去 #all
- agent 跟人在 DM 列表里混排，区分只剩小 🤖 标识 + 状态色点（running / idle / error）
- bot 是一次性回应（信息查询、统计、提醒）；agent 是长期值班的 bot
- 在某条消息 `spawn loop`，把讨论升级成深加工
- loop 的进展可回流进 chat，让团队感知，不需要别人 attach

**chat 也是 context source**：
- channel 或 DM 可被 loop ingest（`loop.context.chats[]`：`{channelId, upTo}` 快照），M:N 关系
- chat tab 的 channel header 显示"**📤 N loops 把这条 chat 作为 context**"反向引用，可点跳进 loop
- loop tab 的 header 显示 chat chip（如 `chat: #dev:86`），可点跳进对应 channel

**Chat 与 Loop 是搭档，不是替代**：chat 是 sync 协调层 + 临时 context；loop 是异步深加工层 + 沉淀产物。spawn 是单向升级（chat → loop），回流是可见性 broadcast（loop → chat），ingest 是 chat 作为 loop 原料的 M:N 引用。三种关系，但职责不重叠。

### 1.5 概念关系图

```
                              ┌──[broadcast]──┐
                              │               ▼
chat ──[spawn]──→  loop ──[ingest M:N]──── chat
                    │  ▲
                    │  │ [tag]
                    │  └──── focus (派生 view)
                    │
                    ├──[沉淀 distill]──→ knowledge
                    │
                    ├──→ repo (git worktree)
                    │
                    └──[pattern distill]──→ agent (长期值班)
```

三个 chat ↔ loop 关系：
- **spawn**：chat 消息 → 新 loop（chat → loop，单向升级）
- **ingest**：channel/DM 作为 loop 的 context source，loop.context.chats[] 引用（chat → loop，M:N）
- **broadcast**：loop 进展回流进 chat（loop → chat）

### 1.6 顶层组织

10 人左右共享一个 **workspace**（如内部 codename `1001`，对外 brand `loopat`）。
Workspace 是隔离边界，跨 workspace 的 loop / context / focus 不互通。

**workspace 治理**：
- 左上角 brand（🧶 loopat · 1001）点开 dropdown：copy invite link / view members in #all / settings / switch workspace
- **加成员** = 复制 invite link 发给受邀人，受邀人通过 link 登录后 self-join 进 #all（不需要 admin approve）
- workspace 成员 directory = `#all` channel 的 members 面板（不另起 admin UI）

---

## 2. 阶段性目标

> 前两个 phase 定义 3-6 个月内不会再变的目标方向。后两个是落地里程碑：0.1 单人 → 0.2 协作。

### Phase 1：高保真原型 ✅

**目标**：把 1001 想要的功能和样式都完整呈现在前端原型里 —— 不涉及实现。

**产出**：
- 说明文档（本文 + `1001-story.md`）
- 高保真前端原型 `phase1-prototype/`（Vite + SolidJS + Tailwind v4，纯 mock，11 loops / 3 agents / 2 humans 全场景覆盖）

**退出标准**：reviewer 看完前端原型能讲清楚 1001 是什么。

**当前状态**：完成。

### Phase 2：架构选型 ← 当前

**目标**：选定一套 1-2 个月内能实现的架构。**必须有妥协，不追完美又复杂。**

**结论草案（详见 §3.3）**：选 **filesystem-first** 路线。技术栈 = Claude Agent SDK + Hono + Vite + assistant-ui + sandbox-runtime。等周末跟 panlilu close。

**之前并行的两条 spike**：
- **opencode-fork**（simpx）—— 调研后倾向不 fork（upstream 撕裂风险 + 改 attach SSE→ws 工作量大）；但作为 reference impl 大量借鉴（其 stack = Vercel AI SDK + MCP + Hono + filesystem session，跟我们结论高度一致）
- **loopat-ts**（panlilu）—— DB-first 路线（Next.js + tRPC + Prisma + Postgres + NextAuth），跟最终选型架构哲学冲突。这一周工作大部分 throw away，schema 思考归档进 knowledge

**已否决候选**：
- 自写 from scratch（Vercel AI SDK + 自写 loop）—— loop 智能度追不上 Claude
- Mastra — 强制 Postgres 依赖，违反 filesystem-first
- pi (earendil-works) — 1 人小项目，生产 mileage 不足
- pi.dev — IDE 内嵌形态，方向不匹配
- LangGraph — 不兼容 edge runtime
- OpenAI Agents SDK / Codex CLI — provider 锁，loop 智能度不及

**产出**：选型推导（§3.3）+ 周末跟 panlilu close 后定稿。

> Phase 1 + Phase 2 完成后，3-6 个月的目标固定下来，不再 churn。

### Phase 3：0.1 单人版（升级版 ccx）

**目标**：100% 代替我本地的 ccx，连续用一周不回退。

**范围（按概念）**：

| 概念 | 0.1 范围 |
|---|---|
| **Loop** | 完整（无 attach）。spawn / chat / close 单人即可；前端跟原型差不多 |
| **Context** | Knowledge + Repos。**显示能力必须有；编辑可后置** |
| **Focus** | 类 ccx todo，先只起"关联 loop"作用 |
| **Chat** | 单聊 chatbot（不支持 group），体现 chat-agent 与 loop 的区别就够 —— 可后置 |
| **Agent** | 0（不在 0.1） |

**关键约束**：c/s 架构从 0.1 就要有 —— 即使只有自己用，为 0.2 铺路，避免中途返工。

**退出标准**：连续用一周，不再回去用 ccx。

### Phase 4：0.2 多人协作

**目标**：在 0.1 的 c/s 架构之上加入"attach 别人 loop" + 团队 Chat 能力。

**范围**：
- attach 协议（多 client mirror）
- driver-transfer
- **Chat 落地：自部署 Mattermost + 1001 sync agent + 1001 chat tab UI**（详见 §3.4）
- 权限边界初步划线

**退出标准**：两人能完成"一人在 chat 中 @ 触发 → spawn loop → 另一人 attach 接手 → close" 的完整流程。

---

## 3. 设计细节

### 3.1 4 个一级概念的 UI 范围（Phase 1 高保真原型）

> 顶部导航顺序：**Loop · Focus · Chat · Context**（active 区在前，reference 库在右；左上角 brand 🧶 loopat · 1001 是 workspace dropdown）

**Loop tab**（最完整）
- 左 loop list（filter 档：我的 / 全部 / RFD）
- 中 chat-first（loop 与 AI 的对话流，含 diff/read/command/artifact 富卡片）
- 右 可选 panel：workdir / editor (CodeMirror) / terminal / info（toggle 开关）
- chat 不显示个人名字（统一 user/ai），driver 切换插系统标记
- header chips：context（knowledge / notes / personal / chat:#xxx 多个）+ focus tag

**Focus tab**（zen）
- **无 sidebar**，顶部窄 toolbar 只有 tagline `what matters now` + `edit notes/focus.md ↗`
- 主区居中卡片：📌 Pinned / focus（8d 倒计时）/ ⑂ active 但未归类 / 📝 inbox preview
- 删除"归档"视图 —— 派生模型下"归档"=不出现在当下，无独立 view

**Context tab**（最大）
- 顶部 horizontal sub-nav：**Knowledge / Notes / Personal / Agents / Repos**（5 sub-tabs）
- 每个 sub-tab 独占 sidebar+main
- Knowledge 是 MVP 的重点：Obsidian-like（wikilink + backlinks + 树状）
- Personal 含 secrets/ 子目录（特殊渲染：值打码 + 🔐 标识）

**Chat tab**（轻量）
- Slack-like channels + DMs（**无 group**）
- `#all` 频道含 workspace 全员（人 + agent），充当成员目录
- channel header 可展开"members（搜索 + 点名直接 DM）"
- channel 头下方 `📤 N loops 把这条 chat 作为 context` 反向引用，可折叠
- 每条消息可 `spawn loop`
- 0.1 阶段简化：先单聊 chatbot 走通，channel/group 后置

### 3.2 关键架构选择

**约定大于配置**
- 目录结构、文件命名、frontmatter 字段、agent persona 字段、API 端点 —— 都是约定
- 用户不能配置层级、字段名、tool 集语义

**统一的 C/S 架构**
- 每个 loop 跑在某个 server 上 —— server 既可以是本机也可以是云端
- client 走同一套 attach 协议
- 共享 local server 的安全 trade-off（端口、权限、账户）是协作不可避免的妥协
- **0.1 即采用 c/s 架构**，即使只有自己用 —— 这是 Phase 3 → Phase 4 平滑过渡的前提

### 3.3 Loop 架构选型（Phase 2 推导结论）

围绕 Loop 页（最复杂的 tab）的三个关键技术问题，逐项推导出具体选型。**核心哲学：filesystem-first，不引入 DB**。

#### 3.3.1 Agent loop runtime → `@anthropic-ai/claude-agent-sdk`

候选对比后选择 Claude Agent SDK 直连：

| 候选 | 否决理由 |
|---|---|
| Vercel AI SDK + 自写 loop | 工程量大；loop 智能度追不上 Claude Code |
| Mastra | 强制 Postgres 依赖，跟 filesystem-first 冲突 |
| pi (earendil-works) | 1 人 maintainer 小项目，生产 mileage 不足 |
| OpenAI Agents SDK / Codex CLI | provider 锁；loop 智能度不如 Claude |
| LangGraph | 不兼容 edge runtime，部署受限 |

**Claude Agent SDK 优势**：
- **loop 智能度第一** —— 它就是 Claude Code 的内核，行业标杆
- **session 是 JSONL 文件**（`~/.claude/projects/<hash>/<id>.jsonl`，肉眼可读）—— 跟我们 filesystem-first 哲学天然契合
- **provider 不锁** —— 通过环境变量切换：直连 Anthropic / AWS Bedrock / GCP Vertex / OpenRouter / 任意 Anthropic-compatible gateway
- **MCP 一等公民** —— 自定义工具协议跨框架可移植
- **skills 系统现成** —— 跟我们 `knowledge/skills/` 直接对接
- **subagent (Task tool) / plan mode / hooks / headless 全套** —— 跟 1001 的 fork loop / spawn / agent triggers 同构

**唯一妥协**：subscription auth 全球被禁（Anthropic 2026-04 革除所有第三方 OAuth），只能 API key 计费。属于客观限制，所有候选都一样，不构成选项差异。

**计费规模预估**：单人单日重度使用（5000万 tokens / 95% cache 命中 / 90:10 input:output）≈ $96/天；通过 prompt cache + Sonnet/Haiku 路由 + output 控制可压到 $30-50/天。

#### 3.3.2 Web Chat UI → `assistant-ui` (React) + Hono server

**前端**：
- 框架：**React 19 + Vite SPA**（不用 Next.js —— Loop 页是长连接 ws，serverless timeout 反受限）
- Chat 渲染：**`@assistant-ui/react`** —— 自带 streaming / tool_use 卡片 / 内嵌 diff viewer / syntax highlighting；通过 `ExternalStoreRuntime` 桥接 ws
- 编辑器：CodeMirror 6（prototype 已用）
- 终端：xterm.js + 后端 node-pty
- 文件树：react-arborist

**后端**：
- HTTP + ws server：**Hono**（opencode 同款；TS-first；ws 原生；跨 runtime）
- 协议：每条 loop 一个 ws topic `/ws/loop/<id>`，server broadcast SDK events 到所有 subscriber

**关键映射**：原型里的富卡片（diff / read / command / artifact / todo）= Claude SDK 流出的 `tool_use` + `tool_result` 块按 tool name 分发渲染。**schema 不需要重新发明**。

#### 3.3.3 Context 隔离 → filesystem + symlinks，Phase 4+ 上 `@anthropic-ai/sandbox-runtime`

**filesystem 形态**（Q3 原始直觉的精确实现）：

```
~/.loopat/
├── shared/
│   ├── knowledge/         (chmod 755，team 共享，git 同步)
│   ├── notes/             (chmod 755，team prose)
│   └── repos/<repo-id>/   (.git ref，loop 启动时 git worktree add)
├── personal/<user-id>/    (per-user 私有)
└── loops/<loop-id>/
    ├── workdir/                          (git worktree of repo, RW)
    ├── .context/
    │   ├── knowledge/  → ../../shared/knowledge       (RO mount)
    │   ├── notes/      → ../../shared/notes           (RW mount)
    │   ├── personal/   → ../../personal/<driver-id>   (driver 切换时 unlink/relink)
    │   └── chats/
    │       ├── all@12.jsonl       (immutable 快照，从消息库 dump)
    │       └── dev@86.jsonl       (文件名带 @upTo，sync 创建新文件不 mutate)
    ├── .claude/
    │   └── projects/<hash>/<sid>.jsonl   (SDK session JSONL，per-loop 不污染 ~)
    └── .pid                               (sandbox 进程 pid)
```

**关键设计**：
- **chat-mount = immutable JSONL 文件**（文件名带 `@upTo`），对应 `loop.context.chats[]`。sync = 物化新文件，旧文件保留 → 历史可追
- **agent 直接用 Read tool 读 jsonl** —— 跟读普通文件一样，零特殊语义
- **driver-transfer**：`unlink personal symlink → relink → 重启 sandbox 进程`
- **SDK session 落在 loop 内**（覆盖 SDK 默认 `~/.claude/projects/`），整个 loop 目录可打包迁移

**沙箱分阶段**：

| Phase | 隔离强度 | 用什么 |
|---|---|---|
| Phase 3（你 + panlilu，自 trust） | chmod + symlinks + Claude SDK `allowedPaths` | 不上 sandbox-runtime；零成本 |
| Phase 4（小团队，driver 跨人） | **`@anthropic-ai/sandbox-runtime`** | bwrap (Linux) / sandbox-exec (macOS)，per-loop 子进程隔离 |
| Phase 5+（开放产品 / 不可信用户） | E2B microVM 或 Docker | 硬件级 |

`@anthropic-ai/sandbox-runtime` 是 Anthropic 自家开源的 lib（Claude Code 内部就用它隔离 MCP server），库 API：`SandboxManager.initialize() + wrapWithSandbox()`，配置 fs allow/deny + network 域名白名单。微秒级启动，无 daemon，**远比 Docker 轻**。

#### 3.3.4 总架构图

```
┌───────────────────────────────────────────────────────────┐
│ Browser (React + Vite + assistant-ui + CodeMirror)         │
└───────────────────────────────────────────────────────────┘
              ↑ ws (attach protocol)
              ↓
┌───────────────────────────────────────────────────────────┐
│ Hono server (Node)                                         │
│   - REST: loops / workspaces / focus / context             │
│   - ws: per-loop topic broadcast                           │
│   - per-loop: spawn sandboxed Node child                   │
└───────────────────────────────────────────────────────────┘
              ↓ spawn (Phase 4+ wrapped via sandbox-runtime)
┌───────────────────────────────────────────────────────────┐
│ Per-loop child process                                     │
│   - cwd = workdir, allowedPaths = .context/ + workdir      │
│   - Claude Agent SDK session                               │
│   - MCP server (loopat-tools/) 自定义 1001 操作             │
│   - 4 内置 tools: Read / Write / Edit / Bash               │
│   - sandbox: @anthropic-ai/sandbox-runtime（Phase 4+）     │
└───────────────────────────────────────────────────────────┘
              ↓
       Claude API（默认）/ Bedrock / Vertex / OpenRouter
```

#### 3.3.5 跟 panlilu loopat-ts spike 的取舍

panlilu 这一周做的 `loopat-ts` 是 **DB-first 路线**（Next.js + tRPC + Prisma + Postgres + NextAuth）。本节推导的是 **filesystem-first 路线**。两者**架构哲学冲突**，不是技术细节冲突：

| 维度 | filesystem-first（本节） | DB-first（panlilu） |
|---|---|---|
| Source of truth | 目录 + JSONL 文件 | Postgres 行 |
| Domain model | 文件系统约定 + frontmatter | Prisma schema |
| revision / audit | git 自然管 | DB 自己写 |
| Auth | workspace 边界 = filesystem 边界 + invite link token | NextAuth + Account/Session 表 |
| 部署起步成本 | `node loop-server.js` | Postgres + migrate + Next.js build |
| Claude SDK 适配 | session JSONL 同构，零 ORM | 要桥 Prisma ↔ SDK |
| agent 友好度 | agent `Read('notes/focus.md')` 直接读 | agent 不能直接读 DB，要走 tRPC |
| 跟 Q3 直觉吻合 | 是（"context 就是一个目录"） | 否 |
| 跟 opencode / Claude Code 路径一致 | 是 | 否 |

**结论倾向**：filesystem-first 更贴 1001 哲学。panlilu 这周的工作大部分要 throw away（架构决定，非技术质量问题），但 schema 思考 + ws 协议草稿 + auth 边界讨论值得保留作为概念地图，沉淀进 `knowledge/loopat/architecture.md`。

**周末 close 取舍的关键议题**：
1. 把 Q1+Q2+Q3 推导跟 panlilu 过一遍，看他能否提出 filesystem 路线 cover 不了的真实需求（如跨 loop 检索 / 实时强一致性）
2. 如果他不能 → 这周末就是结论：filesystem-first 落地，Prisma/Auth/tRPC 一周作品归档进 `thoughts/superseded/`
3. 重新分工：simpx 做 Hono server + Claude SDK + sandbox 集成；panlilu 做 Vite frontend + assistant-ui + 右 panel 组件

### 3.4 Chat 架构选型

Chat tab（团队 Slack-like channels + DMs）跟 Loop 内的 AI 对话是不同产品形态。要解决的核心矛盾：

> 不自建 chat 客户端基础设施（富文本 / 长连接 / 一致性 / 多端同步是深坑），但要保留 1001 的 chat-as-context + spawn-loop + 反向引用 等差异化语义，且坚持 filesystem-first（agents 直接 `Read('chats/<id>/messages.jsonl')`）。

#### 3.4.1 候选对比

| 候选 | 自托管 | 全消息访问 | 历史保留 | 现成客户端 | 月成本 | 评价 |
|---|---|---|---|---|---|---|
| 自建 chat（filesystem JSONL + 自写 UI） | ✅ | ✅ | ✅ | ❌ 全自建 | $0 | 富文本/客户端/一致性/长连接坑全要自填，**否决** |
| **Mattermost (Team Edition)** | ✅ | ✅ via WS subscribe | ✅ DB-backed 永久 | ✅ **官方 web/mac/win/iOS/android 全套** | $0 | **本节选型** |
| Slack | ❌ SaaS | Pro $8/u 才完整 | 90d 免费 / Pro 无限 | ✅ 极好 | $80/月 (10 人 Pro) | 数据 sovereignty 不符 1001 定位 |
| 钉钉 | ❌ SaaS | ❌ Bot 仅收 @ 它的消息 | 客户端缓存 | ✅ 极好 | 0-付费 | API 设计哲学不允许全 channel sync，跟 1001 用法冲突 |
| WuKongIM | ✅ Apache 2.0 | ✅ via webhook | ✅ 永久 | ❌ **只有 SDK 没有客户端** | $0 | 性能过剩；客户端要 1001 自建（违反"不入坑"原则） |
| Discord | ❌ SaaS | ✅ | ✅ 免费无限 | ✅ 好 | $0 | gamer-y 气质，不适合正式团队 |

#### 3.4.2 选型：Mattermost (Team Edition) 自部署

**部署形态**：
- 1 台 4GB VPS（约 $24/月）
- Docker compose：`postgres:15` + `mattermost/mattermost-team-edition:latest`
- 协议：MIT（核心）/ AGPL（Enterprise，1001 暂不需要）
- 提供 REST v4 + WebSocket events API + Webhook（in/out）+ Plugin（Go in-process）

**为什么 Mattermost > 其他**：
1. vs Slack：数据 100% 自有 + 永久保留 + 零月费
2. vs 钉钉：可监听全 channel 消息，不限于 @
3. vs WuKongIM：**现成全平台官方客户端**（web/mac/win/iOS/android 全开源 MIT），用户日常聊天有 native app 兜底；WuKongIM 只有 SDK，移动端要自建
4. vs 自建：富文本 / 客户端 / 一致性 / 长连接 / 历史 / 搜索全部 Mattermost 给

#### 3.4.3 与 1001 的集成形态（filesystem-first 保留）

```
┌──────────────────────────────────────────────────────┐
│ Mattermost server (Docker on VPS)                     │
│   ├─ PostgreSQL                                       │
│   ├─ Mattermost binary (Go)                           │
│   └─ Native clients (web/mac/win/iOS/android)        │
│        ↑↓ 用户日常聊天走这里                           │
└──────────────────────────────────────────────────────┘
            │ /api/v4/websocket (订阅 posted event)
            │ /api/v4/posts (REST 发消息)
            ▼
┌──────────────────────────────────────────────────────┐
│ 1001 Hono server                                      │
│   ├─ sync agent: WS 订阅 → 镜像                        │
│   └─ chat tab API: GET 读 fs / POST 转发 MM REST      │
└──────────────────────────────────────────────────────┘
            │ append jsonl
            ▼
┌──────────────────────────────────────────────────────┐
│ chats/<channel>/messages.jsonl  (filesystem-first)    │
│ ← agents 直接 Read('chats/dev/messages.jsonl')         │
│ ← 1001 web tab 渲染从这里读                            │
└──────────────────────────────────────────────────────┘
```

**关键设计**：
- **MM 是消息真源**（数据库 + 长连接 + 一致性都 MM 给）
- **fs jsonl 是 agent 友好镜像**（sync agent 把 MM events 物化成 JSONL 一行一条）
- **1001 web chat tab 是 first-class 客户端**（不嵌 iframe）：渲染走 fs，写入经 1001 server → MM REST API → events 回流 mirror 自动更新
- **用户三种入口同步**：MM mobile app / MM desktop / 1001 web tab，消息进同一个 MM channel + 同一份 mirror

**1001 chat tab 给 MM 没有的差异化**（让用户愿意用 1001 而不是只用 MM 客户端）：
1. 每条消息 inline `📎 spawn loop` —— 选消息 + 当前 channel 当 chat-mount → 一键 spawn loop with chat context
2. channel header 下 `📤 N loops 把这条 chat 作为 context` 反向引用，可点跳进 loop
3. agent DM 一等公民（dm-coo / dm-ops-bot），跟 MM 普通 user DM 视觉同列但内核是 Claude Agent SDK
4. `[[notes/focus.md]]` wikilink inline 渲染 + 点跳 Context tab
5. 跟 #all 的 members 面板共享 workspace 全员目录

#### 3.4.4 已知限制与对策

**1. Bot 看 channel 消息要被加进 channel**（跟 Slack 同模型）
- public channel：sync agent bot 自动 join 全部
- private channel：需要 admin invite

**2. 私 DM 同步**（Phase 5 再做）
- bot account 看 bot ↔ 人 的 DM
- 看不到 人 ↔ 人 的 DM（合规边界）
- 真要 sync：每个用户 OAuth 给 user token，Phase 5 再做

**3. 已知 bug**（2026-02 社区报告）
- 某些 bot account 通过 WS 收不到 channel posted event
- Workaround：sync agent 用 `team_user` 账号 + user token 而非 bot account（本来就是"看一切"用例的标准做法）

**4. Free Team Edition 功能限制**
- 无 SAML / LDAP / 高级审计 —— Phase 4 团队 ≤ 50 人不需要
- Phase 5+ 给 enterprise 客户再升 Enterprise

#### 3.4.5 阶段路径

| 阶段 | 方案 |
|---|---|
| Phase 3（你 + panlilu） | **不做 chat tab**。日常沟通用现有工具（钉钉 / iMessage 等）。1001 内只有 Loop tab + agent 对话 |
| Phase 4（团队 ≤ 10 人） | **Mattermost Team Edition 自部署 + 1001 sync agent + 1001 web chat tab UI** |
| Phase 5+（开放产品） | Source 抽象成 `ChatSource` 接口，加 Slack / WuKongIM / 钉钉 / Discord adapter，按客户偏好切。所有 adapter 共享 fs jsonl mirror 接口，agent 一致 |

#### 3.4.6 跟 §3.3 Loop 架构的衔接

Chat 跟 Loop 在底层共用相同基础设施：
- 同一台 Hono server（loop server + sync agent 两个 module）
- 同一个 ws 协议（attach 协议跟 chat 实时增量是同形态广播）
- 同一份 filesystem 约定（chats/ 跟 loops/ 平级在 workspace 目录下）
- agents 用同一个 Claude Agent SDK + MCP server 既能驱动 loop 又能 post 到 chat

**→ Phase 4 一次到位，不返工**。

---

## 4. 待解（按优先级）

1. **Loop 共享的安全边界**：C/S attach 协议的权限模型、本机 server 暴露端口的安全 trade-off 还没想清楚
2. **Workspace 隔离 + 权限**：账户系统、谁能看哪个 loop / focus / knowledge
3. **Agent 提炼回流的触发机制**：被动监听 / 定时跑 / on-demand 触发
4. **Knowledge 的 wikilink + backlinks 持久化索引**：原型是 mock，要有真实的反向索引和增量维护
5. **Loop 的 dir 与 repo worktree 映射**：spawn loop 时 git worktree add 的策略，close / archive 时 worktree 怎么回收

---

## 5. 当前状态指针

- **品牌**：`loopat.ai`（logo 🧶 毛线团；隐藏词 "pat" 作为 AI 反馈动作）；内部 codename `1001`
- **主仓**：`github.com/simpx/loopat`
- **原型代码**：`phase1-prototype/`（Vite + SolidJS + Tailwind v4，纯 mock，Phase 1 ✅）
- **Phase 2 选型推导**：§3.3（filesystem-first 路线）
- **Phase 2 spike 现状**：
  - simpx：`opencode-fork`（branch `1001-prototype`）—— 调研用，最终不 fork，借鉴 stack
  - panlilu：`loopat-ts/`（Next.js + tRPC + Prisma + WS，staging `staging.loopat.ai`）—— 跟选型冲突，周末 close 后归档至 `thoughts/superseded/`
- **历史思考脉络**：`thoughts/`（包括 `thoughts/superseded/` 里的早期框架）
