Skip to content

skills-lock-valid

skills-lock.json files must be valid and portable project lockfiles

Severity error (auto)
Autofix -
Since v0.20.0
Repo Types skills-lock
Category Vercel

Why

The Vercel skills CLI records each project's installed skills in skills-lock.json. The lockfile tells later skills update and restore operations where a skill came from, which source dialect to use, which SKILL.md was selected, and what content hash was installed. A lockfile can remain valid JSON while a wrong field type or an unusable path quietly makes those operations unreliable.

This rule follows the project-lock structure implemented by the CLI's src/local-lock.ts:

  • the root is an object with numeric version and an object-valued skills;
  • each skill has non-empty source and sourceType strings;
  • computedHash, when present, is a lowercase, 64-character SHA-256 hex digest. The CLI reads it only to detect drift, so an entry without one is a warning rather than an error;
  • optional sourceUrl, ref, skillPath, and wellKnownDigest fields have the string shape their consumers expect;
  • optional subagents is an array of strings. An empty string is valid here: the CLI uses it for a source's root agent;
  • skillPath cannot be absolute or traverse above the downloaded source, and ends in SKILL.md;
  • a wellKnownDigest, when present, uses sha256: followed by 64 lowercase hex characters.

Known sourceType values are github, gitlab, git, local, well-known, node_modules, and download. A newer CLI may add another one, so an unknown value is information rather than an error and can be accepted immediately with extra-source-types.

Validation is offline and structural: computedHash is checked for format (a lowercase 64-character SHA-256 hex digest) rather than recalculated over the network. Because lockfiles are generated by package managers, defects are reported for human review without autofix.

Detection

Every exact skills-lock.json filename is discovered recursively. This supports monorepos where the root and individual packages each run the skills CLI. Vendored directories and paths excluded through skillsaw configuration are not attached. A global .skill-lock.json or singular skill-lock.json is a different file and is not claimed by this rule.

The rule auto-enables whenever at least one non-excluded project lockfile is present. A lockfile is structured JSON rather than agent prose, so content rules never read it.

skillsaw also uses valid lock entries as provenance for installed skill directories. A remote, package-managed, unknown, or repository-external local source marks the matching installed skill as externally sourced. Those payloads are linted by default, but skillsaw fix never rewrites them. Set the top-level lint-external-content: false configuration key to omit them from rule discovery while continuing to validate skills-lock.json itself. A local source that resolves inside the lint root remains repository-owned.

Severity

Errors identify data the CLI cannot reliably interpret: invalid or non-strict JSON (including bare NaN or Infinity), the wrong top-level shape, missing or wrong-typed required fields, malformed digests, malformed optional fields, or a skillPath that escapes its source or does not point to SKILL.md.

Warnings identify a lockfile that remains readable but is not portable or may not restore correctly:

  • a schema version newer than this skillsaw release;
  • an entry without computedHash, which npx skills check cannot verify;
  • a bare git or gitlab shorthand without the sourceUrl the CLI's update path needs;
  • an absolute local source path;
  • backslashes in skillPath, which are not portable path separators.

An unknown sourceType is informational because it may come from a newer or custom skills CLI.

Examples

Good:

{
  "version": 1,
  "skills": {
    "release-notes": {
      "source": "vercel-labs/skills",
      "sourceType": "github",
      "computedHash": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
      "sourceUrl": "https://github.com/vercel-labs/skills.git",
      "ref": "main",
      "skillPath": "skills/release-notes/SKILL.md"
    }
  }
}

Bad:

{
  "version": 1,
  "skills": {
    "release-notes": {
      "source": "/Users/alice/src/skills/release-notes",
      "sourceType": "local",
      "computedHash": "not-a-sha256",
      "skillPath": "../README.md",
      "subagents": "reviewer"
    }
  }
}

The absolute source only works on one machine, the digest has the wrong shape, skillPath escapes the downloaded source and does not end in SKILL.md, and subagents must be an array.

How to fix

Regenerate a damaged lockfile with the same skills CLI release used by the project, or correct the reported structural fields and rerun the CLI command that consumes it. Prefer project-relative local sources and / separators.

If a legitimate source type was added after this skillsaw release, accept it without disabling the rest of the rule:

rules:
  skills-lock-valid:
    extra-source-types:
      - registry

Configuration

rules:
  skills-lock-valid:
    enabled: auto  # true | false | auto
    severity: error
Parameter Description Default
extra-source-types Additional sourceType values to accept when a newer or custom skills CLI writes sources this skillsaw release does not know []

Run skillsaw explain skills-lock-valid to see this documentation and the rule's effective configuration in your terminal.