乐于分享
好东西不私藏

claude code 源码解读(3)任务管理机制

claude code 源码解读(3)任务管理机制

这就是AI编程最典型的“坑”:“上下文失忆症”。为了治好这个毛病,Claude Code特意上线了**Task Manager(任务管理器)Write Todo(待办写入)**两个“神器”。


🛠️ 一、Write Todo:从“随手贴便签”到“可查可追溯的小数据库”

早期的Agent用的TodoWrite工具,说难听点就是张随手贴的便签纸,格式简单到不能再简单:

- [ ] 实现用户注册API
- [ ] 写前端表单

这种方式的槽点真的太多了,总结下来就三个:

  1. 1. 易丢失:任务全存在内存里,一关终端,好家伙,待办直接“蒸发”,等于白规划;
  2. 2. 没逻辑:没有任务依赖,AI哪知道“得先做A才能做B”,经常瞎忙活,越做越乱;
  3. 3. 不协同:没法跨会话共享,两个Claude会话各干各的,根本没法一起完成一个项目。

Claude Code的进化

现在的Write Todo,把待办任务持久化存在本地文件里(默认路径是~/.claude/tasks/),查起来、追溯起来都方便,也给后面Task Manager的升级铺好了路。

核心代码逻辑拆解(大白话版)

源码里,TodoManager类就是管待办的“大管家”,它不光记任务文本,还得管着AI,不让它“随心所欲”。下面这段简化的Python代码,咱们不用深究语法,看明白它的核心思路就行:

classTodoManager:
def__init__(self):
self.items = []

defupdate(self, items: list) -> str:
# 规则1:最多记20个任务,别让AI把待办当成无限备忘录,记太多反而乱
iflen(items) > 20:
raise ValueError("Max 20 todos allowed")

        validated = []
        in_progress_count = 0

for item in items:
# 规则2:任务必须有明确内容和状态,别写个“做任务”就完事
            text = item.get("text""").strip()
            status = item.get("status""pending"# 就三种状态:待办、进行中、已完成

# 规则3:一次只能干一件事,别让AI想着“多线程干活”,最后啥都干不好
if status == "in_progress":
                in_progress_count += 1

            validated.append(item)

if in_progress_count > 1:
raise ValueError("Only one task can be in_progress at a time")

self.items = validated
returnself.render()

defrender(self) -> str:
# 把任务列表变成AI和人都能看懂的样子,让AI知道自己干到哪了
        lines = []
for item inself.items:
            marker = {"pending""[ ]""in_progress""[>]""completed""[x]"}[item["status"]]
            lines.append(f"{marker} #{item['id']}{item['text']}")
return"\n".join(lines)

这段代码的核心思路就三个:

  1. 1. 状态要明明白白:AI想改任务状态,必须调用工具,不能在心里“偷偷规划”,进度一眼就能看到;
  2. 2. 一次只干一件事:通过限制“进行中”任务只能有一个,避免AI分心,干一件成一件;
  3. 3. 进度要看得见render()函数生成的列表,会反馈给AI,让它清楚自己干到哪了,形成闭环。

🧠 二、Task Manager:不止是记录,更是“动态问责”

有了Write Todo工具,AI就一定会主动使用吗?答案是否定的。AI模型往往会“偷懒”,跳过规划环节直接编写代码,导致项目流程混乱、进度失控。

为解决这一问题,Claude Code在Task Manager中引入了**“Nag Reminder(唠叨提醒)”**机制,通过运行时监控,强制AI养成规划习惯。

代码实现:计数器与动态提醒注入

在Agent的主循环中,隐藏着一个关键计数器rounds_since_todo,用于监控AI是否及时更新待办。以下是伪代码演示其核心逻辑:

# 伪代码演示:Nag Reminder 机制
rounds_since_todo = 0

while running:
# 1. 检查当前轮次AI是否调用了todo工具
    used_todo = False
for block in response.content:
if block.name == "todo":
            used_todo = True
            rounds_since_todo = 0# 调用则重置计数器
break

# 2. 未调用则计数器累加
ifnot used_todo:
        rounds_since_todo += 1

# 3. 累计3轮未调用,强制插入提醒
if rounds_since_todo >= 3:
        messages[-1]["content"].insert(0, {
"type""text",
"text""<reminder>Update your todos. You haven't updated your plan in a while.</reminder>"
        })
        rounds_since_todo = 0# 提醒后重置计数器

这个机制的精妙之处在于“柔性约束”:它没有在Prompt中强制要求“必须使用Todo”,而是通过运行时监控。忙活3轮仍未更新计划,他就会敲敲桌子提醒你:“先规划,再动手”。


🚀 三、进阶:从Todo到Task的跨越,适配复杂项目

随着项目复杂度提升,仅能罗列待办的Write Todo已无法满足需求。Claude Code进一步升级,引入**Task Manager(任务管理器)**核心能力,将简单待办升级为“Trello + Jira”混合管理模式,新增依赖管理与跨会话协同能力,真正实现“项目级管理”,完成从基础待办到专业任务管理的跨越。

1. 依赖管理:避免流程混乱

复杂工程中,任务之间往往存在明确的先后顺序:

  • • 旧版Todo:仅能线性罗列任务1、2、3,无法体现依赖关系;
  • • 新版Task:支持blocked_by(被…阻塞)属性,可明确任务间的先后逻辑。

例如,“部署服务器”任务必须等待“编写代码”任务完成后才能启动。Task Manager(而非Write Todo)会将这些依赖元数据存储在本地文件中,AI规划时会自动校验依赖链,避免出现“未打地基就盖屋顶”的低级错误——这正是Jira式项目管理的核心优势,由Task Manager实现落地。

依赖管理核心代码示例

以下是Task Manager处理任务依赖的简化Python代码,清晰展示其如何校验依赖关系、确保任务按顺序执行:

classTaskManager:
def__init__(self):
self.tasks = []  # 存储所有任务,包含依赖元数据

defadd_task(self, task: dict):
# 任务结构示例:{"id": "task1", "text": "编写代码", "status": "pending", "blocked_by": []}
# 校验任务格式,确保blocked_by字段存在(无依赖则为空列表)
if"blocked_by"notin task:
            task["blocked_by"] = []
# 校验依赖任务是否存在(避免引用不存在的任务)
for dep_id in task["blocked_by"]:
ifnotany(t["id"] == dep_id for t inself.tasks):
raise ValueError(f"依赖任务 {dep_id} 不存在,请先创建该任务")
self.tasks.append(task)

defcheck_dependency(self, task_id: str) -> bool:
# 检查指定任务的所有依赖是否已完成
        task = next(t for t inself.tasks if t["id"] == task_id)
for dep_id in task["blocked_by"]:
            dep_task = next(t for t inself.tasks if t["id"] == dep_id)
if dep_task["status"] != "completed":
# 依赖未完成,返回False,任务无法启动
returnFalse
# 所有依赖已完成,返回True,任务可启动
returnTrue

defupdate_task_status(self, task_id: str, status: str):
# 更新任务状态时,自动校验依赖(若为in_progress状态)
if status == "in_progress"andnotself.check_dependency(task_id):
            dep_ids = next(t["blocked_by"for t inself.tasks if t["id"] == task_id)
raise ValueError(f"任务 {task_id} 依赖的任务 {dep_ids} 未完成,无法启动")

        task = next(t for t inself.tasks if t["id"] == task_id)
        task["status"] = status
# 状态更新后,可触发依赖任务的状态检查(可选,提升协同效率)
self.trigger_dependent_tasks(task_id)

deftrigger_dependent_tasks(self, completed_task_id: str):
# 当一个任务完成后,检查所有依赖它的任务,若依赖已全部完成则提醒AI启动
        dependent_tasks = [t for t inself.tasks if completed_task_id in t["blocked_by"]]
for task in dependent_tasks:
ifself.check_dependency(task["id"]):
print(f"提醒:任务 {task['id']}{task['text']})的所有依赖已完成,可启动")

这段代码核心实现了三个关键功能,完美复刻Jira的依赖管理逻辑:

  1. 1. 依赖校验:添加任务时,校验依赖的任务是否存在,避免无效依赖;
  2. 2. 状态管控:启动任务(in_progress)前,强制检查所有依赖是否已完成,杜绝流程混乱;
  3. 3. 自动触发:当一个任务完成后,自动检查依赖它的任务,提醒AI启动可执行的任务,实现流程自动化。

2. 跨会话协同:多AI分工合作

这是Claude Code任务管理最具“黑科技”的特性——通过环境变量CLAUDE_CODE_TASK_LIST_ID,可让多个Claude会话共享同一个任务列表,实现分工协作。

# 终端 A(负责后端开发)
export CLAUDE_CODE_TASK_LIST_ID=my-project
claude

# 终端 B(负责前端开发)
export CLAUDE_CODE_TASK_LIST_ID=my-project
claude

当终端A完成“数据库设计”任务并标记为completed时,终端B的Task Manager会实时感知到阻塞解除,自动触发“API开发”任务,实现前后端协同开发的无缝衔接。


📌 总结:Claude Code实现“专业项目管理”的核心逻辑

从Write Todo的“持久化待办记录”,到Task Manager升级为Jira式管理、实现“动态问责+依赖协同”,Claude Code向我们展示了构建可靠AI Agent的三个核心原则:

  1. 1. 持久化存储:不依赖易丢失的内存,将任务状态写入本地磁盘(~/.claude/tasks/),确保进度可追溯;
  2. 2. 强逻辑约束:通过代码逻辑(如“单任务进行中”“任务数量限制”),限制AI的发散思维,避免流程混乱;
  3. 3. 软引导机制:通过“唠叨提醒”在运行时动态纠正AI行为,让规划成为习惯,而非强制要求。

这正是Claude Code区别于普通AI编程工具的核心优势——它不仅能“写代码”,更能像高级工程师一样,规划流程、管理项目、协同分工,真正实现从“健忘的临时助手”到“专业的开发伙伴”的跨越。