Public tooling extracted from the Vouchington product monorepo. Two npm packages, one CLI.
Обзор
Public tooling extracted from the Vouchington product monorepo. Two npm packages, one CLI. Both packages are published to npm. Releases go through the Release workflow (workflow_dispatch) using npm trusted publishing (OIDC). Do not publish from a laptop. The repository also publishes the public security-triage, vouchington-workflow, vouchington-testing, and vouchington-database agent plugins. security-triage has one repository-neutral security-finding skill. vouchington-workflow provides reusable implementation, commit, GitHub Actions, Dependabot, package-metadata, npm-publishing, static-analysis, planning, issue-management, blackboard journaling, retrospective and follow-up review, CI-log review, stacked-pull-request draining, and pull-request-description skills. All plugins use one canonical skills/ tree for every supported host; consumer repositories add their local mechanics and policy in repository-local instruction files or thin wrapper skills.
README
vouchington-tooling
Public tooling extracted from the Vouchington product monorepo. Two npm packages, one CLI.
| Package | What it is |
|---|---|
vouchington-tooling |
Libraries plus the vouchington CLI |
eslint-plugin-vouchington |
Non-generic Vouchington ESLint / Oxlint rules |
Both packages are published to npm. Releases go through the Release workflow (workflow_dispatch) using npm trusted publishing (OIDC). Do not publish from a laptop.
Agent plugins
The repository also publishes the public security-triage,
vouchington-workflow,
vouchington-testing, and
vouchington-database agent plugins. security-triage has one
repository-neutral security-finding skill. vouchington-workflow provides reusable implementation,
commit, GitHub Actions, Dependabot, package-metadata, npm-publishing, static-analysis, planning, issue-management,
blackboard journaling, retrospective and follow-up review, CI-log review, stacked-pull-request draining, and
pull-request-description skills. All plugins use one canonical
skills/ tree for every supported host; consumer repositories add their local mechanics and policy
in repository-local instruction files or thin wrapper skills. The portable issue workflow verifies live
collaborator authority before creation, routes denied external work to a verified consumer tracker,
uses existing labels without extra approval, and requires explicit approval before creating labels.
Consumers still own repository defaults, taxonomy definitions, templates, and stricter policy.
Domain skill entrypoints read applicable AGENTS.md and a repository-local adapter when present.
The default adapter is .agents/skills//SKILL.md; local instructions may name an
alias, such as nextjs-vitest-test-authoring → web-vitest-test-authoring. A previously read
adapter or canonical skill is not loaded again. This is agent guidance, not runtime concatenation
or a new loader API; linked files and plugin installation alone do not prove an adapter was read.
Workflow references load by phase. Plans are proportional and saved once outside Git, including
in an existing issue or PR description; the skills do not require a separate Plan issue or template.
The github-actions-authoring skill requires event-driven orchestration and prohibits remote-state
polling in CI; it loads github-actions-checklist as a prerequisite. The checklist also defines the
portable trigger, 30-minute timeout, runner, action-pinning, dependency-update testing, real required
checks, domain-oriented test jobs, and branch-aware concurrency policies.
security-triage is intentionally repository-neutral: it analyzes findings and returns a versioned
handoff, while each consuming repository owns issue taxonomy and issue creation.
vouchington-testing supplies shared test-authoring guidance plus Vitest, backend, Next.js,
Playwright, Storybook, Swift, and .NET specializations. vouchington-database supplies PostgreSQL
performance and UUIDv7 partitioning guidance. Consumer wrappers own runner configuration, fixtures,
database policy, and commands.
These integrations are opt-in. Installing a package or cloning this repository does not enable an AI coding platform, transcript adapter, workflow, or CI provider. Select only the plugin directories, transcript formats, and provider-specific Actions adapters that your repository explicitly adopts; generic skills remain host-neutral and read the consuming repository’s local instructions.
This repository adopts Agent Blackboard for durable agent-session notes. The vouchington-workflow
journaling skills call the tools of the vouchington mcp server,
which vouchington-machines registers once per machine as vouchington-tooling in each harness,
not per repository; it also disables the upstream agent-blackboard plugin machine-wide (decision
vouchington#1019). This repository carries no MCP, Claude settings, or Codex config for it. Credential-management commands remain CLI-only. MCP is the supported path.
When it is unavailable, the journaling skill has agents tell the human how to restore it; its CLI
fallback is a last resort and requires both a journal entry and a human-facing notice.
Install (opt-in)
Codex:
codex plugin marketplace add vouchington/vouchington-tooling --ref main
codex plugin add security-triage@vouchington
codex plugin add vouchington-workflow@vouchington
codex plugin add vouchington-testing@vouchington
codex plugin add vouchington-database@vouchington
Claude:
claude plugin marketplace add vouchington/vouchington-tooling --sparse .claude-plugin plugins
claude plugin install security-triage@vouchington
claude plugin install vouchington-workflow@vouchington
claude plugin install vouchington-testing@vouchington
claude plugin install vouchington-database@vouchington
Grok:
grok plugin install vouchington/vouchington-tooling#plugins/security-triage
grok plugin install vouchington/vouchington-tooling#plugins/vouchington-workflow
grok plugin install vouchington/vouchington-tooling#plugins/vouchington-testing
grok plugin install vouchington/vouchington-tooling#plugins/vouchington-database
Other Claude-compatible clients that support the same direct-install syntax can select either plugin directory.
Cursor loads local Agent Plugins. Clone the source once and link its plugin directory into Cursor’s local plugin root, then restart Cursor or reload the window:
mkdir -p ~/.cursor/plugins/sources ~/.cursor/plugins/local
git clone --depth 1 https://github.com/vouchington/vouchington-tooling.git \
~/.cursor/plugins/sources/vouchington-tooling
ln -s ~/.cursor/plugins/sources/vouchington-tooling/plugins/vouchington-workflow \
~/.cursor/plugins/local/vouchington-workflow
ln -s ~/.cursor/plugins/sources/vouchington-tooling/plugins/security-triage \
~/.cursor/plugins/local/security-triage
ln -s ~/.cursor/plugins/sources/vouchington-tooling/plugins/vouchington-testing \
~/.cursor/plugins/local/vouchington-testing
ln -s ~/.cursor/plugins/sources/vouchington-tooling/plugins/vouchington-database \
~/.cursor/plugins/local/vouchington-database
The clone and symlink commands intentionally fail if either target already exists, preventing an update from overwriting or nesting an existing local plugin.
Centralized Cursor marketplace publication is not part of this repository change.
GitHub Actions
Pin composite actions by commit SHA and keep a trailing # vX.Y.Z comment.
Git tags are vouchington-tooling/vX.Y.Z (slash-separated) so Dependabot can
parse them. Hyphenated vouchington-tooling-vX.Y.Z tags from before v0.6.2 are
historical. The Backfill slash release tags workflow aliases those hyphen tags
onto the same commits without creating GitHub Releases or publishing to npm.
Pin the public Dependabot automerge action by commit SHA.
- uses: vouchington/vouchington-tooling/.github/actions/dependabot-automerge@ # vX.Y.Z
with:
automerge_token: ${{ secrets.DEPENDABOT_AUTOMERGE_TOKEN }}
# Optional: JSON rules that require manual merge for an ecosystem/directory.
manual_update_rules: '[{"packageEcosystem":"nuget","directory":"/native"}]'
dependabot-automerge fetches trusted Dependabot metadata with the workflow token, only enables
auto-merge for patch updates at any version and minor updates with a stable target on major 1 or later, and rechecks the live bot-owned same-repository
branch before using the dedicated token to enable eligible auto-merge or disable stale auto-merge.
Enable auto-merge once per PR on opened, reopened, and ready_for_review. Do not re-run enablement on synchronize.
Keep edited so a base-branch retarget can disable stale auto-merge. Already-armed PRs are a no-op.
Unsigned or otherwise unverified HEAD (mixed repair commits) is a successful human-merge no-op and does not fail the job.
The automerge_token must be a dedicated token because a
GITHUB_TOKEN merge does not trigger downstream workflows. It must be stored specifically as a
repository Dependabot secret, or as an organization Dependabot secret selected for every consumer
repository—not only as an Actions secret—and needs Contents and Pull requests read/write permission. Mutation failures intentionally fail the job
so a broken or underprivileged token cannot look like successful automation. Both manual-rule fields
must exactly match dependabot/fetch-metadata; ecosystems are lowercase and directories include the leading slash. Use the action only from a trusted
pull_request_target workflow that checks out the exact base SHA with credentials disabled; never
check out or execute pull-request code.
The action never submits or requires an approval review. Branch-protection required checks remain the merge gate; consumers should not add a separate workflow that auto-approves Dependabot PRs.
Required-result gate
Pin ci-required-result-gate by its full 40-character commit SHA to give a required fan-in job a strict, compact
dependency-result contract. The action accepts only a non-empty JSON object whose entries contain
exactly a result of success or skipped; failures, cancellations, missing result fields, and
malformed input fail the gate. It is dependency-free and resolves its checked-in shell script from
GITHUB_ACTION_PATH, so it does not require checkout or Node dependencies.
- uses: vouchington/vouchington-tooling/.github/actions/ci-required-result-gate@ # vX.Y.Z
with:
results: >-
{"tests":{"result":"${{ needs.tests.result }}"},"lint":{"result":"${{ needs.lint.result }}"}}
Keep the full commit SHA authoritative. The trailing comment must be this package’s release
version (# vX.Y.Z for tag vouchington-tooling/vX.Y.Z) so Dependabot can compare it. An
action-local # v1.0.0 looks newer than 0.y.z package tags, so Dependabot never proposes a
bump. Build the compact object explicitly from each dependency’s result instead of passing
toJSON(needs), which may contain unsupported fields or exceed process environment limits.
The caller owns key-set completeness: keep a repository test that compares the explicit keys with
the fan-in job’s declared needs. A second hand-built expected-key input would duplicate the same
contract and could drift independently.
Use mode: build only when preserving an existing build-gate name or message contract; it applies
the same success/skipped acceptance rule.
CLI
vouchington --help
vouchington --version
vouchington runner-port-policy
vouchington runner-port-policy --reserved 2200
vouchington with-host-lock --name expensive-build --timeout-seconds 60 -- make build
vouchington gha-runtime-audit --pr-workflow CI --push-workflow '/^Main CI \\(.+\\)$/'
vouchington ast-grep-pack
vouchington gha-output name
vouchington gha-needs-results
vouchington download-with-diagnostics
vouchington download-optional-run-artifacts --pattern 'coverage-*' --dir ./coverage-fallback
vouchington download-optional-run-artifacts --name coverage-tooling --name coverage-web --dir ./coverage-fallback
vouchington host-pressure-diagnostics
vouchington allocate-browser-safe-ports 2 --policy ./policy.json --forbidden-ports ./ports.json
vouchington diagnose-port-collision --ports "2200 2216"
vouchington prepare-trivy-db
vouchington gha-artifacts-cleanup run --run-id 123 --keep-pattern 'plan-*'
vouchington http-origin --field cdn_origin https://images.example.com
vouchington vitest-blob-manifest [reports-directory]
vouchington vitest-report-attempt write
vouchington vitest-report-attempt read
vouchington prepare-vitest-reports [primary-directory] [fallback-directory] [output-directory]
vouchington pnpm-install --runner-lifecycle persistent --install-scripts true
vouchington check-cache-size /tmp/cache 1048576 node-modules
vouchington make-shard-matrix 4
vouchington load-runner-env
vouchington clean-workspace
vouchington install-github-release --repo lycheeverse/lychee --version 0.24.2 --asset 'lychee-{platform}.tar.gz' --bin lychee
vouchington run-with-timeout 120 10 docker push example
vouchington lint-links --offline
vouchington materialize-pr-context
vouchington wait-for-apt-locks
vouchington retrospective-transcript --jsonl /path/to/transcript.jsonl
vouchington install-playwright-chromium-arm64
vouchington ghcr-package-retention example%2Fapi
vouchington harness-admission-lane 4
vouchington harness-assert-gates HARNESS_DISPATCH_ENABLED HARNESS_SHEPHERD_ENABLED
vouchington nuget-central-version trusted.props candidate.props metadata.json out.props
vouchington swift-semantic-equal BASE HEAD App.swift
vouchington post-review
vouchington stage-review-payload optional|required
pnpm-install runs the pnpm on PATH and never reads the consumer’s packageManager field, so
consumers need no pnpm pin. It works with pnpm 11 and 12. The metadata fingerprint includes
pnpm --version and every workspace manifest, so changing either triggers one reconciling install.
For persistent pnpm-install, v5 metadata tracks structural inputs separately from the
--install-scripts policy and records scriptsEnabledInstallVerified only after pnpm reports a
parseable empty pendingBuilds ledger. A v4, malformed, or missing stamp on a populated tree, a
matching stamp with pending or unreadable build state, and an unverified scripts-enabled tree all
use two script-free forced reconciliation passes. If a scripts-enabled install or
reconciliation leaves a parseable nonempty ledger, it completes pnpm’s own generic
pnpm rebuild --pending --recursive finalization. Before that rebuild, it safely deduplicates
identical pending IDs. After rebuilding, it removes only residual IDs proven absent from pnpm’s
current workspace and installed virtual-store lockfiles, without dropping live dependencies or workspace importers. Removed stale IDs are reported. This covers
pnpm 11.13.1’s duplicate-importer and stale-package ledger behavior, then rechecks native and workspace-link health and
requires an empty ledger. Unreadable or unresolved ledger state fails without refreshing the stamp
for scripts-enabled runs. Scripts-disabled installs can finish with unreadable state, but
write an unverified stamp so the next scripts-enabled invocation reconciles. They retain
verification only when the matching prior stamp was verified and pnpm still reports an empty ledger.
An isolated native-binary mismatch uses one strict forced install only when structural provenance
matches, workspace links are valid, and pnpm records empty ignoredBuilds and pendingBuilds ledgers;
otherwise it retains two script-free reconciliation passes plus generic pending finalization. Native and workspace-link health
are verified after the two script-free passes and any generic pending rebuild, before its metadata
stamp is refreshed. ignoredBuilds remains consumer policy, but
disqualifies isolated native repair.
The command emits a structured non-secret provenance diagnostic identifying changed structural
categories, the last script policy, script capability, and native-binary health.
download-optional-run-artifacts uses the current Actions run and host. Pattern mode discovers
non-expired artifacts across the run, keeps the first result for each name (matching gh run download), and extracts each selected name into its own directory. Ordinary absence is reported as
availability=unavailable. Artifact listing retries up to three times with bounded backoff;
exhausted transport errors, invalid names, and cancellation remain hard failures.
Name mode takes one or more --name flags (mutually exclusive with --pattern), lists
the run’s artifacts once, and extracts every requested name that is present into /.
Names are matched literally, in request order, with repeats downloaded once; empty names, ., ..,
and names containing /, \, or a line break are rejected before anything is listed. Requested
names absent from the run are expected (callers pass a superset such as retry-attempt variants) and
are skipped with a single bounded ::notice:: (the absent count, the first three names, then
and N more) and never one line per name. availability=available means at least one requested
artifact was downloaded; availability=unavailable (exit 0) means none was
present. A present artifact whose download fails is a hard failure: the helper stops at the first
one, prints download failed artifact= exit=, exits non-zero (a downloader exit of 3 is
reported as 1 so it cannot be mistaken for absence), and writes no availability output.
Machine-wide agent settings now belong to vouchington-machines.
Use its configure-agents.sh and diagnose-agents.sh; see the migration note.
Packages
vouchington-tooling
Subpath imports keep consumers off modules they do not need. Heavy parsers are optional:
import { isRunnerReservedPort, runnerPortPolicy } from 'vouchington-tooling/runner-port-policy'
import { initSqlAst, extractCreateTableMetadata } from 'vouchington-tooling/sql-ast'
import { splitSqlStatements } from 'vouchington-tooling/sql-scanner'
import { auditCiJobRuntime } from 'vouchington-tooling/gha-runtime-audit'
import { writeVitestBlobManifest } from 'vouchington-tooling/vitest-blob-manifest'
import { prepareVitestReports } from 'vouchington-tooling/vitest-reports'
import { runInstallLifecycle, validateReleaseAgePolicy } from 'vouchington-tooling/pnpm-install'
import {
buildSharedContext,
installFakeGit,
runNamedChecks,
} from 'vouchington-tooling/shared-context'
import { writeSelectedFilesOutput } from 'vouchington-tooling/gha-selected-files'
import { createArtifactClassifier, runCleanup } from 'vouchington-tooling/gha-artifacts-cleanup'
import { validateOptionalHttpOrigin } from 'vouchington-tooling/http-origin'
import { boundPendingLine, splitCompleteLines } from 'vouchington-tooling/process-line-buffer'
import { decide } from 'vouchington-tooling/transient-retry'
import { parseCsvRows } from 'vouchington-tooling/csv'
import { readResponseBody } from 'vouchington-tooling/http-body'
import { parseReviewPayload } from 'vouchington-tooling/gha-review-payload'
import { runPostReview } from 'vouchington-tooling/gha-post-review'
import { nextPageUrlFromLinkHeader } from 'vouchington-tooling/http-link-pagination'
import {
cmdUpload,
discoverDownloadControl,
mintPrefixUploadControl,
} from 'vouchington-tooling/coverage-transport'
import { pruneDeployedRuntimeDeps } from 'vouchington-tooling/pnpm-deploy'
import { parseDockerfileRuntimeImages } from 'vouchington-tooling/dockerfile-parse'
import { checkSccComplexity } from 'vouchington-tooling/scc-complexity'
import { runCiLocal } from 'vouchington-tooling/ci-local'
import { rateLimitDelay } from 'vouchington-tooling/gha-rate-limit'
import { parseCheckpoint } from 'vouchington-tooling/gha-pr-checkpoint'
import { checkWorkspaceGatesPolicy } from 'vouchington-tooling/workspace-gates'
import { checkGhaWorkspacePolicy } from 'vouchington-tooling/gha-workspace-policy'
import { requireUpToDate } from 'vouchington-tooling/require-up-to-date'
import { checkFreshBase, classifyFreshBase } from 'vouchington-tooling/fresh-base'
import { runGitleaksDirectoryScan } from 'vouchington-tooling/gitleaks-directory-scan'
import { runAstGrepExamples } from 'vouchington-tooling/ast-grep-examples'
import { astGrepPackPaths } from 'vouchington-tooling/ast-grep-pack'
import { validateNugetUpdate } from 'vouchington-tooling/nuget-central-version'
import { normalizeSwiftSource } from 'vouchington-tooling/swift-semantic-equal'
import { isSwiftCodeOffset } from 'vouchington-tooling/swift-source-offset'
import { validateResolvedPinDelta } from 'vouchington-tooling/swift-resolved-pin-delta'
import { runRetrospectiveTranscript } from 'vouchington-tooling/retrospective-transcript'
import { buildSessionFrictionReport, recordFriction } from 'vouchington-tooling/session-friction'
import { createPullRequest, processDiffCommand, runGh, runGit } from 'vouchington-tooling/gh-cli'
processDiffCommand runs a caller-supplied git diff or gh pr diff executable and argv without
a shell, emitting complete unified-diff file blocks without accumulating the whole patch. It keeps
at most one file block (which can itself be large), preserves preambles and line content, and drains
a bounded stderr tail for typed command failures. Blocks are provisional until the returned promise
resolves: callers must discard accumulated results if the command later exits nonzero or is signaled.
vouchington-tooling/gh-cli also parses pull request body references.
parseClosingIssueReferences finds GitHub closing keywords (close/closes/closed,
fix/fixes/fixed, resolve/resolves/resolved) followed by #N, owner/repo#N or an issue
URL, deduplicated by key (#N or lowercased owner/repo#N, see formatReferenceKey).
parseNonClosingRefs collects Ref, Refs and Part of keys from text the caller has already
scoped, such as a “Related issues” section.
vouchington-tooling/pull-request-diff counts added and deleted lines in unified-diff text
(countDiffLineChanges, excluding +++/--- headers) and compares them with caller-supplied
LargeDiffThresholds through exceedsLargeDiffThreshold. DEFAULT_LARGE_DIFF_THRESHOLDS
(5,000 added, 20,000 deleted) is only an example default.
import {
countDiffLineChanges,
exceedsLargeDiffThreshold,
} from 'vouchington-tooling/pull-request-diff'
exceedsLargeDiffThreshold(countDiffLineChanges(diffText), {
addedLines: 5000,
deletedLines: 20_000,
})
sql-ast requires the optional dependency @libpg-query/parser. sql-scanner does not.
dockerfile-parse uses dockerfile-ast.
session-friction remains dormant until a caller explicitly supplies a session id, absolute log
directory, hook observation, and journal loader. Host payload parsing, hook installation, session
discovery, and journal transport stay with the consuming repository. Capture stores at most 500
events per session, counts rejected captures in a bounded atomic sidecar, truncates event detail to 1,000 characters, and consumes up to 500 entries
from the journal loader when building a report, stopping earlier when its aggregate 1 MB
inspected-byte budget is reached. Log reads are capped at 2 MB, journal Markdown at
10,000 bytes per entry, and newly created evidence directories and files are owner-only. Recording
and report construction synchronously access the evidence log and may wait up to one second for a
contended per-session file lock before failing explicitly. Evidence-directory validation requires
POSIX ownership and mode checks (Linux and macOS), so session-friction throws on Windows.
Command-prefix normalization attempts limited redaction of obvious credential patterns but is not
a secret scrubber; callers must not include credentials in captured commands.
composeRetrospective (vouchington-tooling/agent-blackboard) can also assess ## CI Failures and
## Sandbox & Permission Audit from journal entries alone with journal: {journalLoader}, which
needs no friction directory or log and reports frictionStatus: 'journal-only'. It is an
alternative to the friction input, and the two are mutually exclusive.
Security-sensitive helpers are provider-neutral and fail closed on malformed artifacts, payloads, response bodies, and pagination links. Product policy, credentials, and network transport remain in the consuming repository.
eslint-plugin-vouchington
House-style rules shared across Vouchington repositories. Rule routing:
- Generic (any TypeScript/JavaScript repo) →
eslint-plugin-no-mistakes - Vouchington convention with no product nouns → this plugin
- Single-repo product coupling → stays in the product monorepo
The plugin currently ships postgres-cursor-call-contract, banned-member-read, and factory-owner-location. Callers pass module specifiers, members, factories, and owner files; product paths stay in the consuming repository.
Development
Requires Node 24+ and pnpm 12. The repository does not pin pnpm: no manifest declares
packageManager, and local work uses whichever pnpm 12 is installed. CI asks pnpm/action-setup for
latest-12 after actions/setup-node, so it runs the newest pnpm 12 release that is at least one day
old. New 12.x releases reach CI without a PR; moving to pnpm 13 needs one.
pnpm-setup-policy.test.mts enforces that shape.
pnpm install
pnpm run lint
pnpm run typecheck
pnpm run build
pnpm test
pnpm run lint includes the jscpd clone-size gate and the
scc complexity ceiling. Both match the Vouchington product repository:
any clone of 200 lines or more fails at 85% similarity, and scc 3.7.0 fails a counted file
whose complexity is over 50.
Run the local CLI after a build:
node packages/vouchington-tooling/dist/cli/index.mjs --help
Validated journal and retrospective feedback uses the existing agent-blackboard subpath. Explicit
interactive mode persists sanitized pending records in a bounded outbox; autonomous mode
requires fresh online admission and acknowledged terminal readback. Work outcome, evidence coverage,
and delivery remain separate. See the feedback contract
for current APIs, privacy bounds, stable event replay, and the breaking journal writer adoption.
Рекомендуемые инструменты
Попробуйте другой запрос или уберите фильтр.
Установка
npx skillfish add vouchington/vouchington-tooling