# Skill Lab API & CLI Reference
> Generated from MDX sources at build time. The rendered page at https://skill-lab.dev/docs and this markdown share the same content — edits to the MDX update both.
Base URL: `https://api.skill-lab.dev`
Hosted docs: https://skill-lab.dev/docs
Machine-readable index: https://skill-lab.dev/llms.txt
---
## Overview
### Introduction
v1
REST / JSON
API Reference
// api.skill-lab.dev
Programmatically scan GitHub repositories for SKILL.md files
and evaluate them against 37 quality and security checks. Returns structured
JSON with scores, pass/fail results, and fix suggestions.
```text
https://api.skill-lab.dev
```
#### Quick Example
```bash
curl https://api.skill-lab.dev/v1/repos/anthropics/claude-code/evaluate
```
> Prefer running locally?
> [Install the sklab CLI](/docs/cli/cli-install)
> to run the same checks and LLM judge against a skill directory on your
> machine — no repo push required.
### Errors
All error responses return a JSON object with a `detail` field containing the error message.
error response format:
```json
{
"detail": "Not found: owner/repo. Check the URL and make sure the repository is public."
}
```
#### Status Codes
| Status | Meaning | When |
| ------ | ------------ | --------------------------------------------------------------------------------- |
| 400 | Bad Request | Malformed JSON body or validation failure |
| 404 | Not Found | Repository or skill path does not exist, or the repository is private |
| 429 | Rate Limited | Per-IP rate limit exceeded, or GitHub API rate limit exhausted on the server side |
| 502 | Bad Gateway | Upstream service error (LLM endpoints) |
Validation errors return detail as either a string or an array
of Pydantic validation error objects.
### Rate Limits
Requests are rate-limited per IP address. Limits vary by endpoint type:
| Endpoint | Rate Limit |
| -------------------------------------------- | ------------------ |
| Scan endpoints (/evaluate, /info, /export) | 30 requests/minute |
| LLM endpoints (/optimize, /triggers, /judge) | 5 requests/minute |
| Other endpoints | 60 requests/minute |
The API also fetches repository data through the GitHub REST API v3. GitHub's
own rate limits apply on the server side:
| Server Config | GitHub Rate Limit |
| --------------- | ------------------- |
| No GitHub token | 60 requests/hour |
| With token | 5,000 requests/hour |
#### Caching
Evaluation results are cached on the server, keyed by `owner/repo/commit_sha` (and `path` for single-skill requests).
- If the repository's HEAD has not changed, the cached result is returned instantly
- Cache TTL is 1 hour — after expiry, the next request triggers a fresh evaluation
- Full-repo and single-skill results are cached independently
## API
### Evaluate
**GET** `/v1/repos/{owner}/{repo}/evaluate`
Evaluate skills in a GitHub repository. Omit `path` to scan the entire repo and evaluate every SKILL.md found. Provide `path` to evaluate a single skill at that location.
#### Path Parameters
| Parameter | Type | Description |
| --------- | ------ | ------------------------------- |
| owner | string | GitHub username or organization |
| repo | string | Repository name |
#### Query Parameters
| Parameter | Type | Description |
| --------- | ------ | ---------------------------------------------------------------------------- |
| path | string | Optional. Path to a specific skill — omit to evaluate all skills in the repo |
> GitHub URL segments are stripped automatically.
> You can paste paths directly from GitHub's UI — segments like `tree/main/` or `blob/main/` are removed before lookup. Both `skills/my-skill` and `skills/my-skill/SKILL.md` work.
> Results are cached by commit SHA for 1 hour. If the repo's HEAD hasn't changed, the response is served from cache.
#### Response
The response shape depends on whether `path` is provided.
- **Without `path`** — returns a [ScanResult](#scanresult) object with a `skills` array containing one [SkillResult](#skillresult) per SKILL.md found (up to 50).
- **With `path`** — returns a [SkillEvaluateResult](#skillevaluateresult) object: the skill's fields flattened at the top level alongside `owner`, `repo`, `commit_sha`, and `scanned_at`. No `skills` array, no `truncated` field.
#### Response Schemas
##### ScanResult
\\See also the `ScanResult` field reference below.
| Field | Type | Description |
| ----------- | -------------------------------- | ---------------------------------------------------------------------------- |
| owner | string | GitHub username or organization |
| repo | string | Repository name |
| commit\_sha | string | Full SHA of the commit that was scanned |
| skills | \[SkillResult\[]]\(#skillresult) | Array of evaluated skills found in the repository |
| scanned\_at | string | ISO 8601 timestamp of when the scan was performed |
| error | string \| null | Top-level error message if the scan itself failed, otherwise null |
| truncated | boolean | True if the repository contained more than 50 skills and results were capped |
**Example:**
```json
{
"owner": "anthropics",
"repo": "claude-code",
"commit_sha": "a04e4f9...",
"skills": [
{
"path": "skills/git-commit/SKILL.md",
"name": "git-commit",
"quality_score": 85.0,
"overall_pass": true,
"checks_run": 37,
"checks_passed": 30,
"checks_failed": 3,
"results": [...]
}
],
"scanned_at": "2025-03-24T12:00:00+00:00",
"error": null,
"truncated": false
}
```
##### SkillEvaluateResult
\\See also the `SkillEvaluateResult` field reference below.
| Field | Type | Description |
| -------------- | -------------------------------- | ------------------------------------------------------------- |
| owner | string | GitHub username or organization |
| repo | string | Repository name |
| commit\_sha | string | Full SHA of the commit that was evaluated |
| scanned\_at | string | ISO 8601 timestamp of when the evaluation was performed |
| path | string | Path to the SKILL.md file within the repository |
| name | string \| null | Skill name extracted from frontmatter |
| description | string \| null | Skill description extracted from frontmatter |
| quality\_score | number | Overall quality score from 0 to 100 |
| overall\_pass | boolean | Whether all high-severity checks passed |
| checks\_run | number | Total number of checks executed |
| checks\_passed | number | Number of checks that passed |
| checks\_failed | number | Number of checks that failed |
| results | \[CheckResult\[]]\(#checkresult) | Detailed results for each individual check |
| summary | object | Aggregated pass/fail counts grouped by severity and dimension |
| error | string \| null | Error message if the skill failed to evaluate, otherwise null |
**Example:**
```json
{
"owner": "anthropics",
"repo": "claude-code",
"commit_sha": "a04e4f9...",
"scanned_at": "2025-03-24T12:00:00+00:00",
"path": "skills/git-commit/SKILL.md",
"name": "git-commit",
"description": "Write conventional commit messages",
"quality_score": 85.0,
"overall_pass": true,
"checks_run": 37,
"checks_passed": 30,
"checks_failed": 3,
"results": [...],
"summary": {...},
"error": null
}
```
##### SkillResult
\\See also the `SkillResult` field reference below.
| Field | Type | Description |
| -------------- | -------------------------------- | -------------------------------------------------------------- |
| path | string | Path to the SKILL.md file within the repository |
| name | string \| null | Skill name extracted from frontmatter |
| description | string \| null | Skill description extracted from frontmatter |
| quality\_score | number | Overall quality score from 0 to 100 |
| overall\_pass | boolean | Whether all high-severity checks passed |
| checks\_run | number | Total number of checks executed |
| checks\_passed | number | Number of checks that passed |
| checks\_failed | number | Number of checks that failed |
| results | \[CheckResult\[]]\(#checkresult) | Detailed results for each individual check |
| summary | object | Aggregated pass/fail counts grouped by severity and dimension |
| error | string \| null | Error message if this skill failed to evaluate, otherwise null |
**Example:**
```json
{
"by_severity": {
"high": { "passed": 5, "failed": 0 },
"medium": { "passed": 12, "failed": 2 },
"low": { "passed": 13, "failed": 1 }
},
"by_dimension": {
"structure": { "passed": 10, "failed": 1 },
"naming": { "passed": 3, "failed": 0 },
"description": { "passed": 2, "failed": 1 },
"content": { "passed": 10, "failed": 1 },
"security": { "passed": 5, "failed": 0 }
}
}
```
##### CheckResult
\\See also the `CheckResult` field reference below.
| Field | Type | Description |
| ----------- | --------------------------- | --------------------------------------------------------------------------------- |
| check\_id | string | Unique identifier for the check |
| check\_name | string | Human-readable check name |
| passed | boolean | Whether this check passed |
| severity | "high" \| "medium" \| "low" | Severity level of the check |
| dimension | string | Quality dimension: "structure", "naming", "description", "content", or "security" |
| message | string | Human-readable result message |
| fix | string? | Suggested fix when the check fails |
| details | object? | Additional check-specific data |
| location | string? | File location relevant to the check |
**Example:**
```json
{
"check_id": "naming_format",
"check_name": "Name Format",
"passed": false,
"severity": "high",
"dimension": "naming",
"message": "Skill name 'MySkill' is not in kebab-case",
"fix": "Rename to 'my-skill'"
}
```
#### Errors
| Status | Cause |
| ------ | ---------------------------------- |
| 404 | Repository or skill path not found |
| 429 | GitHub API rate limit reached |
#### Examples
Whole repo:
```bash
curl "https://api.skill-lab.dev/v1/repos/anthropics/claude-code/evaluate"
```
```javascript
const res = await fetch("https://api.skill-lab.dev/v1/repos/anthropics/claude-code/evaluate");
const data = await res.json();
// data.skills[0].quality_score
```
```python
import httpx
res = httpx.get("https://api.skill-lab.dev/v1/repos/anthropics/claude-code/evaluate")
data = res.json()
# data['skills'][0]['quality_score']
```
Single skill:
```bash
curl "https://api.skill-lab.dev/v1/repos/owner/repo/evaluate?path=my-skill"
```
```javascript
const res = await fetch("https://api.skill-lab.dev/v1/repos/owner/repo/evaluate?path=my-skill");
const data = await res.json();
// data.quality_score
```
```python
import httpx
res = httpx.get("https://api.skill-lab.dev/v1/repos/owner/repo/evaluate?path=my-skill")
data = res.json()
# data['quality_score']
```
GitHub-style path (auto-stripped):
```bash
# tree/main/ is stripped automatically
curl "https://api.skill-lab.dev/v1/repos/owner/repo/evaluate?path=tree/main/skills/my-skill"
```
### Check Registry
**GET** `/v1/checks`
Returns the full catalog of static checks that skill-lab runs during evaluation. Each check includes its dimension, severity, and whether it is required by the Agent Skills spec.
#### Response
Returns an object with a `checks` array and a `count` integer. Each check has: `check_id`, `check_name`, `dimension`, `severity`, `spec_required`, `description`, and `fix`.
#### Example
```bash
curl https://api.skill-lab.dev/v1/checks
```
### Skill Info
**GET** `/v1/repos/{owner}/{repo}/info`
Returns parsed metadata and token estimates without running the full evaluation. Omit `path` to get info for every SKILL.md in the repo. Provide `path` to get info for a single skill. Lighter weight than evaluate — useful for discovery and cataloging.
#### Path Parameters
| Parameter | Type | Description |
| --------- | ------ | ------------------------------- |
| owner | string | GitHub username or organization |
| repo | string | Repository name |
#### Query Parameters
| Parameter | Type | Description |
| --------- | ------ | ---------------------------------------------------------------------------- |
| path | string | Optional. Path to a specific skill — omit to evaluate all skills in the repo |
#### Response
The response shape depends on whether `path` is provided.
- **Without `path`** — returns an object with `owner`, `repo`, `commit_sha`, a `skills` array of info objects (up to 50), and `truncated`.
- **With `path`** — returns a single info object with `name`, `description`, `raw_frontmatter`, `body_preview` (first 500 chars), `has_scripts`, `has_references`, `has_assets`, `estimated_tokens`, and `parse_errors`.
example response:
```json
{
"owner": "anthropics",
"repo": "claude-code",
"path": "skills/git-commit/SKILL.md",
"name": "git-commit",
"description": "Write conventional commit messages",
"raw_frontmatter": { "name": "git-commit", ... },
"body_preview": "# Git Commit\nGenerate conventional ...",
"has_scripts": false,
"has_references": true,
"has_assets": false,
"estimated_tokens": 1240,
"parse_errors": []
}
```
#### Errors
| Status | Cause |
| ------ | ---------------------------------- |
| 404 | Repository or skill path not found |
| 429 | GitHub API rate limit reached |
#### Examples
Single skill:
```bash
curl "https://api.skill-lab.dev/v1/repos/owner/repo/info?path=my-skill"
```
```javascript
const res = await fetch("https://api.skill-lab.dev/v1/repos/owner/repo/info?path=my-skill");
const data = await res.json();
// data.estimated_tokens
```
```python
import httpx
res = httpx.get("https://api.skill-lab.dev/v1/repos/owner/repo/info?path=my-skill")
data = res.json()
# data['estimated_tokens']
```
Whole repo:
```bash
curl "https://api.skill-lab.dev/v1/repos/anthropics/claude-code/info"
```
### Export
**GET** `/v1/repos/{owner}/{repo}/export`
Renders all skills in a repository as agent-platform-ready prompt snippets in XML, Markdown, or JSON format.
#### Path Parameters
| Parameter | Type | Description |
| --------- | ------ | ------------------------------- |
| owner | string | GitHub username or organization |
| repo | string | Repository name |
#### Query Parameters
| Parameter | Type | Description |
| --------- | ----------------------------- | ------------------------------ |
| format | "xml" \| "markdown" \| "json" | Output format (default: `xml`) |
#### Response
Returns an object with `owner`, `repo`, `format`, `skill_count`, and `content` (the rendered string).
example response:
```json
{
"owner": "anthropics",
"repo": "claude-code",
"format": "xml",
"skill_count": 3,
"content": "\n ...\n"
}
```
#### Errors
| Status | Cause |
| ------ | ---------------------------------- |
| 404 | Repository or skill path not found |
| 429 | GitHub API rate limit reached |
#### Example
```bash
curl "https://api.skill-lab.dev/v1/repos/owner/repo/export?format=xml"
```
```javascript
const res = await fetch("https://api.skill-lab.dev/v1/repos/owner/repo/export?format=xml");
const data = await res.json();
// data.content
```
```python
import httpx
res = httpx.get("https://api.skill-lab.dev/v1/repos/owner/repo/export?format=xml")
data = res.json()
# data['content']
```
### Optimize
**POST** `/v1/repos/{owner}/{repo}/optimize`
Runs LLM-powered optimization on a SKILL.md file. Returns the original and optimized content with before/after quality scores. Rate limited to 5 requests per minute.
#### Path Parameters
| Parameter | Type | Description |
| --------- | ------ | ------------------------------- |
| owner | string | GitHub username or organization |
| repo | string | Repository name |
#### Query Parameters
| Parameter | Type | Description |
| --------- | ------ | -------------------------------------------- |
| path | string | Path to the skill directory or SKILL.md file |
#### Request Body
Optional JSON body:
| Field | Type | Description |
| ----- | ------- | ----------------------------------------------- |
| model | string? | LLM model override (default: server-configured) |
#### Response
Returns `original_content`, `optimized_content`, `original_score`, `optimized_score`, `original_failures`, `optimized_failures`, and `usage` (token counts).
example response:
```json
{
"owner": "owner",
"repo": "repo",
"path": "skills/my-skill/SKILL.md",
"original_content": "---\nname: my-skill\n---\n...",
"optimized_content": "---\nname: my-skill\n---\n...",
"original_score": 72.5,
"optimized_score": 95.0,
"original_failures": 5,
"optimized_failures": 1,
"usage": { "model": "claude-haiku-4-5-20251001", "input_tokens": 2100, "output_tokens": 1800 }
}
```
> This endpoint calls an LLM and may take 10-30 seconds to respond.
> Results are cached per commit SHA and model — repeated requests for the same
> skill on the same commit return the cached response.
#### Errors
| Status | Cause |
| ------ | ---------------------------------------- |
| 404 | Repository or skill path not found |
| 422 | LLM generation failed |
| 429 | Rate limit exceeded |
| 503 | Service not configured (missing API key) |
| 504 | Operation timed out |
#### Example
```bash
curl -X POST "https://api.skill-lab.dev/v1/repos/owner/repo/optimize?path=my-skill"
```
```javascript
const res = await fetch("https://api.skill-lab.dev/v1/repos/owner/repo/optimize?path=my-skill", { method: "POST" });
const data = await res.json();
// data.optimized_score
```
```python
import httpx
res = httpx.post("https://api.skill-lab.dev/v1/repos/owner/repo/optimize?path=my-skill")
data = res.json()
# data['optimized_score']
```
### Triggers
**POST** `/v1/repos/{owner}/{repo}/triggers`
Generates trigger test YAML for a SKILL.md file using an LLM. The generated tests cover explicit, implicit, contextual, and negative trigger types. Rate limited to 5 requests per minute.
#### Path Parameters
| Parameter | Type | Description |
| --------- | ------ | ------------------------------- |
| owner | string | GitHub username or organization |
| repo | string | Repository name |
#### Query Parameters
| Parameter | Type | Description |
| --------- | ------ | -------------------------------------------- |
| path | string | Path to the skill directory or SKILL.md file |
#### Request Body
Optional JSON body:
| Field | Type | Description |
| ----- | ------- | ----------------------------------------------- |
| model | string? | LLM model override (default: server-configured) |
#### Response
Returns `skill_name`, `triggers_yaml` (the generated YAML string), `test_count`, and `usage` (token counts).
example response:
```json
{
"owner": "owner",
"repo": "repo",
"path": "skills/my-skill/SKILL.md",
"skill_name": "my-skill",
"triggers_yaml": "triggers:\n - type: explicit\n prompt: ...",
"test_count": 12,
"usage": { "model": "claude-haiku-4-5-20251001", "input_tokens": 3200, "output_tokens": 900 }
}
```
> This endpoint calls an LLM and may take 10-30 seconds to respond.
> Results are cached per commit SHA and model — repeated requests for the same
> skill on the same commit return the cached response.
#### Errors
| Status | Cause |
| ------ | ---------------------------------------- |
| 404 | Repository or skill path not found |
| 422 | LLM generation failed |
| 429 | Rate limit exceeded |
| 503 | Service not configured (missing API key) |
| 504 | Operation timed out |
#### Example
```bash
curl -X POST "https://api.skill-lab.dev/v1/repos/owner/repo/triggers?path=my-skill"
```
```javascript
const res = await fetch("https://api.skill-lab.dev/v1/repos/owner/repo/triggers?path=my-skill", { method: "POST" });
const data = await res.json();
// data.triggers_yaml
```
```python
import httpx
res = httpx.post("https://api.skill-lab.dev/v1/repos/owner/repo/triggers?path=my-skill")
data = res.json()
# data['triggers_yaml']
```
### Judge
**POST** `/v1/repos/{owner}/{repo}/judge`
Runs an LLM-as-judge quality review on a SKILL.md file. Scores the skill across 9 criteria on two axes: Activation Quality and Instruction Quality. Returns per-criterion scores (0-4), axis scores, an overall judge score (0-100), a verdict band, and improvement suggestions. Rate limited to 5 requests per minute.
#### Path Parameters
| Parameter | Type | Description |
| --------- | ------ | ------------------------------- |
| owner | string | GitHub username or organization |
| repo | string | Repository name |
#### Query Parameters
| Parameter | Type | Description |
| --------- | ------ | -------------------------------------------- |
| path | string | Path to the skill directory or SKILL.md file |
#### Request Body
Optional JSON body:
| Field | Type | Description |
| ----- | ------- | ---------------------------------------------------------- |
| model | string? | LLM model override — supports claude-\*, gpt-\*, gemini-\* |
#### Response
Returns `criteria` (array of 9 objects with `id`, `name`, `axis`, `score`, `reasoning`), `activation_score`, `instruction_score`, `judge_score` (0-100), `verdict` (Poor/Fair/Good/Very Good/Excellent), `suggestions`, and `usage`.
example response:
```json
{
"owner": "owner",
"repo": "repo",
"path": "skills/my-skill/SKILL.md",
"criteria": [
{ "id": "trigger_clarity", "name": "Trigger Clarity", "axis": "activation", "score": 3, "reasoning": "..." }
],
"activation_score": 75.0,
"instruction_score": 80.0,
"judge_score": 77.8,
"verdict": "Good",
"suggestions": ["Add explicit trigger examples", "..."],
"usage": { "model": "claude-haiku-4-5-20251001", "input_tokens": 2900, "output_tokens": 1100 }
}
```
> This endpoint calls an LLM and may take 10-30 seconds to respond.
> Multi-provider: pass a `claude-*`, `gpt-*`, or `gemini-*` model ID
> to use different providers.
#### Errors
| Status | Cause |
| ------ | ---------------------------------------- |
| 404 | Repository or skill path not found |
| 422 | LLM generation failed |
| 429 | Rate limit exceeded |
| 503 | Service not configured (missing API key) |
| 504 | Operation timed out |
#### Example
```bash
curl -X POST "https://api.skill-lab.dev/v1/repos/owner/repo/judge?path=my-skill"
```
```javascript
const res = await fetch("https://api.skill-lab.dev/v1/repos/owner/repo/judge?path=my-skill", { method: "POST" });
const data = await res.json();
// data.judge_score
```
```python
import httpx
res = httpx.post("https://api.skill-lab.dev/v1/repos/owner/repo/judge?path=my-skill")
data = res.json()
# data['judge_score']
```
### Health
**GET** `/health`
Returns server status. Use this to verify the API is running and reachable.
#### Response
200 OK:
```json
{
"status": "ok"
}
```
#### Example
```bash
curl https://api.skill-lab.dev/health
```
## CLI
### Installation
`sklab` is the CLI that ships with the [skill-lab](https://pypi.org/project/skill-lab/) PyPI package. It runs the same static checks and LLM judge as the hosted API — but locally, against a skill directory on your machine. Python 3.10 or newer is required.
#### Install
```bash
$ pip install skill-lab
```
Or with uv:
```bash
$ uv pip install skill-lab
```
#### Verify
```bash
$ sklab --version
```
Running `sklab` on its own scans the current directory for SKILL.md
files and prints a getting-started guide.
#### API Keys
Static commands (`check`, `scan`, `info`, `list-checks`) run without any credentials. LLM-powered commands — `evaluate` (judge step), `generate`, `trigger`, and `optimize` — need an API key:
| Provider | Env var | Model prefix |
| --------- | ------------------- | ------------ |
| Anthropic | `ANTHROPIC_API_KEY` | `claude-*` |
| OpenAI | `OPENAI_API_KEY` | `gpt-*` |
| Google | `GEMINI_API_KEY` | `gemini-*` |
Provider is auto-detected from the model prefix passed to `--model`. Keys are
read from the environment, a `.env` file in the current directory, or any
standard shell-profile setup. The default model is
`claude-haiku-4-5-20251001` (Anthropic).
#### Trigger Testing Prerequisite
`sklab trigger` drives a live LLM runtime through the Claude CLI:
```bash
$ npm install -g @anthropic-ai/claude-code
```
### Quickstart
From a fresh install to a scored skill in three commands.
##### 1. Install and scan
```bash
$ pip install skill-lab
$ cd path/to/your-skills
$ sklab
```
Running `sklab` on its own discovers every SKILL.md under the current
directory and prints the getting-started guide.
##### 2. Evaluate a skill
```bash
$ export ANTHROPIC_API_KEY=sk-ant-...
$ sklab evaluate ./my-skill
```
Runs 37 static checks plus a 9-criteria LLM judge. Pass `--skip-review`
to skip the LLM step if you do not have a key.
##### 3. Gate CI
```yaml
# .github/workflows/skills.yml
- run: pip install skill-lab
- run: sklab check --repo
```
`sklab check` exits 1 on any high-severity failure, so it drops straight
into a pre-merge job.
#### Next steps
### sklab evaluate
Static checks plus LLM quality review with 0–100 scoring.
> **Also available over HTTP.** The [Evaluate Skills endpoint](/docs/endpoints/evaluate) runs the same logic on the server against a GitHub repository — useful when you want results in a browser, a CI job without installing Python, or an agent that reaches skill-lab.dev directly.
```bash
sklab evaluate [SKILL_PATH] [OPTIONS]
```
Runs 37 static checks across Structure, Naming, Description, Content, and Security, then sends the skill to an LLM judge that scores it on 9 criteria across Activation and Instruction axes. Use --skip-review for a static-only run, or --format json to emit the same payload shape as the /v1/evaluate endpoint.
#### Arguments
| Argument | Required | Description |
| ----------- | -------- | --------------------------------------------------------------- |
| SKILL\_PATH | no | Path to the skill directory. Defaults to the current directory. |
#### Options
| Flag | Value | Description |
| --------------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| --output, -o | \ | Write the report to a file (implies --format json if --format is not set). |
| --format, -f | json\|console (default: `console`) | Output format. |
| --verbose, -V | flag | Show all checks (including passing ones) and LLM reasoning. |
| --spec-only, -s | flag | Run only the checks required by the Agent Skills spec. |
| --all, -a | flag | Discover and evaluate every skill under the current directory. |
| --repo | flag | Discover and evaluate every skill from the git repo root. |
| --skip-review | flag | Skip the LLM judge (static checks only). |
| --model, -m | \ (default: `claude-haiku-4-5-20251001`) | Model for the LLM judge. Supports Anthropic, OpenAI (gpt-\*), and Gemini (gemini-\*) models — provider auto-detected from the prefix. |
| --optimize | flag | Automatically chain into sklab optimize after evaluation (no interactive prompt). |
#### Examples
Evaluate one skill
```bash
sklab evaluate ./my-skill
```
JSON report to disk
```bash
sklab evaluate ./my-skill -f json -o report.json
```
Static checks only (no API key)
```bash
sklab evaluate ./my-skill --skip-review
```
Every skill in the current repo
```bash
sklab evaluate --repo
```
Evaluate then optimize in one step
```bash
sklab evaluate ./my-skill --optimize
```
#### Output
Console rendering groups checks by dimension with pass/fail status and the LLM judge's per-criterion scores. With --format json, the output matches the /v1/repos/{owner}/{repo}/evaluate response payload.
#### Exit Codes
| Code | Meaning |
| ---- | --------------------------------------------------- |
| 0 | All high-severity checks passed. |
| 1 | One or more checks failed, or a CLI error occurred. |
#### Notes
- LLM review requires ANTHROPIC\_API\_KEY, OPENAI\_API\_KEY, or GEMINI\_API\_KEY. The env var is selected from the model prefix.
- \--all and --repo are mutually exclusive, and cannot be combined with a positional SKILL\_PATH.
### sklab check
Quick pass/fail check — exits 0 or 1, designed for CI pipelines.
```bash
sklab check [SKILL_PATH] [OPTIONS]
```
Runs the same static checks as evaluate, skips the LLM step, and prints only high-severity failures. The non-zero exit code on failure makes it a drop-in gate for pre-commit hooks and CI jobs.
#### Arguments
| Argument | Required | Description |
| ----------- | -------- | --------------------------------------------------------------- |
| SKILL\_PATH | no | Path to the skill directory. Defaults to the current directory. |
#### Options
| Flag | Value | Description |
| --------------- | ----- | ----------------------------------------------------------------------- |
| --spec-only, -s | flag | Validate only against the Agent Skills spec (skip quality suggestions). |
| --all, -a | flag | Check every skill under the current directory. |
| --repo | flag | Check every skill from the git repo root. |
#### Examples
CI gate
```bash
sklab check ./my-skill
```
Pre-commit (all skills)
```bash
sklab check --all
```
Spec-only in CI
```bash
sklab check --repo --spec-only
```
#### Exit Codes
| Code | Meaning |
| ---- | --------------------------------------------------- |
| 0 | All checks passed. |
| 1 | One or more checks failed, or a CLI error occurred. |
### sklab scan
Security-focused scan with BLOCK / SUS / ALLOW status per skill.
```bash
sklab scan [SKILL_PATH] [OPTIONS]
```
Runs the 5 security checks — prompt injection, evaluator manipulation, unicode obfuscation, YAML anomalies, and suspicious size/structure — and classifies each skill as BLOCK, SUS, or ALLOW. BLOCK triggers a non-zero exit so you can wire it into pre-merge checks.
#### Arguments
| Argument | Required | Description |
| ----------- | -------- | --------------------------------------------------------------- |
| SKILL\_PATH | no | Path to the skill directory. Defaults to the current directory. |
#### Options
| Flag | Value | Description |
| ------------- | ----- | ------------------------------------------------------------------- |
| --all, -a | flag | Scan every skill under the current directory. |
| --verbose, -v | flag | Show findings for SUS skills in addition to BLOCK (bulk mode only). |
#### Examples
Scan one skill
```bash
sklab scan ./my-skill
```
Audit every skill
```bash
sklab scan --all
```
#### Output
Per-skill status: BLOCK on injection / jailbreak / unicode / YAML / evaluator findings; SUS on size or structure anomalies only; ALLOW if no findings.
#### Exit Codes
| Code | Meaning |
| ---- | ------------------------------------ |
| 0 | ALLOW or SUS only. |
| 1 | One or more skills classified BLOCK. |
### sklab info
Skill metadata and token cost estimates (discovery / activation / on-demand).
> **Also available over HTTP.** The [Skill Info endpoint](/docs/endpoints/skill-info) runs the same logic on the server against a GitHub repository — useful when you want results in a browser, a CI job without installing Python, or an agent that reaches skill-lab.dev directly.
```bash
sklab info [SKILL_PATH] [OPTIONS]
```
Shows the parsed frontmatter fields and three token-cost estimates: discovery (name + description — the cost to keep the skill loaded), activation (full SKILL.md body), and on-demand (references / assets / scripts). Useful for catalog pages and budget planning — no LLM call, no API key required.
#### Arguments
| Argument | Required | Description |
| ----------- | -------- | --------------------------------------------------------------- |
| SKILL\_PATH | no | Path to the skill directory. Defaults to the current directory. |
#### Options
| Flag | Value | Description |
| ----------- | ------- | --------------------------------------------------------------- |
| --json | flag | Emit structured JSON (pipe-friendly). |
| --field, -f | \ | Extract a single field by dotted path (e.g. tokens.activation). |
#### Examples
Human-readable
```bash
sklab info ./my-skill
```
Pipe to jq
```bash
sklab info ./my-skill --json | jq .tokens
```
Single field
```bash
sklab info ./my-skill -f tokens.activation
```
### sklab prompt
Export one or more skills as a prompt snippet for agent platforms.
> **Also available over HTTP.** The [Export Skills endpoint](/docs/endpoints/export) runs the same logic on the server against a GitHub repository — useful when you want results in a browser, a CI job without installing Python, or an agent that reaches skill-lab.dev directly.
```bash
sklab prompt [SKILL_PATHS...] [OPTIONS]
```
Renders the named skills as XML, Markdown, or JSON suitable for pasting into an agent platform's system prompt. Accepts multiple paths — pass several skills to render them as a single combined prompt.
#### Arguments
| Argument | Required | Description |
| ------------ | -------- | ----------------------------------------------------------------- |
| SKILL\_PATHS | no | One or more skill directories. Defaults to the current directory. |
#### Options
| Flag | Value | Description |
| ------------ | ------------------------------------ | -------------- |
| --format, -f | xml\|markdown\|json (default: `xml`) | Output format. |
#### Examples
Single skill as XML
```bash
sklab prompt ./skill-a
```
Multiple skills
```bash
sklab prompt ./skill-a ./skill-b
```
JSON to a file
```bash
sklab prompt ./skill-a -f json > skills.json
```
### sklab generate
Auto-generate \~13 trigger test cases for a skill via LLM.
> **Also available over HTTP.** The [Generate Triggers endpoint](/docs/endpoints/triggers) runs the same logic on the server against a GitHub repository — useful when you want results in a browser, a CI job without installing Python, or an agent that reaches skill-lab.dev directly.
```bash
sklab generate [SKILL_PATH] [OPTIONS]
```
Reads the SKILL.md description and produces .sklab/tests/triggers.yaml with \~13 test cases across all 4 trigger types: explicit, implicit, contextual, and negative. Run \`sklab trigger\` afterwards to execute the tests against a live runtime.
#### Arguments
| Argument | Required | Description |
| ----------- | -------- | --------------------------------------------------------------- |
| SKILL\_PATH | no | Path to the skill directory. Defaults to the current directory. |
#### Options
| Flag | Value | Description |
| ----------- | --------------------------------------------------- | ----------------------------------------------------------------------------- |
| --model, -m | \ (default: `claude-haiku-4-5-20251001`) | Model ID. Supports Anthropic, OpenAI (gpt-\*), and Gemini (gemini-\*) models. |
| --force | flag | Overwrite an existing triggers.yaml file. |
#### Examples
Generate with default model
```bash
sklab generate ./my-skill
```
Use a different model
```bash
sklab generate ./my-skill -m claude-sonnet-4-6
```
Overwrite existing tests
```bash
sklab generate ./my-skill --force
```
#### Notes
- Requires an API key for the selected provider (ANTHROPIC\_API\_KEY, OPENAI\_API\_KEY, or GEMINI\_API\_KEY).
- The skill path is a positional argument — it comes before the --model flag.
### sklab trigger
Run trigger tests against a live LLM runtime.
```bash
sklab trigger [SKILL_PATH] [OPTIONS]
```
Executes the tests in .sklab/tests/triggers.yaml and reports which prompts correctly activated (or correctly failed to activate) the skill. Use --type to filter by a single trigger category while debugging.
#### Arguments
| Argument | Required | Description |
| ----------- | -------- | --------------------------------------------------------------- |
| SKILL\_PATH | no | Path to the skill directory. Defaults to the current directory. |
#### Options
| Flag | Value | Description |
| ------------ | ---------------------------------- | --------------------------------------------------------------------------------- |
| --provider | local\|docker (default: `local`) | Execution provider: local (temp-dir isolation) or docker (container isolation). |
| --type, -t | \ | Only run tests of this trigger type: explicit, implicit, contextual, or negative. |
| --output, -o | \ | Write the JSON report to a file. |
| --format, -f | json\|console (default: `console`) | Output format. |
#### Examples
Run all tests
```bash
sklab trigger ./my-skill
```
Debug false positives
```bash
sklab trigger ./my-skill -t negative
```
Container isolation
```bash
sklab trigger ./my-skill --provider docker
```
#### Notes
- Requires the Claude CLI: npm install -g @anthropic-ai/claude-code.
- Run \`sklab generate\` first if .sklab/tests/triggers.yaml does not yet exist.
### sklab stats
Personal usage history and score trends across the skills you have evaluated.
```bash
sklab stats [count|score|tokens] [--here]
```
With no subcommand, prints a usage overview from \~/.sklab/usage.db. Pass a subcommand to drill into one metric. Invocation data is populated by the PostToolUse hook — run \`sklab setup\` once to install it.
#### Subcommands
| Subcommand | Description |
| ---------- | ---------------------------------------------- |
| count | Skill invocation counts for the current month. |
| score | Score trend across all evaluated skills. |
| tokens | Token usage per skill for the current month. |
#### Options
| Flag | Value | Description |
| ------ | ----- | ---------------------------------------------------- |
| --here | flag | Limit results to skills inside the current git repo. |
#### Examples
Overview
```bash
sklab stats
```
Per-month invocations
```bash
sklab stats count
```
Scope to this repo
```bash
sklab stats tokens --here
```
#### Notes
- If you see 'No usage data found', run \`sklab setup\` first — the PostToolUse hook is what populates the stats database.
### sklab list-checks
Browse all 37 checks across 5 dimensions.
> **Also available over HTTP.** The [Check Registry endpoint](/docs/endpoints/check-registry) runs the same logic on the server against a GitHub repository — useful when you want results in a browser, a CI job without installing Python, or an agent that reaches skill-lab.dev directly.
```bash
sklab list-checks [OPTIONS]
```
Prints a table of every check with its ID, dimension, severity, and whether the Agent Skills spec requires it. Use it as a reference when reading evaluate output.
#### Options
| Flag | Value | Description |
| ------------------ | ------ | -------------------------------------------------------------------------- |
| --dimension, -d | \ | Filter by dimension: structure, naming, description, content, or security. |
| --spec-only, -s | flag | Only spec-required checks. |
| --suggestions-only | flag | Only quality-suggestion checks (non-spec). |
#### Examples
All checks
```bash
sklab list-checks
```
Security only
```bash
sklab list-checks -d security
```
Spec-required only
```bash
sklab list-checks --spec-only
```
### sklab optimize
LLM-powered SKILL.md rewrite with diff preview and score delta.
> **Also available over HTTP.** The [Optimize Skill endpoint](/docs/endpoints/optimize) runs the same logic on the server against a GitHub repository — useful when you want results in a browser, a CI job without installing Python, or an agent that reaches skill-lab.dev directly.
```bash
sklab optimize [SKILL_PATH] [OPTIONS]
```
Reads the latest evaluation from .sklab/evals/ (so run \`sklab evaluate\` first), feeds the static failures and judge feedback to an LLM, and proposes an improved SKILL.md. Shows a unified diff and a before/after score before applying. Pass --auto to skip the confirmation prompt.
#### Arguments
| Argument | Required | Description |
| ----------- | -------- | --------------------------------------------------------------- |
| SKILL\_PATH | no | Path to the skill directory. Defaults to the current directory. |
#### Options
| Flag | Value | Description |
| ----------- | --------------------------------------------------- | ----------------------------------------------------------------------------- |
| --model, -m | \ (default: `claude-haiku-4-5-20251001`) | Model ID. Supports Anthropic, OpenAI (gpt-\*), and Gemini (gemini-\*) models. |
| --auto | flag | Apply the rewrite without the confirmation prompt. |
#### Examples
Review diff interactively
```bash
sklab optimize ./my-skill
```
Apply without prompt
```bash
sklab optimize ./my-skill --auto
```
Use a stronger model
```bash
sklab optimize ./my-skill -m claude-sonnet-4-6
```
#### Notes
- Requires a prior \`sklab evaluate\` run — optimize reads from .sklab/evals/.
- Requires ANTHROPIC\_API\_KEY, OPENAI\_API\_KEY, or GEMINI\_API\_KEY for the selected provider.
### sklab setup
Install the PostToolUse hook that powers sklab stats.
```bash
sklab setup
```
Writes PostToolUse hooks into \~/.claude/settings.json (Claude Code) and \~/.cursor/hooks.json (Cursor) so sklab records a row in \~/.sklab/usage.db every time a skill fires. Safe to re-run — the command is idempotent.
#### Examples
One-time install
```bash
sklab setup
```
#### Notes
- Without this hook, \`sklab stats\` has no data to show.
- The hook only records skill names, token counts, and timestamps — no prompt or file contents.