GESH Lab · LLM tooling

Lint the skill before it taxes every turn.

Zero-dependency linter for Claude Code and Agent Skills. Frontmatter, progressive disclosure, dead refs, secrets, stale model IDs — plus a 22-skill NetOps pack for the change window.

89lint checks
22NetOps skills
0runtime deps
3profiles
2026Claude fields

What 0.5 adds

CLI and playground now agree. Pin the GitHub Action at @v0.5.0. Docs live here; the engine lives in one Python 3.8+ file.

2026 models

Opus 5, Sonnet 5, Fable 5, Mythos 5 are current. Opus 4.8 / Sonnet 4.6 / Haiku 4.5 stay current. Claude 3.x is stale-model-id. --fix rewrites 3.x to claude-sonnet-5.

Computer-use safety

computer-unscoped fails closed when computer use / computer_toolset is paired with bare Bash on a jump host.

Out of beta

Agent Skills no longer need the skills-2025-10-02 header. beta-header-stale flags copy that still says they do. plugin-colon-name catches plugin:skill in name:.

Current model IDs

Anything else is stale-model-id. Override leftovers with --allow-model.

claude-opus-5

Opus 5

Deep reasoning, long-horizon agents.

claude-opus-4-8

Opus 4.8

Previous flagship, still current.

claude-sonnet-5

Sonnet 5

Default coding / NetOps agent. --fix target.

claude-sonnet-4-6

Sonnet 4.6

Still current in Claude Code.

claude-haiku-4-5

Haiku 4.5

Fast, cheap classification.

claude-fable-5

Fable 5

Frontier class. Alias: fable.

claude-mythos-5

Mythos 5

Cyberdefense / trusted access. Alias: mythos.

Install

Python 3.8+, no dependencies. Exit non-zero on ERROR so it drops into CI. --fail-on-warn and --min-score 80 for stricter gates.

Install script

curl -fsSL https://raw.githubusercontent.com/gesh75/claude-skill-lint/main/install.sh -o install.sh
bash install.sh
skill-lint ~/.claude/skills

Single file

curl -O https://raw.githubusercontent.com/gesh75/claude-skill-lint/main/skill_lint.py
chmod +x skill_lint.py
./skill_lint.py ~/.claude/skills

GitHub Action

name: skill-lint
on: [push, pull_request]
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: gesh75/claude-skill-lint@v0.5.0
        with:
          path: skills
          profile: claude-code
          sarif: skill-lint.sarif
      - uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: skill-lint.sarif

CLI

skill_lint.py [PATH] [--json] [--sarif FILE] [--profile claude-code|spec|claude-ai]
              [--allow-model ID] [--fail-on-warn] [--fix] [--stdin]
              [--min-score N] [--ignore CODE] [--exclude GLOB]

Profiles: claude-code (default, CC extensions are INFO), spec (strict Agent Skills), claude-ai (reserved names + XML). Score: errors −16, warns −6, infos −1, floor 0.

Checks

89 rules across schema, authoring, safety, disclosure, and style. Full table in the README. New in 0.5:

CodeLevelWhat it catches
computer-unscopedWARNcomputer use / computer_toolset paired with unscoped Bash
beta-header-staleINFOskills-2025-10-02 treated as still required — Agent Skills are out of beta
plugin-colon-nameWARNname contains a colon; plugin namespace is /plugin:name at invoke time
stale-model-idWARNoutdated Claude model id (Claude 3.x, pre-4.5 leftovers)
unscoped-bashWARNallowed-tools grants bare Bash
disk-wipe / reverse-shellERRORmkfs, dd if=/dev/zero, nc -e, /dev/tcp, pty.spawn

Two cost surfaces

L1 description is loaded every turn (~100 tok). L2 body loads on fire (<5k tok). L3 references/scripts are zero until read. A vague trigger is a permanent tax.

Fail-closed CI

Non-zero exit on ERROR. GitHub Actions annotations and SARIF 2.1.0. Treat a skill like software you install.

Safety second pass

Secrets, reverse shells, disk wipes, curl|bash, insecure TLS, unpinned installs, bundled .env / id_rsa.

NetOps pack

22 production skills. Each file lints clean at ERROR/WARN, has a do-not-use boundary, numbered steps, and a verify loop. Copy into ~/.claude/skills//SKILL.md.

Source: skills/netops. Lint the pack with python3 skill_lint.py skills/netops --quiet --min-score 90.