u-foo 3.0.17 → 3.0.19
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/OPTIONAL_SKILLS/ufoo-bus-poll/SKILL.md +24 -11
- package/README.md +53 -29
- package/README.zh-CN.md +45 -31
- package/SKILLS/ufoo/SKILL.md +22 -10
- package/SKILLS/ufoo-bus/SKILL.md +29 -15
- package/bin/ufoo.js +19 -5
- package/package.json +2 -1
- package/src/agents/prompts/groupBootstrap.js +1 -1
- package/src/agents/prompts/native/ufoo.js +1 -1
- package/src/app/chat/commandExecutor.js +11 -5
- package/src/app/cli/run.js +2 -3
- package/src/code/UCODE_PROMPT.md +1 -1
- package/src/config.js +10 -0
- package/src/coordination/bus/subscriber.js +32 -0
- package/src/coordination/state/paths.js +4 -0
- package/src/runtime/contracts/eventContract.js +5 -0
- package/src/runtime/daemon/controlPlaneService.js +130 -12
- package/src/runtime/daemon/index.js +65 -0
- package/src/runtime/daemon/mcpConfigure.js +175 -0
- package/src/runtime/daemon/mcpControl.js +123 -0
- package/src/runtime/daemon/mcpHttpServer.js +412 -0
- package/src/runtime/daemon/mcpServer.js +94 -103
- package/src/runtime/daemon/mcpStdioProxy.js +247 -0
- package/src/runtime/daemon/projectRuntimeControlPlane.js +115 -0
- package/src/runtime/daemon/projectRuntimeGateway.js +358 -0
|
@@ -26,13 +26,16 @@ the host's maximum pending-call window ends.
|
|
|
26
26
|
|
|
27
27
|
## Attach the subscriber
|
|
28
28
|
|
|
29
|
-
1. Inspect
|
|
29
|
+
1. Inspect the host Agent's inherited `UFOO_SUBSCRIBER_ID` before starting or
|
|
30
|
+
mutating any helper terminal. If it is nonempty, stop this workflow: the
|
|
30
31
|
ufoo wrapper already registered the Agent and direct injection is its receive
|
|
31
32
|
path. Do not call MCP `register_agent` or arm a poll.
|
|
32
33
|
2. When the variable is absent, reuse the exact subscriber already returned to
|
|
33
|
-
this session by MCP `register_agent
|
|
34
|
-
call
|
|
35
|
-
|
|
34
|
+
this session by MCP `register_agent` together with its `agent_handle`, or
|
|
35
|
+
call `register_agent` once. Pass a stable `client_instance_id` when the host
|
|
36
|
+
exposes one. Do not call bare `ufoo bus join` or borrow another subscriber.
|
|
37
|
+
Keep the returned pair as the external Agent's identity. Never expose the
|
|
38
|
+
handle in messages, reports, logs, or the Cursor listener terminal.
|
|
36
39
|
3. Select the receive mechanism from the host App's actual wake capability,
|
|
37
40
|
never from Agent type:
|
|
38
41
|
|
|
@@ -44,8 +47,9 @@ the host's maximum pending-call window ends.
|
|
|
44
47
|
|
|
45
48
|
Agent type and subscriber prefix are not capability signals. An externally
|
|
46
49
|
hosted MCP subscriber named `codex:*`, `claude-code:*`, or any other type is
|
|
47
|
-
eligible because the
|
|
48
|
-
delivery mode.
|
|
50
|
+
eligible because the Agent's inherited environment—not its name—selected this
|
|
51
|
+
delivery mode. A variable exported later inside a dedicated helper terminal
|
|
52
|
+
does not reclassify the host Agent as wrapper-managed.
|
|
49
53
|
|
|
50
54
|
## Use Codex App pending MCP wait
|
|
51
55
|
|
|
@@ -57,6 +61,7 @@ prints stdout. Keep the wait inside one foreground MCP tool call instead:
|
|
|
57
61
|
|
|
58
62
|
- `project_root`: the registered project root
|
|
59
63
|
- `subscriber`: the caller-owned MCP subscriber
|
|
64
|
+
- `agent_handle`: the opaque handle returned with that registration
|
|
60
65
|
- `after_seq`: `0` for the first wait, then the last returned `last_seq`
|
|
61
66
|
- `timeout_seconds`: `600`
|
|
62
67
|
2. Leave that tool call pending. Do not background it and do not start
|
|
@@ -64,7 +69,7 @@ prints stdout. Keep the wait inside one foreground MCP tool call instead:
|
|
|
64
69
|
not invoke the model or consume model tokens.
|
|
65
70
|
3. If it returns `status: "message"`, handle every returned message, then call
|
|
66
71
|
MCP `ack_bus` with `through_seq: <last_seq>`. This preserves messages that
|
|
67
|
-
arrived after the returned batch.
|
|
72
|
+
arrived after the returned batch. Include the same `agent_handle`.
|
|
68
73
|
4. If it returns `status: "timeout"`, no message was received. If monitoring is
|
|
69
74
|
still required, immediately call `wait_for_message` again with the same
|
|
70
75
|
`after_seq`. The timeout return is the only periodic model wake.
|
|
@@ -80,14 +85,21 @@ Never run two pending waits for the same subscriber.
|
|
|
80
85
|
1. Check for an existing `ufoo bus poll ... --follow` process for the literal
|
|
81
86
|
MCP subscriber. Keep one healthy process; the CLI rejects a duplicate
|
|
82
87
|
receive lease.
|
|
83
|
-
2. Start this command through Cursor's monitored background shell
|
|
88
|
+
2. Start this command through Cursor's monitored background shell. Bind the
|
|
89
|
+
MCP-returned subscriber inside that dedicated terminal, then launch the
|
|
90
|
+
resident poll:
|
|
84
91
|
|
|
85
92
|
```bash
|
|
86
|
-
|
|
93
|
+
export UFOO_SUBSCRIBER_ID="<mcp-subscriber-id>"
|
|
94
|
+
exec ufoo bus poll "$UFOO_SUBSCRIBER_ID" --follow --interval 30
|
|
87
95
|
```
|
|
88
96
|
|
|
89
97
|
Use `30` seconds by default; accept `15`–`120` when the user requests a
|
|
90
98
|
different latency. Do not use `nohup`, shell `&`, or an OS-detached daemon.
|
|
99
|
+
This terminal-local export gives its CLI commands a stable sender/subscriber
|
|
100
|
+
identity. It must happen only after the host Agent was classified as
|
|
101
|
+
external and registered through MCP; it is not evidence of wrapper launch
|
|
102
|
+
or direct-injection support.
|
|
91
103
|
3. Start the monitored task with
|
|
92
104
|
`block_until_ms: 0`.
|
|
93
105
|
4. Configure `notify_on_output` with:
|
|
@@ -118,6 +130,7 @@ For Cursor, handle every `[ufoo]<from:...>` event in the emitted batch.
|
|
|
118
130
|
2. Acknowledge only after handling:
|
|
119
131
|
|
|
120
132
|
- Codex App: MCP `ack_bus` with the returned `last_seq` as `through_seq`.
|
|
133
|
+
Include the caller-owned `agent_handle`.
|
|
121
134
|
- Cursor: run the exact command printed by the stream:
|
|
122
135
|
|
|
123
136
|
```bash
|
|
@@ -127,8 +140,8 @@ For Cursor, handle every `[ufoo]<from:...>` event in the emitted batch.
|
|
|
127
140
|
Preserve the sequence boundary so later messages stay pending.
|
|
128
141
|
3. Reply only with a requested result, answer, blocker, or fact the sender
|
|
129
142
|
needs. Use MCP `dispatch_message` with the same `project_root`,
|
|
130
|
-
caller-owned subscriber
|
|
131
|
-
`message`.
|
|
143
|
+
caller-owned subscriber and `agent_handle`, sender ID as `target`, and
|
|
144
|
+
substantive result as `message`.
|
|
132
145
|
|
|
133
146
|
Do not reply to greetings, thanks, or acknowledgement-only messages. After
|
|
134
147
|
sending, continue the current task. Keep the existing Cursor stream running, or
|
package/README.md
CHANGED
|
@@ -27,8 +27,8 @@ Package: [u-foo on npm](https://www.npmjs.com/package/u-foo)
|
|
|
27
27
|
- Launch modes for internal, tmux, host, Terminal.app, and iTerm2 workflows.
|
|
28
28
|
- Built-in group templates for launching and orchestrating multi-agent workflows.
|
|
29
29
|
- `ucode`, a native ufoo coding-agent runtime.
|
|
30
|
-
-
|
|
31
|
-
|
|
30
|
+
- One loopback Streamable HTTP MCP server inside the home-scoped global
|
|
31
|
+
controller daemon, plus a disposable `ufoo mcp` stdio compatibility proxy.
|
|
32
32
|
|
|
33
33
|
## Requirements
|
|
34
34
|
|
|
@@ -58,7 +58,7 @@ Installed binaries:
|
|
|
58
58
|
|
|
59
59
|
| Binary | Purpose |
|
|
60
60
|
|---|---|
|
|
61
|
-
| `ufoo` | Main CLI, chat dashboard,
|
|
61
|
+
| `ufoo` | Main CLI, chat dashboard, daemons, global MCP server/proxy, groups, bus, context, memory, reports, and online helpers. |
|
|
62
62
|
| `uclaude` | Claude Code wrapper with ufoo bootstrap and bus identity. |
|
|
63
63
|
| `ucodex` | Codex wrapper with ufoo bootstrap and bus identity. |
|
|
64
64
|
| `uagy` | Antigravity wrapper with ufoo bootstrap and bus identity. |
|
|
@@ -100,15 +100,27 @@ Use global chat mode to switch between registered projects:
|
|
|
100
100
|
ufoo -g
|
|
101
101
|
```
|
|
102
102
|
|
|
103
|
-
For
|
|
103
|
+
For Codex App, Codex CLI, and the Codex IDE extension, start global mode once
|
|
104
|
+
and install the shared direct HTTP configuration:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
ufoo -g
|
|
108
|
+
ufoo mcp configure codex
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
The configuration points all three Codex surfaces at the same authenticated
|
|
112
|
+
loopback endpoint. Restart the Codex surface after configuring it.
|
|
113
|
+
|
|
114
|
+
For a host that has not been verified with direct HTTP, keep the compatible
|
|
115
|
+
stdio configuration:
|
|
104
116
|
|
|
105
117
|
```bash
|
|
106
118
|
ufoo mcp
|
|
107
119
|
```
|
|
108
120
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
121
|
+
This command is a stateless transport proxy into the same global server. It
|
|
122
|
+
does not own Agent registrations or project state. Inspect or restart the
|
|
123
|
+
singleton listener with `ufoo mcp status` and `ufoo mcp restart`.
|
|
112
124
|
|
|
113
125
|
## Runtime Model
|
|
114
126
|
|
|
@@ -122,16 +134,19 @@ ufoo / ufoo chat
|
|
|
122
134
|
-> coordination bus/context/memory/history/report/state/status
|
|
123
135
|
-> shared controller/worker tools and native ucode tools
|
|
124
136
|
|
|
125
|
-
|
|
126
|
-
|
|
137
|
+
Codex App / CLI / IDE -> Streamable HTTP --+
|
|
138
|
+
ufoo mcp stdio proxy ----------------------+
|
|
139
|
+
-> home-scoped global controller daemon
|
|
140
|
+
(one MCP listener and tool router)
|
|
127
141
|
-> ~/.ufoo/projects/runtime
|
|
128
|
-
->
|
|
142
|
+
-> ProjectRuntimeGateway
|
|
143
|
+
-> selected project daemon for bus/report/activity/wait state
|
|
129
144
|
```
|
|
130
145
|
|
|
131
146
|
### Agent Delivery Modes
|
|
132
147
|
|
|
133
|
-
ufoo supports two Agent delivery modes, selected only
|
|
134
|
-
`UFOO_SUBSCRIBER_ID
|
|
148
|
+
ufoo supports two Agent delivery modes, selected only from the host Agent's
|
|
149
|
+
inherited `UFOO_SUBSCRIBER_ID` before any helper terminal is started:
|
|
135
150
|
|
|
136
151
|
- Wrapper-managed Agents start through `ucodex`, `uclaude`, `uagy`, `ukimi`, or
|
|
137
152
|
`ucode`. The wrapper provides `UFOO_SUBSCRIBER_ID`; ufoo monitors the shell
|
|
@@ -140,14 +155,17 @@ ufoo supports two Agent delivery modes, selected only by the presence of
|
|
|
140
155
|
or run a resident bus poll.
|
|
141
156
|
- Externally hosted Agents have no wrapper-provided subscriber environment.
|
|
142
157
|
They register themselves once through MCP `register_agent`, retain the
|
|
143
|
-
returned subscriber
|
|
158
|
+
returned subscriber plus opaque `agent_handle`, and select the host App's
|
|
159
|
+
native no-token wait:
|
|
144
160
|
Codex App keeps MCP `wait_for_message` pending, while Cursor monitors
|
|
145
161
|
`ufoo bus poll --follow` background output with `notify_on_output`.
|
|
146
162
|
|
|
147
163
|
Agent type names and subscriber prefixes are routing metadata, not capability
|
|
148
|
-
signals.
|
|
149
|
-
|
|
150
|
-
|
|
164
|
+
signals. After an external Cursor Agent registers through MCP, its dedicated
|
|
165
|
+
listener terminal may export the returned subscriber as
|
|
166
|
+
`UFOO_SUBSCRIBER_ID` so CLI operations share one identity. That child-shell
|
|
167
|
+
binding does not alter the host Agent's already selected external mode and is
|
|
168
|
+
not evidence of wrapper injection.
|
|
151
169
|
|
|
152
170
|
Chat is a UI client. The daemon owns project runtime state. Agents communicate
|
|
153
171
|
through bus queues, prompt injection, shared memory, reports, and tool handlers
|
|
@@ -235,17 +253,21 @@ ufoo skills list --optional
|
|
|
235
253
|
ufoo skills install ufoo-bus-poll --target /path/to/that/agent/skills
|
|
236
254
|
```
|
|
237
255
|
|
|
238
|
-
Register once through MCP `register_agent
|
|
239
|
-
|
|
256
|
+
Register once through MCP `register_agent` and retain its returned subscriber
|
|
257
|
+
and `agent_handle`. Include the handle in heartbeat, activity, send, receive,
|
|
258
|
+
acknowledgement, report, and unregister calls. The handle is an ownership
|
|
259
|
+
capability: do not send it to peers or print it in reports.
|
|
240
260
|
|
|
241
261
|
- **Codex App:** call MCP `wait_for_message` in the foreground with
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
`
|
|
247
|
-
-
|
|
248
|
-
|
|
262
|
+
the registered subscriber and handle, `after_seq: 0`, and
|
|
263
|
+
`timeout_seconds: 600`. The tool call stays pending inside ufoo; a message
|
|
264
|
+
returns immediately and wakes the task without shell stdout. On timeout,
|
|
265
|
+
re-arm with the same cursor. After handling a message response, call MCP
|
|
266
|
+
`ack_bus` with the same handle and its `last_seq` as `through_seq`, then
|
|
267
|
+
re-arm with that `last_seq` when the Agent is idle again.
|
|
268
|
+
- **Cursor:** bind the MCP subscriber and run
|
|
269
|
+
`export UFOO_SUBSCRIBER_ID="<subscriber-id>"; exec ufoo bus poll
|
|
270
|
+
"$UFOO_SUBSCRIBER_ID" --follow --interval 30` through the monitored
|
|
249
271
|
background shell with `block_until_ms: 0`, and configure
|
|
250
272
|
`notify_on_output` to match `\[ufoo\]`. Startup and empty intervals are
|
|
251
273
|
silent; only ufoo-delivered messages wake the model.
|
|
@@ -254,10 +276,12 @@ Both paths keep idle queue checks outside the LLM. A background PTY alone is
|
|
|
254
276
|
not a wake mechanism in Codex App.
|
|
255
277
|
|
|
256
278
|
The poll skill is not installed by postinstall or `skills install all`.
|
|
257
|
-
Wrapper-managed Agents skip MCP registration and external waiting
|
|
258
|
-
`UFOO_SUBSCRIBER_ID`
|
|
259
|
-
|
|
260
|
-
|
|
279
|
+
Wrapper-managed Agents skip MCP registration and external waiting when
|
|
280
|
+
`UFOO_SUBSCRIBER_ID` was present in the Agent's inherited launch environment.
|
|
281
|
+
A value exported later inside a Cursor listener terminal does not rerun this
|
|
282
|
+
classification. Receive-path selection depends on host App capabilities, never
|
|
283
|
+
on whether the external Agent calls itself Codex, Claude, Cursor, or another
|
|
284
|
+
type.
|
|
261
285
|
|
|
262
286
|
### Context, Memory, History, Reports
|
|
263
287
|
|
package/README.zh-CN.md
CHANGED
|
@@ -25,8 +25,8 @@ npm 包:[u-foo](https://www.npmjs.com/package/u-foo)
|
|
|
25
25
|
- 支持 internal、tmux、host、Terminal.app、iTerm2 等启动模式。
|
|
26
26
|
- 内置 group 模板,用于启动和编排多 Agent 工作流。
|
|
27
27
|
- 提供原生 ufoo coding-agent 运行时 `ucode`。
|
|
28
|
-
-
|
|
29
|
-
|
|
28
|
+
- home 级 global controller daemon 内提供唯一的本机 Streamable HTTP MCP
|
|
29
|
+
server;`ufoo mcp` 仅作为可随时销毁的 stdio 兼容代理。
|
|
30
30
|
|
|
31
31
|
## 环境要求
|
|
32
32
|
|
|
@@ -56,7 +56,7 @@ npm link
|
|
|
56
56
|
|
|
57
57
|
| 命令 | 用途 |
|
|
58
58
|
|---|---|
|
|
59
|
-
| `ufoo` | 主 CLI、chat 仪表盘、daemon
|
|
59
|
+
| `ufoo` | 主 CLI、chat 仪表盘、daemon、global MCP server/proxy、group、bus、context、memory、report 和 online helper。 |
|
|
60
60
|
| `uclaude` | Claude Code 包装器,注入 ufoo bootstrap 和 bus 身份。 |
|
|
61
61
|
| `ucodex` | Codex 包装器,注入 ufoo bootstrap 和 bus 身份。 |
|
|
62
62
|
| `uagy` | Antigravity 包装器,注入 ufoo bootstrap 和 bus 身份。 |
|
|
@@ -98,14 +98,18 @@ ucode
|
|
|
98
98
|
ufoo -g
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
-
|
|
101
|
+
Codex App、Codex CLI 和 Codex IDE extension 共用同一份配置。先启动一次
|
|
102
|
+
global mode,再写入经过验证的直接 HTTP 配置:
|
|
102
103
|
|
|
103
104
|
```bash
|
|
104
|
-
ufoo
|
|
105
|
+
ufoo -g
|
|
106
|
+
ufoo mcp configure codex
|
|
105
107
|
```
|
|
106
108
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
+
重启 Codex surface 后即可使用。尚未验证直接 HTTP 的 host 继续配置
|
|
110
|
+
`ufoo mcp`;该命令只是连接同一 global server 的无状态 stdio 代理,不拥有
|
|
111
|
+
Agent 注册或项目状态。用 `ufoo mcp status` 检查唯一 listener,用
|
|
112
|
+
`ufoo mcp restart` 只重启 listener。
|
|
109
113
|
|
|
110
114
|
## 运行模型
|
|
111
115
|
|
|
@@ -119,28 +123,34 @@ ufoo / ufoo chat
|
|
|
119
123
|
-> coordination bus/context/memory/history/report/state/status
|
|
120
124
|
-> shared controller/worker tools and native ucode tools
|
|
121
125
|
|
|
122
|
-
|
|
123
|
-
|
|
126
|
+
Codex App / CLI / IDE -> Streamable HTTP --+
|
|
127
|
+
ufoo mcp stdio proxy ----------------------+
|
|
128
|
+
-> home-scoped global controller daemon
|
|
129
|
+
-> one MCP listener and tool router
|
|
124
130
|
-> ~/.ufoo/projects/runtime
|
|
125
|
-
->
|
|
131
|
+
-> ProjectRuntimeGateway
|
|
132
|
+
-> selected project daemon for bus/report/activity/wait state
|
|
126
133
|
```
|
|
127
134
|
|
|
128
135
|
### Agent 消息投递模式
|
|
129
136
|
|
|
130
|
-
ufoo 支持两种 Agent
|
|
137
|
+
ufoo 支持两种 Agent 投递模式,只根据启动辅助 terminal 之前,宿主 Agent
|
|
138
|
+
继承的 `UFOO_SUBSCRIBER_ID` 是否存在来选择:
|
|
131
139
|
|
|
132
140
|
- 包装器托管的 Agent 通过 `ucodex`、`uclaude`、`uagy`、`ukimi` 或 `ucode`
|
|
133
141
|
启动。包装器会提供 `UFOO_SUBSCRIBER_ID`;ufoo 能监控其 shell 活动并定位
|
|
134
142
|
注入端点,因此可以直接注入 bus 消息。这类 Agent 复用环境中的身份,
|
|
135
143
|
不通过 MCP 重复注册,也不运行常驻 bus poll。
|
|
136
144
|
- 外部 host 托管的 Agent 没有包装器提供的 subscriber 环境变量。它通过 MCP
|
|
137
|
-
`register_agent` 注册一次,保留返回的 subscriber
|
|
138
|
-
|
|
139
|
-
|
|
145
|
+
`register_agent` 注册一次,保留返回的 subscriber 和不透明
|
|
146
|
+
`agent_handle`,再选择宿主 App 原生的无 token 等待方式:Codex App 挂起
|
|
147
|
+
MCP `wait_for_message`,Cursor 则用 `notify_on_output` 监控
|
|
148
|
+
`ufoo bus poll --follow` 的后台输出。
|
|
140
149
|
|
|
141
|
-
Agent 类型名和 subscriber 前缀只是路由元数据,不是能力判断条件。外部
|
|
142
|
-
|
|
143
|
-
|
|
150
|
+
Agent 类型名和 subscriber 前缀只是路由元数据,不是能力判断条件。外部
|
|
151
|
+
Cursor Agent 通过 MCP 注册后,可以在专用监听 terminal 内把返回的
|
|
152
|
+
subscriber 导出为 `UFOO_SUBSCRIBER_ID`,让 CLI 操作复用同一身份。这个
|
|
153
|
+
子 shell 绑定不会改变宿主 Agent 已选择的外部模式,也不代表支持包装器注入。
|
|
144
154
|
|
|
145
155
|
Chat 是 UI client。daemon 拥有项目运行态。Agent 通过 bus queue、prompt
|
|
146
156
|
injection、shared memory、report 和 tool handler 协作,而不是直接依赖
|
|
@@ -223,25 +233,29 @@ ufoo skills list --optional
|
|
|
223
233
|
ufoo skills install ufoo-bus-poll --target /path/to/that/agent/skills
|
|
224
234
|
```
|
|
225
235
|
|
|
226
|
-
先通过 MCP `register_agent` 注册一次并保留返回的 subscriber
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
+
先通过 MCP `register_agent` 注册一次并保留返回的 subscriber 与
|
|
237
|
+
`agent_handle`。heartbeat、activity、send、receive、ack、report 和
|
|
238
|
+
unregister 都带上该 handle;它是所有权凭证,不应发送给其他 Agent,也不应
|
|
239
|
+
写进 report。
|
|
240
|
+
|
|
241
|
+
- **Codex App:**前台调用 MCP `wait_for_message`,传入注册所得 subscriber
|
|
242
|
+
和 handle,首次使用 `after_seq: 0`、`timeout_seconds: 600`。工具调用在
|
|
243
|
+
ufoo 内保持 pending;有消息立即返回并唤醒当前任务,不依赖 shell stdout。
|
|
244
|
+
超时后用相同游标续挂;处理消息后,用同一 handle 和返回的 `last_seq`
|
|
245
|
+
调用 MCP `ack_bus`,Agent 再次空闲时以该 `last_seq` 续挂。
|
|
246
|
+
- **Cursor:**在 monitored background shell 中绑定 MCP subscriber,再运行
|
|
247
|
+
`export UFOO_SUBSCRIBER_ID="<subscriber-id>"; exec ufoo bus poll
|
|
248
|
+
"$UFOO_SUBSCRIBER_ID" --follow --interval 30`,设置
|
|
236
249
|
`block_until_ms: 0`,并让 `notify_on_output` 匹配 `\[ufoo\]`。启动和
|
|
237
250
|
空轮询保持静默,只有 ufoo 投递消息会唤醒模型。
|
|
238
251
|
|
|
239
252
|
两条路径都把空闲检查留在 LLM 之外。仅有后台 PTY 输出并不能唤醒 Codex App。
|
|
240
253
|
|
|
241
|
-
poll skill 不会由 postinstall 或 `skills install all`
|
|
242
|
-
`UFOO_SUBSCRIBER_ID
|
|
243
|
-
|
|
244
|
-
|
|
254
|
+
poll skill 不会由 postinstall 或 `skills install all` 安装。如果
|
|
255
|
+
`UFOO_SUBSCRIBER_ID` 在 Agent 启动时的继承环境中已经存在,包装器托管的
|
|
256
|
+
Agent 就跳过 MCP 注册和外部等待;之后在 Cursor 监听 terminal 中导出的值
|
|
257
|
+
不会重新触发这次分类。接收链路由宿主 App 的能力决定,与外部 Agent 叫
|
|
258
|
+
Codex、Claude、Cursor 或其他类型无关。
|
|
245
259
|
|
|
246
260
|
### Context、Memory、History、Report
|
|
247
261
|
|
package/SKILLS/ufoo/SKILL.md
CHANGED
|
@@ -14,7 +14,8 @@ Apply the unified workspace protocol. Use `$ufoo-bus`, `$ufoo-context`, or
|
|
|
14
14
|
|
|
15
15
|
## Resolve the bus delivery mode
|
|
16
16
|
|
|
17
|
-
Use the
|
|
17
|
+
Use the host Agent's inherited launch environment as the only delivery-mode
|
|
18
|
+
signal. Evaluate it before creating or mutating helper terminals. Do not infer
|
|
18
19
|
capabilities from the Agent type or subscriber prefix.
|
|
19
20
|
|
|
20
21
|
- If `UFOO_SUBSCRIBER_ID` is nonempty, the Agent was started by a ufoo wrapper
|
|
@@ -22,15 +23,21 @@ capabilities from the Agent type or subscriber prefix.
|
|
|
22
23
|
`register_agent`, run `ufoo bus join`, or start `ufoo bus poll`; the wrapper
|
|
23
24
|
and daemon deliver follow-ups by direct prompt injection.
|
|
24
25
|
- If `UFOO_SUBSCRIBER_ID` is absent, the Agent is externally hosted. Reuse the
|
|
25
|
-
subscriber already returned to this session
|
|
26
|
-
`register_agent` once if none exists.
|
|
27
|
-
session
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
subscriber and `agent_handle` already returned to this session, or call
|
|
27
|
+
MCP `register_agent` once if none exists. When the host
|
|
28
|
+
exposes a stable local session identifier, pass it as `client_instance_id`
|
|
29
|
+
so a transport restart can recover the subscriber and rotate the handle.
|
|
30
|
+
Keep the returned pair as session-local identity; never send or report the
|
|
31
|
+
handle to another Agent. Invoke `$ufoo-bus-poll` to establish the receive
|
|
32
|
+
path using this host App's own no-token wait and self-wake primitive. A
|
|
33
|
+
Cursor-style dedicated listener terminal may export the returned value as
|
|
34
|
+
`UFOO_SUBSCRIBER_ID` after registration so its CLI commands share the
|
|
35
|
+
identity. That helper-local export does not change the already selected
|
|
36
|
+
external delivery mode and must not be treated as wrapper evidence.
|
|
30
37
|
|
|
31
38
|
In the sections below, `<subscriber-id>` means the wrapper-provided
|
|
32
|
-
`UFOO_SUBSCRIBER_ID` or the subscriber returned by MCP
|
|
33
|
-
|
|
39
|
+
`UFOO_SUBSCRIBER_ID` or the subscriber returned by MCP. `<agent-handle>` means
|
|
40
|
+
the opaque capability returned with an external MCP registration.
|
|
34
41
|
|
|
35
42
|
## Synchronize workspace state
|
|
36
43
|
|
|
@@ -56,20 +63,25 @@ Treat these prompt prefixes as work inputs:
|
|
|
56
63
|
For each received bus task:
|
|
57
64
|
|
|
58
65
|
1. Execute it immediately within the current authority.
|
|
59
|
-
2. Acknowledge it only after handling:
|
|
66
|
+
2. Acknowledge it only after handling. A wrapper-managed Agent uses:
|
|
60
67
|
|
|
61
68
|
```bash
|
|
62
69
|
ufoo bus ack "<subscriber-id>"
|
|
63
70
|
```
|
|
64
71
|
|
|
72
|
+
An external Agent calls MCP `ack_bus` with `project_root`, `subscriber`,
|
|
73
|
+
`agent_handle: "<agent-handle>"`, and the delivered sequence boundary.
|
|
65
74
|
3. Reply only with a requested answer, delegated result, or fact the sender
|
|
66
75
|
needs to continue. Do not reply with greetings or bare acknowledgements.
|
|
67
|
-
4. Emit a concise runtime report for delegated work
|
|
76
|
+
4. Emit a concise runtime report for delegated work. A wrapper-managed Agent
|
|
77
|
+
uses:
|
|
68
78
|
|
|
69
79
|
```bash
|
|
70
80
|
ufoo report done "<summary>" --agent "<subscriber-id>"
|
|
71
81
|
```
|
|
72
82
|
|
|
83
|
+
An external Agent calls MCP `report_agent_status` with the same subscriber
|
|
84
|
+
and handle.
|
|
73
85
|
After sending or broadcasting, continue the current task. Do not start an
|
|
74
86
|
ad-hoc check or poll, sleep, or wait for a reply. A wrapper-managed Agent
|
|
75
87
|
receives follow-ups by direct injection; an external Agent leaves its existing
|
package/SKILLS/ufoo-bus/SKILL.md
CHANGED
|
@@ -21,17 +21,24 @@ Verify `.ufoo/bus/` exists. If it does not, initialize it:
|
|
|
21
21
|
ufoo init --targets bus --project "$(pwd)"
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
Use `UFOO_SUBSCRIBER_ID` as the only delivery-mode
|
|
24
|
+
Use the host Agent's inherited `UFOO_SUBSCRIBER_ID` as the only delivery-mode
|
|
25
|
+
signal. Evaluate it before creating or mutating helper terminals:
|
|
25
26
|
|
|
26
27
|
- Nonempty: this is a wrapper-managed Agent. The wrapper already registered
|
|
27
28
|
the subscriber and the daemon can inject into its monitored shell. Reuse the
|
|
28
29
|
value. Do not call MCP `register_agent`, run `ufoo bus join`, or arm resident
|
|
29
30
|
polling.
|
|
30
31
|
- Absent: this is an externally hosted Agent. Reuse this session's
|
|
31
|
-
MCP-registered subscriber or call MCP `register_agent`
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
MCP-registered subscriber and `agent_handle`, or call MCP `register_agent`
|
|
33
|
+
exactly once. If the host exposes a stable local session id, pass it as
|
|
34
|
+
`client_instance_id`. Keep the returned pair as `<subscriber-id>` and
|
|
35
|
+
`<agent-handle>` for later MCP operations. Treat the handle as a private
|
|
36
|
+
capability: do not send, log, or report it. Invoke
|
|
37
|
+
`$ufoo-bus-poll` once at session start to select the receive path supported
|
|
38
|
+
by the host App. That skill may bind the subscriber as
|
|
39
|
+
`UFOO_SUBSCRIBER_ID` inside a dedicated Cursor listener terminal after MCP
|
|
40
|
+
registration. Never use that helper-local value to reclassify the host as
|
|
41
|
+
wrapper-managed.
|
|
35
42
|
|
|
36
43
|
Never choose a delivery mode from an Agent type such as `codex`, `cursor`, or
|
|
37
44
|
`claude-code`. Agents do not self-register with bare `ufoo bus join`.
|
|
@@ -45,7 +52,8 @@ ufoo bus check "<subscriber-id>"
|
|
|
45
52
|
```
|
|
46
53
|
|
|
47
54
|
For an external Agent, use MCP `poll_inbox` with its `project_root` and
|
|
48
|
-
caller-owned `<subscriber-id>` only when an explicit
|
|
55
|
+
caller-owned `<subscriber-id>` and `<agent-handle>` only when an explicit
|
|
56
|
+
manual check is required.
|
|
49
57
|
If `$ufoo-bus-poll` woke the session with an emitted pending batch, handle that
|
|
50
58
|
batch directly. Do not run a second check for the same wake.
|
|
51
59
|
|
|
@@ -64,6 +72,7 @@ For every pending batch:
|
|
|
64
72
|
pending. For a `$ufoo-bus-poll` wake, run the exact `ack --through <seq>`
|
|
65
73
|
line printed by the Cursor stream. A Codex App wait returns `last_seq`; pass
|
|
66
74
|
it to MCP `ack_bus` as `through_seq`.
|
|
75
|
+
Every external `ack_bus` call also includes the caller-owned `agent_handle`.
|
|
67
76
|
4. Reply only when the sender requested an answer, delegated work whose result
|
|
68
77
|
is needed, or needs a discovered blocker or fact.
|
|
69
78
|
|
|
@@ -88,9 +97,9 @@ ufoo bus broadcast "<substantive message>"
|
|
|
88
97
|
```
|
|
89
98
|
|
|
90
99
|
For an external Agent, call MCP `dispatch_message` with its `project_root`,
|
|
91
|
-
caller-owned `subscriber`, `target`, and `message`. Use target
|
|
92
|
-
broadcast. This preserves the registered sender identity instead of
|
|
93
|
-
CLI-side identity.
|
|
100
|
+
caller-owned `subscriber`, `agent_handle`, `target`, and `message`. Use target
|
|
101
|
+
`*` for a broadcast. This preserves the registered sender identity instead of
|
|
102
|
+
creating a CLI-side identity.
|
|
94
103
|
|
|
95
104
|
Target resolution order is exact ID, nickname, agent type, then `*`.
|
|
96
105
|
|
|
@@ -101,11 +110,12 @@ keep their App-specific receive wait armed when idle.
|
|
|
101
110
|
|
|
102
111
|
## Delegate resident watching
|
|
103
112
|
|
|
104
|
-
For an externally hosted Agent
|
|
105
|
-
`$ufoo-bus-poll` at session start and follow it
|
|
106
|
-
receive path, not an Agent-type fallback. That
|
|
107
|
-
`wait_for_message` for Codex App or monitored
|
|
108
|
-
Never invoke it when the
|
|
113
|
+
For an externally hosted Agent whose inherited launch environment had no
|
|
114
|
+
`UFOO_SUBSCRIBER_ID`, invoke `$ufoo-bus-poll` at session start and follow it
|
|
115
|
+
end-to-end. This is its normal receive path, not an Agent-type fallback. That
|
|
116
|
+
skill selects pending MCP `wait_for_message` for Codex App or monitored
|
|
117
|
+
background stdout for Cursor. Never invoke it when the variable was already
|
|
118
|
+
present before helper-terminal setup.
|
|
109
119
|
|
|
110
120
|
Do not implement a timer, tick, sleep/check loop, or second resident mechanism
|
|
111
121
|
in this skill. Do not arm resident watching merely because a message was sent
|
|
@@ -115,7 +125,8 @@ using the rules above and leave re-arming or stream lifecycle to
|
|
|
115
125
|
|
|
116
126
|
## Report delegated work
|
|
117
127
|
|
|
118
|
-
Use the shared report contract when bus work represents a task
|
|
128
|
+
Use the shared report contract when bus work represents a task. A
|
|
129
|
+
wrapper-managed Agent uses:
|
|
119
130
|
|
|
120
131
|
```bash
|
|
121
132
|
ufoo report start "<task>" --task <id> --agent "<subscriber-id>"
|
|
@@ -125,3 +136,6 @@ ufoo report error "<reason>" --task <id> --agent "<subscriber-id>"
|
|
|
125
136
|
```
|
|
126
137
|
|
|
127
138
|
Use `--scope private` only for helper-internal reports.
|
|
139
|
+
|
|
140
|
+
An external Agent calls MCP `report_agent_status` with `project_root`,
|
|
141
|
+
`subscriber`, `agent_handle`, the task id, phase, and summary.
|
package/bin/ufoo.js
CHANGED
|
@@ -14,16 +14,21 @@ function hasGlobalModeFlag(args = []) {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
function printMcpHelp() {
|
|
17
|
-
console.log("Usage: ufoo mcp [options]");
|
|
17
|
+
console.log("Usage: ufoo mcp [status|restart|configure codex] [options]");
|
|
18
18
|
console.log("");
|
|
19
|
-
console.log("Run the
|
|
19
|
+
console.log("Run the stdio compatibility proxy or control the global MCP listener.");
|
|
20
20
|
console.log("");
|
|
21
21
|
console.log("Options:");
|
|
22
22
|
console.log(" --no-auto-start Do not auto-start the home-scoped global controller daemon");
|
|
23
|
+
console.log(" --json Print status or restart results as JSON");
|
|
24
|
+
console.log(" --dry-run Print a Codex HTTP configuration without writing it");
|
|
23
25
|
console.log(" -h, --help Display help for the MCP bridge command");
|
|
24
26
|
console.log("");
|
|
25
27
|
console.log("Notes:");
|
|
26
28
|
console.log(" Configure MCP-capable clients with command: ufoo mcp");
|
|
29
|
+
console.log(" Inspect the singleton listener: ufoo mcp status");
|
|
30
|
+
console.log(" Restart only the listener: ufoo mcp restart");
|
|
31
|
+
console.log(" Configure Codex App/CLI/IDE: ufoo mcp configure codex");
|
|
27
32
|
console.log(" Example without daemon auto-start: ufoo mcp --no-auto-start");
|
|
28
33
|
console.log(" Human diagnostics are available in chat: /mcp status, /mcp tools, /mcp help");
|
|
29
34
|
}
|
|
@@ -47,9 +52,18 @@ async function main() {
|
|
|
47
52
|
printMcpHelp();
|
|
48
53
|
return;
|
|
49
54
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
55
|
+
const operation = argv[1];
|
|
56
|
+
if (operation === "status" || operation === "restart") {
|
|
57
|
+
const { runMcpControlCli } = require("../src/runtime/daemon/mcpControl");
|
|
58
|
+
await runMcpControlCli(operation, { json: argv.includes("--json") });
|
|
59
|
+
} else if (operation === "configure") {
|
|
60
|
+
const { runMcpConfigureCli } = require("../src/runtime/daemon/mcpConfigure");
|
|
61
|
+
runMcpConfigureCli(argv[2], { dryRun: argv.includes("--dry-run") });
|
|
62
|
+
} else {
|
|
63
|
+
await runMcpServer({
|
|
64
|
+
autoStart: !argv.includes("--no-auto-start"),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
53
67
|
return;
|
|
54
68
|
}
|
|
55
69
|
if (cmd === "agent-runner") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "u-foo",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.19",
|
|
4
4
|
"description": "Multi-Agent Workspace Protocol. Just add u. claude → uclaude, codex → ucodex.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"homepage": "https://ufoo.dev",
|
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
58
|
"@anthropic-ai/claude-agent-sdk": "^0.2.138",
|
|
59
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
59
60
|
"@openai/codex-sdk": "^0.145.0",
|
|
60
61
|
"@xterm/addon-serialize": "^0.14.0",
|
|
61
62
|
"@xterm/headless": "^6.0.0",
|
|
@@ -38,7 +38,7 @@ const SHARED_UFOO_PROTOCOL = [
|
|
|
38
38
|
"coordination — never for greetings, acknowledgments, or emoji alone.",
|
|
39
39
|
"Those create reply loops between agents.",
|
|
40
40
|
"",
|
|
41
|
-
"A nonempty `UFOO_SUBSCRIBER_ID` means the ufoo wrapper/daemon already",
|
|
41
|
+
"A nonempty `UFOO_SUBSCRIBER_ID` in this Agent's inherited launch environment means the ufoo wrapper/daemon already",
|
|
42
42
|
"registered this Agent and can inject into its monitored session. Reuse that",
|
|
43
43
|
"identity; never call MCP `register_agent`, run bare `ufoo bus join`, or",
|
|
44
44
|
"start resident `ufoo bus poll`.",
|
|
@@ -9,7 +9,7 @@ Participate in multi-agent coordination through the ufoo bus/context system:
|
|
|
9
9
|
- Use shared memory for durable project facts. Read existing memory before writing new memory; do not use it for transient task state.
|
|
10
10
|
- Support launch/close/resume/inject flows managed by ufoo daemon.
|
|
11
11
|
- Prefer canonical ufoo commands (\`ufoo ctx\`, \`ufoo bus\`, \`ufoo memory\`, \`ufoo report\`) for coordination and status sync.
|
|
12
|
-
- A nonempty \`UFOO_SUBSCRIBER_ID\` means the ufoo wrapper/daemon already registered this Agent and can inject directly into its monitored session. Reuse that identity; never call MCP \`register_agent\`, run bare \`ufoo bus join\`, or start resident \`ufoo bus poll\`.
|
|
12
|
+
- A nonempty \`UFOO_SUBSCRIBER_ID\` in this Agent's inherited launch environment means the ufoo wrapper/daemon already registered this Agent and can inject directly into its monitored session. Reuse that identity; never call MCP \`register_agent\`, run bare \`ufoo bus join\`, or start resident \`ufoo bus poll\`.
|
|
13
13
|
- After sending a bus message, do not poll \`ufoo bus check\`, invoke \`/ubus\`, sleep, or wait for a reply. Continue the current task; any follow-up message will be automatically injected into your prompt/session.
|
|
14
14
|
|
|
15
15
|
Execution protocol:
|