<?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>vx | Releases</title>
<description>What each vx release changed.</description>
<link>https://vznjs.github.io/vx/releases/</link>
<language>en</language>
<atom:link rel="self" type="application/rss+xml" href="https://vznjs.github.io/vx/releases/rss.xml"/>
<item><title>vx speaks to agents</title><link>https://vznjs.github.io/vx/releases/vx-0-0-632/</link><guid isPermaLink="true">https://vznjs.github.io/vx/releases/vx-0-0-632/</guid><description>vx run speaks JSON, every refusal has a stable code, and vx mcp plans and runs tasks. vx init moves a Turbo or Nx repo to vx in one command.</description><pubDate>Fri, 09 Oct 2026 09:00:00 GMT</pubDate><category>release</category><content:encoded>&lt;p&gt;vx 0.0.626 to 0.0.632 shipped on 2026-10-08 and 2026-10-09. This batch
makes vx easy for an AI agent to drive: results as JSON, errors with
stable codes, failed output an agent can act on, and an MCP server that
runs and plans tasks. It also makes &lt;code dir=&quot;auto&quot;&gt;vx init&lt;/code&gt; the one command to adopt a
Turbo or Nx repo.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this release&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#vx-run-speaks-json&quot;&gt;vx run speaks JSON&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#stable-error-codes&quot;&gt;Stable error codes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#failed-output-agents-can-act-on&quot;&gt;Failed output agents can act on&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#vx-mcp-runs-and-plans-tasks&quot;&gt;vx mcp runs and plans tasks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#why-a-task-is-affected&quot;&gt;Why a task is affected&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#vx-init-adopts-turbo-and-nx&quot;&gt;vx init adopts Turbo and Nx&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#one-ordered-log-on-a-cache-hit&quot;&gt;One ordered log on a cache hit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#remote-execution-tls-by-default&quot;&gt;Remote execution: TLS by default&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;vx-run-speaks-json&quot;&gt;vx run speaks JSON&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#vx-run-speaks-json&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “vx run speaks JSON”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;vx run --format json&lt;/code&gt; prints one result object on stdout: each task’s
status, exit code, duration and key, plus the time the cache saved and
the critical path. An agent reads one value instead of parsing a log.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://vznjs.github.io/vx/_astro/ec.w36nc.css&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:76ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--all&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--format&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#7FDBCA;--1:#096E72&quot;&gt;2&gt;&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;/dev/null&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;&quot;runId&quot;&lt;/span&gt;&lt;span style=&quot;--0:#C5E478;--1:#3B61B0&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;01a11f0d-014c-700d-a4ad-59e93a00a129&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;&quot;ok&quot;&lt;/span&gt;&lt;span style=&quot;--0:#C5E478;--1:#3B61B0&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--1:#3B61B0&quot;&gt;&lt;span style=&quot;--0:#82AAFF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;&quot;exitCode&quot;&lt;/span&gt;&lt;span style=&quot;--0:#C5E478;--1:#3B61B0&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;0,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;&quot;savedMs&quot;&lt;/span&gt;&lt;span style=&quot;--0:#C5E478;--1:#3B61B0&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;1270,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;&quot;tasks&quot;&lt;/span&gt;&lt;span style=&quot;--0:#C5E478;--1:#3B61B0&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:4ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span style=&quot;--0:#C5E478;--1:#3B61B0&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@demo/api#build&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;cache-hit&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;durationMs&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;3,&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;$ vx run build --all --format json 2&gt;/dev/null{  &amp;#x22;runId&amp;#x22;: &amp;#x22;01a11f0d-014c-700d-a4ad-59e93a00a129&amp;#x22;,  &amp;#x22;ok&amp;#x22;: true,  &amp;#x22;exitCode&amp;#x22;: 0,  &amp;#x22;savedMs&amp;#x22;: 1270,  &amp;#x22;tasks&amp;#x22;: [    { &amp;#x22;id&amp;#x22;: &amp;#x22;@demo/api#build&amp;#x22;, &amp;#x22;status&amp;#x22;: &amp;#x22;cache-hit&amp;#x22;, &amp;#x22;durationMs&amp;#x22;: 3, ... }&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/3271&quot;&gt;#3271&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/3296&quot;&gt;#3296&lt;/a&gt;. Deep dive:
&lt;a href=&quot;../../blog/built-for-agents/&quot;&gt;Built for agents&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;stable-error-codes&quot;&gt;Stable error codes&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#stable-error-codes&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Stable error codes”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Every refusal now carries a &lt;code dir=&quot;auto&quot;&gt;VX_E_&lt;/code&gt; code that does not change between
versions, so a script or an agent branches on the code, not the wording.
Unknown verbs, usage mistakes and the reading verbs’ refusals are coded
too.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:125ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;biuld&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--all&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--format&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;json&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;&quot;ok&quot;&lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;:false,&lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;&quot;error&quot;&lt;/span&gt;&lt;span style=&quot;--0:#C5E478;--1:#3B61B0&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;&quot;:&quot;&lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;VX_E_UNKNOWN_TASK&lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;&quot;,&quot;&lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;&quot;:&quot;&lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run:&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;no&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;projects&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;declare&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;task&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;biuld.&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;Did&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;you&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;mean&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;build?&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;}}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;$ vx run biuld --all --format json{&amp;#x22;ok&amp;#x22;:false,&amp;#x22;error&amp;#x22;:{&amp;#x22;code&amp;#x22;:&amp;#x22;VX_E_UNKNOWN_TASK&amp;#x22;,&amp;#x22;message&amp;#x22;:&amp;#x22;vx run: no projects declare task(s): biuld. Did you mean build?&amp;#x22;}}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/3298&quot;&gt;#3298&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/3321&quot;&gt;#3321&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/3324&quot;&gt;#3324&lt;/a&gt;. Deep dive:
&lt;a href=&quot;../../blog/error-codes/&quot;&gt;Error codes&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;failed-output-agents-can-act-on&quot;&gt;Failed output agents can act on&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#failed-output-agents-can-act-on&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Failed output agents can act on”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A failed task’s output is kept for &lt;code dir=&quot;auto&quot;&gt;vx last --failed&lt;/code&gt;, and every
&lt;code dir=&quot;auto&quot;&gt;file:line:col&lt;/code&gt; in it becomes a location an agent can open and a
terminal can click.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:94ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;last&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--failed&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--format&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#7FDBCA;--1:#096E72&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;jq&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;.tasks[] | select(.output != &quot;&quot;) | {status, locations}&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span style=&quot;--0:#C5E478;--1:#3B61B0&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;failed&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;&quot;locations&quot;&lt;/span&gt;&lt;span style=&quot;--0:#C5E478;--1:#3B61B0&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:4ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;&quot;file&quot;&lt;/span&gt;&lt;span style=&quot;--0:#C5E478;--1:#3B61B0&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;/work/demo/packages/ui/src/index.ts&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;line&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;3,&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;col&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F78C6C;--1:#AA0982&quot;&gt;7&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;$ vx last --failed --format json | jq &amp;#x27;.tasks[] | select(.output != &amp;#x22;&amp;#x22;) | {status, locations}&amp;#x27;{  &amp;#x22;status&amp;#x22;: &amp;#x22;failed&amp;#x22;,  &amp;#x22;locations&amp;#x22;: [    { &amp;#x22;file&amp;#x22;: &amp;#x22;/work/demo/packages/ui/src/index.ts&amp;#x22;, &amp;#x22;line&amp;#x22;: 3, &amp;#x22;col&amp;#x22;: 7 }  ]}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;vx last --log &amp;#x3C;task&gt;&lt;/code&gt; prints one task’s output from a recorded run, so an
agent reads only the log it needs. vx also ships an agent skill
(&lt;code dir=&quot;auto&quot;&gt;skills/vx/SKILL.md&lt;/code&gt;) and the JSON schemas the docs point at.&lt;/p&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/3273&quot;&gt;#3273&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/3264&quot;&gt;#3264&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/3325&quot;&gt;#3325&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/3288&quot;&gt;#3288&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;vx-mcp-runs-and-plans-tasks&quot;&gt;vx mcp runs and plans tasks&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#vx-mcp-runs-and-plans-tasks&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “vx mcp runs and plans tasks”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;@vzn/vx-mcp&lt;/code&gt; gained new tools: &lt;code dir=&quot;auto&quot;&gt;runTasks&lt;/code&gt; runs tasks and returns the
JSON result, &lt;code dir=&quot;auto&quot;&gt;planTasks&lt;/code&gt; returns what a run would do without running it,
&lt;code dir=&quot;auto&quot;&gt;listTasks&lt;/code&gt; narrows by &lt;code dir=&quot;auto&quot;&gt;--filter&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;--affected&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;getConfig&lt;/code&gt; returns a
task’s resolved config, &lt;code dir=&quot;auto&quot;&gt;getTaskLog&lt;/code&gt; returns one task’s output, and
&lt;code dir=&quot;auto&quot;&gt;whyDidThisRerun&lt;/code&gt; answers like &lt;code dir=&quot;auto&quot;&gt;vx why&lt;/code&gt;, root cause included.
&lt;code dir=&quot;auto&quot;&gt;mcp({ run })&lt;/code&gt; limits &lt;code dir=&quot;auto&quot;&gt;runTasks&lt;/code&gt; to named tasks or turns it off.&lt;/p&gt;
&lt;pre class=&quot;mermaid&quot; role=&quot;img&quot; aria-label=&quot;diagram&quot;&gt;flowchart LR
  A[agent] --&gt;|planTasks| P[what would run]
  A --&gt;|runTasks| R[JSON result]
  A --&gt;|whyDidThisRerun| W[root cause]
  style R stroke:#c6f84e,stroke-width:2px&lt;/pre&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/3289&quot;&gt;#3289&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/3303&quot;&gt;#3303&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/3320&quot;&gt;#3320&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/3300&quot;&gt;#3300&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/3338&quot;&gt;#3338&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/3330&quot;&gt;#3330&lt;/a&gt;. Deep dive:
&lt;a href=&quot;../../blog/agents-and-mcp/&quot;&gt;Agents and MCP&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;why-a-task-is-affected&quot;&gt;Why a task is affected&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#why-a-task-is-affected&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Why a task is affected”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;--dry&lt;/code&gt; now prints, under each task &lt;code dir=&quot;auto&quot;&gt;--affected&lt;/code&gt; kept, the changed file
that kept it and the dependency it came through.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:96ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--all&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--affected=HEAD&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--dry&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;would&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;▶&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;@demo/docs#build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;cache&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;miss&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;—&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;would&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;exec&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;   &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;e50d7ee9&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;~309ms&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:23ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                       &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;affected:&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;packages/ui/src/index.ts&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;changed&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; (an &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;), via @demo/ui#build&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;▶&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;@demo/ui#build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;cache&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;miss&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;—&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;would&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;exec&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;   &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;e212d097&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;~312ms&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:23ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                       &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;affected:&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;packages/ui/src/index.ts&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;changed&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; (an &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;$ vx run build --all --affected=HEAD --drywould run:  ▶  @demo/docs#build  cache miss — would exec   e50d7ee9  ~309ms                       affected: packages/ui/src/index.ts changed (an input), via @demo/ui#build  ▶  @demo/ui#build    cache miss — would exec   e212d097  ~312ms                       affected: packages/ui/src/index.ts changed (an input)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/3276&quot;&gt;#3276&lt;/a&gt;. Deep dive:
&lt;a href=&quot;../../blog/see-inside-a-run/&quot;&gt;See inside a run&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;vx-init-adopts-turbo-and-nx&quot;&gt;vx init adopts Turbo and Nx&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#vx-init-adopts-turbo-and-nx&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “vx init adopts Turbo and Nx”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;In a repo with &lt;code dir=&quot;auto&quot;&gt;turbo.json&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;nx.json&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;vx init&lt;/code&gt; runs
&lt;code dir=&quot;auto&quot;&gt;@vzn/vx-migrate&lt;/code&gt;. It asks whether to write native config (a
&lt;code dir=&quot;auto&quot;&gt;vx.config.ts&lt;/code&gt; per package) or keep the repo’s own config live;
&lt;code dir=&quot;auto&quot;&gt;--native&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;--keep&lt;/code&gt; answer up front. A Turbo remote cache or a
self-hosted Nx cache the repo already uses is kept.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:16ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--native&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx init --native&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/3258&quot;&gt;#3258&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/3237&quot;&gt;#3237&lt;/a&gt;. Deep dive:
&lt;a href=&quot;../../blog/from-turborepo/&quot;&gt;From Turborepo&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;one-ordered-log-on-a-cache-hit&quot;&gt;One ordered log on a cache hit&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#one-ordered-log-on-a-cache-hit&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “One ordered log on a cache hit”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A task’s stdout and stderr are now stored as one ordered log, so a cache
hit replays stderr too, in the order the task wrote it. Live and on a
hit, a task’s output prints as one section.&lt;/p&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/3251&quot;&gt;#3251&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/3248&quot;&gt;#3248&lt;/a&gt;. Deep dive:
&lt;a href=&quot;../../blog/inside-a-cache-hit/&quot;&gt;Inside a cache hit&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;remote-execution-tls-by-default&quot;&gt;Remote execution: TLS by default&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#remote-execution-tls-by-default&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Remote execution: TLS by default”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;@vzn/vx-reapi&lt;/code&gt; connects an endpoint with no scheme over TLS, as Bazel
does; plaintext takes &lt;code dir=&quot;auto&quot;&gt;grpc://&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;tls: false&lt;/code&gt;. A remote result can now write only the
outputs the task declares.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:44ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;reapi&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;({ endpoint: &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;grpc://localhost:8980&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; })&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;reapi({ endpoint: &amp;#x27;grpc://localhost:8980&amp;#x27; })&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/3265&quot;&gt;#3265&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/3256&quot;&gt;#3256&lt;/a&gt;. Deep dive:
&lt;a href=&quot;../../blog/remote-execution/&quot;&gt;Remote execution&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;breaking-changes&quot;&gt;Breaking changes&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#breaking-changes&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Breaking changes”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;The cache format is now &lt;code dir=&quot;auto&quot;&gt;vx-cache-v42&lt;/code&gt;: every cached task misses once after upgrading (&lt;a href=&quot;https://github.com/vznjs/vx/pull/3251&quot;&gt;#3251&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;@vzn/vx-reapi&lt;/code&gt;: an endpoint with no scheme now uses TLS; a plaintext server needs &lt;code dir=&quot;auto&quot;&gt;grpc://&lt;/code&gt; (&lt;a href=&quot;https://github.com/vznjs/vx/pull/3265&quot;&gt;#3265&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See &lt;a href=&quot;../../guides/upgrading/&quot;&gt;Upgrading&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;how-to-update&quot;&gt;How to update&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#how-to-update&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “How to update”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:29ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;-D&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;@vzn/vx@latest&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm install -D @vzn/vx@latest&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;A standalone binary updates itself with &lt;code dir=&quot;auto&quot;&gt;vx upgrade&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;learn-more&quot;&gt;Learn more&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#learn-more&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Learn more”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;../../guides/agents/&quot;&gt;AI agents guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../../quickstart/&quot;&gt;Quickstart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/vznjs/vx/releases&quot;&gt;Every release on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item>
<item><title>Runs that explain themselves</title><link>https://vznjs.github.io/vx/releases/vx-0-0-625/</link><guid isPermaLink="true">https://vznjs.github.io/vx/releases/vx-0-0-625/</guid><description>A live run now says how long is left, vx why follows a re-run to the file that caused it, and a bad config points at its line.</description><pubDate>Thu, 08 Oct 2026 19:00:00 GMT</pubDate><category>release</category><content:encoded>&lt;p&gt;vx 0.0.590 to 0.0.625 all shipped on 2026-10-08. This batch is about
answers: how long a run has left, why a task re-ran, and where a config
is wrong. It also brings Vite Task and Lerna migration, a dev server that
stays up under &lt;code dir=&quot;auto&quot;&gt;vx watch&lt;/code&gt;, and faster warm runs on large workspaces.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this release&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#live-run-end-forecast&quot;&gt;Live run end forecast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#vx-why-walks-to-the-root-cause&quot;&gt;vx why walks to the root cause&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#config-errors-point-at-the-line&quot;&gt;Config errors point at the line&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#time-the-cache-saved&quot;&gt;Time the cache saved&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#dev-server-stays-up-in-vx-watch&quot;&gt;Dev server stays up in vx watch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#migrate-from-vite-task&quot;&gt;Migrate from Vite Task&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#better-nx-and-lerna-migration&quot;&gt;Better Nx and Lerna migration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#vx-show-takes-filters&quot;&gt;vx show takes filters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#faster-warm-runs&quot;&gt;Faster warm runs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;live-run-end-forecast&quot;&gt;Live run end forecast&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#live-run-end-forecast&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Live run end forecast”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A second into a live run, the &lt;code dir=&quot;auto&quot;&gt;time&lt;/code&gt; row says what is left. The forecast
comes from each unfinished task’s median run time in local history, so
it needs no setup. Worker rows mark the task on the &lt;code dir=&quot;auto&quot;&gt;critical path&lt;/code&gt; and
say how many tasks wait on each (&lt;code dir=&quot;auto&quot;&gt;blocks N&lt;/code&gt;). In Ghostty, iTerm2,
WezTerm and Windows Terminal, vx also draws progress in the tab and posts
a desktop notification when a run of 10 s or more ends.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://vznjs.github.io/vx/_astro/ec.w36nc.css&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:63ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:5ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;1.40s running          web#build  critical path · blocks 3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:5ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;1.10s running          docs#build&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;time      1.41s · ~3s left&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;1.40s running          web#build  critical path · blocks 3     1.10s running          docs#build  time      1.41s · ~3s left&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/3246&quot;&gt;#3246&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;vx-why-walks-to-the-root-cause&quot;&gt;vx why walks to the root cause&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#vx-why-walks-to-the-root-cause&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “vx why walks to the root cause”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;When a task re-ran only because a dependency moved, &lt;code dir=&quot;auto&quot;&gt;vx why&lt;/code&gt; used to stop
at that dependency and tell you which &lt;code dir=&quot;auto&quot;&gt;vx why&lt;/code&gt; to run next. It now
follows the chain inside the same run down to the task whose own inputs
changed, and prints it under &lt;code dir=&quot;auto&quot;&gt;root cause&lt;/code&gt;. &lt;code dir=&quot;auto&quot;&gt;--format json&lt;/code&gt; carries the
chain as &lt;code dir=&quot;auto&quot;&gt;roots&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:68ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;$ vx why app#build&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;verdict    cache key changed: upstream lib#build&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;what changed (1 component, 5 unchanged):&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:4ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;changed upstream  lib#build  dcdf2a600ba2194d → 921ea5200e280cc9&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;root cause:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:4ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;app#build ← lib#build ← file packages/lib/src/index.ts&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;$ vx why app#build  verdict    cache key changed: upstream lib#build  what changed (1 component, 5 unchanged):    changed upstream  lib#build  dcdf2a600ba2194d → 921ea5200e280cc9  root cause:    app#build ← lib#build ← file packages/lib/src/index.ts&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;pre class=&quot;mermaid&quot; role=&quot;img&quot; aria-label=&quot;diagram&quot;&gt;flowchart LR
  F[&quot;file packages/lib/src/index.ts&quot;] --&gt;|changed| L[&quot;lib#build&quot;] --&gt;|key moved| A[&quot;app#build&quot;]
  style F stroke:#c6f84e,stroke-width:2px&lt;/pre&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/3245&quot;&gt;#3245&lt;/a&gt;. Deep dive:
&lt;a href=&quot;../../blog/why-did-this-rerun/&quot;&gt;Why did this re-run?&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;config-errors-point-at-the-line&quot;&gt;Config errors point at the line&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#config-errors-point-at-the-line&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Config errors point at the line”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A config refusal now names the file at &lt;code dir=&quot;auto&quot;&gt;line:col&lt;/code&gt;, relative to your
directory, so a terminal can open it on click. Below the message it
prints the lines leading up to the field with a caret under it.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:160ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;vx: packages/app/vx.config.ts:8:47: tasks.build.cache.outputs must be an object (fields: files, workspaceFiles), not an array — did you mean `{ files: [...] }`?&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;6 |       dependsOn: ['^build'],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;7 |       exec: { command: 'sleep 0.6 &amp;#x26;&amp;#x26; mkdir -p dist &amp;#x26;&amp;#x26; cp src/index.ts dist/' },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;&gt; 8 |       cache: { inputs: { files: ['src/**'] }, outputs: ['dist/**'] },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:4ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;|                                               ^&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx: packages/app/vx.config.ts:8:47: tasks.build.cache.outputs must be an object (fields: files, workspaceFiles), not an array — did you mean &amp;#x60;{ files: [...] }&amp;#x60;?  6 |       dependsOn: [&amp;#x27;^build&amp;#x27;],  7 |       exec: { command: &amp;#x27;sleep 0.6 &amp;#x26;&amp;#x26; mkdir -p dist &amp;#x26;&amp;#x26; cp src/index.ts dist/&amp;#x27; },&gt; 8 |       cache: { inputs: { files: [&amp;#x27;src/**&amp;#x27;] }, outputs: [&amp;#x27;dist/**&amp;#x27;] },    |                                               ^&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/3247&quot;&gt;#3247&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;time-the-cache-saved&quot;&gt;Time the cache saved&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#time-the-cache-saved&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Time the cache saved”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;The result line now says how much time the cache saved. The figure is
the sum of the stored run times of the tasks it restored, not the time
the restore took.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:53ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;info      4 workers · local cache&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;time      39ms&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;result    2 tasks · all cached · 928ms saved · 39ms&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;info      4 workers · local cache  time      39ms  result    2 tasks · all cached · 928ms saved · 39ms&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;vx-charts&quot;&gt;&lt;figure class=&quot;vx-bars&quot;&gt;&lt;figcaption&gt;Two tasks, all cached&lt;/figcaption&gt;&lt;div class=&quot;vx-bar&quot; style=&quot;--w:100%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;stored run time&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;928 ms&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;vx-bar vx-bar-lead&quot; style=&quot;--w:4.2%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;restore took&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;39 ms&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/3242&quot;&gt;#3242&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;dev-server-stays-up-in-vx-watch&quot;&gt;Dev server stays up in vx watch&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#dev-server-stays-up-in-vx-watch&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Dev server stays up in vx watch”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;vx watch dev&lt;/code&gt; restarted the dev server on every cycle, even for an edit
inside the app, so the dev tool’s own hot reload never got a chance. The
server now stays up while its task config is unchanged. Each cycle
rebuilds only the libraries an edit reaches, and the dev tool reloads
what changed. A config change or a crash still restarts it.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:12ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;watch&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;dev&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx watch dev&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;pre class=&quot;mermaid&quot; role=&quot;img&quot; aria-label=&quot;diagram&quot;&gt;flowchart LR
  E[&quot;edit in lib&quot;] --&gt; L[&quot;lib#build reruns&quot;] --&gt; D[&quot;dev server stays up&quot;] --&gt; H[&quot;hot reload&quot;]&lt;/pre&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/3243&quot;&gt;#3243&lt;/a&gt;. Deep dive:
&lt;a href=&quot;../../blog/watch-mode/&quot;&gt;Watch mode&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;migrate-from-vite-task&quot;&gt;Migrate from Vite Task&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#migrate-from-vite-task&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Migrate from Vite Task”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;npx @vzn/vx-migrate&lt;/code&gt; now reads a repo that uses vite-plus. It loads each
&lt;code dir=&quot;auto&quot;&gt;vite.config&lt;/code&gt; as &lt;code dir=&quot;auto&quot;&gt;vp run&lt;/code&gt; does and writes a &lt;code dir=&quot;auto&quot;&gt;vx.config.ts&lt;/code&gt; per package
from &lt;code dir=&quot;auto&quot;&gt;run.tasks&lt;/code&gt; and the package scripts. A nested &lt;code dir=&quot;auto&quot;&gt;vp run&lt;/code&gt; becomes a
&lt;code dir=&quot;auto&quot;&gt;dependsOn&lt;/code&gt; edge instead of a second runner inside vx. &lt;code dir=&quot;auto&quot;&gt;vx run&lt;/code&gt; also
accepts the &lt;code dir=&quot;auto&quot;&gt;vp run&lt;/code&gt; flags you already type: &lt;code dir=&quot;auto&quot;&gt;-r&lt;/code&gt; reads as &lt;code dir=&quot;auto&quot;&gt;--all&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;-w&lt;/code&gt;
as &lt;code dir=&quot;auto&quot;&gt;--filter //&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;--concurrency-limit&lt;/code&gt; as &lt;code dir=&quot;auto&quot;&gt;--concurrency&lt;/code&gt;, and
&lt;code dir=&quot;auto&quot;&gt;--ignore-depends-on&lt;/code&gt; as &lt;code dir=&quot;auto&quot;&gt;--exclude-dependencies&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:19ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;npx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;@vzn/vx-migrate&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;-r&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npx @vzn/vx-migratevx run build -r&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/2908&quot;&gt;#2908&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2965&quot;&gt;#2965&lt;/a&gt;. Guide:
&lt;a href=&quot;../../guides/migrate/#vite-task&quot;&gt;Vite Task&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;better-nx-and-lerna-migration&quot;&gt;Better Nx and Lerna migration&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#better-nx-and-lerna-migration&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Better Nx and Lerna migration”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A Lerna repo whose root scripts call &lt;code dir=&quot;auto&quot;&gt;lerna run&lt;/code&gt; now migrates through
&lt;code dir=&quot;auto&quot;&gt;nx()&lt;/code&gt;, since Lerna runs Nx’s task runner underneath. &lt;code dir=&quot;auto&quot;&gt;nx.json&lt;/code&gt;’s
&lt;code dir=&quot;auto&quot;&gt;parallel&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;defaultBase&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;maxCacheSize&lt;/code&gt; are written into
&lt;code dir=&quot;auto&quot;&gt;vx.workspace.ts&lt;/code&gt; as &lt;code dir=&quot;auto&quot;&gt;concurrency&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;affectedBase&lt;/code&gt; and
&lt;code dir=&quot;auto&quot;&gt;cacheRetention.maxSize&lt;/code&gt;, where they used to be notes. A &lt;code dir=&quot;auto&quot;&gt;run-commands&lt;/code&gt;
line that starts with &lt;code dir=&quot;auto&quot;&gt;nx &amp;#x3C;target&gt; &amp;#x3C;project&gt;&lt;/code&gt; becomes a &lt;code dir=&quot;auto&quot;&gt;dependsOn&lt;/code&gt; edge
instead of a todo. And &lt;code dir=&quot;auto&quot;&gt;-p 'apps/*'&lt;/code&gt; selects by directory, as Nx does.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:24ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;npx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;@vzn/vx-migrate&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;-p&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;apps/*&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npx @vzn/vx-migratevx run build -p &amp;#x27;apps/*&amp;#x27;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/3072&quot;&gt;#3072&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/3007&quot;&gt;#3007&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2956&quot;&gt;#2956&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2887&quot;&gt;#2887&lt;/a&gt;. Guide:
&lt;a href=&quot;../../guides/migrate/#nx&quot;&gt;Nx&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;vx-show-takes-filters&quot;&gt;vx show takes filters&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#vx-show-takes-filters&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “vx show takes filters”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;vx show&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;vx show &amp;#x3C;task&gt;&lt;/code&gt; now select projects the same way
&lt;code dir=&quot;auto&quot;&gt;vx run&lt;/code&gt; does. This is the vx form of &lt;code dir=&quot;auto&quot;&gt;turbo ls --affected&lt;/code&gt; and
&lt;code dir=&quot;auto&quot;&gt;nx show projects --affected&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:25ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;$ vx show --affected&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;app  packages/app  1 task&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;lib  packages/lib  1 task&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;$ vx show --affectedapp  packages/app  1 tasklib  packages/lib  1 task&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/2986&quot;&gt;#2986&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;faster-warm-runs&quot;&gt;Faster warm runs&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#faster-warm-runs&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Faster warm runs”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Four changes cut the overhead of a warm run on the 1,090-package bench.
An all-hit run went from 752 ms to 708 ms by reusing group keys. A
restore went from 2,356 ms to 2,019 ms by walking outputs once. The
scheduler dropped about 25 ms of per-task bookkeeping, and a frozen run
loads its configs 2.9× faster. A new check on every PR
now holds spawn, hash and SQLite counts on these paths to a baseline.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:18ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--all&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx run build --all&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;vx-charts&quot;&gt;&lt;figure class=&quot;vx-bars&quot;&gt;&lt;figcaption&gt;All-hit run, 1,090 packages&lt;/figcaption&gt;&lt;div class=&quot;vx-bar&quot; style=&quot;--w:100%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;before&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;752 ms&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;vx-bar vx-bar-lead&quot; style=&quot;--w:94.1%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;after&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;708 ms&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/figure&gt;&lt;figure class=&quot;vx-bars&quot;&gt;&lt;figcaption&gt;Restore, 1,090 packages&lt;/figcaption&gt;&lt;div class=&quot;vx-bar&quot; style=&quot;--w:100%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;before&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;2,356 ms&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;vx-bar vx-bar-lead&quot; style=&quot;--w:85.7%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;after&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;2,019 ms&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/3235&quot;&gt;#3235&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/3241&quot;&gt;#3241&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/3239&quot;&gt;#3239&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/3240&quot;&gt;#3240&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/3238&quot;&gt;#3238&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;breaking-changes&quot;&gt;Breaking changes&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#breaking-changes&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Breaking changes”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;The cache format is now &lt;code dir=&quot;auto&quot;&gt;vx-cache-v41&lt;/code&gt;: every cached task misses once after upgrading (&lt;a href=&quot;https://github.com/vznjs/vx/pull/3030&quot;&gt;#3030&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;exec.env&lt;/code&gt; &lt;code dir=&quot;auto&quot;&gt;define&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;passThrough&lt;/code&gt; names must be shell identifiers; others are refused at load (&lt;a href=&quot;https://github.com/vznjs/vx/pull/2958&quot;&gt;#2958&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;A tag that &lt;code dir=&quot;auto&quot;&gt;--filter tag:&lt;/code&gt; cannot select (&lt;code dir=&quot;auto&quot;&gt;**&lt;/code&gt;, an upper-case glob) is refused at load (&lt;a href=&quot;https://github.com/vznjs/vx/pull/2966&quot;&gt;#2966&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Config array fields are typed &lt;code dir=&quot;auto&quot;&gt;readonly&lt;/code&gt;; copy a resolved list before mutating it (&lt;a href=&quot;https://github.com/vznjs/vx/pull/2938&quot;&gt;#2938&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;Cache.storeFallback&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;Cache.storeMoved&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;Cache.orphansBeforeReset&lt;/code&gt; are removed; open a &lt;code dir=&quot;auto&quot;&gt;Cache&lt;/code&gt; in &lt;code dir=&quot;auto&quot;&gt;'preview'&lt;/code&gt; mode instead of the last (&lt;a href=&quot;https://github.com/vznjs/vx/pull/2976&quot;&gt;#2976&lt;/a&gt;, &lt;a href=&quot;https://github.com/vznjs/vx/pull/3041&quot;&gt;#3041&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See &lt;a href=&quot;../../guides/upgrading/&quot;&gt;Upgrading&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;how-to-update&quot;&gt;How to update&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#how-to-update&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “How to update”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:29ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;-D&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;@vzn/vx@latest&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm install -D @vzn/vx@latest&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;A standalone binary updates itself with &lt;code dir=&quot;auto&quot;&gt;vx upgrade&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;learn-more&quot;&gt;Learn more&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#learn-more&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Learn more”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;../../quickstart/&quot;&gt;Quickstart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../../benchmarks/&quot;&gt;Benchmarks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/vznjs/vx/releases&quot;&gt;Every release on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item>
<item><title>Every cache key known before a task runs</title><link>https://vznjs.github.io/vx/releases/vx-0-0-589/</link><guid isPermaLink="true">https://vznjs.github.io/vx/releases/vx-0-0-589/</guid><description>Two workspace rules that let vx know every key before anything runs, servers that stay off when only cache hits need them, and a live OpenTelemetry export.</description><pubDate>Wed, 07 Oct 2026 12:00:00 GMT</pubDate><category>release</category><content:encoded>&lt;p&gt;vx 0.0.521 to 0.0.589 shipped on 2026-10-07. The theme is fewer surprises:
the graph refuses configs that would delete files or slow every run, a
fully cached run boots nothing it does not need, and telemetry tells you
why a task rebuilt.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this release&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#keys-known-before-anything-runs&quot;&gt;Keys known before anything runs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#one-output-path-one-task&quot;&gt;One output path, one task&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#outputs-that-would-delete-your-sources&quot;&gt;Outputs that would delete your sources&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#servers-only-cache-hits-need-stay-off&quot;&gt;Servers only cache hits need stay off&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#live-opentelemetry-export&quot;&gt;Live OpenTelemetry export&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#vx-migrate-declares-and-installs-plugins&quot;&gt;vx-migrate declares and installs plugins&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#faster-all-cached-runs&quot;&gt;Faster all-cached runs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#vx-watch-follows-what-you-asked-for&quot;&gt;vx watch follows what you asked for&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#forwarded-args-reach-the-command&quot;&gt;Forwarded args reach the command&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#cache-correctness-fixes&quot;&gt;Cache correctness fixes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;keys-known-before-anything-runs&quot;&gt;Keys known before anything runs&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#keys-known-before-anything-runs&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Keys known before anything runs”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A task whose input globs could match another task’s outputs used to get a
preliminary key: vx could not probe, prefetch or restore it ahead of the
schedule. The new &lt;code dir=&quot;auto&quot;&gt;rules.upfrontKeys&lt;/code&gt; refuses such a task at load and
names the &lt;code dir=&quot;auto&quot;&gt;!&lt;/code&gt; entry that fixes it. It is on by default. The producer’s
key already reaches the reader through &lt;code dir=&quot;auto&quot;&gt;dependsOn&lt;/code&gt;, so excluding its
outputs loses nothing. &lt;code dir=&quot;auto&quot;&gt;rules: { upfrontKeys: false }&lt;/code&gt; in
&lt;code dir=&quot;auto&quot;&gt;vx.workspace.ts&lt;/code&gt; keeps the old waiting path.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://vznjs.github.io/vx/_astro/ec.w36nc.css&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:74ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;vx: app#test reads &quot;**/*&quot; in cache.inputs.files, which matches app#build's&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;output &quot;dist/**&quot;: a task's key must not read another task's outputs (the&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;dependency's key already cascades through dependsOn). Exclude it: add&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;&quot;!dist/**&quot; to app#test's cache.inputs.files, or set rules: { upfrontKeys:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;false } in vx.workspace.ts to let it wait for its producer.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx: app#test reads &amp;#x22;**/*&amp;#x22; in cache.inputs.files, which matches app#build&amp;#x27;soutput &amp;#x22;dist/**&amp;#x22;: a task&amp;#x27;s key must not read another task&amp;#x27;s outputs (thedependency&amp;#x27;s key already cascades through dependsOn). Exclude it: add&amp;#x22;!dist/**&amp;#x22; to app#test&amp;#x27;s cache.inputs.files, or set rules: { upfrontKeys:false } in vx.workspace.ts to let it wait for its producer.&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/2846&quot;&gt;#2846&lt;/a&gt;. Docs:
&lt;a href=&quot;../../guides/configure/#workspace-config&quot;&gt;Workspace config&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;one-output-path-one-task&quot;&gt;One output path, one task&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#one-output-path-one-task&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “One output path, one task”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Two tasks whose outputs overlapped were allowed when a &lt;code dir=&quot;auto&quot;&gt;dependsOn&lt;/code&gt; edge
ordered them. That was correct, but every run of the dependant paid for a
stamp, a diff and a clean. &lt;code dir=&quot;auto&quot;&gt;rules.exclusiveOutputs&lt;/code&gt;, on by default,
refuses the ordered pair too. Give each task its own output path, or set
&lt;code dir=&quot;auto&quot;&gt;rules: { exclusiveOutputs: false }&lt;/code&gt; to keep the additive path. Output
globs that overlap without sharing a prefix, such as &lt;code dir=&quot;auto&quot;&gt;dist/**/*.js&lt;/code&gt;
beside &lt;code dir=&quot;auto&quot;&gt;dist/sth/**&lt;/code&gt;, are now caught as well.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:74ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;vx: app#types and app#build both declare the output &quot;dist/**&quot; in&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;cache.outputs.files: vx cleans a task's declared outputs before it runs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;and before a cache-hit restore, so whichever of these runs second DELETES&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;the other's output. Give each task its own output path, or set rules: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;exclusiveOutputs: false } in vx.workspace.ts to let a dependant add to its&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;upstream's outputs.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx: app#types and app#build both declare the output &amp;#x22;dist/**&amp;#x22; incache.outputs.files: vx cleans a task&amp;#x27;s declared outputs before it runsand before a cache-hit restore, so whichever of these runs second DELETESthe other&amp;#x27;s output. Give each task its own output path, or set rules: {exclusiveOutputs: false } in vx.workspace.ts to let a dependant add to itsupstream&amp;#x27;s outputs.&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;pre class=&quot;mermaid&quot; role=&quot;img&quot; aria-label=&quot;diagram&quot;&gt;flowchart LR
  B[&quot;app#build&quot;] --&gt;|writes| D[(&quot;dist/**&quot;)]
  T[&quot;app#test&quot;] -.-&gt;|&quot;reads **/*&quot;| D
  D -.- X[&quot;refused: add !dist/**&quot;]&lt;/pre&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/2845&quot;&gt;#2845&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2841&quot;&gt;#2841&lt;/a&gt;. Deep dive:
&lt;a href=&quot;../../blog/strict-output-ownership/&quot;&gt;Strict output ownership&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;outputs-that-would-delete-your-sources&quot;&gt;Outputs that would delete your sources&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#outputs-that-would-delete-your-sources&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Outputs that would delete your sources”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;vx removes a task’s outputs before it runs. A formatter that declared
&lt;code dir=&quot;auto&quot;&gt;src/**&lt;/code&gt; as both inputs and outputs had every committed file under &lt;code dir=&quot;auto&quot;&gt;src&lt;/code&gt;
deleted. The graph now refuses it, whatever the rules, and says what to
do instead.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:74ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;vx: app#fmt: every file &quot;src/**&quot; in cache.inputs.files selects is also its&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;own output: vx removes a task's outputs before it runs, so the task would&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;delete its own sources. A task that rewrites files in place (a formatter)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;declares no outputs.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx: app#fmt: every file &amp;#x22;src/**&amp;#x22; in cache.inputs.files selects is also itsown output: vx removes a task&amp;#x27;s outputs before it runs, so the task woulddelete its own sources. A task that rewrites files in place (a formatter)declares no outputs.&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/2847&quot;&gt;#2847&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;servers-only-cache-hits-need-stay-off&quot;&gt;Servers only cache hits need stay off&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#servers-only-cache-hits-need-stay-off&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Servers only cache hits need stay off”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A &lt;code dir=&quot;auto&quot;&gt;persistent&lt;/code&gt; task pulled in as a dependency booted on every run, and its
dependants waited for it to be ready even when they were cache hits. Now
vx holds such a server dormant. It starts only if a dependant misses, and
otherwise never spawns. A fully cached &lt;code dir=&quot;auto&quot;&gt;vx run e2e#test&lt;/code&gt; over &lt;code dir=&quot;auto&quot;&gt;web#dev&lt;/code&gt;
went from 2.2 s to under 190 ms. Dependants in the server’s own project
still wait for it.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:15ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;e2e#test&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx run e2e#test&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;vx-charts&quot;&gt;&lt;figure class=&quot;vx-bars&quot;&gt;&lt;figcaption&gt;Cached vx run e2e#test over web#dev&lt;/figcaption&gt;&lt;div class=&quot;vx-bar&quot; style=&quot;--w:100%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;before&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;2.2 s&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;vx-bar vx-bar-lead&quot; style=&quot;--w:8.6%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;after&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;under 190 ms&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/2851&quot;&gt;#2851&lt;/a&gt;. Deep dive:
&lt;a href=&quot;../../blog/dev-servers-in-the-graph/&quot;&gt;Dev servers in the graph&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;live-opentelemetry-export&quot;&gt;Live OpenTelemetry export&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#live-opentelemetry-export&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Live OpenTelemetry export”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;@vzn/vx-otel&lt;/code&gt; now sends each task as it ends, batched once a second, so a
dashboard follows a CI run while it runs. &lt;code dir=&quot;auto&quot;&gt;live: false&lt;/code&gt; sends it all at
the end. Traces, metrics and logs share one resource key. Task spans gain
the command, queue wait, input file count, artifact size, save and fetch
time, and for a miss, what its key changed since the last saved entry.
On CI, every signal links back to the run and the pull request.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:68ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C5E478;--1:#3B61B0&quot;&gt;OTEL_EXPORTER_OTLP_ENDPOINT&lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;http://localhost:4318&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--all&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 vx run build --all&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/2786&quot;&gt;#2786&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2787&quot;&gt;#2787&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2792&quot;&gt;#2792&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2794&quot;&gt;#2794&lt;/a&gt;. Docs:
&lt;a href=&quot;../../guides/plugins/#opentelemetry&quot;&gt;OpenTelemetry&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;vx-migrate-declares-and-installs-plugins&quot;&gt;vx-migrate declares and installs plugins&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#vx-migrate-declares-and-installs-plugins&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “vx-migrate declares and installs plugins”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A migrated repo used to end with a note asking you to declare the lockfile
plugin yourself. &lt;code dir=&quot;auto&quot;&gt;@vzn/vx-migrate&lt;/code&gt; now writes the plugins into
&lt;code dir=&quot;auto&quot;&gt;vx.workspace.ts&lt;/code&gt; and installs them at its own version: the lockfile’s
&lt;code dir=&quot;auto&quot;&gt;@vzn/vx-lockfile&lt;/code&gt; plugin, &lt;code dir=&quot;auto&quot;&gt;scheduleHistoryPlugin()&lt;/code&gt;, and &lt;code dir=&quot;auto&quot;&gt;github()&lt;/code&gt; from
&lt;code dir=&quot;auto&quot;&gt;@vzn/vx-ci&lt;/code&gt; when &lt;code dir=&quot;auto&quot;&gt;.github/workflows&lt;/code&gt; exists. Written files no longer
carry a “Generated by” header. vx also stops printing cache upkeep
notices on upgrade.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:19ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;npx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;@vzn/vx-migrate&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npx @vzn/vx-migrate&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/2777&quot;&gt;#2777&lt;/a&gt;. Docs:
&lt;a href=&quot;../../guides/migrate/#one-command&quot;&gt;One command&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;faster-all-cached-runs&quot;&gt;Faster all-cached runs&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#faster-all-cached-runs&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Faster all-cached runs”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Several cuts to the warm path. Task globs match through one RegExp per
side instead of a dozen &lt;code dir=&quot;auto&quot;&gt;Bun.Glob&lt;/code&gt; calls per file. &lt;code dir=&quot;auto&quot;&gt;@vzn/vx-lockfile&lt;/code&gt;,
&lt;code dir=&quot;auto&quot;&gt;@vzn/vx-ci&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;@vzn/vx-mcp&lt;/code&gt; load their internals only when used, and
&lt;code dir=&quot;auto&quot;&gt;@vzn/vx-otel&lt;/code&gt; imports in 1.4 ms instead of 9.6 ms. A repo with no remote
no longer spawns two git commands on the run path. Together they make
the all-cached run of the vx repo itself 25% faster.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:18ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--all&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx run build --all&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;vx-charts&quot;&gt;&lt;figure class=&quot;vx-bars&quot;&gt;&lt;figcaption&gt;@vzn/vx-otel import&lt;/figcaption&gt;&lt;div class=&quot;vx-bar&quot; style=&quot;--w:100%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;before&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;9.6 ms&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;vx-bar vx-bar-lead&quot; style=&quot;--w:14.6%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;after&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;1.4 ms&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/2785&quot;&gt;#2785&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2788&quot;&gt;#2788&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2842&quot;&gt;#2842&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;vx-watch-follows-what-you-asked-for&quot;&gt;vx watch follows what you asked for&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#vx-watch-follows-what-you-asked-for&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “vx watch follows what you asked for”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;vx watch lib#build&lt;/code&gt; watched every project; it now watches &lt;code dir=&quot;auto&quot;&gt;lib&lt;/code&gt; and the
projects other &lt;code dir=&quot;auto&quot;&gt;pkg#task&lt;/code&gt; arguments name. &lt;code dir=&quot;auto&quot;&gt;vx watch --affected&lt;/code&gt; re-runs
tasks for edits made after it started, not only those in the starting
diff. An edit inside a nested project no longer triggers a cycle on the
root project.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:18ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;watch&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;lib#build&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx watch lib#build&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/2828&quot;&gt;#2828&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2827&quot;&gt;#2827&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2832&quot;&gt;#2832&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;forwarded-args-reach-the-command&quot;&gt;Forwarded args reach the command&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#forwarded-args-reach-the-command&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Forwarded args reach the command”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Args after &lt;code dir=&quot;auto&quot;&gt;--&lt;/code&gt; now reach a command that ends in a heredoc or a trailing
newline, where before they never arrived or ran as a command of their own
(&lt;code dir=&quot;auto&quot;&gt;--watch: not found&lt;/code&gt;). The &lt;code dir=&quot;auto&quot;&gt;$&lt;/code&gt; line in the output shows the command with
the args, as it ran.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:22ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;test&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--watch&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx run test -- --watch&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/2790&quot;&gt;#2790&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2802&quot;&gt;#2802&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2831&quot;&gt;#2831&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;cache-correctness-fixes&quot;&gt;Cache correctness fixes&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#cache-correctness-fixes&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Cache correctness fixes”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Several runs could store or replay wrong bytes under a green result. A
file added under an input glob while the command ran is now caught and
the save withheld. Committed files under a &lt;code dir=&quot;auto&quot;&gt;node_modules&lt;/code&gt; directory, such
as test fixtures, are part of the key again. The clean before a run no
longer follows an output directory linked to another directory in the
project. A dependant that deletes its upstream’s files no longer gets
them restored on every hit.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:18ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--all&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx run build --all&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/2854&quot;&gt;#2854&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2793&quot;&gt;#2793&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2795&quot;&gt;#2795&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2822&quot;&gt;#2822&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2823&quot;&gt;#2823&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;breaking-changes&quot;&gt;Breaking changes&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#breaking-changes&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Breaking changes”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;CACHE_VERSION&lt;/code&gt; is now &lt;code dir=&quot;auto&quot;&gt;vx-cache-v40&lt;/code&gt;: every cached task misses once after
the upgrade (&lt;a href=&quot;https://github.com/vznjs/vx/pull/2825&quot;&gt;#2825&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See &lt;a href=&quot;../../guides/upgrading/&quot;&gt;Upgrading&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;how-to-update&quot;&gt;How to update&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#how-to-update&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “How to update”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:29ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;-D&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;@vzn/vx@latest&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm install -D @vzn/vx@latest&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;A standalone binary updates itself with &lt;code dir=&quot;auto&quot;&gt;vx upgrade&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;learn-more&quot;&gt;Learn more&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#learn-more&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Learn more”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;../../quickstart/&quot;&gt;Quickstart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../../benchmarks/&quot;&gt;Benchmarks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/vznjs/vx/releases&quot;&gt;Every release on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item>
<item><title>One cache for every checkout</title><link>https://vznjs.github.io/vx/releases/vx-0-0-520/</link><guid isPermaLink="true">https://vznjs.github.io/vx/releases/vx-0-0-520/</guid><description>The cache moves to ~/.vx and is shared by every checkout of a repo, --affected follows task edges, and npx @vzn/vx-migrate does the whole adoption.</description><pubDate>Tue, 06 Oct 2026 12:00:00 GMT</pubDate><category>release</category><content:encoded>&lt;p&gt;vx 0.0.496 to 0.0.520 shipped from October 4 to October 6, 2026. The theme
is less setup and less noise: every clone and worktree of a repo now shares
one cache, &lt;code dir=&quot;auto&quot;&gt;--affected&lt;/code&gt; picks tasks instead of packages, one command moves
a Turbo or Nx setup to vx, and the run summary is the last thing a run
prints.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this release&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#one-cache-for-every-checkout&quot;&gt;One cache for every checkout&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#affected-runs-follow-task-edges&quot;&gt;Affected runs follow task edges&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#vx-migrate-does-the-whole-adoption&quot;&gt;vx-migrate does the whole adoption&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#the-summary-is-the-last-line&quot;&gt;The summary is the last line&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#restored-and-up-to-date-hits-everywhere&quot;&gt;Restored and up-to-date hits everywhere&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#vznvx-github-is-now-vznvx-ci&quot;&gt;@vzn/vx-github is now @vzn/vx-ci&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#task-metrics-and-linked-spans-in-opentelemetry&quot;&gt;Task metrics and linked spans in OpenTelemetry&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#less-cpu-per-cold-miss&quot;&gt;Less CPU per cold miss&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#fixes&quot;&gt;Fixes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;one-cache-for-every-checkout&quot;&gt;One cache for every checkout&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#one-cache-for-every-checkout&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “One cache for every checkout”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Cache entries now live in &lt;code dir=&quot;auto&quot;&gt;~/.vx/&amp;#x3C;id&gt;/cache&lt;/code&gt;, like Nx. The id comes from
the git remote and the workspace’s path in the repo (or the first commit
when there is no remote), so clones and worktrees of one repo hit each
other’s entries. &lt;code dir=&quot;auto&quot;&gt;cacheDir&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;VX_CACHE_DIR&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;--cache-dir&lt;/code&gt; still keep the
whole cache in one directory of your choosing. A store or index from
another schema version is now reset instead of refusing the run, and its
artifacts are indexed again on their next hit, so a schema change no
longer throws the artifacts away.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://vznjs.github.io/vx/_astro/ec.w36nc.css&quot;&gt;&lt;figure class=&quot;frame has-title not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;vx.workspace.ts&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:72ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { defineWorkspace } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx/config&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;defineWorkspace&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;cacheDir: &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;build/.vx&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#919F9F;--1:#5D6376&quot;&gt;// unset: ~/.vx/&amp;#x3C;id&gt;/cache, shared by checkouts&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import { defineWorkspace } from &amp;#x27;@vzn/vx/config&amp;#x27;export default defineWorkspace({  cacheDir: &amp;#x27;build/.vx&amp;#x27;, // unset: ~/.vx/&lt;id&gt;/cache, shared by checkouts})&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;pre class=&quot;mermaid&quot; role=&quot;img&quot; aria-label=&quot;diagram&quot;&gt;flowchart LR
  A[&quot;~/code/app&quot;] --&gt; C[(&quot;~/.vx/&amp;#x26;lt;id&amp;#x26;gt;/cache&quot;)]
  R[&quot;worktree: app-review&quot;] --&gt; C
  H[&quot;worktree: app-hotfix&quot;] --&gt; C&lt;/pre&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/2773&quot;&gt;#2773&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2775&quot;&gt;#2775&lt;/a&gt;. Docs:
&lt;a href=&quot;../../guides/configure/#workspace-config&quot;&gt;Workspace config&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;affected-runs-follow-task-edges&quot;&gt;Affected runs follow task edges&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#affected-runs-follow-task-edges&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Affected runs follow task edges”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;--affected&lt;/code&gt; now selects tasks, not packages. A changed file seeds the tasks
whose declared inputs match it, and a requested task runs when its
&lt;code dir=&quot;auto&quot;&gt;dependsOn&lt;/code&gt; closure holds a seeded one. A package with no &lt;code dir=&quot;auto&quot;&gt;build&lt;/code&gt; task gets a
default build group behind &lt;code dir=&quot;auto&quot;&gt;^build&lt;/code&gt;, keyed on every file of the package. So a
package consumed as source still moves its dependants’ keys: here &lt;code dir=&quot;auto&quot;&gt;ui&lt;/code&gt; has no
tasks, and an edit to it re-runs &lt;code dir=&quot;auto&quot;&gt;app#test&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:32ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C5E478;--1:#3B61B0&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#7FDBCA;--1:#096E72&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;packages/ui/src/i.ts&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;test&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--affected=HEAD&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;echo &amp;#x27;x&amp;#x27; &gt;&gt; packages/ui/src/i.tsvx run test --affected=HEAD&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:37ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:1ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;⏺︎     7ms success miss     app#test&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;⏺︎     7ms success miss     app#test&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/2770&quot;&gt;#2770&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;vx-migrate-does-the-whole-adoption&quot;&gt;vx-migrate does the whole adoption&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#vx-migrate-does-the-whole-adoption&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “vx-migrate does the whole adoption”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;npx @vzn/vx-migrate&lt;/code&gt; now asks whether to migrate natively (a
&lt;code dir=&quot;auto&quot;&gt;vx.config.ts&lt;/code&gt; per package) or keep &lt;code dir=&quot;auto&quot;&gt;turbo.json&lt;/code&gt; / &lt;code dir=&quot;auto&quot;&gt;nx.json&lt;/code&gt; as the source.
&lt;code dir=&quot;auto&quot;&gt;--native&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;--keep&lt;/code&gt; answer it; without a terminal it is native. It
installs vx with the repo’s own package manager (&lt;code dir=&quot;auto&quot;&gt;--no-install&lt;/code&gt; skips that)
and leaves your &lt;code dir=&quot;auto&quot;&gt;package.json&lt;/code&gt; scripts alone.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:28ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;npx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;@vzn/vx-migrate&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--native&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npx @vzn/vx-migrate --native&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/2771&quot;&gt;#2771&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2772&quot;&gt;#2772&lt;/a&gt;. Docs:
&lt;a href=&quot;../../guides/migrate/#one-command&quot;&gt;One command&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;the-summary-is-the-last-line&quot;&gt;The summary is the last line&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#the-summary-is-the-last-line&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “The summary is the last line”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Nothing prints below the end-of-run summary anymore. Aborted and unstarted
tasks are rows in the task list with their own status, a skipped task names
its blocker, and a flaky task carries a note on its row. Warnings from
uploads, plugin teardown and history land above the summary. The failure
recap is gone: each failure’s output already prints above it.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:62ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:1ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;◼︎    11ms failed  miss     a#build&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:1ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;⊘         skipped          b#build • blocked by a#build&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;┌─ a#build &gt; failed (exit 1)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;$ mkdir -p dist &amp;#x26;&amp;#x26; cp src/i.ts dist/ &amp;#x26;&amp;#x26; exit 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;└─ a#build ── (11ms) failed (exit 1)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;─ vx 0.0.0 ───────────────────────────────────────────────────&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;projects  ▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:12ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;2 in run · 2 total&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;tasks     ▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:12ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;1 failed · 1 skipped · 2 total&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;cache     ▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:12ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;1 miss · 1 skipped&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;info      4 workers · local cache&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;time      56ms · max 11ms · avg 11ms · min 11ms&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;result    2 tasks · 1 failed · 0 cached (0%) · 56ms&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;◼︎    11ms failed  miss     a#build ⊘         skipped          b#build • blocked by a#build┌─ a#build &gt; failed (exit 1)$ mkdir -p dist &amp;#x26;&amp;#x26; cp src/i.ts dist/ &amp;#x26;&amp;#x26; exit 1└─ a#build ── (11ms) failed (exit 1)─ vx 0.0.0 ───────────────────────────────────────────────────  projects  ▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰            2 in run · 2 total  tasks     ▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰            1 failed · 1 skipped · 2 total  cache     ▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰            1 miss · 1 skipped  info      4 workers · local cache  time      56ms · max 11ms · avg 11ms · min 11ms  result    2 tasks · 1 failed · 0 cached (0%) · 56ms&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/2752&quot;&gt;#2752&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2757&quot;&gt;#2757&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2780&quot;&gt;#2780&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2781&quot;&gt;#2781&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;restored-and-up-to-date-hits-everywhere&quot;&gt;Restored and up-to-date hits everywhere&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#restored-and-up-to-date-hits-everywhere&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Restored and up-to-date hits everywhere”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A hit either found its outputs in place (up-to-date) or restored them from
the cache. Only the live summary told them apart before. The run history
now stores the split, so &lt;code dir=&quot;auto&quot;&gt;vx last&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;vx info&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;vx why&lt;/code&gt;, the markdown
report, &lt;code dir=&quot;auto&quot;&gt;vx mcp&lt;/code&gt; and the plugins all show it.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:64ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;$ vx last&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;2 tasks · 2 hits (0 up-to-date, 2 restored: 2 local, 0 remote)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;restored-local    a#build      17ms  73b25577a99ad2f8&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;restored-local    b#build      13ms  4935028bcd991dbd&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;$ vx last  2 tasks · 2 hits (0 up-to-date, 2 restored: 2 local, 0 remote)  restored-local    a#build      17ms  73b25577a99ad2f8  restored-local    b#build      13ms  4935028bcd991dbd&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Commit
&lt;a href=&quot;https://github.com/vznjs/vx/commit/f336e9f3e06bc6f9ca8d4dc615c92aaa0f968585&quot;&gt;f336e9f&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;vznvx-github-is-now-vznvx-ci&quot;&gt;@vzn/vx-github is now @vzn/vx-ci&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#vznvx-github-is-now-vznvx-ci&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “@vzn/vx-github is now @vzn/vx-ci”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;The GitHub Actions plugin has a new package name. The &lt;code dir=&quot;auto&quot;&gt;github()&lt;/code&gt; export is
unchanged, so only the import moves.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;vx.workspace.ts&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:55ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { defineWorkspace } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx/config&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { github } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx-ci&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;defineWorkspace&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;({ plugins: [&lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;github&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;()] })&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import { defineWorkspace } from &amp;#x27;@vzn/vx/config&amp;#x27;import { github } from &amp;#x27;@vzn/vx-ci&amp;#x27;export default defineWorkspace({ plugins: [github()] })&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/2782&quot;&gt;#2782&lt;/a&gt;. Docs:
&lt;a href=&quot;../../guides/ci/#github-actions&quot;&gt;GitHub Actions&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;task-metrics-and-linked-spans-in-opentelemetry&quot;&gt;Task metrics and linked spans in OpenTelemetry&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#task-metrics-and-linked-spans-in-opentelemetry&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Task metrics and linked spans in OpenTelemetry”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;@vzn/vx-otel&lt;/code&gt; now sends per-task metrics: duration, CPU time and peak
memory at each task’s end, and CPU usage and memory each second while it
runs, so a metrics backend can chart them. A task span links to the tasks
it waited on, records each failed attempt as a &lt;code dir=&quot;auto&quot;&gt;vx.task.retry&lt;/code&gt; event, and
each &lt;code dir=&quot;auto&quot;&gt;VX_TIMING&lt;/code&gt; stage is a child span of the run.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:68ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C5E478;--1:#3B61B0&quot;&gt;OTEL_EXPORTER_OTLP_ENDPOINT&lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;http://localhost:4318&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--all&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 vx run build --all&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/2783&quot;&gt;#2783&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2784&quot;&gt;#2784&lt;/a&gt;. Docs:
&lt;a href=&quot;../../guides/plugins/#opentelemetry&quot;&gt;OpenTelemetry&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;less-cpu-per-cold-miss&quot;&gt;Less CPU per cold miss&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#less-cpu-per-cold-miss&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Less CPU per cold miss”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A cold run does less work per task: no deferred closure walk when nothing
is deferred, upstream outputs read only for a plugin executor, and small
artifacts packed on the calling thread. On macOS tasks run under &lt;code dir=&quot;auto&quot;&gt;dash&lt;/code&gt;
when it is on &lt;code dir=&quot;auto&quot;&gt;PATH&lt;/code&gt;. vx’s own cold CPU on 1,090 packages went from 6.85 s
to 5.7 s.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:26ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--all&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--force&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx run build --all --force&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;vx-charts&quot;&gt;&lt;figure class=&quot;vx-bars&quot;&gt;&lt;figcaption&gt;vx cold CPU, 1,090 packages&lt;/figcaption&gt;&lt;div class=&quot;vx-bar&quot; style=&quot;--w:100%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;before&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;6.85 s&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;vx-bar vx-bar-lead&quot; style=&quot;--w:83.2%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;after&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;5.7 s&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/2767&quot;&gt;#2767&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;fixes&quot;&gt;Fixes&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#fixes&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Fixes”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;An extglob such as &lt;code dir=&quot;auto&quot;&gt;src/@(x|y).ts&lt;/code&gt; in a task glob matched no file, so an
edit replayed a stale hit. vx now refuses it at load and suggests the
brace form (&lt;a href=&quot;https://github.com/vznjs/vx/pull/2768&quot;&gt;#2768&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Tasks get &lt;code dir=&quot;auto&quot;&gt;npm_execpath&lt;/code&gt; for the repo’s package manager, so tools like
&lt;code dir=&quot;auto&quot;&gt;npm-run-all&lt;/code&gt; call back pnpm or bun instead of a global npm
(&lt;a href=&quot;https://github.com/vznjs/vx/pull/2774&quot;&gt;#2774&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;On macOS a wildcard write grant in the sandbox now covers what is inside
the directories it matches, which pnpm’s lock files need
(&lt;a href=&quot;https://github.com/vznjs/vx/commit/c931a094303928046d9067d5278eefef8d6e2913&quot;&gt;c931a09&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:79ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;cache: { inputs: { files: [&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;src/{x,y}.ts&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;] }, outputs: { files: [&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;dist/**&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;] } }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;cache: { inputs: { files: [&amp;#x27;src/{x,y}.ts&amp;#x27;] }, outputs: { files: [&amp;#x27;dist/**&amp;#x27;] } }&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;breaking-changes&quot;&gt;Breaking changes&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#breaking-changes&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Breaking changes”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;@vzn/vx-github&lt;/code&gt; is now &lt;code dir=&quot;auto&quot;&gt;@vzn/vx-ci&lt;/code&gt;; &lt;code dir=&quot;auto&quot;&gt;github()&lt;/code&gt; is unchanged.&lt;/li&gt;
&lt;li&gt;The cache moves to &lt;code dir=&quot;auto&quot;&gt;~/.vx/&amp;#x3C;id&gt;/cache&lt;/code&gt;; existing entries miss once.&lt;/li&gt;
&lt;li&gt;The run history gains hit counts; an older index is dropped once.&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;Cache.getMany&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;CacheLayer.getMany&lt;/code&gt; take an optional get context.&lt;/li&gt;
&lt;li&gt;The end-of-run failure recap and &lt;code dir=&quot;auto&quot;&gt;formatFailureRecap&lt;/code&gt; are removed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See &lt;a href=&quot;../../guides/upgrading/&quot;&gt;Upgrading&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;how-to-update&quot;&gt;How to update&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#how-to-update&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “How to update”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:29ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;-D&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;@vzn/vx@latest&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm install -D @vzn/vx@latest&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;A standalone binary updates itself with &lt;code dir=&quot;auto&quot;&gt;vx upgrade&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;learn-more&quot;&gt;Learn more&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#learn-more&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Learn more”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;../../quickstart/&quot;&gt;Quickstart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../../benchmarks/&quot;&gt;Benchmarks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/vznjs/vx/releases&quot;&gt;Every release on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item>
<item><title>Ready for Docker and pull requests</title><link>https://vznjs.github.io/vx/releases/vx-0-0-495/</link><guid isPermaLink="true">https://vznjs.github.io/vx/releases/vx-0-0-495/</guid><description>vx prune cuts a workspace and its lockfile for a Docker build, projects take tags you can filter on, and remote cache writes can be scoped per pull request.</description><pubDate>Sat, 03 Oct 2026 12:00:00 GMT</pubDate><category>release</category><content:encoded>&lt;p&gt;vx 0.0.361 to 0.0.495 all shipped on 2026-10-03. The theme is closing gaps
people hit when they move a Turbo or Nx repo over: a Docker prune, tags,
interactive tasks, Turbo’s range spelling, and a remote cache a PR cannot
poison. Dev servers, the sandbox and remote execution also tell you more
when something goes wrong.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this release&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#prune-a-workspace-for-docker&quot;&gt;Prune a workspace for Docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#project-tags&quot;&gt;Project tags&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#interactive-tasks&quot;&gt;Interactive tasks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#per-pr-remote-cache-scope&quot;&gt;Per-PR remote cache scope&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#colour-in-task-output-and-help&quot;&gt;Colour in task output and help&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#dev-servers-that-die-or-stall&quot;&gt;Dev servers that die or stall&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#turbo-style-affected-ranges&quot;&gt;Turbo-style affected ranges&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#a-sandbox-that-names-hidden-reads&quot;&gt;A sandbox that names hidden reads&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#remote-execution-falls-back-past-a-queue-bound&quot;&gt;Remote execution falls back past a queue bound&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#nx-your-own-executors-as-commands&quot;&gt;Nx: your own executors as commands&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;prune-a-workspace-for-docker&quot;&gt;Prune a workspace for Docker&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#prune-a-workspace-for-docker&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Prune a workspace for Docker”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Declaring &lt;code dir=&quot;auto&quot;&gt;pnpm()&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;bun()&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;npm()&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;yarn()&lt;/code&gt; from &lt;code dir=&quot;auto&quot;&gt;@vzn/vx-lockfile&lt;/code&gt;
now adds &lt;code dir=&quot;auto&quot;&gt;vx prune&lt;/code&gt;, vx’s answer to &lt;code dir=&quot;auto&quot;&gt;turbo prune&lt;/code&gt;. It copies the named
projects and their workspace dependencies to &lt;code dir=&quot;auto&quot;&gt;out/&lt;/code&gt;, and cuts each lockfile
to what that subset installs, so it still installs frozen. &lt;code dir=&quot;auto&quot;&gt;--docker&lt;/code&gt;
splits the copy into &lt;code dir=&quot;auto&quot;&gt;json/&lt;/code&gt; (manifests and lockfile, the cacheable install
layer) and &lt;code dir=&quot;auto&quot;&gt;full/&lt;/code&gt; (everything).&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://vznjs.github.io/vx/_astro/ec.w36nc.css&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:59ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;$ vx prune web --docker&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;vx prune: 2 projects → out (json/ + full/), bun.lock pruned&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;ui (packages/ui)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;web (packages/web)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;$ vx prune web --dockervx prune: 2 projects → out (json/ + full/), bun.lock pruned  ui (packages/ui)  web (packages/web)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;pre class=&quot;mermaid&quot; role=&quot;img&quot; aria-label=&quot;diagram&quot;&gt;flowchart LR
  W[&quot;workspace&quot;] --&gt;|&quot;vx prune web --docker&quot;| O[&quot;out/&quot;]
  O --&gt; J[&quot;json/ package.json files + lockfile&quot;]
  O --&gt; F[&quot;full/ ui and web sources&quot;]&lt;/pre&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/2750&quot;&gt;#2750&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;project-tags&quot;&gt;Project tags&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#project-tags&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Project tags”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A project config can carry &lt;code dir=&quot;auto&quot;&gt;tags&lt;/code&gt;, and &lt;code dir=&quot;auto&quot;&gt;--filter tag:&amp;#x3C;pattern&gt;&lt;/code&gt; selects the
projects holding a match, as Nx’s &lt;code dir=&quot;auto&quot;&gt;tag:&lt;/code&gt; does. &lt;code dir=&quot;auto&quot;&gt;vx show&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;vx mcp&lt;/code&gt; list
them, and the Nx adoption carries Nx tags over. Tags are in no cache key.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;packages/web/vx.config.ts&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:56ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { defineProject } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx/config&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;defineProject&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;tags: [&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;frontend&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;tasks: { build: { exec: { command: &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;vite build&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; } } },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import { defineProject } from &amp;#x27;@vzn/vx/config&amp;#x27;export default defineProject({  tags: [&amp;#x27;frontend&amp;#x27;],  tasks: { build: { exec: { command: &amp;#x27;vite build&amp;#x27; } } },})&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:38ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;$ vx run build --filter tag:frontend&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:1ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;⏺︎     7ms success no-cache ui#build&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:1ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;⏺︎     8ms success no-cache web#build&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;$ vx run build --filter tag:frontend ⏺︎     7ms success no-cache ui#build ⏺︎     8ms success no-cache web#build&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/2749&quot;&gt;#2749&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;interactive-tasks&quot;&gt;Interactive tasks&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#interactive-tasks&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Interactive tasks”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;exec.interactive: true&lt;/code&gt; marks a task that reads the terminal: a prompt, a
REPL, a watch mode’s keys. On a TTY it gets vx’s stdin, stdout and stderr,
and nothing else starts while it runs. It always runs on this machine and
is never cached or sandboxed. Off a TTY, on CI, it runs like any task. The
Turbo adoption maps Turbo’s &lt;code dir=&quot;auto&quot;&gt;interactive: true&lt;/code&gt; to it.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:72ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { defineProject } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx/config&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;defineProject&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;tasks: { repl: { exec: { command: &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;bun repl&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;, interactive: &lt;/span&gt;&lt;span style=&quot;--0:#FF6A83;--1:#A24848&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; } } },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import { defineProject } from &amp;#x27;@vzn/vx/config&amp;#x27;export default defineProject({  tasks: { repl: { exec: { command: &amp;#x27;bun repl&amp;#x27;, interactive: true } } },})&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/2748&quot;&gt;#2748&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;per-pr-remote-cache-scope&quot;&gt;Per-PR remote cache scope&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#per-pr-remote-cache-scope&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Per-PR remote cache scope”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;cacheScope&lt;/code&gt; decides where a run’s remote cache writes land. &lt;code dir=&quot;auto&quot;&gt;'trusted'&lt;/code&gt;
reads and writes the shared keys and is the default on CI. &lt;code dir=&quot;auto&quot;&gt;'read-only'&lt;/code&gt;
writes nothing and is the default off CI. Any other name, such as
&lt;code dir=&quot;auto&quot;&gt;'pr-123'&lt;/code&gt;, reads its own keys then the trusted ones, and writes only its
own, so a pull request never writes what the default branch reads. Set it
in &lt;code dir=&quot;auto&quot;&gt;vx.workspace.ts&lt;/code&gt;, with &lt;code dir=&quot;auto&quot;&gt;VX_CACHE_SCOPE&lt;/code&gt;, or let the &lt;code dir=&quot;auto&quot;&gt;github()&lt;/code&gt; plugin
(now &lt;code dir=&quot;auto&quot;&gt;@vzn/vx-ci&lt;/code&gt;) set it on Actions. It is a client-side convention: real
isolation needs a server that scopes writes by token.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:40ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C5E478;--1:#3B61B0&quot;&gt;VX_CACHE_SCOPE&lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;pr-123&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--all&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;VX_CACHE_SCOPE=pr-123 vx run build --all&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/2746&quot;&gt;#2746&lt;/a&gt;. See
&lt;a href=&quot;../../security/#cache-poisoning&quot;&gt;Cache poisoning&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;colour-in-task-output-and-help&quot;&gt;Colour in task output and help&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#colour-in-task-output-and-help&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Colour in task output and help”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A task’s stdout is a pipe, so tools printed plain under vx. Tasks now get
&lt;code dir=&quot;auto&quot;&gt;FORCE_COLOR=1&lt;/code&gt; unless they already see &lt;code dir=&quot;auto&quot;&gt;FORCE_COLOR&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;NO_COLOR&lt;/code&gt;, as
under Nx and Turbo. When vx’s own output is plain, it strips the escapes
from task output, live and replayed. &lt;code dir=&quot;auto&quot;&gt;vx help&lt;/code&gt; on a terminal now has bold
headings and cyan verbs, flags and examples; piped help stays plain.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:29ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C5E478;--1:#3B61B0&quot;&gt;NO_COLOR&lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--all&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;NO_COLOR=1 vx run build --all&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/2742&quot;&gt;#2742&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2744&quot;&gt;#2744&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;dev-servers-that-die-or-stall&quot;&gt;Dev servers that die or stall&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#dev-servers-that-die-or-stall&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Dev servers that die or stall”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A dependency server that crashed mid-run was named only at the end, while
its dependants failed with no word of why. vx now says so when it happens,
and dependants not yet started skip, named for the server. A server whose
&lt;code dir=&quot;auto&quot;&gt;readyWhen&lt;/code&gt; never matches no longer waits in silence: after 10 seconds vx
says what it waits for and whether anything bounds the wait.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:52ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;$ vx run web#e2e&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;┌─ web#e2e &gt; $ sleep 1; echo e2e done&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;vx: web#dev exited with code 3 while the run went on&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;e2e done&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;└─ web#e2e ── (1.01s) success&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;$ vx run web#e2e┌─ web#e2e &gt; $ sleep 1; echo e2e donevx: web#dev exited with code 3 while the run went one2e done└─ web#e2e ── (1.01s) success&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/2152&quot;&gt;#2152&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2338&quot;&gt;#2338&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2463&quot;&gt;#2463&lt;/a&gt;. Deep dive:
&lt;a href=&quot;../../blog/dev-servers-in-the-graph/&quot;&gt;Dev servers in the graph&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;turbo-style-affected-ranges&quot;&gt;Turbo-style affected ranges&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#turbo-style-affected-ranges&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Turbo-style affected ranges”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Turbo’s CI spelling &lt;code dir=&quot;auto&quot;&gt;--filter=[origin/main...HEAD]&lt;/code&gt; was refused as a range.
vx diffs a base against the working tree, so a range that ends at &lt;code dir=&quot;auto&quot;&gt;HEAD&lt;/code&gt;
means the same set plus any uncommitted edit. &lt;code dir=&quot;auto&quot;&gt;&amp;#x3C;base&gt;...HEAD&lt;/code&gt; and
&lt;code dir=&quot;auto&quot;&gt;&amp;#x3C;base&gt;..HEAD&lt;/code&gt; now work in &lt;code dir=&quot;auto&quot;&gt;--filter&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;--affected&lt;/code&gt;; a range that ends
anywhere else is still refused.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:41ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;test&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--affected=origin/main...HEAD&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx run test --affected=origin/main...HEAD&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/2149&quot;&gt;#2149&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2373&quot;&gt;#2373&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;a-sandbox-that-names-hidden-reads&quot;&gt;A sandbox that names hidden reads&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#a-sandbox-that-names-hidden-reads&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “A sandbox that names hidden reads”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A sandboxed task that failed on a read the sandbox hid saw only its tool’s
“File not found”: &lt;code dir=&quot;auto&quot;&gt;tsc&lt;/code&gt; extending a root &lt;code dir=&quot;auto&quot;&gt;tsconfig.base.json&lt;/code&gt; was the
common case. A failed task now names the hidden paths that exist on the
host and the grant to add. Separately, the host’s credential stores
(&lt;code dir=&quot;auto&quot;&gt;~/.ssh&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;~/.aws&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;~/.npmrc&lt;/code&gt; and the like) are now denied to sandboxed
tasks unless &lt;code dir=&quot;auto&quot;&gt;allow.read&lt;/code&gt; names one, so a dependency cannot copy a key into
a cached output.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:79ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;vx: the sandbox hid paths outside the project that exist on this machine,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;which are not reported as violations: /repo/tsconfig.base.json. If the&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;task reads one, grant it, e.g. `allow: { read: ['../../tsconfig.base.json'] }`.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx: the sandbox hid paths outside the project that exist on this machine,which are not reported as violations: /repo/tsconfig.base.json. If thetask reads one, grant it, e.g. &amp;#x60;allow: { read: [&amp;#x27;../../tsconfig.base.json&amp;#x27;] }&amp;#x60;.&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/2387&quot;&gt;#2387&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2344&quot;&gt;#2344&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2451&quot;&gt;#2451&lt;/a&gt;. See the
&lt;a href=&quot;../../guides/sandboxing/&quot;&gt;sandboxing guide&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;remote-execution-falls-back-past-a-queue-bound&quot;&gt;Remote execution falls back past a queue bound&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#remote-execution-falls-back-past-a-queue-bound&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Remote execution falls back past a queue bound”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;With &lt;code dir=&quot;auto&quot;&gt;@vzn/vx-reapi&lt;/code&gt;, an action no worker picked up waited without bound
unless the task set &lt;code dir=&quot;auto&quot;&gt;exec.timeout&lt;/code&gt;, and then it failed as timed out. The
new &lt;code dir=&quot;auto&quot;&gt;queueTimeoutMs&lt;/code&gt; bounds the wait for a worker. Past it, vx cancels the
remote operation, runs the task on this machine, and says why once. A task
placed &lt;code dir=&quot;auto&quot;&gt;exec.remote: 'only'&lt;/code&gt; fails with that reason instead.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;vx.workspace.ts&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:48ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { defineWorkspace } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx/config&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { reapi } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx-reapi&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;defineWorkspace&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;plugins: [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:4ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;reapi&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:6ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;endpoint: &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;grpcs://grpc.example.com:443&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:6ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;execute: &lt;/span&gt;&lt;span style=&quot;--0:#FF6A83;--1:#A24848&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:6ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;queueTimeoutMs: &lt;/span&gt;&lt;span style=&quot;--0:#F78C6C;--1:#AA0982&quot;&gt;60_000&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:4ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;}),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import { defineWorkspace } from &amp;#x27;@vzn/vx/config&amp;#x27;import { reapi } from &amp;#x27;@vzn/vx-reapi&amp;#x27;export default defineWorkspace({  plugins: [    reapi({      endpoint: &amp;#x27;grpcs://grpc.example.com:443&amp;#x27;,      execute: true,      queueTimeoutMs: 60_000,    }),  ],})&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/2716&quot;&gt;#2716&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2723&quot;&gt;#2723&lt;/a&gt;. Deep dive:
&lt;a href=&quot;../../blog/remote-execution/&quot;&gt;Remote execution&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;nx-your-own-executors-as-commands&quot;&gt;Nx: your own executors as commands&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#nx-your-own-executors-as-commands&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Nx: your own executors as commands”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;nx()&lt;/code&gt; runs every Nx executor through &lt;code dir=&quot;auto&quot;&gt;nx-exec&lt;/code&gt;, a Node boot per task. A
workspace’s own executor that only wraps a shell command can now skip that:
&lt;code dir=&quot;auto&quot;&gt;nx({ executors })&lt;/code&gt; takes a function per executor name that returns
&lt;code dir=&quot;auto&quot;&gt;{ command, timeout?, env? }&lt;/code&gt;, or &lt;code dir=&quot;auto&quot;&gt;undefined&lt;/code&gt; to leave the target to
&lt;code dir=&quot;auto&quot;&gt;nx-exec&lt;/code&gt;. Each function’s source text keys the cached mapping, so an edit
re-maps. Also, an Nx output that starts with a wildcard (&lt;code dir=&quot;auto&quot;&gt;**/*.d.ts&lt;/code&gt;) now
stays cached instead of turning the target uncached.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;vx.workspace.ts&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:77ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { defineWorkspace } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx/config&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { nx } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx-migrate&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;defineWorkspace&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;plugins: [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:4ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;nx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:6ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;executors: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:8ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@acme/tools:shell&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#D7DBE0;--1:#403F53&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; ({ command: &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;(t&lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#FAF39F;--1:#111111&quot;&gt;options&lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#7FDBCA;--1:#096E72&quot;&gt;command&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;) }),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:6ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:4ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;}),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import { defineWorkspace } from &amp;#x27;@vzn/vx/config&amp;#x27;import { nx } from &amp;#x27;@vzn/vx-migrate&amp;#x27;export default defineWorkspace({  plugins: [    nx({      executors: {        &amp;#x27;@acme/tools:shell&amp;#x27;: (t) =&gt; ({ command: String(t.options.command) }),      },    }),  ],})&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/2733&quot;&gt;#2733&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2736&quot;&gt;#2736&lt;/a&gt;. Deep dive:
&lt;a href=&quot;../../blog/from-nx/&quot;&gt;From Nx&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;breaking-changes&quot;&gt;Breaking changes&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#breaking-changes&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Breaking changes”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Core &lt;code dir=&quot;auto&quot;&gt;SCHEMA_VERSION&lt;/code&gt; v29 to v30: an older cache index is dropped on
first open (&lt;a href=&quot;https://github.com/vznjs/vx/pull/2246&quot;&gt;#2246&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;nx()&lt;/code&gt; migrations write &lt;code dir=&quot;auto&quot;&gt;nx-exec&lt;/code&gt; lines where they wrote executor
commands (&lt;a href=&quot;https://github.com/vznjs/vx/pull/2632&quot;&gt;#2632&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;vx init&lt;/code&gt; keeps existing configs and exits 0 instead of refusing with 1
(&lt;a href=&quot;https://github.com/vznjs/vx/pull/2546&quot;&gt;#2546&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;reapi()&lt;/code&gt; refuses &lt;code dir=&quot;auto&quot;&gt;onWarn&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;tlsCaPem&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;tlsClientCertPem&lt;/code&gt; and
&lt;code dir=&quot;auto&quot;&gt;tlsClientKeyPem&lt;/code&gt;; use the file options
(&lt;a href=&quot;https://github.com/vznjs/vx/pull/2535&quot;&gt;#2535&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;@vzn/vx-reapi&lt;/code&gt;’s plugin-api record drops the &lt;code dir=&quot;auto&quot;&gt;WireOnly&lt;/code&gt; type
(&lt;a href=&quot;https://github.com/vznjs/vx/pull/2541&quot;&gt;#2541&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;refuseUnknownOptions&lt;/code&gt; takes a &lt;code dir=&quot;auto&quot;&gt;PluginOptionKinds&lt;/code&gt; record, and a plugin
option of the wrong kind is refused
(&lt;a href=&quot;https://github.com/vznjs/vx/pull/2475&quot;&gt;#2475&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;@vzn/vx-reapi&lt;/code&gt; stops exporting its wire and Merkle internals
(&lt;a href=&quot;https://github.com/vznjs/vx/pull/2521&quot;&gt;#2521&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;@vzn/vx-migrate&lt;/code&gt; exports only its four plugins
(&lt;a href=&quot;https://github.com/vznjs/vx/pull/2520&quot;&gt;#2520&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;@vzn/vx-lockfile&lt;/code&gt; stops exporting its parser namespaces
(&lt;a href=&quot;https://github.com/vznjs/vx/pull/2512&quot;&gt;#2512&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;@vzn/vx-otel&lt;/code&gt; stops exporting its OTLP builders
(&lt;a href=&quot;https://github.com/vznjs/vx/pull/2508&quot;&gt;#2508&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;@vzn/vx-github&lt;/code&gt; stops exporting its Checks API helpers
(&lt;a href=&quot;https://github.com/vznjs/vx/pull/2503&quot;&gt;#2503&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See &lt;a href=&quot;../../guides/upgrading/&quot;&gt;Upgrading&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;how-to-update&quot;&gt;How to update&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#how-to-update&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “How to update”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:29ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;-D&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;@vzn/vx@latest&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm install -D @vzn/vx@latest&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;A standalone binary updates itself with &lt;code dir=&quot;auto&quot;&gt;vx upgrade&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;learn-more&quot;&gt;Learn more&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#learn-more&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Learn more”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;../../quickstart/&quot;&gt;Quickstart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../../benchmarks/&quot;&gt;Benchmarks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/vznjs/vx/releases&quot;&gt;Every release on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item>
<item><title>The Turbo and Nx flags you already type</title><link>https://vznjs.github.io/vx/releases/vx-0-0-360/</link><guid isPermaLink="true">https://vznjs.github.io/vx/releases/vx-0-0-360/</guid><description>vx 0.0.326 to 0.0.360 migrate Nx executor targets as the commands they run, accept the --filter and flag spellings Turbo, pnpm and Nx users already type, and cut a scoped run on 1,000 projects from 181 ms to 113 ms.</description><pubDate>Fri, 02 Oct 2026 12:00:00 GMT</pubDate><category>release</category><content:encoded>&lt;p&gt;vx 0.0.326 to 0.0.360 all shipped on 2 October 2026. The theme is moving
in: migrations write configs that run without Nx or Turbo installed, the
CLI takes the selections you already know, and long-running dev servers
behave. Windows is now supported through WSL only.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this release&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#nx-targets-migrate-as-plain-commands&quot;&gt;Nx targets migrate as plain commands&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#cleaner-turbo-migrations&quot;&gt;Cleaner Turbo migrations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#filters-and-flags-from-turbo-pnpm-and-nx&quot;&gt;Filters and flags from Turbo, pnpm and Nx&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#affected-runs-compare-with-the-trunk&quot;&gt;Affected runs compare with the trunk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#dev-servers-you-can-rely-on&quot;&gt;Dev servers you can rely on&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#faster-scoped-runs&quot;&gt;Faster scoped runs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#secrets-masked-in-run-history&quot;&gt;Secrets masked in run history&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#vx-init-maps-more-repos&quot;&gt;vx init maps more repos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#sandboxed-tasks-run-once&quot;&gt;Sandboxed tasks run once&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#reftable-repositories&quot;&gt;Reftable repositories&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;nx-targets-migrate-as-plain-commands&quot;&gt;Nx targets migrate as plain commands&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#nx-targets-migrate-as-plain-commands&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Nx targets migrate as plain commands”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;bunx @vzn/vx-migrate&lt;/code&gt; used to write every Nx executor target as an
&lt;code dir=&quot;auto&quot;&gt;nx-exec&lt;/code&gt; line, so the migrated config still needed Nx to run. It now
writes the command the executor drives, with the defaults Nx applies:
jest, vitest, vite build, eslint, tsc, playwright, esbuild, swc, Next.js,
Cypress, Storybook, and the Vite dev and preview servers. &lt;code dir=&quot;auto&quot;&gt;@nx/js:node&lt;/code&gt;
becomes &lt;code dir=&quot;auto&quot;&gt;node&lt;/code&gt; on the build output, as a persistent task. Webpack and
Rollup targets name Nx’s &lt;code dir=&quot;auto&quot;&gt;convert-to-inferred&lt;/code&gt; generator in their TODO,
and &lt;code dir=&quot;auto&quot;&gt;nx-release-publish&lt;/code&gt; gets one note instead of a failing task per
package. &lt;code dir=&quot;auto&quot;&gt;nx()&lt;/code&gt; still runs executors through &lt;code dir=&quot;auto&quot;&gt;nx-exec&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://vznjs.github.io/vx/_astro/ec.w36nc.css&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:20ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;bunx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;@vzn/vx-migrate&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--all&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;bunx @vzn/vx-migratevx run build --all&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/2298&quot;&gt;#2298&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2333&quot;&gt;#2333&lt;/a&gt;. Guide:
&lt;a href=&quot;../../guides/migrate/#nx&quot;&gt;Nx&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;cleaner-turbo-migrations&quot;&gt;Cleaner Turbo migrations&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#cleaner-turbo-migrations&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Cleaner Turbo migrations”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A task env that several packages share is now one export in
&lt;code dir=&quot;auto&quot;&gt;vx-preset.ts&lt;/code&gt; instead of a copy in every config: vercel/ai’s output
is 2× smaller, with every key unchanged. The &lt;code dir=&quot;auto&quot;&gt;.env&lt;/code&gt; probes are named exports
too (&lt;code dir=&quot;auto&quot;&gt;dotenvFiles&lt;/code&gt;). Framework variables Turbo infers, such as Next’s
&lt;code dir=&quot;auto&quot;&gt;NEXT_PUBLIC_*&lt;/code&gt;, are written out from the names your source and its
workspace dependencies spell, so a migrated Next build no longer inlines
them empty. The report also names the &lt;code dir=&quot;auto&quot;&gt;@vzn/vx-lockfile&lt;/code&gt; plugin your
lockfile needs, and says when &lt;code dir=&quot;auto&quot;&gt;turbo()&lt;/code&gt; is redundant once the configs
are written.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:19ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;npx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;@vzn/vx-migrate&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npx @vzn/vx-migrate&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/2207&quot;&gt;#2207&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2217&quot;&gt;#2217&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2218&quot;&gt;#2218&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2225&quot;&gt;#2225&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2319&quot;&gt;#2319&lt;/a&gt;. Guide:
&lt;a href=&quot;../../guides/migrate/#turborepo&quot;&gt;Turborepo&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;filters-and-flags-from-turbo-pnpm-and-nx&quot;&gt;Filters and flags from Turbo, pnpm and Nx&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#filters-and-flags-from-turbo-pnpm-and-nx&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Filters and flags from Turbo, pnpm and Nx”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;--filter&lt;/code&gt; now reads Turbo’s &lt;code dir=&quot;auto&quot;&gt;&amp;#x3C;name&gt;...[ref]&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;...x...&lt;/code&gt; forms as Turbo
does, matches a name without its scope as pnpm does (&lt;code dir=&quot;auto&quot;&gt;cart&lt;/code&gt; finds
&lt;code dir=&quot;auto&quot;&gt;@shop/cart&lt;/code&gt;), and lets a trailing &lt;code dir=&quot;auto&quot;&gt;**&lt;/code&gt; in a path match its base
directory. &lt;code dir=&quot;auto&quot;&gt;vx run&lt;/code&gt; takes Nx’s camelCase flags (&lt;code dir=&quot;auto&quot;&gt;--skipNxCache&lt;/code&gt;,
&lt;code dir=&quot;auto&quot;&gt;--nxBail&lt;/code&gt;) and Nx short project names in &lt;code dir=&quot;auto&quot;&gt;cart:build&lt;/code&gt;. Every flag in
Turbo 2.11’s run help now either works or is refused with the vx way to
do it.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:89ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;$ vx run build --heap&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;vx run: --heap (turbo): use `--profile[=&amp;#x3C;path&gt;]` for vx's own trace (see `vx run --help`)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;$ vx run build --heapvx run: --heap (turbo): use &amp;#x60;--profile[=&lt;path&gt;]&amp;#x60; for vx&amp;#x27;s own trace (see &amp;#x60;vx run --help&amp;#x60;)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/2015&quot;&gt;#2015&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2016&quot;&gt;#2016&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2017&quot;&gt;#2017&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2018&quot;&gt;#2018&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2041&quot;&gt;#2041&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2055&quot;&gt;#2055&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;affected-runs-compare-with-the-trunk&quot;&gt;Affected runs compare with the trunk&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#affected-runs-compare-with-the-trunk&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Affected runs compare with the trunk”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;With no &lt;code dir=&quot;auto&quot;&gt;origin/HEAD&lt;/code&gt; (no remote, or the fetch &lt;code dir=&quot;auto&quot;&gt;actions/checkout&lt;/code&gt; does),
a bare &lt;code dir=&quot;auto&quot;&gt;--affected&lt;/code&gt; compared with &lt;code dir=&quot;auto&quot;&gt;HEAD~1&lt;/code&gt; and saw only a branch’s last
commit. It now compares with the first trunk branch that is not HEAD, as
Turbo and Nx do. On a one-commit shallow clone, vx says the history is
missing instead of only that the ref did not resolve. Under &lt;code dir=&quot;auto&quot;&gt;turbo()&lt;/code&gt; on
GitHub Actions, the base is the pull request’s base or the push’s
&lt;code dir=&quot;auto&quot;&gt;before&lt;/code&gt;, as Turbo picks it.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:22ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;test&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--affected&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx run test --affected&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/2088&quot;&gt;#2088&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2122&quot;&gt;#2122&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2287&quot;&gt;#2287&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;dev-servers-you-can-rely-on&quot;&gt;Dev servers you can rely on&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#dev-servers-you-can-rely-on&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Dev servers you can rely on”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A server vx keeps after the summary now streams its output line by line
instead of showing nothing. One that crashes after the summary counts as
failed in &lt;code dir=&quot;auto&quot;&gt;--summarize&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;--report&lt;/code&gt;. When another task in the run
fails, vx stops the servers and exits 1 instead of holding them forever.
&lt;code dir=&quot;auto&quot;&gt;vx run app#dev&lt;/code&gt; over a &lt;code dir=&quot;auto&quot;&gt;dependsOn: ['^dev']&lt;/code&gt; group now keeps the
servers it stands for.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:16ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;dev&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--all&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx run dev --all&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/2030&quot;&gt;#2030&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2039&quot;&gt;#2039&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2054&quot;&gt;#2054&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2096&quot;&gt;#2096&lt;/a&gt;. Deep dive:
&lt;a href=&quot;../../blog/dev-servers-in-the-graph/&quot;&gt;Dev servers in the graph&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;faster-scoped-runs&quot;&gt;Faster scoped runs&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#faster-scoped-runs&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Faster scoped runs”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A run scoped to one package no longer walks git over its whole
dependency closure, only over the projects that own a task, and it finds
that closure by search instead of building it for the whole graph. On
1,000 projects, a warm &lt;code dir=&quot;auto&quot;&gt;vx run build --filter pkg-500&lt;/code&gt; went from 181 ms
to 113 ms. A plain repository’s git facts are read off the disk instead
of from a &lt;code dir=&quot;auto&quot;&gt;git rev-parse&lt;/code&gt; spawn, and a cold load imports 128 configs at a
time.&lt;/p&gt;
&lt;p&gt;A warm frozen run also keeps its lock check from one run to the next.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:29ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--filter&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;pkg-500&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx run build --filter pkg-500&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;vx-charts&quot;&gt;&lt;figure class=&quot;vx-bars&quot;&gt;&lt;figcaption&gt;Warm vx run build --filter pkg-500, 1,000 projects&lt;/figcaption&gt;&lt;div class=&quot;vx-bar&quot; style=&quot;--w:100%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;before&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;181 ms&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;vx-bar vx-bar-lead&quot; style=&quot;--w:62.4%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;after&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;113 ms&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/2035&quot;&gt;#2035&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2241&quot;&gt;#2241&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2306&quot;&gt;#2306&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2323&quot;&gt;#2323&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2329&quot;&gt;#2329&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;secrets-masked-in-run-history&quot;&gt;Secrets masked in run history&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#secrets-masked-in-run-history&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Secrets masked in run history”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;The invocation line vx stores and &lt;code dir=&quot;auto&quot;&gt;vx last&lt;/code&gt; prints kept a secret passed
after &lt;code dir=&quot;auto&quot;&gt;--&lt;/code&gt; whole, while the task’s own output masked it. It is now masked
with the same rule before it is recorded. &lt;code dir=&quot;auto&quot;&gt;--tag&lt;/code&gt; values, stored on the
history row and sent to telemetry, are masked too.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:36ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;publish&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--1:#3B61B0&quot;&gt;&lt;span style=&quot;--0:#82AAFF&quot;&gt;--token=&lt;/span&gt;&lt;span style=&quot;--0:#C5E478&quot;&gt;$NPM_TOKEN&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;last&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx run publish -- --token=$NPM_TOKENvx last&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/2307&quot;&gt;#2307&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2337&quot;&gt;#2337&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;vx-init-maps-more-repos&quot;&gt;vx init maps more repos&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#vx-init-maps-more-repos&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “vx init maps more repos”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;vx init&lt;/code&gt; now maps a script that runs a server as a persistent task, so
a dependent no longer waits on it forever. A build’s output directory is
guessed from its own command when no framework rule names one. The
&lt;code dir=&quot;auto&quot;&gt;next:&lt;/code&gt; line it prints is runnable, naming &lt;code dir=&quot;auto&quot;&gt;git init&lt;/code&gt; first when needed.
It names Yarn Plug’n’Play when that is why a config cannot load, and
&lt;code dir=&quot;auto&quot;&gt;vx.config.cjs&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;vx.config.cts&lt;/code&gt; are read as configs.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:7ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;init&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx init&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/2070&quot;&gt;#2070&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2098&quot;&gt;#2098&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2100&quot;&gt;#2100&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2169&quot;&gt;#2169&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2290&quot;&gt;#2290&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2308&quot;&gt;#2308&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;sandboxed-tasks-run-once&quot;&gt;Sandboxed tasks run once&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#sandboxed-tasks-run-once&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Sandboxed tasks run once”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A strace that warns it cannot check the seccomp filter order still works,
but vx read the warning as a tracer failure and ran every sandboxed task
twice. vx now uses such a strace only when it is quiet, and otherwise runs
tasks untraced. A task with a port bridge also waits for its host listener
before it starts, so a server’s port no longer refuses its first
connection under load.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:17ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;test&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--all&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx run test --all&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/2121&quot;&gt;#2121&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2130&quot;&gt;#2130&lt;/a&gt;. Deep dive:
&lt;a href=&quot;../../blog/the-sandbox/&quot;&gt;The sandbox&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;reftable-repositories&quot;&gt;Reftable repositories&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#reftable-repositories&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Reftable repositories”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Git 2.45 can store refs as a reftable (&lt;code dir=&quot;auto&quot;&gt;--ref-format=reftable&lt;/code&gt;). vx read
HEAD from the ref files, which a reftable repository does not keep, and
&lt;code dir=&quot;auto&quot;&gt;vx-migrate&lt;/code&gt; missed branch moves. Both now handle it; keys, cache hits and
&lt;code dir=&quot;auto&quot;&gt;--affected&lt;/code&gt; match a normal repository.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:30ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--ref-format=reftable&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;git init --ref-format=reftable&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/2318&quot;&gt;#2318&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;breaking-changes&quot;&gt;Breaking changes&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#breaking-changes&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Breaking changes”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Native Windows is unsupported; run vx under WSL. Tasks no longer get
&lt;code dir=&quot;auto&quot;&gt;SYSTEMROOT&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;APPDATA&lt;/code&gt; and the other Windows env vars
(&lt;a href=&quot;https://github.com/vznjs/vx/pull/2227&quot;&gt;#2227&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See &lt;a href=&quot;../../guides/upgrading/&quot;&gt;Upgrading&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;how-to-update&quot;&gt;How to update&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#how-to-update&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “How to update”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:29ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;-D&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;@vzn/vx@latest&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm install -D @vzn/vx@latest&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;A standalone binary updates itself with &lt;code dir=&quot;auto&quot;&gt;vx upgrade&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;learn-more&quot;&gt;Learn more&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#learn-more&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Learn more”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;../../quickstart/&quot;&gt;Quickstart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../../benchmarks/&quot;&gt;Benchmarks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/vznjs/vx/releases&quot;&gt;Every release on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item>
<item><title>Fewer surprises when you switch</title><link>https://vznjs.github.io/vx/releases/vx-0-0-325/</link><guid isPermaLink="true">https://vznjs.github.io/vx/releases/vx-0-0-325/</guid><description>vx init maps a root package.json's repo-wide scripts, a bare --affected takes its base from affectedBase, and Turbo and Nx commands, flags and cache switches now land where you expect.</description><pubDate>Thu, 01 Oct 2026 12:00:00 GMT</pubDate><category>release</category><content:encoded>&lt;p&gt;vx 0.0.243 to 0.0.325 all shipped on 2026-10-01. The theme is adoption:
moving from Turbo or Nx to vx has fewer surprises, from the
first &lt;code dir=&quot;auto&quot;&gt;vx init&lt;/code&gt; to the CI job that must not write the shared cache.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this release&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#root-scripts-in-vx-init&quot;&gt;Root scripts in vx init&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#a-default-base-for-affected-runs&quot;&gt;A default base for affected runs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#turbos-task&quot;&gt;Turbo’s //#task&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#turbo-and-nx-spellings-name-the-vx-way&quot;&gt;Turbo and Nx spellings name the vx way&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#remote-cache-switches-for-pull-requests&quot;&gt;Remote cache switches for pull requests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#turbocache-reads-all-of-turbos-cache-config&quot;&gt;turboCache() reads all of Turbo’s cache config&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#nx-follows-more-of-nxjson&quot;&gt;nx() follows more of nx.json&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#more-turbo-builds-stay-cached&quot;&gt;More Turbo builds stay cached&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#a-faster-vx-from-npm&quot;&gt;A faster vx from npm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#edited-bun-patches-invalidate-the-cache&quot;&gt;Edited Bun patches invalidate the cache&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;root-scripts-in-vx-init&quot;&gt;Root scripts in vx init&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#root-scripts-in-vx-init&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Root scripts in vx init”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;vx run lint&lt;/code&gt; used to find no project in many repos, because the root’s
&lt;code dir=&quot;auto&quot;&gt;lint&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;test&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;format&lt;/code&gt; scripts were never mapped. &lt;code dir=&quot;auto&quot;&gt;vx init&lt;/code&gt; now turns
a root script that checks the whole repo into a root task. A script that
runs the members (&lt;code dir=&quot;auto&quot;&gt;pnpm -r&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;--filter&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;--cwd&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;--prefix&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;vp run&lt;/code&gt;, a
runner, or vx itself) stays unmapped, and init names it. A run scoped
to a project that lacks a task others declare now says so and names
&lt;code dir=&quot;auto&quot;&gt;--all&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://vznjs.github.io/vx/_astro/ec.w36nc.css&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:152ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;acme (the workspace root): its scripts that check the whole repo are its tasks; left out as running the members (`pnpm -r`, `--filter`, a runner): build&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;acme (the workspace root): its scripts that check the whole repo are its tasks; left out as running the members (&amp;#x60;pnpm -r&amp;#x60;, &amp;#x60;--filter&amp;#x60;, a runner): build&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/1994&quot;&gt;#1994&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1996&quot;&gt;#1996&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/2004&quot;&gt;#2004&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1971&quot;&gt;#1971&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;a-default-base-for-affected-runs&quot;&gt;A default base for affected runs&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#a-default-base-for-affected-runs&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “A default base for affected runs”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A bare &lt;code dir=&quot;auto&quot;&gt;--affected&lt;/code&gt; compared with &lt;code dir=&quot;auto&quot;&gt;origin/HEAD&lt;/code&gt;, so a git-flow repo diffed
against the wrong branch. &lt;code dir=&quot;auto&quot;&gt;affectedBase&lt;/code&gt; in &lt;code dir=&quot;auto&quot;&gt;vx.workspace.ts&lt;/code&gt; now names
the ref, and &lt;code dir=&quot;auto&quot;&gt;--affected=&amp;#x3C;base&gt;&lt;/code&gt; still wins. &lt;code dir=&quot;auto&quot;&gt;nx()&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;turbo()&lt;/code&gt; set it
from Nx’s &lt;code dir=&quot;auto&quot;&gt;defaultBase&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;NX_BASE&lt;/code&gt;, and from Turbo’s &lt;code dir=&quot;auto&quot;&gt;TURBO_SCM_BASE&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;vx.workspace.ts&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:66ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { defineWorkspace } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx/config&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;defineWorkspace&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;({ affectedBase: &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;origin/develop&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; })&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import { defineWorkspace } from &amp;#x27;@vzn/vx/config&amp;#x27;export default defineWorkspace({ affectedBase: &amp;#x27;origin/develop&amp;#x27; })&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/1960&quot;&gt;#1960&lt;/a&gt;. Docs:
&lt;a href=&quot;../../guides/configure/#workspace-config&quot;&gt;Workspace config&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;turbos-task&quot;&gt;Turbo’s //#task&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#turbos-task&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Turbo’s //#task”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Turbo spells a root task &lt;code dir=&quot;auto&quot;&gt;//#lint&lt;/code&gt;. vx read &lt;code dir=&quot;auto&quot;&gt;//&lt;/code&gt; as a project name and
refused it in &lt;code dir=&quot;auto&quot;&gt;vx run&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;vx show&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;vx why&lt;/code&gt; and in &lt;code dir=&quot;auto&quot;&gt;dependsOn&lt;/code&gt;. All four
now take it as the root project’s task, from any directory.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:14ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;//#lint&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx run //#lint&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/1953&quot;&gt;#1953&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1956&quot;&gt;#1956&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1957&quot;&gt;#1957&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;turbo-and-nx-spellings-name-the-vx-way&quot;&gt;Turbo and Nx spellings name the vx way&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#turbo-and-nx-spellings-name-the-vx-way&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Turbo and Nx spellings name the vx way”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Turbo’s and Nx’s run flags and verbs used to stop at “unknown flag” or
“unknown command”. Now &lt;code dir=&quot;auto&quot;&gt;-F&lt;/code&gt; is &lt;code dir=&quot;auto&quot;&gt;--filter&lt;/code&gt;, three Nx options are aliases,
and the rest (&lt;code dir=&quot;auto&quot;&gt;--env-mode&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;--global-deps&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;nx graph&lt;/code&gt;,
&lt;code dir=&quot;auto&quot;&gt;nx show projects&lt;/code&gt; and more) say what does it in vx. A flag cut short (&lt;code dir=&quot;auto&quot;&gt;--dry&lt;/code&gt;)
or &lt;code dir=&quot;auto&quot;&gt;--json&lt;/code&gt; on a verb that takes &lt;code dir=&quot;auto&quot;&gt;--format json&lt;/code&gt; gets a hint too.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:144ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;$ vx run build --env-mode=strict&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;vx run: --env-mode (turbo): vx passes only the variables a task declares (strict): list the rest in `exec.env.passThrough` (see `vx run --help`)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;$ vx graph&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;`nx graph` is `vx run &amp;#x3C;task&gt; --graph[=&amp;#x3C;file&gt;.dot]` here: the task graph as Graphviz DOT&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;$ vx info --json&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;vx info: unknown flag: --json (did you mean --format json?) (see `vx info --help`)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;$ vx run build --env-mode=strictvx run: --env-mode (turbo): vx passes only the variables a task declares (strict): list the rest in &amp;#x60;exec.env.passThrough&amp;#x60; (see &amp;#x60;vx run --help&amp;#x60;)$ vx graph&amp;#x60;nx graph&amp;#x60; is &amp;#x60;vx run &lt;task&gt; --graph[=&lt;file&gt;.dot]&amp;#x60; here: the task graph as Graphviz DOT$ vx info --jsonvx info: unknown flag: --json (did you mean --format json?) (see &amp;#x60;vx info --help&amp;#x60;)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/1948&quot;&gt;#1948&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1949&quot;&gt;#1949&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1950&quot;&gt;#1950&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1951&quot;&gt;#1951&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1955&quot;&gt;#1955&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1964&quot;&gt;#1964&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1936&quot;&gt;#1936&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;remote-cache-switches-for-pull-requests&quot;&gt;Remote cache switches for pull requests&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#remote-cache-switches-for-pull-requests&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Remote cache switches for pull requests”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A CI keeps an untrusted pull request from writing the shared cache with
Turbo’s &lt;code dir=&quot;auto&quot;&gt;TURBO_CACHE&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;TURBO_REMOTE_CACHE_READ_ONLY&lt;/code&gt;, or Nx’s
&lt;code dir=&quot;auto&quot;&gt;NX_SKIP_REMOTE_CACHE&lt;/code&gt;. vx ignored them, so such a job wrote what &lt;code dir=&quot;auto&quot;&gt;main&lt;/code&gt;
would restore. &lt;code dir=&quot;auto&quot;&gt;turboCache()&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;nxCache()&lt;/code&gt; now honour each one. A
switch can only narrow the run’s &lt;code dir=&quot;auto&quot;&gt;--cache&lt;/code&gt; policy, never widen it.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:49ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C5E478;--1:#3B61B0&quot;&gt;TURBO_REMOTE_CACHE_READ_ONLY&lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--all&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;TURBO_REMOTE_CACHE_READ_ONLY=1 vx run build --all&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/1941&quot;&gt;#1941&lt;/a&gt;. Docs:
&lt;a href=&quot;../../guides/ci/#remote-cache&quot;&gt;Remote cache&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;turbocache-reads-all-of-turbos-cache-config&quot;&gt;turboCache() reads all of Turbo’s cache config&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#turbocache-reads-all-of-turbos-cache-config&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “turboCache() reads all of Turbo’s cache config”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;turboCache()&lt;/code&gt; declined on Vercel and in a &lt;code dir=&quot;auto&quot;&gt;turbo link&lt;/code&gt;ed repo. It now
reads &lt;code dir=&quot;auto&quot;&gt;VERCEL_ARTIFACTS_TOKEN&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;_OWNER&lt;/code&gt;, and &lt;code dir=&quot;auto&quot;&gt;.turbo/config.json&lt;/code&gt;.
It honours Turbo’s timeouts, signs only where &lt;code dir=&quot;auto&quot;&gt;turbo.json&lt;/code&gt; turns signing
on, and sends &lt;code dir=&quot;auto&quot;&gt;teamId&lt;/code&gt; only in Vercel’s &lt;code dir=&quot;auto&quot;&gt;team_&lt;/code&gt; form. &lt;code dir=&quot;auto&quot;&gt;vx init&lt;/code&gt; declares
it in a linked repo, and says when &lt;code dir=&quot;auto&quot;&gt;nx.json&lt;/code&gt; uses Nx Cloud, which vx
cannot share.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;vx.workspace.ts&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:68ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { defineWorkspace } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx/config&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { turbo, turboCache } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx-migrate&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;defineWorkspace&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;({ plugins: [&lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;turboCache&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;(), &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;turbo&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;()] })&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import { defineWorkspace } from &amp;#x27;@vzn/vx/config&amp;#x27;import { turbo, turboCache } from &amp;#x27;@vzn/vx-migrate&amp;#x27;export default defineWorkspace({ plugins: [turboCache(), turbo()] })&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/1942&quot;&gt;#1942&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1939&quot;&gt;#1939&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1940&quot;&gt;#1940&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1946&quot;&gt;#1946&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1962&quot;&gt;#1962&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;nx-follows-more-of-nxjson&quot;&gt;nx() follows more of nx.json&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#nx-follows-more-of-nxjson&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “nx() follows more of nx.json”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;nx()&lt;/code&gt; now caps the local cache at &lt;code dir=&quot;auto&quot;&gt;maxCacheSize&lt;/code&gt; (or
&lt;code dir=&quot;auto&quot;&gt;NX_MAX_CACHE_SIZE&lt;/code&gt;), and lets &lt;code dir=&quot;auto&quot;&gt;NX_PARALLEL&lt;/code&gt; win over &lt;code dir=&quot;auto&quot;&gt;nx.json&lt;/code&gt;’s
&lt;code dir=&quot;auto&quot;&gt;parallel&lt;/code&gt;, as Nx 23 does. &lt;code dir=&quot;auto&quot;&gt;nxCache()&lt;/code&gt; keeps reads on when a read-only
token’s upload is refused. &lt;code dir=&quot;auto&quot;&gt;bunx @vzn/vx-migrate --from nx&lt;/code&gt; exports the
graph itself when none is on disk.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:32ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C5E478;--1:#3B61B0&quot;&gt;NX_PARALLEL&lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--all&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;NX_PARALLEL=2 vx run build --all&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/1945&quot;&gt;#1945&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1944&quot;&gt;#1944&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1947&quot;&gt;#1947&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1977&quot;&gt;#1977&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;more-turbo-builds-stay-cached&quot;&gt;More Turbo builds stay cached&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#more-turbo-builds-stay-cached&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “More Turbo builds stay cached”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;turbo()&lt;/code&gt; left a task uncached when its outputs glob might reach a
source file. It now proves more globs safe: &lt;code dir=&quot;auto&quot;&gt;**/dist/**&lt;/code&gt; with no tracked
&lt;code dir=&quot;auto&quot;&gt;dist&lt;/code&gt; directory, a pattern like &lt;code dir=&quot;auto&quot;&gt;dist-*/**&lt;/code&gt; that matches no tracked
top-level entry, and top-level artifacts like &lt;code dir=&quot;auto&quot;&gt;*.xml&lt;/code&gt;. vercel/ai’s 69
builds and tldraw’s 35 now cache. &lt;code dir=&quot;auto&quot;&gt;nx()&lt;/code&gt; shares the same rules.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:18ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--all&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx run build --all&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/1974&quot;&gt;#1974&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1986&quot;&gt;#1986&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1969&quot;&gt;#1969&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1980&quot;&gt;#1980&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;a-faster-vx-from-npm&quot;&gt;A faster vx from npm&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#a-faster-vx-from-npm&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “A faster vx from npm”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Every &lt;code dir=&quot;auto&quot;&gt;vx&lt;/code&gt; an npm user runs starts in a small Node launcher. It is now
CommonJS, not ESM: &lt;code dir=&quot;auto&quot;&gt;vx --version&lt;/code&gt; went from 65.5 ms to 57.0 ms. On Node
22.15 and newer the launcher replaces itself with the binary instead of
spawning it: from 54.2 ms to 45.3 ms. The binary itself answers
&lt;code dir=&quot;auto&quot;&gt;--version&lt;/code&gt; before loading the dispatcher, from 20.1 ms to 16.4 ms.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:16ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;npx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--version&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npx vx --version&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;vx-charts&quot;&gt;&lt;figure class=&quot;vx-bars&quot;&gt;&lt;figcaption&gt;vx --version from npm&lt;/figcaption&gt;&lt;div class=&quot;vx-bar&quot; style=&quot;--w:100%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;before&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;65.5 ms&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;vx-bar vx-bar-lead&quot; style=&quot;--w:87%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;after&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;57 ms&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/figure&gt;&lt;figure class=&quot;vx-bars&quot;&gt;&lt;figcaption&gt;On Node, spawning vx&lt;/figcaption&gt;&lt;div class=&quot;vx-bar&quot; style=&quot;--w:100%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;before&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;54.2 ms&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;vx-bar vx-bar-lead&quot; style=&quot;--w:83.6%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;after&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;45.3 ms&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/figure&gt;&lt;figure class=&quot;vx-bars&quot;&gt;&lt;figcaption&gt;The binary&lt;/figcaption&gt;&lt;div class=&quot;vx-bar&quot; style=&quot;--w:100%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;before&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;20.1 ms&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;vx-bar vx-bar-lead&quot; style=&quot;--w:81.6%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;after&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;16.4 ms&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/1979&quot;&gt;#1979&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1981&quot;&gt;#1981&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1961&quot;&gt;#1961&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;edited-bun-patches-invalidate-the-cache&quot;&gt;Edited Bun patches invalidate the cache&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#edited-bun-patches-invalidate-the-cache&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Edited Bun patches invalidate the cache”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;bun.lock&lt;/code&gt; records a patch by path, so editing the patch leaves the
lockfile byte-identical while &lt;code dir=&quot;auto&quot;&gt;bun install&lt;/code&gt; applies the new one. Without
the &lt;code dir=&quot;auto&quot;&gt;bun()&lt;/code&gt; plugin, vx replayed the old outputs. Core now folds each
patch &lt;code dir=&quot;auto&quot;&gt;bun.lock&lt;/code&gt; names into the key, and &lt;code dir=&quot;auto&quot;&gt;--affected&lt;/code&gt; widens on its edit.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:68ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#919F9F;--1:#5F636F&quot;&gt;# after editing patches/left-pad@1.3.0.patch and running bun install&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--all&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx run build --all&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/1904&quot;&gt;#1904&lt;/a&gt;. Docs:
&lt;a href=&quot;../../guides/configure/#lockfiles&quot;&gt;Lockfiles&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;breaking-changes&quot;&gt;Breaking changes&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#breaking-changes&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Breaking changes”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;vx init&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;vx-migrate&lt;/code&gt; write
&lt;code dir=&quot;auto&quot;&gt;import type { ProjectConfig } from '@vzn/vx/config'&lt;/code&gt;
(&lt;a href=&quot;https://github.com/vznjs/vx/pull/2013&quot;&gt;#2013&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;@vzn/vx-migrate&lt;/code&gt; adopts Turbo and Nx only: &lt;code dir=&quot;auto&quot;&gt;lage()&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;wireit()&lt;/code&gt;,
&lt;code dir=&quot;auto&quot;&gt;workspaceScripts()&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;--from lage|wireit|scripts&lt;/code&gt; are gone
(&lt;a href=&quot;https://github.com/vznjs/vx/pull/2009&quot;&gt;#2009&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;moon support is removed: &lt;code dir=&quot;auto&quot;&gt;moon()&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;mapMoonWorkspace&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;--from moon&lt;/code&gt;
(&lt;a href=&quot;https://github.com/vznjs/vx/pull/2008&quot;&gt;#2008&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;vx info --format json&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;vx mcp&lt;/code&gt;’s &lt;code dir=&quot;auto&quot;&gt;getWorkspaceInfo&lt;/code&gt; gain
&lt;code dir=&quot;auto&quot;&gt;sandbox.untraced&lt;/code&gt; (&lt;a href=&quot;https://github.com/vznjs/vx/pull/2000&quot;&gt;#2000&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;vx init&lt;/code&gt; maps a root’s repo-wide scripts to root tasks
(&lt;a href=&quot;https://github.com/vznjs/vx/pull/1994&quot;&gt;#1994&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;vx init&lt;/code&gt; drops the &lt;code dir=&quot;auto&quot;&gt;readyWhen&lt;/code&gt; note on a persistent task nothing
depends on (&lt;a href=&quot;https://github.com/vznjs/vx/pull/1987&quot;&gt;#1987&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;turbo()&lt;/code&gt; caches outputs it proved safe, and the plugin API’s tracked
set changed (&lt;a href=&quot;https://github.com/vznjs/vx/pull/1986&quot;&gt;#1986&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1974&quot;&gt;#1974&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;The npm launcher is CommonJS
(&lt;a href=&quot;https://github.com/vznjs/vx/pull/1979&quot;&gt;#1979&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;A bare &lt;code dir=&quot;auto&quot;&gt;--affected&lt;/code&gt; reads &lt;code dir=&quot;auto&quot;&gt;affectedBase&lt;/code&gt; first
(&lt;a href=&quot;https://github.com/vznjs/vx/pull/1960&quot;&gt;#1960&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Turbo task &lt;code dir=&quot;auto&quot;&gt;tags&lt;/code&gt; map to nothing
(&lt;a href=&quot;https://github.com/vznjs/vx/pull/1934&quot;&gt;#1934&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See &lt;a href=&quot;../../guides/upgrading/&quot;&gt;Upgrading&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;how-to-update&quot;&gt;How to update&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#how-to-update&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “How to update”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:29ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;-D&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;@vzn/vx@latest&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm install -D @vzn/vx@latest&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;A standalone binary updates itself with &lt;code dir=&quot;auto&quot;&gt;vx upgrade&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;learn-more&quot;&gt;Learn more&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#learn-more&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Learn more”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;../../quickstart/&quot;&gt;Quickstart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../../benchmarks/&quot;&gt;Benchmarks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/vznjs/vx/releases&quot;&gt;Every release on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item>
<item><title>Starts 2× faster</title><link>https://vznjs.github.io/vx/releases/vx-0-0-242/</link><guid isPermaLink="true">https://vznjs.github.io/vx/releases/vx-0-0-242/</guid><description>turbo() now runs root tasks, single-package repos and with sidecars as Turbo does, nx() finds every project in an integrated repo, and the CLI starts 2× faster.</description><pubDate>Wed, 30 Sep 2026 12:00:00 GMT</pubDate><category>release</category><content:encoded>&lt;p&gt;vx 0.0.200 to 0.0.242 shipped on 2026-09-29 and 09-30. Most of the batch
makes &lt;code dir=&quot;auto&quot;&gt;turbo()&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;nx()&lt;/code&gt; from &lt;code dir=&quot;auto&quot;&gt;@vzn/vx-migrate&lt;/code&gt; run more real repos
unchanged. Core also starts faster, saves misses faster, and tells you how
to fix a task that rewrites its own input.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this release&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#turbo-root-tasks-without-a-root-config&quot;&gt;Turbo root tasks without a root config&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#turbo-with-sidecars&quot;&gt;Turbo with sidecars&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#turbo-env-wildcards-and-framework-prefixes&quot;&gt;Turbo env wildcards and framework prefixes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#nx-projects-outside-the-package-list&quot;&gt;Nx projects outside the package list&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#faster-startup&quot;&gt;Faster startup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#faster-cache-misses&quot;&gt;Faster cache misses&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#vx-reapi-fails-fast-when-the-server-is-down&quot;&gt;vx-reapi fails fast when the server is down&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#a-hint-for-tasks-that-rewrite-their-inputs&quot;&gt;A hint for tasks that rewrite their inputs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#sandbox-gitconfig-and-writes-outside-the-project&quot;&gt;Sandbox: gitConfig and writes outside the project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#vx-mcp-takes-short-run-ids&quot;&gt;vx-mcp takes short run ids&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;turbo-root-tasks-without-a-root-config&quot;&gt;Turbo root tasks without a root config&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#turbo-root-tasks-without-a-root-config&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Turbo root tasks without a root config”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A &lt;code dir=&quot;auto&quot;&gt;//#format&lt;/code&gt; task in turbo.json used to need a &lt;code dir=&quot;auto&quot;&gt;vx.config.ts&lt;/code&gt; at the
root, or &lt;code dir=&quot;auto&quot;&gt;vx run format --all&lt;/code&gt; said no project declares it. Core gained a
&lt;code dir=&quot;auto&quot;&gt;discover&lt;/code&gt; stage, where a plugin names directories that become projects,
and &lt;code dir=&quot;auto&quot;&gt;turbo()&lt;/code&gt; names the root when turbo.json declares a &lt;code dir=&quot;auto&quot;&gt;//#&lt;/code&gt; task. A
single-package Turbo setup, with no workspaces at all, now maps its
plain tasks to the root too. The two-line workspace file is all you need:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://vznjs.github.io/vx/_astro/ec.w36nc.css&quot;&gt;&lt;figure class=&quot;frame not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:63ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { WorkspaceConfig } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx/config&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { turbo } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx-migrate&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { plugins: [&lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;turbo&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;()] } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;satisfies&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFCB8B;--1:#111111&quot;&gt;WorkspaceConfig&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import type { WorkspaceConfig } from &amp;#x27;@vzn/vx/config&amp;#x27;import { turbo } from &amp;#x27;@vzn/vx-migrate&amp;#x27;export default { plugins: [turbo()] } satisfies WorkspaceConfig&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/1859&quot;&gt;#1859&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1867&quot;&gt;#1867&lt;/a&gt;. Deep dive:
&lt;a href=&quot;../../blog/from-turborepo/&quot;&gt;From Turborepo&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;turbo-with-sidecars&quot;&gt;Turbo with sidecars&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#turbo-with-sidecars&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Turbo with sidecars”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Turbo’s &lt;code dir=&quot;auto&quot;&gt;with&lt;/code&gt; key (&lt;code dir=&quot;auto&quot;&gt;web#dev&lt;/code&gt; with &lt;code dir=&quot;auto&quot;&gt;api#dev&lt;/code&gt;) was a todo, so starting
&lt;code dir=&quot;auto&quot;&gt;web#dev&lt;/code&gt; started no API. Each persistent sidecar is now an edge: vx
starts it and runs the task beside it. A task with no script of its own,
like the &lt;code dir=&quot;auto&quot;&gt;dev&lt;/code&gt; in Turbo’s with-tailwind example, becomes a group that
starts its sidecars.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:14ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;web#dev&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx run web#dev&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/1864&quot;&gt;#1864&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1866&quot;&gt;#1866&lt;/a&gt;. See
&lt;a href=&quot;https://vznjs.github.io/vx/compare/turbo-nx-support/&quot;&gt;Turbo and Nx config support&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;turbo-env-wildcards-and-framework-prefixes&quot;&gt;Turbo env wildcards and framework prefixes&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#turbo-env-wildcards-and-framework-prefixes&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Turbo env wildcards and framework prefixes”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Under &lt;code dir=&quot;auto&quot;&gt;turbo()&lt;/code&gt;, a &lt;code dir=&quot;auto&quot;&gt;*&lt;/code&gt; name in &lt;code dir=&quot;auto&quot;&gt;env&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;passThroughEnv&lt;/code&gt; (&lt;code dir=&quot;auto&quot;&gt;NEXT_PUBLIC_*&lt;/code&gt;)
now expands over the run’s environment, as Turbo does, instead of leaving
the task without those variables. Turbo 2’s framework inference applies
too, so a Next.js build gets its &lt;code dir=&quot;auto&quot;&gt;NEXT_PUBLIC_*&lt;/code&gt; values and no longer
inlines empty ones. A &lt;code dir=&quot;auto&quot;&gt;!NAME&lt;/code&gt; entry removes that name from the list.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:62ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C5E478;--1:#3B61B0&quot;&gt;NEXT_PUBLIC_API_URL&lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;https://api.example.com&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--all&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;NEXT_PUBLIC_API_URL=https://api.example.com vx run build --all&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/1896&quot;&gt;#1896&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1897&quot;&gt;#1897&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1881&quot;&gt;#1881&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;nx-projects-outside-the-package-list&quot;&gt;Nx projects outside the package list&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#nx-projects-outside-the-package-list&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Nx projects outside the package list”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;An integrated Nx repo keeps its &lt;code dir=&quot;auto&quot;&gt;project.json&lt;/code&gt; libraries out of the
package manager’s workspace list. &lt;code dir=&quot;auto&quot;&gt;nx()&lt;/code&gt; attached only the ones that list
named: 1 of analogjs’s 21 build tasks. It now names each graph node’s
directory through the &lt;code dir=&quot;auto&quot;&gt;discover&lt;/code&gt; stage, so every project runs, and a root
project needs no hand-written config. A warm &lt;code dir=&quot;auto&quot;&gt;nx()&lt;/code&gt; run also reuses core’s
&lt;code dir=&quot;auto&quot;&gt;git status&lt;/code&gt; for its graph key instead of spawning its own.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:18ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--all&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx run build --all&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/1862&quot;&gt;#1862&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1901&quot;&gt;#1901&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;faster-startup&quot;&gt;Faster startup&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#faster-startup&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Faster startup”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;vx --version&lt;/code&gt; spent most of its time importing the run path. Every verb
now loads on use, &lt;code dir=&quot;auto&quot;&gt;run&lt;/code&gt; included, so &lt;code dir=&quot;auto&quot;&gt;--version&lt;/code&gt; went from about 60 ms to
25 ms. A warm no-op run is unchanged.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:12ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--version&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx --version&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;vx-charts&quot;&gt;&lt;figure class=&quot;vx-bars&quot;&gt;&lt;figcaption&gt;vx --version&lt;/figcaption&gt;&lt;div class=&quot;vx-bar&quot; style=&quot;--w:100%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;before&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;60 ms&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;vx-bar vx-bar-lead&quot; style=&quot;--w:41.7%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;after&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;25 ms&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/1883&quot;&gt;#1883&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;faster-cache-misses&quot;&gt;Faster cache misses&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#faster-cache-misses&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Faster cache misses”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Each miss paid async round trips to check where its outputs live and to
clean them before the task ran. Those now run synchronously for small
sets. A full-miss run of 100 tasks went from 594 ms to 541 ms, and from
979 ms to 898 ms at &lt;code dir=&quot;auto&quot;&gt;--concurrency 1&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:18ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--all&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx run build --all&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;vx-charts&quot;&gt;&lt;figure class=&quot;vx-bars&quot;&gt;&lt;figcaption&gt;Full miss, 100 tasks&lt;/figcaption&gt;&lt;div class=&quot;vx-bar&quot; style=&quot;--w:100%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;before&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;594 ms&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;vx-bar vx-bar-lead&quot; style=&quot;--w:91.1%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;after&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;541 ms&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/figure&gt;&lt;figure class=&quot;vx-bars&quot;&gt;&lt;figcaption&gt;Same, --concurrency 1&lt;/figcaption&gt;&lt;div class=&quot;vx-bar&quot; style=&quot;--w:100%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;before&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;979 ms&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;vx-bar vx-bar-lead&quot; style=&quot;--w:91.7%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;after&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;898 ms&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/1885&quot;&gt;#1885&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1898&quot;&gt;#1898&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;vx-reapi-fails-fast-when-the-server-is-down&quot;&gt;vx-reapi fails fast when the server is down&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#vx-reapi-fails-fast-when-the-server-is-down&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “vx-reapi fails fast when the server is down”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Every cache call spent 2.1 s backing off when the REAPI server refused the
connection, so a five-task run took 24 s. Once one call has spent its
retries, the next ones give up at the first refusal until the server
answers again. The same run now takes 2.6 s and falls back to the local
cache.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:18ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--all&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx run build --all&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/1887&quot;&gt;#1887&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;a-hint-for-tasks-that-rewrite-their-inputs&quot;&gt;A hint for tasks that rewrite their inputs&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#a-hint-for-tasks-that-rewrite-their-inputs&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “A hint for tasks that rewrite their inputs”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A task that rewrites one of its own inputs, like TanStack Router’s
committed &lt;code dir=&quot;auto&quot;&gt;routeTree.gen.ts&lt;/code&gt;, is never saved: its key no longer describes
the files. The status line named the file but not the fix. It now says to
declare the file in &lt;code dir=&quot;auto&quot;&gt;cache.outputs&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:213ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;[vx] app#build: `packages/app/src/routeTree.gen.ts` changed after its key was taken — the result stands, but is not saved under a key that no longer describes it; if the task writes it, declare it in cache.outputs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;[vx] app#build: &amp;#x60;packages/app/src/routeTree.gen.ts&amp;#x60; changed after its key was taken — the result stands, but is not saved under a key that no longer describes it; if the task writes it, declare it in cache.outputs&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/1877&quot;&gt;#1877&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;sandbox-gitconfig-and-writes-outside-the-project&quot;&gt;Sandbox: gitConfig and writes outside the project&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#sandbox-gitconfig-and-writes-outside-the-project&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Sandbox: gitConfig and writes outside the project”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;allow.gitConfig&lt;/code&gt; was ignored, so &lt;code dir=&quot;auto&quot;&gt;.git/config&lt;/code&gt; stayed read-only to every
sandboxed task. It now reaches the sandbox, for that task only. A &lt;code dir=&quot;auto&quot;&gt;dir/&lt;/code&gt;
write grant outside the project is created when missing, so a tool can
fill a cold cache in your home. When a task fails, vx names the writes the
sandbox refused outside the project and the directory to grant.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:73ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { defineProject } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx/config&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;defineProject&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;tasks: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:4ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;compile: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:6ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;exec: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:8ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;command: &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;bun build --compile --target=bun-linux-x64 src/bin.ts&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:8ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;sandbox: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:10ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;allow: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:12ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;network: [&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;registry.npmjs.org&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:12ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;write: [&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;~/.bun/install/cache/&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;.*.tmp/**&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:10ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:8ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:6ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:4ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import { defineProject } from &amp;#x27;@vzn/vx/config&amp;#x27;export default defineProject({  tasks: {    compile: {      exec: {        command: &amp;#x27;bun build --compile --target=bun-linux-x64 src/bin.ts&amp;#x27;,        sandbox: {          allow: {            network: [&amp;#x27;registry.npmjs.org&amp;#x27;],            write: [&amp;#x27;~/.bun/install/cache/&amp;#x27;, &amp;#x27;.*.tmp/**&amp;#x27;],          },        },      },    },  },})&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/1851&quot;&gt;#1851&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1875&quot;&gt;#1875&lt;/a&gt;. See
&lt;a href=&quot;../../guides/sandboxing/#what-you-can-grant&quot;&gt;What you can grant&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;vx-mcp-takes-short-run-ids&quot;&gt;vx-mcp takes short run ids&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#vx-mcp-takes-short-run-ids&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “vx-mcp takes short run ids”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;vx why --run&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;vx last&lt;/code&gt; accept the short id that &lt;code dir=&quot;auto&quot;&gt;vx last --list&lt;/code&gt;
prints. The MCP tool &lt;code dir=&quot;auto&quot;&gt;whyDidThisRerun&lt;/code&gt; answered “not found” for it. It now
resolves ids the same way the CLI does.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:92ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;ok     2026-10-08T19:56:51.484Z  01a11d17-099c  1 task · 0 hits  148ms  $ vx run build --all&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;ok     2026-10-08T19:56:51.484Z  01a11d17-099c  1 task · 0 hits  148ms  $ vx run build --all&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/1888&quot;&gt;#1888&lt;/a&gt;. Deep dive:
&lt;a href=&quot;../../blog/agents-and-mcp/&quot;&gt;Agents and MCP&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;breaking-changes&quot;&gt;Breaking changes&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#breaking-changes&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Breaking changes”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Plugins: &lt;code dir=&quot;auto&quot;&gt;PLUGIN_HOOKS&lt;/code&gt; gains &lt;code dir=&quot;auto&quot;&gt;discover&lt;/code&gt;, after &lt;code dir=&quot;auto&quot;&gt;config&lt;/code&gt;
(&lt;a href=&quot;https://github.com/vznjs/vx/pull/1859&quot;&gt;#1859&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;vx-mcp: &lt;code dir=&quot;auto&quot;&gt;whyDidThisRerun&lt;/code&gt;’s &lt;code dir=&quot;auto&quot;&gt;runId&lt;/code&gt; now takes a prefix
(&lt;a href=&quot;https://github.com/vznjs/vx/pull/1888&quot;&gt;#1888&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See &lt;a href=&quot;../../guides/upgrading/&quot;&gt;Upgrading&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;how-to-update&quot;&gt;How to update&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#how-to-update&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “How to update”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:29ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;-D&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;@vzn/vx@latest&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm install -D @vzn/vx@latest&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;A standalone binary updates itself with &lt;code dir=&quot;auto&quot;&gt;vx upgrade&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;learn-more&quot;&gt;Learn more&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#learn-more&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Learn more”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;../../quickstart/&quot;&gt;Quickstart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../../benchmarks/&quot;&gt;Benchmarks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/vznjs/vx/releases&quot;&gt;Every release on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item>
<item><title>Start from Turbo or Nx in one line</title><link>https://vznjs.github.io/vx/releases/vx-0-0-199/</link><guid isPermaLink="true">https://vznjs.github.io/vx/releases/vx-0-0-199/</guid><description>vx init now sets up a Turbo or Nx repo with one plugin line, the workspace root can hold tasks, and vx last jumps straight to the run that failed.</description><pubDate>Mon, 28 Sep 2026 12:00:00 GMT</pubDate><category>release</category><content:encoded>&lt;p&gt;vx 0.0.76 through 0.0.199 shipped on 2026-09-27 and 2026-09-28. The theme
is adoption: a Turbo or Nx user gets a working setup from &lt;code dir=&quot;auto&quot;&gt;vx init&lt;/code&gt;, their
habits get an answer instead of an error, and the root package can hold
tasks. The run footer, &lt;code dir=&quot;auto&quot;&gt;vx last&lt;/code&gt; and secret masking also got better. Two
changes are breaking; they are listed at the end.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this release&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#vx-init-adopts-a-turbo-or-nx-repo&quot;&gt;vx init adopts a Turbo or Nx repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#turbo-and-nx-habits-get-an-answer&quot;&gt;Turbo and Nx habits get an answer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#a-workspace-root-can-be-a-project&quot;&gt;A workspace root can be a project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#narrow-a-filter-by-a-git-range&quot;&gt;Narrow a filter by a git range&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#exclude-paths-from-outputs&quot;&gt;Exclude paths from outputs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#a-one-line-result-row&quot;&gt;A one-line result row&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#vx-last-finds-the-failure&quot;&gt;vx last finds the failure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mask-any-secret-by-name&quot;&gt;Mask any secret by name&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#scaffold-a-plugin&quot;&gt;Scaffold a plugin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#json-schemas-for-json-output&quot;&gt;JSON Schemas for JSON output&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;vx-init-adopts-a-turbo-or-nx-repo&quot;&gt;vx init adopts a Turbo or Nx repo&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#vx-init-adopts-a-turbo-or-nx-repo&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “vx init adopts a Turbo or Nx repo”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;In a repo with &lt;code dir=&quot;auto&quot;&gt;turbo.json&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;nx.json&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;vx init&lt;/code&gt; used to copy scripts
into one config per package and drop every edge the repo declared. It now
writes only &lt;code dir=&quot;auto&quot;&gt;vx.workspace.ts&lt;/code&gt; with &lt;code dir=&quot;auto&quot;&gt;turbo()&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;nx()&lt;/code&gt;, which read the repo
as it is. When it sees a remote cache (&lt;code dir=&quot;auto&quot;&gt;TURBO_TOKEN&lt;/code&gt; in CI, or a
&lt;code dir=&quot;auto&quot;&gt;remoteCache&lt;/code&gt; in turbo.json), it adds &lt;code dir=&quot;auto&quot;&gt;turboCache()&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;nxCache()&lt;/code&gt; too, so
the first vx run on CI hits the cache Turbo already filled. The &lt;code dir=&quot;auto&quot;&gt;next:&lt;/code&gt;
line installs what is missing with your package manager.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://vznjs.github.io/vx/_astro/ec.w36nc.css&quot;&gt;&lt;figure class=&quot;frame not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:77ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#919F9F;--1:#5D6376&quot;&gt;// vx.workspace.ts, as vx init writes it beside turbo.json&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { WorkspaceConfig } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx/config&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { turbo, turboCache } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx-migrate&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { plugins: [&lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;turbo&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;(), &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;turboCache&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;()] } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;satisfies&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFCB8B;--1:#111111&quot;&gt;WorkspaceConfig&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// vx.workspace.ts, as vx init writes it beside turbo.jsonimport type { WorkspaceConfig } from &amp;#x27;@vzn/vx/config&amp;#x27;import { turbo, turboCache } from &amp;#x27;@vzn/vx-migrate&amp;#x27;export default { plugins: [turbo(), turboCache()] } satisfies WorkspaceConfig&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;pre class=&quot;mermaid&quot; role=&quot;img&quot; aria-label=&quot;diagram&quot;&gt;flowchart LR
  T[&quot;turbo.json or Nx graph&quot;] --&gt; I[&quot;vx init&quot;] --&gt; P[&quot;one plugin line in vx.workspace.ts&quot;] --&gt; R[&quot;vx run build --all&quot;]&lt;/pre&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/1706&quot;&gt;#1706&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1801&quot;&gt;#1801&lt;/a&gt;. Docs:
&lt;a href=&quot;../../guides/migrate/#turborepo&quot;&gt;Migrate from Turborepo&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;turbo-and-nx-habits-get-an-answer&quot;&gt;Turbo and Nx habits get an answer&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#turbo-and-nx-habits-get-an-answer&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Turbo and Nx habits get an answer”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Hands trained on Turbo or Nx type &lt;code dir=&quot;auto&quot;&gt;turbo build&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;nx run web:build&lt;/code&gt;,
&lt;code dir=&quot;auto&quot;&gt;--dry-run&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;-p&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;--parallel&lt;/code&gt;. vx refused each as unknown. Now every
Turbo and Nx run flag has one outcome: it works as is, it is an alias, or
the error names the vx spelling. A task typed as a verb, and Nx’s
&lt;code dir=&quot;auto&quot;&gt;project:target&lt;/code&gt;, name the &lt;code dir=&quot;auto&quot;&gt;vx run&lt;/code&gt; to type instead.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:61ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;$ vx build&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;vx: `build` is a task here, not a command: vx run build --all&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;$ vx run app:build&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;vx run: `app:build` is Nx's project:target: vx run app#build&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;$ vx buildvx: &amp;#x60;build&amp;#x60; is a task here, not a command: vx run build --all$ vx run app:buildvx run: &amp;#x60;app:build&amp;#x60; is Nx&amp;#x27;s project:target: vx run app#build&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/1715&quot;&gt;#1715&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1720&quot;&gt;#1720&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1768&quot;&gt;#1768&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;a-workspace-root-can-be-a-project&quot;&gt;A workspace root can be a project&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#a-workspace-root-can-be-a-project&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “A workspace root can be a project”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A root task, like codegen or a root &lt;code dir=&quot;auto&quot;&gt;tsc -b&lt;/code&gt; every package waits on, had
no home. A &lt;code dir=&quot;auto&quot;&gt;vx.config.ts&lt;/code&gt; at the root is now a project: its globs stop at
every member, and other tasks can depend on it. &lt;code dir=&quot;auto&quot;&gt;--filter //&lt;/code&gt; selects it,
as in Turbo. &lt;code dir=&quot;auto&quot;&gt;turbo()&lt;/code&gt; maps Turbo’s &lt;code dir=&quot;auto&quot;&gt;//#task&lt;/code&gt; keys onto it, and
&lt;code dir=&quot;auto&quot;&gt;bunx @vzn/vx-migrate&lt;/code&gt; writes the root config for them. Five of eleven
real Turbo repos had root tasks that were dropped before.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:61ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#919F9F;--1:#5D6376&quot;&gt;// vx.config.ts at the workspace root&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { defineProject } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx/config&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;defineProject&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;tasks: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:4ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;codegen: { exec: { command: &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;bun scripts/codegen.ts&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; } },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// vx.config.ts at the workspace rootimport { defineProject } from &amp;#x27;@vzn/vx/config&amp;#x27;export default defineProject({  tasks: {    codegen: { exec: { command: &amp;#x27;bun scripts/codegen.ts&amp;#x27; } },  },})&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:26ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;codegen&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--filter&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;//&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx run codegen --filter //&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/1646&quot;&gt;#1646&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1724&quot;&gt;#1724&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1685&quot;&gt;#1685&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1827&quot;&gt;#1827&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;narrow-a-filter-by-a-git-range&quot;&gt;Narrow a filter by a git range&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#narrow-a-filter-by-a-git-range&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Narrow a filter by a git range”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A selector followed by a git range, like &lt;code dir=&quot;auto&quot;&gt;@scope/*[HEAD]&lt;/code&gt; or
&lt;code dir=&quot;auto&quot;&gt;{./apps/*}[main]&lt;/code&gt;, was read as one name glob and matched nothing. vx now
reads it as Turbo and pnpm do: the selected projects that changed since
that ref.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:44ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--filter&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;{./packages/*}[main]&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx run build --filter &amp;#x27;{./packages/*}[main]&amp;#x27;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/1703&quot;&gt;#1703&lt;/a&gt;. Docs:
&lt;a href=&quot;../../guides/ci/#run-and-filter&quot;&gt;Run and filter&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;exclude-paths-from-outputs&quot;&gt;Exclude paths from outputs&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#exclude-paths-from-outputs&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Exclude paths from outputs”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;cache.outputs&lt;/code&gt; now takes &lt;code dir=&quot;auto&quot;&gt;!&lt;/code&gt; entries. A path matched by one is not
cleaned, saved, restored or taken from a remote, and &lt;code dir=&quot;auto&quot;&gt;vx watch&lt;/code&gt; still
sees it. A scratch dir inside &lt;code dir=&quot;auto&quot;&gt;dist&lt;/code&gt; no longer forces a task to run
uncached. Turbo and Nx negated outputs map to it.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:56ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { defineProject } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx/config&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;defineProject&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;tasks: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:4ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;build: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:6ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;exec: { command: &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;bun run build&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:6ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;cache: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:8ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;inputs: { files: [&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;src/**&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;] },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:8ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;outputs: { files: [&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;dist/**&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;!dist/tmp/**&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;] },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:6ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:4ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import { defineProject } from &amp;#x27;@vzn/vx/config&amp;#x27;export default defineProject({  tasks: {    build: {      exec: { command: &amp;#x27;bun run build&amp;#x27; },      cache: {        inputs: { files: [&amp;#x27;src/**&amp;#x27;] },        outputs: { files: [&amp;#x27;dist/**&amp;#x27;, &amp;#x27;!dist/tmp/**&amp;#x27;] },      },    },  },})&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/1649&quot;&gt;#1649&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1679&quot;&gt;#1679&lt;/a&gt;. Docs:
&lt;a href=&quot;../../guides/configure/#caching&quot;&gt;Caching&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;a-one-line-result-row&quot;&gt;A one-line result row&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#a-one-line-result-row&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “A one-line result row”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;The footer spread tasks, cache hits and time over three meters. It now
ends with one &lt;code dir=&quot;auto&quot;&gt;result&lt;/code&gt; line: task count, how many were cached, time saved
and wall time. It says &lt;code dir=&quot;auto&quot;&gt;all cached&lt;/code&gt; when every task hit, and puts
failures first.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:52ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;info      4 workers · local cache&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;time      27ms&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;result    2 tasks · all cached · 22ms saved · 27ms&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;info      4 workers · local cache  time      27ms  result    2 tasks · all cached · 22ms saved · 27ms&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/1760&quot;&gt;#1760&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;vx-last-finds-the-failure&quot;&gt;vx last finds the failure&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#vx-last-finds-the-failure&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “vx last finds the failure”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;After a green re-run, finding the failure took &lt;code dir=&quot;auto&quot;&gt;--list&lt;/code&gt; and a copied
UUID. &lt;code dir=&quot;auto&quot;&gt;vx last --failed&lt;/code&gt; replays the latest failed run, and with &lt;code dir=&quot;auto&quot;&gt;--list&lt;/code&gt;
lists only failures. &lt;code dir=&quot;auto&quot;&gt;--list&lt;/code&gt; prints short run ids, and &lt;code dir=&quot;auto&quot;&gt;vx last&lt;/code&gt; and
&lt;code dir=&quot;auto&quot;&gt;vx why&lt;/code&gt; take any unique prefix. A failed replay ends with the command
that re-runs what failed.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:77ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;$ vx last --failed&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;$ vx run test --all&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;3 tasks · 2 hits (2 up-to-date, 0 restored) · 1 failed&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;failed (exit 1)   app#test        5ms  a210b23e08eded55  no-cache  0.3× cpu&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;up-to-date        lib#build       0ms  18679153744c589a&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;up-to-date        app#build       2ms  15f0218ef9e7a02c&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;re-run what failed: vx run app#test&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;$ vx last --failed  $ vx run test --all  3 tasks · 2 hits (2 up-to-date, 0 restored) · 1 failed  failed (exit 1)   app#test        5ms  a210b23e08eded55  no-cache  0.3× cpu  up-to-date        lib#build       0ms  18679153744c589a  up-to-date        app#build       2ms  15f0218ef9e7a02c  re-run what failed: vx run app#test&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/1499&quot;&gt;#1499&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1385&quot;&gt;#1385&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1436&quot;&gt;#1436&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1493&quot;&gt;#1493&lt;/a&gt;. Deep dive:
&lt;a href=&quot;../../blog/why-did-this-rerun/&quot;&gt;Why did this re-run?&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;mask-any-secret-by-name&quot;&gt;Mask any secret by name&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#mask-any-secret-by-name&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Mask any secret by name”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;vx masks values of env vars whose names hold &lt;code dir=&quot;auto&quot;&gt;TOKEN&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;SECRET&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;KEY&lt;/code&gt;,
&lt;code dir=&quot;auto&quot;&gt;PASSWORD&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;PASSWD&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;CREDENTIAL&lt;/code&gt;, wherever it prints, stores or
exports a task’s output or command. That missed names like &lt;code dir=&quot;auto&quot;&gt;GH_PAT&lt;/code&gt;: a
task that echoed it stored the token in its cached log. The new
&lt;code dir=&quot;auto&quot;&gt;exec.env.secret&lt;/code&gt; list masks any name you give it.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:61ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { defineProject } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx/config&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;defineProject&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;tasks: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:4ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;publish: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:6ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;exec: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:8ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;command: &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;bun scripts/publish.ts&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:8ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;env: { passThrough: [&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;GH_PAT&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;], secret: [&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;GH_PAT&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;] },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:6ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:4ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import { defineProject } from &amp;#x27;@vzn/vx/config&amp;#x27;export default defineProject({  tasks: {    publish: {      exec: {        command: &amp;#x27;bun scripts/publish.ts&amp;#x27;,        env: { passThrough: [&amp;#x27;GH_PAT&amp;#x27;], secret: [&amp;#x27;GH_PAT&amp;#x27;] },      },    },  },})&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/1406&quot;&gt;#1406&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1532&quot;&gt;#1532&lt;/a&gt;. Docs:
&lt;a href=&quot;../../guides/configure/#environment-variables&quot;&gt;Environment variables&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;scaffold-a-plugin&quot;&gt;Scaffold a plugin&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#scaffold-a-plugin&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Scaffold a plugin”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;vx init --plugin &amp;#x3C;seam&gt;&lt;/code&gt; writes &lt;code dir=&quot;auto&quot;&gt;plugins/&amp;#x3C;seam&gt;.ts&lt;/code&gt;, a runnable plugin,
and a test that drives it through a real run. It covers all nine seams:
executor, cache, telemetry, schedule, admit, commands, project, graph and
key. The templates are the same examples the repo’s gate runs.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:121ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;$ vx init --plugin telemetry&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;wrote plugins/telemetry.ts and plugins/telemetry.test.ts&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;Declare it in vx.workspace.ts: import { jsonlTelemetry } from './plugins/telemetry.ts', then plugins: [jsonlTelemetry(…)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;Test it: bun test plugins/telemetry.test.ts (needs @vzn/vx installed)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;$ vx init --plugin telemetrywrote plugins/telemetry.ts and plugins/telemetry.test.tsDeclare it in vx.workspace.ts: import { jsonlTelemetry } from &amp;#x27;./plugins/telemetry.ts&amp;#x27;, then plugins: [jsonlTelemetry(…)]Test it: bun test plugins/telemetry.test.ts (needs @vzn/vx installed)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/1415&quot;&gt;#1415&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1347&quot;&gt;#1347&lt;/a&gt;. Docs:
&lt;a href=&quot;../../guides/plugins/#write-one&quot;&gt;Write one&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;json-schemas-for-json-output&quot;&gt;JSON Schemas for JSON output&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#json-schemas-for-json-output&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “JSON Schemas for JSON output”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;CI scripts and agents parse &lt;code dir=&quot;auto&quot;&gt;vx show&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;vx info&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;vx why&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;vx last&lt;/code&gt;,
&lt;code dir=&quot;auto&quot;&gt;vx cache prune --format json&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;vx run --dry=json&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;--summarize&lt;/code&gt;.
Their shapes are now JSON Schemas shipped in
&lt;code dir=&quot;auto&quot;&gt;node_modules/@vzn/vx/schemas/&lt;/code&gt;, and tests hold each output to its schema.
&lt;code dir=&quot;auto&quot;&gt;vx cache prune&lt;/code&gt; gained &lt;code dir=&quot;auto&quot;&gt;--format json&lt;/code&gt; in the same batch.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:63ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--all&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--dry=json&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#7FDBCA;--1:#096E72&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;plan.json&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;   &lt;/span&gt;&lt;span style=&quot;--0:#919F9F;--1:#5F636F&quot;&gt;# schemas/plan.json&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx run build --all --dry=json &gt; plan.json   # schemas/plan.json&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/1608&quot;&gt;#1608&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1675&quot;&gt;#1675&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1681&quot;&gt;#1681&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1644&quot;&gt;#1644&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;breaking-changes&quot;&gt;Breaking changes&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#breaking-changes&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Breaking changes”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;vx stats&lt;/code&gt; is removed; run &lt;code dir=&quot;auto&quot;&gt;vx info&lt;/code&gt;, which prints the same report.
PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/1392&quot;&gt;#1392&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;defineProject&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;defineWorkspace&lt;/code&gt; reject undeclared keys at
type-check time; vx already refused them at load.
PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/1792&quot;&gt;#1792&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/1793&quot;&gt;#1793&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See &lt;a href=&quot;../../guides/upgrading/&quot;&gt;Upgrading&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;how-to-update&quot;&gt;How to update&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#how-to-update&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “How to update”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:29ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;-D&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;@vzn/vx@latest&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm install -D @vzn/vx@latest&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;A standalone binary updates itself with &lt;code dir=&quot;auto&quot;&gt;vx upgrade&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;learn-more&quot;&gt;Learn more&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#learn-more&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Learn more”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;../../quickstart/&quot;&gt;Quickstart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../../benchmarks/&quot;&gt;Benchmarks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/vznjs/vx/releases&quot;&gt;Every release on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item>
<item><title>Affected runs that include dependents</title><link>https://vznjs.github.io/vx/releases/vx-0-0-75/</link><guid isPermaLink="true">https://vznjs.github.io/vx/releases/vx-0-0-75/</guid><description>nx() maps an Nx project graph to vx tasks with nothing written, --affected selects dependents too, and remote caches stream artifacts instead of holding them in memory.</description><pubDate>Sun, 27 Sep 2026 12:00:00 GMT</pubDate><category>release</category><content:encoded>&lt;p&gt;vx 0.0.22 through 0.0.75 shipped between 2026-09-15 and 2026-09-27. The
theme is adoption and correctness: nx() maps an Nx graph as it is, CI selection
does what its name says, and several stale cache hits are gone. A few
changes are breaking; they are listed at the end.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this release&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#start-from-an-nx-graph-with-nx&quot;&gt;Start from an Nx graph with nx()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#affected-runs-include-dependents&quot;&gt;Affected runs include dependents&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#cache-retention&quot;&gt;Cache retention&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#remote-caches-stream-artifacts&quot;&gt;Remote caches stream artifacts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#try-vx-in-the-browser&quot;&gt;Try vx in the browser&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#brackets-are-literal-in-task-globs&quot;&gt;Brackets are literal in task globs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#configs-are-json-data&quot;&gt;Configs are JSON data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#stale-hit-fixes&quot;&gt;Stale-hit fixes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#faster-config-reloads-in-vx-watch&quot;&gt;Faster config reloads in vx watch&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;start-from-an-nx-graph-with-nx&quot;&gt;Start from an Nx graph with nx()&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#start-from-an-nx-graph-with-nx&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Start from an Nx graph with nx()”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;nx()&lt;/code&gt; from &lt;code dir=&quot;auto&quot;&gt;@vzn/vx-migrate&lt;/code&gt; turns every target in Nx’s resolved project
graph into a vx task. You write no config. Executor targets run through
&lt;code dir=&quot;auto&quot;&gt;nx-exec&lt;/code&gt;, one process per executor on Nx’s own &lt;code dir=&quot;auto&quot;&gt;runExecutor&lt;/code&gt;, and
run-commands targets run as the shell commands they are. Configurations
become &lt;code dir=&quot;auto&quot;&gt;&amp;#x3C;target&gt;:&amp;#x3C;configuration&gt;&lt;/code&gt; tasks. &lt;code dir=&quot;auto&quot;&gt;nx-exec&lt;/code&gt; starts in 214 ms
against 346 ms for &lt;code dir=&quot;auto&quot;&gt;nx run&lt;/code&gt; with the daemon warm.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://vznjs.github.io/vx/_astro/ec.w36nc.css&quot;&gt;&lt;figure class=&quot;frame has-title not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;vx.workspace.ts&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:51ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { defineWorkspace } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx/config&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { nx } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx-migrate&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;defineWorkspace&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;({ plugins: [&lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;nx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;()] })&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import { defineWorkspace } from &amp;#x27;@vzn/vx/config&amp;#x27;import { nx } from &amp;#x27;@vzn/vx-migrate&amp;#x27;export default defineWorkspace({ plugins: [nx()] })&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;vx-charts&quot;&gt;&lt;figure class=&quot;vx-bars&quot;&gt;&lt;figcaption&gt;Start one executor&lt;/figcaption&gt;&lt;div class=&quot;vx-bar&quot; style=&quot;--w:100%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;nx run, daemon warm&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;346 ms&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;vx-bar vx-bar-lead&quot; style=&quot;--w:61.8%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;nx-exec&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;214 ms&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/685&quot;&gt;#685&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/688&quot;&gt;#688&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/691&quot;&gt;#691&lt;/a&gt;. Docs:
&lt;a href=&quot;../../guides/migrate/#nx&quot;&gt;Migrate from Nx&lt;/a&gt;. Deep dive:
&lt;a href=&quot;../../blog/from-nx/&quot;&gt;From Nx&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;affected-runs-include-dependents&quot;&gt;Affected runs include dependents&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#affected-runs-include-dependents&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Affected runs include dependents”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;--affected&lt;/code&gt; used to select only the changed projects. On a branch that
edited &lt;code dir=&quot;auto&quot;&gt;lib&lt;/code&gt;, a CI gate ran &lt;code dir=&quot;auto&quot;&gt;lib&lt;/code&gt;’s tests and skipped &lt;code dir=&quot;auto&quot;&gt;app&lt;/code&gt;, which depends
on it. It now selects the changed projects and everything that depends on
them. &lt;code dir=&quot;auto&quot;&gt;--filter '[&amp;#x3C;base&gt;]'&lt;/code&gt; keeps the changed-only form, and the new
&lt;code dir=&quot;auto&quot;&gt;--filter '...^&amp;#x3C;pattern&gt;'&lt;/code&gt; selects a package’s dependents without the
package itself.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:34ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;test&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--affected=origin/main&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx run test --affected=origin/main&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;pre class=&quot;mermaid&quot; role=&quot;img&quot; aria-label=&quot;diagram&quot;&gt;flowchart LR
  U[&quot;ui changed&quot;] --&gt; UT[&quot;ui#test&quot;]
  U --&gt; W[&quot;web#test&quot;]
  U --&gt; D[&quot;docs#test&quot;]
  style U stroke:#c6f84e,stroke-width:2px&lt;/pre&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/446&quot;&gt;#446&lt;/a&gt;, commit
&lt;a href=&quot;https://github.com/vznjs/vx/commit/c148bd6826199de9b52beb4244ed59f2474fa0a6&quot;&gt;c148bd6&lt;/a&gt;.
Docs: &lt;a href=&quot;../../guides/ci/#run-and-filter&quot;&gt;Run and filter&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;cache-retention&quot;&gt;Cache retention&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#cache-retention&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Cache retention”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;cacheRetention&lt;/code&gt; in &lt;code dir=&quot;auto&quot;&gt;vx.workspace.ts&lt;/code&gt; evicts local cache entries at the end
of a run, by the same policy &lt;code dir=&quot;auto&quot;&gt;vx cache prune&lt;/code&gt; takes as flags. &lt;code dir=&quot;auto&quot;&gt;olderThan&lt;/code&gt;
drops entries unused for that long, then &lt;code dir=&quot;auto&quot;&gt;maxSize&lt;/code&gt; drops the least recently
used past the size. It does work only when something is due.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;vx.workspace.ts&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:55ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { defineWorkspace } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx/config&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;defineWorkspace&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;cacheRetention: { olderThan: &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;30d&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;, maxSize: &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;10G&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import { defineWorkspace } from &amp;#x27;@vzn/vx/config&amp;#x27;export default defineWorkspace({  cacheRetention: { olderThan: &amp;#x27;30d&amp;#x27;, maxSize: &amp;#x27;10G&amp;#x27; },})&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/755&quot;&gt;#755&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/772&quot;&gt;#772&lt;/a&gt;. Docs:
&lt;a href=&quot;../../guides/configure/#workspace-config&quot;&gt;Workspace config&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;remote-caches-stream-artifacts&quot;&gt;Remote caches stream artifacts&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#remote-caches-stream-artifacts&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Remote caches stream artifacts”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A remote cache layer now streams an artifact between disk and the wire
instead of holding it in memory. On a 150 MiB round trip, peak memory grew
by 45 MiB instead of 495 MiB. Every first-party layer moved with it. If you
wrote your own layer, see Breaking changes below.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:92ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#919F9F;--1:#5D6376&quot;&gt;// a remote cache layer's get and put, as they read today&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;(hash: string): &lt;/span&gt;&lt;span style=&quot;--0:#C5E478;--1:#3B61B0&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;{ body: Blob &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; Response; durationMs: number &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;undefined&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF6A83;--1:#A24848&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;(hash: string, body: Blob, meta: { durationMs: number }): &lt;/span&gt;&lt;span style=&quot;--0:#C5E478;--1:#3B61B0&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#7FDBCA;--1:#096E72&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// a remote cache layer&amp;#x27;s get and put, as they read todayget(hash: string): Promise&lt;{ body: Blob | Response; durationMs: number | undefined } | null&gt;put(hash: string, body: Blob, meta: { durationMs: number }): Promise&lt;void&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/756&quot;&gt;#756&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/761&quot;&gt;#761&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;try-vx-in-the-browser&quot;&gt;Try vx in the browser&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#try-vx-in-the-browser&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Try vx in the browser”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;The docs site has a “Try it” page that runs vx’s real planner in your
browser, bundled from core’s own source. Edit a file, an environment
variable or a &lt;code dir=&quot;auto&quot;&gt;vx.config.mjs&lt;/code&gt;, press Run, and read each task’s key, hit or
miss, and why a key moved. Core’s tests hold the page’s plan to what
&lt;code dir=&quot;auto&quot;&gt;vx run --dry=json&lt;/code&gt; prints.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:29ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--all&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--dry=json&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx run build --all --dry=json&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/789&quot;&gt;#789&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/791&quot;&gt;#791&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/793&quot;&gt;#793&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/797&quot;&gt;#797&lt;/a&gt;. Page:
&lt;a href=&quot;../../playground/&quot;&gt;Try it&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;brackets-are-literal-in-task-globs&quot;&gt;Brackets are literal in task globs&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#brackets-are-literal-in-task-globs&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Brackets are literal in task globs”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A bracket in &lt;code dir=&quot;auto&quot;&gt;cache.inputs.files&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;cache.outputs.files&lt;/code&gt; or
&lt;code dir=&quot;auto&quot;&gt;workspaceFiles&lt;/code&gt; now means a bracket. Read as a character class, an input
over a Next.js route like &lt;code dir=&quot;auto&quot;&gt;app/[id]/&lt;/code&gt; keyed nothing, so an edit replayed
an old output. An output over one deleted &lt;code dir=&quot;auto&quot;&gt;app/i/page.js&lt;/code&gt; and saved
nothing. &lt;code dir=&quot;auto&quot;&gt;\[id\]&lt;/code&gt; still works. &lt;code dir=&quot;auto&quot;&gt;CACHE_VERSION&lt;/code&gt; moved to v28.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:45ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;cache: { inputs: { files: [&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;app/[id]/**&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;] } }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;cache: { inputs: { files: [&amp;#x27;app/[id]/**&amp;#x27;] } }&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/765&quot;&gt;#765&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;configs-are-json-data&quot;&gt;Configs are JSON data&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#configs-are-json-data&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Configs are JSON data”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A project config must be JSON data on every path, because the cache key
folds its JSON. A function, symbol, bigint, &lt;code dir=&quot;auto&quot;&gt;NaN&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;Map&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;Date&lt;/code&gt;, cycle or
&lt;code dir=&quot;auto&quot;&gt;undefined&lt;/code&gt; inside an array is refused before the schema, with the path
that holds it. Before, &lt;code dir=&quot;auto&quot;&gt;vx watch&lt;/code&gt; accepted a function that &lt;code dir=&quot;auto&quot;&gt;vx run&lt;/code&gt;
refused, and a &lt;code dir=&quot;auto&quot;&gt;Map&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;Date&lt;/code&gt; loaded on both and was keyed as &lt;code dir=&quot;auto&quot;&gt;{}&lt;/code&gt; or a
string. An &lt;code dir=&quot;auto&quot;&gt;undefined&lt;/code&gt; property is still fine, and &lt;code dir=&quot;auto&quot;&gt;vx.workspace.ts&lt;/code&gt; is not
held to this rule.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:18ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--all&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx run build --all&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/792&quot;&gt;#792&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;stale-hit-fixes&quot;&gt;Stale-hit fixes&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#stale-hit-fixes&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Stale-hit fixes”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Two bugs could replay wrong output under a green run. Bun’s xxHash3 reads
only 32 bits of a seed, so the key fold carried 32 bits of state and two
input sets could share a key. The fold now feeds the seed forward
(&lt;code dir=&quot;auto&quot;&gt;CACHE_VERSION&lt;/code&gt; v29). And npm and Yarn link every workspace package at the
root, so a sandboxed task could read its own project through
&lt;code dir=&quot;auto&quot;&gt;node_modules&lt;/code&gt; without the read being reported. That read now fails the
task (&lt;code dir=&quot;auto&quot;&gt;CACHE_VERSION&lt;/code&gt; v30). Each bump makes every entry miss once.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:18ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--all&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx run build --all&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/775&quot;&gt;#775&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/806&quot;&gt;#806&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/812&quot;&gt;#812&lt;/a&gt;. Deep dive:
&lt;a href=&quot;../../blog/the-sandbox/&quot;&gt;The sandbox&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;faster-config-reloads-in-vx-watch&quot;&gt;Faster config reloads in vx watch&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#faster-config-reloads-in-vx-watch&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Faster config reloads in vx watch”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A watch cycle that re-reads configs now starts one config worker for the
round, not one per config. With 50 configs a round went from 148 ms to
10.5 ms.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:19ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;watch&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;test&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--all&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx watch test --all&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;vx-charts&quot;&gt;&lt;figure class=&quot;vx-bars&quot;&gt;&lt;figcaption&gt;Watch round, 50 configs&lt;/figcaption&gt;&lt;div class=&quot;vx-bar&quot; style=&quot;--w:100%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;before&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;148 ms&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;vx-bar vx-bar-lead&quot; style=&quot;--w:7.1%&quot;&gt;&lt;span class=&quot;vx-bar-name&quot;&gt;after&lt;/span&gt;&lt;span class=&quot;vx-bar-value&quot;&gt;10.5 ms&lt;/span&gt;&lt;span class=&quot;vx-bar-track&quot;&gt;&lt;span class=&quot;vx-bar-fill&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/785&quot;&gt;#785&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;breaking-changes&quot;&gt;Breaking changes&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#breaking-changes&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Breaking changes”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;A bracket in a task glob is a literal character, not a class
(&lt;a href=&quot;https://github.com/vznjs/vx/pull/765&quot;&gt;#765&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;A project config value JSON cannot carry fails to load
(&lt;a href=&quot;https://github.com/vznjs/vx/pull/792&quot;&gt;#792&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;A negated absolute path (&lt;code dir=&quot;auto&quot;&gt;!/x&lt;/code&gt;) in &lt;code dir=&quot;auto&quot;&gt;cache.inputs.files&lt;/code&gt; fails to load
(&lt;a href=&quot;https://github.com/vznjs/vx/pull/774&quot;&gt;#774&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;A remote cache layer’s &lt;code dir=&quot;auto&quot;&gt;get&lt;/code&gt; resolves &lt;code dir=&quot;auto&quot;&gt;{ body: Blob | Response }&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;put&lt;/code&gt;
takes a &lt;code dir=&quot;auto&quot;&gt;Blob&lt;/code&gt;; a layer that returns bytes is refused
(&lt;a href=&quot;https://github.com/vznjs/vx/pull/761&quot;&gt;#761&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See &lt;a href=&quot;../../guides/upgrading/&quot;&gt;Upgrading&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;how-to-update&quot;&gt;How to update&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#how-to-update&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “How to update”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:29ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;-D&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;@vzn/vx@latest&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm install -D @vzn/vx@latest&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;A standalone binary updates itself with &lt;code dir=&quot;auto&quot;&gt;vx upgrade&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;learn-more&quot;&gt;Learn more&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#learn-more&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Learn more”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;../../quickstart/&quot;&gt;Quickstart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../../benchmarks/&quot;&gt;Benchmarks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/vznjs/vx/releases&quot;&gt;Every release on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item>
<item><title>The foundation</title><link>https://vznjs.github.io/vx/releases/vx-0-0-21/</link><guid isPermaLink="true">https://vznjs.github.io/vx/releases/vx-0-0-21/</guid><description>The first 21 releases built the foundation: a TypeScript task graph with a content-addressed cache, a sandbox that proves what a task reads, and plugins for remote caches, telemetry and adoption.</description><pubDate>Sun, 13 Sep 2026 12:00:00 GMT</pubDate><category>release</category><content:encoded>&lt;p&gt;vx 0.0.1 shipped on 2026-05-13 and 0.0.21 on 2026-09-13. Those 21
releases built the foundation every later one stands on: a task graph
from TypeScript configs, a cache keyed on content, and seams for
plugins. This post covers what a new user meets, as it shipped then and
as it still works today.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In this release&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#tasks-in-typescript-one-graph&quot;&gt;Tasks in TypeScript, one graph&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#a-content-addressed-cache&quot;&gt;A content-addressed cache&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#filters-and-affected-runs&quot;&gt;Filters and affected runs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#watch-mode&quot;&gt;Watch mode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#dev-servers-in-the-graph&quot;&gt;Dev servers in the graph&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#the-sandbox&quot;&gt;The sandbox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#vx-why-and-vx-last&quot;&gt;vx why and vx last&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#vx-lock-and-frozen-runs&quot;&gt;vx lock and frozen runs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#plugins-on-seams&quot;&gt;Plugins on seams&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#adopting-from-turborepo-and-nx&quot;&gt;Adopting from Turborepo and Nx&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;tasks-in-typescript-one-graph&quot;&gt;Tasks in TypeScript, one graph&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#tasks-in-typescript-one-graph&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Tasks in TypeScript, one graph”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Each package declares its tasks in a &lt;code dir=&quot;auto&quot;&gt;vx.config.ts&lt;/code&gt;. A task is one shell
command, and &lt;code dir=&quot;auto&quot;&gt;dependsOn&lt;/code&gt; orders it: &lt;code dir=&quot;auto&quot;&gt;'^build'&lt;/code&gt; means &lt;code dir=&quot;auto&quot;&gt;build&lt;/code&gt; in every
package this one depends on. vx discovers the projects, evaluates every
config, and builds one graph for the whole workspace. A config is a
program, so shared settings are an import, not a special field.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;https://vznjs.github.io/vx/_astro/ec.w36nc.css&quot;&gt;&lt;figure class=&quot;frame has-title not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;packages/app/vx.config.ts&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:80ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { defineProject } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx/config&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;defineProject&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;tasks: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:4ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;build: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:6ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;dependsOn: [&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;^build&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:6ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;exec: { command: &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;tsc -b&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:6ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;cache: { inputs: { files: [&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;src/**&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;] }, outputs: { files: [&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;dist/**&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;] } },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:4ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import { defineProject } from &amp;#x27;@vzn/vx/config&amp;#x27;export default defineProject({  tasks: {    build: {      dependsOn: [&amp;#x27;^build&amp;#x27;],      exec: { command: &amp;#x27;tsc -b&amp;#x27; },      cache: { inputs: { files: [&amp;#x27;src/**&amp;#x27;] }, outputs: { files: [&amp;#x27;dist/**&amp;#x27;] } },    },  },})&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Commit &lt;a href=&quot;https://github.com/vznjs/vx/commit/4e7e62ebec80c1d7d3d2415f21680f28dc875009&quot;&gt;4e7e62e&lt;/a&gt;.
Docs: &lt;a href=&quot;../../guides/configure/#tasks-and-dependencies&quot;&gt;Tasks and dependencies&lt;/a&gt;.
Deep dive: &lt;a href=&quot;../../blog/config-in-typescript/&quot;&gt;Config in TypeScript&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;mermaid&quot; role=&quot;img&quot; aria-label=&quot;diagram&quot;&gt;flowchart LR
  C[&quot;vx.config.ts&quot;] --&gt; G[&quot;task graph&quot;] --&gt; K[&quot;cache keys&quot;] --&gt; H{&quot;hit?&quot;}
  H --&gt;|yes| R[&quot;restore outputs&quot;]
  H --&gt;|no| X[&quot;run, then save&quot;]&lt;/pre&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;a-content-addressed-cache&quot;&gt;A content-addressed cache&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#a-content-addressed-cache&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “A content-addressed cache”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Caching is opt-in, and a cached task lists its input files. vx never
guesses them. The key folds those files, the task’s resolved config,
the package’s &lt;code dir=&quot;auto&quot;&gt;package.json&lt;/code&gt;, the lockfile and the keys of the tasks it
depends on. Tracked, clean files are keyed by the blob ids already in
git’s index, so a warm run reads almost nothing. Entries live in a local
SQLite index with compressed archives, and a hit restores the outputs
and replays the logs.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:62ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;$ vx run build --all&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;─ vx 0.0.0 ───────────────────────────────────────────────────&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;projects  ▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:12ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;2 in run · 2 total&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;tasks     ▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:12ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;2 success · 2 total&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;cache     ▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:12ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;2 up-to-date&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;info      4 workers · local cache&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;time      32ms&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;result    2 tasks · all cached · 45ms saved · 32ms&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;$ vx run build --all─ vx 0.0.0 ───────────────────────────────────────────────────  projects  ▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰            2 in run · 2 total  tasks     ▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰            2 success · 2 total  cache     ▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰            2 up-to-date  info      4 workers · local cache  time      32ms  result    2 tasks · all cached · 45ms saved · 32ms&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/7&quot;&gt;#7&lt;/a&gt;, &lt;a href=&quot;https://github.com/vznjs/vx/pull/86&quot;&gt;#86&lt;/a&gt;,
commit &lt;a href=&quot;https://github.com/vznjs/vx/commit/613d5279a7ae189c0d29a0b08c9874aac5ca8e7f&quot;&gt;613d527&lt;/a&gt;.
Docs: &lt;a href=&quot;../../guides/configure/#caching&quot;&gt;Caching&lt;/a&gt;.
Deep dives: &lt;a href=&quot;../../blog/explicit-over-magical/&quot;&gt;Explicit over magical&lt;/a&gt;,
&lt;a href=&quot;../../blog/keys-from-git/&quot;&gt;Keys from git&lt;/a&gt;,
&lt;a href=&quot;../../blog/cascade-through-inputs/&quot;&gt;Cascade through inputs&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;filters-and-affected-runs&quot;&gt;Filters and affected runs&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#filters-and-affected-runs&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Filters and affected runs”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;--filter&lt;/code&gt; takes pnpm-style patterns: a name, a glob, a path, a
package with its dependencies (&lt;code dir=&quot;auto&quot;&gt;app...&lt;/code&gt;) or dependents (&lt;code dir=&quot;auto&quot;&gt;...lib&lt;/code&gt;).
&lt;code dir=&quot;auto&quot;&gt;--affected&lt;/code&gt; selects what changed since a git base, &lt;code dir=&quot;auto&quot;&gt;origin/HEAD&lt;/code&gt; by
default. A change to a workspace-level file that every key folds, such
as a lockfile no plugin claims, widens it to every project. A later
release made &lt;code dir=&quot;auto&quot;&gt;--affected&lt;/code&gt; include the changed projects’ dependents too.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:22ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;test&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--affected&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx run test --affected&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/58&quot;&gt;#58&lt;/a&gt;, &lt;a href=&quot;https://github.com/vznjs/vx/pull/210&quot;&gt;#210&lt;/a&gt;.
Docs: &lt;a href=&quot;../../cli/&quot;&gt;CLI&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;watch-mode&quot;&gt;Watch mode&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#watch-mode&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Watch mode”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;vx watch&lt;/code&gt; runs a task, then runs it again on every change. Each cycle
is a normal &lt;code dir=&quot;auto&quot;&gt;vx run&lt;/code&gt;, so the cache key decides what re-runs, and an edit
to an unrelated file costs a fully cached cycle. A task that writes into
its own project does not trigger itself: a cycle starts only when file
contents differ, not on every event.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:19ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;vx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;watch&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;test&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;--all&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;vx watch test --all&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/67&quot;&gt;#67&lt;/a&gt;.
Deep dive: &lt;a href=&quot;../../blog/watch-mode/&quot;&gt;Watch mode&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;dev-servers-in-the-graph&quot;&gt;Dev servers in the graph&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#dev-servers-in-the-graph&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Dev servers in the graph”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;exec.persistent&lt;/code&gt; marks a server or watcher that does not exit. Its
dependents start once it prints a line matching &lt;code dir=&quot;auto&quot;&gt;readyWhen&lt;/code&gt;, not after a
sleep. When the run ends, vx stops the server, and Ctrl-C leaves nothing
running.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;packages/web/vx.config.ts&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:86ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { defineProject } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx/config&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;defineProject&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;tasks: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:4ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;dev: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:6ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;exec: { command: &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;vite&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;, persistent: { readyWhen: &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;Local:&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; }, timeout: &lt;/span&gt;&lt;span style=&quot;--0:#F78C6C;--1:#AA0982&quot;&gt;30_000&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:4ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:4ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;e2e: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:6ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;dependsOn: [&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;dev&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:6ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;exec: { command: &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;playwright test&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:4ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import { defineProject } from &amp;#x27;@vzn/vx/config&amp;#x27;export default defineProject({  tasks: {    dev: {      exec: { command: &amp;#x27;vite&amp;#x27;, persistent: { readyWhen: &amp;#x27;Local:&amp;#x27; }, timeout: 30_000 },    },    e2e: {      dependsOn: [&amp;#x27;dev&amp;#x27;],      exec: { command: &amp;#x27;playwright test&amp;#x27; },    },  },})&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/62&quot;&gt;#62&lt;/a&gt;, &lt;a href=&quot;https://github.com/vznjs/vx/pull/189&quot;&gt;#189&lt;/a&gt;.
Docs: &lt;a href=&quot;../../guides/configure/#dev-tasks&quot;&gt;Dev tasks&lt;/a&gt;.
Deep dives: &lt;a href=&quot;../../blog/dev-servers-in-the-graph/&quot;&gt;Dev servers in the graph&lt;/a&gt;,
&lt;a href=&quot;../../blog/ctrl-c/&quot;&gt;Ctrl-C&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;the-sandbox&quot;&gt;The sandbox&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#the-sandbox&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “The sandbox”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;exec.sandbox&lt;/code&gt; runs a task where only what you granted exists. You
declare capabilities (&lt;code dir=&quot;auto&quot;&gt;read&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;write&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;network&lt;/code&gt;) and vx maps them to
bubblewrap on Linux and the system sandbox on macOS. An undeclared read
or write of the task’s own files fails the task and names the path, and
a failed task is never cached. That turns an input list from a promise
into a checked boundary.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;packages/app/vx.config.ts&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:94ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { defineProject } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx/config&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;defineProject&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;tasks: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:4ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;build: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:6ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;exec: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:8ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;command: &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;vite build&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:8ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;sandbox: { allow: { read: [&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;], write: [&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;dist/**&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;] } },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:6ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:6ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;cache: { inputs: { files: [&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;src/**&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;index.html&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;] }, outputs: { files: [&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;dist/**&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;] } },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:4ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import { defineProject } from &amp;#x27;@vzn/vx/config&amp;#x27;export default defineProject({  tasks: {    build: {      exec: {        command: &amp;#x27;vite build&amp;#x27;,        sandbox: { allow: { read: [&amp;#x27;.&amp;#x27;], write: [&amp;#x27;dist/**&amp;#x27;] } },      },      cache: { inputs: { files: [&amp;#x27;src/**&amp;#x27;, &amp;#x27;index.html&amp;#x27;] }, outputs: { files: [&amp;#x27;dist/**&amp;#x27;] } },    },  },})&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PRs &lt;a href=&quot;https://github.com/vznjs/vx/pull/15&quot;&gt;#15&lt;/a&gt;, &lt;a href=&quot;https://github.com/vznjs/vx/pull/102&quot;&gt;#102&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/pull/245&quot;&gt;#245&lt;/a&gt;,
commit &lt;a href=&quot;https://github.com/vznjs/vx/commit/d7f6e74af7e82c51301223b7912b725a7cad9c8d&quot;&gt;d7f6e74&lt;/a&gt;.
Docs: &lt;a href=&quot;../../guides/sandboxing/&quot;&gt;Sandboxing tasks&lt;/a&gt;.
Deep dive: &lt;a href=&quot;../../blog/the-sandbox/&quot;&gt;The sandbox&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;vx-why-and-vx-last&quot;&gt;vx why and vx last&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#vx-why-and-vx-last&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “vx why and vx last”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;vx why&lt;/code&gt; compares a task’s last two runs and names what moved its key: a
file, an env var, a config field, an upstream task. &lt;code dir=&quot;auto&quot;&gt;vx last&lt;/code&gt; replays a
recorded run’s summary from local history. Both read only what the runs
already stored.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:128ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;$ vx why lib#build&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;lib#build — run 01a11d16-a5b0-74af-a52d-bb0bbf33a1ed&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;this run   2026-10-08T19:56:25.939Z · success · executed · key 49a37e4bfb0bd487&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;previous   2026-10-08T19:56:18.576Z · cache-hit · up-to-date · key e291b2e50af34f01&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;verdict    cache key changed: file packages/lib/src/index.js&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;what changed (1 component, 4 unchanged):&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:4ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;changed file  packages/lib/src/index.js  09b76aaa26ac6afc3f6b09805e8ede78e0637954 → 838198e50b78e865ce6cde1f69d359ffeacc3063&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;what to do:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:4ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;file  an edit re-runs by design; a file the task does not read belongs out of cache.inputs.files&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;$ vx why lib#buildlib#build — run 01a11d16-a5b0-74af-a52d-bb0bbf33a1ed  this run   2026-10-08T19:56:25.939Z · success · executed · key 49a37e4bfb0bd487  previous   2026-10-08T19:56:18.576Z · cache-hit · up-to-date · key e291b2e50af34f01  verdict    cache key changed: file packages/lib/src/index.js  what changed (1 component, 4 unchanged):    changed file  packages/lib/src/index.js  09b76aaa26ac6afc3f6b09805e8ede78e0637954 → 838198e50b78e865ce6cde1f69d359ffeacc3063  what to do:    file  an edit re-runs by design; a file the task does not read belongs out of cache.inputs.files&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Commits &lt;a href=&quot;https://github.com/vznjs/vx/commit/7edfaebe7627d8cfd6a141554320beb98f5eb6dc&quot;&gt;7edfaeb&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/commit/4013941a0d28cbe5195ca32571a62a61d568c360&quot;&gt;4013941&lt;/a&gt;,
PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/333&quot;&gt;#333&lt;/a&gt;.
Docs: &lt;a href=&quot;../../guides/configure/#why-did-it-re-run&quot;&gt;Why did it re-run?&lt;/a&gt;.
Deep dive: &lt;a href=&quot;../../blog/why-did-this-rerun/&quot;&gt;Why did this re-run?&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;vx-lock-and-frozen-runs&quot;&gt;vx lock and frozen runs&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#vx-lock-and-frozen-runs&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “vx lock and frozen runs”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;vx lock&lt;/code&gt; writes every project’s resolved config to &lt;code dir=&quot;auto&quot;&gt;vx-lock.json&lt;/code&gt;.
&lt;code dir=&quot;auto&quot;&gt;vx run --frozen&lt;/code&gt; builds the graph from that file instead of evaluating
configs, and &lt;code dir=&quot;auto&quot;&gt;vx lock --check&lt;/code&gt; fails when the two drift. Run both in CI
and the graph a run sees is the one you reviewed.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;txt&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:48ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;$ vx lock&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;vx lock: locked 2 project configs → vx-lock.json&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;$ vx lock --check&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d6deeb;--1:#403f53&quot;&gt;vx lock --check: up to date (2 projects)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;$ vx lockvx lock: locked 2 project configs → vx-lock.json$ vx lock --checkvx lock --check: up to date (2 projects)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Commit &lt;a href=&quot;https://github.com/vznjs/vx/commit/133a55a1b534377484825b47b498b1fca5dc6275&quot;&gt;133a55a&lt;/a&gt;.
Docs: &lt;a href=&quot;../../guides/ci/#a-frozen-graph&quot;&gt;A frozen graph&lt;/a&gt;.
Deep dive: &lt;a href=&quot;../../blog/lock-and-frozen/&quot;&gt;vx lock&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;plugins-on-seams&quot;&gt;Plugins on seams&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#plugins-on-seams&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Plugins on seams”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Core runs and caches on this machine and applies no plugin by default.
Everything else is a plugin declared in &lt;code dir=&quot;auto&quot;&gt;vx.workspace.ts&lt;/code&gt;, named by its
package. By 0.0.21 these shipped: &lt;code dir=&quot;auto&quot;&gt;@vzn/vx-reapi&lt;/code&gt; (remote cache and
remote execution on any Bazel REAPI server), &lt;code dir=&quot;auto&quot;&gt;@vzn/vx-lockfile&lt;/code&gt; (each
package keyed on its own dependencies), &lt;code dir=&quot;auto&quot;&gt;@vzn/vx-otel&lt;/code&gt; (OpenTelemetry),
a GitHub Actions job summary (today &lt;code dir=&quot;auto&quot;&gt;@vzn/vx-ci&lt;/code&gt;), &lt;code dir=&quot;auto&quot;&gt;@vzn/vx-mcp&lt;/code&gt; (a
&lt;code dir=&quot;auto&quot;&gt;vx mcp&lt;/code&gt; server for coding agents) and &lt;code dir=&quot;auto&quot;&gt;@vzn/vx-schedule-history&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;vx.workspace.ts&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:70ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { defineWorkspace } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx/config&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { bun } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx-lockfile&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; { reapi } &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;@vzn/vx-reapi&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C792EA;--1:#8844AE&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;defineWorkspace&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot; style=&quot;--ecIndent:2ch&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;plugins: [&lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;bun&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;(), &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;reapi&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;({ endpoint: &lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#984E4D&quot;&gt;grpcs://cache.internal:443&lt;/span&gt;&lt;span style=&quot;--0:#D9F5DD;--1:#111111&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; })],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import { defineWorkspace } from &amp;#x27;@vzn/vx/config&amp;#x27;import { bun } from &amp;#x27;@vzn/vx-lockfile&amp;#x27;import { reapi } from &amp;#x27;@vzn/vx-reapi&amp;#x27;export default defineWorkspace({  plugins: [bun(), reapi({ endpoint: &amp;#x27;grpcs://cache.internal:443&amp;#x27; })],})&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/259&quot;&gt;#259&lt;/a&gt;,
commits &lt;a href=&quot;https://github.com/vznjs/vx/commit/02d6b67b4b904d28ed3fa27e8fa214c0878b8acc&quot;&gt;02d6b67&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/commit/a485690c3def0f7dd4c1d6f8f122533c374fec50&quot;&gt;a485690&lt;/a&gt;,
&lt;a href=&quot;https://github.com/vznjs/vx/commit/b5e534d39d8ecdf6483f80f79a945138df5ab132&quot;&gt;b5e534d&lt;/a&gt;.
Docs: &lt;a href=&quot;../../guides/plugins/&quot;&gt;Plugins&lt;/a&gt;.
Deep dives: &lt;a href=&quot;../../blog/pipeline-with-seams/&quot;&gt;A pipeline with seams&lt;/a&gt;,
&lt;a href=&quot;../../blog/remote-execution/&quot;&gt;Remote execution&lt;/a&gt;,
&lt;a href=&quot;../../blog/lockfile-aware-keys/&quot;&gt;Lockfile-aware keys&lt;/a&gt;,
&lt;a href=&quot;../../blog/agents-and-mcp/&quot;&gt;Agents and MCP&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;adopting-from-turborepo-and-nx&quot;&gt;Adopting from Turborepo and Nx&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#adopting-from-turborepo-and-nx&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Adopting from Turborepo and Nx”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;@vzn/vx-migrate&lt;/code&gt; covers adoption. Its &lt;code dir=&quot;auto&quot;&gt;turbo()&lt;/code&gt; plugin runs a Turbo
repo under vx with nothing written, reading &lt;code dir=&quot;auto&quot;&gt;turbo.json&lt;/code&gt; and the
package scripts each run. &lt;code dir=&quot;auto&quot;&gt;bunx @vzn/vx-migrate&lt;/code&gt; writes native
&lt;code dir=&quot;auto&quot;&gt;vx.config.ts&lt;/code&gt; files from &lt;code dir=&quot;auto&quot;&gt;turbo.json&lt;/code&gt; or an Nx graph, and
&lt;code dir=&quot;auto&quot;&gt;turboCache()&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;nxCache()&lt;/code&gt; keep an existing remote cache. In any
other repo, &lt;code dir=&quot;auto&quot;&gt;vx init&lt;/code&gt; writes starter configs from the &lt;code dir=&quot;auto&quot;&gt;package.json&lt;/code&gt;
scripts.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:20ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;bunx&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;@vzn/vx-migrate&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;bunx @vzn/vx-migrate&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;PR &lt;a href=&quot;https://github.com/vznjs/vx/pull/302&quot;&gt;#302&lt;/a&gt;,
commit &lt;a href=&quot;https://github.com/vznjs/vx/commit/14878720a463e532520eac5c8e206d5e8fd9a1f1&quot;&gt;1487872&lt;/a&gt;.
Docs: &lt;a href=&quot;../../guides/migrate/&quot;&gt;Migrate&lt;/a&gt;.
Deep dives: &lt;a href=&quot;../../blog/from-turborepo/&quot;&gt;From Turborepo&lt;/a&gt;, &lt;a href=&quot;../../blog/from-nx/&quot;&gt;From Nx&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;breaking-changes&quot;&gt;Breaking changes&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#breaking-changes&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Breaking changes”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;The package became &lt;code dir=&quot;auto&quot;&gt;@vzn/vx&lt;/code&gt;, and a project config lists &lt;code dir=&quot;auto&quot;&gt;tasks&lt;/code&gt;
directly, with no &lt;code dir=&quot;auto&quot;&gt;run: { tasks }&lt;/code&gt; wrapper
(&lt;a href=&quot;https://github.com/vznjs/vx/pull/43&quot;&gt;#43&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See &lt;a href=&quot;../../guides/upgrading/&quot;&gt;Upgrading&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;how-to-update&quot;&gt;How to update&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#how-to-update&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “How to update”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal not-content&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sh&quot; class=&quot;wrap&quot; style=&quot;--ecMaxLine:29ch&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#82AAFF;--1:#3B61B0&quot;&gt;-D&lt;/span&gt;&lt;span style=&quot;--0:#D6DEEB;--1:#403F53&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#ECC48D;--1:#3B61B0&quot;&gt;@vzn/vx@latest&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm install -D @vzn/vx@latest&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;A standalone binary updates itself with &lt;code dir=&quot;auto&quot;&gt;vx upgrade&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;sl-heading-wrapper level-h2&quot;&gt;&lt;h2 id=&quot;learn-more&quot;&gt;Learn more&lt;/h2&gt;&lt;a class=&quot;sl-anchor-link&quot; href=&quot;#learn-more&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;sl-anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot; data-pagefind-ignore=&quot;&quot;&gt;Section titled “Learn more”&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;../../quickstart/&quot;&gt;Quickstart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../../benchmarks/&quot;&gt;Benchmarks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/vznjs/vx/releases&quot;&gt;Every release on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item>
</channel>
</rss>