n2n-nexus 0.9.2 → 0.9.3

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.
@@ -0,0 +1,421 @@
1
+ # n2n-nexus 工具参考
2
+
3
+ [English version](TOOLS_REFERENCE.md)
4
+
5
+ 本文档介绍 n2n-nexus 适配器提供的 MCP 工具。工具调用会转发给运行在 `NEXUS_ENDPOINT` 的 host(`n2n-nexus-host`)。
6
+
7
+ 下面的参数表来自 `contract/tools.json`。host 通过 `GET /api/tools` 提供这份 JSON Schema,并在处理函数运行前用它校验每一次调用。参数无效的调用会被拒绝,并返回说明原因的错误(`Invalid arguments for <tool>: ...`);schema 没有声明的键会在校验前被丢弃。
8
+
9
+ ## 约定
10
+
11
+ - 每个成功的结果都返回两份:一份是 `structuredContent`(JSON 对象),另一份是放在文本块里的同一段 JSON,供只读取文本的客户端使用。返回数据的工具(`search_projects`、`get_global_topology`、`get_project`、`read_messages`、`list_events`、`get_global_strategy`、`list_global_docs`、`get_global_doc`、`list_meetings`、`get_task`、`list_tasks`、`peers`、`read`、`set_profile`)还会提供 `outputSchema`;只返回确认的工具不提供,以保持 `tools/list` 精简。结果的结构就是 `contract/tools.json` 里的 `outputSchema` 条目;host 用它们校验每一个结果。
12
+ - 调用按实例限流(默认每秒 20 次,突发 60 次;对应 host `settings.json` 中的 `rateLimit` 和 `rateBurst`)。超出限制的调用会失败并返回 "Rate limit exceeded ... retry after Ns";等待该时长后重试。
13
+ - 每个工具都有供客户端界面显示的 `title`(例如 "Delete Project")。
14
+ - 每个工具都带有 MCP annotations:`readOnlyHint`、`destructiveHint`、`idempotentHint` 和 `openWorldHint: false`(所有工具都只作用于 host)。按照 MCP 的定义,只有更新完全是追加时,工具才算非破坏性。读取类工具标为只读。`start_meeting`、`create_task`、`send_message`、`send` 和 `reply` 只追加数据,是非破坏性的;`update_task` 也标为非破坏性且幂等。`listen`、`set_profile`、`sync_project_assets`、`update_project`、`upload_project_asset`、`rename_project`、`sync_global_doc`、`update_global_strategy`、`end_meeting`、`archive_meeting`、`reopen_meeting`、`cancel_task`、`host_maintenance` 和 `host_delete_project` 会改写或删除已有状态,标为破坏性,以便客户端请求确认。`read_messages` 和 `read` 不是只读的,因为它们会推进调用方自己的未读状态;但它们是非破坏性的,因为不改变任何共享数据。
15
+ - 每个适配器都有一个实例 ID(`NEXUS_INSTANCE_ID`、`--id`,默认是 `mcp-<hostname>-<工作目录的哈希>-<IDE 名>`,其中 IDE 名是 MCP 客户端名,取自请求的 `io.modelcontextprotocol/clientInfo`,2025 代的客户端则取自 `initialize`)。读取游标以它为键,所以同一个 IDE 在同一个工作区里重启后它保持不变,而同一个工作区里的两个 IDE 仍然互相区分。适配器在每次调用中都以 `instanceId` 带上它;没有它时 `read_messages` 会失败。
16
+ - 结果里会出现两种 ID。直接消息工具(`peers`、`send`、`read`、`reply`)使用对话的会话 ID,即 `claude:<id>` 或 `codex:<id>`。`read_messages` 中的 `from`、`list_events` 中的 `actor`、会议的 `initiator` 和 `participants`,以及全局文档的 `updatedBy` 都是适配器实例 ID(`mcp-…`);它们不是会话,不能用于 `send`。
17
+ - 项目 ID 采用 `[prefix]_[name]` 格式;前缀列在[助手指南](ASSISTANT_GUIDE_zh.md#2-项目-id)中。
18
+ - 所有项目写入工具都同步执行并直接返回结果。任务工具(`create_task`、`get_task`、`list_tasks`、`update_task`、`cancel_task`)用于跟踪由助手自己管理的工作。
19
+ - 项目工具显式接收 `projectId`。
20
+ - `host_delete_project` 是破坏性操作,且不可逆。
21
+
22
+ ## 共享对象结构
23
+
24
+ ### 项目 manifest
25
+
26
+ 由 `sync_project_assets` 使用,`update_project` 使用其中一部分。
27
+
28
+ | 字段 | 类型 | MCP schema 是否要求 | 说明 |
29
+ | --- | --- | --- | --- |
30
+ | `id` | string | 是 | 项目 ID。不能通过 `update_project` 修改;请使用 `rename_project`。 |
31
+ | `name` | string | 是 | 便于阅读的项目名称。 |
32
+ | `description` | string | 是 | 项目简介。 |
33
+ | `techStack` | string[] | 是 | 项目使用的技术。 |
34
+ | `relations` | object[] | 是 | 项目之间的关系。结构:`{ targetId, type }`,其中 `type` 为 `dependency`、`parent`、`child` 或 `related`。 |
35
+ | `repositoryUrl` | string | 是 | 源代码仓库 URL。 |
36
+ | `localPath` | string | 是 | 项目在本地文件系统中的路径。 |
37
+ | `endpoints` | object[] | 是 | 结构:`{ name, url, description }`。 |
38
+ | `apiSpec` | object[] | 是 | 结构:`{ method, path, summary }`。 |
39
+ | `billing` | object | 否 | `{ plain, price }`:以自由文本表示的计费方案或条款(`plain`)和价格(`price`),两者都是字符串。 |
40
+ | `lastUpdated` | string | 否 | 保存在 manifest 中的字段。 |
41
+ | `apiDependencies` | object | 否 | 可选,项目 ID 到版本约束的映射。 |
42
+ | `gatewayCompatibility` | string | 否 | 可选,网关版本兼容性字符串。 |
43
+ | `api_versions` | object | 否 | 可选,功能级 API 版本映射。 |
44
+ | `feature_tier` | string | 否 | 可选,`standard`、`advanced` 或 `team`。 |
45
+
46
+ ## 项目资产管理
47
+
48
+ ### `sync_project_assets`
49
+
50
+ 同步完整的项目 manifest 和内部文档。
51
+
52
+ | 参数 | 类型 | 必填 | 说明 |
53
+ | --- | --- | --- | --- |
54
+ | `manifest` | 项目 manifest | 是 | 完整的 manifest 对象。见[项目 manifest](#项目-manifest)。 |
55
+ | `internalDocs` | string | 是 | Markdown 格式的实现指南或内部笔记。 |
56
+
57
+ 行为:
58
+
59
+ - 保存 manifest 和项目文档。
60
+ - 返回 `{ ok: true, projectId }`。
61
+
62
+ ### `upload_project_asset`
63
+
64
+ 把二进制或文本资产上传到项目的资产库。
65
+
66
+ | 参数 | 类型 | 必填 | 说明 |
67
+ | --- | --- | --- | --- |
68
+ | `projectId` | string | 是 | 目标项目。必须已存在。 |
69
+ | `fileName` | string | 是 | 只能是文件名。不安全的路径字符会被替换;`.` 会被拒绝。 |
70
+ | `base64Content` | string | 是 | Base64 编码的文件内容。 |
71
+
72
+ 行为:
73
+
74
+ - 把文件随项目存进 host 数据库,替换同名资产。项目改名或删除时,其资产也随之改名或删除。
75
+ - 返回 `{ ok: true, projectId, fileName }`,其中是清理后的文件名。
76
+
77
+ ### `update_project`
78
+
79
+ 修改已有项目 manifest 中的字段。
80
+
81
+ | 参数 | 类型 | 必填 | 说明 |
82
+ | --- | --- | --- | --- |
83
+ | `projectId` | string | 是 | 要更新的项目。 |
84
+ | `patch` | object | 是 | 要更新的部分 manifest 字段。未知字段和 `id` 会被拒绝。 |
85
+
86
+ 行为:
87
+
88
+ - 返回 `{ ok: true, projectId }`。
89
+ - 要修改项目 ID,请使用 `rename_project`。
90
+
91
+ ### `rename_project`
92
+
93
+ 重命名项目 ID,并级联更新关系。
94
+
95
+ | 参数 | 类型 | 必填 | 说明 |
96
+ | --- | --- | --- | --- |
97
+ | `oldId` | string | 是 | 现有项目 ID。 |
98
+ | `newId` | string | 是 | 新项目 ID。 |
99
+
100
+ 行为:
101
+
102
+ - `oldId` 不存在时失败。
103
+ - 返回 `{ ok: true, oldId, newId }`。
104
+
105
+ ### `search_projects`
106
+
107
+ 搜索项目注册表。
108
+
109
+ | 参数 | 类型 | 必填 | 默认值 | 说明 |
110
+ | --- | --- | --- | --- | --- |
111
+ | `query` | string | 是 | | 项目 ID、名称或描述中的子串,不区分大小写。 |
112
+ | `limit` | integer | 否 | `10` | 最多返回的项目数(1–200)。 |
113
+
114
+ ### `get_global_topology`
115
+
116
+ 读取项目拓扑。
117
+
118
+ | 参数 | 类型 | 必填 | 说明 |
119
+ | --- | --- | --- | --- |
120
+ | `projectId` | string | 否 | 提供时,返回该项目及它直接或间接依赖的项目(只看出向关系);未知的 projectId 会报错。不提供时,返回所有项目(id、名称、摘要、最后活跃时间)以及项目总数和关系总数。 |
121
+
122
+ 行为:
123
+
124
+ - 提供了 `projectId` 但项目不存在时失败。
125
+
126
+ ### `get_project`
127
+
128
+ 读取单个项目的 manifest 和内部文档。
129
+
130
+ | 参数 | 类型 | 必填 | 默认值 | 说明 |
131
+ | --- | --- | --- | --- | --- |
132
+ | `projectId` | string | 是 | | 要读取的项目。 |
133
+ | `includeDocs` | boolean | 否 | `true` | 设为 `false` 时不返回内部文档。 |
134
+
135
+ 行为:
136
+
137
+ - 返回 `{ manifest, internalDocs? }`。
138
+ - 项目不存在时失败。
139
+
140
+ ## 消息与协作
141
+
142
+ ### 对话之间的直接消息
143
+
144
+ 每个 Claude Code 和 Codex 对话都是一个会话,ID 为 `claude:<会话 ID>` 或 `codex:<会话 ID>`,取自客户端。`n2n-nexus install <claude|codex>` 写入的 hooks 会创建会话并保持其状态最新;子代理与其父对话共用同一个会话。恢复对话时沿用原来的会话。在同一个客户端里开始的新对话(例如 Claude Code 中执行 `/clear` 之后)是一个新会话;Claude Code 还会结束旧会话,旧会话随之变为离线。
145
+
146
+ 下面六个工具从 MCP 请求的 `_meta` 识别调用方,从不使用参数:Claude Code 带上 `claudecode/toolUseId`,它由 PreToolUse hook 在调用前刚刚绑定到对话;Codex 带上 `sessionId`。其他客户端、没有 hooks 的对话,或绑定已超过五分钟的调用会收到一条错误,说明:直接消息需要装有 n2n-nexus hooks 的 Claude Code 或 Codex(`n2n-nexus install <claude|codex>`);hooks 只对安装之后开始的对话生效;MCP 服务器必须以 `n2n-nexus` 为名注册;PreToolUse 绑定过期时再调用一次工具即可解决。其他所有工具都不关心调用方。
147
+
148
+ 这六个工具是对话之间的直接消息。全局聊天和会议是另外的东西:`send_message` 发到那里,`read_messages` 从那里读取;两者都不会发到或读取对话的直接消息。
149
+
150
+ | 工具 | 参数 | 结果与行为 |
151
+ | --- | --- | --- |
152
+ | `peers` | `includeOffline?: boolean = false` | `{ self: Profile, peers: Profile[] }`;其他未离线的会话,最近活跃的在前。带 `includeOffline` 时,还包括过去 24 小时内活跃过的离线会话。 |
153
+ | `send` | `to: string`、`text: string`(1–32000 个字符)、`notifyWhenIdle?: boolean = false` | `{ messageId, to: { id, name, status } }`。`to` 是会话 ID(任何状态)或某个未离线会话的名称;不能给自己发消息。离线的收件方在恢复时收到消息。带 `notifyWhenIdle` 时,收件方下一次结束一轮、开始待命或离线时,你会收到一次通知(订阅 24 小时后失效)。 |
154
+ | `read` | `count?: integer = 10`(1–50) | `{ messages: [{ messageId, from: { id, name }, replyTo, text, createdAt }], remaining }`;未读消息,最早的在前,读取后标为已读。 |
155
+ | `reply` | `messageId: string`、`text: string`(1–32000 个字符) | 结果与 `send` 相同。该消息必须是发给你的;回复发给它的发送方,`replyTo` 设为该消息。 |
156
+ | `listen` | `on: boolean` | `{ listening }`。开启期间,对话每结束一轮,其 Stop hook 会等待最多 590 秒,有消息或通知到达时让对话继续。在 Claude Code 中按 Esc 会结束一次等待。 |
157
+ | `set_profile` | `name?: string`(1–48 个 `A–Z a–z 0–9 . _ @ # -` 中的字符)、`note?: string`(≤ 200 个字符);至少提供一个 | `{ profile }`。名称在未离线的会话中唯一。 |
158
+
159
+ `Profile` 包含 `id`、`name`、`client`(`claude` 或 `codex`)、`cwd`、`note`、`status` 和 `lastActiveAt`。会话的初始名称为 `<client>@<工作目录名>`,该名称已被某个未离线会话占用时加上 `#2`、`#3`、…。`status` 为 `working`(用户发送了提示词或有工具在运行)、`idle`(本轮已结束;有后台等待消息的会话改为显示 `listening`)、`listening`(在 listen 模式下等待)或 `offline`(对话已结束)。客户端不一定会报告对话结束,所以 `idle` 或 `working` 的会话 30 分钟没有任何活动也会变为 `offline`;它的下一个事件会让它恢复。只有 `listening` 的会话会立即回应;`idle` 和 `working` 的会话要等它的用户下次发送提示词或它下次调用工具时才会看到消息。
160
+
161
+ 送达。收件方的 hooks 会提醒新消息;通知只带发送方、时间和第一行(最多 100 个字符),正文通过 `read` 以工具输出的形式送达:
162
+
163
+ | 客户端事件 | 收件方看到的内容 |
164
+ | --- | --- |
165
+ | 对话开始 | 自己的名称和 ID、未离线的其他会话(最多列出五个)、其中哪些能立即回应,以及 `peers`、`send` 和 `read` 的用法。 |
166
+ | 提交提示词 | 未读消息数、最多列出五条,以及待处理的通知。 |
167
+ | 每次工具调用后 | 只有尚未提醒过的消息和通知。 |
168
+ | 本轮即将结束 | 有未读内容时,本轮带着提醒再继续一次。 |
169
+ | 待命中 | 一有新内容到达就结束等待,对话带着它继续。 |
170
+ | 空闲(本轮已结束) | Stop hook 启动的后台等待(`n2n-nexus hook <client> --wait`,最长一小时)带着提醒开启新的一轮:Claude Code 通过 `asyncRewake` hook(退出码 2),Codex 通过 `codex queue --thread <会话 ID>`(`NEXUS_CODEX_COMMAND` 可替换 `codex` 命令)。在无人值守的 Claude 会话(`claude -p`、`CLAUDE_CODE_SESSION_ATTENDED=0`)中,该 hook 立即返回,因为 `claude -p` 会等它结束才退出。等待期间会话显示为 `listening`;对话中的任何新活动都会结束等待。Codex 只会为运行中的 Codex 应用里已加载的对话启动排队的一轮,且 Codex 退出时等待结束。 |
171
+ | 自动轮次上限 | 被叫醒、待命中的 Stop,以及因消息而不结束的 Stop,各算一次自动轮次;提醒中会写 `Automatic turn n of N`。设置了 `maxAutoTurns` 时(host `settings.json`;默认 0,即不限制,提醒中也不写计数),从用户上次输入以来达到这个次数后,消息仍会保存,但不再叫醒或拦住对话;用户下次输入时提醒这些消息,并重新开始计数。叫醒后一分钟内的提示词视为被叫醒的那一轮开始,不清零计数。 |
172
+
173
+ 未读消息 24 小时后过期,发送方随后会收到通知。通知也会报告 `notifyWhenIdle` 的结果。
174
+
175
+ HTTP 客户端:hooks 调用 `POST /api/hook`,请求体为 `{ client: "claude" | "codex", input }`,其中 `input` 包含 hook 标准输入中的字段 `hook_event_name`、`session_id`、`cwd`、`stop_hook_active`、`tool_use_id`、`tool_name`、`source` 和 `reason`;响应为 `{ output }`,不为 null 时由 hook 打印。工具调用在 `POST /api/tools/call` 中用与 `tool`、`args`、`instanceId` 并列的 `caller` 指明会话:`{ client: "claude", toolUseId }` 或 `{ client: "codex", sessionId }`。它们只在可信本地 host 范围内标识对话,不是凭证:同一系统用户的任何进程都能发送它们(见 [SECURITY_zh.md](SECURITY_zh.md) 中的本地信任模型)。
176
+
177
+ ### `send_message`
178
+
179
+ 发到某个会议或全局聊天。要给某一个对话发消息,请使用 `send`;`send_message` 不会发到对话的直接消息。
180
+
181
+ | 参数 | 类型 | 必填 | 说明 |
182
+ | --- | --- | --- | --- |
183
+ | `message` | string | 是 | 消息正文。 |
184
+ | `category` | string | 否 | `PROPOSAL`、`DECISION`、`UPDATE`、`CHAT` 或 `MEETING_START`(保留值;host 从不写入)之一。不传时消息没有分类。 |
185
+ | `meetingId` | string | 否 | 目标会议。必须处于活跃状态。 |
186
+
187
+ 行为:
188
+
189
+ - 提供 `meetingId` 时,消息发到该会议。
190
+ - 否则,如果有活跃会议,消息发到该会议。
191
+ - 否则写入全局聊天。
192
+ - 会议中的 `DECISION` 消息还会记入该会议的决策(`list_meetings` 中的 `decisionCount`)。
193
+ - 随消息保存的发送方是调用方的适配器实例 ID。
194
+ - 结果:`{ ok: true, sentTo: "meeting" | "global", meetingId?, messageId?, message }`;全局聊天的消息 ID 是数字。
195
+
196
+ ### `read_messages`
197
+
198
+ 读取全局聊天或会议中的未读消息。发给你的对话的直接消息用 `read` 读取。
199
+
200
+ | 参数 | 类型 | 必填 | 默认值 | 说明 |
201
+ | --- | --- | --- | --- | --- |
202
+ | `count` | integer | 否 | `10` | 要读取的消息数(1–500)。 |
203
+ | `meetingId` | string | 否 | | 提供时从该会议读取。否则从全局日志读取。 |
204
+
205
+ 行为:
206
+
207
+ - 全局和会议的读取都按适配器实例增量进行:每次调用只返回尚未返回给该实例的消息,最早的在前,并推进游标。
208
+ - 每条消息的 `from` 是发送方的适配器实例 ID,不是会话 ID:不能对它使用 `send`。
209
+ - 需要调用方实例:没有 `instanceId` 的调用会失败,并返回 `read_messages needs the instanceId field of the POST /api/tools/call body (the n2n-nexus MCP adapter sends it automatically); unread cursors are kept per instance.` MCP 适配器总会带上它。
210
+
211
+ ### `list_events`
212
+
213
+ 读取结构化活动日志。
214
+
215
+ | 参数 | 类型 | 必填 | 默认值 | 说明 |
216
+ | --- | --- | --- | --- | --- |
217
+ | `limit` | integer | 否 | `20` | 最多返回的事件数,最新的在前(1–500)。 |
218
+ | `action` | string | 否 | | 完整的 action(`meeting.end`)或前缀(`project`、`meeting`)。 |
219
+
220
+ 行为:
221
+
222
+ - 通过 host 工具产生的每一次状态变更都会被记录:`project.sync`、`project.update`、`project.rename`、`project.delete`、`project.asset`、`doc.sync`、`strategy.update`、`meeting.start`、`meeting.end`、`meeting.archive`、`meeting.reopen`、`maintenance.prune`、`maintenance.clear`。
223
+ - 每个事件带有 `timestamp`、`actor`(适配器实例 ID,不是会话 ID)、`action`,以及可选的 `target` 和 `detail`。
224
+
225
+ ### `update_global_strategy`
226
+
227
+ 覆盖写入主战略文档。
228
+
229
+ | 参数 | 类型 | 必填 | 说明 |
230
+ | --- | --- | --- | --- |
231
+ | `content` | string | 是 | 全局战略文档的完整 Markdown 内容。 |
232
+
233
+ 行为:
234
+
235
+ - 替换已保存的战略文档。用 `get_global_strategy` 读回。
236
+
237
+ ### `get_global_strategy`
238
+
239
+ 读取主战略文档。没有参数。
240
+
241
+ 行为:
242
+
243
+ - 返回 `{ content }`。
244
+
245
+ ### `list_global_docs`
246
+
247
+ 列出全局共享文档。没有参数。
248
+
249
+ 行为:
250
+
251
+ - 返回 `{ count, docs: [{ docId, title, lastUpdated, updatedBy }] }`,最近更新的在前。
252
+
253
+ ### `get_global_doc`
254
+
255
+ 读取一份全局共享文档。
256
+
257
+ | 参数 | 类型 | 必填 | 说明 |
258
+ | --- | --- | --- | --- |
259
+ | `docId` | string | 是 | 来自 `list_global_docs` 的文档 ID。 |
260
+
261
+ 行为:
262
+
263
+ - 返回 `{ docId, title, lastUpdated, updatedBy, content }`。
264
+ - 文档不存在时失败。
265
+
266
+ ### `sync_global_doc`
267
+
268
+ 创建或更新一份全局共享文档。
269
+
270
+ | 参数 | 类型 | 必填 | 说明 |
271
+ | --- | --- | --- | --- |
272
+ | `docId` | string | 是 | 固定不变的文档 ID。 |
273
+ | `title` | string | 是 | 便于阅读的文档标题。 |
274
+ | `content` | string | 是 | Markdown 内容。 |
275
+
276
+ ## 会议管理
277
+
278
+ ### `list_meetings`
279
+
280
+ 列出会议,最新的在前。
281
+
282
+ | 参数 | 类型 | 必填 | 默认值 | 说明 |
283
+ | --- | --- | --- | --- | --- |
284
+ | `status` | string | 否 | | `active`、`closed` 或 `archived`。 |
285
+ | `limit` | integer | 否 | `20` | 最多返回的会议数(1–200)。 |
286
+
287
+ 行为:
288
+
289
+ - 返回 `{ count, activeMeetingId, meetings: [{ id, topic, status, initiator, startTime, endTime?, participants, messageCount, decisionCount, summary? }] }`。
290
+ - 用 `read_messages(meetingId)` 读取会议的消息。
291
+
292
+ ### `start_meeting`
293
+
294
+ 开启一个新会议。
295
+
296
+ | 参数 | 类型 | 必填 | 说明 |
297
+ | --- | --- | --- | --- |
298
+ | `topic` | string | 是 | 会议主题。用于创建会议记录。 |
299
+
300
+ 行为:
301
+
302
+ - 调用方的适配器实例成为会议的 `initiator`。
303
+ - 新会议成为所有人的默认会议:不传 `meetingId` 的 `send_message` 和 `end_meeting` 都作用于它,直到它结束(之后是仍处于活跃状态、最近被激活的会议,如果有的话)。`reopen_meeting` 以同样的方式让重新开启的会议成为默认会议。
304
+
305
+ ### `end_meeting`
306
+
307
+ 关闭并锁定会议。
308
+
309
+ | 参数 | 类型 | 必填 | 说明 |
310
+ | --- | --- | --- | --- |
311
+ | `meetingId` | string | 否 | 要关闭的会议。不传时使用活跃会议。 |
312
+ | `summary` | string | 否 | 可选的结束总结。 |
313
+
314
+ ### `archive_meeting`
315
+
316
+ 存档已关闭的会议。
317
+
318
+ | 参数 | 类型 | 必填 | 说明 |
319
+ | --- | --- | --- | --- |
320
+ | `meetingId` | string | 是 | 要存档的会议。 |
321
+
322
+ ### `reopen_meeting`
323
+
324
+ 重新激活已关闭或已存档的会议。
325
+
326
+ | 参数 | 类型 | 必填 | 说明 |
327
+ | --- | --- | --- | --- |
328
+ | `meetingId` | string | 是 | 要重新开启的会议。 |
329
+
330
+ 行为:
331
+
332
+ - 任何适配器实例都能结束、存档或重新开启会议,不只是它的 `initiator`。
333
+
334
+ ## 任务管理
335
+
336
+ ### `create_task`
337
+
338
+ 创建一条任务记录,由你自己用 `update_task` 跟踪和更新;host 不执行任务。
339
+
340
+ | 参数 | 类型 | 必填 | 说明 |
341
+ | --- | --- | --- | --- |
342
+ | `source_meeting_id` | string | 否 | 把任务关联到某个会议,便于追溯。该会议必须存在。 |
343
+ | `metadata` | object | 否 | 任意元数据对象。 |
344
+ | `ttl` | integer | 否 | 存活时间,单位毫秒。超过 TTL 的待处理或运行中任务会在每小时一次的维护中被标为 `failed`(`TTL expired`);结束的任务 7 天后清除。 |
345
+
346
+ 行为:
347
+
348
+ - 返回 `{ task_id, status, message, task }`。
349
+
350
+ ### `get_task`
351
+
352
+ 读取任务状态和结果。
353
+
354
+ | 参数 | 类型 | 必填 | 说明 |
355
+ | --- | --- | --- | --- |
356
+ | `taskId` | string | 是 | `create_task` 返回的任务 ID。 |
357
+
358
+ ### `list_tasks`
359
+
360
+ 列出任务,可按状态筛选。
361
+
362
+ | 参数 | 类型 | 必填 | 默认值 | 说明 |
363
+ | --- | --- | --- | --- | --- |
364
+ | `status` | string | 否 | | `pending`、`running`、`completed`、`failed` 或 `cancelled` 之一。 |
365
+ | `limit` | integer | 否 | `50` | 最多返回的任务数(1–500)。 |
366
+
367
+ ### `update_task`
368
+
369
+ 更新你创建的任务。
370
+
371
+ | 参数 | 类型 | 必填 | 说明 |
372
+ | --- | --- | --- | --- |
373
+ | `taskId` | string | 是 | 要更新的任务。 |
374
+ | `status` | string | 否 | `pending`、`running`、`completed`、`failed` 或 `cancelled` 之一。 |
375
+ | `progress` | number | 否 | 进度,从 `0` 到 `1`。 |
376
+ | `result_uri` | string | 否 | 结果所在位置。 |
377
+ | `error_message` | string | 否 | 任务失败的原因。 |
378
+ | `metadata` | object | 否 | 替换任务的整个元数据对象;未提供的键不会保留。 |
379
+
380
+ 行为:
381
+
382
+ - 只修改提供的字段和任务的更新时间。
383
+ - 返回任务:`{ id, status, progress, source_meeting_id, metadata, result_uri, error_message, created_at, updated_at, ttl }`。
384
+ - 任务不存在时失败。
385
+
386
+ ### `cancel_task`
387
+
388
+ 取消待处理或运行中的任务。
389
+
390
+ | 参数 | 类型 | 必填 | 说明 |
391
+ | --- | --- | --- | --- |
392
+ | `taskId` | string | 是 | 要取消的任务。 |
393
+
394
+ ## 维护
395
+
396
+ ### `host_maintenance`
397
+
398
+ 修剪或清空全局聊天流。
399
+
400
+ | 参数 | 类型 | 必填 | 说明 |
401
+ | --- | --- | --- | --- |
402
+ | `action` | string | 是 | `prune` 或 `clear`。 |
403
+ | `count` | integer | `prune` 时必填 | 要删除的最旧消息数;`prune` 时至少为 `1`。`clear` 会忽略它。 |
404
+
405
+ 行为:
406
+
407
+ - 返回 `{ ok, removed, remaining }`。
408
+
409
+ ### `host_delete_project`
410
+
411
+ 永久删除项目及其资产。
412
+
413
+ | 参数 | 类型 | 必填 | 说明 |
414
+ | --- | --- | --- | --- |
415
+ | `projectId` | string | 是 | 要删除的项目。 |
416
+
417
+ 行为:
418
+
419
+ - 项目不存在时失败。
420
+ - 返回 `{ ok: true, projectId }`。
421
+ - 此操作不可逆。
@@ -0,0 +1,139 @@
1
+ # n2n-nexus user guide
2
+
3
+ [中文版](USER_GUIDE_zh.md)
4
+
5
+ This guide covers using n2n-nexus once it is installed: the tray, which conversations can message each other, checking that it works, troubleshooting, and the reference of commands and settings. To install it, see the [Installation guide](INSTALL.md); for how the pieces work inside, see [Architecture](ARCHITECTURE.md); for the tools, see the [Tools reference](TOOLS_REFERENCE.md).
6
+
7
+ ## 1. The tray
8
+
9
+ The tray menu shows the address the host listens on and the number of online sessions, opens the log and data folders, switches LAN access on and off, restarts the host and turns **Start at login** on or off (`n2n-nexus-host autostart on|off` does the same). The menu is in Chinese on a Chinese system and in English otherwise.
10
+
11
+ - **Allow LAN access** makes this host reachable from other machines: [Installation guide](INSTALL.md#6-several-machines-and-environments).
12
+ - **Restart** applies an edited `settings.json`. While the background service runs the host, the tray only controls it: **Restart** restarts the service's host.
13
+
14
+ ## 2. Claude desktop app
15
+
16
+ The Claude desktop app has two kinds of conversation:
17
+
18
+ - **Code** tab: this is Claude Code. It uses the same `~/.claude/settings.json` hooks and MCP servers as the `claude` CLI, so after `n2n-nexus install claude` it can do everything, direct messages included.
19
+ - **Chat**: ordinary chat conversations. They can use MCP servers added to the desktop app's `claude_desktop_config.json`, but they run no hooks. There n2n-nexus offers the shared tools (projects, documents, meetings, tasks, global chat) but not direct messages, because nothing tells the host which chat is which.
20
+
21
+ Use the Code tab for sessions that should talk to each other.
22
+
23
+ ## 3. Direct messages between conversations
24
+
25
+ Each conversation appears in `peers`. A new direct message is announced to the recipient automatically: when the user sends a prompt, after each tool call, and once before the turn ends. The recipient reads the text with `read`. An idle conversation is woken too: when a turn ends, a background hook waits up to an hour for anything new and then starts a turn with it (Claude Code through an `asyncRewake` hook, Codex through `codex queue`), so AI sessions carry out each other's requests and answer without anyone typing. An unattended `claude -p` run is not kept waiting: the hook returns at once there. A Codex conversation is woken only while it is loaded in the running Codex app, and not again after Codex restarts until it ends a turn; see [Architecture](ARCHITECTURE.md#sessions-presence-and-waking-idle-conversations) for the limits. With `listen` on, a conversation that finished its turn keeps waiting for up to about 10 minutes and continues when a message arrives; while it waits, input you type is queued until you press Esc.
26
+
27
+ ## 4. Check that it works
28
+
29
+ - `n2n-nexus doctor` checks the installed commands and the host: [Installation guide](INSTALL.md#7-check-the-installation).
30
+ - In a conversation, ask the AI to call `peers`: it lists the other sessions that are online.
31
+ - The tray menu shows how many sessions are online.
32
+
33
+ ## 5. Troubleshooting
34
+
35
+ | Symptom | Cause and fix |
36
+ |---|---|
37
+ | Tool calls say n2n-nexus-host is not available | The host is not running or not reachable: start it ([Installation guide, step 2](INSTALL.md#2-start-the-host)), or for another machine turn LAN access on ([step 6](INSTALL.md#6-several-machines-and-environments)). |
38
+ | Codex sessions never appear in `peers` | The Codex hooks are not trusted yet ([Installation guide, step 4](INSTALL.md#4-turn-on-the-codex-hooks-one-time-required)). |
39
+ | A conversation gets message notices but has no `read` / `reply` tools | The hooks are installed but the MCP server is not registered for this configuration. Common with several Claude config directories (`CLAUDE_CONFIG_DIR`, account switchers): run `CLAUDE_CONFIG_DIR=<that dir> n2n-nexus install claude`, then start a new conversation. |
40
+ | "This call carries no agent session" | The conversation started before the hooks were installed (start a new one), the MCP server is not named `n2n-nexus`, or an identity expired (call the tool again). In a Claude desktop chat this is expected (section 2). |
41
+ | `claude -p` scripts | They are not held open by the background wait; nothing to do. |
42
+
43
+ ## 6. Reference
44
+
45
+ ### n2n-nexus-host commands
46
+
47
+ ```bash
48
+ # Tray app (default)
49
+ n2n-nexus-host
50
+
51
+ # Run in the foreground without a tray; flags override settings.json (--port 0 picks a free port)
52
+ n2n-nexus-host serve [--host 127.0.0.1] [--port 5688] [--root <dir>]
53
+
54
+ # Background service that starts at boot (elevated terminal on Windows, sudo on macOS / Linux).
55
+ # install refuses while the tray runs the host (quit it first; reopened, it controls the service),
56
+ # writes --host / --port to settings.json, stops a host running for the data directory,
57
+ # registers and starts the service, and reports what answers on the port.
58
+ # uninstall removes the service and stops its host; a tray or a foreground serve keeps running.
59
+ n2n-nexus-host service install [--host <addr>] [--port <port>] [--root <dir>]
60
+ n2n-nexus-host service uninstall [--root <dir>]
61
+ n2n-nexus-host service status [--host <addr>] [--port <port>] [--root <dir>]
62
+
63
+ # Start the tray at login, or stop doing so
64
+ n2n-nexus-host autostart on|off
65
+
66
+ n2n-nexus-host version
67
+ ```
68
+
69
+ Under `sudo`, the service uses the default data and log directories of the user who ran `sudo`, unless `--root` names another data directory. Only one host runs per data directory: a second one exits with "another n2n-nexus-host is running".
70
+
71
+ ### n2n-nexus commands
72
+
73
+ ```bash
74
+ # Start the MCP adapter (launched by the IDE)
75
+ NEXUS_ENDPOINT=http://127.0.0.1:5688 n2n-nexus mcp [--id <instance id>]
76
+
77
+ # Install / remove the hooks and MCP server for Claude Code or Codex
78
+ n2n-nexus install <claude|codex> [--endpoint <url>] [--node <path>]
79
+ n2n-nexus uninstall <claude|codex>
80
+
81
+ # Check that the installed hook and MCP commands still run and that the host answers
82
+ # with the client's contract version (exit 1 when not)
83
+ n2n-nexus doctor [claude|codex]
84
+
85
+ # Hook entry point (written into the client configuration by install)
86
+ n2n-nexus hook <claude|codex> [--endpoint <url>] [--wait]
87
+ ```
88
+
89
+ ### Environment variables
90
+
91
+ Client (`n2n-nexus`):
92
+
93
+ | Variable | Description | Default |
94
+ | --- | --- | --- |
95
+ | `NEXUS_ENDPOINT` | Host URL for the MCP adapter, the hooks and `doctor`, or `discover` to find one on the LAN | `http://127.0.0.1:5688` |
96
+ | `NEXUS_DISCOVERY_PORT` | UDP port the client queries with `discover` | `5688` |
97
+ | `NEXUS_INSTANCE_ID` | Override the MCP instance ID (read cursors are keyed on it) | `mcp-<hostname>-<hash of working directory>-<IDE name>` |
98
+ | `NEXUS_CODEX_COMMAND` | Command the Codex background wait runs as `<command> queue ...` | `codex` |
99
+
100
+ Host (`n2n-nexus-host`): only `NEXUS_ROOT`, the data directory (`--root` overrides it). Every other host setting is in `settings.json`, which the tray, the service and the command line share.
101
+
102
+ ### settings.json
103
+
104
+ Read when the host starts; command-line flags override it. A missing file or field uses the default.
105
+
106
+ | Field | Description | Default |
107
+ | --- | --- | --- |
108
+ | `host` | Address to listen on (an IPv4 address listens on IPv4 only, an IPv6 address on IPv6 only); `0.0.0.0` makes the host reachable from the LAN | `"127.0.0.1"` |
109
+ | `port` | TCP port | `5688` |
110
+ | `discoveryPort` | UDP port of LAN discovery, answered only when `host` is not a loopback address | `5688` |
111
+ | `allowedHosts` | Extra DNS names accepted in the `Host` header (IP literals, `localhost` and `host.docker.internal` are always accepted) | `[]` |
112
+ | `rateLimit` | Tool calls per second per instance; each client address gets 5x. Hooks have their own budget at the same rate per conversation and 5x per client address. `0` disables rate limiting | `20` |
113
+ | `rateBurst` | Calls an instance may make at once before the per-second limit applies (minimum 1) | `60` |
114
+ | `maxAutoTurns` | Automatic turns a conversation may take between its user's prompts (wakes, listening and Stops held open for messages); past it, messages wait until the user prompts. `0` disables the limit | `0` |
115
+
116
+ After editing the file, restart the host (tray **Restart**, or restart `serve` or the service).
117
+
118
+ ### Data and logs
119
+
120
+ The host keeps all coordination data in one SQLite database in its data directory:
121
+
122
+ | Platform | Data directory | Log directory |
123
+ | --- | --- | --- |
124
+ | Windows | `%LOCALAPPDATA%\n2n-nexus` | `%LOCALAPPDATA%\n2n-nexus\logs` |
125
+ | macOS | `~/Library/Application Support/n2n-nexus` | `~/Library/Logs/n2n-nexus` |
126
+ | Linux | `$XDG_DATA_HOME/n2n-nexus` (default `~/.local/share/n2n-nexus`) | `$XDG_STATE_HOME/n2n-nexus` (default `~/.local/state/n2n-nexus`) |
127
+
128
+ Override the data directory with `--root <path>` or `NEXUS_ROOT`.
129
+
130
+ ```text
131
+ <data directory>/
132
+ ├── nexus.db # projects, assets, docs, meetings, global chat, events, tasks, read cursors, conversations, direct messages
133
+ ├── settings.json # host settings (see above)
134
+ └── host.lock # one host per data directory
135
+ ```
136
+
137
+ The background service, and the tray while it runs the host itself, log to `host.log` in the log directory (10 MB per file, 3 old files kept); the tray's own lines go to `tray.log` there; `n2n-nexus-host serve` logs to standard error. What the host deletes and when: [Architecture](ARCHITECTURE.md#maintenance-and-retention).
138
+
139
+ Data of n2n-nexus 0.x (`~/.n2n-nexus`) is not imported: the host does not read it and leaves it in place.