猫咖
首页博客工具
搜索
语言
切换网站风格
选择主题颜色
点击特效
主题

猫咖 · 持续更新中,源码见 GitHub。

Index 05: TodoWrite — 让智能体先计划后执行

2026年7月30日
AI智能体Kotlin后端

系列

使用Kotlin从0开发一个ClaudeCode技术文章

系列

使用Kotlin从0开发一个ClaudeCode

进度 5 / 21

使用Kotlin从0开发一个ClaudeCode

上一篇

Index 04: Hooks — 给工具链装上前后扩展点

下一篇

Index 06: Subagent — 异步后台子智能体

目标

s01 到 s04 让智能体从"只会说话"成长为"能读会写、安全可控、可观测的工具调用系统"。但接到一个多步骤任务时,它仍然是"走一步看一步"——读个文件、改两行、再读、再改。中间没有"我接下来要做什么"的概念。

Index 05 的目标是给智能体装上规划能力:

  1. 定义 TodoItem 极简数据模型——content + status 三态(pending / in_progress / completed)
  2. 实现 TodoStore 全局单例存储——线程安全,整体替换语义
  3. 实现 TodoWriteTool 工具——让 LLM 通过 tool_use 显式更新待办列表
  4. 接入 ReplLoop——注册工具、/clear 清空待办
  5. AgentLoop 零修改——TodoWriteTool 是普通 Tool,自然被 ToolRegistry 发现和调度

完成后的效果——智能体接到复杂任务时,会先调用 todo_write 列计划:

TEXT
> 帮我给 UserService.kt 加上日志,并修复 getUserById 的 NPE

[Agent 调用 todo_write 创建 3 项待办]
Todo list updated (0/3 completed, 1 in progress, 2 pending):
  1. [~] Read UserService.kt
  2. [ ] Add logging to all public methods
  3. [ ] Fix NPE in getUserById

[Agent 调用 read_file]
[Agent 调用 todo_write 更新:第 1 项完成,第 2 项 in_progress]
Todo list updated (1/3 completed, 1 in progress, 1 pending):
  1. [x] Read UserService.kt
  2. [~] Add logging to all public methods
  3. [ ] Fix NPE in getUserById

LLM 自己维护进度,用户也看得到全貌。


架构:最小闭环的"计划本"

Index 05 在 s02-s04 的工具链路上增加了一个"内存记事本"——它是普通工具,没有特殊地位:

TEXT
                    用户输入 "帮我重构 X"
                              │
                              ▼
                    ┌──────────────────┐
                    │   AgentLoop      │
                    │  messagesHistory │
                    └──┬─────────────┘
                       │ LLM 决定调用 todo_write
                       ▼
            ┌──────────────────────────────────┐
            │   executeOneTool (s02-s04 链路)    │
            │                                    │
            │  ① Permission (s03) ──── 放行     │
            │  ② PreToolUse Hook (s04) ─ 放行    │
            │  ③ TodoWriteTool.execute          │
            │       │                            │
            │       ▼                            │
            │     TodoStore.replaceAll(items)   │
            │       │                            │
            │       ▼                            │
            │     返回状态概览文本                │
            │  ④ PostToolUse Hook (s04) ─ 透传   │
            └──────────────────────────────────┘
                       │
                       ▼
            tool_result 进入 messagesHistory
            LLM 下一轮能看到当前 todo 状态

关键洞察:TodoWriteTool 与 ReadFileTool / WriteFileTool / BashTool 是同辈工具。它没有任何"特殊通道"——穿过同一个 Permission 管线,经过同一组 Pre/Post hooks,由同一个 AgentLoop 调度。唯一不同的是它修改的是内存状态而非文件系统。

层Index 04 状态Index 05 变更
数据模型—TodoItem (content + status) + TodoStatus 枚举
存储—TodoStore 全局单例(CopyOnWriteArrayList)
工具3 个内置+TodoWriteTool(isReadOnly=false)
智能体AgentLoopHooks 已稳定零修改
REPL欢迎语 Index 04注册 TodoWriteTool + /clear 清空 TodoStore

第一层:数据模型

TodoItem——极简三字段

KOTLIN
data class TodoItem(
    val content: String,
    val status: TodoStatus = TodoStatus.PENDING
)

enum class TodoStatus { PENDING, IN_PROGRESS, COMPLETED }

为什么这么简?因为 s05 阶段没有持久化(CLAUDE.md 决策 4:内存存储优先),也不需要排序——LLM 用数组下标定位。加了 id / priority / createdAt 都是"为未来预留",违反 CLAUDE.md "严格迭代,不做预留" 原则。

没有状态机校验:理论上"同时只能一个 IN_PROGRESS"是合理的约束,但 TodoStore 不强制。原因有二:

  1. 校验会让 TodoWriteTool 变成有状态工具,错误处理复杂
  2. LLM 在 system prompt 引导下基本能自律,过度校验反而误伤合法场景

未来 s07 Skill Loading 阶段若引入更复杂的规划模式,再加状态机不迟。


第二层:存储

TodoStore——全局单例 + CopyOnWriteArrayList

KOTLIN
object TodoStore {
    private val items: CopyOnWriteArrayList<TodoItem> = CopyOnWriteArrayList()

    fun replaceAll(newItems: List<TodoItem>) {
        items.clear()
        items.addAll(newItems)
    }

    fun getAll(): List<TodoItem> = items.toList()  // 快照副本
    fun clear() { items.clear() }
    fun inProgressCount(): Int = items.count { it.status == TodoStatus.IN_PROGRESS }
    fun completedCount(): Int = items.count { it.status == TodoStatus.COMPLETED }
    fun size(): Int = items.size
}

参考 s02 的 ToolRegistry 单例风格——Index 05-11 阶段使用全局 object,s06 Subagent 需要多实例隔离时再改为 class + 注入(ToolRegistry.kt:9 的注释已经预告了这个演进)。

为什么用 CopyOnWriteArrayList?

  • s02 AgentLoop 已支持工具并发调用——读操作(read_file)会并行执行
  • TodoWriteTool 的 isReadOnly=false 让它走串行分支,理论上不会被并发调用
  • 但 TodoStore 作为全局可变状态,仍需防御未来直接调用场景(s06 Subagent、自定义 hook 等)
  • 读多写少场景下 CopyOnWriteArrayList 读路径无锁,性能优于 synchronizedList

为什么 getAll() 返回 toList() 副本?

KOTLIN
"getAll returns a snapshot copy that external mutation cannot affect" {
    TodoStore.replaceAll(listOf(TodoItem("Original", TodoStatus.PENDING)))
    val snapshot = TodoStore.getAll()
    // 尝试修改快照——toList() 返回不可变 List,add 抛 UnsupportedOperationException
    (snapshot as? MutableList<TodoItem>)?.add(TodoItem("Hijacked", TodoStatus.COMPLETED))

    TodoStore.size() shouldBe 1  // 内部状态不变
    TodoStore.getAll()[0].content shouldBe "Original"
}

这是不可变契约——外部拿到的 List 不能反向影响内部状态。CopyOnWriteArrayList.toArray() 本就返回新数组,但 toList() 包一层更明确语义并返回 Kotlin 不可变 List 视图。

整体替换语义:replaceAll 是核心写方法,每次调用覆盖整个列表,不合并、不增量。这与 Anthropic 官方 TodoWrite 工具的设计一致——LLM 不需要记住"上次写到哪了",每次传完整数组即可。简单、无状态冲突。


第三层:TodoWriteTool

工具签名

KOTLIN
class TodoWriteTool : Tool {
    override val name = "todo_write"
    override val description = "Update the todo list (plan before executing, track progress)"
    override val isReadOnly = false  // 修改内存状态,串行执行
    override val jsonSchema: JsonObject = ...
    override suspend fun execute(input: JsonObject): ToolResult
}

与 WriteFileTool / BashTool 完全平行——没有特殊接口、没有特殊处理。

isReadOnly = false 的含义:s02 AgentLoop 的 executeTools 按 isReadOnly 分组——读操作并行,写操作串行。TodoWriteTool 标记为写操作,避免与自身并发覆盖(虽然 TodoStore 本身并发安全,但语义上待办列表更新应有序)。

JSON Schema 结构

JSON
{
  "name": "todo_write",
  "description": "Use this tool to create and update a todo list ...",
  "input_schema": {
    "type": "object",
    "properties": {
      "todos": {
        "type": "array",
        "description": "Complete list of todos (replaces existing list)",
        "items": {
          "type": "object",
          "properties": {
            "content": { "type": "string" },
            "status": {
              "type": "string",
              "enum": ["pending", "in_progress", "completed"]
            }
          },
          "required": ["content", "status"]
        }
      }
    },
    "required": ["todos"]
  }
}

description 引导 LLM "先计划后执行":在工具 description 里明确写 "Plan before executing multi-step tasks, then update statuses as you progress"——配合 systemPrompt 形成双重引导。这是让 LLM "会用"工具的关键。

execute 执行逻辑

KOTLIN
override suspend fun execute(input: JsonObject): ToolResult {
    // 1. 取 todos 数组(runCatching 防御类型不匹配)
    val todosArray = ...
        ?: return ToolResult("", "Error: todos is required and must be an array", isError = true)

    // 2. 逐项解析并校验——错误消息带 todos[$index] 位置
    val parsed = mutableListOf<TodoItem>()
    for ((index, element) in todosArray.withIndex()) {
        val obj = runCatching { element.jsonObject }.getOrNull()
            ?: return ToolResult("", "Error: todos[$index] must be an object", isError = true)

        val content = runCatching { obj["content"]?.jsonPrimitive?.content }.getOrNull()
            ?: return ToolResult("", "Error: todos[$index].content is required and must be a string", isError = true)

        val statusStr = runCatching { obj["status"]?.jsonPrimitive?.content }.getOrNull()
            ?: return ToolResult("", "Error: todos[$index].status is required and must be a string", isError = true)

        val status = parseStatus(statusStr)
            ?: return ToolResult("", "Error: todos[$index].status '$statusStr' is invalid; must be one of: pending, in_progress, completed", isError = true)

        parsed.add(TodoItem(content = content, status = status))
    }

    // 3. 整体替换存储
    TodoStore.replaceAll(parsed)

    // 4. 返回状态概览文本
    return ToolResult("", buildSummary(parsed))
}

关键设计要点:

  1. 逐项精确报错:错误消息带 todos[$index],LLM 自我修正时知道改哪一项
  2. runCatching 包裹类型转换:kotlinx.serialization 的 jsonObject / jsonPrimitive 在类型不匹配时抛异常,必须防御
  3. 失败时不部分写入:解析阶段先收集到 parsed 临时列表,全部通过后才 replaceAll——避免半成功状态
  4. status 大小写不敏感:parseStatus 用 value.lowercase(),LLM 写 "IN_PROGRESS" 也能解析
  5. toolCallId 返回空字符串:AgentLoop.executeOneTool 会自动用真实 id 覆盖(s02 既有约定,参考 WriteFileTool)

返回的状态概览

TEXT
Todo list updated (1/3 completed, 1 in progress, 1 pending):
  1. [x] Read UserService.kt
  2. [~] Add logging to all public methods
  3. [ ] Fix NPE in getUserById

人类可读格式,LLM 单次调用即可看到全貌,无需额外查询工具。[x] [~] [ ] 三个标记借鉴 git diff 的视觉风格。

空数组时返回 "Todo list cleared."——明确语义,不是错误。


ReplLoop 集成

三处修改

KOTLIN
// 1. 注册工具(start() 内)
ToolRegistry.register(ReadFileTool())
ToolRegistry.register(WriteFileTool())
ToolRegistry.register(BashTool())
ToolRegistry.register(TodoWriteTool())  // 新增

// 2. /clear 命令清空 TodoStore
CMD_CLEAR, CMD_C -> {
    agentLoop.messagesHistory.clear()
    approvalStore.clear()
    TodoStore.clear()  // 新增
    logger.info {"Conversation history, permission memory, and todo list cleared"}
    println("Conversation history, permission memory, and todo list cleared.")
    true
}

// 3. 欢迎语
println("🐱 Cat-Code — Index 05: TodoWrite")

为什么 /clear 要清空 TodoStore?

用户输入 /clear 表示要"重新开始"——待办列表应随之清空,否则下次对话 LLM 看到陈旧待办,可能基于已完成任务继续推理。与 ApprovalStore 一起 clear,保持"清空所有可变状态"的一致语义。

这与 s04 LoggingHook(无状态)不同——TodoStore 是有状态存储,必须显式清理。


测试策略

遵循 s02-s04 的 Fake 模式,不引入 mock 框架。直接调用 TodoStore.clear() 做测试隔离,与 ToolRegistry.clear() 风格一致。

TodoStoreTest(12 用例)

TEXT
replaceAll stores given items                                  ✓
replaceAll with empty list clears existing items               ✓
replaceAll is idempotent when called twice with same input     ✓
replaceAll overwrites previous items completely                ✓
getAll returns empty list by default                           ✓
getAll returns a snapshot copy that external mutation cannot affect ✓
clear empties all items                                        ✓
clear on empty store is no-op                                  ✓
inProgressCount returns count of IN_PROGRESS items             ✓
completedCount returns count of COMPLETED items                ✓
size returns total count                                       ✓
replaceAll is thread-safe under concurrent writes             ✓

并发测试:50 个协程并发调用 replaceAll,最终状态应是某次完整写入的结果(不出现部分覆盖):

KOTLIN
"replaceAll is thread-safe under concurrent writes" {
    runBlocking {
        coroutineScope {
            (1..50).map { i ->
                async {
                    TodoStore.replaceAll(listOf(TodoItem("item-$i", TodoStatus.COMPLETED)))
                }
            }.awaitAll()
        }
    }
    TodoStore.size() shouldBe 1  // 最终是某次完整写入的结果
    TodoStore.getAll()[0].content shouldStartWith "item-"
}

TodoWriteToolTest(12 用例)

TEXT
execute replaces todo store with given items                   ✓
execute returns summary containing status overview             ✓
execute with empty todos array clears the store                ✓
execute returns error when todos is missing                   ✓
execute returns error when todos is not an array               ✓
execute returns error when todo item is not an object          ✓
execute returns error when content is missing                  ✓
execute returns error when status is missing                   ✓
execute returns error when status value is invalid            ✓
execute accepts status case-insensitively                      ✓
execute replaces previous list completely                     ✓
execute reports error index correctly for second item          ✓

AgentLoopTest 集成测试(+3 用例)

TEXT
run updates TodoStore when LLM calls todo_write                ✓
run passes todo_write tool definition to LLM                  ✓
run does not modify TodoStore when tool execution is blocked  ✓

第三个测试特别重要——通过 s04 的 onPreToolUse hook 阻止工具执行,验证 TodoStore 未被修改。这证明了 s04 的 Hook 系统对 s05 工具有效,两层架构协同工作。

afterTest 隔离扩展

KOTLIN
afterTest {
    ToolRegistry.clear()
    TodoStore.clear()  // 新增
}

跨测试用例不能污染——每个测试都应从空 TodoStore 开始。


关键设计取舍

决策点选择理由
TodoStore 并发容器CopyOnWriteArrayList读多写少,读路径无锁;防御未来直接调用场景
getAll 返回类型List(toList 副本)防外部修改内部状态,不可变契约
TodoWriteTool.isReadOnlyfalse修改内存状态,串行执行避免自覆盖
ToolResult 返回内容状态概览文本LLM 单次调用即可见全貌,无需二次查询
TodoWriteTool 包路径tool/tools/与 3 个内置工具一致;todo/ 只放纯领域模型
TodoItem 字段content + status(默认 PENDING)极简,未来 s09 Memory/s12 持久化时再扩
状态机校验不做LLM 自律,避免过度工程化
/todo REPL 命令不加TodoStore 是工具内部状态,不对用户暴露
toolCallId 填充返回 "",AgentLoop 自动覆盖s02 既有约定
TodoStore 扩展点object 单例,s06 重构为 class遵循"严格迭代",不为未来预留抽象
解析失败处理不部分写入收集到 parsed 临时列表,全部通过后才 replaceAll

踩坑记录

1. kotlinx.serialization 的类型转换会抛异常

最初写 input["todos"]?.jsonArray,但 jsonArray 是扩展属性,类型不匹配时直接抛 IllegalStateException,不会返回 null:

KOTLIN
// ❌ 类型不匹配时抛异常
val todosArray = input["todos"]?.jsonArray

// ✅ runCatching 防御
val todosElement = input["todos"]
val todosArray = when {
    todosElement == null -> null
    else -> runCatching { todosElement.jsonArray }.getOrNull()
}

同样 element.jsonObject 和 obj["content"]?.jsonPrimitive?.content 都需要 runCatching 防御。LLM 传入畸形 JSON 时不能让整个 AgentLoop 崩溃。

2. toList() 返回不可变 List,as? MutableList 会失败

最初的测试写法:

KOTLIN
@Suppress("UNCHECKED_CAST")
(snapshot as? MutableList<TodoItem>)?.add(TodoItem("Hijacked", TodoStatus.COMPLETED))

发现 as? MutableList 实际上会成功(返回非 null),但调用 add 抛 UnsupportedOperationException——因为 Kotlin 的 toList() 返回的是 Arrays.asList() 包装的不可变视图。

修正后的测试:捕获 UnsupportedOperationException 即可,这正是"外部无法修改"的预期行为。

3. TodoWriteTool 不需要注入 TodoStore

最初考虑用构造函数注入 TodoStore 实例:

KOTLIN
class TodoWriteTool(private val store: TodoStore = TodoStore) : Tool { ... }

但 TodoStore 是 object 单例,无法作为类型参数传递。若改成 class 又违反"严格迭代"原则——s05 阶段没有多实例需求。

最终决定:TodoWriteTool 直接引用 TodoStore 全局单例,与 WriteFileTool 直接调用 File() 风格一致。s06 Subagent 重构时再抽接口。

4. 测试失败的错误消息要带位置

最初写的错误消息:

KOTLIN
return ToolResult("", "Error: status is required", isError = true)

LLM 看到 "status is required" 不知道是哪一项的 status 缺失。改为带 todos[$index]:

KOTLIN
return ToolResult("", "Error: todos[$index].status is required and must be a string", isError = true)

LLM 自我修正时能直接定位到 todos[1].status,效率高很多。

5. UI 展示逻辑不该混入 AgentLoop 组装代码

最初实现"todo_write 后展示给用户"时,直接在 ReplLoop 的 onPostToolUse lambda 里硬编码:

KOTLIN
// ❌ 三个问题
onPostToolUse = { tc, result ->
    val finalResult = hookManager.firePostToolUse(tc, result)
    if (tc.name == "todo_write" && !finalResult.isError) {  // ① 字符串硬编码
        println()                                            // ② 硬编码 println
        println(finalResult.content)
        println()
    }
    finalResult
}

问题:

  1. 字符串硬编码工具名——"todo_write" 重复了 TodoWriteTool.name 的真相,后续改名要同步两处
  2. 展示逻辑与组装混杂——ReplLoop 同时承担"组装 AgentLoop"和"UI 展示"职责
  3. 硬编码 println 无扩展性——无法测试展示行为,也无法被其他场景(GUI、日志面板)复用

重构方案——抽取 TodoDisplayHook,与 LoggingHook / TimingHook 同辈:

KOTLIN
// ✅ 优雅版本
class TodoDisplayHook(
    private val output: (String) -> Unit = { msg -> println(msg) }  // 注入便于测试
) {
    fun registerTo(manager: HookManager) {
        val handler: HookHandler = handler@{ event ->
            if (event.toolCall.name != TodoWriteTool.NAME) {  // 引用常量
                return@handler HookResult.Continue
            }
            // ...输出概览...
            HookResult.Continue  // 不替换 result
        }
        manager.on(HookEvent.Type.POST_TOOL_USE, handler)
    }
}

// ReplLoop 只需一行注册
TodoDisplayHook().registerTo(hookManager)

关键设计:

  • TodoWriteTool.NAME 常量:companion object 暴露 const val NAME = "todo_write",消除字符串硬编码
  • 依赖方向合法:TodoDisplayHook 放在 todo/ 包,依赖 hooks + tool 单向;若放 hooks/builtins/ 会反向依赖 todo 包
  • output 函数注入:默认 println,测试可注入 mutableListOf<String>() 收集输出
  • 返回 Continue:hook 只做副作用(println),不替换 result——用户看到的 println 和 LLM 看到的 tool_result 是同一份内容的副本

这正是 s04 Hooks 架构的价值——新增 UI 展示能力时零修改 AgentLoop,只需注册一个新 hook。


文件清单

TEXT
src/main/kotlin/com/sepcai/code/
├── todo/                              # [新建] 待办领域模型包
│   ├── TodoItem.kt                    # data class + TodoStatus 枚举
│   ├── TodoStore.kt                   # 全局单例存储(CopyOnWriteArrayList)
│   └── TodoDisplayHook.kt             # [新建] PostToolUse hook,todo_write 后镜像输出到 stdout
├── tool/
│   └── tools/
│       └── TodoWriteTool.kt           # [新建] 实现 Tool 接口的 todo_write 工具(+NAME 常量)
└── repl/
    └── ReplLoop.kt                    # [修改] 注册工具 + TodoDisplayHook + /clear 清空 + 欢迎语

src/test/kotlin/com/sepcai/code/
├── todo/                              # [新建]
│   ├── TodoStoreTest.kt               # 12 个用例
│   └── TodoDisplayHookTest.kt         # [新建] 6 个用例(输出/错误过滤/工具过滤/Continue)
├── tool/
│   └── TodoWriteToolTest.kt           # [新建] 12 个用例
└── agent/
    └── AgentLoopTest.kt               # [修改] +3 个集成测试,afterTest 加 TodoStore.clear()

7 个源文件(4 新建 + 3 修改)· 3 个新测试文件 + 1 个测试修改 · 164 个测试 · 全部通过。


下一站

s05 完成了阶段二的第一个能力——规划。智能体现在能:

  • 在执行前显式列出步骤
  • 过程中更新进度
  • 用户和 LLM 都能看到当前状态

但 TodoWriteTool 是单线程的——所有 todo 由主 AgentLoop 维护。当你让智能体"重构 UserService 和 OrderService 两个文件"时,它仍然串行处理,无法让子智能体并行处理两个独立任务。

Index 06: Subagent 将引入子智能体——让主智能体可以分发独立任务给隔离的子智能体执行。核心设计:

  • Subagent 数据模型——隔离的 AgentLoop 实例 + 独立 messagesHistory
  • Task 工具——让主智能体通过 tool_use 派发任务
  • ToolRegistry 改为 class——每个子智能体有独立的工具注册表(s05 的 object 单例会破坏隔离)
  • TodoStore 改为 class——同样原因,每个子智能体有独立的待办列表

这个重构面不小——ToolRegistry 和 TodoStore 都要从 object 改成 class,ReplLoop 要负责创建实例并注入。但收益巨大:智能体可以真正并行处理独立任务,每个子智能体有自己的上下文(不污染主对话)。

阶段一(最小闭环)已经全部完成,阶段二(智能体能力)正在让智能体真正具备智能体的能力——规划、子智能体、技能加载、上下文压缩、跨会话记忆。

目录

当前章节:目标

  • 1. 目标
  • 2. 架构:最小闭环的"计划本"
  • 3. 第一层:数据模型
  • 4. TodoItem——极简三字段
  • 5. 第二层:存储
  • 6. TodoStore——全局单例 + CopyOnWriteArrayList
  • 7. 第三层:TodoWriteTool
  • 8. 工具签名
  • 9. JSON Schema 结构
  • 10. execute 执行逻辑
  • 11. 返回的状态概览
  • 12. ReplLoop 集成
  • 13. 三处修改
  • 14. 测试策略
  • 15. TodoStoreTest(12 用例)
  • 16. TodoWriteToolTest(12 用例)
  • 17. AgentLoopTest 集成测试(+3 用例)
  • 18. afterTest 隔离扩展
  • 19. 关键设计取舍
  • 20. 踩坑记录
  • 21. 1. kotlinx.serialization 的类型转换会抛异常
  • 22. 2. toList() 返回不可变 List,as? MutableList 会失败
  • 23. 3. TodoWriteTool 不需要注入 TodoStore
  • 24. 4. 测试失败的错误消息要带位置
  • 25. 5. UI 展示逻辑不该混入 AgentLoop 组装代码
  • 26. 文件清单
  • 27. 下一站
回到顶部

相关推荐

查看全部文章
Index 21: Terminal UX —— Claude Code 风格终端交互

Index 21: Terminal UX —— Claude Code 风格终端交互

2026年8月21日

Index 21 将 cat-code 终端交互升级为 Claude Code 风格,解决旧 REPL 黑箱、无中断及输入体验差的问题。通过 JLine3 与 Mordant 实现历史补全、实时工具可见性、Spinner 状态及 Esc 中断。核心采用 UI 与 AgentLoop 解耦的事件流架构,支持内联权限菜单与优雅降级。同时配置 logback 收敛控制台日志,确保 TUI 清爽且功能无损,显著提升可用性。

Index 20: Comprehensive Agent —— 全机制集成(收口)

Index 20: Comprehensive Agent —— 全机制集成(收口)

2026年8月13日

作为收官之作,把 s01-s19 的二十个核心机制整合为一个全面智能体:统一的状态查询与运行周期、自治认领与工作区隔离的贯通,以及 /status 命令的全局可视化。全机制协同运转,标志着 Cat-Code 从零完整复刻 Claude Code 核心能力的收官。

Index 19: MCP Plugin —— 多传输 / 通道路由 / 工具池组装

Index 19: MCP Plugin —— 多传输 / 通道路由 / 工具池组装

2026年8月13日

引入 MCP(Model Context Protocol)插件机制,通过多传输适配与通道路由,把外部 MCP 服务器的工具动态接入智能体的工具池。工具注册从静态编译期扩展为运行时动态组装,让智能体能力随外部服务即插即用。