Skip to content
vxvx
GitHubBlueskydev.toRSS

Plugin commands

A plugin declared in .vx/workspace.ts can add verbs:

import { definePlugin, type VxPlugin } from '@vzn/vx'
export function mcp(): VxPlugin {
return definePlugin(import.meta, {
commands: {
mcp: {
description: 'serve the run history to an AI agent over stdio',
async run(argv, ctx) {
// ctx.workspaceRoot, ctx.cacheDir, ctx.concurrency, ctx.cache, ctx.warn(...)
return 0 // the process exit code
},
},
},
})
}

The plugin’s name is its package name, which definePlugin reads from import.meta; a plain object is refused when the workspace loads. ctx.cache reads the plugin’s own entries as setup writes them (the local store, then each remote the workspace’s cache plugins supply, under the run’s scope), read-only, opened on first use.

(@vzn/vx-history ships exactly this: vx history, what it learned per task and the reservation its admit hook packs.) The dispatcher tries core’s verbs first and consults plugins only for a word core does not know, loading the workspace config from the cwd to find them (outside a workspace the verb is simply unknown). A plugin verb that names a core verb, or one plugins of two packages both declare, is refused when the workspace loads — such a verb could never run, or would hide the other plugin’s. Plugins of one package are one owner (two of its plugins may carry the same verb): the first declared runs. A plugin verb’s return value is the exit code, an integer 0–255 (anything else — nothing, a fraction, 256, which the OS would keep as 0 — fails naming the plugin and the verb), and a thrown UserError prints as cleanly as core’s own. Anything else thrown fails in one line, no stack: plugin '<p>' failed in command '<verb>': <msg>. vx help lists every plugin verb under “Plugin commands”, with the plugin’s name.

An unknown verb is answered with what this workspace knows: the “did you mean” set is core’s verbs AND the ones its plugins declare (the lookup that just failed already loaded them, so it costs nothing), and when nothing is close enough to guess, a second line says where a verb can come from — the verbs declared here, or that .vx/workspace.ts is what would declare one, or that there is no workspace here at all. Core still names no package: it lists what the workspace itself declares.

Turborepo, Nx and other product names are trademarks of their owners. vx is not affiliated with or endorsed by them.