背景 🍅
Agent Skills 已经悄悄取代提示词,成为 Agent 开发的主流组织单元。背后起作用的是它的两个特性:一是渐进式披露,skill 占用的上下文开销和任务实际用到的部分成正比;二是可手工编辑,人始终留在创作环节里。一份 SKILL.md 加上几个配套脚本,就能把领域知识、工作流约定和工具调用习惯打包成可分发的资产。GitHub 上如今各式 skills 琳琅满目,就是这股热情的直接结果。
热潮之下有一种典型的失败场景:你从 GitHub 拉下来一个星标很高的 skill,本地一跑,效果和 README 里写的相去甚远。你一头雾水,一个 skill 里明明没多少可出错的东西,为什么就是复现不了?这多半不是 skill 写得差,而是作者当时用的模型和你手里的不一致,或者作者是挂着 OpenClaw 开发的,而你用的是 Hermes Agent。同一个 skill,让原作者如虎添翼,到你这里却聊胜于无。
这不是偶然,而是结构性的问题,可以拆成三层来看:
- 不同 LLM 的训练过程差异很大,能力侧重各不相同,在代码生成、指令遵从、工具调用、长链路推理这些方向上分布并不均匀,各有强项也各有盲区;
- 不同 Agent Harness 在工具集合、沙箱契约、上下文管理、错误回传协议上各有一套自己的模式;
- skill 自身依赖的运行环境(Python 包、CLI 工具、环境变量等),决定了它名义上的能力实际能兑现几成。
把别人的 skill 原封不动搬到自己机器上,等于假装模型与环境之间不存在任何差异。在这篇工作之前,可移植性从来没有被当作 skill 应该具备的属性。SkVM 把它变成了一等问题:skill 不是一段对模型说的提示词文本,而是一个需要面向异构的 LLM-Harness 目标平台去编译、去优化的程序。围绕这个视角,SkVM 搭出了一整套面向 LLM Skills 的编译器与运行时系统。
一则类比 🍅
为什么编译并运行 skills 这件事,能和虚拟机搭上关系?要理解这个比喻的深度,得回头看一段更久远的工程史。
七十年代到九十年代之间,硬件架构更新得极快,几乎每几年就冒出一种新的。同一段 C 代码,落在 VAX、SPARC、x86 这些不同的处理器上,要想跑出像样的性能,几乎都得重新选指令、重新排寄存器、重新对齐内存访问。最后收敛下来的解法只有两种:一条是静态编译的路,编译器在编译期把源码翻译成目标处理器最合适的机器码;另一条是虚拟机的路,先把源码降到一份与硬件无关的中间表示(IR/字节码),再由 VM 在运行期把它即时翻译成当前平台的机器指令。手段不同,本质是同一个动作:在源和目标中间塞一层抽象,让硬件差异被吸收掉,而不是漏到上层。
SkVM 的设计就是这条思路的同构搬运。可以做这样的对齐:
| 经典编译/VM 世界 | SkVM 世界 |
| 源代码 | Skill(SKILL.md 与附属脚本、资源) |
| 目标硬件 | 某个 LLM 与某个 Agent Harness 的组合 |
| ISA / ABI | 26 条 Primitive 原语 |
| Profiler / 性能计数器 | Profiler 产出的 Target Capability Profile(TCP) |
| AOT 编译器 | 三遍 Pass 的 AOT Compiler |
| JIT | JIT-Boost(热路径固化)与 JIT-Optimize(内容自改) |
SkVM 里每一个组件都能在体系结构教科书里找到对位,这个映射经得起推敲,不是装饰性的修辞。一旦接受“LLM 是一台带着自然语言 ISA 的奇怪处理器“这个设定,编译器和虚拟机几十年攒下的经验教训,连同它们踩过的坑,就都可以拿来复用。
最见功力的设计决定,是 ISA 放在哪。ISA 之所以成为体系结构里最关键的一层,是因为它充当了可移植与高效之间的契约,SkVM 看到了这一点。它把 26 条原语放在了同样的位置:skill 作者面向原语去写,而 26 个维度的粒度恰到好处,既足以精确刻画不同模型之间真实存在的能力差异,又不至于膨胀成一套没法维护的分类学。
技术原理拆解 🍅
整条流水线一句话说完:Profiler 把目标平台的真实能力测出来;AOT Compiler 对照测算结果,把 skill 改写成这个平台跑得动的版本;进入运行时之后,JIT 系统再根据现场观测,持续抬高 skill 的实际发挥。
1. Profiler:把模型能力从语感变成数字 🍅
Profiler 要回答的问题非常明确:某个 LLM 配某个 Harness 的具体组合下,每一项原子能力到底处在什么档位?它沿 26 个预定义的基准维度做全面的能力侧写,可归为四大类:
- Generation:覆盖代码和文本生成;
- Reasoning:覆盖逻辑、数学、规划等推理能力;
- Tool Use:覆盖文件与命令调用;
- Instruction Following:覆盖格式、约束、多步指令的遵从程度。
每条原语进一步切成 L1 / L2 / L3 三个梯度,这 26 条原语足以覆盖大约 95% 的真实 skill 需求。Profiler 为每条原语配一组微基准,按原语性质走两条判分路径:涉及实际副作用的(如 gen.code.* 与 tool.*),让 Agent 真的去操作环境,再到 workDir 里检查文件产物;纯文本生成或推理类的,把模型回答落到 response.txt,由判分脚本做匹配评分。所有结果最后拼成一份 JSON 形式的 TCP(Target Capability Profile):
{
"model": "anthropic/claude-sonnet-4-6",
"adapter": "bare-agent",
"primitives": {
"gen.code.python": "L3",
"reason.math": "L2",
"tool.file.write": "L3",
"follow.constraint": "L1"
}
}
有一个细节值得划重点:TCP 刻画的是模型加 Harness 这个整体,从来不是孤立的模型。同一个模型,换一套可见工具集、换一种交互协议、换一种上下文管理方式,测出来就是另一回事。SkVM 后续所有决策都建立在这种端到端实测上,而不是任何脱离上下文的能力宣称。这个立场是对的,因为开头那个场景里坑掉开发者的,恰恰就是脱离上下文的能力宣称。
2. AOT Compiler:三遍 Pass,把通用 skill 改写成专用 Variant 🍅
AOT Compiler 是整个系统的核心。输入是原始 skill 加 TCP,输出是针对目标平台改写后的 Variant。流程拆成三遍 Pass,各管一类问题。
Pass 1:能力缺口弥补
第一遍解决的是“skill 假设你会做这件事,但你做不到“这类失败:
- 让 LLM 通读 skill,提取一份 SCR(Skill Capability Requirements):这个 skill 隐式假设了目标具备哪些原语、各到什么档位;
- 把 SCR 与 TCP 做差集,找出所有“需要 L2、实测只有 L1“的缺口。这一步纯属集合运算,不调 LLM;
- 把缺口清单交给
compiler-agent,逐条决定怎么改:可能是把一段要求一次到位的复杂推理拆成多步引导(CoT 化),可能是把相对路径改成绝对路径、降低 tool.exec 对路径解析能力的要求,最极端时直接换一条实现路线。
这里的分工值得停下来品一品。SkVM 没有把整遍 Pass 都丢给 LLM:**只有“理解 skill“和“选择改写策略“真的需要语言模型,缺口对比就是确定性的集合运算。**哪一步交给 LLM、哪一步留给确定性代码,这种划分是贯穿整套系统的工程口味。每从 LLM 手里挪出来一步,这一步就变得便宜、快速、可复现。
Pass 2:环境绑定
第二遍把视线从“模型脑子里有什么“转向“机器上装了什么“:
- LLM 先从 skill 里提炼出依赖清单(Python 包、CLI 工具、环境变量等);
- 一段 shell 脚本扫描当前机器,逐项检查是否就位;
- 产出一份幂等的
env-setup.sh,作为 skill 启动前的预热脚本。
它专治那种最让人崩溃的“运行时玄学“:模型边跑边猜,盲目地试 pip install ...、试 which git、试一切它不确定是否存在的东西,token 一路烧光,任务还没真正开始。把依赖解析一次性挪到事前,就是把一场开放式的运行时搜索,换成一笔固定的启动成本。
Pass 3:并发 DAG 提取
第三遍是性能 Pass:
- LLM 把 skill 的工作流分解成带依赖关系的步骤集合;
- 系统再用确定性逻辑把它装配成一张有向无环图;
- 从这张 DAG 上挖三种并行模式:
- DLP(Data-Level Parallelism):同一动作作用在不同数据项上,可并行;
- ILP(Instruction-Level Parallelism):相互无依赖的独立指令,可并行;
- TLP(Task-Level Parallelism):独立子任务整体并发。
这张 DAG 交给 Runtime 调度执行。论文报告的端到端加速里,相当一部分来自这一步:DLP / ILP / TLP 全开时,平均执行时间大约能压到原来的三分之一。
三遍的产物各自落盘到 ~/.skvm/proposals/aot-compile/{adapter}/{model}/{skillName}/{passTag}/,互不覆盖,可以只重跑某一遍而不必从头来过。对一个本质上带着 LLM 不确定性的编译过程来说,按 Pass 分离地持久化几乎是必备的工程纪律:任何一遍出问题,都污染不了前面几遍的成果。
3. JIT-Boost:把重复的 LLM 调用固化成确定性代码 🍅
AOT 之后,skill 还要被一次又一次真正执行。SkVM 注意到执行过程里一个朴素的事实:**很多 LLM 调用在结构上是高度重复的。**同一个文件分析 skill,处理每个文件之前都让模型生成一次 list_directory 调用,每次都重新走完整推理,token 和延迟都说不过去,因为跑过头几次之后,这个调用里根本没有需要推理的成分了。
JIT-Boost 的做法是识别出反复出现的模式,在合适的时机绕开 LLM:
- 候选挖掘:一个 headless agent 离线读完整份 skill,找出有固化潜力的调用模式,写入
boost-candidates.json,每条记录包含关键词、代码签名、函数模板和参数列表;
- 运行时挂钩:借 Adapter 暴露的
beforeLLM / afterLLM 钩子,在每次 LLM 调用前后插桩;
- 阈值触发:
afterLLM 钩子为每个候选统计连续命中次数,达到阈值(默认 3)后,下一次进入 beforeLLM 时直接抽参数、套模板执行,LLM 这一步被整个跳过;
- 失败回退:固化路径连续失败 M 次(默认 3)就自动降级回正常的 LLM 流程,该候选被标记为不再可信。
整个机制是一条自适应的反馈环:观察一段时间,决定要不要提速,提速后继续盯着结果,不行就退回去。论文在命中率高的 skill 片段上报告了 19 到 50 倍的加速,token 和延迟也压缩到相近的量级。注意回退机制买来的那种不对称性:一次错误固化的最坏后果是有界的,失败几次就自动回退;而最好的情况是把 LLM 从循环里整个拿掉。正是这种不对称,让激进的固化变成一件可以放心去试的事。
4. JIT-Optimize:让运行时证据反过来改 skill 本身 🍅
如果说 JIT-Boost 是在执行链路上抠浪费,JIT-Optimize 就更进一层:它直接动 skill 的文本本身。
设计上最有意思的是一个递归结构:**干这件事的 Optimizer,本身就是一个 headless agent。**每一轮的剧本大致是:
- Engine 先把 skill 目录拷贝到一个临时工作区;
- 把本轮可用的“证据“(合成任务的执行轨迹、真实 bench 跑出的对话日志,或一份既往会话的 NDJSON)序列化到
.optimize/ 子目录;
- 以工作区为 cwd,拉起一个 headless agent(默认由
opencode 驱动);
- 这个 agent 用自带的
read / edit / write / grep / bash 等工具去改 skill 文件;
- 改完之后,agent 必须落一份
submission.json,其中 rootCause 字段不可缺省,它要求 agent 写明这次修改针对的根本原因;
- Engine 给工作区拍快照、算 diff,并核对 agent 声明的
changedFiles 与实际改动是否一致。
为什么把 rootCause 设成必填?因为缺了它,Optimizer 实际上是在“改一改看看指标动不动“,也就是无目标的随机扰动。根本原因一旦必填,每次修改都得带着一个明确的诊断;更重要的是,所有轮次的 rootCause 都进入历史,回灌给下一轮的 Optimizer,让它知道哪些路已经走过且无效。看起来只是一个字段级的约束,结构上却把多轮迭代从盲走扳成了带记忆的搜索。
每次优化都会留下一棵完整的 Proposal 树:
~/.skvm/proposals/jit-optimize/{harness}/{model}/{skill}/{ts}/
original/
round-0/ # 基线
round-1/ … round-N/ # 每轮的完整 skill 目录
history.json # 每轮的 rootCause / metric / bestRound
analysis.md # 人类可读摘要
注意每个 round-N/ 都是一份可独立部署的完整 skill 目录,不是 diff。审阅的人可以挑任意一轮接受,不必把整条历史链一起吞下去。这是个有意为之的选择:让人能在自己实际审阅的粒度上行使判断。
5. Adapters 与并发调度:用同一种“驱动接口“封装所有 Harness 🍅
最后一块是 Adapter 层。SkVM 把五种主流 Agent Harness(bare-agent、opencode、openclaw、hermes、agentclaw)统一封在一个 AgentAdapter 接口背后,并约定它们都暴露同一组 RuntimeHooks:beforeLLM / afterLLM / afterTool / afterRun。这正是前面 JIT-Boost 能“零侵入接入任意 Harness“的真正前提:它只需要钩子,不用关心钩子背后是 Hermes 的 session export 还是 OpenClaw 的临时实例。
并发这边,src/core/concurrency.ts 实现了一套层级化的槽位调度器。它把并发预算按 adapter × model × task 三个维度切分,组与组之间允许偷槽(slot stealing):空闲的组可以借走忙碌组没占满的资源。在大规模 profile 和 bench 场景下,这套调度器决定的是两个非常实际的问题:成本上到底跑不跑得起,实验能不能在一夜之间跑完。
体会与思考 🍅
把这套系统从头到尾走一遍之后,有几点感受值得单独拿出来谈。
一、“能力可量化“是整套自动化能成立的真正起点。
体系结构的全部价值,几乎可以归结为一件事:在程序员的意图和具体硬件的能力之间,找到一层可以形式化描述的中间表示,让编译器一边消费上层语义,一边吸收下层差异。SkVM 把这个关键动作搬到了 LLM Agent 的语境里。26 条原语出现以前,所有关于“模型够不够强“的讨论都停留在感性比较:“这个模型推理弱一些”“那个模型工具调用更稳”。原语加 L1/L2/L3 之后,模型能力第一次变成了一行代码可以拿来做分支判断的 reason.logic = L1。没有这层量化,AOT 的缺口分析根本无从谈起,后续所有机制都会失去立足点。
二、把 LLM 嵌进编译器,等于把非确定性请进了 VM 内部。
传统编译器是符号变换,输入相同则输出必然相同。而 SkVM 的三遍 Pass 都内嵌了 LLM 调用,这意味着同一份 skill 编译两次,结果完全可能不一样。SkVM 没有回避这一点,而是用一整套结构把它框住:每个 Pass 的产物分开落盘,跨子系统的 JSON 一律过 Zod schema 校验,运行时再由 JIT-Optimize 兜底纠偏。它的工程哲学等于是先承认编译时不可能一步到位,然后用持久化、校验、运行时反馈三件事,把这种不确定性约束在可控范围内。
三、Headless Agent 事实上已经成了一种基础设施级的原语。
JIT-Boost 的候选挖掘也好,JIT-Optimize 的 Optimizer 也好,SkVM 在两处最复杂的环节都没有自己造一套“代码分析加多文件编辑“的工具链,而是直接把任务交给 headless agent,理由很简单:这本来就是 agent 擅长的事。但这种复用不是白拿的:Optimizer 的上限被 driver agent 的上限锁死。SkVM 的应对是用 OptimizeConfig.driver 把 driver 显式抽出来,允许在 bare-agent / opencode / claude-code 之间切换。这是正确的解耦动作,默认假设就是“驱动会被升级“。
四、可移植性与最优性之间没有免费午餐。
所有中间层系统的命门都在这里:可移植,和在某一个特定目标上榨干最后一滴性能,本来就是一对结构性矛盾。一份为 Claude Sonnet 手写、被人反复调过的提示词,理论最优值可能就是高于 SkVM 的编译产物;在那些对提示风格特别敏感的细分场景里,通用改写甚至会丢掉一些微妙的性能。SkVM 给出的对冲是三件事:运行时让 JIT-Optimize 再补救一轮,所有轮次保留完整 proposal 供人挑选,配一套 bench 系统让差距可度量而不是靠嘴争。这是一个中间层该有的诚实姿态。
五、真正让这套系统立得住的,是那些不那么性感的工程决定。
SkVM 论文层面的创新固然抢眼,但仔细翻代码会发现,让它真的能跑、能被外人用起来的,多半是一些不张扬的工程口味:
- 选 TypeScript + Bun、no build step,新人 clone 下来就能改;
- 所有跨模块边界都用 Zod schema 锁定契约,把运行时惊喜压到最少;
src/adapters/registry.ts 是唯一的 adapter 登记入口,新增 harness 只动一处文件;
- 缓存目录
~/.skvm/ 全局共享,但允许 SKVM_CACHE 覆盖,便利与可控兼得;
rootCause 字段强制非空,把 agent 自我纠错的纪律用代码而不是约定落实下来。
这些条目单看都不起眼,叠在一起,就是研究原型和别人真能上手运维的系统之间的分水岭。
总结 🍅
SkVM 的价值,站在两种读者的位置上看是两回事。
站在工程师视角,它把一直被默默忍受的“skill 跨平台不可用“问题,拆成了一条完整的工具链:量化(Profiler)→ 静态适配(AOT Compiler)→ 运行时持续磨合(JIT-Boost + JIT-Optimize)。skill 从此不再是“在我这台机器上、配某个特定模型、跑某个特定版本时还行“的孤立资产,而成了一种可分发、可编译、可验证、可自演化的软件制品。
站在体系结构视角,它完成了一次罕见的范式迁移:把语言虚拟机时代验证了几十年的整套方法论(能力抽象、静态分析、动态优化、中间表示)成体系地搬到了以 LLM 为算力底座的新型计算栈上。在这个映射里,26 条原语对应 ISA,AOT Compiler 对应 LLVM 的前端,JIT-Boost 对应 V8 的热路径优化;而 JIT-Optimize 走得比任何传统 VM 都远,它让“程序“在运行过程中改写自己。这种自我改写在硬件世界里没有对应物,是 LLM 进入栈底之后才被释放出来的新自由度。
放到更长的尺度上想,下一步最值得期待的方向,很可能是 skill 之间的依赖关系与版本管理。当一个 skill 的输出被另一个 skill 当作输入消费时,SkVM 能不能像 npm 或 cargo 那样自动维护组合兼容性?这一步一旦打通,它的角色就会从一个工具,跃迁为一整代 LLM Agent 的“发行版“基础设施。
Background 🍅
Agent Skills have quietly replaced bare prompts as the mainstream unit of organization in agent development, and the two properties driving that shift are worth naming precisely: progressive disclosure, which keeps a skill’s context cost proportional to how much of it a task actually needs, and hand-editability, which keeps humans in the authoring loop. A single SKILL.md plus a few companion scripts can package domain knowledge, workflow conventions, and tool-calling habits into a distributable asset, which is why GitHub is now flooded with them.
That flood produces a characteristic failure mode. You pull down a well-starred skill, run it locally, and the results fall far short of what the README promised. It’s baffling (there is hardly any code in a skill to be wrong), yet you cannot reproduce the author’s results. Usually the skill isn’t badly written. The author developed it against a different model than yours, or ran it on OpenClaw while you’re on Hermes Agent. A skill that gave its author real leverage arrives on your machine nearly inert.
This is structural, not bad luck, and it decomposes into three layers:
- Different LLMs emerge from very different training processes with unevenly distributed capabilities (code generation, instruction following, tool calling, long-chain reasoning), each model with its own strengths and blind spots;
- Different agent harnesses impose their own tool sets, sandbox contracts, context-management policies, and error-reporting protocols;
- The runtime environment a skill depends on (Python packages, CLI tools, environment variables) caps how much of its nominal capability it can actually deliver.
Copying someone’s skill verbatim onto your machine amounts to pretending none of these differences exist. Before this work, portability was simply never treated as a property skills needed to have. SkVM makes it a first-class problem: a skill is not prompt text addressed to a model, but a program that must be compiled and optimized for a heterogeneous LLM–harness target platform, and SkVM builds a full compiler-and-runtime system around that premise.
An Analogy 🍅
Why should compiling and running skills have anything to do with virtual machines? The metaphor is deeper than it looks, and the way to see that is to revisit an older chapter of engineering history.
From the 1970s through the 1990s, hardware architectures churned relentlessly, a new one every few years. The same C program, landing on a VAX, a SPARC, or an x86 machine, had to re-select instructions, re-allocate registers, and re-align memory accesses before it performed decently. The field converged on exactly two answers: static compilation, where the compiler translates source ahead of time into the best machine code for a known target; and the virtual machine, where source is first lowered to a hardware-independent intermediate representation (IR/bytecode) and translated just-in-time on whatever platform it lands on. Different mechanisms, one essential move: insert an abstraction layer between source and target so that hardware differences get absorbed rather than leaked.
SkVM is an isomorphic transplant of that move. The alignment is worth laying out explicitly:
| Classic compiler/VM world | SkVM world |
| Source code | Skill (SKILL.md plus accompanying scripts and resources) |
| Target hardware | A combination of some LLM and some Agent Harness |
| ISA / ABI | 26 Primitives |
| Profiler / performance counters | The Target Capability Profile (TCP) produced by the Profiler |
| AOT compiler | The three-pass AOT Compiler |
| JIT | JIT-Boost (hot-path solidification) and JIT-Optimize (self-rewriting content) |
Every component in SkVM has a counterpart in an architecture textbook; the mapping holds up under pressure rather than serving as decoration. Once you accept the framing of an LLM as an unusual processor exposing a natural-language ISA, decades of compiler and VM lessons, including their known failure modes, become available for reuse.
The sharpest design decision is where the ISA goes. The ISA became the single most consequential layer in computer architecture because it is the contract that mediates portability against efficiency, and SkVM saw this. Its 26 primitives sit at exactly that point: skill authors write against the primitives, and 26 dimensions proves fine-grained enough to characterize the capability differences that genuinely exist between models without ballooning into an unmaintainable taxonomy.
Unpacking the Technical Principles 🍅
The pipeline in one sentence: the Profiler measures what the target platform can actually do; the AOT Compiler rewrites the skill against those measurements into a version that runs on this platform; the JIT system then keeps raising the skill’s effective capability at runtime, based on what it observes in the field.
1. Profiler: Turning Model Capability from Intuition into Numbers 🍅
The Profiler answers a precise question: for one specific LLM paired with one specific harness, at what tier does each atomic capability sit? It profiles across 26 predefined benchmark dimensions, grouped into four categories:
- Generation: code and text generation;
- Reasoning: logical, mathematical, planning, and related reasoning;
- Tool Use: file and command invocation;
- Instruction Following: compliance with formats, constraints, and multi-step instructions.
Each primitive is graded into three tiers (L1 / L2 / L3), and the 26 primitives together cover roughly 95% of real skill needs. Every primitive gets a set of micro-benchmarks, scored along one of two paths depending on its nature: primitives with real side effects (such as gen.code.* and tool.*) let the agent actually operate on the environment, after which the file artifacts in workDir are inspected; pure text-generation or reasoning primitives write the model’s answer to response.txt for match-based grading by a scoring script. Everything assembles into a JSON TCP (Target Capability Profile):
{
"model": "anthropic/claude-sonnet-4-6",
"adapter": "bare-agent",
"primitives": {
"gen.code.python": "L3",
"reason.math": "L2",
"tool.file.write": "L3",
"follow.constraint": "L1"
}
}
The detail worth underlining: the TCP portrays the model-plus-harness as a whole, never the model in isolation. Give the same model a different visible tool set, a different interaction protocol, or different context management, and it profiles differently. Every downstream decision in SkVM rests on this end-to-end empirical measurement rather than on any context-free capability claim. That is the correct epistemic posture, since context-free claims are exactly what failed the developer in the opening scenario.
2. AOT Compiler: Three Passes That Rewrite a Generic Skill into a Specialized Variant 🍅
The AOT Compiler is the heart of the system. Its input is the original skill plus the TCP; its output is a Variant rewritten for the target platform. The work splits into three passes, each owning a distinct problem.
Pass 1: Capability Gap Filling
The first pass handles the class of failures where the skill assumes a capability the target doesn’t have:
- An LLM reads through the skill and extracts an SCR (Skill Capability Requirements): which primitives the skill implicitly assumes the target has, and at what tier;
- The SCR is diffed against the TCP to find every gap of the form “requires L2, measured L1,” a step that is pure set arithmetic, with no LLM call;
- The gap list goes to the
compiler-agent, which decides the rewrite case by case: splitting a complex one-shot reasoning step into multi-step guidance (CoT-ization), converting relative paths to absolute paths to lower the demand tool.exec places on path resolution, or, in the extreme case, swapping in an entirely different implementation route.
The division of labor here deserves a pause. SkVM does not hand the whole pass to the LLM. Only “understanding the skill” and “choosing the rewrite strategy” genuinely need a language model; the gap comparison is deterministic set arithmetic. Deciding which steps go to the LLM and which stay in deterministic code is an engineering sensibility that recurs throughout the system: every step moved out of the LLM is a step that becomes cheap, fast, and reproducible.
Pass 2: Environment Binding
The second pass shifts attention from what’s in the model’s head to what’s installed on the machine:
- An LLM distills a dependency list from the skill (Python packages, CLI tools, environment variables, etc.);
- A shell script scans the current machine and checks each item;
- The output is an idempotent
env-setup.sh that runs as a warm-up before the skill starts.
This targets a specific, maddening failure pattern of runtime guessing: the model blindly trying pip install ..., probing which git, testing everything it isn’t sure exists, burning tokens while the actual task hasn’t begun. Resolving dependencies once, ahead of time, converts that open-ended runtime search into a fixed setup cost.
Pass 3: Concurrent DAG Extraction
The third pass is the performance pass:
- An LLM decomposes the skill’s workflow into a set of steps with dependency relationships;
- Deterministic logic assembles them into a directed acyclic graph;
- Three parallelism patterns are mined from this DAG:
- DLP (Data-Level Parallelism): the same action applied to different data items can run in parallel;
- ILP (Instruction-Level Parallelism): mutually independent instructions can run in parallel;
- TLP (Task-Level Parallelism): independent subtasks run concurrently as wholes.
The Runtime schedules execution off this DAG. A substantial share of the paper’s end-to-end speedup comes from this pass: with DLP / ILP / TLP all enabled, average execution time compresses to roughly one-third of the original.
Each pass persists its products to ~/.skvm/proposals/aot-compile/{adapter}/{model}/{skillName}/{passTag}/, none overwriting another, so any single pass can be re-run without starting over. For a compilation process that embeds LLM nondeterminism, per-pass persistence is close to mandatory engineering discipline: a failure in one pass cannot contaminate the results of the passes before it.
3. JIT-Boost: Solidifying Repeated LLM Calls into Deterministic Code 🍅
After AOT, the skill still gets executed over and over, and SkVM notices a plain fact about those executions: many LLM calls are structurally repetitive. A file-analysis skill that makes the model generate a list_directory call before processing each file re-runs full reasoning every single time, indefensible in both tokens and latency, because nothing about that call requires reasoning after the first few occurrences.
JIT-Boost identifies the recurring pattern and bypasses the LLM at the right moment:
- Candidate mining: a headless agent reads the entire skill offline, finds call patterns with solidification potential, and writes them to
boost-candidates.json, each record carrying keywords, a code signature, a function template, and a parameter list;
- Runtime hooking: using the
beforeLLM / afterLLM hooks exposed by the Adapter, it instruments before and after each LLM call;
- Threshold triggering: the
afterLLM hook counts consecutive hits per candidate; once the threshold (default 3) is reached, the next entry into beforeLLM extracts parameters and executes the template directly, and the LLM step is skipped entirely;
- Failure fallback: if the solidified path fails M times in a row (default 3), it automatically downgrades back to the normal LLM flow, and the candidate is marked as no longer trustworthy.
The mechanism is an adaptive feedback loop: observe for a while, decide whether to boost, keep watching after boosting, roll back if it doesn’t hold. On high-hit-rate skill fragments the paper reports 19–50× speedups, with tokens and latency shrinking by similar factors. Note the asymmetry the fallback buys: the worst case of a wrong boost is bounded (a few failed attempts, then automatic reversion), while the best case removes the LLM from the loop entirely. That asymmetry is what makes aggressive solidification safe to attempt.
4. JIT-Optimize: Letting Runtime Evidence Rewrite the Skill Itself 🍅
Where JIT-Boost squeezes waste out of the execution path, JIT-Optimize goes one step further and touches the text of the skill itself.
The most interesting part of its design is a recursive structure: the Optimizer is itself a headless agent. Each round runs roughly:
- The Engine copies the skill directory to a temporary workspace;
- It serializes this round’s “evidence” (execution traces from synthetic tasks, dialogue logs from real bench runs, or an NDJSON of a past session) into the
.optimize/ subdirectory;
- With the workspace as cwd, it spins up a headless agent (driven by
opencode by default);
- The agent uses its own
read / edit / write / grep / bash tools to modify the skill files;
- On finishing, the agent must produce a
submission.json whose rootCause field must not be omitted: it has to state the root cause this modification targets;
- The Engine snapshots the workspace, computes the diff, and verifies that the agent’s declared
changedFiles matches the actual changes.
Why force rootCause to be non-empty? Because without it, the Optimizer degenerates into “tweak something and see if the metric moves,” aimless perturbation. Requiring a root cause forces every modification to carry an explicit diagnosis, and, more importantly, the rootCause history from every round feeds back into the next round’s Optimizer, telling it which paths were already tried and found wanting. What looks like a field-level constraint structurally converts multi-round iteration from a random walk into search with memory.
Each optimization leaves behind a complete Proposal tree:
~/.skvm/proposals/jit-optimize/{harness}/{model}/{skill}/{ts}/
original/
round-0/ # baseline
round-1/ … round-N/ # the full skill directory for each round
history.json # rootCause / metric / bestRound for each round
analysis.md # human-readable summary
Note that every round-N/ is a complete, independently deployable skill directory, not a diff. A reviewer can accept any single round without swallowing the entire history chain, a deliberate choice that keeps humans able to exercise judgment at the granularity they actually review at.
5. Adapters and Concurrency Scheduling: One “Driver Interface” for Every Harness 🍅
The last piece is the Adapter layer. SkVM wraps five mainstream agent harnesses (bare-agent, opencode, openclaw, hermes, agentclaw) behind a single AgentAdapter interface and requires each to expose the same set of RuntimeHooks: beforeLLM / afterLLM / afterTool / afterRun. This is the real precondition for JIT-Boost’s ability to plug into any harness with zero intrusion: it needs only the hooks, and never has to care whether the implementation behind a hook is Hermes’s session export or OpenClaw’s ephemeral instance.
On the concurrency side, src/core/concurrency.ts implements a hierarchical slot scheduler. It partitions the concurrency budget along three dimensions (adapter × model × task) and permits slot stealing across groups: an idle group can borrow capacity a busy group hasn’t claimed. In large-scale profiling and benching, this scheduler is what decides two very practical questions: whether the cost is affordable at all, and whether the experiment finishes overnight.
Reflections and Thoughts 🍅
After walking through the system, a few points deserve to be discussed on their own.
1. Quantifiable capability is the starting point that makes all the automation possible.
Nearly the entire value of computer architecture reduces to one move: finding, between programmer intent and concrete hardware, an intermediate representation formal enough that a compiler can consume upper-layer semantics on one side and absorb lower-layer differences on the other. SkVM transplants exactly this move into the LLM-agent context. Before the 26 primitives, every discussion of “is the model strong enough” lived at the level of intuition: “this model is a bit weak at reasoning,” “that one is steadier at tool calls.” After primitives plus L1/L2/L3, model capability became, for the first time, a line of reason.logic = L1 that code can branch on. Without that layer of quantification, the AOT gap analysis has no ground to stand on, and every downstream mechanism loses its anchor.
2. Embedding an LLM inside a compiler invites nondeterminism into the VM itself.
A traditional compiler is a symbolic transformation: identical input necessarily yields identical output. All three of SkVM’s passes embed LLM calls, meaning compiling the same skill twice may well produce different results. SkVM doesn’t pretend otherwise; it contains the problem structurally: each pass’s products persisted separately, JSON at every subsystem boundary validated through Zod schemas, and runtime JIT-Optimize standing by as a corrective backstop. The engineering philosophy amounts to admitting that compile time cannot get it right in one shot, then using persistence, validation, and runtime feedback to keep the resulting uncertainty inside a controllable envelope.
3. Headless agents have effectively become an infrastructure-level primitive.
At its two most complex junctures (JIT-Boost’s candidate mining and JIT-Optimize’s Optimizer), SkVM builds no bespoke “code analysis + multi-file editing” toolchain. It hands the job to a headless agent, for the simple reason that this is precisely what agents are good at. The reuse isn’t free: the Optimizer’s ceiling is locked to the driver agent’s ceiling. SkVM’s answer is to factor the driver out explicitly via OptimizeConfig.driver, switchable among bare-agent / opencode / claude-code, the right decoupling, with “the driver will get upgraded” as the default assumption.
4. There is no free lunch between portability and optimality.
This is the Achilles’ heel of every middle-layer system: portability and squeezing the last drop out of one specific target are structurally at odds. A prompt hand-written for Claude Sonnet and tuned by a patient human can have a higher theoretical optimum than SkVM’s compiled output, and in niches acutely sensitive to prompt style, generic rewriting may even lose subtle performance. SkVM’s hedges are honest ones: let JIT-Optimize take another corrective pass at runtime, keep the full proposals of every round so a human can pick, and ship a bench system so the gap is measurable rather than argued about. That is the posture a middle layer should hold.
5. What actually makes the system stand up are the unglamorous engineering decisions.
The paper-level innovations catch the eye, but reading the code, what makes SkVM runnable and adoptable by strangers is mostly quiet engineering taste:
- TypeScript + Bun with no build step, so a newcomer can clone and start editing;
- Contracts locked at every cross-module boundary with Zod schemas, keeping runtime surprises to a minimum;
src/adapters/registry.ts as the sole adapter registration entry, so adding a harness touches one file;
- A globally shared cache directory
~/.skvm/ with an override via SKVM_CACHE, balancing convenience against controllability;
- The
rootCause field forced non-empty, enshrining the discipline of agent self-correction in code rather than in convention.
Each item is unremarkable on its own. Stacked together, they are the watershed between a research prototype and a system other people can actually operate.
Conclusion 🍅
SkVM’s value reads differently depending on which reader you are.
From an engineer’s perspective, it decomposes the long-tolerated problem of skills not working across platforms into a complete toolchain: quantification (Profiler) → static adaptation (AOT Compiler) → continuous runtime tuning (JIT-Boost + JIT-Optimize). A skill stops being an isolated asset that “works okay on my machine, with a particular model, on a particular version” and becomes a distributable, compilable, verifiable, self-evolving software artifact.
From an architecture perspective, it accomplishes a rare paradigm transplant: the entire methodology validated over decades of language virtual machines (capability abstraction, static analysis, dynamic optimization, intermediate representation) systematically moved onto a new computing stack whose compute substrate is the LLM. In this mapping, the 26 primitives correspond to the ISA, the AOT Compiler to LLVM’s front end, and JIT-Boost to V8’s hot-path optimization; JIT-Optimize then goes beyond what any traditional VM does: it lets the “program” rewrite itself during execution. That self-rewriting has no counterpart in the hardware world; it is a genuinely new degree of freedom unlocked only once an LLM sits at the bottom of the stack.
On a longer horizon, the direction most worth watching is dependency relationships and version management between skills. When one skill’s output is consumed as another skill’s input, can SkVM maintain composition compatibility automatically, the way npm or cargo does? Once that step opens up, its role leaps from a tool to distribution-level infrastructure for an entire generation of LLM agents.