<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>lj-yg · 工程笔记 · 随笔</title>
    <link>https://www.lj-yg.cn/</link>
    <atom:link href="https://www.lj-yg.cn/feed.xml" rel="self" type="application/rss+xml"/>
    <description>lj-yg 的工程笔记：系统设计、AI Agent、后端与基础设施的实践记录。</description>
    <language>zh-CN</language>
    <lastBuildDate>Fri, 11 Sep 2026 11:18:33 +0800</lastBuildDate>
    <item>
      <title>排版样例：写作时能用什么</title>
      <link>https://www.lj-yg.cn/posts/markdown-guide/</link>
      <guid isPermaLink="true">https://www.lj-yg.cn/posts/markdown-guide/</guid>
      <pubDate>Thu, 10 Sep 2026 00:00:00 +0800</pubDate>
      <description>这篇是把站点支持的 Markdown 元素都摆一遍，方便以后写文章时对照：标题、列表、引用、表格、代码块、图片、分割线。</description>
      <content:encoded><![CDATA[<p>这篇是一份<strong>排版对照表</strong>，不是教程。写作时拿不准某个元素长什么样，回来看一眼。</p>
<h2 id="行内元素">行内元素<a class="anchor" href="#行内元素" aria-label="锚点">#</a></h2>
<p>普通段落。<strong>加粗</strong>、<em>斜体</em>、<code>行内代码</code>、<a href="/archive/">站内链接</a>、<a href="https://nginx.org/" target="_blank" rel="noopener noreferrer">外部链接</a>（外部链接会自动加 <code>rel=&quot;noopener&quot;</code> 并在新标签打开）。</p>
<blockquote>
<p>引用块用衬线斜体，左侧一根朱砂竖线。</p>
<p>适合放定义、结论，或者从别处摘来的原话。第二段会和第一段保持一点间距。</p>
</blockquote>
<h2 id="列表">列表<a class="anchor" href="#列表" aria-label="锚点">#</a></h2>
<p>无序列表：</p>
<ul>
<li>第一项，短一点</li>
<li>第二项，稍微写长一些，用来观察换行后的行距是否还舒服</li>
<li>第三项
<ul>
<li>嵌套一层，缩进由 <code>padding-left</code> 控制</li>
<li>再一条</li>
</ul>
</li>
</ul>
<p>有序列表：</p>
<ol>
<li>先确认目标</li>
<li>再拆步骤</li>
<li>最后验证结果——<strong>做完不等于做对</strong>，验证要单独算一步</li>
</ol>
<h2 id="代码">代码<a class="anchor" href="#代码" aria-label="锚点">#</a></h2>
<p>行内的 <code>ss -lntp</code> 长这样。块级代码带语言标签和复制按钮，语言名写在围栏后面：</p>
<figure class="code" data-lang="python"><pre><code class="language-python"><span class="kn">from</span><span class="w"> </span><span class="nn">pathlib</span><span class="w"> </span><span class="kn">import</span> <span class="n">Path</span>

<span class="k">def</span><span class="w"> </span><span class="nf">files_under</span><span class="p">(</span><span class="n">root</span><span class="p">:</span> <span class="n">Path</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="w">    </span><span class="sd">"""统计目录下的文件数。"""</span>
    <span class="k">return</span> <span class="nb">sum</span><span class="p">(</span><span class="mi">1</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">root</span><span class="o">.</span><span class="n">rglob</span><span class="p">(</span><span class="s2">"*"</span><span class="p">)</span> <span class="k">if</span> <span class="n">p</span><span class="o">.</span><span class="n">is_file</span><span class="p">())</span>

<span class="nb">print</span><span class="p">(</span><span class="n">files_under</span><span class="p">(</span><span class="n">Path</span><span class="p">(</span><span class="s2">"dist"</span><span class="p">)))</span>
</code></pre></figure>
<figure class="code" data-lang="bash"><pre><code class="language-bash"><span class="c1"># 查看 nginx 实际监听的端口与进程</span>
ss<span class="w"> </span>-lntp<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>-E<span class="w"> </span><span class="s2">":80 |:443 "</span>

<span class="c1"># 语法检查后平滑重载</span>
nginx<span class="w"> </span>-t<span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span>nginx<span class="w"> </span>-s<span class="w"> </span>reload
</code></pre></figure>
<p>没有标语言的代码块会按纯文本渲染：</p>
<figure class="code" data-lang="text"><pre><code class="language-text">这是一段没有语言标记的文本块
    保留了缩进
</code></pre></figure>
<h2 id="表格">表格<a class="anchor" href="#表格" aria-label="锚点">#</a></h2>
<table>
<thead>
<tr>
<th>元素</th>
<th>写法</th>
<th>用途</th>
</tr>
</thead>
<tbody>
<tr>
<td>标题</td>
<td>行首 <code>##</code></td>
<td>会自动进右侧目录（3 个以上才显示）</td>
</tr>
<tr>
<td>表格</td>
<td>竖线分隔</td>
<td>参数、对照、清单</td>
</tr>
<tr>
<td>引用</td>
<td>行首 <code>&gt;</code></td>
<td>结论或摘录</td>
</tr>
<tr>
<td>分割线</td>
<td>单独一行 <code>---</code></td>
<td>段落切换</td>
</tr>
</tbody>
</table>
<h2 id="图片">图片<a class="anchor" href="#图片" aria-label="锚点">#</a></h2>
<p>图片放在 <code>static/img/</code> 下，用绝对路径引用，构建时会一起同步：</p>
<figure class="code" data-lang="markdown"><pre><code class="language-markdown">![<span class="nt">说明文字</span>](<span class="na">/assets/img/example.png</span>)
</code></pre></figure>
<h2 id="分割线与结尾">分割线与结尾<a class="anchor" href="#分割线与结尾" aria-label="锚点">#</a></h2>
<hr />
<p>分割线在正文里是一根居中的短横，用来做场景切换。</p>
<p>写到这里，元素基本齐了。以后加新语法（脚注、数学公式之类），先在这里补一条，再拿去正式文章里用。</p>
]]></content:encoded>
    </item>
    <item>
      <title>DeepSeek Harness</title>
      <link>https://www.lj-yg.cn/posts/deepseek-harness/</link>
      <guid isPermaLink="true">https://www.lj-yg.cn/posts/deepseek-harness/</guid>
      <pubDate>Fri, 14 Aug 2026 00:00:00 +0800</pubDate>
      <description>DeepSeek 官方开源的 agent harness：没有特权核心、一切皆插件、事件溯源会话，以及&quot;用 agent 开发 agent&quot;的工程文化。</description>
      <content:encoded><![CDATA[<h2 id="overview">Overview<a class="anchor" href="#overview" aria-label="锚点">#</a></h2>
<p><strong>DeepSeek Harness（<code>dsh</code>）</strong> 是 DeepSeek AI 官方开源的 <strong>agent harness（智能体运行时框架）</strong>，MIT 协议，当前 0.1.0-rc.5（开发者预览，快速迭代，官方声明有破坏性变更）。</p>
<p>与&quot;一个 agent 应用&quot;的区别：它是<strong>承载 agent 的框架</strong> —— 你可以用它运行自己的 agent（Web UI / headless / ACP），也可以把 Claude Code、Codex 桥接进来当执行后端。架构核心是<strong>一切皆插件</strong>，底层由 <a href="/posts/cordis/">Cordis</a> 插件框架驱动（vendored，<code>@deepseek-ai/cordis</code> v4.0.1），设计源自论文《A Programming Paradigm for Spatiotemporal Composability》。</p>
<ul>
<li><strong>CLI:</strong> <code>dsh web</code>（Web UI @ 127.0.0.1:3080）/ <code>dsh --profile headless &quot;task&quot;</code>（一次性 runner）</li>
<li><strong>npm:</strong> <code>npx @deepseek-ai/dsh web</code></li>
<li><strong>Tech stack:</strong> TypeScript monorepo（pnpm，Node ^22.19 || &gt;=24），~2085 个 TS 源文件，49 个包组、~130+ 工作区包</li>
<li><strong>Python SDK:</strong> <code>python/sdk</code>（JSON-RPC stdio 客户端）</li>
<li><strong>Home:</strong> https://github.com/deepseek-ai/deepseek-harness</li>
</ul>
<h2 id="core-architecture">Core Architecture<a class="anchor" href="#core-architecture" aria-label="锚点">#</a></h2>
<h3 id="1-一切皆插件cordis">1. 一切皆插件（Cordis）<a class="anchor" href="#1-一切皆插件cordis" aria-label="锚点">#</a></h3>
<p><strong>没有特权核心</strong>：模型适配器、工具注册表、会话日志、甚至 agent loop 本身都是插件，全部可从配置替换（见 <a href="/posts/plugin-everything-architecture/">Plugin-Everything Architecture</a>）。</p>
<ul>
<li><strong>Context</strong> 是服务仓库：服务占用稳定 <code>ctx.&lt;key&gt;</code>（<code>ctx.tools</code> / <code>ctx.llm</code> / <code>ctx.sessions</code>），插件通过 key 找服务而非 import 具体实现</li>
<li><strong>inject 声明依赖</strong>：加载顺序由服务依赖表达</li>
<li><strong>可逆副作用</strong>：注册都通过 <code>ctx.effect()</code> / <code>ctx.on()</code>，插件卸载时自动回滚</li>
<li><strong>四种事件派发</strong>：<code>emit</code>（观察）/ <code>waterfall</code>（中间件链，需调 next()）/ <code>parallel</code>（并行）/ <code>serial</code>（按序）</li>
</ul>
<h3 id="2-capability-seam能力接缝">2. Capability Seam（能力接缝）<a class="anchor" href="#2-capability-seam能力接缝" aria-label="锚点">#</a></h3>
<p>每个可替换能力拆成三角色：<strong>Service Definition</strong>（接口）/ <strong>Service Provider</strong>（实现）/ <strong>Consumer</strong>（模型工具）。换 provider（本地 bash → 远程沙箱 → pwsh）不影响模型可见契约（见 <a href="/posts/capability-seam/">Capability Seam</a>）。</p>
<p>核心接缝：<code>llm</code>、<code>shell</code>、<code>fs</code>、<code>subprocess</code>、<code>terminal</code>、<code>web</code>、<code>lsp</code>、<code>skill</code>、<code>subagent</code>、<code>sandbox</code>、<code>compaction</code>、<code>code-runtime</code>、<code>jobs</code>、<code>approval</code>。</p>
<h3 id="3-事件溯源会话日志">3. 事件溯源会话日志<a class="anchor" href="#3-事件溯源会话日志" aria-label="锚点">#</a></h3>
<p><code>Session</code> 是 append-only 的 <code>SessionEvent</code> 日志 —— 单一事实来源。LLM 消息历史<strong>从日志派生</strong>（<code>deriveMessages()</code>），不单独存储。&quot;模型可见 ⇒ 已记录&quot;是运行时不变式（见 <a href="/posts/event-sourced-session-log/">Event-Sourced Session Log</a>）。</p>
<h3 id="4-turnstep-循环">4. Turn/Step 循环<a class="anchor" href="#4-turnstep-循环" aria-label="锚点">#</a></h3>
<p>turn = 0+ 个 step；step = 一次模型请求 + 其调用的工具。完整流水线见 <a href="/posts/agent-turn-step-loop/">Agent Turn-Step Loop</a>。</p>
<h2 id="key-subsystems">Key Subsystems<a class="anchor" href="#key-subsystems" aria-label="锚点">#</a></h2>
<table>
<thead>
<tr>
<th>子系统</th>
<th>ctx key</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>session</td>
<td><code>ctx.sessions</code></td>
<td>append-only SessionEvent 日志 + 内存 store</td>
</tr>
<tr>
<td>system-prompt</td>
<td><code>ctx.systemPrompt</code></td>
<td>prompt 分段 + 工具 schema 组装</td>
</tr>
<tr>
<td>tools</td>
<td><code>ctx.tools</code></td>
<td>作用域工具注册表 + 受管执行流水线</td>
</tr>
<tr>
<td>agent</td>
<td><code>ctx.agents</code></td>
<td>Agent 接口、live 注册表、initiator 传播</td>
</tr>
<tr>
<td>agent-loop</td>
<td><code>ctx.agentLoop</code></td>
<td>默认驱动（ReactLoopAgent）</td>
</tr>
<tr>
<td>llm</td>
<td><code>ctx.llm</code></td>
<td>LLM 适配器注册表（deepseek / pi-ai / replay）</td>
</tr>
<tr>
<td>subagent</td>
<td><code>ctx.subagents</code></td>
<td>6 个 provider：in-process / acp / codex / claude-code / dsh-sdk</td>
</tr>
<tr>
<td>sandbox</td>
<td><code>ctx.sandbox</code></td>
<td>进程沙箱（landlock Linux / Windows ACL 受限令牌）</td>
</tr>
<tr>
<td>compaction</td>
<td><code>ctx.compaction</code></td>
<td>上下文压缩（surface replace 摘要）</td>
</tr>
<tr>
<td>web</td>
<td><code>ctx.web</code></td>
<td>搜索（Exa/Perplexity/DeepSeek）+ fetch</td>
</tr>
</tbody>
</table>
<h2 id="engineering-culture">Engineering Culture<a class="anchor" href="#engineering-culture" aria-label="锚点">#</a></h2>
<ul>
<li><strong>1372 个 Agent Notes</strong>（<code>.agents/notes/</code>，implemented/proposed/rejected/archived 四态）—— 用 agent 开发 agent 的工程文化，每个架构决策可检索</li>
<li>双语文档体系（.md + .zh.md + .i18n.yaml 配对），生成式目录（config-catalog / tool-catalog / module-graph / capability-seams 图）</li>
<li>严格规则：非平凡变更必须带 Agent Note；同进程 typed 边界不重复运行时校验；switch on discriminant tags；waterfall 必须调 next()</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Cordis</title>
      <link>https://www.lj-yg.cn/posts/cordis/</link>
      <guid isPermaLink="true">https://www.lj-yg.cn/posts/cordis/</guid>
      <pubDate>Fri, 14 Aug 2026 00:00:00 +0800</pubDate>
      <description>DeepSeek Harness 底层 vendored 的插件框架——插件向共享 context 贡献服务、类型化事件与可逆副作用，五要素加四种事件派发。</description>
      <content:encoded><![CDATA[<h2 id="overview">Overview<a class="anchor" href="#overview" aria-label="锚点">#</a></h2>
<p><strong>Cordis</strong> 是 <a href="/posts/deepseek-harness/">DeepSeek Harness</a> 底层的<strong>插件框架</strong>：插件向共享 context 贡献服务、类型化事件和可逆副作用。设计源自论文《A Programming Paradigm for Spatiotemporal Composability》（cordiverse/paper）。</p>
<p>DeepSeek Harness 没有依赖 npm 版 Cordis，而是<strong>vendored 进仓库</strong>（<code>vendor/cordis</code>），并全部 rescope 为 <code>@deepseek-ai/*</code>（<code>@deepseek-ai/cordis</code> v4.0.1，上游 cordis 4.0.0-rc.7 快照）—— 完全拥有框架层：可审计、可打补丁、可随 harness 发布。</p>
<ul>
<li><strong>上游:</strong> https://github.com/cordiverse/cordis</li>
<li><strong>Vendored 版本:</strong> 4.0.1（本地修改 17+ 项）</li>
<li><strong>配套库:</strong> cosmokit 1.8.1、schemastery 3.18.0（schema 校验）、loader/include/group/timer/hmr/logger-console 插件</li>
</ul>
<h2 id="core-ideas五要素">Core Ideas（五要素）<a class="anchor" href="#core-ideas五要素" aria-label="锚点">#</a></h2>
<ol>
<li><strong>插件是实现 Service 的对象</strong>：函数（可选 <code>inject</code> + <code>apply(ctx)</code>）或 <code>Service</code> 子类，生命周期由 Cordis 挂载到当前 context</li>
<li><strong>Context 是服务仓库</strong>：服务占用稳定 <code>ctx.&lt;key&gt;</code>（<code>ctx.tools</code>、<code>ctx.llm</code>、<code>ctx.sessions</code>），插件通过 key 找服务而非 import 具体实现</li>
<li><strong>inject 声明依赖</strong>：插件声明所需服务，等服务存在后再加载 —— 加载顺序由服务依赖表达而非手动排布</li>
<li><strong>类型化事件通信</strong>：服务通过 TypeScript declaration merging 声明事件名，然后按 <code>emit</code> / <code>waterfall</code> / <code>parallel</code> / <code>serial</code> 派发</li>
<li><strong>注册是可逆副作用</strong>：prompt 分段、工具 schema、适配器、监听器都通过 <code>ctx.effect()</code> / <code>ctx.on()</code> 安装，reload/teardown 可预测回滚</li>
</ol>
<h2 id="dispatch-modes">Dispatch Modes<a class="anchor" href="#dispatch-modes" aria-label="锚点">#</a></h2>
<table>
<thead>
<tr>
<th>Mode</th>
<th>Awaited?</th>
<th>派发顺序</th>
<th>有返回值?</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>emit</code></td>
<td>否</td>
<td>按注册顺序观察</td>
<td>否</td>
</tr>
<tr>
<td><code>waterfall</code></td>
<td>否</td>
<td>按注册顺序观察</td>
<td>是</td>
</tr>
<tr>
<td><code>parallel</code></td>
<td>是</td>
<td>所有监听器并行</td>
<td>否</td>
</tr>
<tr>
<td><code>serial</code></td>
<td>是</td>
<td>按注册顺序</td>
<td>是</td>
</tr>
</tbody>
</table>
<p><strong>Waterfall 语义</strong>：监听器 <code>(...args, next)</code>，调 <code>next()</code> 委托（可能包装的结果传给下一个），不调则短路。策略监听器短路是设计（拥有决策），注解/观察监听器必须委托。</p>
<h2 id="vendoring-决策deepseek-harness-特有">Vendoring 决策（DeepSeek Harness 特有）<a class="anchor" href="#vendoring-决策deepseek-harness-特有" aria-label="锚点">#</a></h2>
<ul>
<li>9 个包全量源码拷贝进 <code>vendor/</code>：cosmokit、schemastery、cordis、loader、include、group、timer、hmr、logger-console</li>
<li>全部 rescope 为 <code>@deepseek-ai/*</code>（发布 harness 即发布框架层；占用上游名会 squat registry）</li>
<li>目录名和上游版本号故意不变，manifest 仍可读为上游快照；<code>linkWorkspacePackages</code> 让保留的 semver 范围解析到 pin 的 workspace</li>
<li><strong>17+ 项本地修改日志</strong>（vendor/README.md）：fiber 生命周期硬化（3 处 reentrant disposal 缺口）、事务性 Loader/Include 配置协调、HMR 精确配置监听（Windows 路径）、<code>!!js</code> 表达式惰性求值（loader config）、include patch 语义导出等</li>
</ul>
<h2 id="extension-pointsdsh-内用法">Extension Points（dsh 内用法）<a class="anchor" href="#extension-pointsdsh-内用法" aria-label="锚点">#</a></h2>
<ul>
<li><code>ctx.effect()</code> / <code>ctx.on()</code> 安装可逆副作用</li>
<li><strong>Map → derived-union 模式</strong>：插件通过 <code>declare module</code> 声明合并扩展 <code>ContentBlockMap</code>、<code>SessionEventMap</code>、<code>TurnTriggerMap</code>、<code>FinishReasonMap</code> 等 6 个 canonical maps —— 无需改拥有包</li>
<li><code>isolate</code> realm：preset 挂载的服务对 host 不可见（agent preset 组合的基础）</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Plugin-Everything Architecture</title>
      <link>https://www.lj-yg.cn/posts/plugin-everything-architecture/</link>
      <guid isPermaLink="true">https://www.lj-yg.cn/posts/plugin-everything-architecture/</guid>
      <pubDate>Fri, 14 Aug 2026 00:00:00 +0800</pubDate>
      <description>&quot;一切皆插件&quot;：模型适配器、工具注册表、会话日志甚至 agent loop 本身都可从配置替换，扩展方式就是在别的插件旁边挂一个插件。</description>
      <content:encoded><![CDATA[<h2 id="definition">Definition<a class="anchor" href="#definition" aria-label="锚点">#</a></h2>
<p><strong>&quot;一切皆插件&quot;（plugin-everything）</strong> 是 <a href="/posts/deepseek-harness/">DeepSeek Harness</a> 的架构主张：<strong>没有特权核心</strong>。模型适配器、工具注册表、会话日志、甚至 agent loop 本身都是插件，全部可从配置替换。你扩展 dsh 的方式 = 在别的插件旁边挂一个插件。</p>
<p>底层框架是 <a href="/posts/cordis/">Cordis</a>（vendored）。</p>
<h2 id="核心机制">核心机制<a class="anchor" href="#核心机制" aria-label="锚点">#</a></h2>
<h3 id="1-context-服务仓库">1. Context = 服务仓库<a class="anchor" href="#1-context-服务仓库" aria-label="锚点">#</a></h3>
<p>服务占用稳定 <code>ctx.&lt;key&gt;</code>（<code>ctx.tools</code>、<code>ctx.llm</code>、<code>ctx.sessions</code>）。插件通过 key 找服务，<strong>不 import 具体实现</strong> —— 运行时组合而非编译时耦合。</p>
<h3 id="2-inject-声明依赖">2. inject 声明依赖<a class="anchor" href="#2-inject-声明依赖" aria-label="锚点">#</a></h3>
<p>插件 <code>inject: ['shell']</code> 声明所需服务，等服务存在后再加载。加载顺序由服务依赖表达，而非手动 boot 排布。</p>
<h3 id="3-可逆副作用registrations-are-effects">3. 可逆副作用（Registrations are effects）<a class="anchor" href="#3-可逆副作用registrations-are-effects" aria-label="锚点">#</a></h3>
<p>每个贡献（prompt 分段、工具 schema、适配器、监听器、provider）都通过 <code>ctx.effect()</code> / <code>ctx.on()</code> 安装；注册返回 disposer。插件卸载时一切可预测回滚 —— 没有&quot;卸载残留&quot;。</p>
<h3 id="4-声明合并扩展map-derived-union">4. 声明合并扩展（Map → derived-union）<a class="anchor" href="#4-声明合并扩展map-derived-union" aria-label="锚点">#</a></h3>
<p>几乎所有可扩展 sum type 遵循一个模式：interface 按 discriminant tag 建 map（<code>ThingMap</code>），union 用 <code>keyof</code> 派生。插件通过 <code>declare module</code> <strong>声明合并</strong>添加变体 —— 无需改拥有包：</p>
<figure class="code" data-lang="ts"><pre><code class="language-ts"><span class="c1">// 插件扩展，不改 dsh-session 源码</span>
<span class="kr">declare</span><span class="w"> </span><span class="nx">module</span><span class="w"> </span><span class="s1">'@deepseek-ai/dsh-session'</span><span class="w"> </span><span class="p">{</span>
<span class="w">  </span><span class="kd">interface</span><span class="w"> </span><span class="nx">SessionEventMap</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="s1">'compaction/summary'</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="cm">/* ... */</span><span class="w"> </span><span class="p">}</span>
<span class="w">  </span><span class="p">}</span>
<span class="p">}</span>
</code></pre></figure>
<p>6 个 canonical maps：<code>ContentBlockMap</code>、<code>MessageSourceMap</code>、<code>FinishReasonMap</code>、<code>TurnTriggerMap</code>、<code>TurnEndReasonMap</code>、<code>SessionEventMap</code>。</p>
<h3 id="5-四种事件派发">5. 四种事件派发<a class="anchor" href="#5-四种事件派发" aria-label="锚点">#</a></h3>
<p><code>emit</code>（观察）/ <code>waterfall</code>（中间件链，需 next()）/ <code>parallel</code>（并行）/ <code>serial</code>（按序）—— 见 <a href="/posts/cordis/">Cordis</a>。</p>
<h2 id="组合机制profile-bundle-patch">组合机制：Profile / Bundle / Patch<a class="anchor" href="#组合机制profile-bundle-patch" aria-label="锚点">#</a></h2>
<ul>
<li><strong>Profile</strong>：命名组合（Harness home 内），列出 bundle + 用户 <code>cordis.patch.yml</code>；<code>web</code> / <code>headless</code> 是模板</li>
<li><strong>Bundle</strong>：Cordis config rows + 其代码的分发格式（<code>dsh.profile</code> 列 bundle，<code>dsh.bundle</code> 指向 patch 文件）</li>
<li><strong>Patch 层序</strong>：profile bundles（按列序）→ profile patch → home-level patch → <code>--patch</code> overlay。patch 按 row id 替换整个 config 或插入新 row</li>
<li><strong>dsh-base</strong> = 每个 profile 第一层（模型适配器、工具、持久化、sandbox/approval 政策、settings/credentials/telemetry）</li>
<li>验证：<code>dsh --profile web --dump-config</code> 打印实际启动的插件树；每行都可被你的 patch 替换</li>
</ul>
<h2 id="能力作用域scope-与-agent-preset">能力作用域：Scope 与 Agent Preset<a class="anchor" href="#能力作用域scope-与-agent-preset" aria-label="锚点">#</a></h2>
<ul>
<li><strong>Scope（作用域）</strong>：per-agent 注册原语（<code>createScope</code>/<code>scopeOf</code>/<code>scopeTarget</code>），session/agent 的注册是 agent-local，disposal 时回滚</li>
<li><strong>Agent Preset</strong>（<code>ctx.agentPresets</code>）：per-session agent 组合，从 preset cordis.yml 在 agent scope 下挂载
<ul>
<li>子 agent 通过 <code>composeFrom</code> <strong>继承父的组合</strong>（bind 非 mount —— 拿到父的同一 generation，保证与父历史一致）</li>
<li><code>isolate</code> realm：preset 挂载的服务对 host 不可见（agent 私有服务）</li>
<li><code>recompose</code> 可在 agent 无产出时换 preset（有产出则禁止 —— 已记录的工具调用新组合做不了）</li>
</ul>
</li>
</ul>
<h2 id="why价值">Why（价值）<a class="anchor" href="#why价值" aria-label="锚点">#</a></h2>
<ol>
<li><strong>可组合</strong>：产品是插件树，任何层可被更高层 patch 覆盖</li>
<li><strong>可热改</strong>：HMR 支持运行时配置/模块热更新</li>
<li><strong>可替换</strong>：换 provider、换 loop、换持久化后端，全部从配置</li>
<li><strong>可回滚</strong>：副作用可逆，卸载无残留</li>
<li><strong>可扩展无 fork</strong>：声明合并扩展 map，不改拥有包源码</li>
</ol>
<h2 id="trade-offs-open-questions">Trade-offs / Open Questions<a class="anchor" href="#trade-offs-open-questions" aria-label="锚点">#</a></h2>
<ul>
<li>&quot;一切皆插件&quot;的代价：心智模型复杂、调试插件树困难（有 <code>--dump-config</code> 缓解）</li>
<li>插件粒度：dsh 拆成 ~130+ 工作区包，包爆炸是真实成本（capability seam 规则部分缓解）</li>
<li>框架层 vendoring（cordis 17+ 本地修改）：拥有框架层 = 可审计可补丁，但同步上游成本高</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Capability Seam</title>
      <link>https://www.lj-yg.cn/posts/capability-seam/</link>
      <guid isPermaLink="true">https://www.lj-yg.cn/posts/capability-seam/</guid>
      <pubDate>Fri, 14 Aug 2026 00:00:00 +0800</pubDate>
      <description>把可替换能力拆成 Service Definition / Provider / Consumer 三个包——换执行后端不再牵连模型看到的工具契约。</description>
      <content:encoded><![CDATA[<h2 id="definition">Definition<a class="anchor" href="#definition" aria-label="锚点">#</a></h2>
<p><strong>Capability Seam（能力接缝）</strong> 是 <a href="/posts/deepseek-harness/">DeepSeek Harness</a> 中&quot;可替换能力&quot;的模块化模式：一个可替换能力拆成<strong>三个角色</strong>，分别放在独立包中：</p>
<ol>
<li><strong>Service Definition</strong> — Cordis <code>Service</code> + vocabulary types，拥有 <code>ctx.&lt;key&gt;</code>，只依赖契约所需词汇。它是一个 <code>Service</code>（抽象类或具体注册表服务），<strong>绝不</strong>是 TS <code>interface</code></li>
<li><strong>Service Provider</strong> — 提供/注册实现的插件（如 <code>dsh-bash-local</code>、<code>dsh-bash-sandbox</code>）</li>
<li><strong>Consumer</strong> — 模型和插件编程对向（如 <code>dsh-tool-bash</code>：<code>bash</code> 工具 schema）</li>
</ol>
<p>三者中<strong>任何一个角色都不构成 seam</strong>。一个完整的接缝 = Service Definition + 一个或多个 Provider + 一个或多个 Consumer。</p>
<h2 id="why">Why<a class="anchor" href="#why" aria-label="锚点">#</a></h2>
<p>可替换能力的三个关注点以<strong>不同速率、因不同原因</strong>变化：</p>
<ul>
<li><strong>契约</strong>（能力是什么）—— 极少变</li>
<li><strong>实现</strong>（怎么跑）—— 常变（本地 → 沙箱 → 远程）</li>
<li><strong>消费者 API</strong>（模型/插件对向）—— 变但独立</li>
</ul>
<p>如果合并一个包，换本地 executor 为沙箱 executor 会牵连模型看到的工具 schema，即使模型契约从未变。拆分后：<strong>Service Provider 和 Consumer 独立演进，新后端永不冒模型契约风险</strong>。</p>
<p>这不同于&quot;运行时谁提供/谁需要能力&quot;（Cordis services + <code>inject</code> 已解决），seam 决定的是<strong>包边界</strong>。</p>
<h2 id="canonical-examplebash-三件套">Canonical Example（bash 三件套）<a class="anchor" href="#canonical-examplebash-三件套" aria-label="锚点">#</a></h2>
<table>
<thead>
<tr>
<th>角色</th>
<th>包</th>
<th>内容</th>
</tr>
</thead>
<tbody>
<tr>
<td>Service Definition</td>
<td><code>dsh-shell</code></td>
<td><code>ShellExecutor</code>、<code>ShellRunResult</code>、<code>ShellProcess</code> 词汇，<code>ctx.shell</code></td>
</tr>
<tr>
<td>Service Provider</td>
<td><code>dsh-bash-local</code> / <code>dsh-bash-sandbox</code> / <code>dsh-pwsh-local</code></td>
<td>子进程、进程组 kill、沙箱包装</td>
</tr>
<tr>
<td>Consumer</td>
<td><code>dsh-tool-bash</code> / <code>dsh-tool-pwsh</code></td>
<td><code>bash</code> 工具 schema + 后台任务注册</td>
</tr>
</tbody>
</table>
<p>换执行器（本地 bash → landlock 沙箱 → Windows pwsh）不影响模型怎么请求 bash。</p>
<h2 id="variants何时不分拆">Variants（何时不分拆）<a class="anchor" href="#variants何时不分拆" aria-label="锚点">#</a></h2>
<ul>
<li><strong>LLM seam 折叠了 Definition 和 Consumer</strong>：Consumer 是 loop 本身（不是可替换的 schema 表面），适配器作为 Provider 包（<code>llm-deepseek</code> / <code>llm-pi-ai</code> / <code>llm-replay</code>）</li>
<li><strong>subagent 是&quot;多 provider 并存&quot;变体</strong>：<code>ctx.subagents</code> 按名注册多个 provider（in-process / acp / codex / claude-code / dsh-sdk），不同于 bash 的单执行器 —— 其注册表跟随 LLM adapter registry 模式</li>
<li><strong>web 是一个接缝两个操作</strong>（search + fetch）：一个 provider-selection 政策所有者、一个 abort/error 词汇，但 Provider 分 <code>WebSearchProvider</code> / <code>WebFetchProvider</code> 注册能力（非工具）</li>
</ul>
<h2 id="full-seam-inventorydsh">Full Seam Inventory（dsh）<a class="anchor" href="#full-seam-inventorydsh" aria-label="锚点">#</a></h2>
<p><code>ctx.llm</code>、<code>ctx.shell</code>、<code>ctx.subprocess</code>、<code>ctx.fs</code>、<code>ctx.terminal</code>、<code>ctx.web</code>、<code>ctx.lsp</code>、<code>ctx.skills</code>、<code>ctx.subagents</code>、<code>ctx.sandbox</code>、<code>ctx.compaction</code>、<code>ctx.codeRuntime</code>、<code>ctx.jobs</code>、<code>ctx.approval</code>、<code>ctx.sessionPersistence</code>、<code>ctx.settings</code>、<code>ctx.credentials</code>、<code>ctx.sessionTelemetry</code>、<code>ctx.storage</code>、<code>ctx.sessionQuery</code>、<code>ctx.sessionTitle</code>、<code>ctx.userQuestions</code>、<code>ctx.directoryPicker</code>、<code>ctx.workflowEngine</code>、<code>ctx.spillStore</code>、<code>ctx.attachments</code></p>
<h2 id="trade-offs">Trade-offs<a class="anchor" href="#trade-offs" aria-label="锚点">#</a></h2>
<ul>
<li><strong>代价</strong>：拆分增加包和样板（package.json、tsconfig、README、injection wiring）</li>
<li><strong>收益</strong>：Provider 和 Consumer 独立发布/版本化；新后端零风险触碰模型契约</li>
<li><strong>不预拆分</strong>：一个能力只有一个想象 provider 和一个 Consumer 时保持单包，直到第二个出现</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Agent Turn-Step Loop</title>
      <link>https://www.lj-yg.cn/posts/agent-turn-step-loop/</link>
      <guid isPermaLink="true">https://www.lj-yg.cn/posts/agent-turn-step-loop/</guid>
      <pubDate>Fri, 14 Aug 2026 00:00:00 +0800</pubDate>
      <description>把 agent 执行建模为 turn → step → 工具调用的嵌套循环，每一层都留下可回放的持久化会话事件。</description>
      <content:encoded><![CDATA[<h2 id="definition">Definition<a class="anchor" href="#definition" aria-label="锚点">#</a></h2>
<p><strong>Turn-Step 循环</strong> 是 <a href="/posts/deepseek-harness/">DeepSeek Harness</a> agent 驱动（agent-loop）的核心执行模型：</p>
<ul>
<li><strong>step（步骤）</strong> = 一次模型请求 + 它调用的工具</li>
<li><strong>turn（回合）</strong> = 0+ 个 step：在第一个输入被认领前打开，一旦没有欠账就关闭</li>
</ul>
<p>一个 agent 交互被建模为嵌套的 turn → step → 工具执行，每一层都有 durable session event（见 <a href="/posts/event-sourced-session-log/">Event-Sourced Session Log</a>）。</p>
<h2 id="turn-flow完整流水线">Turn Flow（完整流水线）<a class="anchor" href="#turn-flow完整流水线" aria-label="锚点">#</a></h2>
<figure class="code" data-lang="text"><pre><code class="language-text">turn/start
  claim next-step input + 1 queued next-turn message
  assemble prompt sections + tool schemas（ctx.systemPrompt）
  -&gt; agent/pre-step                [waterfall] reject | enter(messages)
     reject / 空 enter → turn 无 step 关闭
     step/start
     append user/message
     deriveMessages → agent/request [waterfall] → llm/stream
       → assistant/chunk* → assistant/message
     tool/call* → tools/pre-execute → tools/execute → tools/post-execute → tool/result*
     step/end
     工具还欠请求，或 next-step 输入到达 → claim → 下一 step
  -&gt; agent/turn-stopping           [serial]
turn/end
</code></pre></figure>
<p>事件分三类：</p>
<ul>
<li><strong>Durable session events</strong>：<code>turn/*</code>、<code>step/*</code>、<code>user/message</code>、<code>assistant/*</code>、<code>tool/*</code> —— 持久化事实</li>
<li><strong>Live agent events</strong>（<code>agent/*</code>）：<code>created</code>、<code>disposed</code>、<code>status</code>、<code>inbox/*</code>、<code>pre-step</code>、<code>request</code>、<code>request-error</code>、<code>session-start</code>、<code>turn-stopping</code> —— 观察/拦截在飞工作</li>
<li><strong>Capability events</strong>（<code>fs/*</code>、<code>tools/*</code>、<code>telemetry/*</code>）：给 seam 挂政策和适配器</li>
</ul>
<h2 id="agent-handle">Agent Handle<a class="anchor" href="#agent-handle" aria-label="锚点">#</a></h2>
<p><code>Agent</code> 是每个插件（UI、hooks、orchestrators）编程对向的接口：</p>
<ul>
<li><code>send(message, target, wakeup)</code> — 路由到 inbox 边界（<code>next-turn</code> / <code>next-step</code>）</li>
<li><code>followup()</code> — 排队普通后续回合并唤醒</li>
<li><code>steer()</code> — 最近 step 的转向输入（运行中在下一步边界消费）</li>
<li><code>inject()</code> — 排队模型面向上下文，<strong>不唤醒</strong>（下一 pre-step 认领）</li>
<li><code>cancel(cause, options)</code> — 清队列 + abort 活跃 turn；cause: user | parent | hook | disposed</li>
<li><code>whenIdle()</code> — 整个 agent 活动达到静止</li>
<li><code>runMaintenance()</code> — turn 间维护任务（compaction 用）</li>
<li>Status: <code>idle</code> | <code>running</code></li>
</ul>
<p>Inbox = 两个有序 pending 队列（next-turn / next-step），agent 拥有作为 durable 投影；<code>claim()</code> 移除 proposed step batch（所有 next-step + turn 边界时 1 个 next-turn）。</p>
<h2 id="关键机制">关键机制<a class="anchor" href="#关键机制" aria-label="锚点">#</a></h2>
<h3 id="agentpre-stepwaterfall">agent/pre-step（waterfall）<a class="anchor" href="#agentpre-stepwaterfall" aria-label="锚点">#</a></h3>
<p>唯一在请求派生前的 serial listener chain。监听器可以 <strong>reject</strong>（不开 step）或 <strong>enter</strong>（替换进入 step 的消息批次）。被 reject 的消息不丢弃也不重发，turn 无 step 关闭并记录尝试。<code>PreStepDecision = { kind: 'reject' } | { kind: 'enter'; messages }</code>。</p>
<h3 id="agentrequestwaterfall">agent/request（waterfall）<a class="anchor" href="#agentrequestwaterfall" aria-label="锚点">#</a></h3>
<p>替换冻结的 call config。<code>await next()</code> 得到机器将用的 config（首次请求用 agent options，之后用 logged header）；可返回替换。<strong>不能改消息</strong> —— 模型可见内容必须走 logged channels。</p>
<h3 id="工具调度executetoolcalls">工具调度（executeToolCalls）<a class="anchor" href="#工具调度executetoolcalls" aria-label="锚点">#</a></h3>
<ul>
<li><strong>exclusive</strong> 调用形成屏障（单独跑）；<strong>parallel</strong> 调用滚动池并行（<code>isConcurrencySafe</code> 决定）</li>
<li>结果按<strong>模型顺序</strong>提交；abort 为未启动调用记录合成 error result 保持 replay 有效</li>
<li><code>deferContext()</code> 给复合工具嵌套派发上下文；<code>concludeTurn()</code> 标记终端结果（提前结束 turn）</li>
<li>Code Mode：<code>run_code</code> 子调度经 <code>tools/code-dispatch-log</code> waterfall</li>
</ul>
<h3 id="max-tokens-sticky">max-tokens sticky<a class="anchor" href="#max-tokens-sticky" aria-label="锚点">#</a></h3>
<p>一旦某 step 达 max-tokens 上限，后续正常完成的 step <strong>不得降级</strong> turn 结局。</p>
<h3 id="错误恢复">错误恢复<a class="anchor" href="#错误恢复" aria-label="锚点">#</a></h3>
<p><code>agent/request-error</code>（waterfall）：failed model step 关闭后、turn 关闭前运行；监听器可返回 <code>{ kind: 'retry' }</code>（拥有恢复）或 delegate（默认 terminal）。</p>
<h2 id="设计要点">设计要点<a class="anchor" href="#设计要点" aria-label="锚点">#</a></h2>
<ul>
<li><strong>输入经一个 inbox</strong>：某些消息立即唤醒驱动；injected context 在 inbox 等另一消息唤醒</li>
<li><strong>turn/end 在无 step 时也记录</strong>（reject / empty / cancelled / failure）—— 尝试本身可审计</li>
<li>扩展插件依赖 <code>agent</code>（含需要 initiator 时），<strong>不依赖 agent-loop</strong> —— loop 保持可替换</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Event-Sourced Session Log</title>
      <link>https://www.lj-yg.cn/posts/event-sourced-session-log/</link>
      <guid isPermaLink="true">https://www.lj-yg.cn/posts/event-sourced-session-log/</guid>
      <pubDate>Fri, 14 Aug 2026 00:00:00 +0800</pubDate>
      <description>append-only 的 SessionEvent 日志是单一事实来源，模型上下文从日志派生，因此上下文压缩不需要模型参与。</description>
      <content:encoded><![CDATA[<h2 id="definition">Definition<a class="anchor" href="#definition" aria-label="锚点">#</a></h2>
<p><strong>事件溯源会话日志</strong> 是 <a href="/posts/deepseek-harness/">DeepSeek Harness</a> 会话的核心架构：<code>Session</code> 是 <strong>append-only</strong> 的 <code>SessionEvent</code> 日志 —— 一个 agent 完整交互历史的<strong>单一事实来源</strong>。LLM 消息历史<strong>从日志派生</strong>（<code>deriveMessages()</code>），<strong>不单独存储</strong>；重放就是重新派生。</p>
<p>核心不变式：<strong>&quot;模型可见 ⇒ 已记录&quot;</strong>（Model-visible ⟺ logged）。任何到达模型请求的内容必须能从日志重构 —— 新的模型可见输入必须新增 session event 类型。</p>
<h2 id="sessioneventmap事件词汇">SessionEventMap（事件词汇）<a class="anchor" href="#sessioneventmap事件词汇" aria-label="锚点">#</a></h2>
<p><strong>merge-extensible</strong>：插件通过 TypeScript declaration merging 扩展事件类型（如 compaction 插件添加 <code>compaction/start</code>/<code>summary</code>/<code>end</code>）。</p>
<p>Core 事件：</p>
<table>
<thead>
<tr>
<th>事件</th>
<th>内容</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>turn/start</code> / <code>turn/end</code></td>
<td>打开/关闭 turn（reason: completed/blocked/max-tokens/aborted/error）</td>
</tr>
<tr>
<td><code>step/start</code> / <code>step/end</code></td>
<td>打开/关闭 step（一次模型请求 + 工具执行）</td>
</tr>
<tr>
<td><code>user/message</code></td>
<td>用户角色消息（直接 prompt / agent.inject() 注入 / goal 续轮）</td>
</tr>
<tr>
<td><code>assistant/chunk</code></td>
<td>原始流块 —— token 级重放保真</td>
</tr>
<tr>
<td><code>assistant/message</code></td>
<td>组装好的助手消息（含 usage）</td>
</tr>
<tr>
<td><code>tool/call</code></td>
<td>模型请求的工具调用（raw arguments JSON）</td>
</tr>
<tr>
<td><code>tool/result</code></td>
<td>工具结果（message + error identity + opaque meta）</td>
</tr>
<tr>
<td><code>todo/write</code></td>
<td>整个 todo 列表快照</td>
</tr>
<tr>
<td><code>request/header</code></td>
<td>EpochHeader（call config + system prompt + tool schemas）</td>
</tr>
<tr>
<td><code>request/context</code></td>
<td>路由容量元数据</td>
</tr>
<tr>
<td><code>session/end-seed</code></td>
<td>构造种子结束标记</td>
</tr>
</tbody>
</table>
<h2 id="sessionevent-结构">SessionEvent 结构<a class="anchor" href="#sessionevent-结构" aria-label="锚点">#</a></h2>
<ul>
<li>proper discriminated union over <code>type</code>：<code>switch (event.type)</code> 窄化 <code>event.data</code>，无需 cast</li>
<li><code>seq = log.length</code> 单调连续；事件不可变 deep-frozen</li>
<li><code>Session.append()</code> 在 append 时校验 JSON 可序列化（BigInt/function/Map/Date 等拒绝）和 surface 契约 —— 坏事件在源头失败而非后端 flush 时</li>
<li><strong><code>ignorable: true</code></strong> 标记纯信息记录；缺省 = required（reader 遇到未识别类型必须 refuse 而非静默丢弃）</li>
</ul>
<h2 id="surface-机制模型可见历史">Surface 机制（模型可见历史）<a class="anchor" href="#surface-机制模型可见历史" aria-label="锚点">#</a></h2>
<p>三个<strong>消息产生型事件</strong>（<code>SurfaceEventType</code>: user/message, assistant/message, tool/result）带 <code>SurfaceOp</code>：</p>
<ul>
<li><code>'append'</code> — 正常尾部追加</li>
<li><code>{ op: 'replace', start, end }</code> — 用新节点替换 start..end 表面节点（compaction 用）</li>
</ul>
<p><code>Session.surface</code> 是 readonly live 投影；<code>deriveMessages()</code> 按 surface 节点顺序折叠派生模型历史。<strong>compaction 通过 replace 把一段 surface 摘要成一个 user/message</strong>，被影子的原始事件仍在日志中（可审计、可追溯）。</p>
<h2 id="为什么这是上下文管理的根基">为什么这是上下文管理的根基<a class="anchor" href="#为什么这是上下文管理的根基" aria-label="锚点">#</a></h2>
<ol>
<li><strong>重放保真</strong>：raw <code>assistant/chunk</code> 保留 token 级流式细节，UI 渲染和重放一致</li>
<li><strong>可压缩</strong>：surface replace 让 compaction 无模型改写历史，影子节点不丢</li>
<li><strong>可派生</strong>：fork、resume、transcript、telemetry、title 全部从同一 log 派生</li>
<li><strong>可持久化</strong>：<code>SessionPersistence</code> seam（JSONL / SQLite 后端）+ session/flush checkpoint + 崩溃恢复</li>
<li><strong>可审计</strong>：坏事件源头拒绝；unrecognized 事件 refuse 而非静默丢</li>
</ol>
<h2 id="相关类型">相关类型<a class="anchor" href="#相关类型" aria-label="锚点">#</a></h2>
<ul>
<li><code>EpochHeader</code>（request/header 事件）：call config + adapterDefaults + system + tools，最新快照重构；<code>foldRequestHeader(events)</code> 选择最新 snapshot</li>
<li><code>Branded ID</code>：<code>CallId</code>（工具调用关联）、<code>SessionId</code>（agent/session 共享身份）—— 跨包边界类型安全</li>
</ul>
<h2 id="open-questions-debates">Open Questions / Debates<a class="anchor" href="#open-questions-debates" aria-label="锚点">#</a></h2>
<ul>
<li>日志增长 → 需要 compaction（surface replace）作为一等公民；token-meter 测量影子内容</li>
<li>事件溯源 vs 直接存消息数组：前者强在重放/审计/派生，后者简单但不可重放</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Agent Harness Frameworks</title>
      <link>https://www.lj-yg.cn/posts/agent-harness-frameworks/</link>
      <guid isPermaLink="true">https://www.lj-yg.cn/posts/agent-harness-frameworks/</guid>
      <pubDate>Fri, 14 Aug 2026 00:00:00 +0800</pubDate>
      <description>把 DeepSeek Harness 和 LangGraph、OpenHarness、nanobot、learn-claude-code 放进同一张表，看清 agent 运行时这个设计空间的几条路线。</description>
      <content:encoded><![CDATA[<h2 id="what-is-being-compared-and-why">What is being compared and why<a class="anchor" href="#what-is-being-compared-and-why" aria-label="锚点">#</a></h2>
<p>DeepSeek Harness（dsh）是 2026 年 DeepSeek AI 开源的 agent harness。本文把它与 wiki 中已有的同类框架对比，帮助定位&quot;agent 运行时&quot;这个设计空间的各条路线。对比维度：架构范式、可替换性、会话模型、执行后端、生态。</p>
<h2 id="comparison-table">Comparison Table<a class="anchor" href="#comparison-table" aria-label="锚点">#</a></h2>
<table>
<thead>
<tr>
<th>维度</th>
<th>DeepSeek Harness (dsh)</th>
<th>LangGraph</th>
<th>OpenHarness</th>
<th>nanobot / OpenClaw</th>
<th>learn-claude-code</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>语言/栈</strong></td>
<td>TypeScript monorepo</td>
<td>Python</td>
<td>Python</td>
<td>Python</td>
<td>教程（TypeScript/Node）</td>
</tr>
<tr>
<td><strong>定位</strong></td>
<td>生产级 agent harness（框架）</td>
<td>agent 编排图框架</td>
<td>Claude Code 开源复刻</td>
<td>轻量个人 agent</td>
<td>从零构建 harness 课程</td>
</tr>
<tr>
<td><strong>架构范式</strong></td>
<td>一切皆插件（Cordis）</td>
<td>graph 状态机</td>
<td>引擎 + 43+ 工具 + swarm</td>
<td>轻量 agent loop</td>
<td>渐进式教学</td>
</tr>
<tr>
<td><strong>可替换能力</strong></td>
<td>Capability Seam 三角色（接口/实现/工具分包）</td>
<td>节点可换，编排固定</td>
<td>工具/权限/后端可配</td>
<td>有限</td>
<td>—</td>
</tr>
<tr>
<td><strong>会话模型</strong></td>
<td>事件溯源 SessionEvent log（可重放/可压缩）</td>
<td>checkpoint + state</td>
<td>对话历史 + auto-compaction</td>
<td>会话历史</td>
<td>简单历史</td>
</tr>
<tr>
<td><strong>上下文压缩</strong></td>
<td>surface replace（无模型重写日志）</td>
<td>summarization 节点</td>
<td>auto-compaction</td>
<td>有</td>
<td>教学</td>
</tr>
<tr>
<td><strong>执行后端</strong></td>
<td>bash-local / bash-sandbox / pwsh / E2B 远程</td>
<td>自定</td>
<td>subprocess / tmux / in-process</td>
<td>本地</td>
<td>本地</td>
</tr>
<tr>
<td><strong>模型适配</strong></td>
<td>插件注册表（deepseek / pi-ai / replay）</td>
<td>多 provider</td>
<td>多 provider</td>
<td>本地小型 LLM</td>
<td>教学</td>
</tr>
<tr>
<td><strong>多 agent</strong></td>
<td>subagent seam（6 provider：in-process/acp/codex/claude-code/dsk-sdk）</td>
<td>图内多节点</td>
<td>coordinator + swarm</td>
<td>单 agent 为主</td>
<td>教学</td>
</tr>
<tr>
<td><strong>协议</strong></td>
<td>JSON-RPC SDK / ACP server / Typert RPC</td>
<td>无</td>
<td>MCP 客户端</td>
<td>MCP</td>
<td>教学</td>
</tr>
<tr>
<td><strong>Web UI</strong></td>
<td>有（React client 族）</td>
<td>LangGraph Studio</td>
<td>React TUI</td>
<td>无</td>
<td>—</td>
</tr>
<tr>
<td><strong>License</strong></td>
<td>MIT</td>
<td>MIT</td>
<td>MIT</td>
<td>MIT</td>
<td>—</td>
</tr>
<tr>
<td><strong>成熟度</strong></td>
<td>0.1.0-rc 开发者预览</td>
<td>稳定</td>
<td>v0.1.x</td>
<td>活跃</td>
<td>—</td>
</tr>
</tbody>
</table>
<h2 id="关键差异解读">关键差异解读<a class="anchor" href="#关键差异解读" aria-label="锚点">#</a></h2>
<h3 id="dsh-vs-langgraph图编排-vs-插件运行时">dsh vs LangGraph（图编排 vs 插件运行时）<a class="anchor" href="#dsh-vs-langgraph图编排-vs-插件运行时" aria-label="锚点">#</a></h3>
<ul>
<li>LangGraph 把 agent 工作流建模为 <strong>graph 状态机</strong>（节点 = 工具/LLM/子图），显式编排</li>
<li>dsh 不规定图：核心是<strong>事件溯源会话 + 可替换能力 + 插件运行时</strong>，工作流只是可挂载的插件（workflow seam），loop 本身也是插件</li>
<li>启示：图的显式性适合可预测流程；插件运行时的灵活性适合&quot;agent 即操作系统&quot;的产品形态</li>
</ul>
<h3 id="dsh-vs-openharness框架-vs-复刻">dsh vs OpenHarness（框架 vs 复刻）<a class="anchor" href="#dsh-vs-openharness框架-vs-复刻" aria-label="锚点">#</a></h3>
<ul>
<li>OpenHarness 是 Claude Code 的<strong>行为复刻</strong>（engine + tools + permissions + hooks + swarm），API 形状学 Claude Code</li>
<li>dsh 是<strong>通用框架</strong>，甚至可以把 Claude Code/Codex 桥接进来（hooks-claude-code / hooks-codex）</li>
<li>dsh 的 capability seam 允许一个 harness 承载不同 agent 产品；OpenHarness 目标是&quot;像 Claude Code 的开源替代&quot;</li>
</ul>
<h3 id="dsh-vs-nanobot-openclaw重-vs-轻">dsh vs nanobot / OpenClaw（重 vs 轻）<a class="anchor" href="#dsh-vs-nanobot-openclaw重-vs-轻" aria-label="锚点">#</a></h3>
<ul>
<li>nanobot/OpenClaw 追求超轻量个人 agent（本地模型、简单 loop、快速上手）</li>
<li>dsh 是生产级规模（~130+ 包、事件溯源、沙箱、双语文档、1372 Agent Notes）—— 学习成本高，但架构决策密度极高</li>
</ul>
<h2 id="verdict">Verdict<a class="anchor" href="#verdict" aria-label="锚点">#</a></h2>
<p>对 <strong>Agentic System Designer</strong> 职业路径：</p>
<ul>
<li>想快速做个人 agent → nanobot / OpenClaw 路线</li>
<li>想理解 Claude Code 产品形态 → OpenHarness / learn-claude-code</li>
<li>想学<strong>生产级 harness 架构</strong>（事件溯源、capability seam、插件运行时、Host/Client 双面 TS 工程）→ <strong>DeepSeek Harness 是目前最完整的开源参考</strong>，且是唯一国内顶级大厂开源的同类项目</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Ling (灵)</title>
      <link>https://www.lj-yg.cn/posts/ling-lang/</link>
      <guid isPermaLink="true">https://www.lj-yg.cn/posts/ling-lang/</guid>
      <pubDate>Thu, 18 Jun 2026 00:00:00 +0800</pubDate>
      <description>Ling（灵）：AI 优先、中英双语的编程语言——codemap（LCN）是 canonical IR、源码只是它的投影，MCP/LSP 是 AI 入口。v0.0.6，27 条 ADR 已锁定。</description>
      <content:encoded><![CDATA[<blockquote>
<p><strong>AI 优先、人类其次。</strong> Ling is an AI-first, Chinese-English
bilingual programming language. The codemap (LCN — Ling Canonical
Notation) is the canonical IR; source code is a projection of it.
Built by the wiki maintainer (<code>jiangh_hnr</code> on gitcode).</p>
</blockquote>
<ul>
<li><strong>Repo:</strong> <code>git@gitcode.com:jiangh_hnr/ling-lang.git</code></li>
<li><strong>Version (this clone):</strong> v0.0.6 (Cargo.toml; effect-system milestone)</li>
<li><strong>License:</strong> MIT</li>
<li><strong>Status:</strong> experimental, pre-1.0 — design phase complete (27 ADRs
locked), implementation in progress (v0.0.6 = effect-system baseline)</li>
<li><strong>Web:</strong> https://ling-lang.dev</li>
<li><strong>Implementation:</strong> Rust 2021, targeting LLVM 20</li>
<li><strong>Install (AI-first):</strong> <code>curl -sSL https://ling-lang.dev/install | sh</code>
— daemon runs in background, MCP auto-registered</li>
<li><strong>Install (Rust dev):</strong> <code>git clone ... &amp;&amp; cargo install ling</code></li>
</ul>
<h2 id="what-it-is">What It Is<a class="anchor" href="#what-it-is" aria-label="锚点">#</a></h2>
<p>Ling is a programming language designed so that <strong>AI agents are the
primary authors and readers of source code</strong>; humans are reviewers.
Three commitments follow from this:</p>
<ol>
<li><strong>AI-first, human-second.</strong> Not a &quot;human-first with AI support&quot; or
&quot;dual first-class&quot; — single-customer choice, with all the design
implications that follow.</li>
<li><strong>Codemap is the canonical IR.</strong> Source code is a projection of
codemap, not the other way around. Codemap is bidirectional
(code → codemap, codemap → code), regenerable, schema-enforced,
and gitignored (derived, like <code>target/</code>).</li>
<li><strong>AI consumes codemap via MCP/LSP tools</strong>, not by direct file I/O.
The <code>.lcn</code> files are a serialization target, not the primary AI
interface (ADR 0027).</li>
</ol>
<p>The most distinctive feature compared to other AI-first languages
(see <a href="/posts/zerolang/">Zerolang</a>): Ling's canonical IR is <strong>document-shaped</strong>
(LCN, S-expression, with structured + narrative fields), whereas
Zerolang's is <strong>graph-shaped</strong> (zero.graph). The choice cascades
through everything: edit surface, MCP/LSP design, human review style.</p>
<h2 id="l1-l4-architecture">L1-L4 Architecture<a class="anchor" href="#l1-l4-architecture" aria-label="锚点">#</a></h2>
<figure class="code" data-lang="text"><pre><code class="language-text">L1 Strategic  Naming / version path / AI-first       0001–0003
L2 Language    Type system / memory / effects / form  0004, 0005, 0012–0015
L2.5 Codemap   LCN format / schema / sync / AI access        0006–0011, 0024–0027
L3 Compiler    Frontend / MIR / error recovery / incremental  0016–0020
L4 Backend     LLVM / Cranelift / wasm / signing              0023
L4 Quality     Test strategy / perf budget / CI gates         0021, 0022
</code></pre></figure>
<p>The 27 ADRs are <strong>immutable</strong> — to reverse, write a new ADR that
supersedes. The <code>.harness/docs/ai-first-checklist.md</code> is a hard-rule
gate on every PR.</p>
<h2 id="the-compiler-pipeline-κγ">The Compiler Pipeline (κᵧ)<a class="anchor" href="#the-compiler-pipeline-κγ" aria-label="锚点">#</a></h2>
<figure class="code" data-lang="text"><pre><code class="language-text">Source (.ling) → Scanner (bilingual, indentation-aware)
              → Tokens (per-line tokenize_line)
              → Parser (indent → S-exp, type/symbol resolution)
              → AST (parse-time, discarded)
              → Codemap extractor
              → Codemap (CANONICAL IR; in-memory + .ling/codemap/;
                         daemon-owned, regenerable, gitignored)
              → MIR derivation (per backend: LLVM, Cranelift, wasm)
              → Backend → artifact (.ll / .o / .wasm / binary)
</code></pre></figure>
<p>This is the <strong>strongest possible form of &quot;codemap is the design
surface&quot;</strong> — the AI consumes exactly what the compiler uses. The
trade-off: codemap schema is the highest-stakes contract in the
project, and implementation effort is higher than traditional
pipelines initially.</p>
<h2 id="lcn-ling-config-notation-s-expression-format">LCN — Ling Config Notation (S-Expression Format)<a class="anchor" href="#lcn-ling-config-notation-s-expression-format" aria-label="锚点">#</a></h2>
<p>Same syntax family as <code>.ling</code> source. Files use <code>.lcn</code> extension. The
same parser handles both (modulo codemap-specific fields). Codemap
fields are both structured (types, signatures, effects, call graph
edges, schema-enforced) and narrative (<code>intent_markdown</code>,
<code>design_notes</code>, <code>examples</code>, CommonMark + extensions).</p>
<figure class="code" data-lang="lcn"><pre><code class="language-lcn">(模块 ling_std.core
  (函数 swap
    (参数 [(a Int) (b Int)])
    (返回 Unit)
    (效应 [])
    (意图 "原地交换两个整数。\n\n**为什么不做泛型**: `swap&lt;T&gt;` 在 v0.0.x 被砍掉,理由是 codemap 暴露了所有 call site,AI 看到 monomorphic 版本足够。")
    (调用方 [sort sort_desc test_swap_basic])
    (示例 [(输入 "a=1, b=2" 输出 "a=2, b=1")])
  )
)
</code></pre></figure>
<p>The narrative <code>意图</code> field is the key differentiator from pure
graph-based IRs (like <a href="/posts/zerolang/">Zerolang</a>'s <code>zero.graph</code>). It lets
designers embed <em>why</em> alongside <em>what</em>, in a way that the codemap
schema can validate structurally while the narrative is freeform.</p>
<h2 id="effect-system-pure-first-short-tag-组合-1">Effect System — Pure-First, Short-Tag (组合 1)<a class="anchor" href="#effect-system-pure-first-short-tag-组合-1" aria-label="锚点">#</a></h2>
<p>Standard short-tag vocabulary: <code>!FS</code>, <code>!Net</code>, <code>!Clock</code>, <code>!Rand</code>,
<code>!Panic</code>, <code>!IO</code> (catch-all), <code>!pure</code> (optional explicit).</p>
<p><strong>Core rules:</strong></p>
<ol>
<li><strong>Default = pure.</strong> No tag = pure. Purity is <em>proven</em> by the
reverse-check pass, not assumed.</li>
<li><strong>Purity is reverse-checked.</strong> For any untagged function, the
compiler scans the body for IO-tagged calls. If found, the
function must be tagged.</li>
<li><strong>IO functions must declare a short tag</strong> from the standard
vocabulary.</li>
<li><strong>Codemap stores the full effect set</strong> for every function.</li>
<li><strong>Effect subtyping:</strong> v0.0.x is equal-or-disjoint; subtyping
rules deferred to v0.1+.</li>
</ol>
<p>The reverse-check is <strong>finite and decidable</strong> — implementable in
~1 week, vs multi-month research for full effect inference.</p>
<h2 id="language-form-ι-integrated-adr-0015">Language Form — ι Integrated (ADR 0015)<a class="anchor" href="#language-form-ι-integrated-adr-0015" aria-label="锚点">#</a></h2>
<p>Visual indentation + internal S-expression. The <code>.ling</code> source is
indentation-sensitive (2-space); the AST and codemap are S-expressions.
One parser family, three views.</p>
<p><strong>Bilingual keywords</strong> are the <strong>same</strong> <code>TokenKind</code> variant — <code>让</code> and
<code>let</code> both map to <code>KwLet</code>. Twelve keyword pairs (模块/module, 函数/fn,
让/let, 可变/mut, 返回/return, 如果/if, 另则/else, 遍历/for, 在/in,
只要/while, 模式 (no English)). This is unique among the AI-first
languages known to the wiki.</p>
<h2 id="daemon-model-adr-0024-hybrid">Daemon Model (ADR 0024) — Hybrid<a class="anchor" href="#daemon-model-adr-0024-hybrid" aria-label="锚点">#</a></h2>
<figure class="code" data-lang="rust"><pre><code class="language-rust"><span class="k">trait</span><span class="w"> </span><span class="n">CodemapBackend</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="k">fn</span><span class="w"> </span><span class="nf">lookup_symbol</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">q</span><span class="p">:</span><span class="w"> </span><span class="kp">&amp;</span><span class="nc">SymbolQuery</span><span class="p">)</span><span class="w"> </span><span class="p">-&gt;</span><span class="w"> </span><span class="nb">Result</span><span class="o">&lt;</span><span class="nb">Vec</span><span class="o">&lt;</span><span class="n">SymbolEntry</span><span class="o">&gt;&gt;</span><span class="p">;</span>
<span class="w">    </span><span class="k">fn</span><span class="w"> </span><span class="nf">query_effects</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">q</span><span class="p">:</span><span class="w"> </span><span class="kp">&amp;</span><span class="nc">EffectQuery</span><span class="p">)</span><span class="w"> </span><span class="p">-&gt;</span><span class="w"> </span><span class="nb">Result</span><span class="o">&lt;</span><span class="nb">Vec</span><span class="o">&lt;</span><span class="n">EffectEntry</span><span class="o">&gt;&gt;</span><span class="p">;</span>
<span class="w">    </span><span class="c1">// ...</span>
<span class="p">}</span>
</code></pre></figure>
<p>Two implementations: <code>DaemonBackend</code> (Unix socket / named pipe to
<code>ling daemon</code>, in-memory codemap) and <code>FileBackend</code> (reads
<code>.ling/codemap/&lt;module&gt;.lcn</code> from disk, no daemon required). Both
return identical <code>Result</code> types; the compiler is unaware of which is
in use. Used in: long-running AI sessions (daemon, fast) vs CI /
fresh dev (file, no daemon).</p>
<h2 id="performance-budget-adr-0022">Performance Budget (ADR 0022)<a class="anchor" href="#performance-budget-adr-0022" aria-label="锚点">#</a></h2>
<table>
<thead>
<tr>
<th>Operation</th>
<th>v0.0.x floor</th>
<th>v0.1+ target</th>
</tr>
</thead>
<tbody>
<tr>
<td>Incremental compile (1 line)</td>
<td>200ms</td>
<td>100ms</td>
</tr>
<tr>
<td>Codemap query</td>
<td>20ms</td>
<td>10ms</td>
</tr>
<tr>
<td>LSP/MCP round-trip</td>
<td>40ms</td>
<td>20ms</td>
</tr>
<tr>
<td>Single file analysis</td>
<td>100ms</td>
<td>50ms</td>
</tr>
<tr>
<td>Daemon startup</td>
<td>1s</td>
<td>500ms</td>
</tr>
<tr>
<td>Cold compile (10k LOC)</td>
<td>20s</td>
<td>10s</td>
</tr>
<tr>
<td>Memory (10k LOC)</td>
<td>200MB</td>
<td>100MB</td>
</tr>
</tbody>
</table>
<h2 id="ai-team-harness-6-reins">AI Team Harness (6 reins)<a class="anchor" href="#ai-team-harness-6-reins" aria-label="锚点">#</a></h2>
<p>The <code>.harness/</code> directory defines a 6-role team with an orchestrator:</p>
<ul>
<li><strong>strategist</strong> — L1 strategic decisions</li>
<li><strong>language-designer</strong> — L2 language-layer ADRs</li>
<li><strong>codemap-architect</strong> — L2.5 codemap ADRs</li>
<li><strong>compiler-engineer</strong> — L3 compiler pipeline</li>
<li><strong>backend-engineer</strong> — L4 backend (LLVM, Cranelift, wasm)</li>
<li><strong>quality-engineer</strong> — L4 quality (tests, perf, CI)</li>
</ul>
<p><code>.harness/docs/ai-first-checklist.md</code> is a hard-rule gate on every
PR. <code>.harness/docs/adr-map.md</code> tracks per-rein ownership of ADR areas.</p>
<h2 id="roadmap">Roadmap<a class="anchor" href="#roadmap" aria-label="锚点">#</a></h2>
<figure class="code" data-lang="text"><pre><code class="language-text">v0.0.1  scanner + parser + codemap LCN renderer          ✅ done
v0.0.2  控制流 (if/else) + let 绑定 + 二元运算 + fib      ✅ done
v0.0.3  for/while/match + list types + 模块导入/导出       ⏳ next
v0.0.4  Option/ADT types + user-defined types
v0.0.5  mut bindings + region inference (区域推导 β)
v0.0.6  效应系统基础 !FS / !Net / !Clock                  ✅ done in Cargo.toml
v0.1.0  完整 type checker / MIR + LLVM 后端 + 泛型 + 可重现构建
v0.2.0  trait + Cranelift 后端
v0.3.0  完整效应 + wasm 后端 + codemap 稳定 schema
v1.0    生产可用: 全后端稳定 + 完整 stdlib + LSP + 包管理
</code></pre></figure>
<p>Note: <code>Cargo.toml</code> is at v0.0.6 and <code>effect-demo.ling</code> references
v0.0.6 with working <code>!FS</code> tags — so the effect-system milestone is
done. README's &quot;v0.0.3 next&quot; status block is slightly stale.</p>
<h2 id="hard-engineering-rules-from-agentsmd">Hard Engineering Rules (from AGENTS.md)<a class="anchor" href="#hard-engineering-rules-from-agentsmd" aria-label="锚点">#</a></h2>
<ul>
<li><strong>No <code>unwrap()</code> / <code>expect()</code></strong> in non-test code — emit a <code>Diagnostic</code> instead.</li>
<li><strong>ADRs are immutable.</strong> Reverse = new ADR that supersedes.</li>
<li><strong>Bilingual keywords</strong> are the same <code>TokenKind</code> variant; one tokenizer.</li>
<li><strong>Indentation-aware parsing</strong> (2-space); <code>split_logical_lines()</code> tracks <code>indent</code> per line.</li>
<li><strong>Per-line tokenization</strong> — <code>tokenize_line()</code> called per logical line.</li>
<li><strong>Parser always returns a <code>Module</code></strong> (never panics). Unrecoverable
sections become <code>Stmt::Invalid</code>; errors accumulate in <code>DiagnosticBag</code>.</li>
<li><strong>No GC, ownership-based memory</strong> via region inference.</li>
<li><strong>AI-first checklist gate</strong> on every PR.</li>
</ul>
<h2 id="key-concepts-each-has-a-wiki-page">Key Concepts (each has a wiki page)<a class="anchor" href="#key-concepts-each-has-a-wiki-page" aria-label="锚点">#</a></h2>
<ul>
<li><strong><a href="/posts/codemap-as-design-surface/">Codemap as Design Surface</a></strong> — the core thesis
(codemap is canonical, source is projection)</li>
<li><strong><a href="/posts/effect-system-pure-first/">Effect System Pure-First</a></strong> — 组合 1 (pure-first +
short-tag + reverse-check)</li>
<li><strong>LCN S-Expression Format</strong> — LCN as codemap
serialization (S-expression, .lcn extension)</li>
</ul>
<h2 id="relationships">Relationships<a class="anchor" href="#relationships" aria-label="锚点">#</a></h2>
<h3 id="direct-comparison">Direct comparison<a class="anchor" href="#direct-comparison" aria-label="锚点">#</a></h3>
<ul>
<li><a href="/posts/ai-first-programming-languages/">AI-First Programming Languages — Ling vs Zerolang vs Others</a> — the comparison
page that pairs this with <a href="/posts/zerolang/">Zerolang</a> and others</li>
</ul>
<h3 id="related-entities">Related entities<a class="anchor" href="#related-entities" aria-label="锚点">#</a></h3>
<ul>
<li><a href="/posts/zerolang/">Zerolang</a> — the other known AI-first programming
language; graph-based IR vs Ling's document-based IR</li>
<li>12-Factor Agents — shares the &quot;AI-first / context-engineering&quot;
posture; Factor 5 (own your context window) is the policy-level cousin
of codemap-as-IR</li>
<li>MCP (Model Context Protocol) — the <em>primary</em> AI access pattern to codemap
(ADR 0027), not just a nice-to-have</li>
<li>pi-coding-agent (archived — moved to entities/) — analogous split (7 tools, 4 modes)
at the agent-harness layer</li>
<li>oh-my-openagent — agent harness with maximum-function-set
<ul>
<li>Hook philosophy; Ling attacks the same problem at the
<em>language layer</em> with a <em>minimum + codemap</em> design</li>
</ul>
</li>
</ul>
<h3 id="related-concepts">Related concepts<a class="anchor" href="#related-concepts" aria-label="锚点">#</a></h3>
<ul>
<li><a href="/posts/codemap-as-design-surface/">Codemap as Design Surface</a></li>
<li><a href="/posts/effect-system-pure-first/">Effect System Pure-First</a></li>
<li>LCN S-Expression Format</li>
<li>agent-loop-architecture — <code>ling query *</code> and MCP tools
implement a narrow agent loop for code authoring</li>
<li>Agent Design Principles — Ling's 6 hard indicators of
safe delegation are first-class design principles</li>
<li>Context Engineering — codemap is context-engineering
at the program level: structured + narrative fields</li>
<li>Graph-Native Programming — Zerolang's cousin thesis</li>
<li>Semantic Patch Editing — Zerolang's edit primitive;
Ling uses MCP tools instead of patch operations</li>
<li>Program Graph Store — Zerolang's program database;
Ling's codemap is document-shaped, not graph-shaped</li>
<li>Projection as Source View — Zerolang's projection model;
Ling's <code>.ling</code> source is also a projection of codemap but the
design is bidirectional (codemap → code is first-class)</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Zerolang</title>
      <link>https://www.lj-yg.cn/posts/zerolang/</link>
      <guid isPermaLink="true">https://www.lj-yg.cn/posts/zerolang/</guid>
      <pubDate>Thu, 18 Jun 2026 00:00:00 +0800</pubDate>
      <description>Zerolang：vercel-labs 的 graph-native &quot;给 agent 用的编程语言&quot;——zero.graph 是程序本体，.0 文件是它的投影，改代码走 zero patch。</description>
      <content:encoded><![CDATA[<blockquote>
<p><strong>The programming language for agents.</strong> Graph-native, by Vercel Labs.
<code>zero.graph</code> is the program. <code>.0</code> files are projections of it. Edit
through <code>zero patch</code>. — <code>vercel-labs/zerolang</code></p>
</blockquote>
<ul>
<li><strong>Repo:</strong> <code>vercel-labs/zerolang</code></li>
<li><strong>Version (this clone):</strong> v0.3.4 (workspace <code>package.json</code>)</li>
<li><strong>License:</strong> Apache-2.0</li>
<li><strong>Status:</strong> experimental, pre-1.0 — &quot;expect breaking changes, rough edges,
and security issues. Run it in isolated workspaces, not against
production systems or sensitive data&quot; (README)</li>
<li><strong>Web:</strong> https://zerolang.ai</li>
<li><strong>Install:</strong> <code>curl -fsSL https://zerolang.ai/install.sh | bash</code></li>
<li><strong>Agent bootstrap:</strong> <code>npx skills add vercel-labs/zerolang</code></li>
</ul>
<h2 id="what-it-is">What It Is<a class="anchor" href="#what-it-is" aria-label="锚点">#</a></h2>
<p>Zerolang is a graph-native programming language <strong>explicitly designed for
agents</strong>. The semantic graph (<code>zero.graph</code>) is the program database; the
agent's normal authoring surface is a set of graph operations
(<code>zero query</code>, <code>zero patch</code>, <code>zero check</code>, <code>zero test</code>, <code>zero run</code>).
<code>.0</code> files exist as human-readable projections — reviewable, bidirectionally
syncable, but <strong>not</strong> the normal agent write surface.</p>
<p>It is, in a precise sense, an attempt to redesign the programming
language itself around the agent's edit surface. The agent no longer
writes text and hopes the compiler accepts it — the agent queries the
graph and submits a <em>checked</em> semantic patch, which the compiler
accepts or rejects before the store is written.</p>
<h2 id="architecture-one-paragraph">Architecture (one-paragraph)<a class="anchor" href="#architecture-one-paragraph" aria-label="锚点">#</a></h2>
<p>A graph-first package contains <code>zero.toml</code> (manifest), <code>zero.graph</code>
(checked binary store, content-hashed), and <code>src/main.0</code> (readable
projection). The normal package compile path is:</p>
<figure class="code" data-lang="text"><pre><code class="language-text">zero.graph → repository graph tables
  → semantic validation → type checking
  → MIR + backend facts → direct codegen → artifact
</code></pre></figure>
<p><code>zero.graph</code> is loaded directly — no parse-first stage on the normal
path. This is the same shape as a parse-first pipeline (lexer → AST →
name resolution → type check → IR → codegen) with fewer stages and a
graph input instead of text.</p>
<p>The 8 native build targets are <code>darwin-arm64</code>, <code>darwin-x64</code>,
<code>linux-arm64</code>, <code>linux-musl-arm64</code>, <code>linux-musl-x64</code>, <code>linux-x64</code>,
<code>win32-arm64.exe</code>, <code>win32-x64.exe</code>. The C-implemented compiler lives
at <code>native/zero-c/</code>; a <code>bin/zero</code> wrapper execs the local native
compiler at <code>.zero/bin/zero</code>.</p>
<h2 id="key-concepts-each-has-a-wiki-page">Key Concepts (each has a wiki page)<a class="anchor" href="#key-concepts-each-has-a-wiki-page" aria-label="锚点">#</a></h2>
<ul>
<li><strong>Graph-Native Programming</strong> — the core thesis:
semantic graph is the program database, not text.</li>
<li><strong>Program Graph Store</strong> — <code>zero.graph</code> as a binary,
content-hashed, shape-validated store with explicit
projection/sync boundary.</li>
<li><strong>Semantic Patch Editing</strong> — checked graph patches
(<code>--expect-graph-hash</code>, <code>--expect</code>, typed ops, <code>replaceFunctionBody</code>,
<code>replaceBlockBody</code>) vs text diffs.</li>
<li><strong>Projection as Source View</strong> — <code>.0</code> files as the
reviewable, bidirectionally-syncable human surface; export /
import / verify-projection / status, content-hash drift detection.</li>
</ul>
<h2 id="cli-surface-graph-first-agent-work">CLI Surface (graph-first agent work)<a class="anchor" href="#cli-surface-graph-first-agent-work" aria-label="锚点">#</a></h2>
<p>Core commands (defaults to current directory):</p>
<figure class="code" data-lang="text"><pre><code class="language-text">zero init [--template cli|package]
zero query [--fn &lt;name&gt;] [--find &lt;substr&gt;] [--refs &lt;name&gt;] [--calls &lt;name&gt;]
zero view --fn &lt;name&gt;
zero patch --op '&lt;op&gt;' | --check-only | --dry-run
zero check
zero test
zero run -- &lt;args&gt;
zero build --emit exe|obj|llvm-ir --target &lt;target&gt; --out &lt;path&gt;
zero diff
zero inspect --json          # node IDs, graph hashes, interfaceFingerprints,
                             # targetToolchains, usedStdlibHelpers,
                             # memoryBudgets, releaseTargetContract
zero size --json
zero mem --json
zero targets --json
zero doctor --json
zero skills [get &lt;name&gt;]     # version-matched bundled skills
zero explain &lt;diagnostic-code&gt;
zero fix --plan
</code></pre></figure>
<p>Patch operations cover surgical in-function edits
(<code>--replace-in-fn &lt;fn&gt; --old &lt;text&gt; --new &lt;text&gt;</code>, Edit semantics) up to
bulk helper creation (<code>upsertFunction ... end</code>) and whole function bodies
(<code>--replace-fn &lt;fn&gt; --body-file -</code> with a heredoc).</p>
<h2 id="the-agent-loop-per-day">The Agent Loop (per day)<a class="anchor" href="#the-agent-loop-per-day" aria-label="锚点">#</a></h2>
<p>For most package work:</p>
<figure class="code" data-lang="sh"><pre><code class="language-sh">zero<span class="w"> </span>query<span class="w">                   </span><span class="c1"># ask the graph for facts</span>
zero<span class="w"> </span>patch<span class="w"> </span>--op<span class="w"> </span><span class="nb">help</span><span class="w">         </span><span class="c1"># discover available operations</span>
zero<span class="w"> </span>patch<span class="w"> </span>--op<span class="w"> </span><span class="s1">'addMain'</span><span class="w">    </span><span class="c1"># checked semantic edit</span>
zero<span class="w"> </span>check
zero<span class="w"> </span><span class="nb">test</span>
zero<span class="w"> </span>run<span class="w"> </span>--<span class="w"> </span>&lt;args&gt;
</code></pre></figure>
<p>When a human wants to review projection text:</p>
<figure class="code" data-lang="sh"><pre><code class="language-sh">zero<span class="w"> </span><span class="nb">export</span>
zero<span class="w"> </span>verify-projection
</code></pre></figure>
<p>When a human intentionally edited a projection:</p>
<figure class="code" data-lang="sh"><pre><code class="language-sh">zero<span class="w"> </span>import
zero<span class="w"> </span>check
</code></pre></figure>
<h2 id="language-surface-highlights">Language Surface (highlights)<a class="anchor" href="#language-surface-highlights" aria-label="锚点">#</a></h2>
<ul>
<li><strong>Functions:</strong> <code>fn add(x: i32, y: i32) -&gt; i32 { return x + y }</code></li>
<li><strong>Fallible functions:</strong> use <code>raises</code> and <code>check</code> — no hidden exceptions<figure class="code" data-lang="zero"><pre><code class="language-zero">fn requirePositive(value: i32) -&gt; i32 raises [Invalid] {
    if value &gt; 0 { return value }
    raise Invalid
}
</code></pre></figure>
</li>
<li><strong>Explicit capabilities:</strong> programs receive capabilities explicitly
(e.g. <code>world: World</code>) — no ambient global runtime access. The
33-module stdlib documents effects and target support per helper.</li>
<li><strong>Blocks as graph nodes:</strong> <code>while</code>, <code>match</code>, <code>if/else</code> all lower to
explicit graph control-flow nodes. Agents can patch a whole function
body or a specific block body
(<code>replaceBlockBody #block_then_1234 ...</code>).</li>
<li><strong>Compile-time facts:</strong> a small metadata surface for target and type
facts (integer/Bool/enum static values, <code>compileTime</code>,
<code>target.pointerWidth</code>, <code>fieldType</code>, <code>hasEnumCase</code>).</li>
<li><strong>Modules:</strong> <code>src/foo.0</code> defines module <code>foo</code>; <code>src/foo/mod.0</code>
defines directory module <code>foo</code>. Import cycles and duplicate
public exports are diagnosed before build output.</li>
</ul>
<p>The 33 stdlib modules are: <code>args</code>, <code>ascii</code>, <code>cli</code>, <code>codec</code>, <code>collections</code>,
<code>crypto</code>, <code>csv</code>, <code>diag</code>, <code>env</code>, <code>fmt</code>, <code>fs</code>, <code>http</code>, <code>inet</code>, <code>io</code>, <code>json</code>,
<code>log</code>, <code>math</code>, <code>mem</code>, <code>net</code>, <code>parse</code>, <code>path</code>, <code>proc</code>, <code>rand</code>, <code>regex</code>,
<code>search</code>, <code>sort</code>, <code>str</code>, <code>testing</code>, <code>text</code>, <code>time</code>, <code>toml</code>, <code>unicode</code>,
<code>url</code>. The <code>stdlib</code> skill is ~39 KB of full signature reference,
including ready-made validators (<code>std.time</code> covers RFC 3339 incl. leap
seconds, <code>std.inet</code> covers IPv4/IPv6/hostname, <code>std.regex</code> is ECMA
subset, <code>std.unicode</code> is strict UTF-8).</p>
<h2 id="runtime-goals-non-negotiable">Runtime Goals (non-negotiable)<a class="anchor" href="#runtime-goals-non-negotiable" aria-label="锚点">#</a></h2>
<p>The graph-first model should reduce agent guessing <strong>without</strong> relaxing:</p>
<ul>
<li>token-efficient inspection</li>
<li>low memory usage</li>
<li>fast startup and builds</li>
<li>low runtime latency</li>
<li>explicit capabilities</li>
<li>small, dependency-free artifacts</li>
</ul>
<p>These are inspectable per-graph-input via <code>zero size --json</code>,
<code>zero mem --json</code>, and the benchmark docs.</p>
<h2 id="version-matched-skills-key-agent-facing-pattern">Version-Matched Skills (key agent-facing pattern)<a class="anchor" href="#version-matched-skills-key-agent-facing-pattern" aria-label="锚点">#</a></h2>
<p>The thin external <code>vercel-labs/zerolang</code> skill is a discovery stub only.
The compiler bundles version-matched skills — fetch each topic at most
once per session (content is fixed for a given binary):</p>
<figure class="code" data-lang="sh"><pre><code class="language-sh">zero<span class="w"> </span>skills
zero<span class="w"> </span>skills<span class="w"> </span>get<span class="w"> </span>agent<span class="w">       </span><span class="c1"># ~4 KB</span>
zero<span class="w"> </span>skills<span class="w"> </span>get<span class="w"> </span>language<span class="w">    </span><span class="c1"># ~6 KB</span>
zero<span class="w"> </span>skills<span class="w"> </span>get<span class="w"> </span>graph<span class="w">       </span><span class="c1"># ~9 KB</span>
zero<span class="w"> </span>skills<span class="w"> </span>get<span class="w"> </span>diagnostics<span class="w"> </span><span class="c1"># ~4 KB</span>
zero<span class="w"> </span>skills<span class="w"> </span>get<span class="w"> </span>packages<span class="w">    </span><span class="c1"># ~5 KB</span>
zero<span class="w"> </span>skills<span class="w"> </span>get<span class="w"> </span>builds<span class="w">      </span><span class="c1"># ~5 KB</span>
zero<span class="w"> </span>skills<span class="w"> </span>get<span class="w"> </span>testing<span class="w">     </span><span class="c1"># ~3 KB</span>
zero<span class="w"> </span>skills<span class="w"> </span>get<span class="w"> </span>stdlib<span class="w">      </span><span class="c1"># ~39 KB</span>
zero<span class="w"> </span>skills<span class="w"> </span>get<span class="w"> </span>stdlib<span class="w"> </span>--topic<span class="w"> </span>std.time<span class="w">   </span><span class="c1"># one section only</span>
</code></pre></figure>
<p>If multiple Zero binaries exist, use the one that will run the project.</p>
<h2 id="things-intentionally-not-hidden">Things Intentionally Not Hidden<a class="anchor" href="#things-intentionally-not-hidden" aria-label="锚点">#</a></h2>
<ul>
<li>hidden method registries</li>
<li>vtables</li>
<li>reflection</li>
<li>ambient heap allocation</li>
<li>process-global cleanup lists</li>
</ul>
<p>When a program uses owned resources, allocator state, hosted I/O, network
capability, or C interop, those facts should be visible through graph
inspection and diagnostics.</p>
<h2 id="boundaries">Boundaries<a class="anchor" href="#boundaries" aria-label="锚点">#</a></h2>
<ul>
<li><strong>Pre-1.0, experimental.</strong> Breaking changes are expected; the
contributor policy (AGENTS.md) says explicitly: &quot;Do not preserve
legacy behavior by default. Prefer the clearer agent-facing design
over compatibility shims, migration layers, or carrying old paths
forward.&quot;</li>
<li><strong>Not for production.</strong> No security audit; isolate in disposable
workspaces.</li>
<li><strong>C-implemented compiler</strong> under <code>native/zero-c/</code> — the agent-facing
CLI is in front of a C backend, not a self-hosted VM.</li>
</ul>
<h2 id="repository-layout-this-clone">Repository Layout (this clone)<a class="anchor" href="#repository-layout-this-clone" aria-label="锚点">#</a></h2>
<figure class="code" data-lang="text"><pre><code class="language-text">zerolang\
├── AGENTS.md           # contributor + safety policy
├── README.md           # the thesis + the daily loop
├── package.json        # v0.3.4, pnpm workspace
├── native/zero-c/      # C-implemented compiler
├── bin/zero            # wrapper → .zero/bin/zero
├── std/                # 33 stdlib modules
├── examples/           # 165 .graph + .0 example pairs
├── docs/articles/      # human-readable reference
│   ├── concepts/{graph-architecture, projections, semantic-vs-text, compile-path}.md
│   ├── modules/        # one .md per stdlib module
│   ├── cli-reference.md
│   ├── language-reference.md
│   ├── primitives.md
│   ├── testing.md
│   ├── package-manifest.md
│   ├── standard-library.md
│   ├── c-interop.md
│   ├── cross-compilation.md
│   ├── diagnostics.md
│   ├── target-capabilities.md
│   ├── optimization.md
│   ├── examples.md
│   ├── learn-zero.md
│   └── install.md, getting-started.md, building-from-source.md, benchmarks.md
├── skills/zero/SKILL.md
├── skill-data/         # 8 version-matched bundled skills
├── extensions/vscode/
├── benchmarks/{rosetta, zero}/
├── evals/
├── conformance/        # ~50 conformance fixtures + agent-surface tests
├── tests/
└── scripts/            # pnpm scripts: agent:checks, conformance, etc.
</code></pre></figure>
<h2 id="relationships">Relationships<a class="anchor" href="#relationships" aria-label="锚点">#</a></h2>
<h3 id="related-entities">Related entities<a class="anchor" href="#related-entities" aria-label="锚点">#</a></h3>
<ul>
<li>Vercel Labs — the organization behind it</li>
<li>12-Factor Agents — shares the &quot;agent-first / context-engineering&quot;
posture; Factor 5 (own your context window) and Factor 13 (pre-fetch vs
ask) are explicit cultural cousins</li>
<li>pi-coding-agent (archived — moved to entities/) — analogous split: 7 tools, 4 modes,
~3,100 LOC AgentSession. Zerolang attacks the same problem at the
<em>language</em> layer instead of the <em>agent harness</em> layer</li>
<li>oh-my-openagent — agent harness with maximum-function-set
<ul>
<li>Hook philosophy; Zerolang is the minimum-surface-language
counterpart (<code>zero patch</code> ops are deliberately narrow)</li>
</ul>
</li>
<li>LangGraph — graphs the <em>agent's</em> state machine. Zerolang
graphs the <em>program being authored</em>. Different layer, same word.</li>
<li>Claude Code — the agent harness that would most naturally
drive a <code>zero patch</code> loop</li>
</ul>
<h3 id="related-concepts">Related concepts<a class="anchor" href="#related-concepts" aria-label="锚点">#</a></h3>
<ul>
<li>Graph-Native Programming — the core thesis</li>
<li>Program Graph Store — <code>zero.graph</code> as a binary store</li>
<li>Semantic Patch Editing — checked graph patches</li>
<li>Projection as Source View — <code>.0</code> files as human review surface</li>
<li>agent-loop-architecture — Zerolang is a <em>narrow</em> agent
loop (<code>query → patch → check/run</code>) for a single domain (code authoring)</li>
<li>Context Engineering — <code>zero query</code> is exactly the
pre-fetch-vs-ask pattern from 12-Factor Factor 13</li>
<li>Agent Design Principles — Zerolang embodies several
principles: tool ergonomics, deterministic inspection/repair, regular
patterns over syntactic convenience</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>AI-First Programming Languages — Ling vs Zerolang vs Others</title>
      <link>https://www.lj-yg.cn/posts/ai-first-programming-languages/</link>
      <guid isPermaLink="true">https://www.lj-yg.cn/posts/ai-first-programming-languages/</guid>
      <pubDate>Thu, 18 Jun 2026 00:00:00 +0800</pubDate>
      <description>把 Ling（灵）与 Zerolang 两门 AI-first 语言放在一起比，再引入 Mojo、Carbon、APL/J/K 系、JetBrains MPS 做参照：AI-first 是孤注一掷还是新趋势。</description>
      <content:encoded><![CDATA[<blockquote>
<p>2026-06 更新。聚焦<strong>两门</strong>已知公开的 AI-first 编程语言设计:
<a href="/posts/ling-lang/">Ling (灵)</a>（灵, v0.0.6, 27 ADRs, codemap-as-design-surface）
和 <a href="/posts/zerolang/">Zerolang</a>（v0.3.4, graph-native, <code>zero patch</code>）。
同时纳入<strong>另外 4 个 PL/PL 设计</strong>做参照（Mojo、Carbon、APL/J/K 系、
JetBrains MPS），看 AI-first 是孤注一掷还是新趋势。</p>
</blockquote>
<h2 id="一句话定位">一句话定位<a class="anchor" href="#一句话定位" aria-label="锚点">#</a></h2>
<table>
<thead>
<tr>
<th>项目</th>
<th>一句话定位</th>
<th>状态</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>灵 (Ling)</strong></td>
<td>AI-first, 中英双语, codemap (LCN S-exp) 是 canonical IR, source 是 projection, MCP/LSP 是 AI 入口</td>
<td>设计锁 (27 ADR), v0.0.6 实现中, Rust+LLVM 20</td>
</tr>
<tr>
<td><strong>Zerolang</strong></td>
<td>AI-first, graph (<code>zero.graph</code>) 是 program database, <code>.0</code> 是 projection, <code>zero patch</code> 是 AI 入口</td>
<td>实验性 v0.3.4, C-impl compiler, vercel-labs</td>
</tr>
<tr>
<td><strong>Mojo</strong></td>
<td>AI-first Python 兼容超集, 强调 ownership + 异构加速 (CPU/GPU/AI 加速器)</td>
<td>早期 (Modular 公司), 不是严格的&quot;AI 作者&quot;而是&quot;AI 友好&quot;</td>
</tr>
<tr>
<td><strong>Carbon</strong></td>
<td>C++ 继任者 (Google), 实验性, 强调 interop + 性能, 不强调 AI-first</td>
<td>实验性, 早期, 设计中</td>
</tr>
<tr>
<td><strong>APL/J/K 系</strong></td>
<td>array-first + 极简原语, 长期被认为&quot;可写性差,人类难,程序紧凑&quot; — 反而对 AI 友好?</td>
<td>成熟但小众</td>
</tr>
<tr>
<td><strong>JetBrains MPS</strong></td>
<td>projectional editing, 文本是 projection, AST 是 source of truth</td>
<td>成熟商业, 不是 AI-first 但结构化相同</td>
</tr>
</tbody>
</table>
<p><strong>重点对比的两门：</strong></p>
<ul>
<li><strong>Ling</strong> 是用户的项目（27 ADRs 锁设计，27 ADRs 不可变）</li>
<li><strong>Zerolang</strong> 是外部项目（v0.3.4, 较成熟但仍未 v1.0）</li>
</ul>
<h2 id="核心范式对比">核心范式对比<a class="anchor" href="#核心范式对比" aria-label="锚点">#</a></h2>
<table>
<thead>
<tr>
<th>维度</th>
<th><strong>Ling (灵)</strong></th>
<th><strong>Zerolang</strong></th>
<th>Mojo</th>
<th>Carbon</th>
<th>APL/J 系</th>
<th>JetBrains MPS</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>核心论断</strong></td>
<td>AI first, human second; codemap 是 canonical IR</td>
<td>AI first; graph 是 program database; text 是 projection</td>
<td>AI/ML 加速, Python 友好</td>
<td>C++ 继任, 性能 + interop</td>
<td>array-first, 极简</td>
<td>projectional editing, 文本是 AST 投影</td>
</tr>
<tr>
<td><strong>Canonical 状态</strong></td>
<td>codemap (LCN, S-exp)</td>
<td>zero.graph (binary graph)</td>
<td>text (.py/.mojo)</td>
<td>text (.carbon)</td>
<td>text</td>
<td>AST (projectional)</td>
</tr>
<tr>
<td><strong>Source 关系</strong></td>
<td>projection of codemap (双向同步)</td>
<td>projection of graph (<code>zero export</code>)</td>
<td>source of truth</td>
<td>source of truth</td>
<td>source of truth</td>
<td>projection of AST</td>
</tr>
<tr>
<td><strong>AI 编辑入口</strong></td>
<td>MCP/LSP tools (<code>ling_query_*</code>)</td>
<td><code>zero patch</code> (typed ops)</td>
<td>n/a (传统文本编辑)</td>
<td>n/a</td>
<td>n/a</td>
<td>projectional editor</td>
</tr>
<tr>
<td><strong>AI 读源</strong></td>
<td>通过 MCP tool, 不读 <code>.lcn</code> 直接 I/O</td>
<td><code>zero query</code> 然后可能读 <code>.0</code></td>
<td>直接读 .py</td>
<td>直接读 .carbon</td>
<td>直接读</td>
<td>直接读 AST (projectional)</td>
</tr>
<tr>
<td><strong>目标用户</strong></td>
<td>AI 主, human 审</td>
<td>AI 主, human 审</td>
<td>人类 ML 工程师 (AI 加速)</td>
<td>系统程序员</td>
<td>数值/金融工程师</td>
<td>DSL 作者</td>
</tr>
<tr>
<td><strong>Bilingual / 国际化</strong></td>
<td>中英双语关键字 (KwLet = <code>让</code> = <code>let</code>)</td>
<td>英语</td>
<td>英语</td>
<td>英语</td>
<td>英语 (Unicode-aware)</td>
<td>n/a</td>
</tr>
</tbody>
</table>
<h2 id="canonical-ir-形态对比">Canonical IR 形态对比<a class="anchor" href="#canonical-ir-形态对比" aria-label="锚点">#</a></h2>
<table>
<thead>
<tr>
<th>维度</th>
<th>Ling codemap (LCN)</th>
<th>Zerolang <code>zero.graph</code></th>
<th>Mojo AST</th>
<th>Carbon AST</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>形态</strong></td>
<td>文档 (S-exp)</td>
<td>图 (binary)</td>
<td>树 (text)</td>
<td>树 (text)</td>
</tr>
<tr>
<td><strong>持久化</strong></td>
<td><code>.ling/codemap/*.lcn</code>, gitignored</td>
<td><code>zero.graph</code>, 仓库内 (graph-first package)</td>
<td>n/a</td>
<td>n/a</td>
</tr>
<tr>
<td><strong>Hash 策略</strong></td>
<td>daemon-owned, regenerable</td>
<td>content-hash (per ADR 0027-aware, content-hash decides drift)</td>
<td>n/a</td>
<td>n/a</td>
</tr>
<tr>
<td><strong>Schema 强制度</strong></td>
<td>强: structured 字段 + narrative 字段</td>
<td>强: shape-validated graph</td>
<td>中: 类型系统</td>
<td>中: 类型系统</td>
</tr>
<tr>
<td><strong>Narrative 字段</strong></td>
<td><strong>一等公民</strong> (<code>意图</code>, <code>示例</code>, <code>设计笔记</code> — CommonMark)</td>
<td><strong>无</strong> (Zerolang 没有意图字段等价物)</td>
<td>无 (注释)</td>
<td>无 (注释)</td>
</tr>
<tr>
<td><strong>可读性 (人类)</strong></td>
<td>中 (S-exp 但要学)</td>
<td>低 (binary)</td>
<td>高 (Python-like)</td>
<td>高 (C++-like)</td>
</tr>
<tr>
<td><strong>可读性 (AI 工具)</strong></td>
<td><strong>低 (MCP-tool 抽象后, AI 不直接读)</strong></td>
<td><strong>中 (<code>zero query</code> 输出文本)</strong></td>
<td>高</td>
<td>高</td>
</tr>
<tr>
<td><strong>修订单向性</strong></td>
<td><strong>双向</strong> (code ↔ codemap 都是一等)</td>
<td>单向 (text 是 projection, 正常通过 <code>zero patch</code> 写 graph)</td>
<td>单向 (text → 一切)</td>
<td>单向</td>
</tr>
</tbody>
</table>
<p><strong>核心差异：</strong></p>
<ul>
<li>Ling 把&quot;design rationale&quot;做成了 codemap 的一等字段 (<code>意图</code>, <code>设计笔记</code>)。AI 看 structured, human 看 narrative。</li>
<li>Zerolang 把所有 metadata 都做成 graph node, 没有&quot;narrative&quot;的等价物。</li>
<li>传统 PL 把所有 design rationale 放在注释里, 不是 schema-enforced。</li>
</ul>
<h2 id="edit-primitive-对比">Edit Primitive 对比<a class="anchor" href="#edit-primitive-对比" aria-label="锚点">#</a></h2>
<table>
<thead>
<tr>
<th>维度</th>
<th><strong>Ling</strong></th>
<th><strong>Zerolang</strong></th>
<th>Mojo</th>
<th>Carbon</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>AI 编辑主路径</strong></td>
<td><code>ling patch</code> → 通过 <code>ling_query_*</code> + source → codemap 提取</td>
<td><code>zero patch --op '&lt;op&gt;'</code> 直接改 graph</td>
<td>直接改 .py 文本</td>
<td>直接改 .carbon 文本</td>
</tr>
<tr>
<td><strong>Edit precondition</strong></td>
<td>reverse-check 效应 (函数层)</td>
<td>graph hash + node hash + field expect</td>
<td>type-check 提交</td>
<td>type-check 提交</td>
</tr>
<tr>
<td><strong>Edit guardrail</strong></td>
<td>&quot;pure-first, IO must tag&quot; (效果在 signature 层可见)</td>
<td><code>--expect-graph-hash</code>, <code>--expect</code> (field-level lock)</td>
<td>无 AI 专用</td>
<td>无 AI 专用</td>
</tr>
<tr>
<td><strong>Bidirectional</strong></td>
<td><strong>是</strong> (codemap → code 也是一等)</td>
<td><strong>否</strong> (text → graph 正常, 反向通过 <code>zero import</code>)</td>
<td>否</td>
<td>否</td>
</tr>
<tr>
<td><strong>Error 信息形式</strong></td>
<td>LCN field (codemap 字段) + diagnostic codes</td>
<td>node IDs + graph hashes (machine-readable)</td>
<td>Python traceback</td>
<td>C++ diagnostic</td>
</tr>
<tr>
<td><strong>AI 读 diff</strong></td>
<td><code>ling review</code> (codemap diff + 设计解释, ADR 0010)</td>
<td><code>zero diff</code> (graph diff)</td>
<td><code>git diff</code></td>
<td><code>git diff</code></td>
</tr>
</tbody>
</table>
<h2 id="类型-安全模型对比">类型 + 安全模型对比<a class="anchor" href="#类型-安全模型对比" aria-label="锚点">#</a></h2>
<table>
<thead>
<tr>
<th>维度</th>
<th><strong>Ling</strong></th>
<th><strong>Zerolang</strong></th>
<th>Mojo</th>
<th>Carbon</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>类型系统</strong></td>
<td>hybrid (explicit preferred, local inference)</td>
<td>static, with <code>raises [Invalid]</code> fallible functions</td>
<td>static, Python-like</td>
<td>static, C++-like</td>
</tr>
<tr>
<td><strong>内存模型</strong></td>
<td>region inference β, no GC, ownership-based</td>
<td>explicit capabilities (<code>world: World</code>), no ambient</td>
<td>ownership (Rust-like)</td>
<td>ownership (C++-like)</td>
</tr>
<tr>
<td><strong>效应 / 副作用</strong></td>
<td><strong>显式 effect tags</strong> (<code>!FS</code>/<code>!Net</code>/<code>!Clock</code>/<code>!Rand</code>/<code>!Panic</code>), pure-first + reverse-check</td>
<td><strong>explicit capabilities</strong> passed as args (no ambient)</td>
<td>无内置效应</td>
<td>无内置效应</td>
</tr>
<tr>
<td><strong>Effect 来源</strong></td>
<td><strong>signature 层</strong> (reviewer 一眼可见)</td>
<td><strong>capability 参数传递</strong> (reviewer 看 main 签名)</td>
<td>无</td>
<td>无</td>
</tr>
<tr>
<td><strong>Effect 实现成本</strong></td>
<td><strong>~1 周</strong> (finite reverse-check)</td>
<td>隐式 (无, 用 capability 替代)</td>
<td>n/a</td>
<td>n/a</td>
</tr>
<tr>
<td><strong>Generics</strong></td>
<td>推迟到 v0.1+ (codemap 暴露 call sites, monomorphic 足够)</td>
<td>已支持, generic types</td>
<td>已支持</td>
<td>已支持</td>
</tr>
<tr>
<td><strong>编译期事实</strong></td>
<td><code>compileTime</code>, <code>target.pointerWidth</code>, <code>fieldType</code>, <code>hasEnumCase</code></td>
<td>同 (MET001 诊断)</td>
<td><code>comptime</code> 强大</td>
<td><code>constexpr</code></td>
</tr>
</tbody>
</table>
<h2 id="performance-budget-ai-视角">Performance Budget (AI 视角)<a class="anchor" href="#performance-budget-ai-视角" aria-label="锚点">#</a></h2>
<p>Ling 给了详细的 AI-场景性能预算 (ADR 0022)。Zerolang 没明说，但有 <code>zero size --json</code>, <code>zero mem --json</code>, benchmark docs。</p>
<table>
<thead>
<tr>
<th>Operation</th>
<th>Ling v0.0.x floor</th>
<th>Ling v0.1+ target</th>
<th>Zerolang 类似</th>
</tr>
</thead>
<tbody>
<tr>
<td>增量编译 (改一行)</td>
<td>200ms</td>
<td>100ms</td>
<td>没说, 但有 <code>--json size/mem</code></td>
</tr>
<tr>
<td>Canonical IR 查询</td>
<td>20ms</td>
<td>10ms</td>
<td><code>zero query</code> &lt;100ms (估计)</td>
</tr>
<tr>
<td>LSP/MCP round-trip</td>
<td>40ms</td>
<td>20ms</td>
<td>n/a (没有 MCP 集成)</td>
</tr>
<tr>
<td>Daemon 启动</td>
<td>1s</td>
<td>500ms</td>
<td>n/a (no daemon)</td>
</tr>
<tr>
<td>冷编译 (10k LOC)</td>
<td>20s</td>
<td>10s</td>
<td>没说</td>
</tr>
<tr>
<td>Memory (10k LOC)</td>
<td>200MB</td>
<td>100MB</td>
<td>binary store, 估计 50-100MB</td>
</tr>
</tbody>
</table>
<p><strong>关键观察：</strong> Ling 把 daemon + MCP round-trip 当作 AI 路径的关键路径指标，Zerolang 不假定 daemon，直接走 <code>zero patch</code> 命令。</p>
<h2 id="daemon-background-process-对比">Daemon / Background Process 对比<a class="anchor" href="#daemon-background-process-对比" aria-label="锚点">#</a></h2>
<table>
<thead>
<tr>
<th>维度</th>
<th><strong>Ling</strong></th>
<th><strong>Zerolang</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Daemon?</strong></td>
<td><strong>是</strong> (<code>ling daemon</code>, ADR 0024 hybrid)</td>
<td><strong>否</strong> (无 daemon)</td>
</tr>
<tr>
<td><strong>Fallback</strong></td>
<td>File-level 读 <code>.ling/codemap/*.lcn</code> (CI/无 daemon 环境)</td>
<td>无, 每次 <code>zero query/patch</code> 都直接走 graph store</td>
</tr>
<tr>
<td><strong>优点</strong></td>
<td>长 session 快 (codemap 在内存, daemon-owned)</td>
<td>简单, 无 IPC, 无 daemon 维护成本</td>
</tr>
<tr>
<td><strong>缺点</strong></td>
<td>多了一个进程要保活, 增加 crash surface</td>
<td>每次 query 重新解析, 长 session 慢</td>
</tr>
<tr>
<td><strong>AI 集成点</strong></td>
<td>daemon host MCP server (per ADR 0024, 0027)</td>
<td><code>zero patch</code> 命令, 通过 tool wrapper 暴露给 AI</td>
</tr>
</tbody>
</table>
<h2 id="ai-工具集成">AI 工具集成<a class="anchor" href="#ai-工具集成" aria-label="锚点">#</a></h2>
<table>
<thead>
<tr>
<th>维度</th>
<th><strong>Ling</strong></th>
<th><strong>Zerolang</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>MCP 集成</strong></td>
<td><strong>核心</strong> (ADR 0027: &quot;AI 通过 MCP/LSP, 不直接读 .lcn&quot;)</td>
<td>没说, 有 <code>zero skills</code> bundled skills</td>
</tr>
<tr>
<td><strong>LSP 集成</strong></td>
<td><strong>核心</strong> (LSP server wraps codemap queries)</td>
<td>没说</td>
</tr>
<tr>
<td><strong>Version-matched skills</strong></td>
<td>n/a (compiler daemon is the canonical source)</td>
<td><strong>是</strong> (<code>zero skills get &lt;topic&gt;</code>, 9 个 bundled skills, ~70 KB)</td>
</tr>
<tr>
<td><strong>Skill 安装</strong></td>
<td><code>ling-install-agent</code> (daemon + MCP 自动注册)</td>
<td><code>npx skills add vercel-labs/zerolang</code> (bootstrap stub)</td>
</tr>
<tr>
<td><strong>AI tool 抽象层</strong></td>
<td>单一 <code>CodemapBackend</code> trait, DaemonBackend + FileBackend 双实现</td>
<td><code>zero query / view / patch / inspect</code> 各自独立命令</td>
</tr>
</tbody>
</table>
<h2 id="何时选哪个">何时选哪个？<a class="anchor" href="#何时选哪个" aria-label="锚点">#</a></h2>
<table>
<thead>
<tr>
<th>场景</th>
<th>推荐</th>
<th>原因</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>AI 是主要作者, human 偶尔审</strong></td>
<td><strong>Ling</strong> 或 <strong>Zerolang</strong></td>
<td>都明确为 AI-first 设计</td>
</tr>
<tr>
<td><strong>需要 design rationale 持久化</strong> (intent, why)</td>
<td><strong>Ling</strong></td>
<td>narrative fields 一等公民, 不是注释</td>
</tr>
<tr>
<td><strong>需要 strict structural edit guarantees</strong> (graph + patch + hash)</td>
<td><strong>Zerolang</strong></td>
<td><code>--expect-graph-hash</code>, <code>--expect</code> field locks</td>
</tr>
<tr>
<td><strong>需要 MCP/LSP 开箱即用</strong></td>
<td><strong>Ling</strong></td>
<td>ADR 0027 把 MCP/LSP 作为 AI 主入口, 优先实现</td>
</tr>
<tr>
<td><strong>需要 Chinese 关键字 / 中英双语</strong></td>
<td><strong>Ling</strong></td>
<td>唯一已知的双语 PL</td>
</tr>
<tr>
<td><strong>需要 region inference / no GC</strong></td>
<td><strong>Ling</strong></td>
<td>明确 v0.0.5 实现 region inference β</td>
</tr>
<tr>
<td><strong>想要 graph 形式 IR (而不是 document)</strong></td>
<td><strong>Zerolang</strong></td>
<td>graph-first 是其显式承诺</td>
</tr>
<tr>
<td><strong>想要简单的、命令式的 agent 编辑 surface</strong></td>
<td><strong>Zerolang</strong></td>
<td>9 个 <code>zero *</code> 命令, 不需要 daemon</td>
</tr>
<tr>
<td><strong>想要 Python 兼容 + AI 加速</strong></td>
<td><strong>Mojo</strong></td>
<td>不是 AI-first, 但 Python 生态</td>
</tr>
<tr>
<td><strong>想要 C++ 继任</strong></td>
<td><strong>Carbon</strong></td>
<td>不是 AI-first, 但 Google 背书</td>
</tr>
</tbody>
</table>
<h2 id="哲学-设计哲学差异">哲学 / 设计哲学差异<a class="anchor" href="#哲学-设计哲学差异" aria-label="锚点">#</a></h2>
<table>
<thead>
<tr>
<th>维度</th>
<th><strong>Ling</strong></th>
<th><strong>Zerolang</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>AI / human 关系</strong></td>
<td>&quot;Let AI write a language that AI finds ergonomic&quot; (ADR 0002)</td>
<td>&quot;Zerolang exists because humans increasingly ask agents to write programs&quot; (README)</td>
</tr>
<tr>
<td><strong>作者本人</strong></td>
<td>中文母语, ADR 大量中文, 中英对照</td>
<td>英文</td>
</tr>
<tr>
<td><strong>设计严肃性</strong></td>
<td>27 个 immutable ADR, 9 个 L1-L4 层, 6-rein harness</td>
<td>4 个核心 doc (graph-architecture, projections, semantic-vs-text, compile-path) + bundled skills</td>
</tr>
<tr>
<td><strong>后端</strong></td>
<td>自研 MIR + LLVM 20 + Cranelift + wasm (planned)</td>
<td>C-impl compiler, 8 个 native target</td>
</tr>
<tr>
<td><strong>目标</strong></td>
<td>v1.0 = &quot;production-ready&quot; 长期</td>
<td>v0.x experimental, 接受 breaking changes</td>
</tr>
<tr>
<td><strong>AI 工具设计</strong></td>
<td>daemon + MCP, 多 tool, daemon 是 host</td>
<td>command-line, agent calls <code>zero patch</code> 一次, 不需要常驻</td>
</tr>
<tr>
<td><strong>安全性</strong></td>
<td>effect reverse-check (pure-first)</td>
<td>capabilities (no ambient global access)</td>
</tr>
<tr>
<td><strong>Reviewer 视角</strong></td>
<td>签名层可见 effect</td>
<td>signature 层可见 capability 参数</td>
</tr>
</tbody>
</table>
<h2 id="共同的设计哲学-与主流-pl-对比">共同的设计哲学 (与主流 PL 对比)<a class="anchor" href="#共同的设计哲学-与主流-pl-对比" aria-label="锚点">#</a></h2>
<p>两门 AI-first PL 都有这些与主流不同的核心点：</p>
<ol>
<li><strong>Canonical IR ≠ text</strong> — 都是&quot;text is a projection&quot;。Zerolang 用 binary graph, Ling 用 LCN document, 但都不是&quot;text 是一等公民&quot;。</li>
<li><strong>AI edit 走显式路径</strong> — Zerolang <code>zero patch</code>, Ling MCP tool。不假定 AI 直接改文本。</li>
<li><strong>Drift 是显式管理的</strong> — Zerolang 用 content-hash 决定 <code>RGP006</code>, Ling 用 daemon-owned codemap 强制 schema 一致。</li>
<li><strong>安全 = reviewer-visible</strong> — Zerolang capabilities, Ling effects, 都是为了让 human reviewer 在签名层就能看到函数能不能 IO。</li>
<li><strong>Schema 强约束</strong> — Zerolang shape-validated graph, Ling structured+narrative fields with enforced schema。</li>
<li><strong>Pre-1.0 experimental</strong> — 都明确说&quot;pre-1.0, expect breaking changes, use in isolated workspaces&quot;。</li>
</ol>
<h2 id="不确定的-待观察">不确定的 / 待观察<a class="anchor" href="#不确定的-待观察" aria-label="锚点">#</a></h2>
<ul>
<li><strong>MCP 集成的成熟度：</strong> Ling 把它作为 critical path, 但 v0.0.6 还没到 LSP/MCP 阶段 (按 roadmap 是 v0.1.0+)。Zerolang 没有 MCP 集成, 但有 <code>zero skills</code> bundled skills 作为 agent knowledge 来源。两种模式哪个更 work, 需要 2026-2027 看实际使用。</li>
<li><strong>Codemap 双向同步的实际可行性：</strong> Ling ADR 0025 说 statement+function 粒度 sync, 但双向同步的 conflict resolution 在真实使用中可能比预期复杂。</li>
<li><strong>Graph vs Document IR 的胜出：</strong> 长期看, agent 是否会偏好 graph (structural queries) 还是 document (narrative queries)? 取决于什么样的 query 最常见。如果 &quot;what does this function mean&quot; 重要, Ling 赢; 如果 &quot;what calls this&quot; 重要, Zerolang 赢。</li>
<li><strong>Effect system vs Capabilities 的胜负：</strong> 两个不同的安全模型, 都在为同一目标 (reviewer-visible side effects) 服务。哪个更 AI-friendly, 需要 2027+ 观察。</li>
</ul>
<h2 id="关键-takeaway">关键 takeaway<a class="anchor" href="#关键-takeaway" aria-label="锚点">#</a></h2>
<ul>
<li><strong>AI-first PL 设计已经分化为两派：graph-based (Zerolang) vs document-based (Ling)。</strong></li>
<li>两种都拒绝&quot;text is source of truth&quot;, 都在 explicit 编辑路径, 都有 reviewer-visible 安全机制。</li>
<li><strong>Ling 的独特优势：</strong> design rationale (narrative fields), 中英双语, MCP/LSP 集成是 critical path。</li>
<li><strong>Zerolang 的独特优势：</strong> graph-based structural guarantees, hash-based drift detection, content-hash 的&quot;哪个 side moved&quot;判断。</li>
<li><strong>两者都不是给&quot;AI 加速&quot;用的 (像 Mojo); 都是&quot;为 AI 作者/读者&quot;重新设计的 PL。</strong></li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Codemap as Design Surface</title>
      <link>https://www.lj-yg.cn/posts/codemap-as-design-surface/</link>
      <guid isPermaLink="true">https://www.lj-yg.cn/posts/codemap-as-design-surface/</guid>
      <pubDate>Thu, 18 Jun 2026 00:00:00 +0800</pubDate>
      <description>如果 codemap 而不是源码才是唯一事实来源：编译器退化为校验器，自描述索引从构建产物变成持续同步的活设计面。</description>
      <content:encoded><![CDATA[<blockquote>
<p><strong>Codemap is the canonical IR. Source code is a projection of codemap.</strong>
Three things flip from the parse-first mainstream.</p>
</blockquote>
<p>The &quot;codemap as design surface&quot; idea, formalized in <strong>ADR 0006</strong> of
<a href="/posts/ling-lang/">Ling (灵)</a>, is the most distinctive commitment in any
AI-first programming language known to the wiki. The original
paradigm shift framing:</p>
<table>
<thead>
<tr>
<th>Old paradigm</th>
<th>New paradigm</th>
</tr>
</thead>
<tbody>
<tr>
<td>Source code is the source of truth</td>
<td><strong>Codemap is the source of truth</strong></td>
</tr>
<tr>
<td>Compiler is the primary interface</td>
<td><strong>Codemap is the primary interface; compiler is the verifier</strong></td>
</tr>
<tr>
<td>Self-describing index is a build artifact</td>
<td><strong>Codemap is the design surface, persisted and live-synced</strong></td>
</tr>
</tbody>
</table>
<p>The author's framing of why:</p>
<blockquote>
<p>&quot;AI Agent 工作流永远都是文档驱动的,所以设计优先显得尤为重要。
Codemap 除了派生、亦可以作为比 Markdown 还好用的 AI 文档。AI 既
可以通过 Codemap 设计代码、可以根据代码派生 Codemap。&quot;</p>
</blockquote>
<h2 id="why-quotdesign-surfacequot-not-just-quotdata-structurequot">Why &quot;design surface&quot;, not just &quot;data structure&quot;<a class="anchor" href="#why-quotdesign-surfacequot-not-just-quotdata-structurequot" aria-label="锚点">#</a></h2>
<p>The codemap is a <strong>design surface</strong>, not just a data structure,
because:</p>
<ul>
<li>It is <strong>the interface AI uses to reason about the program.</strong> A
query like &quot;what functions touch the filesystem?&quot; returns from
codemap, not from the parser + analyzer pipeline.</li>
<li>It carries both <strong>structured</strong> (types, signatures, effects, call
graph edges, schema-enforced) <strong>and narrative</strong> (<code>intent_markdown</code>,
<code>design_notes</code>, <code>examples</code>, CommonMark + extensions) fields.
Narrative is first-class, not a comment.</li>
<li>It is <strong>bidirectional</strong> in the design sense: code → codemap and
codemap → code are both first-class. You can author by editing
source and re-extracting, <em>or</em> by editing codemap and regenerating
source.</li>
</ul>
<h2 id="bidirectional-sync-adr-0006-0025">Bidirectional sync (ADR 0006, 0025)<a class="anchor" href="#bidirectional-sync-adr-0006-0025" aria-label="锚点">#</a></h2>
<ul>
<li><strong>code → codemap:</strong> Continuous extraction (codemap is synced as
source edits happen; v0.0.4+ adds a daemon that keeps codemap
in-memory)</li>
<li><strong>codemap → code:</strong> AI or human edits codemap; source is
regenerated</li>
<li>Both directions are first-class</li>
</ul>
<p>Sync granularity is <strong>statement + function</strong> level (ADR 0025) —
invisible to the AI; AI just sees consistent codemap.</p>
<h2 id="the-quotstructured-narrativequot-split">The &quot;structured + narrative&quot; split<a class="anchor" href="#the-quotstructured-narrativequot-split" aria-label="锚点">#</a></h2>
<figure class="code" data-lang="text"><pre><code class="language-text">(function_entry
  ; structured (schema-enforced)
  (name "swap")
  (params [(a Int) (b Int)])
  (return Unit)
  (effects [])

  ; narrative (CommonMark + extensions)
  (意图 "原地交换两个整数。\n\n**为什么不做泛型**: `swap&lt;T&gt;` 在 v0.0.x 被砍掉,理由是 codemap 暴露了所有 call site,AI 看到 monomorphic 版本足够。")
  (示例 [(输入 "a=1, b=2" 输出 "a=2, b=1")])
)
</code></pre></figure>
<p>This is the key differentiator from a pure graph-based IR like
Program Graph Store (Zerolang's <code>zero.graph</code>). The
narrative fields let designers embed <em>why</em> alongside <em>what</em> — in a
way that the codemap schema validates structurally while the
narrative is freeform. The example above is from ADR 0007.</p>
<h2 id="ai-access-pattern-adr-0027-mcplsp-not-direct-file-io">AI access pattern (ADR 0027) — MCP/LSP, not direct file I/O<a class="anchor" href="#ai-access-pattern-adr-0027-mcplsp-not-direct-file-io" aria-label="锚点">#</a></h2>
<p>A later clarification (ADR 0027) re-framed how AI agents interact
with codemap. The original framing in ADR 0006 was &quot;AI reads
codemap.&quot; The clarification:</p>
<blockquote>
<p>&quot;AI Agent 对 Codemap 写法并不一定非要学习,因为我们定义了工具链
MCP/LSP,可以通过 tools 直接给 AI 查询/编辑。AI 仅在设计阶段
可通过 Codemap 写设计。&quot;</p>
</blockquote>
<p><strong>The primary AI access pattern is via MCP/LSP tools</strong>, not by
direct <code>.lcn</code> file I/O. Concretely:</p>
<table>
<thead>
<tr>
<th>Phase</th>
<th>How AI reads codemap</th>
<th>How AI writes codemap</th>
</tr>
</thead>
<tbody>
<tr>
<td>Design proposal</td>
<td>direct file I/O on <code>.lcn</code> (proposals graduate to ADRs)</td>
<td>direct file I/O (rare)</td>
</tr>
<tr>
<td>Normal coding</td>
<td><code>ling_query_types</code>, <code>ling_query_effects</code>, <code>ling_query_callers</code>, <code>ling_review_diff</code></td>
<td>goes through source → codemap extraction pipeline</td>
</tr>
<tr>
<td>Review</td>
<td><code>ling_review</code> renders codemap diff + design explanation</td>
<td>(read-only)</td>
</tr>
</tbody>
</table>
<p>The implication: <strong>build great MCP tools, not pretty <code>.lcn</code> readers.</strong>
This is why MCP (MCP (Model Context Protocol)) is a critical-path implementation
for Ling, not a nice-to-have.</p>
<h2 id="relationship-to-graph-native-programming">Relationship to Graph-Native Programming<a class="anchor" href="#relationship-to-graph-native-programming" aria-label="锚点">#</a></h2>
<p>Both Ling and <a href="/posts/zerolang/">Zerolang</a> agree on the &quot;canonical IR&quot; idea;
they disagree on the shape of that IR and on the edit surface.</p>
<table>
<thead>
<tr>
<th>Dimension</th>
<th><a href="/posts/zerolang/">Zerolang</a> (graph-native)</th>
<th>Ling (codemap)</th>
</tr>
</thead>
<tbody>
<tr>
<td>Canonical IR</td>
<td><code>zero.graph</code> (binary, graph)</td>
<td>codemap (LCN, S-expression, document-shaped)</td>
</tr>
<tr>
<td>Edit surface</td>
<td><code>zero patch</code> (typed ops + preconditions)</td>
<td>MCP/LSP tools (<code>ling_query_*</code>, <code>ling_review_diff</code>)</td>
</tr>
<tr>
<td>Source projection</td>
<td><code>.0</code> file (text, export on demand)</td>
<td><code>.ling</code> file (always present, bidirectional)</td>
</tr>
<tr>
<td>IR persistence</td>
<td>binary, content-hashed, in-store</td>
<td>LCN text files, gitignored, daemon-owned</td>
</tr>
<tr>
<td>Human review style</td>
<td>text projection diff</td>
<td>codemap diff with design rationale (ADR 0010)</td>
</tr>
<tr>
<td>Narrative fields</td>
<td>none (no <code>intent_markdown</code> analogue)</td>
<td>first-class</td>
</tr>
<tr>
<td>Bilingual keywords</td>
<td>no (English only)</td>
<td>yes (Chinese ↔ English, same <code>TokenKind</code>)</td>
</tr>
</tbody>
</table>
<p>The shape choice cascades through everything. Graph IR is good for
<strong>structural queries</strong> (&quot;what calls <code>write</code>?&quot;); document IR is good
for <strong>structural + narrative queries</strong> (&quot;what does <code>swap</code> <em>mean</em> and
why was generics deferred?&quot;).</p>
<h2 id="what-this-enables-ling-side">What this enables (Ling-side)<a class="anchor" href="#what-this-enables-ling-side" aria-label="锚点">#</a></h2>
<ul>
<li><strong>MCP/LSP become thin shells over codemap queries</strong> (ADR 0016) —
no separate query engine, no two-truths problem</li>
<li><strong>AI tool results match compiler-internal results byte-for-byte</strong> —
single source of truth</li>
<li><strong>Repository stays source-dominated</strong> (codemap gitignored) — like
<code>target/</code> in Rust</li>
<li><strong>Codemap review = compiler-internal review</strong> — humans and AI see
the same data</li>
<li><strong>Reproducible builds</strong> (ADR 0023) — any agent with source can
derive identical codemap</li>
</ul>
<h2 id="what-this-costs">What this costs<a class="anchor" href="#what-this-costs" aria-label="锚点">#</a></h2>
<ul>
<li><strong>Codemap schema becomes the highest-stakes contract in the
project.</strong> If codemap has a bug, every downstream stage is
affected. Mitigation: codemap is regenerable from source; <code>ling codemap rebuild</code> recovers.</li>
<li><strong>Implementation effort higher than traditional pipelines
initially.</strong> One-time investment; long-term benefit (shared data
structure).</li>
<li><strong>All &quot;compiler internals&quot; thinking is now &quot;codemap thinking&quot;</strong> —
requires team upskilling.</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Effect System Pure-First</title>
      <link>https://www.lj-yg.cn/posts/effect-system-pure-first/</link>
      <guid isPermaLink="true">https://www.lj-yg.cn/posts/effect-system-pure-first/</guid>
      <pubDate>Thu, 18 Jun 2026 00:00:00 +0800</pubDate>
      <description>默认纯函数、副作用必须打标签的 effect system——让 review AI 代码的人只看函数签名就知道哪些调用有副作用。</description>
      <content:encoded><![CDATA[<blockquote>
<p><strong>Default = pure. IO must be tagged. Purity is proven, not assumed.</strong></p>
</blockquote>
<p>The &quot;pure-first, short-tag&quot; effect system (formalized in <strong>ADR 0013
组合 1</strong> of <a href="/posts/ling-lang/">Ling (灵)</a>) is one of the most pragmatic
effect-system designs known to the wiki. It satisfies the L1
&quot;safe delegation&quot; requirement (humans reviewing AI code can see, at
the signature level, which functions have which side effects) without
the verbosity of fully-explicit effect sets or the implementation
risk of full effect inference.</p>
<h2 id="why-an-effect-system-at-all">Why an effect system at all<a class="anchor" href="#why-an-effect-system-at-all" aria-label="锚点">#</a></h2>
<p>Per ADR 0002 (L1 strategic layer), the &quot;safe delegation&quot; hard
indicator #5 is <strong>explicit side effects</strong>, mandatory at v0.1. This
means: when an AI writes a function, the human reviewer must be able
to see, at the signature, which functions are pure and which touch
state. A function that &quot;looks pure&quot; but secretly reads the network
is a safety violation.</p>
<h2 id="the-four-design-candidates-considered">The four design candidates considered<a class="anchor" href="#the-four-design-candidates-considered" aria-label="锚点">#</a></h2>
<table>
<thead>
<tr>
<th>Candidate</th>
<th>Description</th>
<th>Verdict</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>γₐ</strong></td>
<td>Koka-style fully explicit effect sets in every signature</td>
<td>Rejected: too verbose for the 70-80% pure case</td>
</tr>
<tr>
<td><strong>γᵦ</strong></td>
<td>Short tags (<code>!FS</code>, <code>!Net</code>) in source, full set in codemap</td>
<td>Rejected: must reverse-check anyway; why not make purity the default?</td>
</tr>
<tr>
<td><strong>γᵧ</strong></td>
<td>Implicit, compiler infers effect set</td>
<td>Rejected: implementation risk is research-level (multi-month)</td>
</tr>
<tr>
<td><strong>组合 1</strong></td>
<td>Pure-first, short-tag fallback: default is pure, IO must be tagged, compiler reverse-checks purity</td>
<td><strong>Selected</strong></td>
</tr>
<tr>
<td>组合 2</td>
<td>Every function must explicitly tag including <code>!pure</code></td>
<td>Rejected: adds noise to the most common case</td>
</tr>
<tr>
<td>组合 3</td>
<td>Compiler infers, AI/human can override with explicit tag</td>
<td>Rejected: inference is the same risk as γᵧ</td>
</tr>
</tbody>
</table>
<h2 id="core-rules">Core rules<a class="anchor" href="#core-rules" aria-label="锚点">#</a></h2>
<ol>
<li><strong>Default = pure.</strong> A function with no effect annotation is treated
as pure. Purity is <em>proven</em>, not assumed.</li>
<li><strong>Purity is reverse-checked.</strong> For any function without an effect
tag, the compiler scans the function body for any IO-tagged call.
If found, the function must be tagged with that effect.</li>
<li><strong>IO functions must declare a short tag</strong> drawn from the standard
effect vocabulary.</li>
<li><strong>Codemap stores the full effect set</strong> for every function
(inferred, declared, or proven).</li>
<li><strong>Effect subtyping:</strong> for v0.0.x, effects are equal-or-disjoint
(no automatic subtyping). Subtyping rules can be added in v0.1+.</li>
</ol>
<h2 id="standard-short-tag-vocabulary">Standard short-tag vocabulary<a class="anchor" href="#standard-short-tag-vocabulary" aria-label="锚点">#</a></h2>
<table>
<thead>
<tr>
<th>Tag</th>
<th>Meaning</th>
<th>Examples</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>!FS</code></td>
<td>File system</td>
<td>file_read, file_write, stat, mkdir</td>
</tr>
<tr>
<td><code>!Net</code></td>
<td>Network</td>
<td>http_get, socket_*, dns</td>
</tr>
<tr>
<td><code>!Clock</code></td>
<td>System clock / time</td>
<td>now, sleep</td>
</tr>
<tr>
<td><code>!Rand</code></td>
<td>Randomness</td>
<td>random_int, uuid</td>
</tr>
<tr>
<td><code>!Panic</code></td>
<td>Can panic</td>
<td>assert, divide-by-zero</td>
</tr>
<tr>
<td><code>!IO</code></td>
<td>Catch-all (discouraged)</td>
<td>only when truly needed</td>
</tr>
<tr>
<td><code>!pure</code></td>
<td>Optional explicit purity (same as no tag)</td>
<td>style choice</td>
</tr>
</tbody>
</table>
<p>Multiple tags: <code>!FS,!Clock</code> (comma-separated). For v0.0.x, max 3-4
tags; complex effect combinations get explicit sets in v0.1+.</p>
<h2 id="concrete-examples">Concrete examples<a class="anchor" href="#concrete-examples" aria-label="锚点">#</a></h2>
<figure class="code" data-lang="ling"><pre><code class="language-ling">;; Pure: no tag, no IO inside
(函数 square [x: Int] -&gt; Int = {
  (返回 (* x x))
})

;; IO: tag required
(函数 read_file [path: String] -&gt; String !FS = {
  (返回 (io_read path))
})

;; ERROR: tagged !FS but calls network operation
(函数 sneaky [url: String] -&gt; String !FS = {
  (返回 (http_get url))
})
;; compiler error:
;;   error: function `sneaky` declared `!FS` but calls `http_get` (effect: Net)
;;   note: declare as `!FS,!Net` or remove the call

;; Multiple effects
(函数 load_config [path: String] -&gt; Config !FS,!Clock = {
  (让 stats (file_stat path))    ;; !FS
  (返回 (Config (file_read path) (now)))  ;; !FS, !Clock
})
</code></pre></figure>
<h2 id="the-reverse-check-algorithm">The reverse-check algorithm<a class="anchor" href="#the-reverse-check-algorithm" aria-label="锚点">#</a></h2>
<figure class="code" data-lang="text"><pre><code class="language-text">reverse_check(f):
  for each call site c in f's body:
    let callee = codemap.lookup(c)
    if callee.effects.is_nonempty():
      error: f is implicitly pure but calls {callee.name}
             which has effects {callee.effects}
  if no error: f.effects = {}
</code></pre></figure>
<p>This is a <strong>finite, decidable</strong> check — the function body is finite,
the codemap is finite. No inference involved; just lookup. The
implementation is ~1 week of work vs the multi-month research of
full effect inference.</p>
<h2 id="why-组合-1-wins-on-ai-ergonomics">Why 组合 1 wins on AI ergonomics<a class="anchor" href="#why-组合-1-wins-on-ai-ergonomics" aria-label="锚点">#</a></h2>
<ul>
<li><strong>Most functions are pure; not having to tag them removes noise.</strong>
Pure functions are the 70-80% case; the cost of <code>!pure</code> everywhere
is real.</li>
<li><strong>AI doesn't need to remember to add <code>!pure</code>.</strong> It just leaves the
tag off.</li>
<li><strong>Reverse-check ensures it's not laziness.</strong> If a function is
implicitly pure, the compiler proves it. There's no way to
&quot;forget&quot; an effect tag without the compiler catching it.</li>
<li><strong>Codemap always carries the full effect set for queries, review,
and AI reasoning.</strong> Structured field, schema-enforced.</li>
<li><strong>Composability:</strong> reverse-check + codemap gives a complete effect
flow graph.</li>
</ul>
<h2 id="the-costs-with-mitigations">The costs (with mitigations)<a class="anchor" href="#the-costs-with-mitigations" aria-label="锚点">#</a></h2>
<table>
<thead>
<tr>
<th>Cost</th>
<th>Severity</th>
<th>Mitigation</th>
</tr>
</thead>
<tbody>
<tr>
<td>Reverse-check requires codemap at compile time</td>
<td>Low</td>
<td>Already in scope (codemap-as-IR); trivial integration</td>
</tr>
<tr>
<td>Short-tag vocabulary is fixed (no custom effects in v0.0.x)</td>
<td>Medium</td>
<td>Custom effects (user-defined tags) deferred to v0.1+</td>
</tr>
<tr>
<td>Effect subtyping is &quot;equal-or-disjoint&quot; in v0.0.x</td>
<td>Medium</td>
<td><code>pure ⊆ {FS}</code> is not allowed in v0.0.x; explicit cast or full annotation. Subtyping added v0.1+.</td>
</tr>
<tr>
<td>AI may forget to tag a function with a new effect type it introduces</td>
<td>Low</td>
<td>Reverse-check catches it; error message suggests the fix</td>
</tr>
<tr>
<td>Effect tags scattered across many small functions could clutter</td>
<td>Low</td>
<td>v0.0.x will measure; if it's a problem, consider namespace-level effect grouping</td>
</tr>
</tbody>
</table>
<h2 id="implementation-phases">Implementation phases<a class="anchor" href="#implementation-phases" aria-label="锚点">#</a></h2>
<ul>
<li><strong>v0.0.6</strong> — Effect tag parser, standard vocabulary, reverse-check
pass, codemap records effect sets (✅ done in this clone)</li>
<li><strong>v0.1.0</strong> — Effect subtyping (<code>pure ⊆ {FS}</code>), custom effect tags</li>
<li><strong>v0.2.0</strong> — Effect polymorphism (when generics are introduced)</li>
</ul>
<h2 id="codemap-integration">Codemap integration<a class="anchor" href="#codemap-integration" aria-label="锚点">#</a></h2>
<ul>
<li>Every function has an <code>effects</code> field in codemap (empty list for pure)</li>
<li>AI queries: <code>ling query effects !FS</code> returns all functions touching the filesystem</li>
<li>AI queries: <code>ling query pure</code> returns all pure functions</li>
<li>Codemap diffs (per ADR 0010) show effect changes prominently</li>
</ul>
<h2 id="comparison-to-other-effect-systems">Comparison to other effect systems<a class="anchor" href="#comparison-to-other-effect-systems" aria-label="锚点">#</a></h2>
<table>
<thead>
<tr>
<th>System</th>
<th>Design</th>
<th>AI cost</th>
<th>Implementation cost</th>
</tr>
</thead>
<tbody>
<tr>
<td>Koka</td>
<td>fully explicit effect sets</td>
<td>high (verbose)</td>
<td>medium</td>
</tr>
<tr>
<td>Eff/Cyclone (research)</td>
<td>row-polymorphism, full inference</td>
<td>low</td>
<td>research-level (multi-year)</td>
</tr>
<tr>
<td>Rust <code>unsafe</code></td>
<td>blocks, not function-level</td>
<td>medium</td>
<td>done</td>
</tr>
<tr>
<td>Zig <code>comptime</code></td>
<td>compile-time, no function-level effects</td>
<td>low</td>
<td>done</td>
</tr>
<tr>
<td><strong>Ling 组合 1</strong></td>
<td>pure-first, short-tag, reverse-check</td>
<td><strong>low</strong> (default = pure)</td>
<td><strong>low</strong> (~1 week)</td>
</tr>
</tbody>
</table>
<p>The Ling design is the most pragmatic of these: low AI cost, low
implementation cost, and the safety guarantee is <em>stronger</em> than
&quot;trusted declaration&quot; because purity is <em>proven</em>.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
