DEV Community

Cover image for Give your coding agent the build's memory
VX
VX

Posted on Originally published at vznjs.github.io

Give your coding agent the build's memory

A coding agent dropped into a large monorepo spends a surprising share
of its tokens working out how the build works: reading turbo.json or
a hundred project.json files, guessing which task to run, re-running
things to see whether they are cached. The runner already knows all of
that. @vzn/vx-mcp hands it over.

// vx.workspace.ts
import { defineWorkspace } from '@vzn/vx/config'
import { mcp } from '@vzn/vx-mcp'

export default defineWorkspace({ plugins: [mcp()] })
Enter fullscreen mode Exit fullscreen mode
// Claude Code: .mcp.json at the workspace root — or: claude mcp add vx -- vx mcp
{ "mcpServers": { "vx": { "command": "vx", "args": ["mcp"] } } }
Enter fullscreen mode Exit fullscreen mode

Cursor, Continue.dev and VS Code Copilot take the same command-and-args
shape. Run the agent from inside the workspace and vx mcp finds the
workspace and its cache from the current directory, exactly as vx run
does.

What it answers

Tool The question
listTasks What can I run here? Every project and task as a run would see them, plugin stages included.
getCacheStats What is the cache's state right now? Entries, size, runs and hit rate, per workspace or per project.
getRunHistory What have I been running and how fast? Recent runs with per-task p50, p99, success rate, hit rate.
explainCacheKey What is the cache identity of pkg#build? The latest entry's hash, command, exit code, duration, size.
whyDidThisRerun Why did pkg#test re-execute instead of hitting? The run's key against the previous run's.
getTaskLog What did this task print? A failure's output or the cached log, as vx last --log reads it.
pruneCache Free cache space by age or size; a dry run unless the call says dryRun: false.
planInit What would adopting vx write here? Each file and its TODOs, as vx init --dry --format json plans them.
searchDocs Where is this documented? The reference sections that match, offline, as vx docs finds them.
checkLock Is the config lock current? Each drift vx lock --check finds, before a --frozen run.
getConfig What does this task declare? Its resolved inputs, outputs, env and sandbox, as vx show prints them.
getFailures Why did the last run fail? Each failed task's output and the files it names.
getWorkspaceInfo What is this workspace? Versions and state, the plugins declared, the flaky tasks, whether vx-lock.json exists — the facts a bug report needs.
runTasks Run these tasks. The exit code and the run summary, from vx run --format json.
planTasks What would run, and why. The plan from vx run --dry=json; nothing runs.

The history tools read the same local cache.db tables that vx why,
vx last and vx info read. getRunHistory calls a task flaky only
on a real nondeterminism signal, a within-run retry or one key that
both failed and succeeded, so an agent does not learn to shrug at
repeated failures on changing inputs.

Only runTasks runs anything, through vx run --format json itself
(planTasks asks the same CLI for --dry=json),
so the CLI's selection, refusals and sandbox apply. mcp({ run: ['test'] })
limits it to the tasks you name, and run: false turns it off. The transport is
stdio, which is process-private, so there is no port, no auth and no
attack surface beyond the process the agent already spawned.

Why it is about 230 lines

MCP over stdio is newline-delimited JSON-RPC 2.0 and the three methods
an agent needs: initialize, tools/list, tools/call, plus ping.
The plugin speaks it natively in about 230 lines with no dependencies; the reference SDK pulls
in an HTTP stack this transport never uses. A tool's own refusal ("a
task id must be project#task") comes back as an isError result the
agent can read and correct, not as a protocol error that ends the
conversation.

It is also the clearest example of the commands seam doing what it is
for: one plugin contributes one verb, vx help lists it under "Plugin
commands" from any directory inside the workspace that declares it,
and outside such a workspace the verb does not exist. Core knows
nothing about agents.

The other half

The MCP server is how an agent reads the build. The other half of
working with agents is letting one run the build safely, and that is
what the rest of vx already is: explicit inputs, strict
outputs
, a sandbox that
denies undeclared reads and any domain no task of the run lists, and a
teardown that leaves nothing running when the agent's
session is cancelled. An agent that can only run declared commands
against declared paths is an agent you can leave alone with the
repository.

The guide is Plugins › vx mcp.


Originally published on the vx blog. vx is an MIT task runner and build cache for JS monorepos: github.com/vznjs/vx.

Written with AI assistance.

Top comments (0)