Turn annotated JavaScript files into typed css-visual-diff CLI commands under the verbs namespace.
css-visual-diff verbs turns annotated JavaScript files into CLI commands. It is intended for programmable visual catalog workflows where YAML alone is too static.
Repository-scanned commands live under:
css-visual-diff verbs ...
They are not injected at the root of the CLI. This keeps scan errors, duplicate command paths, and script-specific flags local to the verbs subtree.
Built-ins include:
css-visual-diff verbs script compare region ...
css-visual-diff verbs script compare brief ...
css-visual-diff verbs catalog inspect-page ...
The lazy verbs command discovers scripts from these sources:
.css-visual-diff.yml, .css-visual-diff.override.yml),.css-visual-diff.yml, .css-visual-diff.override.yml),CSS_VISUAL_DIFF_VERB_REPOSITORIES,css-visual-diff verbs --repository ./examples/verbs examples catalog inspect-page \
http://127.0.0.1:8767/ '#cta' /tmp/cssvd-example \
--output json
--verb-repository is an alias for --repository.
export CSS_VISUAL_DIFF_VERB_REPOSITORIES="/path/to/project/verbs:/path/to/other/verbs"
css-visual-diff verbs custom command ...
Use the platform path-list separator (: on Linux/macOS).
For repeatable project workflows, put a local config file at the git root:
# .css-visual-diff.yml
verbs:
repositories:
- name: project
path: ./verbs
Then run the generated command without a bootstrap flag:
css-visual-diff verbs project command ...
Relative paths are resolved relative to the config file that declares them. This means path: ./verbs in /repo/.css-visual-diff.yml resolves to /repo/verbs, even when the command is run from /repo/packages/button.
Use .css-visual-diff.override.yml for private local repositories that should not be committed. Add it to .gitignore when it contains machine-specific or experimental paths.
Current-working-directory config files are also discovered. This lets a monorepo combine a git-root .css-visual-diff.yml with a package-local .css-visual-diff.yml or .css-visual-diff.override.yml when the command is run from that package directory.
System and user app config can also declare repositories:
verbs:
repositories:
- name: local
path: ./verbs
- name: disabled
path: ./disabled
enabled: false
Relative paths are resolved relative to the config file.
function hello(name) {
return `hello ${name}`
}
__verb__("hello", {
parents: ["custom"],
output: "text",
fields: {
name: { argument: true, required: true }
}
})
Run:
css-visual-diff verbs --repository ./verbs custom hello Manuel
Supported metadata sentinels:
__package__({...})__section__("slug", {...})__verb__("functionName", {...})doc`...` These are statically scanned to generate commands. At runtime they are installed as no-op helpers so the script can be required safely.
Metadata must be static literal JavaScript: object literals, arrays, strings, numbers, booleans, and null. Do not use computed values, spreads, function calls, or template substitutions inside metadata.
__package__ controls default command grouping.
__package__({
name: "catalog",
parents: ["examples"],
short: "Example catalog workflows"
})
__verb__("inspectPage", {
parents: ["examples", "catalog"],
short: "Inspect one page into a catalog",
output: "structured",
fields: {
url: { argument: true, required: true, help: "URL to inspect" },
selector: { argument: true, required: true, help: "CSS selector" },
outDir: { argument: true, required: true, help: "Output directory" },
values: { bind: "all" },
failOnMissing: { type: "bool", default: false },
}
})
Command names are normalized for CLI usage. A function named inspectPage becomes command inspect-page.
Common field keys:
typehelpshortdefaultchoicesrequiredargument / argbindsectionSupported field types:
stringbool / booleanint / integerfloat / numberstringList / list / []stringchoicechoiceListArgument fields become positional arguments. Other fields become flags.
Example:
fields: {
url: { argument: true, required: true },
artifacts: {
type: "choice",
choices: ["bundle", "css-json", "html"],
default: "css-json",
},
failOnMissing: { type: "bool", default: false },
}
Generates usage like:
verbs examples catalog inspect-page <url> [flags]
--artifacts css-json
--failOnMissing
A parameter with the same name as a field receives that value:
function inspect(url, selector, outDir) {}
bind: "all"Passes one object containing all resolved field values:
function inspectPage(url, selector, outDir, values) {
if (values.failOnMissing) { /* ... */ }
}
__verb__("inspectPage", {
fields: {
url: { argument: true, required: true },
selector: { argument: true, required: true },
outDir: { argument: true, required: true },
values: { bind: "all" },
failOnMissing: { type: "bool", default: false },
}
})
bind: "context"Passes invocation context:
function debug(ctx) {
return ctx
}
__verb__("debug", {
fields: { ctx: { bind: "context" } }
})
Context contains verb name, function name, module path, source file, root directory, raw values, and section values.
Sections group related flags.
__section__("target", {
fields: {
url: { type: "string", required: true },
waitMs: { type: "int", default: 0 },
}
})
function run(target) {
return target.url
}
__verb__("run", {
fields: { target: { bind: "target" } }
})
Default output is structured/Glazed output. Return objects or arrays to get rows that can be formatted as table/json/yaml/csv.
css-visual-diff verbs ... --output json
For plain text commands:
__verb__("brief", {
output: "text",
fields: { /* ... */ }
})
Common output aliases include:
structuredglazetabletextrawwriterplainPrefer structured output for catalog workflows and write large artifacts to files.
css-visual-diff verbs catalog inspect-page \
http://127.0.0.1:8767/ '#cta' /tmp/cssvd-page \
--slug cta \
--name CTA \
--artifacts css-json \
--output json
Authoring mode: selector misses are recorded and returned as structured rows without failing:
css-visual-diff verbs catalog inspect-page \
http://127.0.0.1:8767/ '#missing' /tmp/cssvd-authoring \
--slug missing \
--output json
CI mode: selector misses write manifest/index and exit non-zero:
css-visual-diff verbs catalog inspect-page \
http://127.0.0.1:8767/ '#missing' /tmp/cssvd-ci \
--slug missing \
--failOnMissing \
--output json
If two repositories define the same generated command path, command construction fails with a clear error such as:
duplicate jsverb path "script compare region" from builtin:scripts/compare.js and /repo/verbs/compare.js
Resolve by changing parents, function name, or __verb__({ name/command }) metadata.
Earlier prototypes injected generated JavaScript commands at the root command. The supported shape is now:
css-visual-diff verbs ...
This avoids surprising root command conflicts and makes script repository problems local to the verbs subtree.
The ticket for the Goja/jsverbs work includes reproducible scripts under:
ttmp/2026/04/24/CSSVD-GOJA-JS-API--design-goja-javascript-api-for-programmable-visual-catalog-workflows/scripts/
Useful binary smokes:
scripts/006-binary-help-smoke.sh
scripts/007-binary-js-api-success-smoke.sh
scripts/008-binary-js-api-typed-error-smoke.sh
scripts/009-binary-catalog-smoke.sh
scripts/010-binary-built-in-catalog-inspect-page-smoke.sh