# 青雲的博客 > 记录 AI Coding Agent 的工程实践与源码解析:深入拆解 Codex、pi 和 DeepSeek Harness,分享上下文管理、工具执行、Agent 运行时、评测复盘与前端开发经验。 Canonical site: https://www.echovic.com Full published content: [llms-full.txt](https://www.echovic.com/llms-full.txt) ## Published Handbooks ### 拆开 Codex - [拆开 Codex](https://www.echovic.com/handbook/codex-internals): 从源码读懂一个生产级 Agent。全书只分析 openai/codex 开源仓库:既把 Codex 的真实实现讲透,也从这些实现中解释一个生产级 Agent 需要处理的模型回路、工具执行、安全治理、状态恢复、扩展协议、多 Agent 和验证体系。 - [不要从目录开始读 Codex](https://www.echovic.com/handbook/codex-internals/01-repository-map): 先不猜哪个 crate 是核心,而是用一条输入链标出协议、Session、turn loop、持久记录和客户端投影各自所在的位置;具体 ownership 从第 7 章展开。 - [同一个 codex,为什么会启动几套不同的系统](https://www.echovic.com/handbook/codex-internals/02-runtime-entrypoints): codex 先做顶层路由,真正启动的可能是交互客户端、一次性执行器、长驻 JSON-RPC 服务或 MCP server;它们共享 core,但不共享协议和终态。 - [Codex 启动时,哪一份配置说了算](https://www.echovic.com/handbook/codex-internals/03-config-precedence): Codex 先按明确的 precedence 合并 ordinary TOML layers,再把 typed ConfigOverrides 应用到最终 Config;这两条路径的来源可见性不同。 - [配置能覆盖,Requirements 不能绕过](https://www.echovic.com/handbook/codex-internals/04-managed-requirements): 第 3 章得到的是 ordinary candidate,不是最终运行值。Requirements 由独立 Vec 按来源顺序 compose,再通过约束对象决定保留、fallback 或报错。 - [登录身份不等于 Agent 身份](https://www.echovic.com/handbook/codex-internals/05-auth-agent-identity): Codex 把账号登录、可复用的 Agent Identity、单次 task 断言和 turn 路由状态放在不同层;每层都有自己的存储、验证和请求边界。 - [模型不是一个字符串:Provider、目录与 ModelInfo](https://www.echovic.com/handbook/codex-internals/06-provider-model-info): 配置先选 provider,ModelsManager 再从 bundled、远端和缓存目录解析 ModelInfo;一个 turn 最后同时持有 provider、模型元数据、有效 context window 和能力边界。 - [你按下回车后,谁接管这次任务](https://www.echovic.com/handbook/codex-internals/07-turn-ownership): 一次回车并不会直接进入 prompt。输入先被包装成 Submission,Session 再决定是否创建 active turn;RegularTask 持有执行权,steer 只追加当前 turn 的 pending input,cancel 则沿 cancellation token 终止这次执行。 - [模型收到的指令从哪里来](https://www.echovic.com/handbook/codex-internals/08-instruction-assembly): 一次 Turn 的指令并非来自单一 system prompt。本章沿固定源码版本追踪 base、developer、host/project instructions、personality 与运行时片段的角色、注入时机和去重边界。 - [History 为什么不能直接拿去做 Prompt](https://www.echovic.com/handbook/codex-internals/09-history-to-prompt): 经 record_items 写入的 item 会先过滤和截断;采样前还要在 clone 上补齐 call/output、清理孤儿项并处理图片能力。本章用跨 resume 的缺失 output 测试,划清 live history、prompt projection、working set 与 wire request。 - [Prompt 怎样变成一份 Responses 请求](https://www.echovic.com/handbook/codex-internals/10-responses-request): 第 9 章只交来规范化后的 Prompt.input;build_prompt 再汇合其他字段,得到一份已经分好所有权的 Prompt。本章追踪普通 Responses 请求、Responses Lite 输入前缀与 WebSocket response.create,并把差异停在 ResponseStream 边界。 - [Codex 为什么有两层循环](https://www.echovic.com/handbook/codex-internals/11-two-level-loop): ResponseStream 只代表一次 provider response。本章沿 RegularTask::run 和 run_turn 解释同一用户可见 turn 为什么会多次 sampling,并划清 continuation、Stop hook 与 task 终态的所有权。 - [一条 Responses 流怎样变成下一步行动](https://www.echovic.com/handbook/codex-internals/12-response-stream-actions): 本章逐项核对 added、delta、done、completed、tool future 与 usage 的消费者,解释完整 item 在哪里写入 history、工具结果何时回填,以及 needs_follow_up 怎样触发下一次请求。 - [断流、限流和 401:Codex 分别从哪里恢复](https://www.echovic.com/handbook/codex-internals/13-recovery-boundaries): 401、HTTP 建流失败、stream 中断、限流、invalid image、cancellation 与 tool future Err 各有不同 owner。本章追踪每层重试什么,以及 local return 最终怎样落成 TurnComplete 或 TurnAborted。 - [模型为什么能调用工具:两张表,一个闭环](https://www.echovic.com/handbook/codex-internals/14-tool-spec-registry): ToolRouter 一边向 Prompt 提供模型可见 specs,一边用 registry 把 FunctionCall 变成带 Session、取消令牌和 tracker 的 ToolInvocation。本章解释这两张表为何不对称,以及 ToolOutput 怎样带原 call_id 回到模型。 - [一份补丁怎样落盘,又怎样成为 TurnDiff](https://www.echovic.com/handbook/codex-internals/15-apply-patch-turn-diff): 从 ApplyPatchHandler 的完整预检进入 ToolOrchestrator,区分有序 Hunk、无序拟议 action、有序 committed delta 与 turn-scoped net diff,并说明失败、move、exact 和事件各自能证明到哪里。 - [模型返回的 Shell 参数,为什么还不是一条进程](https://www.echovic.com/handbook/codex-internals/16-shell-command-normalization): cmd、workdir 与 permission 请求先形成 handler command,再分别投影为执行 envelope、exec-policy segments 和 approval cache identity。三份材料用途不同,spawn 前仍可能被环境、shell snapshot 与 sandbox wrapper 改写。 - [审批、Permission Profile 与沙箱各自拦什么](https://www.echovic.com/handbook/codex-internals/17-approval-permissions-sandbox): Codex 先用 approval policy 和 exec-policy 得到单次调用的审批要求,必要时经 hook、Guardian 或用户审批,再根据 PermissionProfile、per-call request 与平台能力选择 SandboxAttempt。批准只允许继续,不能替代沙箱隔离。 - [命令返回以后,进程为什么还活着](https://www.echovic.com/handbook/codex-internals/18-unified-exec-sessions): Unified Exec 启动进程后,exec_command 可以先返回,OS 进程仍由 session 级 ProcessStore 持有。本章划清 write_stdin、进程退出、turn interrupt、后台清理与 session shutdown 的生命周期。 - [网络访问为什么另有一条决策链](https://www.echovic.com/handbook/codex-internals/19-network-decision-chain): 网络请求先通过 execution attribution 找回 owner,再按显式 deny、local/private 限制和 allowlist 过固定策略。只有满足条件的 NotAllowed 才可能进入审批;显式 deny 不生成 NetworkApprovalContext,reviewer 无法把它翻成 allow。 - [Skills 不是工具:从目录发现到渐进注入](https://www.echovic.com/handbook/codex-internals/20-skills-discovery-injection): Skills 目录经过预算和禁用规则后进入 developer context;只有当前 turn 的显式 mention 才注入 SKILL.md 正文。Skill 本身不会变成 Tool,但受控依赖分支可以安装它声明的缺失 MCP server。 - [外部 MCP Server 的工具怎样进入 Codex](https://www.echovic.com/handbook/codex-internals/21-mcp-tools): MCP server 要依次经过配置投影、连接与 tools/list、模型 exposure、审批和 tools/call。McpRuntimeSnapshot 固定一次 step 使用的 manager 与配置,工具表由 StepContext 的 OnceCell 缓存;发现成功不等于模型可见或调用已执行。 - [Dynamic Tools 为什么把执行权交回宿主](https://www.echovic.com/handbook/codex-internals/22-dynamic-tools-host): thread/start 只把 Dynamic Tool 声明交给 Codex,真正执行仍在宿主。模型调用后,Core 用 call_id 登记 waiter,app-server 反向请求宿主;宿主回传 content items 后,Core 才构造 function_call_output。 - [Code Mode 为什么仍然绕不开同一张工具表](https://www.echovic.com/handbook/codex-internals/23-code-mode-tools): Code Mode 为每次 exec 建立 JavaScript cell,但 nested tools 仍经 CodeModeDispatchBroker 回到当前 turn 的 ToolRouter。stored values、yield/wait、取消和 typed result 都有明确边界;它没有另造一张工具表。 - [一个 Plugin 怎样变成一组可安装能力](https://www.echovic.com/handbook/codex-internals/24-plugin-capability-package): Plugin 有两条装配线:executor-selected roots 由宿主注册的 contributor 解析,本地安装包经 PluginStore 和 PluginsManager 形成 PluginLoadOutcome,再交给各 capability owner。manifest 本身只声明能力。 - [同一段对话,为什么同时存在三种状态](https://www.echovic.com/handbook/codex-internals/25-conversation-state-layers): 一条 thread 的模型工作集、可重放日志和可查询元数据由三个不同 owner 维护。常规写入先更新 live ContextManager,再尝试追加并 flush canonical JSONL,随后由 LiveThread 观察并同步 SQLite 投影;任何一层可见都不能单独证明另外两层已经跟上。 - [上下文快满时,Codex 到底压缩了什么](https://www.echovic.com/handbook/codex-internals/26-context-compaction): compaction 生成 replacement history,替换 live ContextManager,并尝试向 append-only rollout 追加 checkpoint。 - [Resume 与 Fork:恢复的不是同一件事](https://www.echovic.com/handbook/codex-internals/27-resume-and-fork): non-running thread/resume 按 history > path > thread_id 选择来源。cold resume 保留原 thread id;resume(history) 与 fork 用可重放 items 生成新 thread。fork 可持久化,也可保持 ephemeral、pathless。 - [Memory 不是更长的 History](https://www.echovic.com/handbook/codex-internals/28-memory-lifecycle): Memory 是默认关闭的 Experimental Feature。它先从 eligible rollout 提取 StageOneOutput,再由受限 agent 更新 MEMORY.md、memory_summary.md 和可选 skills。读取与 citation usage 回写各有独立 gate。 - [Goal 为什么必须活在 Turn 之上](https://www.echovic.com/handbook/codex-internals/29-persistent-goal): Goal 是 thread-scoped durable state。模型工具与 app-facing service 通过不同入口写入 SQLite;live thread lifecycle 建立 runtime handle,只把 active Goal id 接入 accounting。续跑和事件投影另有门禁。 - [App-server 如何把 Core 变成一套可消费协议](https://www.echovic.com/handbook/codex-internals/30-app-server-protocol): App-server 把 request 排队后交给 Core,再把 event 投影为通知。listener 的常规 thread-scoped 通知按订阅快照投递,ThreadGoalUpdated 特意全局广播;审批等交互通过 callback 请求客户端。它不拥有 Agent loop 或 durable history。 - [TUI 如何把事件流还原成一个稳定界面](https://www.echovic.com/handbook/codex-internals/31-tui-event-projection): TUI 按 thread identity 将 app-server event 写入各 Thread 的有界 store,只有前台 widget 实时消费。切换时重放快照,但避开只属于实时路径的副作用。路由与渲染是两个相邻 layer test,没有共享 fixture 或 event id;UI 快照也不等于 rollout。 - [一个子 Agent 为什么需要独立 Thread](https://www.echovic.com/handbook/codex-internals/32-subagent-thread): `spawn_agent` 为 child 建立独立 `ThreadId`、`AgentPath` 与 runtime。spawn 拓扑、fork history、live registry 和持久 graph 分属不同 owner;edge upsert 是 best effort,失败不撤销 live child,V2 恢复不沿旧版 graph。 - [多个 Agent 怎样通信、等待与中断](https://www.echovic.com/handbook/codex-internals/33-multi-agent-coordination): MultiAgentV2 把消息排队、触发 turn、等待 mailbox、完成通知和 interrupt 分开。child 尝试把 Result 发给 parent;失败只写 debug log,没有 durable retry 或 ack。detached watcher 与 `close_agent` 属于旧版 surface。 - [普通 Responses 与 Realtime 为什么是两套会话](https://www.echovic.com/handbook/codex-internals/34-realtime-conversation): Responses WebSocket 是普通 Turn 的推理通道,可跨 Turn 复用,失败后切 HTTP。Realtime 另有队列、解析器与 WebSocket/WebRTC 状态。两项本地测试分别覆盖 fake Responses WebSocket 和 Realtime loopback,不能证明真实服务、WebRTC 或音频设备。 - [Hooks 为什么不是一条统一回调链](https://www.echovic.com/handbook/codex-internals/35-hook-lifecycle): 十类 Hook 共享 discovery 和 command dispatcher,但 scope、matcher、parser 与 effect 各不相同。PreToolUse 可在执行前阻断或改写,PermissionRequest 只裁决审批,PostToolUse 不能回滚副作用;Core 在工具、审批、压缩和停止等真实调用点分别触发它们。 - [没有证据的“跑通”不算跑通](https://www.echovic.com/handbook/codex-internals/36-verification-evidence): 本章用一条本地 codex-exec 任务对账 request、文件副作用、rollout、resume 与 trace。rollout 子串检查和 trace replay 回答不同问题;四个 GuardianWarning layer test 也不能拼成 E2E。证据按 source、test、artifact、trace 与未覆盖边界分别记账。 ### 深入浅出 DeepSeek Harness - [深入浅出 DeepSeek Harness](https://www.echovic.com/handbook/deepseek-harness-internals): 从一次回车到完整 Agent 平台。沿 DeepSeek Harness 官方仓库的固定 commit,从你在终端敲下 dsh 或在浏览器按下回车讲起,追踪消息怎样穿过 Inbox 进入 Agent Loop,事件日志怎样同时支撑模型上下文、持久化与界面投影,并继续拆解工具治理、Goal、多 Agent、Cordis、MCP、SDK、安全与验证体系。 - [从敲下 dsh 到补丁栈组装完成](https://www.echovic.com/handbook/deepseek-harness-internals/01-cli-entry): dsh 命令不是一个"主程序"。bin.ts 只有53行,做三件事:读版本号、解析参数、按 mode 分发。真正的启动路径是 runProfile():先加载三层环境(进程继承 > cwd/.env > $DSH_HOME/.env,bootstrap-only 变量被拒绝)、然后组装五层补丁栈(bundle layers → profile patches → home patches → --patch overlays → telemetry switch)、最后调 boot() 创建 Cordis Context 并挂载整棵插件树。cordis.yml 每次启动都被覆写为空数组,因为 Loader 的 write-back 机制会把运行时组装结果写回这个文件,如果不清空就会在下次启动时产生重复行。 - [Cordis:不是依赖注入,是生命周期状态机](https://www.echovic.com/handbook/deepseek-harness-internals/02-profile-patch-stack): Cordis 不是经典 DI 容器。每个 Context 是一个 Proxy,服务访问走 get trap 拦截。Fiber 是真正的生命周期单元,它根据 inject 声明的依赖是否全部就绪来决定自己处于 PENDING 还是 ACTIVE。当依赖在运行时动态出现或消失,fiber 会自动 reload 或 unload——这是一个响应式状态机,不是一次性的依赖解析。 - [Agent 和 Session 共用一个身份证——但 Headless 和 Web 走的不是同一条路](https://www.echovic.com/handbook/deepseek-harness-internals/03-cordis-composition): Agent 和 Session 不是两个独立实体——它们共享同一个 SessionId 身份。AgentRegistry 以 SessionId 为键存储 agent entry。Headless 启动时解析命令行 task 创建一个一次性 agent 然后退出;Web 启动时绑定 host:port 长驻运行,通过 ApiProxy/JSON-RPC 按对话创建 agent。两条路复用同一个 AgentRegistry.create,但触发时机和生命周期完全不同。 - [Agent、Session 和那个共用的身份证](https://www.echovic.com/handbook/deepseek-harness-internals/04-agent-session-identity): AgentRegistry 管 Agent 的注册和查找,SessionStore 管 Session 的创建和事件流,它们是两个独立的 Service。但一个 Agent 必须绑定一个 Session 才能运行,createAgent() 是一个三段事务:prepare(构造 Session 和 Agent,不发布)→ setup(调用者提供的 setup 回调,可做额外配置)→ publish(enter 到 store、announce 事件)。任何一步失败,前面已分配的资源自动回滚。 - [为什么 Web 新建会话不是 CLI 的前端按钮](https://www.echovic.com/handbook/deepseek-harness-internals/05-headless-vs-web-entry): 你在浏览器点"新建会话"时,浏览器里没有 Session,没有 Agent,没有 Cordis 容器。浏览器发一个 HTTP RPC 到 Host 进程,ApiProxy 收到后做权限检查、preset 组合、cwd 校验、workspace 归属、去重,然后才在 Host 进程里调 ctx.agents.create()。Session 完全由 Host 管理,浏览器通过 WebSocket 订阅事件流,Client Runtime 按领域投影自己的状态快照——它不持有 Session 对象引用。 - [Inbox 双队列:消息不是直接进模型的](https://www.echovic.com/handbook/deepseek-harness-internals/06-inbox-delivery): Inbox 是模型收到消息之前的双队列暂存区。next-turn 队列存放需要开启新 turn 的用户消息,next-step 队列存放注入当前 step 的消息。splice 是唯一写入点(先持久化再更新内存),claim 是唯一消费点(取走全部 next-step 加一条 next-turn)。turn 边界由 ReactLoopAgent 的三态相位机(idle/maintenance/running)管理,wakeDriver 启动新 phase,preStep 瀑布流做最终裁决。 - [turn/start 之前:谁有权开始新一轮](https://www.echovic.com/handbook/deepseek-harness-internals/07-turn-pre-step): ReactLoopAgent 三态机(idle/maintenance/running)控制谁能开始 turn。wakeDriver 在 idle 时创建 running phase 和新 AbortController,否则 latch wakeRequested。turn() 先 append turn/start 事件,再进入 preStep:claim inbox → assemble system prompt → runtimeContext.project → agent/pre-step waterfall 决策。waterfall 返回 reject 则 turnEnds=blocked,不写 step/start、不调模型。只有 enter 决策后才 append step/start 和 user/message。 - [System Prompt 四层组装](https://www.echovic.com/handbook/deepseek-harness-internals/08-system-prompt-assembly): System Prompt 通过 SystemPrompt.assemble() 构建为四层结构体 PromptAssembly。sections 是有序命名文本块,contexts 是动态运行时上下文(渲染为 user-role 消息),tools 是工具 schema 列表,variables 是严格插值键值对。组装流程:chainLayers 取层级链 → variables 远到近收集(近覆盖远)→ sections name-merge(scope 覆盖 global)+ order 排序 → complete section 检查(最多一个)→ tools 收集 + orderTools 排序 → contexts 收集 → waterfall 分发 → complete section 恢复。 - [历史从事件日志重建,不是从聊天界面](https://www.echovic.com/handbook/deepseek-harness-internals/09-surface-derive-messages): 模型看到的历史消息不是从 UI 状态数组取的,而是从 session 事件日志通过 surface 投影规则重建。只有三类事件能进 surface(user/message、assistant/message、tool/result),且必须携带 surfaceOp 标记。assistant/chunk、turn/start/end、step/start/end、usage、request/header 等都不入模型历史。deriveEventMessage 是 THE 投影规则:空 content 的 assistant/message 投影为 null(不传给模型),其他事件逐类型映射。surface 维护一个 nodes 数组(当前可见的事件 seq 列表),支持 append 和 replace 两种操作。append-origin 事件构成人类 transcript,replacement 事件只影响模型可见 surface,原事件不删除——这让 compaction 可以替换一段历史而不抹掉用户实际看到的内容。 - [LLM Service、流式 chunk 与 BlockAssembler](https://www.echovic.com/handbook/deepseek-harness-internals/10-llm-service-boundary): 本章追踪一个请求从 agent loop 的 buildRequest 出发,经过 prepareCall 锁定 adapter、markAgentLoopRequest 深冻结、llm/stream waterfall 分发、adapter.stream() 产出 StreamChunk,到 BlockAssembler 增量组装为 ContentBlock 并写入 session log 的完整路径。核心设计:PreparedLlmCall 通过闭包捕获 registration 防止 HMR 竞态;deepFreeze 保证 loop 请求的可重建性;waterfall 允许插件短路或包装流;BlockAssembler 容忍乱序和 straggler delta;每个原始 chunk 都记为 assistant/chunk 事件,最终组装消息以 surfaceOp append 和 sourceEventSeqs 引用 chunk 序列号提交。 - [流式响应:chunk 怎样变成消息](https://www.echovic.com/handbook/deepseek-harness-internals/11-stream-to-events): BlockAssembler 是 harness 中从 chunk 流到结构化消息的唯一增量组装算法。adapter 通过 async iterator 逐个产出 StreamChunk,agent loop 对每个 chunk 执行两步操作:先 session.append('assistant/chunk') 持久化(durable-first),再 assembler.push() 更新内存状态。BlockAssembler 内部维护一个 Map 和 order 数组,支持七种 chunk 类型(block-start / text-delta / reasoning-delta / tool-call-delta / block-end / usage / finish)。它兼容两种协议:完整协议(有 block-start/block-end 包裹)和 delta-only 协议(只有 delta,ensure 方法自动创建 partial)。block-end 冻结 partial 后,后续 straggler delta 被静默忽略以防 misbehaving adapter 破坏已关闭块。流结束后,blocks() 按 order 顺序组装 ContentBlock 数组——如果 finish.kind 是 max-tokens,过滤掉所有 tool-call(不完整 JSON arguments 不可执行)。没有 finish chunk 时 finish getter 默认返回 {kind:'stop'}。最后 createAssistantMessage 包装 blocks,append assistant/message 事件,携带 surfaceOp:'append' 和 sourceEventSeqs(引用所有 chunk 的 seq),建立完整的 provenance 链。finish reason 决定后续路径:error/aborted 走 agent/request-error waterfall 重试;max-tokens 返回 step-end;有 tool-call blocks 则 executeToolCalls;否则 step completed。 - [Retry、Abort 与 turn 结账](https://www.echovic.com/handbook/deepseek-harness-internals/12-retry-abort-turn-settlement): 一个 turn 的失败处理和结账分三层。第一层:llm-retry 插件通过 agent/request-error waterfall 实现指数退避重试,有 normal(白名单 codes + maxRetries 上限)和 always(无限重试直到取消)两种模式,每次 retry 先持久化 llm/retry 事件再等待(durable-before-wait)。第二层:turn 级状态管理,max-tokens 具有粘滞性——一旦某 step 命中上限,后续 completed step 不能降级 turn 结果。第三层:Abort 和保证结账——AbortController 是 per-phase 的,abort 后已启动 tool calls drain 到完成、未启动的写入 synthetic error,finally 块保证 turn/end 无条件写入。 - [工具调度器与注册域](https://www.echovic.com/handbook/deepseek-harness-internals/13-tool-call-scheduler): 工具调用在 Harness 里不是"找到函数 → 传参 → 拿返回值"。ToolRuntime 是一个三合一结构:分层注册域(global/ancestor/own 三层 ScopedLayers)、四阶段执行管线(pre-execute → around-dispatch → post-execute → finalize)、以及一个滚动并发调度器(executeToolCalls)。调度器把每次助手回复的 toolCalls\[\] 按 executionMode 分为 parallel 和 exclusive 两类:parallel 组进入一个 maxParallelToolCalls(默认10)大小的滚动池并发执行,exclusive 调用独占整个 step 形成 barrier。分类是 fail-closed 的——只有 isConcurrencySafe 严格返回 true 才走并行,其他一切(未声明、抛异常、返回 truthy 非 boolean)都回退 exclusive。更精妙的是:调度器在每次提交后重新分类后续调用,允许执行中的工具通过替换注册来动态改变后续调用的并发策略。 - [工具注册和作用域:谁能看到什么工具](https://www.echovic.com/handbook/deepseek-harness-internals/14-tool-registry-scope): 工具不是放在一个全局 Map 里。ScopedLayers 分 global 和 per-scope/agent layers;view() 过滤只作用于 inherited tools,scope 自己注册的工具豁免过滤;run_code 不在任何 layer,code-mode 时懒加载追加不能被移除;isConcurrencySafe 是 opt-in,classifier 抛错返回 exclusive。 - [工具参数校验与并行执行池](https://www.echovic.com/handbook/deepseek-harness-internals/15-tool-argument-validation): 参数校验在 defineTool 编译时就将作者 DSL 压缩为 JSON Schema 子集,execute 包装在 body 前硬校验;并行执行池以 executionMode(parallel/exclusive)分类调度,用 maxParallelToolCalls 滚动窗口重叠 dispatch,同时以 slot 数组和 committed 指针保证结果按模型顺序提交。 - [并行工具调用:顺序和屏障](https://www.echovic.com/handbook/deepseek-harness-internals/16-parallel-tool-execution): 并行不是"一起跑"。executionMode() fail-closed 分类,连续 parallel 为一组,exclusive 形成包含 post-execute 的全屏障;只有 body 并发,pre/post 串行;commitReady() head-of-line 保序;run_code 内部有镜像调度器;abort 时 drain started calls,remaining 记 synthetic error。 - [审批三件套:Permission、Approval、AskUser](https://www.echovic.com/handbook/deepseek-harness-internals/17-permission-approval-askuser): Permission 是配置打包,Approval 是服务编排,AskUser 是模型工具——三个独立系统协作构成完整的人机审批闭环。本章把 PreToolDecision 三态、ApprovalService 的 fail-closed 决策链、ToolGuard 的单调否决、sandbox escalation 的 deny-then-retry 编排,以及 ask_user_question 与审批流的边界逐层拆开讲清楚。 - [Bash、Subprocess 和 PTY:各管哪段生命周期](https://www.echovic.com/handbook/deepseek-harness-internals/18-bash-subprocess-pty): 读者常把"Bash 工具"、"子进程管理"和"PTY"当作同一件事的不同叫法。实际上它们是四层明确分离的架构:tool-bash(模型接口)、ShellExecutor(命令语义)、SubprocessRuntime(进程原语)、terminal-bash(终端仿真)。本章把四层的职责、生命周期所有权和交互边界按顺序拆开,方便你在调试或扩展时快速定位问题属于哪一层。 - [结果太大了:Spill、截断和外溢](https://www.echovic.com/handbook/deepseek-harness-internals/19-spill-truncation): Spill 不是工具内置的,是独立插件 @deepseek-ai/dsh-spill-policy 以 prepend:true 注册到 tools/post-execute。先 await next() 让下游 hook 看到完整结果再检查大小。两个 arm:模型面 arm 跳过顶层 read 工具防 read-spill-read 循环;durable-log arm 处理 code-mode 子调度日志且 read 也参与。SpillStore.saveText best-effort,失败保留原文不报错。字节预算预留 notice 开销,head+tail 50/50 split 生成预览。spill 只替换 model-facing content,不替换 canonical value。shell 有独立的 maybeTruncate 硬截断,与 spill 是两层不同机制。 - [append-only Session 与 Event 信封](https://www.echovic.com/handbook/deepseek-harness-internals/20-session-append-only): Session 是一个 append-only 的 SessionEvent\[\] 数组。每个事件携带结构化信封(seq/type/time/data/ignorable/surfaceOp/sourceEventSeqs)。seq 严格等于数组索引,保证连续性。Surface 投影从事件日志派生而非独立存储。Event 类型分两大类:surface-eligible(产生 LLM 消息)和 log-only(边界/追踪/元数据)。append() 经过七层防御保证日志只增不改。 - [Event Envelope:每个事件必须带的身份证](https://www.echovic.com/handbook/deepseek-harness-internals/21-event-envelope): 每个事件必须携带type、seq、time、data四个字段。seq === log.length,从0连续。只有三类事件(user/message, assistant/message, tool/result)是surface事件能带surfaceOp和sourceEventSeqs。ignorable默认false——遇到未知事件类型refuse to resume,而非静默跳过。 - [Surface 投影:模型看到的历史不等于你看到的](https://www.echovic.com/handbook/deepseek-harness-internals/22-surface-projection): Surface是session event log的有序投影——模型可见的消息历史。它不是日志本身,而是由surfaceOp标记从日志中选择性派生出来的。只有user/message、assistant/message、tool/result三类事件能进入Surface。surfaceOp有两种:append追加到尾部,replace用新节点替换\[start,end\]闭区间内的旧节点。SurfaceManager做增量fold,每次访问nodes/replaceGeneration时懒处理delta。deriveMessages()在Surface之上做per-node投影缓存——append只投影新节点O(new),replace触发全量重建。投影结果是frozen Message数组,与delivery和durable history共享同一份冻结对象。 - [投影(Projection):同一份日志长出不同状态](https://www.echovic.com/handbook/deepseek-harness-internals/23-session-projections): 同一份append-only日志可以派生多种状态视图。requestHeader()用headerFoldSeq增量fold只处理新events,canonicalHeader+headerEquals做规范化比较。RuntimeContextProjection反向扫描找到最后一个owned user/message做去重,避免每步重复注入。applyGoalProjection对非goal事件Object.is门控返回同引用。所有投影结果deepFreeze。 - [JSONL 原子写与崩溃恢复](https://www.echovic.com/handbook/deepseek-harness-internals/24-jsonl-crash-recovery): 深入剖析 session-persistence-jsonl 的原子写保证、write-behind 批量策略(默认200ms窗口)、以及 interruptedTurnClosers 崩溃恢复算法。每个事件占一行 JSON、部分行等于未完成事件、重启后丢弃最后不完整行并合成确定性关闭事件。 - [Resume、Fork、Compaction——上下文改写术](https://www.echovic.com/handbook/deepseek-harness-internals/25-resume-fork-compaction): 三条上下文改写路径的完整数据流。Resume:AgentLoop.resumeWith→persistence.prepare(id,signal)→SessionPreparation→Session.fromRestore(id,seed,header) transfer ownership(freezeRestoredObject不structuredClone)→seed循环surfaceManager.validateNext→append session/end-seed标记firstLiveSeq→prepare→enter→announce→emitAgentEvent(session-start,resume)。Fork:SessionStore.fork(source,boundary?,childId?)→_resolveForkSource验证live→_forkSeed检查boundary连续且不在open turn内→events.slice(0,boundary+1)→sessions.create(childId,{seed,meta:{parentSession,seedLength,cwd}})→子session构造replay+end-seed。Compaction:surfaceOp:{op:replace,start,end}追加新事件遮蔽旧surface节点→sourceEventSeqs完整覆盖→foldSurface/SurfaceManager增量维护nodes→replaceGeneration计数器驱动deriveMessages缓存重建。两阶段实现:阶段一model-free tool-result-pruner(只改content受assertToolResultRewrite约束);阶段二LLM摘要生成replace user/message;事务bracket compaction/start…compaction/end包裹异步操作;toolPairingBalancedBefore/After保证边界不切断tool-call/result配对。 - [Goal 为什么是事件流而不是字段](https://www.echovic.com/handbook/deepseek-harness-internals/26-goal-as-events): Goal 不是 Session 上可覆盖的字段。七种操作全部追加 goal/change 事件到 append-only 日志:非 clear 操作写入完整 GoalSnapshot(whole-value,last-wins 投影),clear 写 tombstone。foldGoal 是纯函数,对事件序列做严格归约——seenGoalIds 防 id 重用、requireNextRevision 保证 CAS、validateSnapshotTransition 校验 phase FSM、nextMutationTime 防时钟回拨。GoalActivation(armed/disarmed)是进程本地状态,绝不持久化,session-start 强制 disarmed。 - [Phase、Revision、Round——三道演化闸门](https://www.echovic.com/handbook/deepseek-harness-internals/27-goal-phase-revision-round): GoalPhase(active/paused/blocked/complete)是持久化状态,GoalActivation(armed/disarmed)是进程本地状态,两者完全分离。Revision是CAS乐观锁:create必须revision=1,其他所有mutation(包括clear)必须revision=current+1,精确推进一版。Round不通过goal/change递增,而是通过user/message的source.kind='goal'携带round号推进,fold验证round===roundsStarted+1。非法phase transition、时间倒退、counter漂移都让恢复失败。resume允许从active(disarmed)重新armed。block需要blockedReason(code+message)是策略驱动,pause是用户主动。 - [Plan、Todo、Schedule——Goal 的三个邻居](https://www.echovic.com/handbook/deepseek-harness-internals/28-plan-todo-schedule): Goal 的三个邻居各有分工。Plan Mode 是协作模式开关——/plan 命令触发,plan/mode 事件 last-wins fold 决定当前状态,active 时往 system prompt 注入 plan:policy 段但绝不改工具集,退出必须通过 exit_plan_mode 获得用户 Approve;PlanModeController 用 pendingIntents WeakMap 在 open turn 内暂存选择,等 agent/pre-step 边界再 append。Todo 是模型可见的当前 turn 工作列表——todo_write 每次传完整列表整体替换(无增量 API),toTodoList 校验唯一性和 in_progress 并发数,projection 在 turn/start 清零为 null。Schedule 是持久化定时器——after(延迟一次)、at(绝对时间一次)、every(固定间隔循环,最小 300 秒)三种规则写入 schedule/change 事件流;ScheduleRuntime 是进程内 disposable 投影,driveOnce 做 preflight flush、foldScheduleEvents 重播、dueDecision 唤醒判断,dispatch 时通过 renderReminderFraming 注入防注入 framing 的 user message 并由 agent.followup 入队。三者互不依赖,各自通过 session 事件日志与 Goal 系统平行共存。 - [Subagent 出生与 lineage 管理](https://www.echovic.com/handbook/deepseek-harness-internals/29-subagent-lineage): 揭示 subagent 的完整父子树结构:depth 单调递增、lineage 持久化、one-shot 与 continuable 两种生命周期形态、以及 parent mailbox 通信机制。 - [Parent Mailbox:父 Agent 怎样接住子 Agent 的结果](https://www.echovic.com/handbook/deepseek-harness-internals/30-parent-mailbox): 子Agent向父通信分两条路径——主动报告(reportFrom + report工具)和结算通知(notifySettlement)。reportFrom通过deliverReport实现,支持wakeup(默认,idle父followup开新turn,busy父steer注入当前turn)和quiet(inject不唤醒)。结算通知是manager在child disposal流程中自动发出的,有严格的顺序约束:必须在releaseOwnership之前发送,否则父可能在通知到达前被判定为settled然后cancel清空inbox导致消息丢失。ChildLock用per-child Promise链串行化同一子agent的所有操作(followup/cold-resume/dispose),通过then(op,op)模式保证前序失败不毒化后续操作。sendWaking里admitWaking在发送前先把messageId加入activation.accepted集合,防止Agent.status的idle窗口导致误判settlement。cold resume不经过provider,直接从persistence恢复session状态重建Activation。 - [Workflow:Worker 线程里的脚本编排](https://www.echovic.com/handbook/deepseek-harness-internals/31-workflow-worker-runtime): 追踪一段 workflow 脚本从 start() 校验到 Worker 线程内 vm.Context 沙箱执行,再到子 agent RPC、并发槽位、取消/grace/terminate 的完整流程。 - [收束:Cancel、Dispose 和多 Agent 清理](https://www.echovic.com/handbook/deepseek-harness-internals/32-multi-agent-teardown): Cancel 和 Dispose 方向相反:Cancel top-down(父先停再通知子),Dispose child-first(子先释放再释放父)。finishDisposal() 精确步骤:wake activation → 同步 cancel({ kind: 'parent' }) 在第一个 await 之前 → 拿 whenIdle() Promise → 收集 ownedChildren 映射到 Activation → 启动所有子 dispose → await Promise.all(childDisposals) child-first → await idle 等 turn 结束 → flushFinalState best-effort → observer.capture 在 handle 还活时 → handle.dispose() 释放 Agent 句柄 → activations.delete 从 map 移除 → notifySettlement(先于 releaseOwnership 防父误判)→ releaseOwnership 释放 ownership → observer.settle(failure) 发射终态事件。Disposal memoization:activation.disposal 字段首次赋值后所有并发调用返回同一个 Promise。Cancel 不回滚已发生 side effects,只停止未开始工作。keepInbox:true 用于 interrupt 场景。drainDescendants 只停指定父的后代不影响其他树。Initiator scope 通过 closeInitiators 级联,withoutInitiator 脱离(ScheduleRuntime 用它防止 followup 被错误清理)。FactoryOwnership 管理 factory-level 生命周期:track live agents、trackStartup、abort signal、并行 dispose 全部。 - [Capability Seam 与 cordis.yml 组合](https://www.echovic.com/handbook/deepseek-harness-internals/33-capability-seam): Capability Seam 定义了 DSH 能力接入的三角色架构:Service Definition 声明接口契约、Provider 实现并 provide、Consumer 通过 inject 消费。cordis.yml 用声明式 YAML 替代命令式注册,支持 id-targeted patch、!!js 表达式、group isolate 多实例。 - [cordis.yml 怎样声明可替换的组合](https://www.echovic.com/handbook/deepseek-harness-internals/34-cordis-yml-composition): prepareProfile每次启动writeFileSync将profile目录下的cordis.yml覆写为PROFILE_ROOT_CONFIG(空数组\[\]加注释),这个文件存在只是因为Loader需要一个真实的include root来锚定baseUrl(profile目录),Loader的tree write-back(plugin self-disposing时持久化当前tree)可能把组合行烤入这个文件,下次启动如果不清空会导致bundle insert重复;真正的组合来自五层patch按顺序叠加:bundlePatches(package.json dsh.profile.bundles顺序)→profile.patches(profile目录的cordis.patch.yml)→homePatches($DSH_HOME/cordis.patch.yml,机器本地偏好,跨profile生效)→overlays(--patch命令行参数)→telemetryPatch(DSH_TELEMETRY_DISABLED开关);YAML顶层是EntryOptions数组,每个entry有id(稳定标识用于patch)、name(npm包名或cordis:include/cordis:group)、config(配置对象)、disabled(布尔);config里支持!!js前缀的YAML scalar,被JsExpr schema解析为{__jsExpr:string},Loader在entry激活时eval该表达式,可以访问process.env和ctx上的运行时值;applyEntryPatches先structuredClone输入,buildMap递归索引所有entry(包括group的config子entries),然后逐个patch:有insert且有id则向目标group的config push新entries,有insert无id则push到顶层,有overrides(disabled/config等)则id-targeted覆盖目标entry的字段,找不到id的patch warn跳过;cordis:group是特殊builtin entry,group:true表示它的config是子entries数组,可以配合isolate:{serviceName:true}创建isolate realm——子entries在该realm内注册服务,true表示entry-local realm用新Symbol,不会与其他preset冲突;HMR通过watchUserPatches监听patch文件变化,变化时调用composeLive()(structuredClone五层fresh read),entry.update(newPatches)→Loader重新apply patches→旧Fiber进入UNLOADING→_unload() LIFO执行disposers→新Fiber创建→_reload()执行plugin callback→effect scope自动清理旧贡献注册新贡献。 - [Skills:发现、装载和上下文注入](https://www.echovic.com/handbook/deepseek-harness-internals/35-skills-discovery-injection): 本章以机制剖析(Mode A)视角,完整呈现 DSH Skill 子系统从磁盘发现到模型上下文注入的四阶段管线: 1) skill-filesystem 扫描多层根目录,解析 YAML frontmatter 产出 SkillCandidate; 2) SkillRegistry 通过 ScopedLayers 合并全局与 per-agent 层,rank+providerOrder 决定同名胜出; 3) tool-skill 插件在 agent/pre-step 钩子发布 skill catalog 系统消息,并注册 `skill` tool; 4) 用户显式 `/name` 手势或模型调用 `skill` tool 触发完整 body 注入。 每一阶段均附带源码证据和数据流图解。 - [MCP 工具注册与 Repository Plugin](https://www.echovic.com/handbook/deepseek-harness-internals/36-mcp-tool-registry): MCP 工具通过 McpClientBridge 插件进入 DSH:每个 MCP server 一个实例,连接管理器负责重连,syncTools 做两阶段原子交换(先构建新工具集,再一次性替换旧的),publicToolName 加命名空间前缀并截断到64字符。执行时走和原生工具完全相同的 ToolRuntime 流水线。Repository Plugin (tool-cordis) 让 agent 通过 define/run/stop/undefine 四个工具动态增删 MCP server。 - [Repository Plugin 和 Self-modification](https://www.echovic.com/handbook/deepseek-harness-internals/37-repository-plugin-selfmod): 当在某个cwd下启动dsh或切换workspace时,skill-filesystem provider调用findProjectRoot(cwd)向上查找.git目录确定project root;找到后自动加入两个扫描roots:``/.dsh/skills(source=project-dsh,rank=100最高优先级)`和`/.agents/skills(source=project-agents,rank=200);这两个目录下的SKILL.md或.md文件自动被发现、解析frontmatter、注册到global layer的skill catalog——不需要在cordis.yml里显式声明,打开项目就有项目专属skills;MCP servers和bundles通过类似机制加入——Repository Plugin本质是workspace cwd敏感的自动能力发现;tool-cordis包注册了一组dynamic Cordis tools:cordis_inspect_list/cordis_inspect_query/cordis_inspect_self(只读检视)、cordis_define(创建新Plugin或追加Package版本,包含source code和metadata)、cordis_run(启动host/client halves执行代码,需approval)、cordis_stop(停止active run保留packages)、cordis_undefine(移除Plugin及所有packages);这些工具让模型能在运行时动态编写并加载Cordis插件——但修改受scope边界约束:dynamic plugins由agent session拥有,ctx.dynamicCordisRunner的define/run/undefine方法要求exec.agent参数,只能操作当前session拥有的plugin,不能修改root composition或其他session的plugin;Self-modification的核心边界是generation:Cordis HMR通过Fiber.restart()实现——_setEpoch(INACTIVE)→_unload() LIFO执行所有disposers(取消tool注册、移除prompt section、注销skill provider、断开MCP连接等)→_reload()用新config重新执行plugin callback→注册新effects→provide新services;关键的是:已存在的Agent和Session持有的是旧generation的引用——AgentPresets用standing mount机制,每个compositionStamp(mtime+size)对应一个generation,旧generation在最后一个joined agent离开前不dispose;HMR只影响之后创建的Agent/Session;已创建session的header记录agentPreset id,resume时恢复到同一preset的当时generation(通过standing key);effect scope管理撤销:所有资源注册都通过ctx.effect()返回disposer,Fiber dispose时这些disposer按LIFO执行——这保证了"注册的反向顺序清理":如果A effect注册了资源X,B effect注册了资源Y依赖X,清理时B先dispose(Y释放),然后A dispose(X释放),不会use-after-free;Fiber._unload中_disposables.clear()返回所有disposers,Promise.all并行await(但disposer内部顺序由LIFO保证);HMR配置层的watchUserPatches监听cordis.patch.yml变化→composeLive()fresh read所有层→entry.update(newPatches)→触发Fiber restart→新服务注册旧服务清理→skills/change事件通知catalog刷新→MCP reconnect resync tools。 - [Agent Preset:给单个会话换一套运行时](https://www.echovic.com/handbook/deepseek-harness-internals/38-agent-preset): AgentPresets extends Service(agentPresets),inject=\[loader\]。每个preset是一个目录(目录名=id,匹配/^\[a-z0-9\]\[a-z0-9-\]*$/),含agent.cordis.yml(Cordis EntryList组合)和可选preset.yml(name/description/order)。Discovery扫描roots子目录做浅层YAML健康检查,缺文件或解析失败标broken。Trust分两级:system(shipped,不可写)和user(authored,可写);first-root-wins同id system优先。mount流程:scopeOf取agentKey→resolveMountable拒绝broken→ensureStanding单flight(Map>)→createScope({agentPreset:id})→PresetTree(Include子类,import重写让bare specifier从harness base解析,write禁止)加载agent.cordis.yml→inactiveRows+leakedServices审计→bindScopeParent(agentKey,standing.key)。CompositionStamp(mtimeMs+size)驱动generation轮转。preset内service必须在cordis:group+isolate:true里(entry-local realm),否则leak到root realm被reject。composeFrom同步bind到parent standing mount(不重新resolve,保证子看到相同generation)。recompose通过binding.rebind切换(调用方负责blank检查)。resolveSessionPreset从events尾部找agent-preset/selected事件恢复正确preset。Authoring是copy-only(整目录cp+tightenModes+metadata rewrite)。 - [Headless CLI 与 JSON-RPC Server——两种产品面](https://www.echovic.com/handbook/deepseek-harness-internals/39-headless-cli): Headless CLI 创建一个 Agent、投递一条消息、等跑完、输出文本、退出进程——进程就是任务的生命周期。JSON-RPC Server 反过来:进程启动后持续存活,通过 stdio JSON-RPC 协议接收外部请求,按 sessionId 复用或创建 Agent,notification 推送事件流,直到显式 shutdown。两者共享同一套 Cordis 基础设施和同一个 Agent 实现,差异仅在"进程对外的面"——是一次性命令还是长驻协议服务。 - [JSON-RPC Server:长期进程的暴露方式](https://www.echovic.com/handbook/deepseek-harness-internals/40-jsonrpc-server): JSON-RPC Server 是常驻进程。构造时订阅 ctx 上的 session/event、agent/status、session/created、subagent/end 四个事件源,通过 transport.notify 推送给客户端。客户端先发 initialize 握手(传 cwd/provider/model/maxTokens),然后通过 session/prompt 投递消息,server 用 getOrCreateSession 做去重创建(sessionCreations Map 防并发),拿到 Agent handle 后调 followup。session/event、session.status、subagent.started、subagent.finished 四个 notification 持续推送。shutdown 时先等 pending 创建完成、再 dispose 所有 Agent、再 dispose adapter、再取消所有订阅——drain 完毕才返回。 - [TypeScript 和 Python SDK 共享一套协议](https://www.echovic.com/handbook/deepseek-harness-internals/41-typescript-python-sdk): 你在 TypeScript 里 `new HarnessClient(options)` 或 Python 里 `DeepSeekHarness()`,SDK 会 spawn 一个 dsh-runtime 子进程,通过 stdio 用换行分隔的 JSON-RPC 通信。协议类型定义唯一存在于 `packages/sdk/protocol/src/types.`ts——TS client 和 Python client 都照着这套 shape 实现,但不共享代码(Python 用 pydantic model 重新声明等价类型)。SDK 封装了子进程生命周期(start→initialize→prompt→subscribe→close)、stderr tail 收集、超时 abandon、notification 队列和订阅过滤、子 agent session 树追踪。SDK consumer 看到的接口只有 initialize/prompt/subscribe/close,完全看不到 Cordis、AgentLoop、Session、Surface 这些内部概念。SDK 也支持 embedded 场景——你可以把 dsh runtime 嵌入自己的应用,不通过命令行启动。 - [ApiProxy 与 SDK:Web 的控制面和客户端协议](https://www.echovic.com/handbook/deepseek-harness-internals/42-apiproxy-control-plane): 你用浏览器打开 DeepSeek Harness 时,所有操作走的是 ApiProxy——一个 HTTP/SSE 网关控制面,注册了 40+ RPC 方法,管理 session 的创建/恢复/去重/fork、事件投影、设置热更新和审批流。你用 TypeScript 或 Python SDK 编程驱动 Agent 时,走的是完全不同的路径——一个 stdio JSON-RPC 子进程协议,只有 3 个请求方法(initialize / session/prompt / shutdown),session 靠首次 prompt 延迟创建。两者看起来都是"调用 Agent",但协议模型、传输方式、生命周期管理、事件推送机制全部不同。它们共享的是底层的 Agent 注册表和 Session 持久化,而不是任何客户端协议。 - [Conversation UI:消费事件但不冒充事实源](https://www.echovic.com/handbook/deepseek-harness-internals/43-conversation-ui-projection): 浏览器里的对话界面不持有任何"真实状态"。它是 Host 进程通过 WebSocket MuxFrame 流推送事件的纯投影消费者。Client Runtime 不引用 Session、不引用 Agent、不引用 Cordis 容器。数据流是单向的:Host 的 session log 是 append-only 的唯一事实源,events 通过 mux 流到达客户端;客户端的 SessionManager 将 frame 分发到各个独立的 projection store(conversation、projection-value、queue 等);每个 store fold 自己关心的 frame 类型产出不可变 snapshot;React 组件订阅 snapshot 变化。用户操作全部通过 ApiProxy RPC 发回 Host——本地不先改状态。人类 transcript 用 isAppendSurfaceEvent 筛选 append-origin 事件,surface 的 replacement 操作只给模型看。ProjectionValueStore 遵循 higher-seq-wins 规则接收 host 端已计算好的投影值,客户端零 domain folding。断线重连不走本地持久化,而是重新订阅 mux 流加拉 history tail 重建全部 projection baseline。ToolCallView/ToolResultView 是 host 端 presenter 在事件发射时派生的渲染意图——纯数据描述,从不持久化到 session log,客户端只做形状映射。 - [凭证隔离、Telemetry 与 Mock 测试](https://www.echovic.com/handbook/deepseek-harness-internals/44-credentials-out-of-log): 本章剖析三项机制:(1) 凭证隔离——schema 声明的 role('secret') 字段在跨 wire 边界前被结构化剥离,assertUsableApiKey 拒绝非法凭证时绝不回显原始值;(2) Telemetry——SessionTelemetryCoordinator 按 live/on-demand 两种模式采集 session 事件,通过 session-telemetry/record waterfall 做导出前脱敏,OTel backend 映射至 OTLP/HTTP logs,DSH_TELEMETRY_MODE 环境变量控制启停;(3) Mock 测试——llm-mock-server 提供 26 种脚本化行为、种子随机选择和完整的请求录制,让重试与恢复逻辑获得确定性验证。 - [Telemetry 不能反过来定义会话](https://www.echovic.com/handbook/deepseek-harness-internals/45-telemetry-capture): Telemetry/feedback是观测侧车不是事实源,MessageFeedback存per-message rating+note但从不创建/恢复会话,sameIdentity用createdAt+cwd识别生命周期,版本化乐观并发防冲突,写入前ensureTargetDurable,note是明文无E2E加密。 - [Trajectory、Query 和 Replay](https://www.echovic.com/handbook/deepseek-harness-internals/46-trajectory-query-replay): SessionQueryEngine抽象search/list/read/trace能力,readSession()做重放验证不只是读取,traceEvent()跟踪replacement chain和derived events,analyzeEventLog()执行规范surface折叠,SQLite后端提供FTS,llm-replay适配器支持从记录重放LLM响应。 - [Mock LLM 和 Snapshot 测试](https://www.echovic.com/handbook/deepseek-harness-internals/47-mock-snapshot-testing): ACP Snapshot Harness启动真实agent bin子进程通过ACP JSON-RPC驱动,Record/Replay模式,InputStep脚本支持多步骤+变量替换,Normalizers去除时间戳等非确定性,LLM Mock Server有22种预设故障行为,每个包必须有src/invariant.ts companion(CI gate强制)。 - [Invariant:每个包都有自己的守卫](https://www.echovic.com/handbook/deepseek-harness-internals/48-invariant-catalog-docs): CI gate强制每个包有./invariant export和src/invariant.ts,Invariant通过@deepseek-ai/dsh-invariants注册为Cordis companion plugin,Session有pre/post commit两阶段验证,verify-runtime-closure BFS验证peer依赖闭包,生成式catalog防文档漂移。 - [安全分层:Trust、Permission、Sandbox、Network](https://www.echovic.com/handbook/deepseek-harness-internals/49-trust-permission-sandbox-network): Harness的安全不是单一sandbox围墙,而是四层独立机制的乘积组合。Trust层通过静态信任边界决定哪些代码进入同进程可信域;Permission层(ApprovalService)在service自身的decide()路径强制session策略,never策略在dispatch前截断,escalation只许严格widening且一次性批准无always-allow;Sandbox层(LocalSandboxProvider)通过平台runner chain(bwrap→Landlock→Seatbelt→Windows ACL)实现OS级文件隔离,fail-closed拒绝无runner的执行;Network层通过URL验证、credential剥离、same-origin redirect约束、大小/超时上限实现出站管控。四层独立——任何一层被攻破不自动导致其余层失效。 - [从一个 commit 到下一版:这本书怎样更新](https://www.echovic.com/handbook/deepseek-harness-internals/50-update-fixed-snapshot): 锁 commit 不是为了停在旧版,而是让每个"当前实现"有可复核对象。更新流程:建 detached checkout 确认干净 -> 五维度比较(package graph / public symbols / event vocabulary / config schema / 产品入口)-> 四类证据分别刷新(源码引用 / 可复现实验 / Web 截图 / 叙事审计)-> 最小更新闭包验证 -> doc-sync gate 通过 -> 真实 dogfood 不碰源码。配置声明只能证明"可以怎样组合",类型声明只能证明"允许传什么",只有调用点和状态写入能证明实际运行。doc-sync gate 包含 20+ 验证子任务:cordis catalog 一致性、type equivalence、markdown links、doc refs、mermaid 语法、export jsdoc 等。 ### 深入浅出 Pi - [深入浅出 Pi](https://www.echovic.com/handbook/pi-internals): 从 Agent Loop 到完整运行时。沿 earendil-works/pi 的固定源码版本,追踪模型适配、Agent Loop、工具执行、会话树、扩展系统与终端界面怎样组成一套可嵌入的 Agent 运行时,并明确已实现行为与 Harness v2 设计之间的边界。 - [先固定版本,再谈 Pi 的架构](https://www.echovic.com/handbook/pi-internals/01-fix-version-and-map): 先固定源码,再用实际调用点建立 Pi 地图;package.json 负责说明发布与依赖边界,不能替代运行时控制流。 - [一个 pi 命令,四种运行方式](https://www.echovic.com/handbook/pi-internals/02-cli-entrypoints-and-modes): Pi 的内部模式是 interactive、print、json、rpc;其中 print 与 json 共用单次执行器,RPC 则保留 stdin 作为长驻双向协议。 - [启动阶段到底组装了什么](https://www.echovic.com/handbook/pi-internals/03-runtime-assembly): Pi 先确定有效会话 cwd,再创建 cwd 绑定的设置、资源与模型服务,解析 session 选项并构造会话,最后才安装具体 I/O 模式。 - [配置、信任与资源从哪里进入](https://www.echovic.com/handbook/pi-internals/04-settings-trust-resources): SettingsManager 合并全局与已信任项目配置;ResourceLoader 先以不信任状态预载,再解析 trust 并重新加载 extensions、skills、prompts、themes 与上下文文件。 - [`createAgentSession()` 怎样交出一个可运行会话](https://www.echovic.com/handbook/pi-internals/05-create-agent-session): createAgentSession() 先解析 cwd 与服务默认值,再恢复模型状态、建立工具策略和底层 Agent,最后由 AgentSession 接管事件、持久化、扩展与系统提示组装。 - [AgentMessage 为什么不能直接发给模型](https://www.echovic.com/handbook/pi-internals/06-agent-message-boundary): AgentMessage 是 Agent 状态与上层产品的可扩展消息联合;模型调用前,transformContext 先处理完整 AgentContext,convertToLlm 再把它投影为 pi-ai Message\[\]。 - [模型目录与 Provider Registry 各管什么](https://www.echovic.com/handbook/pi-internals/07-models-and-provider-registry): 生成目录保存内置模型元数据,Provider 提供认证、枚举和 stream 行为;coding-agent 的 ModelRuntime 再组合内置、扩展与 models.json 覆盖,ModelRegistry 只是兼容门面。 - [密钥与 OAuth 怎样落到一次请求](https://www.echovic.com/handbook/pi-internals/08-auth-and-credentials): CredentialStore 保存按 provider 分组的 API key 或 OAuth 凭据;请求开始时,认证策略按显式覆盖、已存凭据和 ambient 来源解析,再由 Models 合并 headers、env 与 baseUrl。 - [请求发出前,Context 还会经历什么](https://www.echovic.com/handbook/pi-internals/09-request-context-options): Agent 消息先投影成只有 systemPrompt、Message\[\] 与 tools 的 Context;streamSimple 再按模型窗口收紧输出预算并传递通用 options,具体 API 最后生成 payload。 - [流式响应怎样变成可消费事件](https://www.echovic.com/handbook/pi-internals/10-streaming-event-stream): provider 适配器把原始增量写入统一 AssistantMessage,并发出 start、内容增量与 done/error;EventStream 同时支持异步迭代和 result(),Agent loop 据此维护消息状态。 - [不同模型 API 怎样被压到同一接口](https://www.echovic.com/handbook/pi-internals/11-provider-normalization): 每个 API 模块对上实现相同的 stream 与 streamSimple,对下各自编码请求和解析响应;共享 transformMessages 先修复跨模型历史、图片与工具调用约束。 - [重试、溢出与中止在哪一层收口](https://www.echovic.com/handbook/pi-internals/12-retry-overflow-abort): provider 层在一次 stream 内重试瞬时 transport 错误;会话层以可见退避重启失败 turn;context overflow 先进入压缩恢复,成功响应只压缩不重放,中止则终结对应请求或等待。 - [`Agent` 怎样把事件还原成状态](https://www.echovic.com/handbook/pi-internals/13-agent-state-wrapper): Agent 在启动一场 run 时复制消息与工具作为循环输入,再按消息、工具和 turn 事件归约公开状态;配置字段仍可直接修改,因此这是一层运行时状态外壳,不是可持久重放的事件存储。 - [两层循环为什么缺一不可](https://www.echovic.com/handbook/pi-internals/14-two-level-agent-loop): 一场 Agent run 可以包含多轮 provider 请求;内层循环消化工具结果与 steering,外层循环只在 Agent 原本要停下时接入 follow-up,两层循环表达了两种不同的继续理由。 - [Steering 与 Follow-up 不是同一种排队](https://www.echovic.com/handbook/pi-internals/15-steering-follow-up-queues): Steering 在完整 turn 结束后、下一次模型请求前注入;Follow-up 只在 Agent 原本要停止时注入。两者各自按 drain point 执行 all 或 one-at-a-time 策略,入队时都尚未进入消息历史。 - [工具执行前先经过哪些检查](https://www.echovic.com/handbook/pi-internals/16-tool-preflight-validation): Pi 先拒绝整条 length-truncated 响应中的所有工具调用;正常调用再按工具查找、参数兼容处理、克隆与 schema 校验、before hook 和 abort 检查完成预检,失败被规范化为模型可见的错误结果。 - [并行工具为什么仍要保留原始顺序](https://www.echovic.com/handbook/pi-internals/17-parallel-tool-batches): 默认 parallel 模式先按模型给出的顺序完成预检,再并发执行允许的工具;结束事件反映真实完成顺序,Promise.all 的有序结果则让 ToolResult 按原始 tool call 顺序进入 transcript 与下一轮模型上下文。 - [一次 Run 怎样停止、失败与继续](https://www.echovic.com/handbook/pi-internals/18-stop-abort-continue): Run 可以自然耗尽、在完整 turn 后优雅停止、因协议 error/aborted 终止,或由 Agent 外壳把意外抛错规范化;abort 是协作信号,continue 则基于现有 transcript 建立一场新的 active run。 - [`AgentHarness` 为什么没有包住 `Agent`](https://www.echovic.com/handbook/pi-internals/19-agent-vs-harness): v0.83.0 中 Agent 和 AgentHarness 是两个并列的高层驱动器,二者都直接调用 runAgentLoop;前者管理实时 AgentState,后者把 Session、快照、Hook 与结构操作收进自己的控制面。稳定版 pi-coding-agent 仍走 Agent 加 AgentSession。 - [一轮请求为什么需要快照与保存点](https://www.echovic.com/handbook/pi-internals/20-turn-snapshot-savepoint): AgentHarness 在 prompt 开始和每个低层 turn 结束后构造新的 turn state。当前 provider 请求使用已解析的模型、系统提示、工具、资源、tool context 与流选项快照;turn_end 先完成事件和 pending write flush,prepareNextTurn 再重建上下文,让最新配置只影响下一次请求。 - [运行中改配置,什么时候才真正生效](https://www.echovic.com/handbook/pi-internals/21-hooks-pending-writes): v0.83.0 的 Harness setter 会立即更新最新运行配置并发事件;若处于 active operation,需要进入 Session tree 的部分先进入内存 pending queue,在保存点按接收顺序追加。当前请求继续使用旧快照,下一请求读取新配置;Hook 或 subscriber 失败不会回滚已经提交的状态。 - [Session 保存的是树,不是一串消息](https://www.echovic.com/handbook/pi-internals/22-session-tree-context): Session backend 保存按时间追加的 entry log,但会话拓扑由每条 entry 的 parentId 形成;active leaf 通过普通追加或持久化 leaf entry 推进。buildContext 只沿 active path 读取并应用 compaction transform,再把可投影 entry 转成 AgentMessage。 - [压缩与回到旧分支怎样改变上下文](https://www.echovic.com/handbook/pi-internals/23-compaction-navigation): compaction 不删除旧 entry,而是在当前 leaf 后追加摘要 entry,并让 context transform 用摘要加 retained tail 替代旧前缀;navigateTree 则把 active leaf 移到已有节点,可在新分支起点追加一条旧分支摘要。两者均是 idle-only 结构操作,且不构成跨多次 append 的事务。 - [持久会话为什么还不等于持久运行](https://www.echovic.com/handbook/pi-internals/24-storage-durability-boundary): v0.83.0 的 JSONL 与 SQLite backend 能保存 SessionTreeEntry、active leaf 和派生索引,但 AgentHarness 的 phase、run intent、队列、pending writes、provider request 与工具执行状态只在内存中。重开会话可以重建对话树,不会自动恢复一条未完成 run;Harness v2 文档提出的 operation log 与 crash resume 属于后续设计。 - [`AgentSession` 如何成为 Coding Agent 的控制面](https://www.echovic.com/handbook/pi-internals/25-agent-session-control-plane): AgentSession 持有底层 Agent、SessionManager、SettingsManager、资源与模型运行时,把 Agent 事件投影成扩展、UI 和 JSONL 更新,并在每次低层 run 后决定是否重试、压缩或继续队列。 - [一条 Prompt 在调用模型前还要过多少关](https://www.echovic.com/handbook/pi-internals/26-prompt-pipeline): prompt() 先允许扩展命令直接消费输入,再让 input hook 处理原文,随后展开 Skill 与模板;流中输入转为队列,空闲输入通过模型、认证和压缩预检后,才组装 user/custom messages 与本轮 system prompt。 - [JSONL 会话文件怎样记录一棵树](https://www.echovic.com/handbook/pi-internals/27-session-manager-jsonl): SessionManager 用 header 加带 id/parentId 的 entry 维护一棵 append-only 树;leaf 决定当前分支,compaction-aware projection 决定模型上下文,而持久文件通常延迟到首条 assistant 消息出现才创建。 - [恢复、分叉与切换会话不是同一个动作](https://www.echovic.com/handbook/pi-internals/28-resume-fork-replace-runtime): AgentSessionRuntime 的 resume、new 与 fork 都先终结并销毁旧 AgentSession,再用目标 cwd 和 SessionManager 创建完整新 runtime;同文件 branch 只移动 leaf,而产品级 fork 通常复制选定路径到新 JSONL。 - [模型切换与设置热更新怎样保持一致](https://www.echovic.com/handbook/pi-internals/29-model-runtime-settings): 模型切换先校验认证,再同步 Agent 当前状态、session model_change 与全局默认,并按新模型能力重算 thinking level;恢复时会话记录优先,reload 则刷新设置、资源和扩展 runtime,而不替换 AgentSession。 - [自动压缩、重试与用量统计怎样协作](https://www.echovic.com/handbook/pi-internals/30-compaction-retry-usage): AgentSession 先持久化每次 assistant 终态,再在 post-run 中区分普通瞬时重试与 overflow/threshold 压缩;压缩只重建活动消息,session stats 仍累计完整历史,而压缩后的当前 Context 在新 usage 到来前保持未知。 - [七个内置工具为什么默认只开四个](https://www.echovic.com/handbook/pi-internals/31-builtin-tool-registry): Pi 先建立包含七个 built-in definition 的 registry,再用独立的 active name 集合决定本轮交给模型的工具;默认四个只是产品选择,不是代码中只有四种工具。 - [读写文件时,Pi 怎样避免相互踩踏](https://www.echovic.com/handbook/pi-internals/32-file-tools-mutation-queue): edit 与 write 在真正碰文件前以 canonical path 进入进程内队列,同一 key 串行、不同 key 并行;它防住当前 Pi 进程内的写写竞争,但不提供跨进程锁或事务回滚。 - [Bash 输出太长时,完整结果去了哪里](https://www.echovic.com/handbook/pi-internals/33-bash-stream-truncation): Bash 以 OutputAccumulator 增量解码并只保留有界尾部,超过 2000 行或 50KB 时才创建临时日志保存完整原始字节;模型收到尾部、截断元数据和路径,而不是无限输出。 - [AGENTS.md、Skills 与 Prompt 模板怎样被发现](https://www.echovic.com/handbook/pi-internals/34-resource-loader): ResourceLoader 把 AGENTS.md/CLAUDE.md、Skills、Prompt 模板装成三种不同产物:上下文全文进入 system prompt,Skill 先暴露索引并按需读取,模板只在 slash 输入匹配时展开。 - [扩展代码从哪里加载,信任边界在哪里](https://www.echovic.com/handbook/pi-internals/35-extension-discovery-trust): Pi 先在 untrusted settings 下加载用户级、显式 CLI 与 inline extension,让它们参与 trust 决策;获准后才加入项目设置和资源。被加载的 factory 仍以宿主进程权限执行,trust 不是沙箱。 - [Extension Runner 怎样串起事件与变换](https://www.echovic.com/handbook/pi-internals/36-extension-runner-hooks): ExtensionRunner 按 extension load order 执行 handler,但不同事件有不同合同:普通事件广播并隔离错误,context/input 等串行变换,可取消事件短路,tool_call 异常则直接阻止执行。 - [自定义工具、Provider 与渲染器谁覆盖谁](https://www.echovic.com/handbook/pi-internals/37-custom-tools-providers-renderers): 同名 tool 先由 extension load order 选首个,再由 SDK custom tool 覆盖 built-in/extension;provider config 按已定义字段合并且后注册字段胜出;renderer 则按 extension 顺序取第一个。 - [不启动 TUI,怎样把 Pi 嵌进自己的程序](https://www.echovic.com/handbook/pi-internals/38-sdk-embedding): createAgentSession 只是移除了内置界面,默认仍装配模型认证、设置、会话持久化、资源发现和写工具;宿主若允许会话替换,还要通过 AgentSessionRuntime 重建 cwd-bound services,并在每次 replacement 后重新绑定事件与扩展。 - [同一场运行怎样投影成文本与 JSON](https://www.echovic.com/handbook/pi-internals/39-print-json-modes): text 与 JSON mode 共用 AgentSessionRuntime 和 prompt 执行路径;text 只取最后一条 assistant 消息的文本块,JSON 则先写可选 session header,再订阅随后 prompts 产生的 live session events,最后统一释放 runtime。 - [RPC 模式如何把会话变成可控制进程](https://www.echovic.com/handbook/pi-internals/40-rpc-mode-protocol): RPC mode 把 AgentSessionRuntime 留在长驻子进程中,通过 stdin/stdout 交换严格 JSONL;request response 只确认命令处理结果,prompt 的完成要等 agent_settled,session replacement 后还必须重绑 extension 与事件订阅。 - [`pi-server` 管的是进程,还是 Agent](https://www.echovic.com/handbook/pi-internals/41-pi-server-supervisor): pi-server 的 ServerSupervisor 持有实例记录、RPC 子进程和事件桥;AgentSession 与 Agent 仍活在子进程里。进程异常退出会留下 error 记录,server 重启只把旧 online/starting 改为 stopped,不会重建未完成运行。 - [Evals 怎样把 Agent 行为变成可检查结果](https://www.echovic.com/handbook/pi-internals/42-evals-and-observable-proof): pi-evals 直接把隔离的 AgentSession 接入 vitest-evals,将消息、工具调用、工具结果与用量归一化后交给断言;v0.83.0 只有 smoke 和 extension 两条 case,它们提供真实行为证据,但结果仍依赖显式选择的模型与可用凭据。 - [TUI 组件、焦点与覆盖层怎样配合](https://www.echovic.com/handbook/pi-internals/43-tui-component-focus): Pi TUI 的普通组件按顺序渲染成行,焦点只决定键盘输入与硬件光标归谁,overlay 则在普通组件完成渲染后按 focusOrder 合成到屏幕。capturing overlay 会接管焦点,nonCapturing overlay 只覆盖画面;关闭或隐藏时,TUI 依据 preFocus 和可见 overlay 恢复输入所有权。 - [键盘输入怎样穿过终端协议到达编辑器](https://www.echovic.com/handbook/pi-internals/44-terminal-input-editor): ProcessTerminal 将 stdin 切到 raw mode,启用 bracketed paste,并协商 Kitty keyboard protocol 或 modifyOtherKeys;StdinBuffer 重组被拆开的控制序列和 paste;TUI 过滤终端响应与 key release 后只把输入交给 focused component;Editor 最后通过可配置 keybindings 修改按 grapheme 管理的文本、历史、paste registry 与 undo state,Enter 才可能触发 onSubmit。 - [Pi 为什么不用每次重画整个终端](https://www.echovic.com/handbook/pi-internals/45-differential-rendering): TUI 将密集 requestRender 合并到最短约 16ms 的调度节奏,先生成完整新行并合成 overlay、提取 cursor marker,再与 previousLines 找到变化区间。正常路径只在 synchronized output 中清理并重写 firstChanged 到 lastChanged;宽高改变、变化落到旧 viewport 上方、shrink 策略或 Kitty 图片安全条件不满足时才 full redraw。 - [流式消息与工具结果怎样出现在屏幕上](https://www.echovic.com/handbook/pi-internals/46-interactive-event-projection): Agent loop 产生消息与工具事件,AgentSession 在转交 extension 和界面 listener 的同时负责会话持久化,并补充 queue、compaction、retry、settled 等控制面事件。InteractiveMode 将流式 assistant 保存在一个临时组件中,以 toolCallId 关联工具组件和 partial result;恢复或压缩后则从 session items 重建同一画面。组件是运行事件的可丢弃投影,不是第二份会话真相。 - [Pi 没有内置沙箱,这意味着什么](https://www.echovic.com/handbook/pi-internals/47-security-containerization): Pi v0.83.0 默认以当前用户和进程环境运行,内置 bash 会在当前 cwd 直接 spawn 本地 shell,write、edit 与 extension 也没有内置权限提示或系统调用隔离。Project Trust 只控制项目级 settings、extensions、skills 和 prompt 等资源是否加载。需要强隔离时,应把整个 Pi 放入容器或 policy sandbox,或明确把特定工具路由进 Gondolin;bind mount、凭据注入和仍在 host 执行的 extension 必须单独审计。 - [怎样验证本册结论,并看清 Harness v2 的边界](https://www.echovic.com/handbook/pi-internals/48-verification-release-evolution): 本册所有源码结论固定到 tag v0.83.0 与 commit 845d6ff1。普通 checkout 不含被忽略的 provider data,完整验证应校验官方 source archive 的 SHA256,在一次性目录执行 npm ci、offline build、8 个 Vitest 文件与 4 个 TUI Node test 文件,再核对 checkout 未被修改。Harness v2 文档中的 durable runs、lanes、operation logs 和 recovery 是设计目标;v0.83.0 已交付边界仍以源码类型、schema、公开 API 与可运行测试为准。 ## English Reading Guides - [Codex Source Code Guide: Inside a Production Coding Agent](https://www.echovic.com/en/handbook/codex-internals): A source-based guide to the open-source openai/codex repository. Follow a request through the model loop, tool execution, approval and sandbox boundaries, conversation persistence, and recovery. The chapters explain why these mechanisms exist and what breaks when their assumptions do not hold. - [DeepSeek Harness Source Code Guide: From Input to Agent Platform](https://www.echovic.com/en/handbook/deepseek-harness-internals): A source-based guide to the official DeepSeek Harness repository at a fixed commit. Start with a terminal command or a browser message, follow it through the inbox and agent loop, and inspect how execution events support model context, persistence, and user interfaces. - [pi Coding Agent Source Code Guide: From Agent Loop to Runtime](https://www.echovic.com/en/handbook/pi-internals): A source-based guide to earendil-works/pi at a pinned version. Explore how provider adapters, an agent loop, tool execution, a session tree, extensions, and a terminal interface fit together. The guide distinguishes behavior implemented in the repository from the separate Harness v2 design. ## Published Posts - [Computer Use 每轮 40 个工具错误,都出在哪里](https://www.echovic.com/blog/ai/orca-computer-use-acceptance-harness): Orca computer use 真机验收复盘:15 项任务的 harness 怎么跑(PTY 里的真实 TUI、从渲染出来的面板读授权、独立核验、清理核查)、前五次运行为什么都死在 harness 自己身上、基线的 37 和 40 个工具错误分别来自 bash 绕路、没有 AX 窗口的窗口编号和系统设置的 AXRaise,可靠性修复(可用窗口、带下一步的错误、无窗口快捷键、AXRaise 回退、失败预算)把错误降到 8、9 个,以及为什么一个改动至少要跑两轮。 - [让 Agent 去开个文件夹,它用了我自己开着的 Finder 窗口](https://www.echovic.com/blog/ai/orca-computer-use-window-boundary): Orca v0.5.14 computer use 窗口边界复盘:窗口归属怎么判定(本轮第一个 computer 调用时拍快照)、逐窗口审批目标 bundle#window: 和规则匹配、拒绝之后为什么让本轮继续、驱动层的四道过滤(托盘 app、桌面、Chrome 同尺寸窗口、辅助窗口)、作用于整个 app 的快捷键(包括 Quit and Keep Windows)、三次真机验收的结果,以及一句 Esc 的说明为什么改了三遍。 - [查一次系统版本要 14 秒:测试慢在 94 万个 .o 文件上](https://www.echovic.com/blog/ai/orca-macos-tests-cfbundle-readdir): 一次 macOS 测试变慢的排查:host_supported 调用 NSProcessInfo.operatingSystemVersion,CoreFoundation 为了本地化版本字符串去找主 bundle 的 .lproj 目录,裸可执行文件的主 bundle 就是它所在的目录;target/debug/deps 里有 94.7 万个条目(94 万个 .o,来自 macOS 上 dev 构建默认的 split-debuginfo=unpacked);用一个只调用一次 operatingSystemVersion 的小程序测出空目录 2 毫秒、30 万个文件 290 毫秒、真实目录 13.6 秒;以及前两次为什么都对上了症状却没找到原因。 - [我让 Codex 在 Windows 虚拟机里替我测了一晚上](https://www.echovic.com/blog/ai/codex-windows-vm-qa-night): 留白与 Cleanzo Windows 版的真机测试复盘:Mac 上开发、Codex 在 Windows 11 云桌面里只测不改、每项配截图、Mac 上的测试与模拟 Win32 的浏览器测试不算 Windows 通过;单实例锁的 key 用了本地化的应用名导致中英文各占一把锁;向进程所有顶层窗口发 WM_CLOSE 让 LibreOffice 在保存询问前崩溃,改为只向用户能关的窗口发 SC_CLOSE;mygo 0.6.2 的 TrashItem 在文件超过回收站容量时直接永久删除,改回 SHFileOperationW 并预检 BitBucket 容量;以及把跑通的流程写成 skill。 - [状态栏显示还剩 33%,请求却超了上下文上限](https://www.echovic.com/blog/ai/orca-context-budget-reply-reservation): Orca v0.5.5 上下文预算复盘:max_tokens 384K 与压缩阈值不一致造成的死区、pinned 通知让整轮无法压缩、对照 dsh 与 Codewhale 的做法、按思考强度设定回复预留并逐请求裁剪、以 API 用量为锚测量提示大小、按工具平衡单元切分当前轮、紧急压缩只采用真正变小的结果,以及实现中把同一份偏差扣了两次的弯路。 - [沙箱挡住了 git mv,模型转头用了 mv](https://www.echovic.com/blog/ai/orca-git-write-sandbox-approval): Orca v0.5.4 git 写授权复盘:.git 在沙箱里为什么必须只读、为什么不能凭命令输出判断沙箱拒绝、Codex 让模型自己申请 require_escalated 而 DeepSeek 不申请、运行前识别 git 写命令的四种判定、单条命令授权只放开 index 与 objects 而保持 config、hooks、modules 只读、Seatbelt 与 bwrap 的做法和 Windows 的退路、「本会话允许」只记开关不记目录,以及 husky 留下的口子。 - [跑 Terminal-Bench 时,Agent 把自己 kill -9 了](https://www.echovic.com/blog/ai/orca-terminal-bench-self-kill): Orca 两轮 Terminal-Bench 2.0 评测复盘:指令在 argv 里导致 Agent 被自己的 /proc 扫描 kill -9(exit 137)、lifetime workspace 服务在会话结束时被 terminate_all 一并取消、修复只把指令从 orca 的 argv 挪到 sh -c 的 argv(exit 143)、Harbor 均分与 scored-only 与基础设施复跑三种口径、环境启动超时泄漏容器,以及把评测探针和台账收进仓库之后探针自己也会过期。 - [录一段网页操作给 Agent:打的字从四个地方漏进了文件](https://www.echovic.com/blog/ai/pilion-recording-typed-text-leaks): Pilion 录制与技能复盘:只有人能录制、Agent 提炼不能凭空造步骤、回放走与 Agent 相同的工具路径、首次回放即使完全访问也要审批;第三期把产物从归一化后的步骤改成只增不改的事件日志;以及打的字经页面正文摘录、页面回显、可访问名、「显示密码」切换四条路径漏进录制文件的过程、每个修复的代价和至今仍认不出的形状。 - [做 Mac 清理工具,难的是证明这些文件没人在用](https://www.echovic.com/blog/architecture-design/cleanzo-mac-cleaner-safety): Cleanzo 0.1.0 到 0.1.3 复盘:$TMPDIR 与正在运行的应用缓存为什么不能整目录清,safeToClean 因 filepath.Abs 不解析符号链接而放行 /var/folders,用 lsof 与 lsappinfo 判断「正在使用」且探测失败就当在用,垃圾直接删除与用户文件进系统废纸篓的分工,读不到的废纸篓不等于空,对照柠檬清理与 Mole 的做法,以及从九个固定分类改成规则表,把原来漏掉的约 22 GB 开发缓存纳入规则。 - [Orca 的终端界面太生硬,我把它重做了一遍](https://www.echovic.com/blog/ai/orca-tui-redesign-v050-retrospective): Orca v0.5.0 终端界面改版复盘:把“生硬”拆成可指认的问题、用 HTML 交互稿评审、chrome.rs 设计 token 与颜色守卫、子代理逐任务实现与终审、审批内联与 tasks dock、Ctrl+Enter 从插到队首改成 steer、后台代理唤醒与 relay 浮点 digest、Ghostty 真终端实测、npm OIDC 发布,以及发布后才看清的投影缺口。 - [Jev:一个故意不聊天的 AI 模型,和它在 Agent 里的位置](https://www.echovic.com/blog/ai/jev-system-one-decision-layer): TypeSafe 发布的 Jev 故意不生成文本。它把"判断"从"生成"里拆出来:输入业务状态,输出类型化的 Choice、Score、Noul 与置信度。本文梳理它的三个原语、判断与执行分离的工程模式,以及它在 Agent 链路里最适合充当的门控层角色。 - [给 Agent 加了子代理,为什么它还是一直自己读代码?](https://www.echovic.com/blog/ai/orca-subagent-delegation-convergence): Orca v0.4.31 子代理运行时复盘:三档委派策略、统一准入作用域与任务树、等待时让出执行 lease、持久 outbox 交付,以及真实 DeepSeek 测试暴露的只读任务收敛问题。 - [按了 Esc 没反应:一个侧问怎么会锁死主任务](https://www.echovic.com/blog/ai/blade-code-side-question-cancellation-ownership): 从 blade-code v0.10.164~167 的三个修复出发,拆解侧问并发模型里的所有权边界——admission lease、按目标去重的取消闩锁、失败 preparation 的排空,以及为什么这类竞态只能靠真实 PTY 轨迹锁定。 - [放宽权限的那一刻,正在跑的工具该不该变强?](https://www.echovic.com/blog/ai/orca-full-access-live-transition): 从 Orca v0.4.28/29 的 full access 与问卷交互重构出发,解释运行中权限变更需要的提交点、快照隔离与专用 patch 通道,以及为什么交互校验必须由请求对象自己承担,而不是挂在调用点的模式匹配上。 - [权限系统真正要证明的,不是“允许”,而是“在哪个边界内执行”](https://www.echovic.com/blog/ai/orca-capability-kernel-sandbox-refactor): 从一个可伪造的沙箱拒绝信息出发,解释 Agent 权限系统为什么不能把 stderr、项目配置或 UI 响应当成授权依据,并拆解 Capability Kernel、Execution Broker、workspace identity 和 fail-closed backend 这套设计选择。 - [当代码不再是瓶颈,研发流程就该重做一遍](https://www.echovic.com/blog/architecture-design/when-code-is-no-longer-the-bottleneck): 读完 Anthropic 的《The AI-Native SDLC playbook》后,我最强烈的感受不是“AI 又能多写多少代码”,而是:代码这段突然变快之后,团队里真正拖节奏的地方换了。需求澄清、评审、验证、发布和线上回流,开始一个个露出原形。要学的不是几个 markdown 文件名,而是整套 artifact、闸门和闭环。 - [Orca 聊久了开始卡:DeepSeek 流式输出到底慢在哪](https://www.echovic.com/blog/ai/orca-deepseek-streaming-hot-path-retrospective): 一次基于 Orca 源码和测试的 TUI 卡顿排查,记录长对话误判、流式批处理、局部投影、commit 索引、token cache 和增量渲染的修复过程。 - [插件化的第五时代:契约迁移,而非契约消失](https://www.echovic.com/blog/ai/pluginization-fifth-era-contract-migration): 从 DLL、OSGi、VS Code 到 DeepSeek Harness,沿着插件系统的历史问题,推导 AI 时代可能出现的契约迁移与运行时治理。 - [不止是渲染:我给画布引擎做了一套让 agent 能"改图"的接口](https://www.echovic.com/blog/architecture-design/agent-canvas-snapshot-ops): 一个面向 agent 的画布光能渲染还不够——agent 得能读懂画布现在长什么样,还得能改它。本文记录如何给 sky-canvas 设计 snapshot + ops 协议,让 LLM 能以"观察→引用→增量改"的循环持续编辑一张画布,并实测用 45 条 ops 从空白画布生成完整星图。 - [同一个 bug,我在 WebGPU 渲染器里犯了三次](https://www.echovic.com/blog/architecture-design/webgpu-buffer-bug-three-times): 上篇讲了怎么用实例化渲染让 WebGPU 一次 draw call 画十万个矩形。这篇讲后来发生的事:把同样手法套到圆、线、文字时,一个 GPU buffer 复用 bug 连续犯了两轮。这是一篇关于"为什么一个修过的 bug 会换个地方重新长出来"的复盘。 - [WebGPU 实例化渲染:如何用一次 draw call 画十万个矩形](https://www.echovic.com/blog/architecture-design/webgpu-instancing-draw-100k-rects): 无限画布最硬的性能瓶颈,是当画布上堆了十万个对象时还要保持 60fps。本文记录在给 sky-canvas 做 WebGPU 渲染底座时,如何用实例化渲染把海量矩形的绘制从 O(N) 个 draw call 压到 O(1),实现 50 万对象单次 draw call 满帧 60FPS。 - [从 TUI 到 ACP:我如何把 Orca 的任务真相收回 Runtime](https://www.echovic.com/blog/ai/orca-runtime-owned-surface-tui-acp-jsonl-retrospective): 复盘 Orca runtime-owned typed surface 重构从普通 TUI turn 到 Goal、workflow、background、ACP 和 JSONL 的完整迁移,包括原子 batch、snapshot/cursor、interaction、terminal、restart recovery 与发布验证。 - [TUI 不该拥有任务:我如何重构一个可恢复的 AI Agent Runtime](https://www.echovic.com/blog/ai/orca-runtime-owned-tui-recovery-retrospective): 复盘 Orca runtime-owned typed surface 重构:从 TUI 与 runtime 的状态分叉,到原子持久化、snapshot/cursor、request-scoped interaction、terminal settlement、restart recovery 和真实 PTY 验证。 - [多智能体并行编码的符号级冲突预防与语义合并](https://www.echovic.com/blog/ai/symlock-symbol-level-conflict-prevention-semantic-merge): 介绍 symlock 的设计与实现:基于 tree-sitter 的符号级冲突预防机制,以及保守的三向语义合并策略。解决多 AI 编码智能体并行工作时,因 git 行级合并导致的假性冲突问题。 - [Goal 为什么又停了:删掉 64 轮上限后,我重新理解了 Agent runtime](https://www.echovic.com/blog/ai/orca-goal-runtime-no-fixed-turn-limit): Orca Goal Mode 第二轮重构:固定 64 轮上限误判 NoProgress,到 runtime 收回生命周期,以及 admission 矩阵如何替代无语义计数器。 - [一个 Goal 为什么跑了 5 小时:从 463 次 update_goal 失败到 v0.2.46](https://www.echovic.com/blog/ai/orca-goal-control-plane-incident-retrospective): 复盘 Orca v0.2.46 Goal Mode 事故:session 取证、thread-local 失效、schema 与执行能力分叉,对照 Codex / Claude Code / Grok Build 重构 ownership,并用真实 DeepSeek 和 Linux CI 收口。 - [AI Agent 工程师的核心能力:从模型调用到可靠系统](https://www.echovic.com/blog/ai/ai-agent-engineer-core-skills-roadmap): 结合 Orca 实践,拆解 AI Agent 工程师真正要用到的工程能力:软件基础、模型边界、Context/RAG、工具治理、状态与 Loop、Harness、评估、安全和产品判断,并给出四个可落地的练习项目。 - [用 Orca 拆开 ChatGPT Computer Use:从 node_repl 到 macOS 原生服务](https://www.echovic.com/blog/ai/chatgpt-computer-use-plugin-security-analysis): ChatGPT Computer Use 逆向笔记:@oai/sky 的平台路由、策略包装、动作编码、服务拉起和遥测,再沿 8 MiB 长度前缀 JSON-RPC 进原生服务、AX Tree、截图与权限边界。 - [任务明明做完了,Orca 为什么还是判失败?](https://www.echovic.com/blog/ai/orca-deepseek-empty-turn-recovery-retrospective): 本文复盘 Orca v0.2.21 的一次真实生产事故:长任务已完成并提交,但 DeepSeek 最终没有产生可见 content 或 tool call,导致 Goal 被判失败。文章涵盖日志取证、语义恢复、会话历史保护、usage 统计、失败持久化、预算治理、回归测试和正式发布。 - [把 @ 文件搜索推到百万路径:Orca 的一次流式重构](https://www.echovic.com/blog/ai/orca-streaming-mention-file-search-refactor): Orca @ 文件搜索从同步 git ls-files / ignore 索引迁到 ignore + Nucleo 流式会话:对比 Claude Code 与 Codex、latest-wins、三层 stale guard、browse、warm catalog、线程所有权和百万路径门槛。 - [Orca 聊久了开始卡,我把 TUI 的滚动重做了一遍](https://www.echovic.com/blog/ai/orca-tui-scroll-performance-refactor): 本文复盘 Orca 基于 Rust 和 ratatui 的 TUI 滚动性能重构,涵盖事件循环饥饿、Markdown 渲染缓存、消息 revision、视口虚拟化、超长会话滚动、PTY 探针和真实 DeepSeek API 验证。 - [Orca 又一轮 DeepSeek V4 适配复盘:重新理解 Agent Harness](https://www.echovic.com/blog/ai/orca-deepseek-v4-adaptation-harness): 本文从 Orca 一次真实 DeepSeek V4 适配出发,解释 DeepSeek-native Coding Agent 为什么需要沿着 provider 行为、tool calling 语义和 agent runtime 一起调整。文章复盘 update_plan 布尔状态归一化、reasoning_content 工具回放、DeepSeek strict mode、update_goal、glob anyOf schema、max_tokens、空响应重试、工具数量上限、系统提示瘦身和 real API 探针。 - [一次 Orca 卡死反馈背后:真正要修的不是某个超时](https://www.echovic.com/blog/ai/orca-context-stability-stuck-session-fix): 本文复盘 Orca 一次真实卡死反馈:从 session 日志定位长会话压力,到参考 Codex 和 Claude Code 的上下文处理方式,再到实现 ranged read_file、grep/glob 分页、去除旧 reasoning replay、soft compaction、tool output micro-compaction、TUI 状态提示和回归测试。 - [Agent 从 Demo 到真实业务,差的不是模型,而是工程秩序](https://www.echovic.com/blog/ai/agent-demo-to-production-engineering-order): 这篇文章从真实 Agent 项目落地的常见问题出发,拆解为什么 Demo 能跑但一接业务就乱:RAG 检索不准、工具调用失控、上下文变长、失败无法兜底、成本不可控。文章给出一套从任务契约、工具治理、Verifier、状态管理到评估集的工程化处理方式。 - [不是 Demo,而是交付:用 Orca 复刻红色警戒的一次实践](https://www.echovic.com/blog/ai/orca-red-alert-clone-practice): 本文复盘一次 Orca 真实实践:从“从0到1复刻红色警戒游戏”的目标出发,使用 Vite、TypeScript、Phaser 3 和 Cloudflare Workers,经历 workflow 失败、系统迭代、交互优化、构建验证和部署上线,观察 Coding Agent 从生成代码走向可交付工作的关键。 - [DeepSeek DSpark:重点不是新模型,而是推理系统能力](https://www.echovic.com/blog/ai/deepseek-dspark-inference-system): 这篇文章从生产系统视角解读 DeepSeek DSpark:半自回归草稿生成、置信度调度验证、线上吞吐和单用户速度提升,以及为什么它应该被理解成推理服务能力,而不是模型能力升级。 - [Harness Engineering 的本质:给智能一套能交付的工程外壳](https://www.echovic.com/blog/ai/harness-engineering-essence): 这篇文章从 Coding Agent 的真实执行场景出发,解释 Harness Engineering 的本质:它不是 Prompt Engineering 的升级版,而是围绕 Agent 执行生命周期建立的一套权限、环境、状态、观测、验证和恢复系统。 - [Loop Engineering 的本质:让 Agent 一轮一轮走向交付](https://www.echovic.com/blog/ai/loop-engineering-essence): 这篇文章从一个运行超过 1 天 19 小时的 Codex goal 任务出发,解释 Loop Engineering 为什么不是 while true,并结合 boss-skill 与 orca 两个实践,拆解 Agent 长任务闭环里的目标、状态、验证、失败恢复和退出条件。 - [让思想穿过时间——写在「教员语录」上线五天](https://www.echovic.com/blog/ai/jiaoyuan-five-days-public-platform-reflection): 「教员语录」上线 5 天后的复盘:1000+ 用户、5000+ 对话、小红书 6w+ 阅读。本文不谈增长方法论,而是记录做这件事的初心——为什么是教员、为什么是现在、20G 全阶段作品语料如何让思想回到原文、以及评论区那些"被击中""被治愈""思想永存"的真实反馈如何反过来鼓励了我。公益平台,传播教员思想方法,帮年轻人对抗内耗、看清方向。 - [把 Orca 的 DeepSeek 缓存命中率打到 99%,我做了九轮优化](https://www.echovic.com/blog/ai/orca-deepseek-cache-optimization): 这篇文章复盘 Orca 针对 DeepSeek Prefix Cache 的九轮缓存优化:从 budget hint 破坏 system prefix,到 volatile 上下文、wire 等价 token 计算、summary state、extractive compaction、remote summary 0% 命中,再到最后用真实 API 评测把主链路稳定到 99% 左右。 - [Orca:一个 DeepSeek 原生的终端 Coding Agent](https://www.echovic.com/blog/ai/orca-deepseek-native-coding-agent): Orca 是一个用 Rust 编写、围绕 DeepSeek 推理与工具调用语义打造的终端 Coding Agent。它实现了多轮 Agent 循环、SSE 流式、1M 上下文自动压缩、审批策略、子 Agent、工作流、持久化目标模式与会话历史。本文聊聊我为什么押注 DeepSeek 生态,以及 Orca 的设计与用法。 - [Harness 实战:让 Agent 流水线可信的五层工程骨架](https://www.echovic.com/blog/ai/harness-five-layer-skeleton-for-agent-pipeline): Harness 不是让 Agent 更聪明,而是让 Agent 的工作更可信。本文基于一个真实的 Agent 研发流水线,拆解五层工程化骨架:定义层、运行层、产物层、门禁层、恢复层,以及如何用 workflow-plan.json 把"流程定义"和"运行实例"彻底分开。 - [Claude Code Workflow 实现原理:一个可恢复的 Agent 编排引擎](https://www.echovic.com/blog/ai/claude-code-workflow-runtime-analysis): 深入分析 Claude Code 2.1.156 版本的 Workflow 实现原理。它不是"让模型自己记住步骤",而是一个可编译、可持久化、可恢复的多阶段 Agent 编排引擎。从 SDK 类型定义、二进制字符串痕迹到运行时行为,逐层拆解 workflow 的 DSL 设计、任务注册、phase 调度和恢复机制。 - [Hermes Agent 深度架构剖析与 OpenClaw 工程化对比](https://www.echovic.com/blog/ai/hermes-agent-deep-architecture-openclaw-comparison): 以 Hermes Agent 源码为主线进行深度架构剖析,从运行时形态、工具系统、长期记忆、任务编排、可插拔性、可观测性、安全模型、社区生态八个工程化维度与 OpenClaw 进行结构化对比。面向工程师、架构师和研究者,侧重讲清架构意图与设计取舍。 - [Agent 时代,真正稀缺的不是能力,而是值得信任的失败](https://www.echovic.com/blog/ai/agent-reliability-trustworthy-failures): 最近一周在排查 OpenClaw 的 cron 和 delivery 问题时,我越来越确信:Agent 系统最难的不是成功路径,而是失败路径。本文从表面成功、失败语义、边界设计和可观测性四个角度,聊聊为什么 Agent 时代真正稀缺的不是能力,而是值得信任的失败。 - [为什么 Harness Engineering 最近突然变热了?](https://www.echovic.com/blog/ai/why-harness-engineering-is-heating-up): 从 AI Coding Agent 的落地现实出发,解释 Harness Engineering 为什么会在最近迅速升温。文章从定义、背景、关键能力、与 Tool Calling 的区别,以及它对 Agent 产品竞争格局的影响几个角度展开,讨论为什么当模型能力逐渐拉平后,真正决定 Agent 可用性的,往往是它背后的执行系统工程。 - [Claude Code 的 /btw:不打断主任务的“顺口一问”,源码里是怎么做隔离的?](https://www.echovic.com/blog/ai/claude-code-btw-side-question): 拆解 Claude Code /btw(side question):feature flag、maxTurns=1、deny tools、skipCacheWrite,为什么它能做到“问完就算,不污染主对话”。 - [浅谈最近爆火的 OpenClaw](https://www.echovic.com/blog/ai/talk-about-openclaw): OpenClaw 最近很火,但它真正值得讨论的,不只是为什么会火,而是它暴露出来的产品形态、信任边界和系统复杂度问题。本文从产品、架构和方向判断三个层面,聊聊我对这类 Agent 系统的看法。 - [STOP Protocol:给 Agent Skill 装上可观测性](https://www.echovic.com/blog/ai/stop-protocol-skill-observability): Agent Skill 是黑盒。你调用一个 Skill,不知道它做了什么、为什么失败、能不能信任。STOP(Skill Transparency & Observability Protocol)是一个开放规范,把 SRE 级别的可观测性引入 Skill 层——Manifest 声明能力、Trace 追踪执行、Assertion 验证结果。 - [给 OpenClaw 装一个学习系统](https://www.echovic.com/blog/ai/give-ai-a-learning-system): AI 助理用过就忘?我给 OpenClaw Agent 写了一个 learning-system skill,让它能系统化地积累经验。包含知识图谱、深度笔记、健康检查和每周回顾,从"能查到"变成"学会了"。 - [开源 Blade Agent SDK:构建多轮会话 AI Agent 的 TypeScript 利器](https://www.echovic.com/blog/ai/blade-agent-sdk-introduction): Blade Agent SDK 是从 Blade Code(类 Claude Code 的 AI 编程助手)中抽取出来的核心能力集合。提供 send/stream 会话模式、会话恢复与分叉、文件检查点、沙箱执行、MCP 集成、上下文压缩、插件系统等经过实战验证的功能,帮助开发者快速构建多轮会话 AI Agent 应用。 - [Agent Skill、MCP 和 Prompt 的区别是什么?](https://www.echovic.com/blog/ai/agent-skill-mcp-prompt-difference): 深入解析 AI Agent 开发中的三个核心概念:Prompt、MCP 和 Agent Skill。从基础定义到实际应用,通过代码示例和对比分析,帮助你理解它们的区别与联系,掌握如何正确选择和使用这些技术组件来构建高效的 AI Agent 系统。 - [Agent 架构重构:为什么 System Prompt 不该存进 History?](https://www.echovic.com/blog/ai/agent-architecture-system-prompt-design): 深入探讨 Coding Agent 架构中 System Prompt 的正确处理方式。分析将系统提示词存入历史消息的常见问题,提出 Stateless Agent 的改进方案,并结合 Prompt Caching 技术实现成本优化。涵盖 Anthropic、OpenAI、Google、DeepSeek 等主流厂商的缓存策略对比,帮助开发者构建灵活、可扩展的 Agent 架构。 - [Agent 核心就几十行代码,那剩下的几万行到底在解决什么问题?](https://www.echovic.com/blog/ai/agent-complexity-explained): 深入探讨 AI Agent 的代码复杂度,为什么核心循环只有几十行,但实际项目却需要几万行代码来处理上下文管理、文件快照、工具执行管道、子代理、权限安全、多模型适配等现实世界的复杂性。 - [Vibe Coding 实践案例:我如何用 AI 从零打造 Blade Code](https://www.echovic.com/blog/ai/vibe-coding-practice-cases): 分享我如何利用 Vibe Coding的方式,从零开发开源 AI 编程助手 Blade Code 的实践经验和感悟。 - [如何编写高效的 CLAUDE.md](https://www.echovic.com/blog/ai/how-to-write-effective-claude-md): 深入解析 CLAUDE.md 文件的编写技巧与最佳实践。揭示为什么"加规则"反而让 AI 更不听话的技术原理,提供经过实战验证的模板和反模式案例。从四条核心铁律到三级治理体系,帮助开发者用最少的文字换取最高的 AI 执行力,显著提升代码生成质量和开发效率。 - [既然 AI Coding 有了 IDE,为什么还要有 CLI?](https://www.echovic.com/blog/ai/why-cli-when-ide-has-agent): 深度解析IDE Agent与CLI Agent的差异与互补关系。从Cursor Agent Mode到Windsurf Cascade,IDE已经进化成Agent,但CLI依然有其不可替代的价值:Headless运行、模型自由切换、Unix哲学组合、透明可控。本文探讨为什么在AI Coding时代,CLI和IDE不是替代关系,而是工具箱里的不同工具。 - [2026 年 Coding Agent 演进与发展趋势深度调研报告](https://www.echovic.com/blog/ai/2026-coding-agent-evolution-trends-report): 基于 MIT Technology Review、OpenAI、Google DeepMind 等权威机构最新研究的深度调研报告。剖析 2026 年 Coding Agent 五大核心趋势:AI 代码占比达 90%、SWE-bench 性能突破 70%、多智能体协作系统、Vibe Coding 自然语言编程兴起、开发者角色从编码者转型为智能体编排者。涵盖 Claude Code、Cursor、Devin、GitHub Copilot、Amazon Q 等主流产品深度对比,以及生产力提升 25-55% 背后的代码质量与技术债务隐患分析。 - [从军师到实习生:一文读懂 Coding Agent](https://www.echovic.com/blog/ai/from-advisor-to-intern-understanding-coding-agent): 从"Copilot"(军师)到"Coding Agent"(实习生)的范式转变,揭秘 AI 如何从提供建议进化为自主执行任务。文章通过作者自研工具 Blade Code 深度解析 Agent 的核心公式(LLM + Prompt + Context + Tools),探讨 MCP、多智能体协作及自我进化闭环,展示 AI 驱动开发的未来图景。 - [Web Components:一个美好的"谎言"?为什么它没能统一前端?](https://www.echovic.com/blog/architecture-design/web-components-a-beautiful-lie): 从技术现实与生态历史两条主线拆解 Web Components:详细解析 Custom Elements、Shadow DOM、HTML Templates 带来的开发者体验、样式隔离、SSR 等硬伤,并对比 React/Vue 等框架的生态虹吸效应,说明它为何未能统一前端。同时总结其在设计系统、微前端、渐进增强等场景的可行定位,帮助读者重新评估这项标准的价值。 - [让效率变得可见:从“被说闲”到“掌控局面”](https://www.echovic.com/blog/thoughts/make-efficiency-visible): 面对“你太闲”的职场偏见,拆解高效反被误解的底层逻辑,并通过价值显性化、主动升维、向上管理三步,建立起“高效且可靠”的个人品牌。 - [为画板 SDK 寻找合适的响应式库](https://www.echovic.com/blog/architecture-design/canvas-sdk-reactive-framework-selection): 记录个人周末开发画板应用时的响应式框架选型过程。从MVVM架构需求出发,对比分析MobX、Vue Reactivity、Valtio、SolidJS等方案的设计哲学和技术特点,最终选择Valtio作为主要方案,SolidJS作为性能优化备选。分享完整的技术调研思路和决策过程。 - [《随机漫步的傻瓜》读后感:人生很多"成功",只是随机事件](https://www.echovic.com/blog/thoughts/random-walk-fool-book-review): 别把运气当实力!塔勒布在《随机漫步的傻瓜》中用犀利的笔触揭示了一个令人不安的真相:华尔街的"投资天才"可能只是运气好的普通人,创业成功者的背后也许隐藏着巨大的随机性。这本书教会我们如何识别幸存者偏差,应对黑天鹅事件,以及在充满不确定性的世界中保持理性和谦逊。 - [Claude Code Subagents 指南:构建智能化开发团队的新范式](https://www.echovic.com/blog/ai/claude-code-subagents-guide): 深入解析Claude Code Subagents智能子代理系统的完整实现指南,从基础概念到高级编排策略的全方位覆盖。详细讲解子代理创建管理、权限控制机制、链式/并行/条件分支编排模式,以及Web开发流水线等企业级实战应用。提供开源agents资源和最佳实践,帮助开发者构建专业化AI开发团队,实现高效协作和自动化工作流程。 - [Claude Code 使用技巧](https://www.echovic.com/blog/ai/claude-code-usage-tips): Claude Code完整使用指南:从安装配置到高级技巧的全方位解析。涵盖官方订阅与第三方代理接入、多模型路由配置(阿里云、Kimi、DeepSeek等)、项目初始化与工作模式切换、Git Worktrees并行开发、Sub Agents专门化助手等核心功能。提供实战案例和最佳实践,帮助开发者充分发挥AI编程助手的潜力,显著提升代码开发效率和质量。 - [LangChain.js 100 行系列 - 02 · LCEL 管道式编程](https://www.echovic.com/blog/ai/langchain-js-100-lines-02-lcel-pipeline-programming): 深入 LangChain.js 核心:LCEL(LangChain Expression Language)管道式编程。 用不到 100 行代码构建可组合、可复用的 AI 应用流水线,掌握现代 LLM 开发的核心范式。 - [LangChain.js 100 行系列 - 01 · Hello LLM](https://www.echovic.com/blog/ai/integrate-llm-into-fullstack-with-typescript-01-overview): LangChain.js 100行系列开篇:从零开始的TypeScript全栈LLM集成实战指南。详细解析如何用不到100行代码将大语言模型无缝集成到全栈应用中,涵盖LangChain.js生态全景、核心概念解析、技术路线图规划和最佳实践。为前端开发者提供完整的AI应用开发框架,从聊天机器人到RAG系统的渐进式学习路径。 - [从"AI编程助手"到"AI开发团队":BMAD METHOD如何重新定义AI驱动开发](https://www.echovic.com/blog/ai/from-ai-programming-assistant-to-ai-development-team-bmad-method): BMAD METHOD(Brainstorm-Model-Architect-Develop)革命性AI驱动开发方法论深度解析。将传统AI编程助手升级为完整AI开发团队协作模式,通过头脑风暴、建模、架构设计、开发实现四个核心阶段,重新定义人机协作边界。让AI从代码生成工具转变为具备战略思维和系统设计能力的开发伙伴,为软件开发团队提供系统性的AI协作框架和实践指南。 - [解构 browser-use:如何用 1400 行 JS 代码让 AI 精准识别网页交互元素](https://www.echovic.com/blog/source-code/deconstructing-browser-use-ai-recognizes-web-interaction-elements): 本文将深入探讨 browser-use 的实现,分析其如何用 1400 行 JavaScript 代码实现让 AI 精准识别网页中的交互元素,并探讨其在自动化测试、用户行为分析等领域的应用前景。 - [用 GitHub Actions 实现定时爬虫](https://www.echovic.com/blog/ai/using-github-actions-for-scheduled-crawlers): 背景:AI 资讯网站的定时数据拉取需求 我最近开发了一个 AI 资讯聚合网站https://www.dayhot.top/,需要每天定时从各大数据源拉取最新内容。 涵盖AI等技术要点。 - [LangChain ReAct 中文解析器实现](https://www.echovic.com/blog/ai/langchain-react-chinese-parser-implementation): 背景与痛点 在用 LangChainJS 开发 Agent 时,ReAct(Reasoning and Acting)模式是最主流的推理与工具调用范式。它要求大模型输出结构化的推理链条,例如: plain Thought: 我需要查找相... 涵盖AI等技术要点。 - [在无知中寻找意义](https://www.echovic.com/blog/thoughts/finding-meaning-in-ignorance): > 我们满心相信这个世界是有意义的,这份信心建立在一个稳妥的基础之上:我们最大限度地忽略自己的无知。 一、认知的“自我欺骗”机制:作为生存策略的意义构建 人类的大脑天生就有“模式识别”和“因果归因”的需求。 - [Kortix开源AI Agent平台深度解析:企业级Agent开发的完整解决方案](https://www.echovic.com/blog/ai/open-source-general-agent-suna-analysis): Kortix是一个开源的企业级AI Agent开发平台,提供构建、管理和训练AI Agent的完整解决方案。平台包含Suna旗舰通用Agent,支持浏览器自动化、文件管理、Web搜索等核心能力,采用四层架构设计(Frontend Dashboard、Backend API、Agent Runtime、Data Infrastructure),为企业提供从客户服务到数据分析的全方位Agent自动化解决方案。 - [《AI Prompt Engineering Handbook》读书笔记](https://www.echovic.com/blog/good-articles/ai-prompt-engineering-handbook-reading-notes): 概述 系统阐述了提示工程的底层逻辑与实践技巧,全书以 “释放大语言模型(LLMs)潜力” 为核心,通过 10 章的结构化内容,串联起从基础概念到前沿技术、从工具平台到行业应用的完整知识体系。 涵盖AI等技术要点。 - [PixiJS 源码揭秘 - 9. 揭秘Filters与Blend Modes](https://www.echovic.com/blog/source-code/pixijs-filters-and-blend-modes): 目录 在PixiJS中,滤镜(Filters)和混合模式(Blend Modes)是实现丰富视觉效果的强大工具。本文将深入源码,解析它们的工作原理和实现细节。 滤镜基础 Filters 滤镜可以为显示对象(DisplayObject... 涵盖前端开发、架构设计、源码解析等技术要点。 - [PixiJS 源码揭秘 - 8. 插件机制深度解析](https://www.echovic.com/blog/source-code/pixijs-plugin-extension-mechanism-deep-dive): 前言 PixiJS 作为一款高性能、高度模块化的 2D WebGL 渲染引擎,已成为许多大型互动项目、游戏和可视化应用的首选技术。其强大的适应性和扩展能力很大程度上归功于其精心设计的插件(扩展)系统。 涵盖前端开发、架构设计、源码解析等技术要点。 - [从快思考到慢思考,大模型的认知跃迁](https://www.echovic.com/blog/ai/from-fast-thinking-to-slow-thinking): 深度解析人工智能从"快思考"到"慢思考"的认知跃迁过程。基于卡尼曼双系统思维理论,探讨大语言模型如何从统计模式的直觉响应演进为深度推理能力。文章分析DeepSeek等新一代AI模型的思考机制变化,揭示AI认知能力的进化路径,以及这种转变对人工智能发展和人类思维理解的深远影响。为AI研究者和技术从业者提供认知科学视角的技术洞察。 - [用小米方法论打造个人品牌:专注、极致、口碑、快](https://www.echovic.com/blog/thoughts/xiaomi-methodology-for-personal-branding): 深度解析雷军"专注、极致、口碑、快"七字诀在个人品牌建设中的应用策略。文章系统拆解小米成功方法论的四大支柱,提供职场人专注定义核心赛道、用工程思维构建能力壁垒、从技能输出积累信任资产、在动态平衡中敏捷进化的实操指南。对比刻意练习、增长黑客等成长理论,揭示小米方法论兼顾战略与战术的独特价值,帮助AI时代的职场人成为自己的"产品经理",打造可持续竞争力。 - [如何挑选适合自己的优质书籍?](https://www.echovic.com/blog/thoughts/how-to-choose-quality-books-that-suit-you): 系统性解析优质书籍的科学选择标准和筛选方法论,深入剖析"紧贴实际需求、表达简明易懂、便于日常应用、基于扎实研究"四大核心特征。详细揭示颜值陷阱、流量陷阱、权威陷阱等常见选书误区,构建完整的选书策略框架和实践指南。帮助读者建立高效阅读体系,实现从"道理都懂"到"真正实践"的认知升级跃迁。 - [PixiJS 源码揭秘 - 7. 事件系统源码解读](https://www.echovic.com/blog/source-code/event-system-source-code): 一、引言 PixiJS 是一个强大的 2D WebGL 渲染引擎,除了核心的渲染功能外,还提供了完整的事件系统来处理用户交互。事件系统作为连接渲染内容与用户交互的重要桥梁,在整个引擎中扮演着关键角色。 涵盖前端开发、架构设计、源码解析等技术要点。 - [如何看透一个组织的本质?四个维度拆解其核心逻辑](https://www.echovic.com/blog/thoughts/how-to-understand-the-essence-of-an-organization): 引言 你有没有想过: - 为什么有些团队总能高效协作,另一些却“人越多越混乱”? - 为什么初创公司初期士气高涨,成长后反而效率骤降? - 为什么同样一批人,换个规则就变成完全不同的组织形态? - [从"学历焦虑"到"能力坐标系",你的职场逆袭指南](https://www.echovic.com/blog/fe-interview/from-degree-anxiety-to-ability-coordinate-system): 职场逆袭完整指南:从"学历焦虑"到"能力坐标系"的认知升级与实战策略。深度解析如何在面试中突破学历限制,通过能力模型构建、STAR法则应用、量化成果展示、方法论沉淀等核心策略,系统性证明职场价值。提供具体挑战场景分析、差异化竞争策略、面试回答框架等实战工具,帮助非985/211毕业生在激烈的人才竞争中实现认知突围,构建个人核心竞争力,最终实现职业发展的逆袭突破。 - [面试官:说说你对前端性能优化的理解?](https://www.echovic.com/blog/fe-interview/frontend-performance-optimization): 前端性能优化面试全攻略:从普通研发到专家岗的分层回答策略与技术深度解析。系统梳理资源加载优化、代码层面优化、缓存策略、图片资源优化、构建流程优化等核心技术点。提供不同职级的专业回答框架和实战示例,深入讲解webpack优化配置、懒加载实现、防抖节流机制、CDN加速策略等关键技术,助力前端开发者在面试中展现扎实的性能优化理论基础和丰富的实践经验。 - [春节回忆随笔](https://www.echovic.com/blog/thoughts/spring-festival-memories): 过去这一周,时间就像被按了快进键,春节更是转瞬即逝。和亲朋好友聚在一起,聊天聊到兴处眉飞色舞,吃饭时满桌佳肴冒着热气,喝酒时酒杯碰撞,欢声笑语不断。可就这样,一天接着一天,春节的热闹还在耳边回响,它却已经悄然离去。 - [AI 编程真的起飞了吗?](https://www.echovic.com/blog/ai/is-ai-programming-really-taking-off): 最近几天深度体验了 AI 编程,借助 AI 完成了三个难度循序渐进的小项目。从项目开发到上线,每个项目平均耗时竟都不到 1 天,效率着实惊人。 一、项目介绍 1. 时间戳转换工具:支持时间戳与日期之间的精准转换 ,多时区时钟功能,能实... 涵盖AI等技术要点。 - [2025 -- 重新出发](https://www.echovic.com/blog/thoughts/2025-start-afresh): 深度回顾2024年的成长轨迹与收获,从阅读283小时61本书、坚持运动316公里跑步、自驾20106公里探索,到工作平台的个人成长实践。系统性展望2025年的人生规划,确立"健康为首、家人次之、工作居后"的生活原则,制定持续学习、追寻热爱、技能提升的具体目标。一份真实的年度总结与新年规划指南。 - [RxJS源码解析(五): Scheduler--高效管理异步操作](https://www.echovic.com/blog/source-code/rxjs-scheduler): 在 RxJS 中,Scheduler (调度器) 是一个重要的概念,它用于控制和管理 Observable 中的异步操作的执行时机。理解 Scheduler 的工作原理和使用方法,可以帮助我们更好地掌控 RxJS 中的异步流程。 - [PixiJS 源码揭秘 - 6. 探索复杂图形 Graphics 的设计与实现](https://www.echovic.com/blog/source-code/explore-the-design-and-implementation-of-graphics): 概述 Graphics类是PixiJS中的一个核心渲染类,它提供了一套完整的2D图形绘制系统。主要用途包括: 1. 绘制基础图形,如线条、圆形、矩形等 2. 为这些图形添加颜色和填充效果 3. 创建复杂的遮罩(mask) 4. 定义复杂... 涵盖前端开发、架构设计、源码解析等技术要点。 - [“老板们”口中的业务判断是什么?](https://www.echovic.com/blog/thoughts/what-is-business-judgment): 深度解析业务判断的核心内涵和实践要点,从业务理解、市场分析、决策评估等多维度阐述业务判断能力的构成要素。结合前端开发视角,详细说明技术人员如何培养业务判断思维,提供学习业务知识、积累实践经验、培养数据分析能力等系统性提升路径,帮助技术人员实现从执行者到决策者的职业转型。 - [RxJS(四):深入理解 Observable 和 Observer](https://www.echovic.com/blog/source-code/rxjs-observables-and-observers): 深入解析RxJS核心组件Observable和Observer的源码实现原理,详细剖析Observable类的订阅机制、数据流传递过程、Observer接口设计和Subscriber实现细节。通过源码分析揭示响应式编程的底层工作机制,为开发者理解RxJS架构设计和构建自定义Observable提供深度技术洞察和实战指导。 - [聊聊最近的内耗](https://www.echovic.com/blog/thoughts/talk-about-the-recent-internal-conflicts): 人生如逆旅,我亦是行人。在漫长旅途中,我们常会遭遇各种棘手问题,陷入内耗泥沼。如何走出,是我们必须修炼的课题。 最近一段时间,我便深陷于自卑与焦虑交织的内耗漩涡之中。 - [PixiJS 源码揭秘 - 5. 探索批处理渲染系统](https://www.echovic.com/blog/source-code/explore-batch-rendering-systems): 在现代网页游戏和图形应用中,性能是一个至关重要的因素。PixiJS 作为一个强大的 2D 渲染引擎,引入了批处理 Batching 系统,以提高渲染效率。今天,我们将深入探讨PixiJS v8的批处理系统,了解其工作原理及其如何提升渲染性能... 涵盖前端开发、架构设计、源码解析等技术要点。 - [《大明王朝 1566》嘉靖四十年风云录](https://www.echovic.com/blog/thoughts/the-forty-years-of-jiajing): 嘉靖四十年,风云变幻,波谲云诡。从钦天监监正周云逸廷杖而死,到改稻为桑国策引发浙江之乱;从严党与清流的朝堂暗涌,到胡宗宪、海瑞、戚继光等正义之士的坚守;从八百万两白银贪污大案的惊天内幕,到抗倭英雄齐大柱的悲剧命运。历史的舞台上演绎着惊心动魄的权力游戏,而百姓却在命运的漩涡中苦苦挣扎。这是一个时代的缩影,也是对权力与正义永恒博弈的深刻思考。 - [群面技巧:如何从众人中脱颖而出](https://www.echovic.com/blog/fe-interview/how-to-stand-out-from-the-group-discussion): 什么是“群面”? 群面,即无领导小组讨论(Leaderless Group Discussion,简称 LGD),是一种将多名应试者临时组成小组,不指定领导,就给定的问题展开讨论以考察应试者综合素质的面试形式。 - [面试攻略:自我介绍的关键要点](https://www.echovic.com/blog/fe-interview/interview-guide-key-points-of-self-introduction): 为什么要自我介绍? 自我介绍在面试和人际交往中都起着至关重要的作用。从面试的角度来看,面试官让候选人做自我介绍有多重目的。首先是暖场,让双方都能快速进入状态,减少紧张感。其次,面试官可以通过自我介绍考察候选人的多方面能力。 - [PixiJS 源码揭秘 - 4. 深入理解渲染系统](https://www.echovic.com/blog/source-code/in-depth-understanding-of-the-rendering-system): AutoDetectRenderer工作原理 在PixiJS中,为了适应不同设备和浏览器的性能需求,引擎提供了一个自动检测渲染器的方法:autoDetectRenderer。 涵盖前端开发、架构设计、源码解析等技术要点。 - [面试官:如果给你一个新项目,你会怎么做?](https://www.echovic.com/blog/fe-interview/how-to-start-a-new-project): 回答 “如果给你一个新项目,你会怎么做?” 这一问题时,不同职级的候选人在主要考察方面以及回答框架上存在着显著差异。下面从前端开发的视角进行具体剖析。 1\. 普通研发岗 「考察点」 基本的技术能力、理解需求、实现功能 「回答... - [程序员的成长秘籍](https://www.echovic.com/blog/thoughts/programmers-growth-secrets): 系统性解析程序员职业发展的完整成长路径,从入门编程到架构师转变的深度指南。详细剖析技术能力进阶、业务理解深化、架构设计思维、团队协作能力等核心要素。分享从前端开发者到前端架构师的实战经验与成长阶段,揭示"手中无剑,心中有剑"的技术境界,帮助程序员制定个人成长策略,实现职业生涯的跃迁升级。 - [PixiJS 源码揭秘 - 3. Scene 与 Container 模块详解](https://www.echovic.com/blog/source-code/detailed-explanation-of-scene-and-container): > 友情提示,本文篇幅较长,且多为代码细节解释。若你对细节不感兴趣,可直接跳转到第三章查看类图,了解 Container 类的整体架构;或者在有需要时,找到对应方法查看详细解释。 涵盖前端开发、架构设计、源码解析等技术要点。 - [但愿人长久,千里共婵娟](https://www.echovic.com/blog/thoughts/happy-mid-autumn-festival): “人有悲欢离合,月有阴晴圆缺,此事古难全。但愿人长久,千里共婵娟”。中秋节是团圆的节日,也是游子寄托思念故乡、思念亲人之情的节日。 - [如何重构 React组件?](https://www.echovic.com/blog/architecture-design/refactor-react-components): 系统性指导React组件重构的最佳实践,从复杂组件的问题识别到优化方案的具体实施。详细介绍组件拆分、自定义Hooks抽取、状态管理优化、性能提升等重构技巧,通过完整的代码示例展示如何将臃肿的组件重构为高性能、可维护、可复用的模块化架构,提升代码质量和开发效率。 - [《大明王朝 1566》之东南柱石胡宗宪](https://www.echovic.com/blog/thoughts/the-southeast-pillar-hu-zongxian-in-ming-dynasty-1566): 《大明王朝1566》中的胡宗宪是一个复杂而立体的人物形象。作为东南柱石,他在抗倭斗争中展现卓越军事才能,深谙政治智慧,在严党与清流之间巧妙周旋。他公忠体国、心怀苍生,面对"改稻为桑"等复杂政策时努力平衡各方利益。与海瑞的刚正不阿不同,胡宗宪选择在现实中担当,体现了"格物致知"的不同理解。文章通过对比剧中理想化形象与历史争议,探讨了在复杂政治环境中如何坚守良知、积极入世的人生哲学。 - [PixiJS 源码揭秘 - 2. 深入探究Application模块](https://www.echovic.com/blog/source-code/dive-deeper-into-the-application-module): 深入解析PixiJS核心Application模块的源码实现和架构设计,详细剖析Application类如何整合渲染器管理、场景图管理和Ticker系统,揭示其初始化流程、生命周期管理和性能优化机制。通过源码分析展示Application模块如何简化2D图形应用开发,为开发者构建高性能游戏和交互应用提供深度技术洞察。 - [在过程中书写真实人生](https://www.echovic.com/blog/thoughts/writing-real-life-in-the-process): 我们常常被告知,人生要有目标,要有理想。目标如同夜空中最亮的星,为我们指引前行的道路;理想恰似远方那座闪耀的灯塔,让我们在迷茫时找到方向。然而,当我们一心盯着目标,急切地奔向理想的彼岸时,却常常忘记了,真正赋予人生意义的,是那一路的过程。 - [依赖倒置原则:张无忌靠的是内力,不是招式](https://www.echovic.com/blog/design-pattern/dependency-inversion-principle): 以张无忌的九阳神功为引,讲清依赖倒置原则:高层模块与低层模块都应依赖抽象。含数据存储的重构示例、依赖注入在前端的做法,以及测试替身与解耦的关系。 - [接口隔离原则:王语嫣懂天下武学,却不属于任何门派](https://www.echovic.com/blog/design-pattern/interface-segregation-principle): 以王语嫣通晓各派武学为引,讲清接口隔离原则:客户端不该依赖它用不到的方法。含"工作和吃饭"接口的拆分示例,以及 TypeScript 中把胖接口拆成小接口的实践。 - [迪米特法则:黄药师的独来独往](https://www.echovic.com/blog/design-pattern/law-of-demeter): 以黄药师的性格为引,讲清迪米特法则:一个对象应当对其他对象知道得尽可能少。含汽车与引擎交互的重构示例、链式调用为何容易违背该法则,以及前端组件通信中的边界。 - [里氏替换原则:子类换了父类,行为不能变](https://www.echovic.com/blog/design-pattern/liskov-substitution-principle): 以郭靖的成长历程为引,讲清里氏替换原则:子类对象应当能替换父类对象而不改变程序行为。含动物类继承的反例、契约式设计的判定方法,以及前端组件继承中的常见违背。 - [开闭原则:像太极拳那样加招式,不改拳理](https://www.echovic.com/blog/design-pattern/open-closed-principle): 以张三丰的太极拳为引,讲清开闭原则:对扩展开放、对修改封闭。含形状扩展的重构示例、用策略与工厂消除 if-else 的做法,以及前端插件化与表单渲染中的应用。 - [单一职责原则:独孤九剑的每一式只破一种兵器](https://www.echovic.com/blog/design-pattern/single-responsibility-principle): 以令狐冲的独孤九剑为引,讲清单一职责原则:一个类只承担一个变更理由。含职责拆分的判定方法、员工管理与报酬管理的重构示例,以及在前端表单校验、动画、数据请求中的落地场景。 - [设计模式六大原则:金庸群侠传](https://www.echovic.com/blog/design-pattern/six-principles-of-design-patterns): 以金庸武侠为背景总览软件设计的六大原则:单一职责、开闭、里氏替换、接口隔离、依赖倒置与迪米特法则。说明 SOLID 五原则与迪米特法则各自约束的是什么、为什么会互相牵扯,并给出每一原则的独立成篇入口。 - [策略模式详解](https://www.echovic.com/blog/design-pattern/strategy-pattern): 策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以互相替换。这种模式使得算法的变化不影响使用算法的客户。策略模式提供了在运行时选择算法的机制,增加了系统的灵活性。 - [迭代器模式详解](https://www.echovic.com/blog/design-pattern/iterator-pattern): 迭代器模式(Iterator Pattern)是一种行为型设计模式,它提供了一种方法顺序访问一个聚合对象中的各个元素,而无需暴露该对象的内部表示。通过迭代器模式,可以对不同的数据结构进行遍历,而不需要了解这些数据结构的内部实现。 - [PixiJS 源码揭秘 - 1. 初识PixiJS源码](https://www.echovic.com/blog/source-code/initial-understanding-of-pixijs-source-code): 深入解析PixiJS高性能2D渲染引擎的源码架构和核心设计理念,详细剖析其WebGL/Canvas双渲染后备机制、模块化架构设计、渲染管线实现和性能优化策略。通过源码分析揭示PixiJS如何实现跨平台高效图形渲染,为开发者理解现代图形引擎架构和构建自定义渲染解决方案提供深度技术参考。 - [告别迷茫:给10 年前的自己](https://www.echovic.com/blog/thoughts/farewell-to-confusion-to-myself-10-years-ago): 在人生的长河中,迷茫常常如影随形,让我们在前行的道路上失去方向,陷入困惑。如果能有机会与 10 年前的自己对话,我一定有很多话想说,尤其是关于如何告别迷茫。 首先我要跟自己说,“不要太顺从了。 - [访问者模式详解](https://www.echovic.com/blog/design-pattern/visitor-pattern): 访问者模式(Visitor Pattern)是一种行为型设计模式,它允许你在不修改对象结构的前提下定义作用于这些对象的新操作。它通过将操作行为从对象中分离出来,放置在一个访问者(Visitor)对象中,使得行为可以动态地添加到对象结构中。这个模式特别适用于对象结构较为稳定,而行为规则频繁变化的场景。 - [模板方法模式详解](https://www.echovic.com/blog/design-pattern/template-method-pattern): 模板方法模式(Template Method Pattern)是一种行为型设计模式,它定义了一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。 - [状态模式详解](https://www.echovic.com/blog/design-pattern/state-pattern): 状态模式(State Pattern)是一种行为型设计模式,它允许对象在内部状态发生改变时改变其行为,对象看起来好像修改了它的类。状态模式的主要目的是使得状态转换的逻辑集中管理,通过引入状态对象,使得状态切换和行为变化变得更加可维护和扩展。 - [寻路,在挑战中前行](https://www.echovic.com/blog/thoughts/pathfinding-moving-forward-in-challenges): 在这个充满挑战的时代,大环境的阴霾似乎笼罩着每一个人。经济不景气,A 股基金连续下跌三年,房产价值缩水,公司裁员不断,工作岗位日益减少,而年龄的压力也如影随形,35 岁大关悄然逼近。 - [观察者模式详解](https://www.echovic.com/blog/design-pattern/observer-pattern): 深入解析观察者模式的核心原理与实现机制,详细剖析Subject-Observer一对多依赖关系的设计思想。包含完整的JavaScript代码实现、天气预报系统实战案例和前端应用场景。讲解事件驱动编程、状态变化通知机制,以及在GUI应用、MVC架构中的最佳实践。 - [《大明王朝 1566》:赵贞吉、海瑞与“格物致知”](https://www.echovic.com/blog/thoughts/investigating-things-to-achieve-knowledge): 赵贞吉与海瑞的交锋 《大明王朝1566》赵贞吉和海瑞关于如何审浙江贪墨案产生了正面的交锋,里面有两段关于格物致知的片段: 1. 赵贞吉心中之羞赧可想而知,毕竟一代“硕儒”,半生的功夫都下在“格物致知”上,这时遇到这样的对手,反而激起了他... - [备忘录模式详解](https://www.echovic.com/blog/design-pattern/memento-pattern): 备忘录模式(Memento Pattern)是一种行为型设计模式,允许在不破坏封装性的前提下,捕获对象的内部状态,并在将来需要时恢复到原先的状态。主要应用于支持撤销和恢复操作的应用程序中,例如文本编辑器、游戏存档系统等。 - [中介者模式详解](https://www.echovic.com/blog/design-pattern/mediator-pattern): 中介者模式(Mediator Pattern)是一种行为型设计模式,它通过引入一个中介者对象,来封装一系列对象之间的交互操作,从而使这些对象不再相互直接引用,降低了对象之间的耦合度。这使得一个对象的变化可以独立于其他对象的变化,更加灵活和可拓展。 - [解释器模式详解](https://www.echovic.com/blog/design-pattern/interpreter-pattern): 解释器模式(Interpreter Pattern)是一种行为型设计模式,它提供了一种方法来定义语言的文法,并且通过解释这些语句来实现该语言的语法分析和执行。主要应用于编译器、查询语言和报告生成等场景。 - [深入解析 useSyncExternalStore 在 React 的实现和运行机制](https://www.echovic.com/blog/source-code/analyzing-usesyncexternalstore-source-code): 深入解析React 18新增的useSyncExternalStore Hook的核心实现原理和运行机制,详细剖析其在React源码中的具体实现、状态订阅同步流程、并发模式下的处理策略。通过源码分析揭示该Hook如何解决外部状态管理库的订阅同步问题,为开发者理解React状态管理机制和构建高性能状态管理方案提供深度技术洞察。 - [命令模式详解](https://www.echovic.com/blog/design-pattern/command-pattern): 命令模式(Command Pattern)是一种行为型设计模式,它将请求或操作封装成一个对象,从而使得可以用不同的请求、队列或日志来参数化其他对象。同时,它还支持可撤销的操作。 - [责任链模式详解](https://www.echovic.com/blog/design-pattern/chain-of-responsibility-pattern): 责任链模式是一种行为型设计模式,它允许多个对象都有机会处理请求,从而避免请求发送者与多个请求处理者耦合在一起。这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。 - [Zustand 源码解析](https://www.echovic.com/blog/source-code/analyzing-zustand-source-code): 深入解析Zustand轻量级状态管理库的核心源码实现,详细剖析其订阅发布机制、状态更新流程、中间件系统和TypeScript类型设计。通过逐行代码分析,揭示Zustand如何以极简的API设计实现高效的状态管理,对比Redux、MobX等方案的优劣,为开发者提供状态管理库选型和自定义状态管理方案的技术参考。 - [代理模式详解](https://www.echovic.com/blog/design-pattern/proxy-pattern): 在软件设计中,代理模式(Proxy Pattern)是一种结构型设计模式。它为其他对象提供一种代理,并由代理对象控制对原对象的访问。代理模式常用于延迟对象的创建、控制对对象的访问以及提高系统的安全性。 - [享元模式详解](https://www.echovic.com/blog/design-pattern/flyweight-pattern): 享元模式是一种结构型设计模式,关注于通过共享机制来有效地支持大量细粒度对象的复用,以减少应用程序的内存使用。这种模式尤其适用于那些对象数量众多,且对象状态大部分可以外部化的场景。 - [普罗米修斯--科幻照进现实](https://www.echovic.com/blog/thoughts/prometheus-science-fiction-shines-into-reality): 今天上班路上听了一期播客https://www.xiaoyuzhoufm.com/episode/669699048fcadceb90cabf19,是真格基金与留形科技 CEO 秦佑铭的对话。 - [外观模式详解](https://www.echovic.com/blog/design-pattern/facade-pattern): 在软件设计中,外观模式(Facade Pattern)是一种结构型设计模式。它为子系统中的一组接口提供了一个统一的高层接口。外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。通过构建一个与客户端交互的外观接口,隐藏子系统的复杂性,从而使得子系统更易于使用和维护。 - [RxJS(三):深入 RxJS 高级主题与实际应用](https://www.echovic.com/blog/architecture-design/rxjs-advanced-topics-and-practical-applications): 深入探索RxJS的高级主题和企业级实际应用,全面覆盖Marble Diagrams调试技巧、Chrome DevTools集成、内存泄漏防护策略、错误处理最佳实践。详细介绍RxJS与React、Angular、Vue等主流框架的集成方案,通过实战项目案例展示如何在复杂业务场景中应用RxJS构建高性能、可扩展的响应式应用架构。 - [RxJS(二):掌握 RxJS 操作符](https://www.echovic.com/blog/architecture-design/rxjs-operators-and-subscription-management): 深入探讨RxJS操作符体系,系统介绍转换操作符(map、mergeMap、switchMap)、过滤操作符(filter、take、debounce)、组合操作符(merge、combineLatest、zip)等核心功能,并介绍多播分享与 Subject 四种类型,通过丰富的代码示例展示如何构建高效、可维护的响应式数据流处理方案。 - [保持在场,做时间的朋友](https://www.echovic.com/blog/thoughts/stay-present-be-a-friend-of-time): 堂弟出差到广州,我和他约了顿饭,聊了很多,颇有些感触。他是 985 高校研究生,明年毕业,暑假就要开始准备秋招找工作。工作目标很明确,稳定第一,薪资第二,发展另说。 - [RxJS(一):深入理解 RxJS 基础与核心概念](https://www.echovic.com/blog/architecture-design/rxjs-fundamentals-and-core-concepts): 深入解析RxJS响应式编程库的基础知识和核心概念,系统介绍Observable、Observer、Subscription等核心组件的工作原理。通过生动的厨房烹饪比喻和丰富的代码示例,详细阐述如何使用RxJS处理异步事件流、数据流转换和复杂事件处理,帮助开发者掌握响应式编程思维和RxJS在现代前端开发中的实际应用。 - [装饰器模式详解](https://www.echovic.com/blog/design-pattern/decorator-pattern): 在软件设计中,装饰器模式(Decorator Pattern)是一种结构型设计模式。它允许向一个现有对象添加新的功能,同时又不改变其结构。装饰器模式通过创建一个装饰类来包装原始类,从而使得原始类和装饰类可以独立变化。 - [组合模式详解](https://www.echovic.com/blog/design-pattern/composite-pattern): 在软件设计中,组合模式(Composite Pattern)是一种结构型设计模式。它的主要目的是将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。这在处理复杂的嵌套结构时尤为有用,例如文件系统、组织架构、图形处理等。 - [JavaScript 异步编程详解](https://www.echovic.com/blog/fe-interview/javascript-asynchronous-programming): 全面深入解析JavaScript异步编程的核心概念与底层实现机制,系统梳理从回调函数到async/await的异步编程模式演进历程。深度剖析事件循环原理、宏任务微任务执行顺序、Promise状态机制、async/await语法糖实现。通过丰富的代码示例和实战场景,详细讲解异步流程控制、并发编程模式、错误处理机制,以及异步编程在前端开发中的性能优化策略与最佳实践。 - [桥接模式详解](https://www.echovic.com/blog/design-pattern/bridge-pattern): 在软件设计中,桥接模式(Bridge Pattern)是一种结构性设计模式。它的主要目的是将抽象部分与实现部分分离,使它们能够独立变化。这种模式通过引入抽象层,减少了抽象与实现之间的耦合,从而实现更灵活的代码设计。 - [适配器模式详解](https://www.echovic.com/blog/design-pattern/adapter-pattern): 适配器模式(Adapter Pattern)是一种结构性设计模式,通过在目标接口和现有接口之间引入适配器类,将不兼容的接口转换为兼容接口,从而使得原本无法直接协作的类可以一起工作。 - [JavaScript 垃圾回收机制详解](https://www.echovic.com/blog/fe-interview/javascript-garbage-collection): JavaScript 是一种高级编程语言,它的内存管理和垃圾回收机制大大简化了开发者的工作,理解垃圾回收机制对优化程序性能和避免内存泄漏非常重要,本文将详细介绍 JavaScript 的垃圾回收机制,包括标记-清除、引用计数、增量回收和分代回收,帮助你深入理解这项关键技术。 - [原型模式详解](https://www.echovic.com/blog/design-pattern/prototype-pattern): 在软件设计中,原型模式(Prototype Pattern)是一种创建型设计模式。它的主要思想是通过复制已有的实例来创建新对象,而不是通过类构造器来创建。这种模式特别适用于对象的创建代价较高,或者需要多个几乎相同的对象时。通过原型模式,我们可以高效地创建对象,并且更灵活地管理对象的状态。 - [创建型设计模式总结](https://www.echovic.com/blog/design-pattern/summary-of-creative-design-patterns): 单例、工厂、抽象工厂、建造者、原型都被归为创建型模式,但它们解决的并不是同一件事。这篇不复述各自的实现,而是把"创建对象"拆成几种不同的麻烦,给出按麻烦找模式的对照表和两组最容易混的选择,并链接到各自独立成篇的详解。 - [建造者模式详解](https://www.echovic.com/blog/design-pattern/builder-pattern): 在软件设计中,建造者模式(Builder Pattern)是一种创建复杂对象的设计模式。它的主要思想是将对象的构造过程分离出来,使得同样的构建过程可以创建不同的表示。 - [工厂模式详解](https://www.echovic.com/blog/design-pattern/factory-pattern): 在软件设计中,工厂模式(Factory Pattern)是一种创建对象的设计模式。它的主要思想是定义一个接口或基类,通过该接口或基类让子类决定实例化哪一个具体类。工厂方法使得实例化过程延迟到子类。本文将介绍工厂模式、抽象工厂模式,并探讨它们在前端开发中的应用场景和一些典型案例。 - [JavaScript 实现继承的多种方式](https://www.echovic.com/blog/fe-interview/implement-inheritance-in-javascript): JavaScript继承机制深度解析:全面讲解原型链继承、构造函数继承、组合继承、原型式继承、寄生式继承、寄生组合式继承等多种实现方式。详细分析每种继承方式的实现原理、优缺点和适用场景,提供完整代码示例和最佳实践。帮助前端开发者深入理解JavaScript基于原型的继承机制,掌握面向对象编程核心概念。 - [单例模式详解](https://www.echovic.com/blog/design-pattern/singleton-pattern): 全面解析单例模式的实现原理和应用场景,详细对比饿汉式、懒汉式、双重检查锁等多种实现方式。深入讲解JavaScript中的单例模式最佳实践,包含配置管理器、数据库连接池等实际案例。分析单例模式的优缺点、线程安全问题和现代前端开发中的应用策略。 - [JavaScript 作用域与闭包详解](https://www.echovic.com/blog/fe-interview/javascript-scope-and-closures): 深入解析JavaScript作用域与闭包的核心机制与底层实现原理,系统阐述全局作用域、函数作用域、块级作用域的特性与区别。详细讲解词法作用域、作用域链、执行上下文等关键概念,深度剖析闭包的形成条件、内存模型、应用场景与性能影响。通过丰富的代码示例展示作用域链查找机制、闭包在模块化、函数柯里化、事件处理中的实际应用,帮助开发者掌握JavaScript核心语言特性。 - [JavaScript 原型与原型链详解](https://www.echovic.com/blog/fe-interview/javascript-prototypes-and-prototype-chains): 深入解析JavaScript基于原型的面向对象编程机制,系统阐述原型(prototype)与原型链(prototype chain)的核心概念和工作原理。详细讲解构造函数、__proto__属性、\[\[Prototype\]\]内部属性的关系,深度剖析对象继承机制、属性查找过程、原型链遍历算法。通过丰富的代码示例展示原型模式在实际开发中的应用,帮助开发者掌握JavaScript面向对象编程的底层实现机制。 - [JavaScript 变量与数据类型](https://www.echovic.com/blog/fe-interview/js-variables-and-data-types): JavaScript 是一门动态类型语言,这意味着你无需提前声明变量的类型。在程序运行时,解释器会自动处理变量的类型。了解 JavaScript 中的基本数据类型和引用类型是理解更高级编程概念的基础。 - [深入了解 JavaScript 中的函数式编程](https://www.echovic.com/blog/fe-interview/in-depth-understanding-of-functional-programming-in-js): 函数式编程是一个强大且日益流行的编程范式,它将函数作为程序构建的基本单元,并强调使用纯函数和不可变数据来编写代码。在JavaScript中,函数式编程的概念可以帮助开发者编写出更简洁、更可维护的代码。本文将深入探讨函数式编程在JavaScript中的应用,帮助你理解其核心概念,特性,以及如何在日常开发中实践。 - [深入理解DOM、BOM和事件模型](https://www.echovic.com/blog/fe-interview/dom-bom-event-model): 深入解析DOM、BOM和事件模型的核心概念与底层实现机制,系统阐述浏览器对象模型与文档对象模型的架构设计。详细讲解DOM节点树结构、BOM浏览器接口、事件冒泡捕获机制等关键技术,深度剖析事件委托、DOM操作优化、跨浏览器兼容性处理等实战技巧。通过丰富的代码示例展示DOM API应用、BOM对象操作、事件处理最佳实践,帮助前端开发者掌握浏览器环境下的核心编程接口与交互机制。 - [详解VSCode依赖注入的原理和实现](https://www.echovic.com/blog/source-code/detailed-explanation-vscode-di): 深入解析VSCode大型开源项目中依赖注入系统的设计原理和实现细节,详细剖析instantiation模块的核心组件:服务标识符、依赖描述符、实例化服务、依赖关系图等。通过源码分析展示如何在TypeScript项目中构建企业级的依赖注入框架,为大型前端应用的架构设计提供实战参考和最佳实践指导。 - [浏览器架构](https://www.echovic.com/blog/fe-interview/browser-architecture): 深入解析现代浏览器的核心架构设计与底层实现机制,系统梳理从单进程到多进程架构的技术演进历程。详细阐述浏览器主进程(Browser Process)、渲染进程(Renderer Process)、GPU进程、网络进程的职责分工与协作机制,深度剖析Blink渲染引擎、V8 JavaScript引擎、网络栈等核心组件的工作原理。通过进程间通信(IPC)、沙箱安全模型、渲染流水线等关键技术点,帮助前端开发者深度理解浏览器内部运行机制。 - [依赖注入:打造高内聚,低耦合的代码艺术](https://www.echovic.com/blog/architecture-design/dependency-injection): 深入解析依赖注入设计模式的核心原理和实践应用,详细阐述控制反转(IoC)概念和依赖注入的三种实现方式:构造函数注入、属性注入、接口注入。通过生动的厨师派对比喻和完整的JavaScript/TypeScript代码示例,展示如何构建高内聚、低耦合的代码架构,提升代码的可测试性、可维护性和可扩展性。 - [HTML基础知识](https://www.echovic.com/blog/fe-interview/html-basic-knowledge): 深入解析HTML(HyperText Markup Language)超文本标记语言的核心概念与语法规范,系统阐述HTML文档结构、语义化标签、表单元素等基础知识。详细讲解DOCTYPE声明、HTML5新特性、标签属性、元素嵌套规则等关键技术点,深度剖析语义化HTML的最佳实践与SEO优化策略。通过丰富的代码示例展示HTML在现代Web开发中的应用,包括可访问性、表单验证、多媒体元素等实用技巧,为前端开发者构建扎实的HTML基础。 - [CSS布局](https://www.echovic.com/blog/fe-interview/css-layout): 深入解析CSS布局的核心技术与实现原理,系统阐述从传统布局到现代布局的技术演进。详细讲解Flexbox弹性布局、Grid网格布局、定位布局、浮动布局等核心技术,深度剖析水平垂直居中、响应式布局、多列布局的实现方案。通过丰富的代码示例展示各种布局技术的应用场景、兼容性处理、性能优化策略,帮助前端开发者掌握现代CSS布局的最佳实践与解决方案。 - [CSS选择器 & 优先级](https://www.echovic.com/blog/fe-interview/css-selector-priority): CSS选择器是前端开发中不可或缺的部分,它允许开发者精确控制页面中元素的样式。选择器的正确使用关乎网页的美观、用户体验以及维护的方便性。了解CSS选择器的种类以及优先级能够帮助我们写出更清晰、更高效的代码。 - [CSS盒模型](https://www.echovic.com/blog/fe-interview/css-box-model): 深入解析CSS盒模型的核心概念与布局机制,系统阐述标准盒模型与IE盒模型的区别与应用场景。详细讲解Content、Padding、Border、Margin四大组成部分的计算规则,深度剖析box-sizing属性对元素尺寸计算的影响。通过丰富的代码示例展示盒模型在实际布局中的应用技巧,包括外边距合并、负边距效果、盒模型调试等关键知识点,为前端开发者提供扎实的CSS布局理论基础。 - [All code is technical debt](https://www.echovic.com/blog/good-articles/all-code-is-technical-debt): > 原文:https://www.tokyodev.com/articles/all-code-is-technical-debt > > 作者:paul-mcmahon ☕ 总结: 💬 技术债务是指通过加速软件开发获得的临时速度提升... - [每天只工作3小时,但每天都做](https://www.echovic.com/blog/good-articles/work-for-only-3-hours-a-day): 原文:https://plumshell.com/2016/03/10/work-for-only-3-hours-a-day-but-everyday/ 作者:plumshell