v2.2.2July 17, 2026
One machine, one device. And an index that stops repeating itself.
A reliability release across the whole stack. A lifetime-plan user reported the CLI showing his paid plan while VS Code, on the same machine and reading the same licence file, insisted he was on Free: vexp had been counting the CLI and the extension as two separate devices all along. Underneath it, a deeper one: your index was storing the same connection over and over, up to 45 times, which quietly skewed how results were ranked. Plus git hooks that turn out never to have run on an npm install, honest answers when a file has nothing to index, and three fixes for agents that got stuck.
Your licence is the same one in the CLI and in VS Code. A lifetime-plan user watched the CLI report his paid plan correctly while VS Code, on the same machine and reading the same licence file, called it Free and refused to add a second repo. vexp identifies a machine with a value it invents on first run and keeps privately, so the CLI and the extension had each invented their own and registered as two separate devices. On a plan that allows one device, whichever checked in first took the slot and the other was turned away, which from the inside is indistinguishable from having no licence at all. Both now settle on a single identity per machine, and the one your account already knows about is the one that wins. Updating is enough: a client that had been pushed to Free re-checks under the identity the server already has and is let straight back in.
Your index stops storing the same connection dozens of times. Every time vexp re-resolved your call graph, which is every time you save, it appended the whole set of connections again instead of recognising the ones it already had. Real indexes reached 45 times their true size: 270,589 stored connections for 5,951 real ones, one pair of functions recorded 75 times over. That was never just wasted space. vexp ranks results partly by how connected a symbol is, so a symbol counted 75 times looked 75 times more important than it was, and vexp flow answered with the same route printed several times because each copy looked like its own path. Both are fixed at the root: repeats are now rejected on the way in, while genuinely distinct call sites on the same pair are kept, because that is real multiplicity rather than duplication. Existing projects collapse once, automatically, the next time vexp opens them. No reindex, nothing to click, and if the cleanup cannot run for any reason your index keeps working exactly as it does today.
Git hooks were never running your index on an npm install. The git hook vexp installs looked for a program that does not exist in the distribution, so on an npm install both of the places it checked came up empty every single time and the hook quietly did nothing. It now uses the command that is actually there. Installs where no vexp is on your PATH at all, which is every VS Code extension install since it carries its own copy, fall back to the exact binary that is running, rewritten on every start so it can never go stale across an upgrade or a Node version switch.
vexp tells you when a file simply has nothing to index. vexp indexes declarations: functions, classes, methods, types. A file that declares none of those, a config object, a barrel of re-exports, a script that is just top-level statements, indexes to zero symbols. That is expected, but vexp answered as though the file had never been indexed at all, which sent people looking for a bug that was not there. One Tier 4 user concluded vexp did not support .mjs files, when the real answer was that their .mjs files were config objects. vexp now checks first and, when the file is indexed, says so and explains what genuinely extracts nothing. Asking about a file from inside a subfolder works too: a relative path used to be looked up against the wrong location and reported as missing.
vexp is visible before your first index. vexp only starts on its own once a project has an index, so in a project it had never seen it showed nothing at all: no status bar, and a sidebar icon that can hide in the activity bar overflow. The first thing you needed was the one thing you could not find. The status bar now starts on a prompt to run that first index. Commands that need an open folder also used to fail with a bare "command not found"; they now say what is actually wrong.
Running out of daily calls no longer looks like a broken install. On the Starter plan vexp stops itself once the day's 20 calls are spent, and VS Code says exactly that in the status bar. Every other agent got something far worse: a bare connection error, which a model reads as a passing glitch and retries, and retries. One user's local model looped on it for over 200,000 tokens and concluded vexp had broken his whole setup, which from where he sat it had. Agents now get a clear, final answer that says the quota is spent, when it resets, and not to retry until it does. Activating a licence clears it on the spot, so upgrading mid-day is never held to the free tier's reset.
The guard stops blocking searches vexp cannot answer. The opencode guard that steers your agent to vexp instead of raw search was refusing every grep and glob while vexp was running, whatever they were aimed at: runtime logs, build output, files outside your project. vexp has no answer for any of those, so the refusal was a dead end rather than a redirect. One agent debugging a rendering bug had its log searches blocked, was told to use vexp instead, and was left with no working tool at all. The guard now blocks only what vexp actually indexed, your source, and steps aside for everything else. It never touches shell commands either, which is what keeps an escape hatch open for everything the index does not cover.
A blocked search tells your agent what to do instead. The refusal used to say only that vexp was running, which a model reads as a tool failure, something to route around rather than a rule to follow. It now says plainly what to call instead, and the generated instructions spell out what vexp does not cover, so your agent stops both working around the block and spending calls on files that were never indexed.
Every agent is told how to phrase a query, not just Claude Code and Cursor. vexp finds code by identifier and path first, so a question written as prose ranks far worse than the same question anchored on the symbols and files it is about. That one rule had only ever been written into 2 of the 9 agent instruction sets, and one example actively demonstrated the weak version. Two separate reports that "the index seems not very useful" traced straight back to it. All nine now carry the same guidance from a single shared source, with examples built on real identifiers, and a test fails if any template loses it. Nothing changed in the engine: the index was never the problem.
Setting up agents no longer reports success while configuring nothing. Agent names had to match exactly, so asking for "opencode" rather than "Opencode" matched nothing, configured nothing, and still printed success and exited cleanly. That is the worst possible outcome for a flag whose whole purpose is unattended automation: a CI step that sets up no agent at all and reports green. Names now match regardless of case and punctuation, and one that still matches nothing is a hard error listing the valid names with a suggestion. The whole list is checked before anything is written, so a single typo can no longer leave a half-configured project behind.
A hand-tuned guard is kept when you upgrade. Setup still refreshes the opencode guard plugin whenever it differs, since freezing you on a stale one would be worse, but your previous version is now saved next to it as a .vexp-bak file, the same treatment every other vexp-managed config file already gets.