Learn Claude Code 学习笔记
本文为作者学习Learn claude code过程中记下的笔记。
Learn Claude Code仓库:https://github.com/shareAI-lab/learn-claude-code
1. 工具的设计
只有 bash 时, 所有操作都走 shell。cat 截断不可预测, sed 遇到特殊字符就崩, 每次 bash 调用都是不受约束的安全面。专用工具 (read_file, write_file) 可以在工具层面做路径沙箱。
这句话是在解释 为什么需要专门的工具,而不是什么都用 bash(shell命令)。
1.1 问题:只用 Bash 的缺点
假设只有 bash 工具,LLM 想读文件时会这样:
cat myfile.txt # 问题1: 文件大时输出超长
sed -i 's/old/new/g' f # 问题2: 特殊字符会破坏命令 (如 `&`, `/`, `$`)
rm important.txt # 问题3: bash 就是个安全漏洞,任何危险命令都能执行
ls / | some_command # 问题4: 可以访问任意目录
| 缺点 | 例子 | 问题 |
|---|---|---|
| 输出不可控 | cat 大文件 |
可能刷爆终端 |
| 特殊字符崩溃 | sed $var |
$ 被 shell 解析出错 |
| 不安全 | rm -rf / |
没有限制,LLM 可能误操作 |
| 路径逃逸 | cat /etc/passwd |
可以访问工作目录外的文件 |
1.2 解决方案:专用工具 + 路径沙箱
def safe_path(p: str) -> Path:
path = (WORKDIR / p).resolve() # 把相对路径转为绝对路径
if not path.is_relative_to(WORKDIR): # 检查是否在允许范围内
raise ValueError(f"Path escapes workspace: {p}")
return path
def run_read(path: str, limit: int = None) -> str:
text = safe_path(path).read_text() # 只能在 WORKDIR 内读取
# ...
这样 即使 LLM 被诱导 执行 read_file(path="/etc/passwd"),也会被 safe_path 拦截,因为 /etc/passwd 不在 WORKDIR 内。
1.3 总结
| 方案 | 优点 | 缺点 |
|---|---|---|
| 只用 bash | 灵活强大 | 危险、不可预测、路径不可控 |
| 专用工具 | 安全、可控、可限制范围 | 需要事先定义好要暴露的功能 |
核心思想:给 LLM 的能力要"最小化原则"——只给它完成目标需要的工具,而不是把所有权限都放开。
2. ToDoWrite
2.1 问题
多步任务中, 模型会丢失进度 -- 重复做过的事、跳步、跑偏。对话越长越严重: 工具结果不断填满上下文, 系统提示的影响力逐渐被稀释。一个 10 步重构可能做完 1-3 步就开始即兴发挥, 因为 4-10 步已经被挤出注意力了。
通过 TodoWrite 让计划可见
我们不让模型在思维链中默默规划,而是强制通过 TodoWrite 工具将计划外化。每个计划项都有可追踪的状态(pending、in_progress、completed)。这有三个好处:(1) 用户可以在执行前看到 agent 打算做什么;(2) 开发者可以通过检查计划状态来调试 agent 行为;(3) agent 自身可以在后续轮次中引用计划,即使早期上下文已经滚出窗口。
同一时间只允许一个任务进行中
TodoWrite 工具强制要求任何时候最多只能有一个任务处于 in_progress 状态。如果模型想开始第二个任务,必须先完成或放弃当前任务。这个约束防止了一种隐蔽的失败模式:试图通过交替处理多个项目来'多任务'的模型,往往会丢失状态并产出半成品。顺序执行的专注度远高于并行切换
3. 子 Agent 上下文隔离
"大任务拆小, 每个小任务干净的上下文" -- 子agent用独立 messages[], 不污染主对话
agent工作越久, messages 数组越胖。每次读文件、跑命令的输出都永久留在上下文里。"这个项目用什么测试框架?" 可能要读 5 个文件, 但父agent只需要一个词: "pytest。
- 父agent有一个
task工具。子agent拥有除task外的所有基础工具 (禁止递归生成)。 - 子agent以
messages=[]启动, 运行自己的循环。只有最终文本返回给父agent。 - 子agent可能跑了 30+ 次工具调用, 但整个消息历史直接丢弃。父agent收到的只是一段摘要文本, 作为普通
tool_result返回。
4. Skill Loader
这是 两层 Skill 注入 的设计。让我逐步解释:
4.1 核心设计思想
不要把所有 skill 内容都塞进 system prompt(太长了)
只在 system prompt 放 skill 名称列表(Layer 1)
等 LLM 需要时,再通过 tool_result 把完整内容注入给 LLM(Layer 2)
4.2 Layer 1:System Prompt(只放元数据)
SYSTEM = f"""You are a coding agent at {WORKDIR}.
Skills available:
{SKILL_LOADER.get_descriptions()}"""
输出长这样:
You are a coding agent at C:\Users\wsmdm\Desktop\learn-claude-code.
Skills available:
- pdf: Process PDF files
- code-review: Review code changes
只占几十个 token,告诉 LLM"有哪些技能可以用"。
4.3 Layer 2:按需加载(完整内容)
当 LLM 调用 load_skill("pdf") 时:
"load_skill": lambda **kw: SKILL_LOADER.get_content(kw["name"]),
返回的是 完整的 skill 文档,被包装成 <skill> 标签:
<skill name="pdf">
## PDF Processing
1. Use pymupdf to read PDF
2. Extract text with...
3. ...
</skill>
这通过 tool_result 机制注入:
results.append({"type": "tool_result", "tool_use_id": block.id, "content": str(output)})
messages.append({"role": "user", "content": results})
4.4 为什么这样设计?
| 问题 | System Prompt 全塞进去 | 按需加载(两层) |
|---|---|---|
| token 消耗 | 巨大(10个skill可能几万元) | 极低 |
| LLM 能用到的 skill | 全部(但可能上下文不够) | 只有用到的那些 |
| 灵活性 | 差 | 好 |
4.5 流程图
LLM 说:"我要处理 PDF"
↓
调用 load_skill(name="pdf")
↓
返回 <skill>pdf 完整文档</skill> 作为 tool_result
↓
这条 tool_result 附加到 messages 里发回给 LLM
↓
LLM 现在"看到了"完整的 PDF 处理指南
↓
继续执行任务
简单说:System Prompt 只告诉你"有哪些工具箱",等你真的要开某个工具时,才把工具箱里的说明书给你看。
5. 上下文压缩
5.1 三层压缩策略
- 每轮运行的微压缩:几乎零成本:它截断旧消息中的 tool_result 块,去除不再需要的冗长命令输出。
- token 数超过阈值时触发的自动压缩:调用 LLM 生成对话摘要,代价高但能大幅缩减上下文。
- 用户触发的手动压缩:用于明确的'重新开始'场景。
分层意味着低成本操作持续运行(保持上下文整洁),而高成本操作很少触发(仅在真正需要时)。
5.2 摘要替换全部消息,而非保留部分历史
自动压缩触发时,生成摘要并替换全部消息历史,不会在摘要旁保留最近的 N 条消息。
这避免了一个微妙的连贯性问题:如果同时保留近期消息和旧消息的摘要,模型会看到重叠内容的两种表示。摘要可能说'我们决定使用方案 X',而近期消息仍在展示讨论过程,产生矛盾信号。
干净的摘要是一个连贯的单一叙述。
5.3 完整对话以 JSONL 格式归档到磁盘
完整的未压缩对话仍会追加到磁盘上的 JSONL 文件中。每条消息、每次工具调用、每个结果都不会丢失。
压缩对内存上下文是有损操作,但对永久记录是无损的。事后分析(调试 agent 行为、计算 token 用量、提取训练数据)始终可以基于完整记录进行。JSONL 格式仅追加写入,对并发写入安全,易于流式处理。
6. 任务系统
"大目标要拆成小任务, 排好序, 记在磁盘上" -- 文件持久化的任务图, 为多 agent 协作打基础。
写入磁盘,建立依赖关系,实现任务持久化
s03 的 TodoManager 问题:
todos = [
{"content": "任务 A"},
{"content": "任务 B"},
{"content": "任务 C"},
]
6.1 只有内容 + 是否完成,没有结构
真实目标的样子:
graph TD
A[A 完成] --> B
A --> C
B & C --> D & E
D & E --> F
style A fill:#90EE90
style B fill:#fff
style C fill:#fff
style D fill:#fff
style E fill:#fff
style F fill:#fff
- A (完成) → B 和 C 可以并行
- D 和 E 都完成后才能做 F
为什么"agent分不清"
- 不知道什么能做
Agent: "还有啥任务?"
系统: [A, B, C, D, E, F]
- Agent 不知道 B 被 A 卡住,也不知道 C 和 D 可以同时跑 → 只能瞎猜或者一股脑全做
-
不知道什么被卡住
A 没做完时,B 实际上"被阻塞"了,但清单里 B 就是一条记录,状态还是 "todo",Agent 以为能做,其实做了也白做(等 A 成果) -
不能表达并行
- C 和 D 独立,没有任何依赖
- 但清单里跟 B 排在一起,看不出谁和谁相关
- → Agent 可能串行做 C、D,白白浪费时间
- 上下文压缩就丢了
6.2 TaskManager: JSON 文件持久化
S03: 内存中的列表
self.todos = []
S06 的 micro_compact 会压缩消息
如果任务状态只存在于 Messages 列表里,压缩后任务清单就消失了!
S07 的改进
{
"id": 1, "subject": "A", "status": "completed", "blockedBy": [], "blocks": [2, 3]
}
{
"id": 2, "subject": "B", "status": "pending", "blockedBy": [1], "blocks": [4]
}
{
"id": 3, "subject": "C", "status": "pending", "blockedBy": [1], "blocks": [4]
}
{
"id": 4, "subject": "D", "status": "pending", "blockedBy": [2, 3], "blocks": []
}
- 文件持久化: .tasks/task_1.json 在磁盘上,s06 压缩不影响
- blockedBy 字段: 显式表达"被谁阻塞"
- blocks 字段: 双向维护,D 知道自己在等谁
- scan_unclaimed_tasks(): 能筛选出 pending + 无 owner + 无 blockedBy 的任务
- 并行检测: 多个任务同时 blockedBy: [] → 可以并行
6.6 核心区别
| 维度 | s03 扁平清单 | s07+ 有向图 |
|---|---|---|
| 依赖关系 | 无 | blockedBy/blocks |
| 状态 | done/not done | pending/in_progress/completed |
| 持久化 | 内存 | JSON 文件 |
| 可执行判断 | 不知道 | blockedBy 为空才能做 |
| 并行识别 | 不知道 | 无依赖的任务可并行 |
6.7 后台任务
"慢操作丢后台, agent 继续想下一步" -- 后台线程跑命令, 完成后注入通知。
启动后台任务不等待,任务完成后放队列,LLM调用前取走结果,队列保证不重复通知
6.8 Agent Team
6.8.1 实现架构
sequenceDiagram
participant User as 用户
participant Agent as 主线程 (Agent)
participant BG as 后台线程
participant LLM as LLM API
Note over Agent: agent_loop()
Agent->>Agent: drain_notifications()
Note over Agent: 从通知队列取结果,注入到 messages
Agent->>LLM: client.messages.create()
LLM-->>Agent: response
loop for block in response.content
Agent->>BG: BG.run(command)
BG-->>Agent: 立即返回 (启动线程)
end
Note over BG: subprocess.run(command)
Note over BG: 命令执行中... (30分钟)
BG->>BG: 执行完毕/超时/出错
BG->>BG: with lock: queue.append(结果)
6.8.2 关键组件
6.8.2.1 守护线程 (daemon=True)
thread = threading.Thread(
target=self._execute, # 线程执行的函数
args=(task_id, command), # 函数参数
daemon=True # 守护模式
)
thread.start()
守护线程 = 主进程退出时会被强制终止的线程
sequenceDiagram
participant User as 用户
participant Main as 主进程
participant BG as 守护线程
User->>Main: quit
Main->>Main: 退出
Note over Main: 守护线程被杀死 (不管任务跑没跑完)
为什么用守护线程?
- 用户 quit 后,不需要后台任务结果了
- 避免主进程卡住等慢任务
6.8.2.2 线程锁 (threading.Lock)
self._lock = threading.Lock()
with self._lock:
self._notification_queue.append({…})
为什么需要锁?
时间线:
sequenceDiagram
participant Agent as Agent 线程
participant BG as 后台线程
Note over Agent: drain() 读队列 (还没数据)
BG->>BG: 命令执行完,写队列
BG->>BG: with lock: queue.append(结果)
Agent->>Agent: 看到空队列,返回 []
Note over Agent: 结果丢了,没人拿到
加锁保证:读写队列不会同时发生。
6.8.2.3 通知队列
_notification_queue = []
后台线程执行完,写入:
with self._lock:
_notification_queue.append({
"task_id": "abc",
"status": "completed",
"result": "…"
})
Agent 线程取出:
with self._lock:
notifs = list(_notification_queue)
_notification_queue.clear() # 清空
return notifs
为什么要清空?
第1轮: 队列 = [结果A]
drain → notifs = [结果A],队列 = []
第2轮: 队列 = []
drain → notifs = [],队列 = []
如果不清空:
第2轮: 队列 = [结果A]
drain → notifs = [结果A] ← 重复通知,LLM 会困惑
6.8.3 完整流程
用户: "编译项目"
Agent:
│ LLM 调用
├─→ 返回 background_run("make")
│
BG.run("make")
│
├── task_id = "abc123"
├── 创建守护线程
├── thread.start() ← 立即返回
└── 返回 "后台任务 abc123 已启动"
Agent:
│ 继续工作…
│
│ (编译在后台跑了30分钟)
30分钟后:
Agent:
│ LLM 调用前
│ ↓
drain_notifications()
│
├── 取走 [结果]
└── 队列清空
│
├─→ 注入 "<background-results>…编译完成…</background-results>"
│
│ LLM 调用
├─→ LLM 看到 "编译完成了"
6.8.3 完整流程
sequenceDiagram
participant User as 用户
participant Agent as Agent
participant BG as 后台线程
User->>Agent: "编译项目"
Agent->>Agent: LLM 调用
Agent-->>Agent: 返回 background_run("make")
Agent->>BG: BG.run("make")
Note over BG: 创建守护线程,返回 task_id
BG-->>Agent: "后台任务 abc123 已启动"
Agent->>Agent: 继续工作...
Note over BG: 命令执行中... (30分钟)
BG->>BG: 执行完成,写入队列
Agent->>Agent: LLM 调用前 drain_notifications()
Note over Agent: 取走结果,队列清空
Agent->>Agent: 注入 "<background-results>编译完成</background-results>"
Agent->>LLM: LLM 调用
Agent-->>User: "编译完成了"
7. Agent Teams
7.1 Teammates + Mailboxes
"任务太大一个人干不完, 要能分给队友" -- 持久化队友 + JSONL 邮箱。
Harness 层: 团队邮箱 -- 多个模型, 通过文件协调
子agent (s04) 是一次性的: 生成、干活、返回摘要、消亡。没有身份, 没有跨调用的记忆。后台任务 (s08) 能跑 shell 命令, 但做不了 LLM 引导的决策。
真正的团队协作需要三样东西:
- (1) 能跨多轮对话存活的持久agent,
- (2) 身份和生命周期管理
- (3) agent之间的通信通道。
s09_agent_teams.py - Agent 团队
持久化命名 Agent,基于文件的 JSONL 收件箱。
每个队友在独立线程中运行自己的 Agent 循环。通过仅追加的收件箱通信。
子 Agent (s04): spawn -> execute -> return summary -> destroyed
队友 (s09): spawn -> work -> idle -> work -> … -> shutdown
.team/config.json .team/inbox/
+----------------------------+ +------------------+
| {"team_name": "default", | | alice.jsonl |
| "members": [ | | bob.jsonl |
| {"name":"alice", | | lead.jsonl |
| "role":"coder", | +------------------+
| "status":"idle"} |
| ]} | send_message("alice", "fix bug"):
+----------------------------+ open("alice.jsonl", "a").write(msg)
read_inbox("alice"):
spawn_teammate("alice","coder",…) msgs = [json.loads(l) for l in …]
| open("alice.jsonl", "w").close()
v return msgs # drain
Thread: alice Thread: bob
+------------------+ +------------------+
| agent_loop | | agent_loop |
| status: working | | status: idle |
| … runs tools | | … waits … |
| status -> idle | | |
+------------------+ +------------------+
5 种消息类型 (全部声明,此处未全部处理):
+-------------------------+-----------------------------------+
| message | 普通文本消息 |
| broadcast | 发送给所有队友 |
| shutdown_request | 请求优雅关闭 (s10) |
| shutdown_response | 批准/拒绝关闭 (s10) |
| plan_approval_response | 批准/拒绝计划 (s10) |
+-------------------------+-----------------------------------+
核心思想: "可以相互对话的队友。"
7.2 设计决策
7.2.1 与subagent的区别
- 在 s04 中,子agent是临时的:创建、执行一个任务、返回结果、销毁。它们的知识随之消亡。
- 在 s09 中,队友是具有身份(名称、角色)和配置文件的持久化线程。队友可以完成任务 A,然后被分配任务 B,并携带之前学到的所有知识。持久化队友积累项目知识,理解已建立的模式,不需要为每个任务重新阅读相同的文件。
我理解的teamate就是状态不隔离,持久化,可互相通信的subagent
7.2.2 团队配置持久化
- 团队结构(成员名称、角色、agent ID)存储在 JSON 配置文件中,而非任何 agent 的内存中。
- 任何 agent 都可以通过读取配置文件发现队友——无需发现服务或共享内存。如果 agent 崩溃并重启,它读取配置即可知道团队中还有谁。
- 这与 s07 的理念一致:文件系统就是协调层。配置文件人类可读,便于手动添加或移除团队成员、调试团队配置问题。
7.2.3 工具分发
- 团队组长获得 ALL_TOOLS(包括 spawn、send、read_inbox 等),而队友获得 TEAMMATE_TOOLS(专注于任务执行的精简工具集)。
- 队友专注于做事(编码、测试、研究)
- 组长专注于协调(创建任务、分配工作、管理沟通)。
8. team_protocols
"队友之间要有统一的沟通规矩" -- 一个 request-response 模式驱动所有协商。
基于 s09 的团队消息系统,加了 Shutdown 协议 和 Plan Approval 协议,两个协议都通过 request_id 关联请求和响应。
8.1 核心:request_id 关联模式
发请求时生成 ID → 响应时带上同样 ID → 精准匹配
sequenceDiagram
participant Lead
participant Alice
Lead->>Alice: req_id = "abc123"
Note over Alice: 处理中…
Alice-->>Lead: 带上 "abc123" 响应
Note over Lead: 收到响应,查 "abc123",知道是谁在回应
8.2 协议一:Shutdown 关闭协议
目的:优雅关闭队友,而不是强制杀死线程。
流程:
- Lead 想关闭 alice
- 生成 req_id = "abc123"
- 把 req_id 存到 tracker
- 发送 shutdown_request 给 alice
- alice 收到,决定批准还是拒绝
- 发送 shutdown_response 带上 req_id
- Lead 更新 tracker 状态
- alice 线程退出或继续工作
状态机:
pending → approved (线程退出)
→ rejected (继续工作)
8.3 协议二:Plan Approval 计划审批协议
目的:队友做重大操作之前,必须获得 Lead 批准。
流程:
- alice 要做大事 (比如重构整个模块)
- 生成 req_id = "xyz789"
- 把计划和 req_id 发给 Lead
- Lead 看计划,决定批准还是拒绝
- alice 收到响应
- approve=true → 开始执行
- approve=false → 修改计划,重新提交
8.4 图解
sequenceDiagram
participant Lead
participant Alice
Note over Lead,Alice: request_id 关联请求和响应
rect rgb(200, 220, 255)
Note over Lead,Alice: Shutdown 协议
Lead->>Alice: shutdown_request + req_id
Alice-->>Lead: shutdown_response + req_id
Note over Lead: 线程退出
end
rect rgb(220, 255, 220)
Note over Lead,Alice: Plan Approval 协议
Alice->>Lead: plan_approval + req_id + 计划内容
Note over Lead: 看到计划,决定
Lead-->>Alice: plan_approval_response + req_id + approve?
Note over Alice: 执行/修改计划
end
8.5 设计决策
JSONL 收件箱文件而非共享内存
收发信息即维护JSON,只加不减。保证并发写入时的安全,不破坏数据;如果写入时崩溃仅留下不完整数据,读取者可以跳过。
五种消息类型覆盖所有协调模式
消息系统恰好支持五种类型:
- (1) message 用于两个 agent 间的点对点通信;
- (2) broadcast 用于全团队公告;
- (3) shutdown_request 用于优雅终止;
- (4) shutdown_response 用于确认终止;
- (5) plan_approval_response 用于组长批准或拒绝队友的计划。
这五种类型映射到基本协调模式:直接通信、广播、生命周期管理和审批流程。
每次 LLM 调用前检查收件箱
队友在每次 agent 循环迭代的顶部、调用 LLM API 之前检查收件箱文件。这确保了对传入消息的最大响应性:响应快,成本低(读取小文件消耗token少),可以影响下次调用。
9. 自主Agent
9.1 Scan Board, Claim Tasks
9.2 设计决策
9.2.1 轮询未认领任务而非事件驱动通知
- 自主队友每隔约 1 秒轮询共享任务板任务。
- 轮询从根本上比发布/订阅更简单:
- 没有订阅管理
- 没有事件路由
- 没有事件丢失的 bug
- 在基于文件的持久化下,轮询保证响应速度,降低文件系统开销。
9.2.2 空闲 60 秒后自动终止
不会因为任务完成到新任务创建之间的短暂间隔而导致过早关闭;又足够短,不会让闲置队友浪费资源。
9.2.3 上下文压缩后重新注入队友身份
-
自动压缩对话时,生成的摘要会丢失关键元数据:队友的名称、所属团队和 agent_id。没有这些信息,队友无法认领任务(任务按名称归属)、无法检查收件箱(收件箱文件以 agent_id 为键)、也无法在消息中表明身份。
-
因此每次自动压缩后,系统会向对话中重新注入一个结构化的身份块:'你是 [team] 团队的 [name],你的 agent_id 是 [id],你的收件箱在 [path]。'这是队友在记忆丢失后保持功能所需的最小上下文。
10. Worktree + 任务隔离
(codex的worktree应该也是这个思路)
任务管目标, worktree 管目录, 按 ID 绑定
agent已经能自主认领和完成任务。但所有任务共享一个目录。两个agent同时重构不同模块 -- A 改 config.py, B 也改 config.py, 未提交的改动互相污染, 谁也没法干净回滚。
任务板管 "做什么" 但不管 "在哪做"。解法: 给每个任务一个独立的 git worktree 目录, 用任务 ID 把两边关联起来。
用 git worktree 做目录级隔离,让多个任务真正并行执行而互不干扰。
10.1 场景
核心问题:
- 任务 A: 重构登录模块
- 任务 B: 修复支付 bug
如果都在同一个目录改代码:
A 在改 auth.py ←──────────────┐
B 也在改 auth.py ──────────────┼──→ 冲突!代码乱套
结果:谁先提交谁覆盖,谁都可能被卡住等对方
解决方案:目录隔离
主仓库
├── auth.py (原始版本)
│
├── .worktrees/
│ ├── auth-refactor/ ← A 的工作目录 (wt/auth-refactor 分支)
│ │ └── auth.py (重构版本)
│ │
│ └── payment-fix/ ← B 的工作目录 (wt/payment-fix 分支)
│ └── auth.py (支付修复版本)
A 和 B 在各自目录改代码
互不干扰,可以同时工作
完成后可以选择:
- keep: 保留这个 worktree,合并到主分支
- remove: 删除 worktree,代码丢弃
10.2 三个核心组件
-
TaskManager - 控制平面
任务 A (id=1): "重构登录" → worktree: "auth-refactor"
任务 B (id=2): "修复支付" → worktree: "payment-fix"- 任务是"想法",存在 .tasks/ 目录
- 记录谁在做,状态是什么
-
WorktreeManager - 执行平面
创建 worktree → 绑定到某个任务
在 worktree 里执行命令
完成后 keep 或 remove -
EventBus - 可观测性
事件 说明 worktree.create.before 创建前 worktree.create.after 创建后 worktree.remove.before 删除前 worktree.remove.after 删除后 task.completed 任务完成 用于追踪整个生命周期,出问题了能查日志
10.3 工作流程
-
创建任务
task_create("重构登录模块") ↓ 任务写入 .tasks/task_1.json status: pending -
创建 worktree 并绑定
worktree_create("auth-refactor", task_id=1) ↓ git worktree add -b wt/auth-refactor .worktrees/auth-refactor ↓ 任务状态: pending → in_progress worktree 绑定到任务 -
在 worktree 里工作
worktree_run("auth-refactor", "git status") worktree_run("auth-refactor", "python test.py") ↓ 所有命令在隔离目录里执行 -
完成后选择
worktree_keep("auth-refactor") → 保留,继续在 auth-refactor 分支工作 worktree_remove("auth-refactor", complete_task=True) → 删除 worktree,任务标记完成
10.4 架构图
graph TB
subgraph 控制平面
TM[TaskManager]
TM -->|"管理"| T1[task_1.json<br/>subject: 重构<br/>worktree: auth-refactor]
TM -->|"管理"| T2[task_2.json<br/>subject: 支付<br/>worktree: payment-fix]
end
TM -->|"绑定"| WM
subgraph 执行平面
WM[WorktreeManager]
WM -->|"创建"| WT1[wt/auth-refactor/]
WM -->|"创建"| WT2[wt/payment-fix/]
end
subgraph 主仓库
ROOT[auth.py 原始]
end
目录结构:
.git/ # 主仓库
├── auth.py # 原始文件
├── .worktrees/
│ ├── index.json # 工作树索引
│ ├── events.jsonl # 生命周期事件日志
│ ├── wt/
│ │ ├── auth-refactor/ # 任务 A 的 worktree (独立分支)
│ │ └── payment-fix/ # 任务 B 的 worktree (独立分支)
总结
这篇文章梳理了 Claude Code 的 10 个核心设计:
| 章节 | 设计 | 核心价值 |
|---|---|---|
| 1 | 专用工具 + 路径沙箱 | 安全可控 |
| 2 | TodoWrite | 计划可见、状态可追踪 |
| 3 | 子 agent 上下文隔离 | 避免污染、保持简洁 |
| 4 | Skill Loader 两层注入 | 按需加载、节省 token |
| 5 | 上下文压缩 | 平衡成本与历史 |
| 6 | 任务系统 + 后台任务 | 持久化、并行化 |
| 7 | Agent Teams | 多 agent 协作 |
| 8 | Team Protocols | 统一的沟通协议 |
| 9 | 自主 agent | 自动认领任务 |
| 10 | Worktree 隔离 | 任务级目录隔离 |
核心思想:
- 可控性:最小权限原则,只暴露必要的工具
- 持久化:磁盘文件作为协调层,重启不丢失
- 隔离性:子 agent 独立上下文、任务独立目录
- 按需加载:Skill 按需注入,控制 token 成本
这些设计的共同目标是让 agent 在长期、多任务、复杂场景下保持稳定、可控、可扩展。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐
所有评论(0)