vouchington-tooling
v0.44.0
Published
Vouchington CLI and extractable tooling libraries.
Readme
vouchington-tooling
Libraries and the vouchington CLI.
The workflow and compiler primitives provide consumer supplied GitHub Actions policy checks and compiler host freshness with bounded build settlement.
config-inventory collects environment, dynamic-configuration,
and package-manager evidence using caller-owned file roles and policies.
finite-enum-ripple compares finite TypeScript declarations,
route configuration, routed pages, and factory calls. Consumers supply every tracked-file role,
declaration name, route label, factory pattern, and exception.
npm install vouchington-tooling
# optional, only if you import vouchington-tooling/sql-ast
npm install @libpg-query/parser
# optional, if you import vouchington-tooling/contract-schema, finite-enum-ripple,
# or post-publication-inventory
# (classic compiler API; typescript@7's package root is version-only)
npm install @typescript/typescript6
# optional, only if you use the Vitest reporter export
npm install vitest
# optional, only for vouchington-tooling/agent-blackboard and agent-blackboard CLI commands
npm install agent-blackboard@^0.6.0
# optional, only for `vouchington mcp` (zod is a peer of the SDK)
npm install @modelcontextprotocol/sdk zodvouchington mcp serves the agent-blackboard journal tools to an agent over
stdio, with Claude, Codex, and Cursor registration examples.
CLI
vouchington --help
vouchington runner-port-policy
vouchington runner-port-policy --file ./policy.json
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 require-up-to-date --remote origin --branch main
vouchington gitleaks-directory-scan --config .gitleaks.toml
vouchington ast-grep-examples --rules ast-grep-tests --config sgconfig.yml
vouchington ast-grep-pack
vouchington gha-workspace-policy
vouchington gha-output name
vouchington gha-needs-results
vouchington download-with-diagnostics <url> <destination>
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-*' --delete-pattern 'coverage-*'
vouchington http-origin --field cdn_origin https://images.example.com
vouchington vitest-blob-manifest <suite> [reports-directory]
vouchington vitest-report-attempt write <directory> <suite>
vouchington vitest-report-attempt read <root>
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 retrospective-facts --pr 49 --repo vouchington/vouchington-infra --raw
vouchington agent-blackboard probe
vouchington agent-blackboard journal append --session-id <uuid> --agent codex --version 1 --file note.md --repository owner/repo --mode autonomous --source-event-id event:1 --work-outcome in-progress --coverage-status partial --timestamp 2026-01-01T00:00:00.000Z
vouchington agent-blackboard journal entries --session-id <uuid>
vouchington agent-blackboard snapshot partition --snapshot <snapshot.jsonl> --checksum <sha256> --counts <counts.json>
vouchington agent-blackboard snapshot cleanup --snapshot <snapshot.jsonl> --partition-directory <partitions-dir> --receipt <receipt-json>
vouchington mcp
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
echo '[{"login":"octocat","type":"User"}]' | vouchington gha-collaborator-trust owner/repo --allow-bot github-actions[bot]
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 <source> <destination>Running allocate-browser-safe-ports without an install
The allocator is a standalone Python script that needs only the Python 3 standard library: no
Node, no pnpm install. Run it from the extracted published tarball:
npm pack vouchington-tooling@<version> # or download the registry .tgz
mkdir extracted && tar -xzf vouchington-tooling-<version>.tgz -C extracted
python3 extracted/package/scripts/allocate-browser-safe-ports.py <count> [--policy ...] [--forbidden-ports ...]pnpm dlx and npx resolve the package's whole dependency tree, which can fail under
minimumReleaseAge (ERR_PNPM_NO_MATURE_MATCHING_VERSION) when a lockstep-published dependency
straddles the cutoff. CI jobs without an install should fetch the tarball instead. Tests enforce
that the script stays stdlib-only and reads only its two sibling JSON files.
For persistent pnpm-install, v5 metadata tracks structural inputs separately from the
--install-scripts policy. A warm scripts-enabled tree can therefore toggle
true → false → true without forced reconciliation; a tree first installed with scripts disabled
uses two script-suppressed verification installs followed by pnpm rebuild --pending --recursive.
Before rebuilding, duplicate pending IDs are collapsed. After rebuilding, IDs proven absent from
the current workspace and installed virtual-store lockfiles are reported and removed; live
dependency and workspace-importer IDs are retained. Any residual ID after the generic rebuild remains a reported hard failure. 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 the two script-free reconciliation passes. Native and workspace-link health
are verified before its metadata stamp is refreshed.
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 <artifact> flags (mutually exclusive with --pattern), lists
the run's artifacts once, and extracts every requested name that is present into <dir>/<name>.
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=<name> exit=<n>, exits non-zero (a downloader exit of 3 is
reported as 1 so it cannot be mistaken for absence), and writes no availability output.
require-up-to-date fetches the requested remote branch and fails unless its fetched tip is an
ancestor of HEAD. fresh-base refreshes <remote>/<branch> (default origin/main, 8 s fetch timeout, --skip-fetch
to compare the cached ref) and prints a JSON report classifying the worktree as up-to-date,
ahead, behind, diverged, dirty (matches the base but has uncommitted changes),
fetch-failed (a failed refresh outranks every other status), or unknown. It prints nothing
outside a Git repository. Unlike require-up-to-date it never fails on staleness; callers decide
what to do with the status.
gitleaks-directory-scan builds and scans isolated staged-index and current
nonignored-working-tree mirrors with an explicit config; --directory selects the repository root.
ast-grep-examples runs native ast-grep test, then validates each scoped rule's files: and
ignores: examples with project languageGlobs replay from its root --config.
The shipped pack maps **/*.ts, **/*.mts, **/*.cts, and **/*.tsx to Tsx so one rule
covers script and JSX surfaces. Consumers must use the same languageGlobs and language: Tsx;
do not add -tsx companion YAML. Angle-bracket type assertions (<T>value) are not valid TSX.
compareAstGrepCompanions compares recursive <name>.yml/.yaml and <name>-tsx companion
rules across every YAML field, returns stable JSON-pointer differences, and rejects unsafe or
ambiguous rule paths. The supplied rule path and every ancestor must be physical directories; YAML
aliases and non-JSON tagged values are rejected before comparison. Callers own any explicit
normalization for language-specific differences.
ast-grep-pack prints JSON { rules, config } for the shipped unconditional rule pack. Point a
consumer sgconfig.yml ruleDirs at rules and keep product-specific YAML locally.
gha-workspace-policy checks tracked workflow and composite-action files in the current repository;
pass --root, --workflow-directory, or --action-directory for consumer-owned layouts.
retrospective-transcript discovers Codex and Claude transcripts by default. It also reads a
Claude-compatible transcript when CURSOR_SESSION_ID is set, and Grok's updates.jsonl session
layout when GROK_SESSION_ID is set. Use --grok-sessions-dir to point discovery at a nondefault
Grok session root. Without --session-id, it reads those session identities from the host
environment.
retrospective-facts keeps local Git evidence separate from GitHub PR data. Commits ahead of
origin/main is populated only from a local ancestry range; GitHub responses instead populate
PR commits. API-derived file and directory counts are labelled GitHub API. When a named local
branch is absent, the command refreshes origin/<branch> before using it and refuses a stale
remote ref when that refresh fails.
For an explicit --repo, it performs no local Git checks: Merged to main is yes only when
GitHub reports a merged PR whose baseRefName is main; a merged PR into another base is reported
as not merged to main, and a missing base is unavailable.
Agent Blackboard support is optional: only the agent-blackboard subpath and its CLI commands
need agent-blackboard@^0.6.0. Snapshot cleanup accepts only package-generated temporary paths.
appendJournal and the journal CLI now require explicit mode, stable source-event identity, work
outcome, feedback coverage, and exact repositories. This is a breaking pre-1.0 API change; adopt the
shared contract before upgrading consumers. appendJournal reads a bounded UTF-8 note and delegates
to writeFeedback, returning delivered or pending state rather than a success-shaped message. The CLI accepts one or more
--repository owner/name flags; it records the entry's exact repositories and updates the session's
cumulative repository list before appending.
Programmatic callers launched from a different workspace directory pass their own module URL as
dependencies: { resolveFrom: import.meta.url }; the CLI defaults to the current package context.
It captures a target under a private tombstone, validates partition names, permissions, JSONL,
ordering, terminal manifests, and the identity-bound cleanup receipt before deleting files, and
restores the original path on a validation failure. Once deletion begins, it retains a private
tombstone plus signed resume metadata instead; retry cleanup with the original partition-directory
path and the same receipt until it completes. The partition command returns that receipt; directory
cleanup requires it.
The receipt is authenticated with an owner-only per-user HMAC key stored under a dedicated
0700 directory in the system temporary directory. This small host-local state is the trust
boundary: a copied or caller-created receipt cannot authorize cleanup without that key.
Host-lock environment:
| Variable | Default | Meaning |
| --------------------------------------- | --------------------- | ------------------------------------------- |
| HOST_LOCK_ROOT | /tmp/host-lock-$UID | Absolute lock directory root |
| HOST_LOCK_LEASE_SECONDS | 60 | Reclaim ceiling for a held lock |
| HOST_LOCK_PROCESS_GROUP_DRAIN_SECONDS | 30 | Time to wait for the command process group |
| HOST_LOCK_ACTIVE | unset | Set while a lock is held; nested locks fail |
Sourceable Bash libraries
scripts/worktree/git-worktrees.sh is included in the published package. Source it to parse
git worktree list --porcelain with git_worktree_* helpers. Its
git_worktree_canonical_path_hash <path> helper resolves the physical path and prints a stable
d plus the first 12 lowercase hexadecimal characters of its SHA-256 digest.
Library
import {
isRunnerReservedPort,
listenOnRunnerUnreservedEphemeralPort,
runnerPortPolicy,
} from 'vouchington-tooling/runner-port-policy'
import { initSqlAst, extractCreateTableMetadata } from 'vouchington-tooling/sql-ast'
import { splitSqlStatements, stripSqlComments } from 'vouchington-tooling/sql-scanner'
import { auditCiJobRuntime } from 'vouchington-tooling/gha-runtime-audit'
import {
inspectHarnessEnvironment,
selectHarnessSession,
} from 'vouchington-tooling/agent-harness-identity'
import {
readVitestReportAttempts,
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 { createSourceModuleGraph } from 'vouchington-tooling/source-module-graph'
import {
decodeSelectedFiles,
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 {
isProcessGroupAlive,
runBrowserSession,
waitForProcessGroupExit,
} from 'vouchington-tooling/browser-session-runner'
import {
generateSchemaSnapshot,
renderSchemaMarkdown,
} from 'vouchington-tooling/pg-schema-snapshot'
import { buildOpenApiDocument, writeOpenApi } from 'vouchington-tooling/openapi-document'
import {
extractResponseContracts,
validateResponseContract,
} from 'vouchington-tooling/contract-schema'
import {
buildFixtureSchemaLock,
validateFixtureContracts,
writeGeneratedFiles,
} from 'vouchington-tooling/api-fixtures'
import { decide, deriveRetryAttempt } from 'vouchington-tooling/transient-retry'
import { parseCsvRows, streamCsvRows } from 'vouchington-tooling/csv'
import {
extractLooseMarkdownTableRows,
extractMarkdownTables,
markdownSectionBetweenHeadings,
parseGfmMarkdown,
parseMarkdownTables,
} from 'vouchington-tooling/markdown'
import { readResponseBody } from 'vouchington-tooling/http-body'
import { runAstGrepRule } from 'vouchington-tooling/ast-grep-rule'
import { parseReviewPayload, remapReviewComments } from 'vouchington-tooling/gha-review-payload'
import { postReviewWithTokenFromEnv, runPostReview } from 'vouchington-tooling/gha-post-review'
import { postClaudeReviewFromEnv } from 'vouchington-tooling/gha-claude-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 {
collectPnpmLicenseReport,
evaluatePnpmLicenseReport,
} from 'vouchington-tooling/dependency-license-policy'
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 { parseUniqueSwiftBinaryTargetChecksum } from 'vouchington-tooling/swift-source-offset'
import { validateResolvedPinDelta } from 'vouchington-tooling/swift-resolved-pin-delta'
import {
createForkLeakDetector,
createVitestWorkerExitDiagnosticsReporter,
formatDiagnosticReportSummaries,
readDiagnosticReportSummaries,
registerForkExitSentinel,
} from 'vouchington-tooling/vitest-diagnostics'
import { runRetrospectiveTranscript } from 'vouchington-tooling/retrospective-transcript'
import { appendJournal, probeBlackboard } from 'vouchington-tooling/agent-blackboard'
import { buildSessionFrictionReport, recordFriction } from 'vouchington-tooling/session-friction'
import { GITHUB_BODY_MAX_CHARACTERS, validateGitHubBodyLength } from 'vouchington-tooling'
import { createPullRequest, processDiffCommand, runGh, runGit } from 'vouchington-tooling/gh-cli'
import {
shellScriptViolations,
workflowYamlViolations,
} from 'vouchington-tooling/gh-api-shell-quoting'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.
let changedFileCount = 0
await processDiffCommand({ executable: 'git', args: ['diff', 'origin/main...HEAD'] }, async () => {
changedFileCount += 1
})
// Use changedFileCount only after processDiffCommand resolves.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,
})This breaking minor removes getDiffAgainstBase; migrate callers to processDiffCommand and pass
the command they need to run.
checkSccComplexity keeps its single repository-wide scan when scopes is omitted. Consumers
that need separately ratcheted areas may provide named scopes with positional includePaths; SCC
runs once per scope and reports the scope in each diagnostic. Parse a consumer-owned JSON baseline
with parseSccComplexityBaseline and pass it as baseline. Baselines are versioned, record the
maximum permitted complexity for each { scope, file }, suppress only values at or below that
ceiling, and reject malformed, duplicate, untracked, stale, or out-of-scope entries.
shellScriptViolations/workflowYamlViolations flag a gh api call whose argument carries an
unquoted ? or &: an unquoted & silently backgrounds the command and truncates the query
(the call still exits 0), and an unquoted ? fails loudly under zsh glob-nomatch but passes
through unexpanded under bash. workflowYamlViolations decodes quoted and folded YAML run:
scalars before scanning, so a hazard hidden by YAML's own quote-stripping is still caught; it
throws on a run: value that is a YAML alias or a multiline PLAIN scalar, shapes it cannot yet
scan safely. Both functions scan already-in-scope source text — deciding which files count as a
shell script or a workflow/action YAML file is left to the caller.
validateGitHubBodyLength measures an issue or pull-request body against GitHub's 65,536 Unicode
code-point limit without altering it. Its result includes the UTF-8 byte count for diagnostics; that
byte count is not a validation limit.
vouchington-tooling/markdown parses GFM into standard mdast/unist nodes, provides pre-order
walking and typed searches, normalizes node text, and extracts positioned tables or heading-bounded
source sections. parseMarkdownTables preserves its compact { cells, line }[][] compatibility
shape, including short table delimiters. extractLooseMarkdownTableRows is intentionally literal
recovery for malformed pipe rows; callers supply table positions to exclude and retain ownership of
their policy interpretation.
parseMarkdownSections returns visible root H2 sections, their exact original content,
startOffset/endOffset source ranges, heading line, and hasVisibleContent. Heading text is
normalized by collapsing whitespace and removing Markdown formatting/comments and collapsed text; matching remains
case-sensitive. Source offsets are JavaScript string offsets, so source.slice(startOffset,
endOffset) preserves Unicode and CRLF exactly. Sections end at the next visible root H2 or EOF;
fenced examples, quoted headings, and headings inside <details> do not create boundaries.
import { parseMarkdownSections, validateMarkdownSections } from 'vouchington-tooling/markdown'
const document = parseMarkdownSections(body)
const diagnostics = validateMarkdownSections(document, {
requiredHeadings: ['Summary', 'Impact'],
})
const relatedIssues = document.sections.find((section) => section.heading === 'Related issues')The caller owns required headings. Validation returns diagnostics with code, message, and
optional heading/line, for missing-heading, duplicate-heading, empty-section, or
malformed-details. Nonempty visible paragraphs, lists, and populated table bodies satisfy the
content check; comments, fenced/indented code, images, disclosure labels, and collapsed-only content
do not. The parser tracks balanced nested details/summary tags in GFM HTML nodes, accepting optional
summaries and quoted attributes; it is not a general HTML validator or sanitizer. It never rewrites
the input or infers semantic relevance, cost, schema conformance, or failure causes. The existing
markdownSectionBetweenHeadings API retains its original boundary behavior.
hasUncheckedMarkdownTask reports parsed unchecked GFM task items, ignoring code and non-task text.
markdownLiteralSpans returns source-backed { kind, position, value } facts for fenced or indented
code, inline code, and raw HTML. markdownHtmlFacts distinguishes inline HTML from block HTML and
labels CommonMark block types 1–7; markdownHtmlBlocks selects block types 1, 6, and 7, retaining
the parser's source bounds, including type 1 blocks through their matching closer or end of input.
Positions use 1-indexed line/column coordinates and JavaScript string offsets, including CRLF and
Unicode source text. These APIs return facts rather than mdast nodes so callers can apply their own
content policy without binding it to parser internals.
import {
hasUncheckedMarkdownTask,
markdownHtmlBlocks,
markdownLiteralSpans,
} from 'vouchington-tooling/markdown'
const hasOpenTask = hasUncheckedMarkdownTask(body)
const literalSpans = markdownLiteralSpans(body)
const blockHtml = markdownHtmlBlocks(body)markdownHtmlBlocks reports CommonMark types 1, 6, and 7; inline tags do not appear in that result.
Use markdownHtmlFacts when inline/block classification and other CommonMark HTML block types are
also needed.
Machine-wide agent configuration now belongs to vouchington-machines.
Use its configure-agents.sh and diagnose-agents.sh; project hooks and MCP configuration remain in their checkouts.
agent-harness-identity inspects the four harness environment signals without choosing a winner.
Callers supply their own precedence to selectHarnessSession, keeping product-specific identity
policy out of this package.
checkWorkspaceGatesPolicy rejects tracked test assertions that hard-code the exact version of a
dependency declared by a non-fixture package manifest. Assert dependency membership or placement,
or derive a configuration or documentation package spec from that manifest instead.
dependency-license-policy keeps legal policy in the consumer. collectPnpmLicenseReport returns
a promise. It creates an isolated, script-free temporary workspace, expands pnpm's supported
architectures to every os, cpu, and libc selector represented in the lockfile, drops every
engines constraint from the audit copy of the lockfile, and validates the JSON report. Dropping
engines keeps pnpm fetch from skipping optional packages that exclude the running Node.js;
pnpm 12's fetch ignores force, so their licenses would otherwise report as Unknown.
Packages are fetched into a private store inside that temporary workspace. Each audit has its own
store, and workspace cleanup removes every downloaded package when the audit succeeds or fails,
without changing the developer's pnpm store. The exported options no longer accept a storeDir
override because caller-owned paths cannot be safely removed; callers that provide a custom
prepareWorkspace own the returned workspace and its nested store lifecycle.
Pass explicit denied SPDX IDs and prefixes, exact aliases, and justified allowlist scopes to
evaluatePnpmLicenseReport. Unknown, malformed, and custom SPDX references fail closed. Allowlist
scopes are either intentionally global or an exact package-name set; the library returns structured
violations and does not format CI-provider diagnostics.
When present, the repository .npmrc is copied into the owner-private temporary workspace so pnpm
can authenticate to the same registries. The workspace and its package store are removed when the
audit finishes, when the process receives SIGINT, SIGTERM, or SIGHUP, and on the next audit if the
previous process died first, including SIGKILL. Each workspace records its owner's PID so a later
audit can delete directories whose owner is gone.
session-friction is an opt-in capture and reporting library. Callers supply the session id,
absolute log directory, host-independent observation, and journal loader; it does not inspect host
environment variables, install hooks, or connect to a journal service by itself. Invoking
recordFriction touches the session log even when no event is classified, preserving the
difference between an observed clean session and missing evidence. Report markdown keeps backend
diagnostics separate from its paste-safe output. Capture stores at most 500 events per session and counts rejected captures in a fixed-size atomic
sidecar under the same session lock for either the event or byte limit, with visible truncated/droppedCount metadata. Saturated
capture reads only the bounded counter; reports also preserve historical overflow markers.
Interrupted or inconsistent counter updates make coverage unavailable. Malformed records also make the scan partial. It
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.
Bounded journal scans that stop before exhaustion are reported as incomplete rather than clean.
Report liveness inherits the caller-supplied journal loader, which must bound its own I/O and yields.
Log reads are capped at 2 MB, journal Markdown at 10,000 bytes per entry,
and rendered audit fields are kept whole: composition loads the journal and friction log once, redacts each field from its raw text before Markdown escaping (a caller-supplied redactor runs first, then the built-in one), then renders the CI and sandbox sections, measures the real envelope against its 12,000-byte markdown and 16,384-byte envelope limits, and shrinks them in a few bounded attempts. A block shrinks Root diagnostic first and Evidence last, cutting only at token boundaries (never inside a URL or SHA) with a trailing …; groups that still cannot fit are omitted and counted in an explicit conforming group that points at the journal. The final attempt keeps only that omission note (about 300 bytes), so an input within roughly 300 bytes of the limit can still fail to compose. A caller-supplied budgets cap limits rendered groups only; the omission note is exempt from it. Permission requests record requested outcomes; explicit result observations may record approved
or denied outcomes. A decision and simultaneous tool failure are both retained and counted in
the report. Escalation detail without a decision remains unknown. Localhost connection
refusal is an ambiguous failure and does not establish a sandbox cause. The supplied log directory must be dedicated
to session-friction; existing directories must already be owner-only, while newly created
directories and log files are enforced as owner-only when recording. Reads use a fixed bounded
buffer that can detect growth one byte beyond the documented 2 MB cap.
Ownership checks require POSIX effective-user IDs (Linux and macOS); session-friction throws on
Windows and other platforms where those IDs are unavailable.
Root-owned system symlink ancestors are supported for paths such as macOS /var; callers must not
allow the directory chain to be mutated while it is being validated.
Command-prefix normalization recognizes simple shell
segments with single or double quotes; it does not evaluate substitutions or implement a full shell
grammar. Normalization attempts limited redaction of obvious credential patterns but is not a secret
scrubber; callers must ensure credentials are never included in captured commands.
Failure classification inspects at most 100,000 structured-stderr characters, split evenly between
the beginning and end when input exceeds that bound.
Cooperating log readers and writers are serialized, including the initial clean-session
touch. Recording and report log reads are synchronous: on contention they block the caller's
event loop for up to one second before failing explicitly. Avoid these APIs on hot request paths.
The artifact, review-payload, HTTP body, and pagination APIs validate untrusted inputs at their
boundaries. Neutral review posting lives in gha-post-review and requires a caller-supplied GitHub
token. Claude App OIDC is an explicitly selected gha-claude-post-review adapter; the legacy
token-source router remains deprecated for one release line.
vitest-diagnostics reads Node diagnostic report JSON from a caller-selected directory. It sorts
filenames, tolerates partial files, returns only a bounded field allowlist, and never emits raw
native frame symbols. Both structured reads and text rendering have hard report-count limits.
Fork diagnostics use a caller-selected recordDirectory in both the worker setup file and the
main-process reporter. Call registerForkExitSentinel({ recordDirectory }) once per fork, then
update setCurrentForkExitModule and setCurrentForkExitProject around tests. Construct
createVitestWorkerExitDiagnosticsReporter({ recordDirectory }) in the Vitest reporter list
before workers start. The reporter clears stale records at construction, preserves them across
watch reruns, and prints an attribution summary only for abnormal worker exits. The worker writes
a synchronous stderr line and one JSONL file per PID; a start record without an exit record
identifies a fork killed before its handler could run. createForkLeakDetector accepts tracked
resource names and warmup, threshold, and sustained-growth settings; the caller supplies each
checkpoint's resource counts. Use a caller-owned run directory: the reporter clears only regular
numeric PID .jsonl files there at construction and leaves the directory and other files alone.
Application metrics and CI artifact handling stay with the caller.
browser-session-runner supervises caller-created browser-test processes. Callers supply command
construction, line classification, retry/outcome policy, and budgets; the library owns process-group
termination, output line buffering, shared deadlines, progress watchdogs, diagnostics, and parent signals.
The returned process must identify a dedicated process group, such as a child spawned with
detached: true; its processGroupId is signalled without assuming the child PID is a group ID.
Stall exits use the caller's classifyExit policy, while parent signals and shared-deadline expiration
are terminal. Output is decoded independently per stream; unfinished lines are classified at close and
diagnosticTailBytes retains a UTF-8-safe tail no larger than its byte budget.
The runner uses monotonic elapsed time, rejects timer budgets above Node's maximum delay, and waits for
the dedicated process group to exit after the direct child closes so descendants cannot overlap a retry.
isProcessGroupAlive and waitForProcessGroupExit are also available when callers need the same
process-group probe and bounded-drain semantics outside a browser session.
Generated arbiter input
The pg-schema-snapshot export also provides projectGeneratedArbiterInput(conflict) for
PostgresSqlConflict facts from [email protected] or newer. It projects normalized key and
partial-predicate column identities, ordered assignment columns, direct non-EXCLUDED references,
and assignment indirection. Named constraints and unresolved expression keys have undefined
keyColumns; missing or incomplete expression coverage sets complete to false. Callers must
reject incomplete projections and retain their own snapshot-dependent replay verdict. The adapter
loads no optional parser peer at runtime and implements no replay-safety policy. Its public
GeneratedArbiterConflict contract is structural, so importing snapshot declarations does not
require the optional peer either.
Contract schema type queries
getExportedTypeFacts and getCallRowTypeFacts use an existing TypeScript Program from the
contract-schema subpath. Every request must also pass typescript, the same TypeScript compiler
API instance that created that Program. The source-file recognition check is a compatibility
guard, and callers remain responsible for pairing the same compiler instance; the query uses the
supplied API for compiler operations. Pass the exact SourceFile.fileName, an exported name or exact call
expression text, and only the property names and exported comparison types the consumer needs.
Facts include the displayed type, whether it is any, requested property displays, and requested
assignability booleans. defaultTypeParameterIndex selects an exported generic default;
direct defaults and direct references to preceding defaults are supported. Dependent composite
defaults and uninstantiated generic type declarations used as assignability targets fail with an
instruction to export and select a named instantiated type. Generic function values remain valid
compiler-backed comparison targets. Default lookup uses an outer class, interface, or type-alias
parameter list when present; otherwise it uses the first checker-visible call or construct
signature, never a hidden implementation or a later overload.
rowSource: 'typeArgument' selects a call's explicit type argument, while
rowSource: 'awaitedRows' selects Awaited<ReturnType>.rows[number].
Call results are source ordered and include one-based line and column. An absent call returns an
empty array so the consumer can enforce its own cardinality; a selected call missing its requested
row type fails with a descriptive error. The package does not choose source files, expected
properties, or contract policy.
Workflow skills outside plugins
The package ships a flat union of canonical workflow, testing, and database skills at
skills/<skill>/SKILL.md. This stable installed path supports agents that do not load Claude or
Codex plugins. The package build materializes plugin source trees without hand-copying skill content
and writes sorted schema-v1 provenance to skills/manifest.json.
Each manifest entry may declare its ordered prerequisites; ordinary Markdown links remain
cross-references and never cause additional skills to be linked.
Prerequisites ensure installation closure; they do not require eagerly reading every installed
skill. Follow the invoked skill's conditional instructions for the current task.
Canonical entrypoints direct agents to applicable local instructions and adapters before using
portable policy. Local AGENTS.md may name an adapter alias; an already-read canonical skill or
adapter is not loaded again. linkSkill still links files only: it does not load instructions,
resolve local aliases, or execute a workflow. Validate observed agent loading separately from
installation and packaged-resource checks.
Use readSkillManifest(skillsRoot) to discover installed skills or
linkSkill({ name, sourceRoot, targetRoot }) to link one into an explicit consumer directory. The
CLI equivalent is vouchington link-skill <name> --source-root <skills-dir> --target-root <dir>.
When sourceRoot contains manifest.json, linking validates the packaged inventory and recursively
links declared prerequisites. Without a manifest, it links the conventional
<sourceRoot>/<name>/SKILL.md repository-local skill. It rejects missing or unsafe sources, paths
outside either root, and existing non-matching destinations.
targetRoot must already exist as a physical directory path: symlinked target roots or ancestors are
rejected.
Validated feedback and delivery
Import createFeedbackEnvelope, validateFeedbackEnvelope, writeFeedback, verifyFreshFeedback,
composeRetrospective, feedbackOutboxStatus, and flushFeedbackOutbox from the existing
vouchington-tooling/agent-blackboard subpath. Consumers must run Node 24 or newer and install agent-blackboard@^0.6.0 explicitly alongside
vouchington-tooling; the provider is not installed by this package. Missing provider installation
returns client-unavailable; missing or invalid connection configuration returns
configuration-invalid, separately from transport outages and authentication rejection.
The upstream agent-blackboard client still owns the
service protocol; this integration adds no provider schema or service. Supply consumer module
context through dependencies.resolveFrom or inject the client loader at the transport boundary.
The version-one envelope retains canonical markdown and storage type: journal | retrospective.
It requires exact canonical repositories, stable URL-safe sourceEventId, ISO timestamp, explicit
workOutcome, and feedbackCoverage with status, sources, and dropped count. Optional category is
context only. Retrospectives retain valid date and integer/string issue/PR references. Markdown is
capped at 12 KB and the envelope at 16 KB. Known credentials are redacted; authors remain responsible
for minimizing summaries and excluding raw logs, transcripts, environment dumps, and undisclosed
secrets. A bound violation fails visibly without clipping findings.
writeFeedback({identity, envelope, mode, ...}) accepts an exact caller-owned session identity and
never manufactures native agent identities. Interactive mode requires an absolute outbox
directory. Ancestor ownership and permissions are not checked; existing directory and record modes
are accepted. New directories and files default to 0700 and 0600. The outbox itself must be a
real directory, and records must be regular files. The writer persists before transport with atomic
rename, file/directory fsync, and a stable record path. The outbox holds at most 128 records and 2 MB. Saturation,
corruption, or persistence failure blocks capture and preserves unsent records. Delivered records
are removed only after matching readback. Pending state includes count and a safe diagnostic;
interactive CLI exit zero means durable retention, and callers must inspect the printed status to
know whether delivery was acknowledged. Autonomous errors and unpersisted writes fail nonzero.
Identity, content, and archived-session conflicts fail in either mode while preserving the unsent
record; they are not reported as transient pending delivery. Replay retains permanently conflicted
records and continues to deliver unrelated pending records; transient failures stop that replay.
Verified delivery retains its receipt when local cleanup fails, returning
cleanupDiagnostic with value "outbox-cleanup-failed". A retained or crash-reappearing record is
safe to replay: an event is identified by session, sourceEventId, and content, and a duplicate that
differs only in timestamp is the same event, so it reports the stored record's timestamp and
receipt and the retained duplicate is removed.
Use vouchington agent-blackboard journal flush --outbox-directory PATH to replay unchanged pending
records after connectivity returns.
Autonomous mode prohibits the filesystem outbox. verifyFreshFeedback requires a fresh source-event
write plus readback of its own append receipt and rejects visible duplicate source records. This
is fresh online reporting evidence, not a distributed execution lease: eventually consistent
provider reads cannot establish source uniqueness. Trusted controllers
supply a unique new authorization-probe source ID, preserve their authoritative run/session
lineage, and atomically claim and revalidate the attempt before execution. Terminal writes keep work outcome separate from coverage and returned delivery state.
The delivered result includes a verified receipt with session ID, source-event ID and creation time.
Controllers require this online result together with atomically established attempt ownership
before execution.
Delivery is at least once. Replays pre-read matching source identity/content, accept equivalent
persistent duplicates, and reject conflicting reuse. Equality ignores object property order while
preserving array order. Each online operation has a 20-second deadline (timeoutMs can shorten it);
readback scans at most 10,000 records or 2 MB. The SDK does not expose cancellation for in-flight
requests, so a timed-out write can commit later. That never grants admission or a delivery receipt;
replay the identical envelope and source ID to verify its actual persistence.
composeRetrospective invokes the existing fact/transcript collectors with raw output disabled and
generates required sections and markers. Tool and architectural assessments preserve observation,
evidence, disposition and tracking reference. None-observed and unassessed states need a scoped
reason. Complete coverage is rejected when required sources are unavailable or capture is partial.
Typed collector reports expose availability independently of rendered text. Composition rejects
aggregate dropped counts below observed friction drops and retains larger caller aggregates without
double counting. Generated frontmatter carries validated work_outcome and feedback_coverage
for consumers to preserve or reject conflicting explicit overrides; trusted mode stays external.
Human top-five summaries do not authorize dropping additional durable findings.
The ## CI Failures and ## Sandbox & Permission Audit sections come from one optional audit
source; the two inputs are mutually exclusive and supplying both throws before any collector runs.
friction: {directory, journalLoader, ...} keeps reading the session-friction log together with the
journal and is unchanged. journal: {journalLoader} needs no friction directory or log: both
sections are assessed from the session's journal entries alone, and the report carries
coverage.frictionStatus: 'journal-only' (in place of empty or events) so the text states that
no log was observed. feedbackCoverage.status: 'complete' accepts either source. It is rejected
when neither is supplied (the error names the missing source), and a journal-only audit does not
count as assessed when the loader reports not-found (there is no log to establish that the session
was observed), throws, or is truncated by the scan bounds.
await composeRetrospective({ ...input, journal: { journalLoader } })journalLoader is the session-friction JournalLoader; JournalLoader, JournalLoadResult,
JournalEntry, and JournalAuditOptions are exported as types from
vouchington-tooling/agent-blackboard. The ## CI Failures block grammar and its three status
lines (failures observed, none observed, unavailable (<reason>)) are the same for both sources.
Journal-only sandbox and permission entries are journal Markdown entries that hold exactly one
block, escaped and length-bounded like CI failures, and other entries are ignored:
- `sandbox-escalation` — git push — network write blocked
- Outcome: requested | approved | denied | unknown
- Evidence: permission prompt shown
- Disposition: reran with approval
- `sandbox-failure` — node test — EPERM writing outside the worktree
- Evidence: stderr showed EPERM
- Disposition: moved output under TMPDIRambiguous-failure takes the same shape as sandbox-failure. The section reports
Status: none observed or Status: events observed, each followed by
(journal entries only; no friction log observed); a truncated scan reports
unavailable (journal scan incomplete) with the entries read so far.
Basic Auth exemption facts
vouchington-tooling/basic-auth-doc-sync extracts literal exemption collections from
TypeScript and route rows from Markdown. Callers configure declaration names and
runbook headings, then compare the returned data using their own route policy.
See the API contract.
TypeScript source graph
vouchington-tooling/source-module-graph exports createSourceModuleGraph. It accepts the
modules report from released no-mistakes
analyzeTypeScriptModules({ root, files }), plus the caller's root, ordered source extensions,
aliases, and file inventory. It resolves local imports and reexport owners without reading or
parsing source again. runtimeImports(file) uses binding references rather than declaration
presence, and reachableFrom(entrypoints, { runtimeOnly: true }) follows used runtime imports,
reexports, and literal dynamic/require loads. Missing or incomplete facts for a reached file
throw; external specifiers resolve to null. The default file inventory limit is 10,000
files and can be reduced with maxFiles.
Retrospective distill classifier
vouchington-tooling/retrospective-distill exports classifySession(session, entries, cutoffs),
which assigns a session one of retrospective, entry-type-unresolved, checkpoint-only,
journal-only, zero-entry-child, or zero-entry-root and decides distillation eligibility
against caller-supplied retroCutoff and sessionCutoff timestamps. It deduplicates replayed
source events, quarantines unknown entry types, invalid feedback envelopes, and conflicting source
events, and never marks an entry-type-unresolved session eligible. readPartitionRecords(path)
reads a local agent-blackboard partition JSONL file; parseDistillClassifyArgs and
runDistillClassify wrap both behind <partition.jsonl> --retro-cutoff <iso> --session-cutoff
<iso> and print one tab-separated line per session. The code is the source of truth for the
taxonomy; the retrospective-distill skill is its human-facing description.
Static schema-allowlist pairs
extractStaticStringPairs(source) from pg-schema-snapshot collects the first two string literals
of every array expression in ESTree field traversal order, including arrays with extra elements.
Conditional alternatives precede consequents, preserving the existing parser walker. It
preserves duplicates and decoded string values. It does not evaluate imports, exported constants,
spreads, or templates, and malformed source throws. Schema-allowlist consumers retain their own
file selection, key filtering, deduplication, snapshot comparison, and diagnostics. Parsing is
source-only and does not build a TypeScript compiler program or execute the source.
SQL view declarations
vouchington-tooling/sql-ast exports extractViewDeclarations(sql) and the
ManagedViewDeclaration type. Await initSqlAst() before calling the extractor. It returns the
qualified, PostgreSQL-quoted names and kinds of top-level CREATE VIEW and
CREATE MATERIALIZED VIEW declarations. It ignores comments, string literals, and other SQL
statements. Keywords that cannot be bare relation names remain quoted. Blank or unparseable SQL returns an empty
array; parser initialization and unexpected errors propagate. Consumers own view teardown and
lifecycle decisions.
SQL index shapes
vouchington-tooling/sql-ast exports asynchronous extractIndexShapes(sql). Await its result;
it lazily loads the optional no-mistakes peer and requires version 0.81.0 or newer when
called with nonblank SQL. Other SQL exports do not require this peer. It does not need
initSqlAst(). It returns
{ idxname, table, shapeKey } for each named top-level CREATE INDEX. Consumers can group
identical keys to detect collisions. Keys use upstream structural identity, including effective
sort/null ordering, quoted relation identity, expressions, predicates, operator classes, and
INCLUDE columns. Key serialization is opaque and must not be persisted across versions.
Any parse diagnostic rejects the whole input. Anonymous indexes and indexes inside DO blocks
are omitted. Consumer call sites must change from synchronous calls to await when adopting
this release.
Publication writer inventory facts
vouchington-tooling/post-publication-inventory exports
analyzePostPublicationWriterSource(source, fileName, options). It returns five booleans for an
approved capture-helper call, a capture opt-out, writes through a configured entity table,
generated relation writes, and eligibility-table writes. Consumers supply every module, symbol,
property, receiver, and table name through PostPublicationWriterSourceOptions and retain their
inventory schema, tracked files, exceptions, and diagnostics.
This preserves source-inventory heuristics, rather than proving runtime execution or SQL safety.
Capture imports/calls are name-based and order-independent; relation-variable appends are
order-sensitive. DML recognition examines literal/template text. Static table matching lowercases
the extracted name; dynamic literal table matching preserves case. Malformed TypeScript uses the
compiler's recovery tree. An argument-free append returns no relation fact.
Pass TypeScript source (.ts or .mts); the parser uses TypeScript mode even if the file name ends
in .tsx. Template expressions join their static fragments for DML matching, while DML prefixes
for generated-table facts come from templates rather than ordinary quoted strings. Dynamic
eligibility-table matching expects an unquoted literal immediately after the DML prefix and does
not recognize DELETE FROM ONLY.
Publication reader source facts
The same subpath exports sourceImportsAndComposesAny, sourceImportsAndUsesBoundaryAny, and
sourceFiltersWithPublicBoundary. Each accepts source text, selected imported symbols, and
ReaderSourceAnalysisOptions. Configure allowed modules per imported symbol, SQL tag and executor
imports through the existing ReaderSqlTemplateOptions, the ignored-call identifier, and the
candidate ID property. Missing import configuration admits no module.
These functions preserve the existing lexical source heuristics: named import aliases, local builder bindings, reassignment rejection, append/push consumption, returned boundary results, and collection filtering with the selected ID set. They do not prove runtime execution, general call graphs, or type identity. Malformed source throws through the ESTree parser. Inventory selection, classifications, exceptions, and diagnostics remain consumer policy.
composesPublicEligibilityView(source, options) checks live SQL fragments with
ReaderPublicViewOptions: SQL extraction settings, source and eligibility relation names, and
their ID columns. Await initSqlAst() from vouchington-tooling/sql-ast before calling it. The
existing parser is reused; no separate SQL facts or parser dependency is introduced.
The check preserves the existing nested SELECT/CTE, equality, inner-join, and correlated EXISTS heuristics. It rejects weakened OR/NOT/boolean/CASE predicates and non-filtering left joins. Every recognized live source reader must be protected. Unparseable SQL fragments are skipped; malformed source returns false. These are bounded syntactic heuristics, not a general SQL safety proof.
