You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@maka.apache.org by "yifanxuaaa (via GitHub)" <gi...@apache.org> on 2026/08/20 15:39:58 UTC
[D] 将bash工具从Claude Code Style迁移到Codex Style [maka]
GitHub user yifanxuaaa created a discussion: 将bash工具从Claude Code Style迁移到Codex Style
当前默认使用的是 Claude Code 风格的 bash 命令工具(支持 `write_stdin`),但 `background=false` 的问题仍然非常值得关注。
## Current Approach & Pain Points
- 我们使用的是 Claude Code 风格的 bash(cmd, background=true/false)
- 当 `background=false` 时,如果命令进入自循环 / 长时间阻塞(例如交互式 CLI、REPL、等待输入的进程、或意外的死循环),会直接卡住整个 agent 运行。
- 目前没有可靠的方式去 kill 一个 foreground 任务。
- 更严重的是 **KV cache 问题**:
- 如果 foreground 阻塞超过 ~5 分钟,部分llm provider 的 cache 会过期。
- 这会导致后续对话成本大幅上升,甚至丢失上下文优势。
## Why Codex-style is better
Codex 的 `exec_command` + `write_stdin` 方案采用 **yield + poll** 模式:
1. `exec_command` 启动命令,最多等待 `yield_time_ms`(默认 10s),如果还在运行就返回 `session_id`。
2. 后续用 `write_stdin`(可带 `chars` 或空字符串)继续发送输入 / 轮询输出。
3. Agent 自己控制轮询节奏,不会长时间阻塞单次 tool call。
优点:
- 不会因为单个长时间运行的命令把整个 agent 卡死。
- 可以随时通过轮询 / 中断(Ctrl-C)管理进程。
- 虽然会多次 tool call(polling),但配合 KV cache 成本很低。
- 对交互式 CLI、OAuth / device-code 登录、REPL、数据库提示、E2E 测试等场景支持更完整。
- 真正解决了 “foreground 阻塞 + cache 过期” 的矛盾。
结论:从 cache 友好性和 agent 可控性来看,**Codex 方案实际上更优**。
## Existing Implementation
我已经有一个可用的 DeepSeek / DSH 插件实现了这套方案,并且做了参数简化:
- Repo: https://github.com/Ephemeral-AI-Lab/dsh-plugins/blob/main/codex-shell/README.md
- 工具:
- `exec_command(cmd, workdir?, yield_time_ms?, max_output_tokens?)`
- `write_stdin(session_id, chars?, yield_time_ms?, max_output_tokens?)`
- 默认使用 pipe 传输(跨平台),支持 session 保留、输出分页、natural-exit 通知、并发清理等。
- 已有完整 unit + E2E 测试覆盖。
这个插件可以直接作为参考 / 默认实现。
## Discussion Points
1. 是否应该把 **默认 shell 工具** 切换到 Codex 这套(`exec_command` + `write_stdin`)?
2. 如果切换,是否保留原有 bash 工具作为可选(或者完全替换)?
3. 对现有 prompt / 工具调用习惯的影响有多大?是否需要迁移指南?
4. `yield_time_ms` 默认值、max_output_tokens、session 生命周期策略是否需要再调优?
5. 其他潜在风险或需要补充的能力(kill、timeout、资源限制等)?
欢迎大家分享实际使用体验、对比测试结果,或者直接反对意见。
如果大家倾向切换,我们可以进一步讨论落地计划(preset、文档、默认配置等)。
GitHub link: https://github.com/apache/maka/discussions/3342
----
This is an automatically sent email for dev@maka.apache.org.
To unsubscribe, please send an email to: dev-unsubscribe@maka.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@maka.apache.org
For additional commands, e-mail: dev-help@maka.apache.org
Re: [D] 将bash工具从Claude Code Style迁移到Codex Style [maka]
Posted by "me2seeks (via GitHub)" <gi...@apache.org>.
GitHub user me2seeks added a comment to the discussion: 将bash工具从Claude Code Style迁移到Codex Style
我也认同尽量减少 LLM 自己做无意义 polling,`completion wake` 作为优化是有价值的。
但如果默认变成“命令超时后自动转后台,然后一直等进程结束再 wake model”,我会担心 liveness 问题。
因为很多进程不一定会自然结束,比如:
* CLI 等待 stdin;
* REPL / 数据库 CLI;
* OAuth / device-code;
* `tail -f`、dev server;
* deadlock 或无限等待。
这时可能出现:
```text id="qw5vjw"
process waits for input / never exits
↑
|
agent waits for process completion
```
所以我觉得 `process/session handle` 还是基础能力,至少需要保留:
```text id="b8f9lo"
poll / stdin / interrupt
```
`completion notification` 可以减少 polling,但更适合作为 session 模型上的优化,而不是唯一的 continuation mechanism。
Maka 现在又已经有 durable `ShellRun` 和 recovery,我反而觉得更适合:
**session/process handle + optional completion wake**
而不是:
**automatic background + completion-only wake**
GitHub link: https://github.com/apache/maka/discussions/3342#discussioncomment-18096196
----
This is an automatically sent email for dev@maka.apache.org.
To unsubscribe, please send an email to: dev-unsubscribe@maka.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@maka.apache.org
For additional commands, e-mail: dev-help@maka.apache.org
Re: [D] 将bash工具从Claude Code Style迁移到Codex Style [maka]
Posted by "yifanxuaaa (via GitHub)" <gi...@apache.org>.
GitHub user yifanxuaaa edited a comment on the discussion: 将bash工具从Claude Code Style迁移到Codex Style
> 我也经常遇到命令意外卡死和超时影响 Cache 的情况,这个痛点提得非常及时!
>
> 不过关于把默认工具切到 Codex 风格的 Yield + Poll 模式,结合 Maka 的使用体验,我个人有一点顾虑,想和大家探讨一下:
>
> 1. **对 Event Log 与 UI 时间线的影响**
> Maka 的 Desktop 和 TUI 是基于 Append-only 日志做流式投射与会话回放的。如果长任务频繁调用 `write_stdin` 轮询,日志里会沉淀大量空跳记录,可能会让前端时间线和回放变得很碎。
> 2. **Turn 预算与调用延迟**
> 每多一轮轮询就会额外消耗一次 Turn 预算与模型往返延迟。尤其在长任务或者跑 Eval 测试时,Step 上限很容易被无意义的轮询占满。
> 3. **机制归属问题**
> 让 LLM 在推理循环中充当轮询调度器,感觉把宿主层本该兜底的进程监控职责推给了模型端。
>
> **个人感觉更轻量的思路:** 不知道能否直接在 Maka 的 `Tool Runtime` 底层做优化——当命令执行超时后,由运行时自动转入后台,等进程真正结束时再单次唤醒模型投递结果?这样既彻底解决了前台卡死和 Cache 过期的问题,又不需要模型在中间做主动轮询。
当command在超过yield_time_ms之后,若还是继续执行,应该被注册成background job。
agent在这种情况下有两件事情可以做:
1.Claude code在没有别的任务执行的时候会进入idle mode,等待命令结束,然后唤醒。聪明点的情况是自己设置一个/loop n 分钟 “alarm" 几分钟的轮训检查。
2. Codex的确会出现反复短轮询write_stdin的情况,聪明点的情况是它能够判断出这个background job可能时间会跑得比较久,write_stdin(..., yield_time_ms)需要设置得久一些。
我认为yield_time_ms+timeout组合是 Codex Shell优于其它agent shell/bash工具的核心,提供了非常灵活且自动转换的foreground + background bash,非常适合做e2e test, interactive cli等任务。但是频繁地write_stdin的确是个问题。我们需要看看能否做到像Claude Code那样在等待background task的时候进入idle模式,这样久不会太多额外步数了
GitHub link: https://github.com/apache/maka/discussions/3342#discussioncomment-18096329
----
This is an automatically sent email for dev@maka.apache.org.
To unsubscribe, please send an email to: dev-unsubscribe@maka.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@maka.apache.org
For additional commands, e-mail: dev-help@maka.apache.org
Re: [D] 将bash工具从Claude Code Style迁移到Codex Style [maka]
Posted by "Astro-Han (via GitHub)" <gi...@apache.org>.
GitHub user Astro-Han added a comment to the discussion: 将bash工具从Claude Code Style迁移到Codex Style
Two follow-ups after sitting with this a bit more — one honest capability gap, and one generalization that fell out of it.
## A known gap: chatty long-running commands + explicit parallel intent
One commenter scenario worth owning: "this task clearly belongs in the background, and the main agent should do other things meanwhile." Checking it against the proposal:
- **Quiet-after-startup processes (dev servers, etc.) are covered**: the process prints its startup banner, goes quiet, debounce fires, the tool call returns `{ref, running}`, and the model continues with other work while the process lives on. Fire-and-forget emerges on its own — the model never has to pre-judge "this one is background."
- **Continuously-chatty long commands are not covered**: debounce never fires on a streaming build/test run, so the park holds the agent loop until the lease expires. The CC-style `background=true` encoded exactly this upfront intent, and I did remove it.
If this gap turns out to matter in practice, the fix is one boolean — `run(command, wait: false)` — and it is *not* a revival of `background`: process lifecycle, semantics, ref, and return shape all stay identical; only the return condition changes (settled-or-chunked vs. immediately). The epistemic reason I'd allow this knob while rejecting time knobs: a model cannot estimate durations, but it *knows for certain* whether it currently has other work to do. Still, my inclination is to leave it out until real traces show the scenario is frequent — every knob given gets used.
## The unit is not "process" — it's "async unit of work"
A second scenario makes the same point from the other side: spawning a subagent that runs silently for 20 minutes and then returns one task output. That is not a new type — under this model it is byte-for-byte the same lifecycle:
```
spawn subagent → goes quiet → early return {ref, running}
→ want the result: read(ref) → parks until it completes → final output
→ have other work: pocket the ref, read later
→ want it dead: stop(ref)
```
Three of the surveyed projects already converged on this unification: kimi-code's background task system is generic (bash, Agent subagents, and AskUserQuestion share one lifecycle and notification mechanism); DSH's `ctx.jobs` registry manages shell, subagent, and terminal jobs uniformly; grok-build's Tasks panel groups Bash / Monitor / Subagent / Workflow together. prime-agent is the extreme: a subagent is just `await rlm(...)`, an async handle indistinguishable from a process.
So the handle registry shouldn't be a shell-tool feature — it's a runtime-level registry of async work units, and shell processes are just its first mount point. Maka's `maka://runtime/...` refs are already generic; the proposal above only attaches processes to them. Subagents, workflows, and monitors should share the same three verbs: read (park-wait) / write (deliver input) / stop.
This also answers the other half of the parallelism question: when the main agent wants to "do something else meanwhile," that something-else often *is* a subagent — and spawning one has the same park semantics, so the main agent delegates, pockets the ref, and walks on.
<details>
<summary><strong>简体中文</strong></summary>
再想了一层之后的两点补充——一个要诚实承认的能力缺口,和一个从缺口里长出来的推广。
## 已知缺口:持续输出型长命令 + 明确的并行意图
有个场景值得主动认领:"这个任务明确适合后台跑,主 agent 同时干别的。"对照提案验算:
- **启动后转安静的进程(dev server 之类)是覆盖的**:进程打印完启动信息、安静下来、防抖触发、tool call 返回 `{ref, running}`,模型拿着 ref 继续干别的,进程一直活着。fire-and-forget 是自然涌现的,模型不需要事先预判"这个该后台"。
- **持续输出型长命令没覆盖**:流式构建/测试永远不会停顿 K 秒,防抖不触发,park 占着 agent loop 直到租约到期。CC 风格的 `background=true` 编码的正是这种事先意图,而我确实把它删了。
如果真实轨迹证明这个缺口高频,修法是一个布尔——`run(command, wait: false)`——而且它**不是 background 复活**:进程生命周期、语义、ref、返回形状全都不变,唯一变化是返回条件(等分段 vs 立即返回)。我拒绝时间旋钮但允许这个旋钮的认识论理由:模型估不准时长,但它**确切知道**自己手头有没有别的活。不过我的倾向仍然是先不加——给出去的旋钮一定会被用,等轨迹说话。
## 抽象的单位不是"进程",是"异步工作单元"
另一个场景从反面说明了同一件事:召唤一个 subagent,闷头跑 20 分钟,最后返回一份 task output。这不是新类型——在这个模型下它的生命周期逐字同构:
```
召唤 subagent → 安静下来 → 提前返回 {ref, running}
→ 想要结果:read(ref) → park 到它完成 → 拿到最终输出
→ 有别的活:ref 揣兜里,回头再 read
→ 想掐死: stop(ref)
```
调研里有三家已经收敛到这个统一:kimi-code 的后台任务系统是通用的(bash、Agent 子代理、AskUserQuestion 共享同一套生命周期和通知机制);DSH 的 `ctx.jobs` 注册表统一管理 shell、subagent、terminal 的 job;grok-build 的 Tasks 面板把 Bash / Monitor / Subagent / Workflow 归在一组。prime-agent 最极端:subagent 就是 `await rlm(...)`,和进程无差别的异步 handle。
所以 handle 注册表不该是 shell 工具的功能——它是 runtime 级的异步工作单元注册表,shell 进程只是第一个挂载点。Maka 的 `maka://runtime/...` ref 已经是通用的,上面的提案只是把进程挂了上去;subagent、workflow、monitor 应该共享同样三个动词:read(park 等待)/ write(投递输入)/ stop(终止)。
这也回答了并行问题的另一半:主 agent 想"同时干点别的"时,那个"别的"往往本身就该是个 subagent——而召唤它有同样的 park 语义,主 agent 派完活、揣着 ref、继续走。
</details>
GitHub link: https://github.com/apache/maka/discussions/3342#discussioncomment-18097516
----
This is an automatically sent email for dev@maka.apache.org.
To unsubscribe, please send an email to: dev-unsubscribe@maka.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@maka.apache.org
For additional commands, e-mail: dev-help@maka.apache.org
Re: [D] 将bash工具从Claude Code Style迁移到Codex Style [maka]
Posted by "me2seeks (via GitHub)" <gi...@apache.org>.
GitHub user me2seeks added a comment to the discussion: 将bash工具从Claude Code Style迁移到Codex Style
我觉得这里有一个概念最好明确区分:**yield 和 background 不是一回事。**
Maka 之前其实已经尝试过比较接近“长时间运行后自动转后台”的方案。
* #547 引入了 `yield_time_ms`:Bash 先等待一小段时间,如果命令还没有结束,就继续作为 background task 执行,并返回一个 runtime ref。
* #764 后来又移除了这个行为,改成 background 必须显式指定。这里一个很重要的经验就是:**运行时间不应该改变命令的执行意图。**
* #1802 又尝试了另一个相关方向:background command 完成时主动唤醒 session,而不是让模型一直 `Read -> sleep -> Read` 轮询。
所以基于这些历史,我会比较谨慎地把下面这种语义重新作为默认行为:
```text
foreground command
↓
等待 N 秒
↓
自动转为 background
↓
结束后 wake model
```
我觉得 Codex-style 方案真正值得借鉴的地方稍微不一样:
> **yield 应该只是把控制权还给 agent,而不应该改变进程本身的 execution intent。**
例如:
```text
exec_command
|
| 10 秒内结束
v
result
|
| 10 秒后仍然运行
v
session_id
|
+-- poll output
+-- write stdin
+-- interrupt
```
这里它仍然是同一个 foreground process,并没有因为超过 10 秒就被悄悄地变成一个“background task”。
变化的只是:这一次 tool call 不再继续阻塞 model loop。
我觉得这个区分很重要,因为它可以同时得到:
1. 短命令仍然保持简单的 `exec -> result` 路径;
2. 长时间运行的 foreground command 不会一直阻塞 agent;
3. 真正需要 fire-and-forget 时,background intent 仍然是显式的;
4. 同一个 process handle 还能自然支持 REPL、OAuth/device-code、数据库 CLI、需要 stdin 的交互式程序等场景。
completion event 当然仍然有价值,但我更倾向于把它看成建立在 session/process-handle 模型之上的一种优化,而不是用它替代 session 模型。
例如:
```text
foreground:
short yield
↓
process/session handle
↓
poll / stdin / interrupt
↓
optional completion notification
background:
explicit opt-in
```
这样也不会重新引入 #764 当时要解决的问题:因为运行时间过去了多久,Runtime 就隐式改变了命令原本的执行语义。
至于 polling 会产生更多 Events / Turns 的问题,我觉得这个问题确实存在,但它可能更适合在 Runtime / Event Log 的表示层解决。
例如连续的空 poll,并不一定每一次都需要作为同等级的 first-class timeline event 暴露出来。
所以我个人更倾向于:
**foreground = short yield + persistent process handle**
**background = explicit intent**
**completion notification = optional optimization**
而不是根据命令运行了多久,自动把 foreground execution 转成 background execution。
GitHub link: https://github.com/apache/maka/discussions/3342#discussioncomment-18095991
----
This is an automatically sent email for dev@maka.apache.org.
To unsubscribe, please send an email to: dev-unsubscribe@maka.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@maka.apache.org
For additional commands, e-mail: dev-help@maka.apache.org
Re: [D] 将bash工具从Claude Code Style迁移到Codex Style [maka]
Posted by "cat0825 (via GitHub)" <gi...@apache.org>.
GitHub user cat0825 added a comment to the discussion: 将bash工具从Claude Code Style迁移到Codex Style
我也经常遇到命令意外卡死和超时影响 Cache 的情况,这个痛点提得非常及时!
不过关于把默认工具切到 Codex 风格的 Yield + Poll 模式,结合 Maka 的使用体验,我个人有一点顾虑,想和大家探讨一下:
1. **对 Event Log 与 UI 时间线的影响**
Maka 的 Desktop 和 TUI 是基于 Append-only 日志做流式投射与会话回放的。如果长任务频繁调用 `write_stdin` 轮询,日志里会沉淀大量空跳记录,可能会让前端时间线和回放变得很碎。
2. **Turn 预算与调用延迟**
每多一轮轮询就会额外消耗一次 Turn 预算与模型往返延迟。尤其在长任务或者跑 Eval 测试时,Step 上限很容易被无意义的轮询占满。
3. **机制归属问题**
让 LLM 在推理循环中充当轮询调度器,感觉把宿主层本该兜底的进程监控职责推给了模型端。
**个人感觉更轻量的思路:**
不知道能否直接在 Maka 的 `Tool Runtime` 底层做优化——当命令执行超时后,由运行时自动转入后台,等进程真正结束时再单次唤醒模型投递结果?这样既彻底解决了前台卡死和 Cache 过期的问题,又不需要模型在中间做主动轮询。
GitHub link: https://github.com/apache/maka/discussions/3342#discussioncomment-18095695
----
This is an automatically sent email for dev@maka.apache.org.
To unsubscribe, please send an email to: dev-unsubscribe@maka.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@maka.apache.org
For additional commands, e-mail: dev-help@maka.apache.org
Re: [D] 将bash工具从Claude Code Style迁移到Codex Style [maka]
Posted by "yifanxuaaa (via GitHub)" <gi...@apache.org>.
GitHub user yifanxuaaa added a comment to the discussion: 将bash工具从Claude Code Style迁移到Codex Style
> 我也经常遇到命令意外卡死和超时影响 Cache 的情况,这个痛点提得非常及时!
>
> 不过关于把默认工具切到 Codex 风格的 Yield + Poll 模式,结合 Maka 的使用体验,我个人有一点顾虑,想和大家探讨一下:
>
> 1. **对 Event Log 与 UI 时间线的影响**
> Maka 的 Desktop 和 TUI 是基于 Append-only 日志做流式投射与会话回放的。如果长任务频繁调用 `write_stdin` 轮询,日志里会沉淀大量空跳记录,可能会让前端时间线和回放变得很碎。
> 2. **Turn 预算与调用延迟**
> 每多一轮轮询就会额外消耗一次 Turn 预算与模型往返延迟。尤其在长任务或者跑 Eval 测试时,Step 上限很容易被无意义的轮询占满。
> 3. **机制归属问题**
> 让 LLM 在推理循环中充当轮询调度器,感觉把宿主层本该兜底的进程监控职责推给了模型端。
>
> **个人感觉更轻量的思路:** 不知道能否直接在 Maka 的 `Tool Runtime` 底层做优化——当命令执行超时后,由运行时自动转入后台,等进程真正结束时再单次唤醒模型投递结果?这样既彻底解决了前台卡死和 Cache 过期的问题,又不需要模型在中间做主动轮询。
当command在超过yield_time_ms之后,若还是继续执行,应该被注册成background job。这时候的行为其实就开始像Claude Code bash(cmd, background=true)一样被注册成background job。
agent在这种情况下有两件事情可以做:
1.Claude code在没有别的任务执行的时候会进入idle mode,等待命令结束,然后唤醒。聪明点的情况是自己设置一个/loop n 分钟 “alarm" 几分钟的轮训检查。
2. Codex的确会出现反复短轮询write_stdin的情况,聪明点的情况是它能够判断出这个background job可能时间会跑得比较久,write_stdin(..., yield_time_ms)需要设置得久一些。
我认为yield_time_ms+timeout组合是 Codex Shell由于其它agent shell/bash工具的核心,提供了非常灵活且自动转换的foreground + background bash,非常适合做e2e test, interactive cli等任务。但是频繁地write_stdin的确是个问题。我们需要看看能否做到像Claude Code那样在等待background task的时候进入idle模式,这样久不会太多额外步数了
GitHub link: https://github.com/apache/maka/discussions/3342#discussioncomment-18096329
----
This is an automatically sent email for dev@maka.apache.org.
To unsubscribe, please send an email to: dev-unsubscribe@maka.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@maka.apache.org
For additional commands, e-mail: dev-help@maka.apache.org
Re: [D] 将bash工具从Claude Code Style迁移到Codex Style [maka]
Posted by "yifanxuaaa (via GitHub)" <gi...@apache.org>.
GitHub user yifanxuaaa edited a comment on the discussion: 将bash工具从Claude Code Style迁移到Codex Style
> 我也经常遇到命令意外卡死和超时影响 Cache 的情况,这个痛点提得非常及时!
>
> 不过关于把默认工具切到 Codex 风格的 Yield + Poll 模式,结合 Maka 的使用体验,我个人有一点顾虑,想和大家探讨一下:
>
> 1. **对 Event Log 与 UI 时间线的影响**
> Maka 的 Desktop 和 TUI 是基于 Append-only 日志做流式投射与会话回放的。如果长任务频繁调用 `write_stdin` 轮询,日志里会沉淀大量空跳记录,可能会让前端时间线和回放变得很碎。
> 2. **Turn 预算与调用延迟**
> 每多一轮轮询就会额外消耗一次 Turn 预算与模型往返延迟。尤其在长任务或者跑 Eval 测试时,Step 上限很容易被无意义的轮询占满。
> 3. **机制归属问题**
> 让 LLM 在推理循环中充当轮询调度器,感觉把宿主层本该兜底的进程监控职责推给了模型端。
>
> **个人感觉更轻量的思路:** 不知道能否直接在 Maka 的 `Tool Runtime` 底层做优化——当命令执行超时后,由运行时自动转入后台,等进程真正结束时再单次唤醒模型投递结果?这样既彻底解决了前台卡死和 Cache 过期的问题,又不需要模型在中间做主动轮询。
当command在超过yield_time_ms之后,若还是继续执行,应该被注册成background job。
agent在这种情况下有两件事情可以做:
1.Claude code在没有别的任务执行的时候会进入idle mode,等待命令结束,然后唤醒。聪明点的情况是自己设置一个/loop n 分钟 “alarm" 几分钟的轮训检查。
2. Codex的确会出现反复短轮询write_stdin的情况,聪明点的情况是它能够判断出这个background job可能时间会跑得比较久,write_stdin(..., yield_time_ms)需要设置得久一些。
我认为yield_time_ms+timeout组合是 Codex Shell由于其它agent shell/bash工具的核心,提供了非常灵活且自动转换的foreground + background bash,非常适合做e2e test, interactive cli等任务。但是频繁地write_stdin的确是个问题。我们需要看看能否做到像Claude Code那样在等待background task的时候进入idle模式,这样久不会太多额外步数了
GitHub link: https://github.com/apache/maka/discussions/3342#discussioncomment-18096329
----
This is an automatically sent email for dev@maka.apache.org.
To unsubscribe, please send an email to: dev-unsubscribe@maka.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@maka.apache.org
For additional commands, e-mail: dev-help@maka.apache.org
Re: [D] 将bash工具从Claude Code Style迁移到Codex Style [maka]
Posted by "Astro-Han (via GitHub)" <gi...@apache.org>.
GitHub user Astro-Han added a comment to the discussion: 将bash工具从Claude Code Style迁移到Codex Style
**TL;DR**: I recommend against a wholesale migration to the Codex-style tools. After a source-level survey of 10 mainstream agent projects, I believe both the Claude Code style and the Codex style each got half of the problem right, and that there is a third form — **park (the tool call simply doesn't return) + debounce-based output chunking + durable process handles** — that is conceptually smaller than either and lands almost directly on Maka's existing ShellRun skeleton. Below: the full comparison, the reasoning, point-by-point answers to the 5 discussion questions, and an honest list of this proposal's known weaknesses (including a caveat about my own benchmark results).
## 1. The survey: 10 projects fall into three and a half schools
I shallow-cloned and read the current source (2026-08) of codex, pi, grok-build, kimi-code, opencode (v2), hermes-agent, deepseek-harness, prime-agent, lobehub, and deer-flow. All claims are backed by file:line-level evidence:
| Project | Execution model | On timeout | Completion wake-up | stdin/interactivity |
|---|---|---|---|---|
| Codex | yield 10s → session_id, model polls | no kill; return handle | **none; pure polling** | ✓ PTY + write_stdin |
| Pi | pure foreground blocking | kill process tree | none | ✗ |
| grok-build | 15s foreground budget → auto-background | **backgrounded, not killed** | ✓ auto-wake synthetic prompt | TUI-only PTY channel |
| kimi-code | 60s foreground → auto-background (default on) | backgrounded, not killed | ✓ `<notification>` injection | ✗ stdin always closed |
| opencode v2 | foreground blocking + explicit background | kill | ✓ synthetic message + doorbell | ✗ |
| hermes-agent | foreground blocking + explicit background | kill | ✓ completion queue + watch_patterns | ✓ most complete (8 process actions) |
| deepseek-harness | foreground blocking + explicit background (four tool generations coexist) | kill | ✓ jobs registry wakeup | ✓ 6-tool PTY family |
| prime-agent | persistent IPython kernel, blocking cells | kill tree | kernel completion events | ✓ the kernel is a REPL |
| lobehub | 30s observation window | no kill; return shell_id | none; pure polling | ✗ |
| deer-flow | pure foreground blocking | kill process group | none | ✗ (backgrounding is a prompt convention) |
Three and a half schools: **model-driven polling** (Codex, lobehub), **runtime wake-up** (grok, kimi, opencode, hermes, DSH), **pure blocking** (Pi, deer-flow), plus the PTC half-school (prime-agent's persistent kernel, Codex's code mode, DSH's run_code — these three have not converged, so I set PTC aside for now).
Two widely repeated claims need correcting:
1. **"Codex's polling pollutes the transcript" — not quite.** Codex's empty polls never enter the transcript: they surface only in the status bar ("Waiting for background terminal"), consecutive waits collapse into a single wait-streak cell, and duplicate waits are suppressed. Polling noise is a **presentation-layer problem that Codex has already solved** (this directly addresses @cat0825's concern #1).
2. **"DSH is moving toward a workflow + wait two-tool PTC" — inaccurate.** DSH's PTC mode reduces the surface to a single `run_code` tool (TS/Python, worker thread); waiting is carried by `job_output(wait: true)`. The codex-shell plugin referenced in the OP lives in the external dsh-plugins repo, not in deepseek-harness itself.
## 2. Reframing: this is not about tool shape
The original framing of #3342 is "what should the tool look like." With 10 implementations side by side, the essential question emerges: **processes live in wall-clock time; the model lives in discrete steps — who absorbs the waiting in between?** There are only three candidates:
- **Model polls**: every glance at the clock = one full request = one cache payment + one round trip;
- **Runtime blocks**: waiting is free for the runtime (an epoll event), but unbounded blocking deadlocks on processes waiting for input;
- **Runtime waits + wakes the model**: looks like the best of both — see §3.
The model is the only actor in the system that pays to check the time. So the default path should never have the model doing the waiting — both camps agree this far. The disagreement is how the runtime hands control back.
## 3. Diagnosis of both routes (including a correction to my own initial conclusion)
**The Codex route (polling)**: for the same wait duration, polling strictly costs more requests than any runtime-owned scheme — it is a dominated strategy. The only thing it buys is intervenability, and intervenability comes from the handle, not from making polling the default. What is genuinely worth absorbing from Codex is **yield does not change process semantics** (@me2seeks's distinction in this thread is exactly right): yielding only returns control to the agent; the process is still the same process, not implicitly converted into something else by elapsed time. That property must be preserved.
**The wake-up route (grok/kimi/opencode, and @cat0825's lightweight variant)**: I initially believed this was optimal, and have since corrected myself. Note one survey fact: **every project that ships wake-ups was forced to build concurrency machinery** — grok has admission control against wake storms, kimi has three-set exactly-once dedup, DSH has maxConsecutiveWakes against self-excitation. This is not a coincidence; it is evidence that wake-up is inherently a concurrency problem: the arrival time is decided by an external process, arrival while the agent is busy forces queueing, queueing makes it late, and lateness destroys the value of waking. Wake-up as the *default* continuation costs an entire admission/dedup/synthetic-message apparatus as its entry fee.
(I previously argued wake-ups are expensive because of cold-cache re-encoding; I withdraw that argument: cache renewal is a problem every design faces and does not differentiate them. Noting this for honesty.)
## 4. My proposal: park + debounce chunking + handle
**Park**: the tool call does not return; the runtime suspends the agent loop; when a boundary is reached, the result is filled into *the same* tool call. From the model's perspective this is pure blocking — but it is not a new mechanism: **"the tool call hasn't returned yet" is already a native concept of the agent loop**. Zero new abstractions. Compare: polling teaches the model to be a scheduler; wake-up requires a concurrency apparatus; park builds nothing.
**Debounce chunking**: park is not unbounded. The tool call returns at `exit ∨ no new output for K seconds ∨ park-lease expiry`. K is a runtime constant (1–3s), invisible to the model. Why not a time budget: (a) models cannot estimate durations — Codex clamping yield_time_ms to 250ms–30s is a confession; (b) "output stopped" is a direct observation of "nothing left to learn," while "how long it has run" is only a guess; (c) processes waiting for input (REPL prompts, device-code, ssh yes/no) share exactly one trait — output stops. **Debounce turns "interactive deadlock" from a special case into the normal path**: K seconds after the prompt prints, the model comes back holding that prompt text and answers it through the handle. This design's vocabulary contains no time concepts at all: no timeout, no yield_ms, no wait.
**Handle**: a ref plus three verbs. The key one: **calling read on a running ref parks until the next output chunk** — this is the embodiment of "keep waiting," and the entry point for an "explicit waiter" (wake-up can therefore safely respond only to explicit subscriptions, never by default). There is no background concept: every process has a durable ref from birth; early return does not change process semantics, only who is watching.
The tool surface converges to:
```
run(command, cwd?, pty?) → {ref, state, output} // constant shape; ref always returned
process(ref, read(offset?, limit?) | write(bytes) | stop)
```
5 core concepts (command/cwd/ref/read/stop) + 2 pluggable ones (pty/write can live in a profile/extension — Pi's interactive-shell extension proves this path). Each surviving concept earns its place by naming something the command string cannot express, or something whose expression would blind the permission/audit system.
**This is closer to Maka's current state than it looks**: the existing Bash + WriteStdin + StopBackgroundTask + Read(ref) skeleton is all there. The changes are semantic tightening, not additions — replace timeout_ms with debounce chunking (without killing the process), decouple pty from run_in_background, unify the return shape.
## 5. Point-by-point answers to the 5 discussion questions
1. **Switch the default tools to exec_command + write_stdin?** No. Polling is a dominated strategy; the part of Codex worth absorbing is the yield semantics, which the proposal above absorbs.
2. **Keep the old bash tool as an option, or replace it entirely?** Unify into the single form above (one tool surface, constant return shape). Two coexisting tracks force the model to make a mode choice it is bad at, on every call.
3. **Impact on prompts / tool-call habits?** The new form has *fewer* concepts for the model to learn (no time parameters, no background judgment). The main migration point: "don't pre-judge long commands; just run them, the runtime will chunk."
4. **Tuning yield_time_ms, max_output_tokens, session lifecycle?** These parameters do not exist in my proposal. K (the debounce window) is a runtime constant, invisible to the model — models' duration estimates are uncalibratable, so they should not be given the knob.
5. **Risks and missing capabilities (kill, timeout, resource limits)?** kill (process-group signal ladder, already present), resource limits (slot caps, already present), timeout — replaced by "lease + debounce + no kill."
## 6. Honest cost list (known weaknesses of this proposal)
To avoid this reading like armchair design, here are the real costs I verified against Maka's source:
- **Progress-bar blind spot**: under PTY, periodic redraws (npm/cargo/docker-style) never go quiet for K seconds; debounce never fires and the boundary falls back to the park lease. Debounce's effective domain and PTY's effective domain are complementary, not overlapping.
- **"User message demotes a park" needs a new channel**: steering currently drains at step boundaries; a park sits mid-step. Demotion requires agent-loop surgery, not a small shell-layer change.
- **The agent is dead between turns**: completion notices piggyback on the next model request; if the turn has ended and the user has left, a process dying at 3am is known to no one. Scenarios that genuinely need proactive reporting belong to a scheduler/automation layer, not to the shell's default behavior.
- **PTY read semantics differ from pipes**: the PTY side stores a rendered screen grid, not a byte stream; offset pagination is undefined for PTY refs.
- **The append-only tax**: historical `timed_out` events must be supported by projections forever; the Eval headless profile freezes the current schema (hash-pinned), so changing the shell requires a formal decision for Eval.
## 7. Open question: I doubt my own benchmark attribution
My internal comparison shows Codex mode performing better with GLM-5.2 and DSv4F — **but I cannot rule out post-training familiarity** (these models' tool-call traces have likely seen Codex-style interaction extensively) rather than an architectural advantage. The ablation I plan: keep the schema in Codex form, change only the runtime behavior (block-to-completion vs. debounced early return), single model (DSv4F), long-command task subset. If identical schemas with different runtimes still diverge, the yield checkpoint itself carries value. Challenges to this experiment design are welcome.
**One final note**: everything above is a position, not a verdict — I may well be wrong. If you see a formulation that is more Occam-lean or closer to the fundamentals, I genuinely want to hear it. Pushback and challenges are very welcome.
---
*Methodology disclosure: this reply is based on AI-assisted source-level research across the 10 repositories above (multiple read-only research agents collecting file:line evidence in parallel), and the proposal was revised through two adversarial review rounds with external models (Claude, Codex CLI).*
<details>
<summary><strong>简体中文</strong></summary>
**TL;DR**:我不建议整体迁移到 Codex 风格。我调研了 10 个主流 agent 项目的 shell 工具源码后认为,CC 风格和 Codex 风格各自只答对了一半,还存在第三种形态——**park(tool call 停着不返回)+ 防抖切段 + 持久 handle**——它在概念数上比两者都少,并且正好落在 Maka 已有的 ShellRun 骨架上。下面附完整对比、推理过程、对 5 个讨论点的逐条回答,以及这套方案已知的坑(含对我自己 benchmark 结果的诚实存疑)。
## 1. 先放调研:10 家其实分成了三个半流派
我浅克隆并源码调研了 codex、pi、grok-build、kimi-code、opencode(v2)、hermes-agent、deepseek-harness、prime-agent、lobehub、deer-flow 的最新版本(2026-08),所有结论均有 file:line 级证据:
| 项目 | 执行模型 | 超时后 | 完成唤醒 | stdin/交互 |
|---|---|---|---|---|
| Codex | yield 10s → session_id,模型轮询 | 不杀,返回 handle | **无,纯轮询** | ✓ PTY + write_stdin |
| Pi | 纯前台阻塞 | kill 进程树 | 无 | ✗ |
| grok-build | 前台 15s 自动转后台 | **转后台不杀** | ✓ auto-wake 合成 prompt | TUI 有独立 PTY |
| kimi-code | 前台 60s 自动转后台(默认开) | 转后台不杀 | ✓ `<notification>` 注入 | ✗ stdin 永闭 |
| opencode v2 | 前台阻塞 + 显式 background | kill | ✓ synthetic 消息 + doorbell | ✗ |
| hermes-agent | 前台阻塞 + 显式后台 | kill | ✓ completion queue + watch_patterns | ✓ 最完整(8 个 process 动作) |
| deepseek-harness | 前台阻塞 + 显式后台(四代工具并存) | kill | ✓ jobs 注册表 wakeup | ✓ PTY 六件套 |
| prime-agent | IPython 内核阻塞执行 | kill 树 | 内核完成事件 | ✓ 内核即 REPL |
| lobehub | 30s 观察窗 | 不杀,返回 shell_id | 无,纯轮询 | ✗ |
| deer-flow | 纯前台阻塞 | 杀进程组 | 无 | ✗(后台化是 prompt 约定) |
三个半流派:**模型轮询**(Codex、lobehub)、**runtime 唤醒**(grok、kimi、opencode、hermes、DSH)、**纯阻塞**(Pi、deer-flow),外加 PTC 那半个(prime-agent 的常驻内核、Codex 的 code mode、DSH 的 run_code——这三家形态还没收敛,先不展开)。
两个流传较广的说法需要纠正:
1. **"Codex 的轮询会污染 transcript"——不完全对**。Codex 的空轮询不进 transcript:只在状态栏显示 "Waiting for background terminal",连续 wait 折叠成单个 wait-streak cell,重复 wait 直接抑制。轮询噪音在 Codex 那里是**表示层问题且已被解决**(这直接回应 @cat0825 的顾虑 1)。
2. **"DSH 在向 workflow + wait 两工具的 PTC 演进"——不准确**。DSH 的 PTC mode 是只剩单一 `run_code`(TS/Python,worker thread),wait 语义由 `job_output(wait:true)` 承担;原帖提到的 codex-shell 插件在外部仓库 dsh-plugins,不在 deepseek-harness 本体。
## 2. 问题的重新表述:这不是工具形状之争
#3342 的原始 framing 是"工具长什么样"。但把 10 家摆在一起后,本质问题浮现出来:**进程跑在墙钟时间里,模型活在离散的步里,中间这段等待由谁消化?**候选只有三个:
- **模型轮询**:模型每"看一次表" = 一次完整请求 = 一次 cache 付费 + 一次往返;
- **runtime 阻塞**:等待对 runtime 免费(一个 epoll 事件),但无界阻塞会死在等输入的进程上;
- **runtime 等待 + 到点叫醒**:看起来两全,但见第 3 节。
模型是系统里唯一"看表要花钱"的角色。所以默认路径上不该由模型来等待——这一点两家的共同结论是一致的,分歧在 runtime 等完之后怎么交棒。
## 3. 对两条路线的诊断(含对我自己初步结论的修正)
**Codex 风格(轮询)**:在相同等待时长下,轮询的请求数严格多于任何 runtime 方案——它是被支配策略。它唯一买到的是"可干预性",而可干预性用 handle 就能获得,不需要把轮询设为默认。Codex 真正值得吸收的不是轮询,是 **yield 不改变进程语义**(@me2seeks 在楼里的区分完全成立):yield 只是把控制权还给 agent,进程还是那个进程,没有因为"超时"被隐式转成别的东西——这条必须保留。
**唤醒路线(grok/kimi/opencode,以及 @cat0825 的轻量方案)**:我一度也认为这是最优解,后来修正了。注意一个调研事实:**每一家做唤醒的都被迫配了并发机器**——grok 有 admission 控制防唤醒风暴、kimi 有三集合 exactly-once 去重、DSH 有 maxConsecutiveWakes 防自激励。这不是巧合,是"唤醒本质是个并发问题"的证据:唤醒到达时刻由外部进程决定,到达时 agent 正在做别的事就要排队,排队就不及时,不及时唤醒的价值就塌了。唤醒作为默认 continuation,入场费是一整套 admission/dedup/合成消息机器。
(我曾用"冷缓存重编码"论证唤醒贵,后来自己撤回了:缓存续期是所有方案共同面对的问题,不构成方案间的区分度。诚实起见注明这一点。)
## 4. 我的提案:park + 防抖切段 + handle
**park**:tool call 不返回,runtime 挂起 agent loop,边界到达时把结果填进同一个 tool call。模型视角 = 纯阻塞,但它不是新机制——**"工具调用还没返回"本来就是 agent loop 的原生概念**,零新抽象。对比:轮询要教模型当调度器,唤醒要造一整套并发机器,park 什么都不造。
**防抖切段(debounce)**:park 不是无界的。tool call 的返回边界是 `退出 ∨ 输出停顿 K 秒 ∨ 租约上限`。K 是 runtime 常量(1–3s),模型不可见。为什么不是时间预算:(a) 模型不会估时长——Codex 把 yield_time_ms clamp 到 250ms–30s 就是供词;(b) "输出停了"是"没什么可学的了"的直接观测,"跑了多久"只是猜测;(c) 等输入的进程(REPL 提示、device-code、ssh yes/no)的共同特征就是输出停了——**防抖把"交互死锁"从特例变成常态路径**:停顿 K 秒后,模型拿着那行提示文本回来,用 handle 回答它。这个设计的词汇表里没有任何时间概念:没有 timeout,没有 yield_ms,没有 wait。
**handle**:ref + 三个动词。关键一条:**对 running 的 ref 调 read 时默认 park 到下一个输出段**——这就是"我继续等"这句话的实体,也是"显式 waiter"的入口(唤醒因此可以安全地只响应显式订阅,不当默认)。没有 background 概念:进程从出生就有 durable ref,提前返回不改变进程语义,只改变谁在看。
工具面收敛为:
```
run(command, cwd?, pty?) → {ref, state, output} // 形状恒定,永远给 ref
process(ref, read(offset?, limit?) | write(bytes) | stop)
```
5 个核心概念(command/cwd/ref/read/stop)+ 2 个可插拔(pty/write 可作为 profile/扩展承载,Pi 的 interactive-shell 扩展证明这条路可行)。每个概念留下的理由是它命名了命令字符串表达不了、或表达出来会让权限/审计系统变瞎的东西。
**这套方案与 Maka 现状的距离比想象近**:现有 Bash + WriteStdin + StopBackgroundTask + Read(ref) 骨架都在,改动是语义收紧而非新增——timeout_ms 换成防抖切段(进程不杀)、拆掉 pty⇒run_in_background 耦合、统一返回形状。
## 5. 对原帖 5 个讨论点的逐条回答
1. **是否切换默认工具到 exec_command + write_stdin**:不建议。轮询是被支配策略;Codex 该吸收的零件是 yield 语义,已被上面的方案吸收。
2. **保留旧 bash 还是完全替换**:建议统一成上面的形态(单工具面、恒定返回形状),不做双轨。双轨 = 模型每次调用都要做一次它不擅长的模式选择。
3. **对 prompt/工具调用习惯的影响**:新形态里模型需要学习的概念反而更少(无时间参数、无 background 判断);主要迁移点是"长命令不用预判,直接跑,runtime 会分段"。
4. **yield_time_ms 等参数调优**:在我的方案里这些参数不存在。K(防抖窗口)是 runtime 常量,模型不可见——模型对时长的估计不可校准,不该给它这个旋钮。
5. **风险与补充能力**:kill(进程组信号阶梯,现有)、资源限制(slot 上限,现有)、timeout——被"租约 + 防抖 + 不杀进程"替代。
## 6. 诚实的代价清单(这套方案已知的坑)
为避免这看起来像纸上谈兵,列出我拿 Maka 源码核实过的真实代价:
- **进度条盲区**:PTY 下 npm/cargo 类周期重绘永远不停顿 K 秒,防抖失效,退化到租约上限。防抖的有效域和 PTY 的有效域是互补的,不是重叠的。
- **"用户新消息打断 park"需要新建通路**:当前 steering 在 step 边界 drain,park 在 step 中途——降级要修 agent loop,不是 shell 层的小改。
- **turn 之间 agent 是死的**:完成通知搭车在下一次模型请求上;turn 结束用户离开后,进程半夜崩了没人知道。真的需要主动汇报的场景应归 scheduler/automation 层,不是 shell 的默认行为。
- **PTY 的 read 语义与 pipe 不统一**:PTY 侧存的是屏幕 grid 不是字节流,offset 分页对 PTY ref 无定义。
- **append-only 的税**:timeout_ms 的历史事件永远要在投射层支持;Eval 的 headless profile 冻结了现有 schema(带 hash),改 shell 需要给 Eval 一个正式说法。
## 7. 开放问题:我对自己的 benchmark 归因存疑
我内部的对比实验显示 Codex 模式在 GLM-5.2 和 DSv4F 上表现更好——**但我不能排除这是后训练熟悉度**(这两个模型的 tool-call 轨迹大概率大量见过 Codex 风格交互),而非架构本身的优势。我计划的消融实验:schema 保持 Codex 形态不变,只改 runtime 行为(阻塞到底 vs 防抖提前返回),DSv4F 单模型、长命令任务子集。如果 schema 相同而 runtime 不同仍产生差异,才能说明 yield 检查点本身有价值。欢迎对这个实验设计的挑战。
**最后说明**:以上只是一家之言,未必对。如果你看到更符合奥卡姆剃刀、更贴近问题本质的方案,我非常希望看到——欢迎 push back 和挑战。
---
*调研方法披露:本回复基于对上述 10 个仓库最新源码的 AI 辅助调研(多个只读研究 agent 并行取证,所有论断带 file:line 引用),方案经两轮外部模型对抗评审(Claude、Codex CLI)修正。*
</details>
GitHub link: https://github.com/apache/maka/discussions/3342#discussioncomment-18097308
----
This is an automatically sent email for dev@maka.apache.org.
To unsubscribe, please send an email to: dev-unsubscribe@maka.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@maka.apache.org
For additional commands, e-mail: dev-help@maka.apache.org