DEV Community

Cover image for Built for the agent at the keyboard
VX
VX

Posted on Edited on Originally published at vznjs.github.io

Built for the agent at the keyboard

A coding agent can't read a progress bar. It parses stdout. So every
vx answer comes as JSON with a schema, a failure keeps its log and the
files it blames, and the run history is a SQLite file.

diagram

The result on stdout, the logs on stderr

vx run prints for people. Then vx last --format json gives the same
run as one JSON document, a row per task. Notices go to stderr, so a
pipe sees only the result.

$ vx run bundle typecheck --all
$ vx last --format json | jq '.invocation | {runId, command, taskCount, failedCount, hitCount, exitOk}'
{
  "runId": "01a16b0f-dbf0-75fc-aaaa-7ce32e7c3a57",
  "command": "vx run bundle typecheck --all",
  "taskCount": 2,
  "failedCount": 1,
  "hitCount": 0,
  "exitOk": false
}
$ vx last --format json | jq '.tasks[0] | {project, task, status, exitCode, durationMs, hash}'
{
  "project": "packages/api",
  "task": "bundle",
  "status": "success",
  "exitCode": 0,
  "durationMs": 5,
  "hash": "f2bf5dd5f2d36920"
}
Enter fullscreen mode Exit fullscreen mode

vx show, vx info, vx why and vx cache clean take the same
--format json, and vx run --dry=json prints the plan before a run.

Every shape has a schema

Each JSON shape ships as a schema in node_modules/@vzn/vx/schemas/:
plan.json, show.json, info.json, why.json, last.json,
cache.json. A new field is a schema change, never a surprise.

A test checks each command's output against its schema. Refusals are
JSON too: A refusal an agent can read.

A failure keeps its log and its files

When a task fails, an agent wants what it printed and which files it
blames. vx saves both:

$ vx last --failed --format json | jq '.tasks[] | select(.status == "failed") | {status, exitCode, output, locations}'
{
  "status": "failed",
  "exitCode": 1,
  "output": "src/index.ts:3:7 - error TS2322: Type string is not assignable to type number\n",
  "locations": [
    {
      "file": "/work/demo/packages/api/src/index.ts",
      "line": 3,
      "col": 7
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

locations lists only files that exist. Secrets are masked. vx keeps
the newest 50 failed runs.

The history is a SQLite file

Every task of every run goes into cache.db: time, CPU, peak memory,
status and cache result. No export step. Query it directly:

$ sqlite3 .vx/cache/cache.db "
  SELECT project, task, status, duration_ms FROM runs
  WHERE run_id = (SELECT run_id FROM runs ORDER BY id DESC LIMIT 1)
  ORDER BY duration_ms DESC;"
packages/api|typecheck|failed|6
packages/api|bundle|success|5
Enter fullscreen mode Exit fullscreen mode

Docs and a skill, as markdown

llms.txt indexes every docs page
as markdown, and
llms-full.txt is the whole
site in one file.

@vzn/vx also ships a SKILL.md that teaches an agent to run, debug
and query vx:

$ mkdir -p .claude/skills/vx
$ cp node_modules/@vzn/vx/skills/vx/SKILL.md .claude/skills/vx/
Enter fullscreen mode Exit fullscreen mode

bunx skills add vznjs/vx installs the same skill. The
agents guide and
machine-readable output have the
details.

One-project workspace · vx dbe4033 · 2026-10-23

More at vznjs.github.io/vx.


Originally published on the vx blog. vx is open-source (MIT) task orchestration with a build cache: vznjs.github.io/vx · GitHub.

Written with AI assistance.

Top comments (0)