pastoralist
v1.13.6
Published
Audit, secure, and clean up package manager overrides for npm, pnpm, Yarn, and Bun.
Maintainers
Readme
Pastoralist
Pastoralist tracks your dependency overrides: why they're there, which packages need them, and when you can remove them.
Overrides usually start as real fixes: a CVE patch, a compatibility pin, a fork, or a transitive dependency workaround.
Months later, the reason may not be clear. Was it a security fix? A transitive bug? Which packages still need it? Can it be removed? With Pastoralist, the override sets the version, and the appendix holds the context.
Use Pastoralist to document dependency overrides, remove the ones you no longer need, and track override security fixes.
Quick Start
Install the global CLI with npm:
npm install --global pastoralistOr install the global CLI with Homebrew:
brew install yowainwright/tap/pastoralistThat's basically it. You can now run pastoralist from your shell when you
manage overrides.
For local projects where you just use pastoralist within scripts or CI,
npm install pastoralist --save-devis enough. Use Homebrew when you want a global CLI outside a project install.
Try It
To see what Pastoralist will find, start with a read-only check:
pastoralist doctorFor first-run guidance across local use, agents, and CI:
pastoralist onboardThe onboarding output includes quick scripts and copy/paste prompts for agents. See the Onboarding guide for the same checklist in the docs.
Working With Your Agent
Pastoralist does not need AI to work. It is ordinary CLI software.
If you use an agent, the included skill gives it the project instructions it needs to set up Pastoralist and keep override or CVE context current later.
Set up the Pastoralist agent skill in a repo:
pastoralist --init agent-skillAdd Pastoralist to a Project
When you are ready to add Pastoralist to the project:
npm install pastoralist --save-dev
npx pastoralistThis keeps the override where your package manager expects it, explains why it exists, and leaves the installed version visible in the lockfile after install:
--- package.json
+++ package.json
@@
{
"name": "shepherd-cli",
"version": "1.0.0",
"dependencies": {
"barn-yard": "^1.8.0"
},
"overrides": {
"barn-yard": "2.0.0"
- }
+ },
+ "pastoralist": {
+ "appendix": {
+ "[email protected]": {
+ "dependents": {
+ "shepherd-cli": "barn-yard@^1.8.0"
+ },
+ "ledger": {
+ "addedDate": "2026-08-22T00:00:00.000Z"
+ }
+ }
+ }
+ }
}
--- package-lock.json
+++ package-lock.json
@@ after npm install
- "node_modules/barn-yard": { "version": "1.8.0" }
+ "node_modules/barn-yard": { "version": "2.0.0" }Use npx pastoralist init when you want the config wizard for workspace paths,
external config, or security scanning.
Optionally keep the appendix current after installs:
{
"scripts": {
+ "postinstall": "pastoralist"
}
}Pastoralist can even add the hook above for you:
npx pastoralist --setup-hookWhat Pastoralist Does
Track Overrides Across Package Managers
Pastoralist works with npm and Bun overrides, pnpm pnpm.overrides, and Yarn
resolutions. It can also tie security fixes, patch files, workspace packages,
and CI checks to the same record.
{
// npm and Bun
"overrides": { "barn-yard": "2.0.0" },
// pnpm
"pnpm": { "overrides": { "old-goat": "4.1.0" } },
// Yarn
"resolutions": { "escaped-sheep": "1.0.1" },
}Record Why an Override Exists
The appendix shows why the override was added, why it is needed, or if it can be removed.
{
"pastoralist": {
"appendix": {
+ "[email protected]": {
+ "dependents": { "shepherd-cli": "barn-yard@^1" },
+ "ledger": {
+ "addedDate": "2026-08-22T00:00:00.000Z",
+ "reason": "Keep the gate API compatible.",
+ },
+ },
},
},
}Keep Security Context With the Override
Security records include the advisory, severity, provider, and patched version.
{
"pastoralist": {
"appendix": {
+ "[email protected]": {
+ "ledger": {
+ "addedDate": "2026-08-22T00:00:00.000Z",
+ "cves": ["CVE-escaped-sheep"],
+ "severity": "high",
+ "securityProvider": "osv",
+ "patchedVersion": "1.0.1",
+ },
+ },
},
},
}Link Local Patches
Pastoralist records the patch-package files that support an override.
{
"pastoralist": {
"appendix": {
"[email protected]": {
+ "patches": ["patches/patchy-alpaca+1.4.0.patch"],
},
},
},
}Remove Stale Overrides Safely
Preview unused overrides before explicitly removing them.
# first, test before removing
pastoralist --remove-unused --dry-run
# remove
pastoralist --remove-unusedConsolidate Workspace Overrides
Read workspace manifests and write one appendix in the root package.json.
{
"pastoralist": {
+ "depPaths": "workspace",
},
}Run Pastoralist in CI
Choose preview, summary, quiet, or machine-readable output.
pastoralist --dry-run
pastoralist --summary
pastoralist --quiet --checkSecurity
pastoralist --outputFormat jsonCLI API
Full reference: CLI API.
The direct commands below assume pastoralist is available from a project
script, global npm install, or Homebrew install. Use npx pastoralist ... for
one-off project setup.
pastoralist
Type:
command
Updates the target package manifest's override appendix. It reads npm
overrides, pnpm pnpm.overrides, Yarn resolutions, and Bun overrides.
pastoralist
pastoralist --dry-runUse this after dependency changes so the appendix stays tied to the override
that package managers actually read. Use --dry-run to preview the same update
without writing files.
--help and --version
Type:
boolean options
Prints CLI help or the installed package version.
pastoralist --help
pastoralist --version # -vUse these to check the installed CLI surface before wiring Pastoralist into scripts or CI.
--styleguide
Type:
boolean option
Opens an interactive radio menu for exploring the Pastoralist DX components
without reading or changing project configuration. Use the arrow keys and Enter
to choose a demo. In the prompt demo, Space toggles choices, a selects all,
n selects none, and Esc cancels.
pastoralist --styleguidepastoralist doctor
Type:
command
Runs a read-only health check. Internally this enables dryRun: true and
summary: true.
pastoralist doctor
pastoralist doctor --outputFormat jsonUse this before setup or cleanup work to see pending appendix, cleanup, and
security state without changing package.json.
In JSON mode, the important proof is small:
{
"updated": false,
"overrideCount": 1
}pastoralist onboard
Type:
command
Prints first-run guidance for local setup, agent setup, and GitHub Action setup.
pastoralist onboardUse this when a human or agent needs the same first-run checklist, setup commands, and CI prompt text.
pastoralist init
Type:
command
Starts the config wizard. The wizard can save config to package.json or an
external config file, configure workspace paths, and set up security scanning.
pastoralist initStores repeatable setup choices so future runs do not depend on memory or local shell history:
{
+ "pastoralist": {
+ "depPaths": "workspace",
+ "checkSecurity": true
+ }
}pastoralist init agent-skill
Type:
command
Installs the bundled Pastoralist agent skill into
.agents/skills/pastoralist. Existing unmanaged skill files are preserved.
pastoralist init agent-skillUse this to give agents Pastoralist-specific setup and maintenance instructions. The marker file lets Pastoralist update only the skill files it manages.
--- .agents/skills/pastoralist/SKILL.md
+++ .agents/skills/pastoralist/SKILL.md
@@
+Use `npx pastoralist doctor` for read-only project health.
+Use `npx pastoralist --remove-unused` only after reviewing dry-run output.
--- .agents/skills/pastoralist/.pastoralist-agent-config
+++ .agents/skills/pastoralist/.pastoralist-agent-config
@@
+pastoralist-agent-config--path, -p
Type:
string optionDefault:"package.json"
Selects the package manifest Pastoralist should read and update.
pastoralist --path packages/app/package.json # -p packages/app/package.jsonUse this when the manifest you want to check is not the root package.json.
--root, -r
Type:
string option
Sets the root directory used to resolve relative paths, config files, lockfiles, patches, and workspace globs.
pastoralist --root ../my-project # -r ../my-projectUse this when scripts run outside the project directory but paths should still resolve from the project root.
--depPaths, -d
Type:
string[] option
Scans additional package manifests for monorepo dependency context. Values are collected until the next flag.
pastoralist --depPaths "packages/*/package.json" # -d "packages/*/package.json"Use this in monorepos so one root appendix can explain which packages still need each override.
For a small barn-yard workspace, it turns scattered dependents into one root ledger entry:
--- package.json
+++ package.json
@@
+ "pastoralist": {
+ "appendix": {
+ "[email protected]": {
+ "dependents": {
+ "shepherd-cli": "barn-yard@^1.8.0",
+ "pasture-ui": "barn-yard@^1.9.0"
+ }
+ }
+ }
+ }--ignore
Type:
string[] option
Excludes package manifests from --depPaths matching.
pastoralist --ignore "**/node_modules/**"Use this to keep generated, vendored, or irrelevant manifests out of workspace scans.
--debug
Type:
boolean option
Enables debug logging for CLI execution.
pastoralist --debugUse this when config discovery, workspace matching, or provider behavior needs a trace.
--dry-run
Type:
boolean option
Previews package, appendix, override-source, and security changes without writing files.
pastoralist --dry-runUse this before committing config, appendix, cleanup, or security changes.
--outputFormat
Type:
"text" | "json" optionDefault:"text"
Selects terminal output or a single machine-readable JSON result.
pastoralist --dry-run --outputFormat jsonUse JSON output when CI or another tool needs stable fields instead of terminal
text. See PastoralistResult below for the full shape.
{
"success": true,
"updated": false,
"overrideCount": 1
}--summary
Type:
boolean option
Prints the metrics table after a text-mode run.
pastoralist --summaryUse this for human-readable run metrics without switching to JSON output.
--quiet, -q
Type:
boolean option
Suppresses normal text output for CI. Security findings make the command exit
with code 1; clean security checks exit with code 0.
pastoralist --quiet --checkSecurity # -q --checkSecurityUse this when CI should fail on vulnerabilities without printing the normal terminal report.
--setup-hook
Type:
boolean option
Adds pastoralist to the target manifest's postinstall script. Existing
postinstall scripts are appended with && pastoralist.
pastoralist --setup-hookKeeps the appendix current after package installs:
{
"scripts": {
- "postinstall": "build"
+ "postinstall": "build && pastoralist"
}
}--remove-unused
Type:
boolean option
Removes verified unused override entries from the active override source and
appendix. Preview first with --dry-run.
pastoralist --remove-unusedRemoves stale override records only after verification says they are no longer needed:
--- package.json
+++ package.json
@@
{
"overrides": {
- "stray-sheep": "1.0.0"
},
"pastoralist": {
"appendix": {
- "[email protected]": {}
}
}
}
--- package-lock.json
+++ package-lock.json
@@ after npm install
- "node_modules/stray-sheep": { "version": "1.0.0" }--checkSecurity
Type:
boolean option
Runs vulnerability scanning before the appendix update. Fixable security findings can add override data and security ledger fields.
pastoralist --checkSecurityUse this to connect vulnerability evidence to the override. With
--forceSecurityRefactor or an approved --interactive fix, Pastoralist can add
the patched override and security ledger fields:
--- package.json
+++ package.json
@@
{
+ "overrides": {
+ "barn-yard": "2.0.0"
+ },
+ "pastoralist": {
+ "appendix": {
+ "[email protected]": {
+ "ledger": {
+ "source": "security",
+ "cves": ["CVE-barn-yard-gate"],
+ "patchedVersion": "2.0.0"
+ }
+ }
+ }
+ }
}
--- package-lock.json
+++ package-lock.json
@@ after npm install
- "node_modules/barn-yard": { "version": "1.8.0" }
+ "node_modules/barn-yard": { "version": "2.0.0" }--securityProvider
Type:
"osv" | "github" | "snyk" | "npm" | "socket" | "spektion" | string[] option
Chooses one or more security providers. OSV is the default when security is enabled and no provider is set.
pastoralist --checkSecurity --securityProvider osvUse this when you need a specific advisory source. OSV is the default when security is enabled and no provider is set.
--securityProviderToken
Type:
string option
Passes a provider token for a single run. Prefer provider environment variables
for CI: GITHUB_TOKEN, SNYK_TOKEN, SOCKET_SECURITY_API_KEY, or
SPEKTION_API_KEY.
pastoralist --checkSecurity --securityProvider github --securityProviderToken "$GITHUB_TOKEN"Use this for a one-off authenticated scan without writing tokens to project config.
Security Mode Flags
Type:
boolean options
Controls how security findings are handled: --interactive prompts for fixes,
--forceSecurityRefactor applies available fixes without prompting,
--hasWorkspaceSecurityChecks includes workspace packages, --promptForReasons
asks for manual ledger reasons, and --strict fails on provider errors.
pastoralist --checkSecurity --interactive
pastoralist --checkSecurity --forceSecurityRefactor --strict
pastoralist --checkSecurity --hasWorkspaceSecurityChecks
pastoralist --promptForReasonsUse --interactive for review, --forceSecurityRefactor for unattended fixes,
and --strict when provider errors should fail the run.
Cache Flags
Type:
string | number | boolean options
Controls provider cache behavior. --cache-dir changes the cache directory,
--cache-ttl sets TTL seconds, --no-cache bypasses reads and writes, and
--refresh-cache bypasses reads while writing fresh data.
pastoralist --checkSecurity --cache-dir .cache/pastoralist
pastoralist --checkSecurity --cache-ttl 3600
pastoralist --checkSecurity --no-cache
pastoralist --checkSecurity --refresh-cacheUse these to avoid repeated provider calls, shorten cache windows, or force a fresh advisory lookup.
Data API
Full reference: Data API.
PastoralistResult
Type:
object
The JSON output shape returned by text-independent CLI runs. It reports write status, security status, unused overrides, applied string overrides, errors, and metrics.
pastoralist --dry-run --outputFormat json{
"success": true,
"hasSecurityIssues": false,
"hasUnusedOverrides": true,
"updated": false,
"securityAlertCount": 0,
"unusedOverrideCount": 1,
"overrideCount": 2,
"errors": [],
"securityAlerts": [],
"unusedOverrides": ["[email protected]"],
"appliedOverrides": {
"old-goat": "4.1.0"
},
"metrics": {
"packagesScanned": 1,
"workspacePackagesScanned": 0,
"appendixEntriesUpdated": 2,
"vulnerabilitiesBlocked": 0,
"overridesAdded": 0,
"overridesRemoved": 0,
"removedOverridePackages": [],
"severityCritical": 0,
"severityHigh": 0,
"severityMedium": 0,
"severityLow": 0,
"writeSuccess": false,
"writeSkipped": true
}
}pastoralist.appendix
Type:
Record<string, AppendixItem>
Stores the ledger entry for each override version. Keys use
package-name@version; values can include root dependencies, dependents,
patches, and ledger metadata.
{
"pastoralist": {
"appendix": {
"[email protected]": {
"dependents": {
"shepherd-cli": "old-goat@^3.0.0"
},
"ledger": {
"addedDate": "2026-08-22T00:00:00.000Z",
"reason": "Keep the older shepherd-cli integration working."
}
}
}
}
}AppendixItem.ledger
Type:
object
Records why an override exists and the security context behind it. Security runs can add CVEs, severity, provider, patched version, source, confidence, and resolution fields.
{
"ledger": {
"addedDate": "2026-08-22T00:00:00.000Z",
"source": "security",
"securityProvider": "osv",
"cves": ["CVE-2026-1234"],
"severity": "high",
"patchedVersion": "4.1.0",
"keep": {
"reason": "Wait for upstream compatibility confirmation.",
"reviewBy": "2026-09-30"
}
}
}Node.js API
Full reference: Node.js API.
update(options)
Type:
(options: Options) => UpdateContext
Runs the core override and appendix update from JavaScript or TypeScript. Pass a
parsed package manifest as config and the manifest path.
import { resolveJSON, update } from "pastoralist";
const path = "./package.json";
const config = resolveJSON(path);
if (config) {
const result = update({
config,
path,
dryRun: true,
depPaths: ["packages/*/package.json"],
});
process.stdout.write(`${result.metrics?.appendixEntriesUpdated ?? 0} entries\n`);
}SecurityChecker.checkSecurity(config, options)
Type:
(config: PastoralistJSON, options?: SecurityCheckRuntimeOptions) => Promise<SecurityCheckResult>
Runs provider-backed vulnerability scanning directly and returns alerts, suggested overrides, update suggestions, package counts, and optional best-case metadata.
import { resolveJSON, SecurityChecker } from "pastoralist";
const config = resolveJSON("./package.json");
const checker = new SecurityChecker({ provider: "osv" });
if (config) {
const result = await checker.checkSecurity(config, {
root: process.cwd(),
packageJsonPath: "./package.json",
severityThreshold: "high",
});
process.stdout.write(`${result.alerts.length} alerts found\n`);
}Configuration
Pastoralist reads config from package.json#pastoralist or an external config
file. External config files use top-level Pastoralist settings.
Config Files
Type:
".pastoralistrc" | ".pastoralistrc.json" | "pastoralist.json" | "pastoralist.config.cjs" | "pastoralist.config.js" | "pastoralist.config.mjs"
Pastoralist searches for the first matching external config file in this order:
.pastoralistrc, .pastoralistrc.json, pastoralist.json,
pastoralist.config.cjs, pastoralist.config.js, then
pastoralist.config.mjs. External config is merged with
package.json#pastoralist; package.json wins on conflicts.
{
"pastoralist": {
"depPaths": "workspace",
"checkSecurity": true
}
}export default {
depPaths: ["packages/*/package.json", "apps/*/package.json"],
checkSecurity: true,
};$schema
Type:
string
The JSON Schema is exported as pastoralist/schema.json.
External JSON config files can reference ./node_modules/pastoralist/src/schema.json with $schema.
Configs that reference this schema reject unknown or mistyped fields; other configs retain compatible validation behavior.
{
"$schema": "./node_modules/pastoralist/src/schema.json",
"depPaths": "workspace",
"checkSecurity": true
}depPaths
Type:
"workspace" | "workspaces" | string[]
Defines additional package manifests used for monorepo dependency context.
"workspace" and "workspaces" resolve from the root manifest's workspaces
field.
{
"workspaces": ["packages/*", "apps/*"],
"pastoralist": {
"depPaths": "workspace"
}
}{
"depPaths": ["packages/*/package.json", "apps/*/package.json"]
}overrideSource
Type:
string
Reads and writes native overrides from a separate JSON or YAML file instead of
the target package manifest. For pnpm 11 projects, Pastoralist can also resolve
pnpm-workspace.yaml automatically.
{
"pastoralist": {
"overrideSource": "config/overrides.json"
}
}packages:
- packages/*
overrides:
old-goat: 4.1.0appendixSource
Type:
string
Writes appendix data to a JSON config file instead of embedding it in
package.json. The target must be JSON or .pastoralistrc.
{
"pastoralist": {
"appendixSource": ".pastoralistrc.json"
}
}compactAppendix
Type:
boolean
Stores routine appendix entries as { "addedDate": "..." } when no dependency,
patch, security, or keep data needs to stay expanded.
{
"pastoralist": {
"compactAppendix": true
}
}overridePaths and resolutionPaths
Type:
Record<string, Appendix>
Keeps manual appendix data for packages whose overrides or resolutions live in
workspace-specific paths. resolutionPaths is the Yarn-oriented fallback.
{
"pastoralist": {
"overridePaths": {
"packages/web/package.json": {
"[email protected]": {
"ledger": {
"addedDate": "2026-08-22T00:00:00.000Z",
"reason": "Pinned for the web app release."
}
}
}
}
}
}checkSecurity
Type:
boolean
Enables security scanning from config. security.enabled can override this
inside the nested security config.
{
"pastoralist": {
"checkSecurity": true
}
}security
Type:
object
Configures security scanning. Supported fields are enabled, provider,
autoFix, interactive, securityProviderToken, severityThreshold,
excludePackages, hasWorkspaceSecurityChecks, strict, and preferLatest.
{
"pastoralist": {
"security": {
"enabled": true,
"provider": ["osv", "npm"],
"severityThreshold": "medium",
"excludePackages": ["@types/*"],
"hasWorkspaceSecurityChecks": true,
"strict": true
}
}
}bestCase
Type:
BestCaseConfig
Opts into portfolio-level security fix selection. Pastoralist ranks complete version states by ordered objectives instead of picking each package fix in isolation.
{
"pastoralist": {
"checkSecurity": true,
"bestCase": {
"enabled": true,
"userOwnedOverrides": ["alpha"],
"riskAggregation": "both",
"objectives": ["known-exploited", "critical", "high", "change-count"],
"search": {
"mode": "auto",
"exactStateLimit": 256,
"beamWidth": 16,
"maxEvaluations": 1000
}
}
}
}See Configuration and Workspaces for the full setup surface.
GitHub Action
Check override tracking on pull requests:
name: Override Check
on: [pull_request]
jobs:
pastoralist:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
+ - uses: yowainwright/pastoralist@v1
+ with:
+ mode: check
+ check-security: falseThe action can also run security checks, update files, or open scheduled maintenance PRs. See the GitHub Action docs.
Security and Release Assurance
- Releases are published from GitHub Actions with npm provenance
- Published tarballs are packed before release and attached to GitHub Releases with artifact attestations
- Stable Homebrew releases build, test, and attest the binary asset matrix
- Stable releases open a reviewed Homebrew tap update
- CI runs CodeQL, OpenSSF Scorecard, unit, integration, e2e, and dependency policy checks
You can verify registry signatures from your project:
npm audit signaturesPlease reach out with any desired security requests and I will do my best to support you!
Thanks
Shout out to Mardin for the conversation, insight, and pairing around this topic.
Made by @yowainwright. MIT, 2022-2026.
