
Lint And Validate
Run project-aware lint and type checks (ESLint, TypeScript, Ruff, mypy) from one agent workflow before you merge or ship.
Overview
lint-and-validate is an agent skill for the Ship phase that detects your stack and runs the right linters and type checkers from one project path.
Install
npx skills add https://github.com/sickn33/antigravity-awesome-skills --skill lint-and-validateWhat is this skill?
- Auto-detects Node.js vs Python from package.json and common config files
- Runs npm run lint, npx eslint, or tsc --noEmit for TypeScript projects
- Runs ruff check and mypy for Python trees when applicable
- Single CLI entry: python lint_runner.py with a project path argument
- UTF-8 safe console output for cross-platform agent runs
- Supports Node.js and Python project detection with multiple linter backends
Adoption & trust: 820 installs on skills.sh; 40.1k GitHub stars; 2/3 security scanners passed (skills.sh audits).
What problem does it solve?
You are about to ship but your agent does not know whether to call ESLint, tsc, Ruff, or mypy for this repo.
Who is it for?
Solo builders shipping Node or Python apps who want stack-aware static checks without writing custom CI scripts each time.
Skip if: Repos with no package.json or Python tooling, change freezes where only docs edits are allowed, or teams that need deep SAST beyond lint and types.
When should I use this skill?
Before merge, release, or when validating that a refactor still passes stack-standard lint and type checks.
What do I get? / Deliverables
You get a unified lint and type-check pass aligned to Node or Python so obvious issues are fixed before review or deploy.
- Lint and type-check console output
- Actionable fix list for the agent to apply
Recommended Skills
Journey fit
Linting and static type checks are classic pre-ship quality gates that catch regressions before release. Testing subphase covers automated checks that do not require full E2E suites—exactly what a unified lint runner provides.
How it compares
Use as a focused lint/type runner instead of asking the agent to guess npm vs pip commands ad hoc.
Common Questions / FAQ
Who is lint-and-validate for?
Indie and solo developers using Claude Code, Cursor, or Codex who maintain mixed Node and Python projects and want one skill to standardize pre-ship checks.
When should I use lint-and-validate?
During Ship/testing before PRs, after refactors in Build, or when aligning local runs with CI in Operate—whenever you need eslint, tsc, ruff, or mypy without manual setup.
Is lint-and-validate safe to install?
It runs standard dev tools via subprocess on your project; review the Security Audits panel on this Prism page and confirm scripts in package.json before executing in production repos.
SKILL.md
READMESKILL.md - Lint And Validate
#!/usr/bin/env python3 """ Lint Runner - Unified linting and type checking Runs appropriate linters based on project type. Usage: python lint_runner.py <project_path> Supports: - Node.js: npm run lint, npx tsc --noEmit - Python: ruff check, mypy """ import subprocess import sys import json from pathlib import Path from datetime import datetime # Fix Windows console encoding try: sys.stdout.reconfigure(encoding='utf-8', errors='replace') except: pass def detect_project_type(project_path: Path) -> dict: """Detect project type and available linters.""" result = { "type": "unknown", "linters": [] } # Node.js project package_json = project_path / "package.json" if package_json.exists(): result["type"] = "node" try: pkg = json.loads(package_json.read_text(encoding='utf-8')) scripts = pkg.get("scripts", {}) deps = {**pkg.get("dependencies", {}), **pkg.get("devDependencies", {})} # Check for lint script if "lint" in scripts: result["linters"].append({"name": "npm lint", "cmd": ["npm", "run", "lint"]}) elif "eslint" in deps: result["linters"].append({"name": "eslint", "cmd": ["npx", "eslint", "."]}) # Check for TypeScript if "typescript" in deps or (project_path / "tsconfig.json").exists(): result["linters"].append({"name": "tsc", "cmd": ["npx", "tsc", "--noEmit"]}) except: pass # Python project if (project_path / "pyproject.toml").exists() or (project_path / "requirements.txt").exists(): result["type"] = "python" # Check for ruff result["linters"].append({"name": "ruff", "cmd": ["ruff", "check", "."]}) # Check for mypy if (project_path / "mypy.ini").exists() or (project_path / "pyproject.toml").exists(): result["linters"].append({"name": "mypy", "cmd": ["mypy", "."]}) return result def run_linter(linter: dict, cwd: Path) -> dict: """Run a single linter and return results.""" result = { "name": linter["name"], "passed": False, "output": "", "error": "" } try: proc = subprocess.run( linter["cmd"], cwd=str(cwd), capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=120 ) result["output"] = proc.stdout[:2000] if proc.stdout else "" result["error"] = proc.stderr[:500] if proc.stderr else "" result["passed"] = proc.returncode == 0 except FileNotFoundError: result["error"] = f"Command not found: {linter['cmd'][0]}" except subprocess.TimeoutExpired: result["error"] = "Timeout after 120s" except Exception as e: result["error"] = str(e) return result def main(): project_path = Path(sys.argv[1] if len(sys.argv) > 1 else ".").resolve() print(f"\n{'='*60}") print(f"[LINT RUNNER] Unified Linting") print(f"{'='*60}") print(f"Project: {project_path}") print(f"Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") # Detect project type project_info = detect_project_type(project_path) print(f"Type: {project_info['type']}") print(f"Linters: {len(project_info['linters'])}") print("-"*60) if not project_info["linters"]: print("No linters found for this project type.") output = { "script": "lint_runner", "project": str(project_path), "type": project_info["type"], "checks": [], "passed": True, "message": "No linters configured" } print(json.dumps(output, indent=2)) sys.exit(0) # Run each linter results = [] all_passed = True