Automated summary
Auto-discovers linting and formatting tools and generates the .claude/checkmate.json configuration file.
Strengths
- Automatic detection of tools based on the environment (npm, uv, cargo, etc.)
- Monorepo support with multiple environments
- Generates a ready-to-use configuration
Limitations
- Requires tools to be already installed in the project
- Only covers explicitly detected languages and tools (JS/TS, Python, Rust, Go)
- If a config already exists, user must confirm deletion
When initializing checkmate for a new project.
If a checkmate configuration already exists, use /checkmate:checkmate-refresh instead.
Security analysis
SafeThe skill only runs read-only diagnostic commands (ls, find, command -v, --version) to detect project structure and available tools. It does not execute any destructive actions or exfiltrate data. All commands are standard and safe.
No concerns found
How this analysis is madeExamples
Set up code quality checks for this project using checkmate.Auto-discover all linting and formatting tools in this project and create the checkmate configuration.Run checkmate-init to generate a .claude/checkmate.json that covers all packages in this monorepo.name: checkmate-init description: Auto-discover linting and formatting tools, generate .claude/checkmate.json configuration. Use when setting up checkmate for a new project. disable-model-invocation: true user-invocable: true argument-hint: ""
checkmate-init
Configure code quality checks for this project by discovering available tools and creating .claude/checkmate.json.
Instructions
You are helping the user set up automated code quality checks. Follow this process:
Step 0: Check for Existing Config
First, check if a config already exists:
ls -la .claude/checkmate.json 2>/dev/null
If config exists, STOP and warn the user:
A checkmate configuration already exists at .claude/checkmate.json
Running /checkmate:checkmate-init will delete the existing config and create a new one.
If you want to update the existing config, run /checkmate:checkmate-refresh instead.
Do you want to proceed and replace the existing configuration? (yes/no)
Only proceed if user explicitly confirms. If they say no, suggest /checkmate:checkmate-refresh.
Step 1: Discover Project Structure
Run these commands to understand the project:
# Find project root (look for .git, package.json, pyproject.toml, Cargo.toml)
ls -la
# Detect file types in the project
find . -type f -name "*.py" | head -1
find . -type f -name "*.ts" -o -name "*.tsx" | head -1
find . -type f -name "*.js" -o -name "*.jsx" | head -1
find . -type f -name "*.rs" | head -1
find . -type f -name "*.go" | head -1
find . -type f \( -name "*.c" -o -name "*.cpp" -o -name "*.cc" -o -name "*.h" -o -name "*.hpp" \) | head -1
find . -type f -name "*.sh" | head -1
# Check for formatter-compatible files
find . -type f \( -name "*.json" -o -name "*.md" -o -name "*.yaml" -o -name "*.yml" \) | head -1
# Check for package managers and config files
ls package.json pyproject.toml Cargo.toml go.mod CMakeLists.txt Makefile .clang-format 2>/dev/null
# Detect build/temp directories to exclude
ls -d dist build out .next .nuxt coverage __pycache__ .pytest_cache target 2>/dev/null
Step 2: Detect All Environments
Use the checkmate:detect-environment subagent to detect all package managers and environment configurations, including nested setups in monorepos.
The agent returns an array of environments:
{
"environments": [
{
"path": ".",
"javascript": { "primary": "pnpm", "exec": ["pnpm", "exec"] },
"python": null,
"rust": null,
"go": null
},
{
"path": "services/api",
"javascript": null,
"python": { "primary": "uv", "exec": ["uv", "run"] },
"rust": null,
"go": null
}
]
}
Use the exec array to build tool invocation commands:
exec: ["pnpm", "exec"]→{ "command": "pnpm", "args": ["exec", "prettier", "--check", "$FILE"] }exec: ["uv", "run"]→{ "command": "uv", "args": ["run", "ruff", "check", "$FILE"] }exec: [](empty) →{ "command": "golangci-lint", "args": ["run", "$FILE"] }
For monorepos: Each environment path needs its own check configuration with the correct invocation pattern.
Step 3: Discover Available Tools
Using the detected invocation pattern, check which tools are available:
JavaScript/TypeScript tools (using detected exec pattern):
<exec> prettier --version 2>/dev/null && echo "prettier available"
<exec> eslint --version 2>/dev/null && echo "eslint available"
<exec> biome --version 2>/dev/null && echo "biome available"
<exec> tsc-files --version 2>/dev/null && echo "tsc-files available"
Note: Avoid tsc - it checks the entire project on every file change. Use tsc-files (per-file) or eslint with @typescript-eslint instead.
Python tools (using detected exec pattern):
<exec> ruff --version 2>/dev/null && echo "ruff available"
<exec> ty --version 2>/dev/null && echo "ty available"
<exec> mypy --version 2>/dev/null && echo "mypy available"
Rust tools:
cargo fmt --version 2>/dev/null && echo "rustfmt available"
cargo clippy --version 2>/dev/null && echo "clippy available"
Go tools:
command -v golangci-lint && golangci-lint --version
command -v staticcheck && staticcheck --version
C/C++ tools:
# Check standard paths first
command -v clang-format && clang-format --version
command -v clang-tidy && clang-tidy --version
command -v cppcheck && cppcheck --version
# macOS Homebrew LLVM (not in PATH by default)
/opt/homebrew/opt/llvm/bin/clang-format --version 2>/dev/null
/opt/homebrew/opt/llvm/bin/clang-tidy --version 2>/dev/null
# Linux Homebrew LLVM
/home/linuxbrew/.linuxbrew/opt/llvm/bin/clang-format --version 2>/dev/null
Platform note: On macOS with Homebrew, LLVM tools are installed at /opt/homebrew/opt/llvm/bin/ but not symlinked to avoid conflicts with Apple's clang. Use the full path in commands:
{ "command": "/opt/homebrew/opt/llvm/bin/clang-format", "args": ["--dry-run", "-Werror", "$FILE"] }
Shell script tools:
command -v shellcheck && shellcheck --version
command -v shfmt && shfmt --version
If no tools found: Suggest installation based on detected environment:
- Python + uv:
uv add --dev ruff - Python + pip:
pip install ruff - TypeScript + pnpm:
pnpm add -D prettier eslint typescript - TypeScript + npm:
npm install -D prettier eslint typescript - TypeScript (tsc present, tsc-files missing):
pnpm add -D tsc-filesornpm install -D tsc-files - Go:
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest - C/C++ (macOS):
brew install llvm(note: use full path/opt/homebrew/opt/llvm/bin/clang-format) - C/C++ (Linux):
apt install clang-format clang-tidyordnf install clang-tools-extra - Shell:
brew install shellcheck shfmtorapt install shellcheck shfmt
Step 4: Build Configuration
Based on discovered tools, file types, and detected invocation pattern, propose a checkmate.json configuration.
Schema (array format):
{
"environments": [
{
"name": "<environment name>",
"paths": ["<path1>", "<path2>"],
"exclude": ["<pattern>"],
"checks": {
"<extension>": [
{
"name": "<display name>",
"command": "<executable>",
"args": ["<arg1>", "$FILE"],
"parser": "<parser name or object>",
"maxDiagnostics": 5
}
]
}
}
]
}
Field definitions:
name- Optional descriptive name for the environmentpaths- Array of paths this environment covers (use"."for root)exclude- Optional array of glob patterns to exclude (e.g.,"**/*.test.ts")checks- Object mapping file extensions to check arrays$FILE- Placeholder replaced with actual file path at runtime
Default excludes: Always exclude build artifacts and temp directories that exist in the project:
- JavaScript/TypeScript:
dist/**,build/**,out/**,.next/**,.nuxt/**,coverage/** - Python:
__pycache__/**,.pytest_cache/**,.venv/**,*.egg-info/** - Rust:
target/** - General:
node_modules/**(already excluded by most tools)
Matching rule: First environment in the array that matches wins. Put specific environments before general ones.
Simple project (single environment):
{
"environments": [
{
"name": "root",
"paths": ["."],
"exclude": ["dist/**", "coverage/**"],
"checks": {
".ts,.tsx": [
{ "name": "prettier", "command": "pnpm", "args": ["exec", "prettier", "--check", "$FILE"], "parser": "prettier", "_auto": true }
]
}
}
]
}
Note: Only include excludes for directories that actually exist in the project.
Monorepo (multiple environments):
{
"environments": [
{
"name": "frontend",
"paths": ["apps/web", "packages/ui"],
"checks": {
".ts,.tsx": [
{ "name": "prettier", "command": "pnpm", "args": ["exec", "prettier", "--check", "$FILE"], "parser": "prettier", "_auto": true }
]
}
},
{
"name": "api",
"paths": ["services/api"],
"checks": {
".py": [
{ "name": "ruff", "command": "uv", "args": ["run", "ruff", "check", "$FILE"], "parser": "ruff", "_auto": true }
]
}
},
{
"name": "root",
"paths": ["."],
"exclude": ["apps/**", "packages/**", "services/**"],
"checks": {
".md,.json": [
{ "name": "prettier", "command": "pnpm", "args": ["exec", "prettier", "--check", "$FILE"], "parser": "prettier", "_auto": true }
]
}
}
]
}
Important: Array order matters - first matching environment wins. Put specific environments (like services/api) before general ones (like .).
Predefined parsers:
| Parser | Use For | Output Format |
|--------|---------|---------------|
| ruff | Ruff linter | path:line:col: CODE message |
| ty | ty type checker | Multi-line Rust-style errors |
| eslint | ESLint (with @typescript-eslint for type checks) | path:line:col severity message rule |
| tsc | tsc, tsc-files (TypeScript) | path(line,col): error TScode: message |
| biome | Biome | path:line:col rule message |
| prettier | Any format checker | Pass/fail only (non-empty = fail) |
| jsonl | JSON Lines output | {"file":"x.ts","line":10,"message":"err"} |
| gcc | GCC-style output | path:line:col: severity: message (clang-format, clang-tidy, shellcheck --format=gcc) |
| generic | Fallback | Returns raw output truncated |
Custom regex parser: For tools without a predefined parser, use an inline regex with named capture groups:
{
"name": "my-linter",
"command": "my-linter",
"args": ["check", "$FILE"],
"parser": {
"pattern": ":(?<line>\\d+):(?<column>\\d+):\\s*(?<message>.+)",
"severity": "error"
}
}
Named groups: line, column, message, rule, severity (all optional).
For unfamiliar tools, use the checkmate:configure-tool subagent to analyze output and build a regex.
Common configurations by environment:
All auto-discovered checks include "_auto": true so /checkmate:checkmate-refresh can manage them.
Python (adapt runner to detected environment):
// uv (uv.lock present)
{ "name": "ruff", "command": "uv", "args": ["run", "ruff", "check", "$FILE"], "parser": "ruff", "_auto": true }
// poetry (poetry.lock present)
{ "name": "ruff", "command": "poetry", "args": ["run", "ruff", "check", "$FILE"], "parser": "ruff", "_auto": true }
// pipenv (Pipfile present)
{ "name": "ruff", "command": "pipenv", "args": ["run", "ruff", "check", "$FILE"], "parser": "ruff", "_auto": true }
// global install or activated venv
{ "name": "ruff", "command": "ruff", "args": ["check", "$FILE"], "parser": "ruff", "_auto": true }
TypeScript/JavaScript (adapt runner to detected package manager):
// pnpm (pnpm-lock.yaml present)
{ "name": "eslint", "command": "pnpm", "args": ["exec", "eslint", "$FILE"], "parser": "eslint", "_auto": true }
// npm (package-lock.json present)
{ "name": "eslint", "command": "npx", "args": ["eslint", "$FILE"], "parser": "eslint", "_auto": true }
// yarn (yarn.lock present)
{ "name": "eslint", "command": "yarn", "args": ["eslint", "$FILE"], "parser": "eslint", "_auto": true }
// bun (bun.lockb present)
{ "name": "eslint", "command": "bun", "args": ["eslint", "$FILE"], "parser": "eslint", "_auto": true }
Rust (always use cargo):
{ "name": "clippy", "command": "cargo", "args": ["clippy", "--", "-D", "warnings"], "parser": "generic", "_auto": true }
{ "name": "rustfmt", "command": "cargo", "args": ["fmt", "--check"], "parser": "prettier", "_auto": true }
Go (direct invocation):
{ "name": "golangci-lint", "command": "golangci-lint", "args": ["run", "$FILE"], "parser": { "pattern": ":(?<line>\\d+):(?<column>\\d+):\\s*(?<message>.+)", "severity": "error" }, "_auto": true }
C/C++ (use full path on macOS Homebrew):
// clang-format (check formatting)
{ "name": "clang-format", "command": "clang-format", "args": ["--dry-run", "-Werror", "$FILE"], "parser": "gcc", "_auto": true }
// macOS Homebrew (not in PATH)
{ "name": "clang-format", "command": "/opt/homebrew/opt/llvm/bin/clang-format", "args": ["--dry-run", "-Werror", "$FILE"], "parser": "gcc", "_auto": true }
// clang-tidy (static analysis)
{ "name": "clang-tidy", "command": "clang-tidy", "args": ["$FILE", "--"], "parser": "gcc", "_auto": true }
// cppcheck
{ "name": "cppcheck", "command": "cppcheck", "args": ["--error-exitcode=1", "--template=gcc", "$FILE"], "parser": "gcc", "_auto": true }
Shell scripts:
// shellcheck (with gcc output format for line numbers)
{ "name": "shellcheck", "command": "shellcheck", "args": ["--format=gcc", "$FILE"], "parser": "gcc", "_auto": true }
// shfmt (format check)
{ "name": "shfmt", "command": "shfmt", "args": ["-d", "$FILE"], "parser": "prettier", "_auto": true }
Full example (Python + uv):
{
"environments": [
{
"name": "root",
"paths": ["."],
"exclude": ["__pycache__/**", ".pytest_cache/**", ".venv/**"],
"checks": {
".py": [
{ "name": "ruff format", "command": "uv", "args": ["run", "ruff", "format", "--check", "$FILE"], "parser": "prettier", "_auto": true },
{ "name": "ruff check", "command": "uv", "args": ["run", "ruff", "check", "$FILE"], "parser": "ruff", "_auto": true },
{ "name": "ty", "command": "uv", "args": ["run", "ty", "check", "$FILE"], "parser": "ty", "_auto": true }
]
}
}
]
}
Full example (TypeScript + npm):
{
"environments": [
{
"name": "root",
"paths": ["."],
"exclude": ["dist/**", "build/**", "coverage/**"],
"checks": {
".ts,.tsx": [
{ "name": "prettier", "command": "npx", "args": ["prettier", "--check", "$FILE"], "parser": "prettier", "_auto": true },
{ "name": "eslint", "command": "npx", "args": ["eslint", "$FILE"], "parser": "eslint", "_auto": true },
{ "name": "tsc-files", "command": "npx", "args": ["tsc-files", "--noEmit", "$FILE"], "parser": "tsc", "_auto": true }
],
".json,.md": [
{ "name": "prettier", "command": "npx", "args": ["prettier", "--check", "$FILE"], "parser": "prettier", "_auto": true }
]
}
}
]
}
Note: For TypeScript type checking, use tsc-files (checks single files) instead of tsc (checks entire project). Alternatively, configure eslint with @typescript-eslint for type-aware linting.
Full example (C++ with CMake):
{
"environments": [
{
"name": "root",
"paths": ["."],
"exclude": ["build/**", "cmake-build-*/**", "third_party/**"],
"checks": {
".cpp,.cc,.c,.h,.hpp": [
{ "name": "clang-format", "command": "/opt/homebrew/opt/llvm/bin/clang-format", "args": ["--dry-run", "-Werror", "$FILE"], "parser": "gcc", "_auto": true }
],
".sh": [
{ "name": "shellcheck", "command": "shellcheck", "args": ["--format=gcc", "$FILE"], "parser": "gcc", "_auto": true },
{ "name": "shfmt", "command": "shfmt", "args": ["-d", "$FILE"], "parser": "prettier", "_auto": true }
]
}
}
]
}
Note: For C++ projects, use full paths for Homebrew-installed LLVM tools on macOS. The --dry-run -Werror flags make clang-format exit non-zero on formatting issues without modifying files.
Step 5: Gather User Preferences
Before presenting the configuration, use the AskUserQuestion tool to gather preferences. Ask all questions in a single call.
Question 1 — Test files:
- header: "Test files"
- question: "Should test files be included or excluded from checks?"
- options:
- "Exclude" — Add exclude patterns for test directories (tests/**, **/.test., **/.spec.)
- "Include" — Run all checks on test files too
- multiSelect: false
Question 2 — Additional checks:
- header: "Custom checks"
- question: "Any custom scripts or project-specific checks to add?"
- options:
- "None" — Only use discovered tools
- "Yes, I'll describe" — Pause for user to describe custom checks
- multiSelect: false
Question 3 — Coverage gaps:
- header: "Missing tools"
- question: "Any tools or file types I missed?"
- options:
- "Looks complete" — Proceed with discovered tools
- "Yes, I'll describe" — Pause for user to list additions
- multiSelect: false
Apply the answers to the proposed configuration before presenting it.
Decision guidance:
- biome vs prettier+eslint: biome is faster but less configurable. Use prettier+eslint for existing configs.
- maxDiagnostics: 5 is good default. Increase to 10 for strict projects. Set to 1 for slow tools.
- Check order: Format checks first, then lint, then type check (fastest to slowest).
- Related file types: Formatters like prettier handle more than code. Recommend adding checks for:
.json- package.json, tsconfig.json, config files.md- README, documentation.yaml,.yml- CI configs, docker-compose.css,.scss- stylesheets.html- templates
For unfamiliar tools, offer to use the checkmate:configure-tool subagent to analyze output and build a parser.
Step 6: Present and Confirm
Show the user:
- What file types were detected
- What tools were found
- The proposed configuration (incorporating answers from Step 5)
Use AskUserQuestion to confirm:
- header: "Config"
- question: "Write this configuration to .claude/checkmate.json?"
- options:
- "Yes, write it" — Proceed to write
- "Show me first" — Display full JSON before writing
- "Make changes" — User describes modifications
- multiSelect: false
Step 7: Write Configuration
After user confirmation, create .claude/checkmate.json with the agreed configuration.
Ensure the .claude/ directory exists:
mkdir -p .claude
Then write the configuration file. The validation hook runs automatically and flags any schema errors.
Step 8: Test Configuration
After writing, test with a sample file:
# Find a sample file and run its checks manually
find . -name "*.py" -o -name "*.ts" | head -1
Run one of the configured commands manually to verify it works.
Inform the user that the checkmate hook runs automatically on file edits. Suggest running /checkmate:checkmate-refresh periodically to keep the config up to date.
Notes
- The
$FILEplaceholder in args gets replaced with the actual file path - Comma-separated extensions (e.g.,
.ts,.tsx) apply the same checks to multiple types - The
parserfield determines how output is parsed into diagnostics - Use
genericparser for tools without a specific parser maxDiagnosticslimits output per check (default: 5)- Task reviewers are not auto-discovered; add
tasksarray manually to trigger code review agents after Task completions (see README)
From the file to a first result
The download contains exactly the content displayed on this page. This copy may differ from the latest version in the source repository.
View the source and supporting filesThis download contains SKILL.md only. Any scripts, references, templates and dependencies are not included. Get the required files from the source, preserving their directory structure, before continuing.
1. Download the file
Download SKILL.mdFrom the root of a test project, save the file as .skill-downloads/checkmate-initialization-mmio71f5/SKILL.md, or use the command below. This folder is for inspecting the skill before installation.
Command for macOS/Linux or WSL: requires a POSIX shell and curl. On Windows without WSL, use the download button and create the folder manually.
mkdir -p '.skill-downloads/checkmate-initialization-mmio71f5' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/checkmate-initialization-mmio71f5/download' --output '.skill-downloads/checkmate-initialization-mmio71f5/SKILL.md.part' && mv '.skill-downloads/checkmate-initialization-mmio71f5/SKILL.md.part' '.skill-downloads/checkmate-initialization-mmio71f5/SKILL.md'2. Check prerequisites
Read SKILL.md before using it. If it references scripts or external services, inspect them and prepare the required access in your test environment.
No recognized prerequisites section in this file. This does not mean it is self-contained: libraries, tools and access requirements may be mentioned elsewhere in the content or source repository.
The platforms on this page are catalog indications. The paths below follow tool documentation; they do not prove this skill has been run in those tools. No minimum tool version is confirmed for this listing.
3. Load the skill
After inspection, copy the complete folder into your project using one of the commands below, then open a new tool session. The command stops if a folder with the same name already exists: compare the files before replacing it.
Claude Code
test -f '.skill-downloads/checkmate-initialization-mmio71f5/SKILL.md' && test -s '.skill-downloads/checkmate-initialization-mmio71f5/SKILL.md' && mkdir -p '.claude/skills' && test ! -e '.claude/skills/checkmate-init' && cp -R '.skill-downloads/checkmate-initialization-mmio71f5' '.claude/skills/checkmate-init'OpenSkills
OpenSkills must already be installed. The local install/read procedure is checked with OpenSkills 1.5.0, which requires Node.js ≥ 20.6.0. Catalog slugs are not resolved automatically.
Official OpenSkills installationopenskills install './.skill-downloads/checkmate-initialization-mmio71f5'openskills read 'checkmate-initialization-mmio71f5'Reading should display the installed file content and its base directory. It does not run the skill or install its dependencies.
For an agent that reads AGENTS.md, then sync the index. This command changes AGENTS.md: review the diff before using it.
openskills syncManual method or another tool: attach SKILL.md to a conversation, or open it in an agent that can read files. Include any required supporting resources. No universal folder is recognized by every tool.
4. Try a first task
Use a short, synthetic input: an API endpoint, a small document or an interface brief. In a new conversation, attach the file or give the agent its path, then adapt this request:
Read .skill-downloads/checkmate-initialization-mmio71f5/SKILL.md and apply its instructions to this example: [describe a test input]. Identify any missing files, dependencies or access. Produce the result requested by the skill without inventing data or running unreviewed scripts.Expected result: output matching the skill instructions, or a precise list of missing prerequisites. A read confirmation alone does not validate a first use. If an external resource is unavailable, that path remains untested.
React Hook Form Best Practices
Development
Master React Hook Form: avoid anti-patterns, manage subscriptions, and handle reset, dirty state, and controlled inputs correctly.
Emotion to Mantine Migration
Development
Migrate Emotion styled-components to Mantine components with style props and CSS modules. Use when converting .styled.tsx files or removing @emotion imports.
Scope Creep Detector
Development
Analyzes git diffs against a stated intent to detect scope creep, unrelated files, broad PRs, and oversized changes, then suggests keep, split, or justify actions.