blob: 00f668742433075e59507847fdb016f7d80607f8 [file] [view]
# 专家团实现详情 — WorkBuddy & QoderWork 逆向(实现级)
> 本文是"专家团/数字同事"两款竞品的**完整实现拆解**,用于指导 maka-agent 的实现。
> 基于对本机安装的 WorkBuddy(腾讯 CodeBuddy 换皮)与 QoderWork(阿里 Qoder)的解包逆向。
> 上层设计与 maka 落点见 [expert-team-plan.md](expert-team-plan.md)。
> 逐层原始 spec(含 byte offset / 逐字字符串)在 scratchpad
> `IMPL-workbuddy-runtime.md``IMPL-workbuddy-mainprocess.md``IMPL-workbuddy-renderer.md`
> `IMPL-workbuddy-colleague.md``IMPL-qoderwork-runtime.md``IMPL-qoderwork-plugins.md`
> 标注:**[C]** = 代码/文件中确证,**[I]** = 推断。
---
# 总览:两家的架构范式
两家惊人地同构,都是 **"Electron 壳(manager)+ 一个 Claude-Code 派生的 CLI agent 引擎 + 一个远程 marketplace"**:
| | WorkBuddy | QoderWork |
|---|---|---|
| | Electron 主进程(DI/CellJS 组件) | Electron 主进程 `main.js` |
| Agent 引擎 | `agent-cli``codebuddy.js` 21.6MB,品牌 "CodeBuddy Code"),**每会话一个 `agent-cli --serve` 子进程** | `qodercli``@qoder-ai/qoder-agent-sdk`),**host(94KB) + worker(35MB obf) 两进程** |
| 引擎↔壳 通信 | HTTP (`/api/v1/*`) + ACP endpoint | hostworker transport + SDK API |
| "专家"单元 | plugin bundle(含 `agents/*.md` 人格)从 COS 拉取 | Plugin 文件夹(skills+commands+connectors)本地/云 |
| 多智能体 | **两种原语**:sub-agents + Agent Teams`TeamCreate` | sub-agents`Agent` 工具,无 team 原语) |
| 人格来源 | 专家 plugin agent md(身份覆盖 system prompt | awareness `SOUL.md` 分层(system-reminder 注入) |
| 数字同事 | 有(cloud-agent + Claw IM + BackgroundAgent 云端) | 无(只到 plugin/awareness 层) |
**关键洞察**:两家的"专家"本质都是 **"带人格的 agent 定义(md + frontmatter)+ 一个能热加载它的 CLI 引擎"**。真正的差异在**多智能体编排**(WorkBuddy 有完整的 Agent Teams 原语,Qoder sub-agent + 工具作用域)和**产品化外壳**(WorkBuddy 有数字同事 + IM + 云端)。
---
# 第一部分:WorkBuddy
## A0. 进程/目录拓扑
- **引擎**:`agent-cli``wb-app/cli/dist/codebuddy.js`),`--serve` 模式暴露本地 HTTP + ACP。**每个会话一个子进程**(`SidecarServer` / `sidecar-entry.js`macOS/Linux `@lydell/node-pty` PTYWindows `spawn`)。[C]
- **状态目录**:引擎侧 `~/.codebuddy/`;壳侧 `~/.workbuddy/`(部分镜像)。
- **专家 marketplace**:腾讯 COS `https://acc-1258344699.cos.accelerate.myqcloud.com/workbuddy/expert-marketplace`
- **引擎自带人类可读文档**(逆向金矿):`wb-app/cli/dist/web-ui/docs/cn/cli/{sub-agents,agent-teams,plugins-reference,skills,sdk-hooks,acp,permissions}.md`
## A1. 数据模型(marketplace)
Manifest = `expert_center.json`331 专家 / 13 分类),外加并行拉取 `internalExpert.json`/`externalExpert.json` 合并(企业内外部隔离)。每个专家条目关键字段:
```
id, categoryId, displayName{en,zh}, profession, description,
promptFile, # COS 相对路径,指向人格 md(如 /plugins/content-creator/agents/content-creator.md)
avatar, defaultInitPrompt{en,zh}, quickPrompts[], tags[],
expertType: "agent"(285) | "team"(46), # team 就是"专家团"
agentName, plugin, # 指向 bundle 内的 agent id
members[] # 仅 team:[{id, displayName, profession, avatar, promptFile, role:"lead"|"member"}]
```
人格 md = YAML frontmatter`name, description, color, emoji, vibe`team lead `maxTurns:200`)+ body(🚨身份覆盖指令 + Role/Capabilities/内置Skill触发 + 🔒身份提醒)。
## A2. 主进程专家生命周期(`IMPL-workbuddy-mainprocess.md`)
DI 组件(CellJS `@Component`):`ExpertManifestProvider`(+`ExpertCacheManager`+`ExpertCenterResourceLoader`)、`ExpertService`/`ExpertCloudService`/`ExpertDesktopService``ExpertPluginService``ExpertHistoryService`
### A2.1 Manifest pipeline — 缓存优先 + 前台增量 + 后台重校验
```
CURRENT_SOURCE_SIGNATURE = JSON.stringify({baseUrl, manifestPath})
cacheDir = <runtimeUserDataDir>/cache/experts → manifest.json / version.txt / metadata.json
metadata = {version, cachedAt, sourceSignature, manifestHash: sha256(JSON), cacheFormatVersion:2}
doInit():
loadFromCache() // sourceSignature 不符则 clear
有缓存 → syncManifestBeforeReady()(前台 fetch,version==&&hash== 则保留,否则替换)
无缓存 → fetchAndCacheManifest()(冷启动远程拉)
backgroundManifestUpdate() // setImmediate 后台重校验,变了才替换
fetchManifest() = Promise.all([base expert_center.json, ...scoped]) → mergeExpertManifests(id-keyed Map,scoped 覆盖 base)
```
**无 ETag**,靠 sha256+version+sourceSignature。企业/visibility 过滤在**渲染层**做。
### A2.2 激活 `ExpertPluginService.activateExpert()`
```
bundleName = pluginName || manifest.experts[].plugin || kebab(expertId)
localPath = 下载 COS /bundles/<bundle>.tar.gz(zip 仅限可信运营平台 URL,host allowlist + zip-slip guard)→ 解压
manifest = 读 .codebuddy-plugin/plugin.json
agentName = resolveExpertAgentName(5 级:manifest.agentName → team leadAgent → agents/<kebab(id)>.md 的 name → 唯一 .md → kebab)
→ 注册 marketplace(marketplace.json 增量)→ 删旧 agent-override settings.json → activeExperts.add
return {expertType, agentName, localPath, pluginRegisteredName}
```
`resolveExpertLocation` 优先级:hint 官方 `experts` 自建 `my-experts`,缺失则懒下载。下载有 in-flight dedup + `.downloaded_at` 时间戳判新旧。
### A2.3 会话绑定 + CLI 注入(核心机制)
`sessions` 表列:`expert_id / expert_locale / expert_runtime_identity / expert_marketplace``upsertSession` COALESCE 合并)。
> **纠正**:`expert_runtime_identity` 是**不透明激活 key 字符串**(默认 `expert:<id>`,实际是 `name@marketplace` sourcePluginId),**不是** JSON 人格快照。用作幂等重激活的 dedup key
**人格如何进入 CLI —— 不是 spawn 参数,而是 before-prompt hook + HTTP:**
```
createWorkbuddyAppServerBeforePromptExpertActivation({sessionId, desiredConfig}):
resolved = resolveExpertLocation(expertId, marketplace) // 懒下载
headers = {"X-Expert-Id": expertId, ...(team ? {"X-Expert-Team-Task":"true"} : {})}
switchExpertPluginForSession(sid, disable=ø, enable=manifest.name, agentName,
sourcePluginId=`${manifest.name}@${marketplace}`, headers)
→ POST `${httpBase}/api/v1/plugins/switch`
body {persist:false, enable:`name@mp`, agentName, sourcePluginId, internalModelRequestHeaders}
```
`persist:false` 只在当前 CLI 进程内生效。这一个 HTTP 调用让通用 `agent-cli` 把该 plugin agent md 当作 system prompt 加载。team 专家额外带 `X-Expert-Team-Task` header,触发 agent-teams 环境。自建专家(`@my-experts`)走两次 POST override-refresh 让编辑后的人格重载。失败则"降级到当前 prompt"(会话仍跑,只是没人格)。
### A2.4 IPC(`expert:*` / `expert-history:*`)
21 `expert:*` channel`init/getCategories/getExperts/getExpert/getFeaturedScenes/getRanking/activatePlugin/switchPluginForSession/exportZip/importFromUrl/preCheckShare/queryShareSecurityScan/scanCustomExperts/addUserExperts/...`)。渲染层实际召唤走**一个 facade RPC `expert:summonExpert`**(不是细粒度 channel),主进程内部编排 detaildownload+activatehistory
### A2.5 分享 & 安全
- 导出 `exportExpertZip`adm-zip,顶层单目录=expertIdmanifest 里盖章分享者。
- 导入 `installExpertZipFromPath`:强制单顶层目录 + `plugin.json` + 路径逃逸 guard `my-experts`
- 安全扫描:腾讯 **XTI** API`SkillSecurityClient``SkillAnalysisUpload`/`SkillAnalysisInfo`md5 键,threatLevellow/medium/high)。`runSkillPreCheck` **fail-open on scanner error, fail-closed on risk verdict**(扫描器出错放行,返回风险则 `security_check_blocked`)。
## A3. Agent 运行时(`IMPL-workbuddy-runtime.md`)—— 最有价值的部分
### A3.1 两种协作原语(不要混)
引擎自带文档明确区分:
| | **Sub-agents** | **Agent Teams** |
|---|---|---|
| 派生 | `Agent` 工具(**无** `name` | `TeamCreate` `Agent`(**带** `name` |
| 上下文 | 独立 window;**结果 summary 回传给 parent** | 独立 window;**完全独立** |
| 通信 | 只能把 final result 上报 parent | 成员间 `SendMessage` mailbox 互发 |
| 协调 | parent 全权编排 | 共享 task list,成员自领任务 |
| 拓扑 | 星型(仅 parent | mesh(成员↔成员 + `@all` 广播) |
marketplace `team` 专家跑在 **Agent Teams** 上;lead 人格 md 里写的编排指令**驱动**真实的 `TeamCreate``Agent``SendMessage` 工具(**没有服务端 router**)。
### A3.2 `Agent` 工具(逐字 schema,offset ~11,263,540)
```js
name = "Agent"
parameters = z.object({
description: z.string(), // 3-5 词任务描述
prompt: z.string(), // 交给 agent 的任务
subagent_type: z.string().optional(),
model: z.enum(["default","lite","reasoning"]).optional(),
resume: z.string().optional(), // 传上次 agentId 续跑(带完整历史 transcript)
run_in_background: z.boolean().optional(), // 返回 task id,用 TaskOutput 取
name: z.string().optional(), // 有 name → teammate(可被 SendMessage 寻址);"team-lead" 保留
team_name: z.string().optional(),
mode: z.enum(["acceptEdits","bypassPermissions","default","plan"]).optional(),
max_turns: z.number().int().positive().optional()
})
```
`execute()` 路由顺序:**fork 特化**(`<fork-boilerplate>` prompt 禁止嵌套 fork)→ **teammate**(有 `name` + team 启用 `spawnTeammate`)→ **background**(`run_in_background` 返回 task id)→ **同步 sub-agent**(默认;`isolation:"worktree"` 则建 git worktree)。
### A3.3 执行模型
- sub-agent/teammate 是**进程内 `AgentTask`**(`detached:true, captureOutput:true`),不是独立 OS 进程;可选 `--swarm`/`CODEBUDDY_INPROCESS_TEAMMATES`
- **独立 context window,全新状态**:成员不继承 lead 历史,spawn 时重载 `CODEBUDDY.md`/MCP/skills
- **返回=summary transcript**:完成时先跑 `SubagentStop` hooks,再用 `result.finalOutput ?? "Task completed"` resolve parent await callback。大输出外置到 `tool-results/{callId}.txt` 用指针引用。
- **禁止嵌套**:sub-agent 不能再 spawn sub-agentteam 不能建 sub-team(只有 lead team)。
- **并行 = 一个 assistant turn 里多个 `Agent` tool_use block**。
- **resume**:每次跑有 `agentId`transcript `~/.codebuddy/projects/{proj}/{parentSid}/subagents/agent-{agentId}.jsonl`
- **内置 agent 类型**:`general-purpose`(全工具)/`explore`(只读,gemini-3.0-flash)/`plan`/`fork`/`compact` + 保留的 `team-lead`
### A3.4 人格→system prompt(身份覆盖机制)
agent md body agent `systemPrompt``buildSystemPromptAgentOverride(name, instructions, appendInstructions)`:**`instructions` 完全替换** base persona`appendInstructions` 追加。marketplace 人格用 `instructions`(完全替换)装入"🚨你是X且只是X,绝不暴露底层模型"的身份覆盖模板。`defaultInitPrompt` **不在** system prompt —— 它作为**首条 user message** 注入。
### A3.5 `TeamCreate` / `SendMessage` / `TaskStop`(逐字 schema)
```js
// TeamCreate(lead-only,一会话一 team;offset ~11,586,300)
"TeamCreate" params: {team_name, description?, agent_type?}
execute: 若已在 team → 拒绝;createTeam → ctx.meta.isTeamLead=true → 启动 inbox 轮询 →
返回 "Spawn teammates with the Agent tool using `name` and `team_name`"
// SendMessage(mailbox;offset ~11,450,000)
"SendMessage" params: {
type: z.enum(["message","broadcast","shutdown_request","shutdown_response","plan_approval_response"]),
recipient?, content?, summary?, request_id?, approve? }
// TaskStop:取消 running/pending 的 AgentTask 或 background shell
```
**Delegate Mode**(Shift+Tab):把 lead 限制为协调工具 `Agent, TaskStop, SendMessage, AskUserQuestion, StructuredOutput`(无 Read/Edit/Bash)。**Plan-before-implement**:`Agent{mode:"plan"}` 成员交计划 lead `SendMessage{plan_approval_response, approve}`
**Team 磁盘状态**:`~/.codebuddy/teams/{team}/config.json``inboxes/{member}.json``~/.codebuddy/tasks/{team}/`(任务 pending/in_progress/completed,支持依赖,完成自动解锁下游,成员自领)。清理 team 必须 lead 做。
### A3.6 Skills / Plugins / Hooks / ACP
- **`skill` 工具**:params `{skill | command, args}``/` 开头走 slash command,否则执行 Skill。人格 frontmatter `skills:` agent start 自动加载。
- **Plugins** 打包 `agents/ skills/ commands/ connectors/``.codebuddy-plugin/plugin.json`),marketplace 注册进 `PluginManager`;专家=从 COS 懒拉的 plugin
- **Hooks**:`PreToolUse/PostToolUse/SessionStart/Stop/SubagentStart/SubagentStop``SubagentStop` parent callback resolve 前触发。
- **权限优先级**:`Agent{mode}` `--subagent-permission-mode` env settings 继承(Delegate Mode 强制 `default`)。
- **ACP team bridge**:`session_info_update._meta["codebuddy.ai/teamUpdate"]` member 状态;成员流用 `_meta["codebuddy.ai/memberEvent"]` 打标路由到各自 timeline`AcpTeamBridge` 刷新时重放历史。
### A3.7 一个 team 专家端到端
1. 召唤 team 专家 下载/解压 bundle session CLI **lead** md 为身份覆盖 system prompt 启动 首条 msg=`defaultInitPrompt`
2. lead 人格指示它调 `TeamCreate{team_name, agent_type}` `~/.codebuddy/teams/…` 启动 inbox 轮询。
3. lead 1+ `Agent{name:"role", subagent_type:"memberId", team_name, prompt, mode?}` 各成为进程内 detached `AgentTask`
4. 成员并行、从共享 task list 自领任务、用 `SendMessage` 协调。
5. 每成员完成触发 `SubagentStop``finalOutput`(仅 summary)回 leadlead 综合 `SendMessage{shutdown_request}` 清理 team
`agent` 型专家(86%)折叠 2-4 步:单个人格注入的对话 agent,可选用 `Agent` 工具做星型 sub-agent
## A4. 渲染层(`IMPL-workbuddy-renderer.md`)
- **召唤流程**:卡片"立即召唤" `handleSummon`team 警告 + 金融风险 gate)→ `useExpertSummon().summonExpert` **一个 facade RPC `expert:summonExpert`**(detaildownload+activatehistory)→ `session.prepare({selectedExpert})` pending expert `goHome()`(新会话)或 `navigate('/task/:id')`
- **`defaultInitPrompt` 在专家中心路径下只 pre-fill composer**(`applyExpertDefaultPrompt` = `setInputValue`),**不自动发送**;只有 colleague chat page `autoSendPrompt` 会真发。`quickPrompts` = `promptOverride` 重召唤的按钮。
- **状态**:无 redux,真值源是 `WorkbuddyAgentAdapterNext.selectedExpertBySession`Map,含 `PENDING_EXPERT_SESSION_KEY`)+ RxJS Subject 总线(`pendingExpertModeActivation$` 等)。会话内切专家 `expert:switchPluginForSession`(原子 disable-old+enable-new,一次 `rebuildAgents`)。深链导入 buffer `globalThis.__GENIE_PENDING_EXPERT_INSTALL_INTENT__`
- **主题**:`useExpertTheme()` `document.body.classList``vscode-dark`/`vscode-high-contrast`dark)+ `MutationObserver` 监听 body class`useThemeClassName()``expert-center-dark|light` 盖在 `.expert-center-page`,切换 `--ec-*` CSS 变量族。per-expert accent 来自人格 frontmatter `color`/`emoji`,与明暗正交;头像 fallback 8 `--ec-avatar-fallback-bg-N``name.charCodeAt(0)%8+1`)。
## A5. 数字同事 / 云助理(`IMPL-workbuddy-colleague.md`)
UI "助理/云助理/数字同事"映射**三个内部子系统**:**cloud-agent**(定义+实例+会话,后端 CRUD)、**cloud-assistant**(entitlement 门)、**Claw**(IM 渠道 + 后台 agent)+ **BackgroundAgent**(云后端,webhook + Redis ChannelRegistry)。
### A5.1 双存储面
- **云面(权威)**:colleague 是**云对象**,非本地行。`POST /v2/user/cloudagent/agents` 创建,带**版本化 `manifest`**。REST`orchestrator/agents/validate-field/quota/clone/versions/enterprise-published` + `/v2/as/conversations/*`IPC `cloudAgent:*` / `cloudAssistant:*` 镜像。
- **本地面(调度/会话)**:`automations` 表(RRULE`schedule_type``next_run_at`、**`expert_id`/`expert_marketplace`**=雇佣的专家、`connector_ids_json``skills_json`、**`push_to_wechat`**)→ `automation_runs`/`automation_runtime_state`IM 绑定存 `settings.json → claw.channels` + `ioa-im-override.json` + `AgentImBindingStore`
### A5.2 创建对话字段
基本信息(avatar 5MB / 昵称 validateField 查重 / 职能预设)+ 能力配置(**hireExpert** `{expert|team|企业智能体}` 1 / **codeRepo** github·cnb·工蜂 OAuth / **knowledgeBase** / **model** listAvailableModels)。雇佣的专家存为 `expert_id`+`expert_marketplace`,会话启动时按普通召唤解析人格;额外由 **MemoryCollector** 注入 `ClawMemory_1/2/3` + `<cwd>/.workbuddy/memory/MEMORY.md`(cap 8000 字)。
### A5.3 IM 绑定(最新颖)—— 无第三方 IM SDK 打包,两种模式
- **`webhook`(云中继,默认)**:`ClawService.registerChannelWithBackend` → `POST /v2/backgroundagent/localProxy/register` 写后端 ChannelRegistry(Redis)返回 `webhookUrl`。IM 平台 → webhook → 后端 → cloud-agent 会话 → 回复。**桌面可离线**。
- **`websocket`/`scan`(本地)**:沙箱化的 IM **CLI plugin 子进程**(`lark-channel`/`wecom` 等)持 WebSocket 到平台,通过 unix-socket JSON-RPC 流给 daemon。
- 各平台认证走 CLI(`lark-cli config init --new`+`auth login`、`wecom-cli init --noninteractive`,抓 stdout 的 auth-URL/QR/device-code)+ 微信机器人 QR + QQ QR。
- 绑定键 `users[uid].targets[targetType][targetId].backends[backendMode][channelType]`,`targetType∈{assistant,colleague}`,`backendMode∈{local,cloud}`。@提及 → `triggerSource="user_mention"`。**IOA gate**(`ioa-im-override.json`)在腾讯内网机器上拦非腾讯 IM。
### A5.4 云/daemon/调度/配额
- `daemon-app-server` 是 Electron main 的独立 stdio-only Node 子进程,跑同一 `module.app-server` 容器 + 常驻后台服务(Claw 渠道 plugin + automation 调度器)——即"本地云"。云模式用后端沙箱 + 微信小程序做"手机远程"。
- 调度:`automations`(RRULE)→ `automation_runs`。
- 配额:服务端 `GET /v2/user/cloudagent/quota`,渲染层映射 个人体验版/专业版/SaaS企业版;`cloudAssistant:getEntitlement` 门控。
---
# 第二部分:QoderWork
## B0. 架构(`IMPL-qoderwork-runtime.md` §0)
Electron 是 **manager**;真实 agent loop 在打包的 **`qodercli`(`@qoder-ai/qoder-agent-sdk`)**:
```
app.asar.unpacked/node_modules/@qoder-ai/qoder-agent-sdk/
package.json # name "@ali/qoder-agent-sdk-next" v1.0.13, qoderCliVersion 1.0.41
dist/index.js # 94KB host(query/listSubagents/hooks/session)
dist/_worker/qoder-worker-runtime.obf.mjs # 35MB 真 agent loop(obfuscated,base64+XOR key "hABjM4Eb0CeC")
```
worker 由 `install` 从 `download.qoder.com/qodercli/releases/1.0.41/...tgz` 下发。`defaultTransport:"worker"`。**Qoder 没有 team 原语**,多智能体只靠 sub-agent + 工具作用域。
## B1. Plugin(专家套件)打包/安装/热加载(`IMPL-qoderwork-plugins.md`)
### 目录 & schema
```
~/.qoderwork/plugins(市场装) / plugins-custom(自建/fork ; Resources/plugins-example15 个内置"本地市场"
配置目录候选 [".qoder-plugin", ".claude-plugin"](兼容 Claude-Code 导入)
plugin.json: {name, displayName, version, description{En,Zh}, category, customizedFrom?, tags,
skills:["./skills/xxx"], commands:["commands/x.md"], qoderMarket?:{pluginId}}
guards: isValidPluginFolderName(无 ../\/前导.); BLOCKED{员工管理,招聘管理,薪酬绩效}; MAX_ZIP 50MB
```
### 安装 → 迁移 → 热加载
- tRPC `plugin.*`(`installMarket/forkPlugin/updateMarket/uninstall/listInstalled/...`);本地源从 `plugins-example` 拷贝,远程源按 `pluginId` 下载。
- **`plugin-cli-migration-service`**:把 plugin 所有权从 Electron 迁给 qodercli(feature-gate `qoderworkPluginCliMigrationV1Succeeded`,幂等一次性)。`PluginCliManagementService.syncInstalled` → SDK `installPlugin(path)` 注册目录 → `enablePlugin/disablePlugin` 开关。
- **热加载**:`reloadMainSessionPlugins(reason)` → `runtime.reloadPlugins()` → `query.reloadPlugins()` 返回 `{plugins[], commands[], agents[], mcpServers[]}`,**live session 内热注入无需重启**。一个 plugin 一次贡献 skills+commands+sub-agents+MCP。
## B2. Skills / Commands
- **Skills**:`SKILL.md`(YAML frontmatter `name/version/description/description_zh/disabled` + body)。发现优先级 builtin→user→plugin→market;首次运行把 default-enabled 内置 skill **拷进** user 目录供编辑。**注入=懒加载 + description 触发**:模型只见 catalog(name+description,故意堆同义触发词),body 在 `@`/`/`/`Skill` 工具激活时加载,`references/` 按需(progressive loading,SKILL.md <500 行)。`user-invocable:false` = 隐藏知识库 skill,只被别的 skill 引用。启停=改 `disabled:` frontmatter。
- **Commands**:`commands/*.md`(frontmatter + body=prompt macro),`/name` 调用。
- **`external-commands`**:`registry.json` 声明的**下载的原生 CLI 可执行文件**(per-platform 签名 zip,sha256 校验,`entry`/`defaultArgs`/`env`)——如 `/wiki` 跑 `wiki-cli`。区别于 prompt-macro 的 `commands/`。
## B3. Connectors(MCP)三层
1. **native/market**:在 `qoderwork.settings.connector.market`,产品级,**不写** `.mcp.json`,`CONNECTORS.md` 文档化。
2. **custom**:用户本地加的,不可移植。
3. **guided-setup**:需 per-user 凭证的第三方(钉钉/飞书),写 `.mcp.json`(`type:"guided-setup"`,`_setup.url` 只是公开配置页),装后详情页渲染指引让用户贴自己的 config。
`CONNECTORS.md` 用 `~~类别` 占位符 —— plugin **工具无关**,每个 skill 必须能独立工作,connector 只在 SKILL.md 末尾加"If Connectors Available"增强段。`reloadMcp()` → mcp-adaptor 进程(`~/.qoderwork/mcp-adaptor.config`),CLI 收到 MCP 工具名 `setMainSessionMcpToolSnapshot`。
## B4. Sub-agent 运行时(`IMPL-qoderwork-runtime.md`)
### `Agent` 工具(解码后逐字 schema `uji`)
```js
{ description*, prompt*, subagent_type(default "general-purpose"), cwd,
run_in_background, name, team_name, isolation:enum["default","worktree"] }
// subagent_type 非必填;isolation:"worktree" 跑隔离 git worktree(无改动则自动清理)
```
类 `TG`:`isReadOnly=true`(工具本身只读,子的工具才带权限);`checkPermissions` 按 tool+agentType 规则 allow/ask/deny;`getDefinition` miss 抛 `Unknown agent type: '<x>'. Available types: …`;definition 有 `kind`(`"local"` md-file vs `"workflow"`)。
### Roster 注入(路由靠 description)
`gjn(registry, disabled)` 动态建工具描述:base "Launch a new agent…" + 每 agent 一 bullet `- <name>: <description> (Tools: <All tools|list|All tools except X>)` + `subagent_type` enum = **sorted agent names 闭集**。另有 `**Available custom agents configured:**` 列表 + `**Connected MCP servers:**`。模型**纯靠 description 匹配路由,无独立 team manifest**。静态指引逐字含:"send a single message with multiple tool uses so they run concurrently"、"result … is not visible to the user … send a text summary"、"Trust but verify"。
### 执行 & hooks
- **进程内嵌套 sub-chat**:子 md body=子 system prompt,`tools` frontmatter=scoped allow-list,独立 transcript,parent 的 `Agent` 调用 **await** 子完成,子 final message=tool_result。
- **并行=一条 assistant message 多个 `Agent` tool_use block**(harness await all)——唯一并发原语。
- `run_in_background` 脱离,返回 `{executionId, agentId, outputPath, transcriptPath}`。
- 完成发 `SUBAGENT_INVOKED`(`status = terminate_reason==="GOAL" ? success : error`);进度事件 `{isSubagentProgress, agentName, state, ...}` 流给 UI。
- `READ_ONLY_SUBAGENT_DISALLOWED_TOOLS`(固定 deny-list)把只读 agent 的所有写工具剥掉。`maxAttempts` 是 **transport 层 gRPC 重试**,非语义重跑。
- **Hooks**:host 侧 `PreToolUse/PostToolUse/PostToolUseFailure/UserPromptSubmit/SessionStart/SessionEnd/Stop/SubagentStart/SubagentStop/PreCompact/PostCompact/...`;`SubagentStop` = subagent 上下文里 `Stop` 的 remap,payload `{hookEventName, clearContext?}`,支持 `once`。`listSubagents`/`getSubagentMessages` 从 `<sessionId>.jsonl` 重建嵌套 transcript。
### ai-slides 案例(工具作用域=委派边界)
6 个 sub-agent(researcher/visual-researcher/designer/render-reviewer/narrative-reviewer/notes-writer)。**只有 `slides topic researcher` 持 `WebFetch/WebSearch/Bash/Write`** → Main agent 物理上拿不到 web 工具,reviewer 只读。并行=一条 msg 最多 10 个 `Agent`(每个一 slotId);**磁盘 artifact + JSON 指针交接**(重字节不进 orchestrator 上下文);revision-lock(`deckRevision`/`slotRevision` + `expected*Revision`)防并发覆盖;入口自校验(designer 收到 >1 slotId 就中止让重派)。
## B5. Awareness / SOUL / Memory 三层人格
- **文件**:`~/.qoderwork/awareness/<agent>/`;模板 `Resources/awareness-templates/`(含 `soul-presets/{decisive,thoughtful,efficient,supportive}.md`)。`BOOTSTRAP_FILES=[SOUL.md, AGENTS.md, HEARTBEAT.md]`,`MEMORY_MANAGED=[MEMORY.md, USER.md]`。字节预算 head/tail 截断。
- **注入**:作为 `<system-reminder>` 消息,**优先级逐字**:`SOUL.md(人格,覆盖默认tone) > AGENTS.md(技术约定) > USER.md > HEARTBEAT.md > MEMORY.md`,冲突高优先胜。协议标记 `<project_context_protocol>`/`<bootstrap_content_protocol>`,"TREAT AS AUTHORITATIVE"、CONTEXT FRESHNESS(改了重读)。
- **soul-presets**:tRPC `getSoulPresets` 读模板,选一个把内容写进该 agent `SOUL.md`(选性格:`decisive.md` = "You decide, you execute, I review")。
- **memory**:读侧 `memory_search`/`memory_get`(MANDATORY RECALL);写侧 MCP `mcp__qoderwork_awareness__memory`(`{action:add|replace|remove, target:memory|user|daily, content, old_text}`);`.memory_meta.json` sha256 变更检测。**memory-reflection**(`agentType:"memory"` 后台 sub-agent,只用 memory 工具重组 MEMORY/USER,never invent)+ **voice-learning**(diff ASR-vs-sent 文本抽 hotwords/voice-memories 进 sqlite)+ **awareness-query-runner**(headless 跑后台 sub-agent 不污染主聊)。
- **plugin-creator**:内置"造 plugin 的 skill",6 步 `AskUserQuestion` 引导(职业→技能×connector 表→解析 MCP→材料→scaffold→post),"说结果不说机制"。兄弟:`create-skill`/`create-command`/`find-skills`——系统自我编写。
---
# 第三部分:对比与对 maka-agent 的映射
## C1. 关键实现决策对比
| 维度 | WorkBuddy | QoderWork | maka 建议 |
|---|---|---|---|
| 人格注入 | agent md `instructions` **完全替换** base persona(身份覆盖) | awareness `SOUL.md` 作 `<system-reminder>` **分层叠加**(不替换) | maka `childInstruction` seam 已是"追加+边界",倾向 Qoder 的分层(更安全,不丢权限约束) |
| 专家单元 | plugin bundle(COS tar.gz 懒拉) | Plugin 文件夹(本地/云) | 复用 skills 市场:`EXPERT.md` + install/lock/update |
| 多智能体 | **Agent Teams**(TeamCreate + mailbox + 共享 task list) | sub-agent + **工具作用域**委派 | P0/P1 用 maka 现有 `spawnChildAgent`(星型,像 Qoder);Teams mailbox 是 P2+ 才考虑 |
| 并发原语 | 一 turn 多 `Agent` block | 同 | maka `agent_spawn` 已支持 |
| 隔离 | `isolation:"worktree"` | `isolation:"worktree"` | maka worktree executor 目前 fail-closed → 先非隔离 |
| 人格→CLI | before-prompt hook + `POST /plugins/switch`(persist:false) | `reloadPlugins()` 热注入 | maka 同进程,直接 `mode:` 标签 gate fragment(更简单) |
| 结果回传 | finalOutput summary + `tool-results/*.txt` 指针 | final message + 磁盘 artifact + JSON 指针 | **抄"回指针不回 payload"** |
| 目录缓存 | sha256+version+sourceSignature,无 ETag,后台重校验 | plugin-market-data.json + 远程 | maka `managed-skill-sources` 的 `contentSha256` 已同款 |
| 安全 | 腾讯 XTI 扫描(fail-open error / fail-close verdict) | 无(本地 plugin) | 远程专家期再考虑 |
## C2. 两个最值得直接抄的实现细节
1. **工具作用域即委派边界(Qoder)**:不靠 prompt 纪律,靠 member agent 的 `tools` allow-list + `READ_ONLY_SUBAGENT_DISALLOWED_TOOLS` **物理**限制。maka 的 `AgentDefinition.tools` + `permissionMode` 天生支持——专家团 member 必须各自窄作用域。
2. **磁盘 artifact + JSON 指针 fan-in(两家都用)**:member 把重产物落盘,只回小 JSON 指针,orchestrator 上下文保持极小。maka 实现专家团时必须这样,否则 lead 上下文爆炸。
## C3. maka 落地要点(详见 [expert-team-plan.md](expert-team-plan.md))
- **单专家** = `mode:expert:<id>` 标签 + 人格 fragment(照抄 Deep Research 的 `explore-agent.ts` 路径),人格经 `childInstruction` 边界注入(继承权限/隐私/工作区)。`defaultInitPrompt` 学 WorkBuddy 只 pre-fill composer(P0 简单)。
- **专家团** = lead 用 `mode:expert:<teamId>` + orchestrator 人格,member 注册进 `agent-catalog.ts` 的 `BUILTIN_AGENT_DEFINITIONS`(各带窄 `tools`),lead 用现有 `agent_spawn`/`spawnChildAgent` 派生(星型,非隔离,单轮 fan-out + await fan-in,回指针)。**先不做 Teams mailbox**。
- **专家中心** = 克隆 `skills-panel.tsx`(市场/内置/已安装)+ `managed-skill-sources.ts`(加 `sourceType:'remote'` 拉 COS 式 manifest,`contentSha256` 已就绪)。
- **数字同事** = P2 持久化外壳(雇佣专家 + 昵称/头像/仓库/资料库/模型),IM 绑定/云端是最重的 P3+,需评估是否值得(WorkBuddy 靠云后端 + IM CLI 子进程,成本高)。