skills_lint

This is not an officially supported Google product. This project is not eligible for the Google Open Source Software Vulnerability Rewards Program.

A static analysis linter for Agent Skills to ensure they meet the specification in presubmit checks. This project is a Dart package and can be run as a CLI tool to validate your skills directory before committing.

Table of Contents

Overview

An Agent Skill is a portable, self-contained directory that extends an AI agent's capabilities. Pre-submit linting ensures that your skill definitions are valid and ready for consumption by agent platforms.

skills_lint validates:

  • Presence of mandatory SKILL.md file.
  • YAML frontmatter constraints (naming, length, etc.).
  • Directory structure (flat, no deep nesting).
  • Relative path integrity.

For a full definition of the skill standard, see the Agent Skills Specification.

Installation

skills_lint ships as both a standalone native binary (no Dart SDK required) and as a Dart package on pub.dev. Pick the path that matches your environment.

Homebrew note. A brew install dart-skills-lint path is on the roadmap; it will land after skills_lint migrates to its own dedicated repository. Until then, the install paths below cover all supported platforms.

1. Dart developers — pub.dev

If you already have the Dart SDK installed, the standard pub.dev paths still work and are unchanged.

As a project dev_dependency

Add to your pubspec.yaml:

dev_dependencies:
  skills_lint: ^0.5.0

Then:

dart pub get

Globally installed

For multiple projects without per-project pubspec entries:

dart install skills_lint

2. install.sh — Linux + macOS, no Dart required

The recommended path for CI runners and laptops without the Dart SDK on PATH. Downloads the matching prebuilt binary from the latest GitHub Release, verifies its SHA256, and installs to /usr/local/bin (with a sudo fallback). Supports macOS arm64 + x64 and Linux x64 + arm64.

curl -fsSL https://github.com/google/skills_lint.dart/releases/latest/download/install.sh | bash

Optional env vars (set before the bash part):

  • INSTALL_DIR — install destination (default /usr/local/bin).
  • VERSION — pin a specific release like 0.4.0 (default latest).
  • REPO — alternate source repo (default google/skills_lint.dart).

macOS first-launch note

macOS binaries are not yet code-signed. The first time you run the binary, macOS Gatekeeper will block it ("cannot be opened because the developer cannot be verified"). Remove the quarantine flag once:

xattr -d com.apple.quarantine "$(which skills_lint)"

This step goes away once notarized builds ship.

3. Direct download — Linux + macOS, no install script

For environments where piping a script to bash isn't acceptable. Grab the tarball for your platform from the latest GitHub Release and verify its SHA256 against the release's SHA256SUMS asset.

TARGET="linux-x64"     # or: macos-arm64, macos-x64, linux-arm64
VERSION="0.5.0"
BASE="https://github.com/google/skills_lint.dart/releases/download/skills_lint-v${VERSION}"
curl -fsSLO "${BASE}/skills_lint-${TARGET}.tar.gz"
curl -fsSLO "${BASE}/SHA256SUMS"
grep " skills_lint-${TARGET}.tar.gz$" SHA256SUMS | sha256sum -c -
tar -xzf "skills_lint-${TARGET}.tar.gz"
sudo install -m 0755 "skills_lint-${TARGET}" /usr/local/bin/skills_lint

On macOS, replace sha256sum -c - with shasum -a 256 -c -.

Usage

skills_lint runs as a command-line tool, configured by flags or by a skills_lint.yaml file. The CLI is the user-facing surface; it also has a programmatic API for contributors who need to embed the linter in their own test suite — see CONTRIBUTING.md.

1. As a Command Line Tool with Arguments

Run the linter against your skills or root skills directories by passing arguments.

dart run skills_lint --skills-directory ./path/to/skills-root

Multiple root directories can be specified:

dart run skills_lint --skills-directory ./path/to/root-a --skills-directory ./path/to/root-b

Validate Individual Skills directly using --skill or -s:

dart run skills_lint --skill ./path/to/my-single-skill

If no directory is specified, it automatically checks .claude/skills and .agents/skills relative to your workspace root.

Flags

  • -d, --skills-directory: Specifies a root directory containing sub-folders of skills to validate. Can be passed multiple times. Can use home tilde expansion (ex: ~/.agents/skills).
  • -s, --skill: Specifies an individual skill directory to validate directly. Can be passed multiple times.
  • -q, --quiet: Hide non-error validation output.
  • -w, --print-warnings: Enable printing of warning messages.
  • --fast-fail: Halt execution immediately on the error.
  • --ignore-config: Ignore the YAML configuration file entirely.
  • --[no-]check-trailing-whitespace: Enable/disable checking for trailing whitespace. (Disabled by default).
  • --fix: Write fixes for failing lints to disk.
  • --dry-run: When combined with --fix, prints the proposed diff without writing.
  • --fix-apply: Deprecated alias for --fix. Prints a deprecation notice on use.

2. As a Command Line Tool with a YAML Configuration File

You can configure the linter using a configuration file (defaulting to skills_lint.yaml in the current directory).

Create skills_lint.yaml in the root of your repository:

# skills_lint.yaml
skills_lint:
  rules:
    check-relative-paths: error
    check-absolute-paths: error
  directories:
    - path: "~/.agents/skills"
      ignore_file: "~/.agents/skills/ignore.json"
  individual_skills:
    - path: "my_custom_standalone_skill"
      rules:
        missing_install_script: warning
      ignore_file: "my_ignores.json"

Then you can simply run:

dart run skills_lint

Rule Precedence

When resolving which severity and parameters to apply for a rule, skills_lint evaluates settings in the following order of precedence (highest to lowest):

  1. CLI Flags / API Overrides:
    • Rule severity overrides: Explicit flags passed to the CLI (e.g., --check-trailing-whitespace or --no-check-trailing-whitespace).
    • Rule parameter overrides: Namespaced command-line parameter flags (e.g., --path-does-not-exist-exclude=".*-workspace"). Passing an empty string (e.g. --path-does-not-exist-exclude="") explicitly clears the custom parameter.
  2. Path-Specific Config: Rules defined under directories: or individual_skills: in skills_lint.yaml for a matching path.
    • If a target config specifies a map (e.g. path-does-not-exist: { severity: error, exclude: "..." }), the parameters map completely overrides any global parameters for that rule.
    • If a target config specifies a simple string severity (e.g. path-does-not-exist: error), the severity is overridden, but the global parameters map is inherited/preserved.
  3. Global Config: Rules and parameters defined under the top-level rules: in skills_lint.yaml.
  4. Defaults: The hardcoded defaults for each rule.

This ensures that you can always override configuration file settings for a specific run by using CLI flags.


3. Custom Rules

Custom rule authoring lives in the dart-skills-lint-validation skill — that skill walks through extending SkillRule and passing the rule into the linter.

Built-in Rules

For the full list of built-in validation rules — default severities, exact diagnostic shapes, auto-fix behavior, and configuration options — see RULES.md.

Recipes

Drop-in snippets for the two most common ways to wire skills_lint into a project's quality gates. Each recipe is exercised by test/recipe_drift_test.dart, so if a flag here goes stale, CI fails.

Recipe: GitHub Actions

Save the following as .github/workflows/lint-skills.yml. It runs on every push and PR, installs skills_lint globally on the runner, and validates every skill under .claude/skills/. Adjust the path to match where your skills live.

# .github/workflows/lint-skills.yml
name: Lint Agent Skills
on:
  push:
    branches: [main]
  pull_request:

permissions: read-all

jobs:
  lint-skills:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - uses: dart-lang/setup-dart@v1
      - run: dart install skills_lint
      - run: skills_lint --skills-directory ./.claude/skills

To validate a single skill directory instead, swap the last step:

      - run: skills_lint --skill ./.claude/skills/my-skill

Recipe: Dart-native pre-commit hook

A pre-commit hook that calls into the linter directly — no Husky, no Python pre-commit framework, just Dart and the existing dart install tooling.

Install the linter globally once per machine:

dart install skills_lint

Then install the hook into the repository (run from the repo root):

cat > .git/hooks/pre-commit <<'HOOK'
#!/bin/sh
set -e
# Lint every skill under .claude/skills before each commit.
# Add --skill arguments for other locations as needed.
exec skills_lint --skills-directory ./.claude/skills --quiet
HOOK
chmod +x .git/hooks/pre-commit

The hook exits non-zero on lint failure, blocking the commit. To auto-apply fixable lints inside the hook, append --fix to the linter invocation.

Recipe: have an agent set it up for you

If you're using Claude Code, Gemini, or another agent that can read repository-local skills, paste the following prompt to have the agent install and validate skills_lint for you. The agent will follow the dart-skills-lint-setup skill for first-time wiring, then the dart-skills-lint-validation skill to run the linter and resolve any failures.

Set up skills_lint in this project. Use the skill at skills/dart-skills-lint-setup/SKILL.md to add it as a dev_dependency, create the configuration file, and wire it into CI. Then use the skill at skills/dart-skills-lint-validation/SKILL.md to run the linter and resolve any failures.

Contributing

Contributions are welcome! Please ensure that any PRs pass the linter and test suite.

Libraries

skills_lint