# ctxlint

[![npm version](https://img.shields.io/npm/v/@yawlabs/ctxlint)](https://www.npmjs.com/package/@yawlabs/ctxlint)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
[![GitHub stars](https://img.shields.io/github/stars/YawLabs/ctxlint)](https://github.com/YawLabs/ctxlint/stargazers)
[![MCP Compliance](https://raw.githubusercontent.com/YawLabs/ctxlint/main/compliance-badge.svg)](https://github.com/YawLabs/mcp-compliance)

**Lint your AI agent context files, MCP server configs, and session data against your actual codebase.** Context linting + MCP config linting + session auditing. 16 AI tools, 8 MCP clients, cross-project consistency, auto-fix. Works as a CLI, CI step, pre-commit hook, or MCP server.

Your `CLAUDE.md` is lying to your agent. Your `.mcp.json` has a hardcoded API key. ctxlint catches both.

[![Add to Yaw MCP](https://yaw.sh/yaw-mcp-button.svg)](https://yaw.sh/mcp/install?name=ctxlint&command=npx&args=-y%2C%40yawlabs%2Fctxlint%2Cserve&description=Lint%20AI%20agent%20context%20files%20and%20MCP%20configs%20against%20your%20codebase&source=https%3A%2F%2Fgithub.com%2FYawLabs%2Fctxlint)

One click adds this to your local Yaw MCP config so it's available in every Yaw Terminal session. Or install manually below.

## Why ctxlint?

Every AI coding tool ships a context file: `CLAUDE.md`, `.cursorrules`, `AGENTS.md`, `.mcp.json`. These files are the single most important interface between you and your agent — they tell it what to build, how to test, where things live.

But context files rot fast. You rename a file, change a build script, or switch from Jest to Vitest — and your `CLAUDE.md` still says the old thing. Your agent follows those stale instructions faithfully, then fails. You lose 10 minutes debugging what turns out to be a wrong path in line 12 of a markdown file.

Multiply that across a team with 5 context files, 3 MCP configs, and 2 people who touched the build system last week — and you have a real problem with no existing solution.

ctxlint is a linter purpose-built for this. It reads your context files, cross-references them against your actual codebase, and catches the drift before your agent does.

- **Instant startup** — ships as a single self-contained bundle with zero runtime dependencies. `npx` downloads a ~400 KB tarball and starts immediately
- **Catches real problems** — broken paths, wrong commands, stale references, contradictions across files
- **Smart suggestions** — detects git renames and fuzzy-matches to suggest the right path
- **Auto-fix** — `--fix` rewrites broken paths automatically using git history
- **Token-aware** — shows how much context window your files consume and flags redundant content
- **Every AI tool** — supports Claude Code, Cursor, Copilot, Windsurf, Gemini, Cline, Aider, and 9 more
- **Multiple outputs** — text, JSON, and SARIF (GitHub Code Scanning)
- **MCP server** — 7 tools for IDE/agent integration with tool annotations for auto-approval
- **Watch mode** — `--watch` re-lints automatically when context files change

## Install

Run directly (no install needed):

```bash
npx -y @yawlabs/ctxlint@latest
```

### Project install (recommended for teams)

```bash
npm install -D @yawlabs/ctxlint
# or
pnpm add -D @yawlabs/ctxlint
```

Then add to your `package.json` scripts:

```json
{
  "scripts": {
    "lint:ctx": "ctxlint --strict"
  }
}
```

### Global install

```bash
npm install -g @yawlabs/ctxlint
```

Useful if you want `ctxlint` available in every project without per-project setup.

## What It Checks

| Check                 | What it finds                                                                                                                                                                                                                                                                    |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Broken paths**      | File references in context that don't exist in your project                                                                                                                                                                                                                      |
| **Wrong commands**    | Build/test commands that don't match your package.json scripts or Makefile targets                                                                                                                                                                                               |
| **Stale context**     | Context files not updated after recent code changes                                                                                                                                                                                                                              |
| **Token waste**       | How much context window your files consume per session                                                                                                                                                                                                                           |
| **Redundancy**        | Content the agent can already infer (e.g. "We use React" when react is in package.json)                                                                                                                                                                                          |
| **Contradictions**    | Conflicting directives across context files (e.g. "use Jest" in one, "use Vitest" in another)                                                                                                                                                                                    |
| **Frontmatter**       | Invalid or missing YAML frontmatter in Cursor .mdc, Copilot instructions, and Windsurf rules                                                                                                                                                                                     |
| **CI coverage**       | Release/deploy workflows in `.github/workflows/` not documented in any context file                                                                                                                                                                                              |
| **CI secrets**        | Secrets used in CI workflows (`${{ secrets.X }}`) not mentioned in context files                                                                                                                                                                                                 |
| **Inline secrets**    | Real secrets pasted into context files — private-key headers, AWS/GitHub/Anthropic/OpenAI/npm/Slack/Google/Stripe token shapes. Messages never echo the secret (6-char redacted prefix only)                                                                                     |
| **Dead hooks**        | PreToolUse hooks / permissions entries in `.claude/settings.json` pointing at scripts that no longer exist (a dead gate silently no-ops). Scans project `.claude/settings.json[.local]` by default; pass `--hooks-global` to also scan the user-global `~/.claude/settings.json` |
| **Missing secrets**   | GitHub secrets set on sibling repos but missing from current project                                                                                                                                                                                                             |
| **Diverged configs**  | Canonical config files (CI, tsconfig, etc.) drifting across sibling projects                                                                                                                                                                                                     |
| **Missing workflows** | GitHub Actions workflows present in 2+ siblings but absent here                                                                                                                                                                                                                  |
| **Stale memory**      | Claude Code memory entries referencing paths that no longer exist                                                                                                                                                                                                                |
| **Duplicate memory**  | Near-duplicate memories across projects (>60% content overlap)                                                                                                                                                                                                                   |
| **Loop detection**    | Agent stuck in loops — repeated commands or cyclic patterns in session history                                                                                                                                                                                                   |
| **Memory overflow**   | `MEMORY.md` past Claude Code's 200-line / 25KB session-load cap — entries beyond it are invisible to the agent                                                                                                                                                                   |

## Supported Context Files

| File                                                                                                 | Tool                        |
| ---------------------------------------------------------------------------------------------------- | --------------------------- |
| `CLAUDE.md`, `CLAUDE.local.md`, `.claude/rules/*.md`                                                 | Claude Code                 |
| `AGENTS.md`, `AGENT.md`, `AGENTS.override.md`                                                        | AAIF / Multi-agent standard |
| `.cursorrules`, `.cursor/rules/*.md`, `.cursor/rules/*.mdc`, `.cursor/rules/*/RULE.md`               | Cursor                      |
| `.github/copilot-instructions.md`, `.github/instructions/*.md`, `.github/git-commit-instructions.md` | GitHub Copilot              |
| `.windsurfrules`, `.windsurf/rules/*.md`                                                             | Windsurf                    |
| `GEMINI.md`                                                                                          | Gemini CLI                  |
| `.clinerules`                                                                                        | Cline                       |
| `.aiderules`                                                                                         | Aider                       |
| `.aide/rules/*.md`                                                                                   | Aide / Codestory            |
| `.amazonq/rules/*.md`                                                                                | Amazon Q Developer          |
| `.goose/instructions.md`, `.goosehints`                                                              | Goose by Block              |
| `.junie/guidelines.md`, `.junie/AGENTS.md`                                                           | JetBrains Junie             |
| `.aiassistant/rules/*.md`                                                                            | JetBrains AI Assistant      |
| `.continuerules`, `.continue/rules/*.md`                                                             | Continue                    |
| `.rules`                                                                                             | Zed                         |
| `replit.md`                                                                                          | Replit                      |

## MCP Server Config Linting

ctxlint also lints MCP server configuration files — the JSON configs that tell AI clients which tools to connect to. These are context interfaces too: they shape what your agent can do.

```bash
# Lint context files + MCP configs
npx @yawlabs/ctxlint@latest --mcp

# Lint only MCP configs
npx @yawlabs/ctxlint@latest --mcp-only

# Include global/user-level configs (Claude Desktop, Cursor, Windsurf, etc.)
npx @yawlabs/ctxlint@latest --mcp-global
```

### What MCP config files are scanned

| File                          | Client                                 |
| ----------------------------- | -------------------------------------- |
| `.mcp.json`                   | Claude Code (universal project config) |
| `.cursor/mcp.json`            | Cursor                                 |
| `.vscode/mcp.json`            | VS Code / GitHub Copilot               |
| `.amazonq/mcp.json`           | Amazon Q Developer                     |
| `.continue/mcpServers/*.json` | Continue                               |

With `--mcp-global`, also scans Claude Desktop, Cursor, Windsurf, and Amazon Q global configs.

### What MCP config checks catch

| Check           | What it finds                                                                          |
| --------------- | -------------------------------------------------------------------------------------- |
| **Schema**      | Invalid JSON, wrong root key (`servers` vs `mcpServers`), missing required fields      |
| **Security**    | Hardcoded API keys and Bearer tokens in git-tracked config files                       |
| **Commands**    | Missing `cmd /c` wrapper for npx on Windows, broken file paths in args                 |
| **Deprecated**  | SSE transport usage (deprecated March 2025, use Streamable HTTP)                       |
| **Env vars**    | Wrong env var syntax for the client (`${VAR}` vs `${env:VAR}` vs `${{ secrets.VAR }}`) |
| **URLs**        | Malformed URLs, localhost in project configs, missing path component                   |
| **Consistency** | Same server configured differently across client configs                               |
| **Redundancy**  | Disabled servers, identical configs at multiple scopes                                 |

### Example MCP config output

```
MCP Configs
  .mcp.json
    ✗ mcp-security    Server "api": hardcoded Bearer token in a git-tracked file
    ✗ mcp-deprecated  Server "old-svc": SSE transport is deprecated — use "http"
    ✓ mcp-schema
    ✓ mcp-commands
  .cursor/mcp.json
    ✗ mcp-env  Server "api": Cursor uses ${env:VAR}, not ${VAR}
    ✓ mcp-schema
  .vscode/mcp.json
    ✗ mcp-schema  .vscode/mcp.json must use "servers" as root key, not "mcpServers"

Cross-file
    ⚠ Server "api" is configured differently in .mcp.json and .cursor/mcp.json
    ℹ Server "db" is in .mcp.json but missing from .cursor/mcp.json

Summary: 3 errors, 2 warnings, 1 info
```

### MCP Config Linting Specification

The full specification for MCP config linting rules, the cross-client config landscape, and a machine-readable rule catalog are published as open specifications:

- **[`MCP_CONFIG_LINT_SPEC.md`](./MCP_CONFIG_LINT_SPEC.md)** — the full lint-rule set (rule count in the [Specifications](#specifications) family table), the complete client/format reference, and implementation guidance. Tool-agnostic — any linter can implement it.
- **[`mcp-config-lint-rules.json`](./mcp-config-lint-rules.json)** — Machine-readable rule catalog for programmatic consumption by AI agents, CI systems, and other tools.

## Session Linting

ctxlint can audit AI agent session data — history files and memory entries — for cross-project consistency. Session checks compare your current project against sibling repos to catch drift and missing setup.

```bash
# Lint context files + session data
npx @yawlabs/ctxlint@latest --session

# Lint only session data
npx @yawlabs/ctxlint@latest --session-only
```

Session checks are **opt-in** because they access files outside the project directory (agent history in your home directory, sibling repos in the parent directory).

### What session files are scanned

| Agent       | History                   | Memory                             |
| ----------- | ------------------------- | ---------------------------------- |
| Claude Code | `~/.claude/history.jsonl` | `~/.claude/projects/*/memory/*.md` |
| Codex CLI   | `~/.codex/history.jsonl`  | —                                  |

### What session checks catch

| Check                     | What it finds                                                                                                                                    |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Missing secrets**       | `gh secret set` ran on 2+ sibling repos but not this one                                                                                         |
| **Diverged configs**      | Shared config files (CI workflows, tsconfig, .prettierrc, etc.) with 20-90% line overlap — enough to be related, different enough to be drifting |
| **Missing workflows**     | GitHub Actions workflows in 2+ siblings but absent from this project                                                                             |
| **Stale memory**          | Memory entries referencing file paths that no longer exist                                                                                       |
| **Duplicate memory**      | Near-duplicate memory entries across projects (>60% overlap)                                                                                     |
| **Loop detection**        | Agent stuck in a loop — 3+ consecutive identical commands, or cyclic A,B,A,B patterns                                                            |
| **Memory index overflow** | `MEMORY.md` exceeds Claude Code's documented 200-line / 25KB session-load cap, so entries past the cap are invisible to the agent                |

### Session Linting Specification

- **[`AGENT_SESSION_LINT_SPEC.md`](./AGENT_SESSION_LINT_SPEC.md)** — the full lint-rule set (rule count in the [Specifications](#specifications) family table), the agent session data landscape across 8 agents, sibling detection strategy, and implementation guidance.
- **[`agent-session-lint-rules.json`](./agent-session-lint-rules.json)** — Machine-readable rule catalog.

## Example Output

```
ctxlint v0.9.10

Scanning /Users/you/my-app...

Found 2 context files (1,847 tokens total)
  CLAUDE.md (1,203 tokens, 42 lines)
  AGENTS.md -> CLAUDE.md (symlink)

CLAUDE.md
  ✗ Line 12: src/auth/middleware.ts does not exist
    → Did you mean src/middleware/auth.ts? (renamed 14 days ago)
  ✗ Line 8: "pnpm test" — script "test" not found in package.json
  ⚠ Last updated 47 days ago. src/routes/ has 8 commits since.
  ⚠ testing framework conflict: "Vitest" in CLAUDE.md vs "Jest" in AGENTS.md
  ℹ Line 3: "Express" is in package.json dependencies — agent can infer this

Summary: 2 errors, 2 warnings, 1 info
  Token usage: 1,203 tokens per agent session
  Estimated waste: ~55 tokens (redundant content)
```

## Options

```
Usage: ctxlint [options] [path]

Arguments:
  path                 Project directory to scan (default: ".")

Options:
  --strict                  Exit code 1 on any warning or error (for CI)
  --checks <list>           Comma-separated checks to run (see below)
  --ignore <list>           Comma-separated checks to skip
  --fix                     Auto-fix broken paths using git history and fuzzy matching
  --fix-dry-run             Preview --fix changes without writing
  --yes                     Skip interactive confirmation prompts (required for --fix in TTY)
  --follow-symlinks         Allow --fix to write through symlinks (default: skip)
  --format <fmt>            Output format: text, json, or sarif (default: text)
  --tokens                  Show token breakdown per file
  --verbose                 Show passing checks too
  --quiet                   Suppress all output except errors (exit code only)
  --config <path>           Path to config file (default: .ctxlintrc in project root)
  --depth <n>               Max subdirectory depth to scan (default: 2)
  --mcp                     Enable MCP config linting alongside context file checks
  --mcp-only                Run only MCP config checks, skip context file checks
  --mcp-global              Also scan user/global MCP config files (implies --mcp)
  --session                 Enable session audit checks (cross-project consistency)
  --session-only            Run only session checks, skip context and MCP checks
  --skills                  Run agent-skill checks (~/.claude/skills + ~/.claude/agents)
  --skills-only             Run only agent-skill checks, skip everything else
  --hooks-global            Also scan the user-global ~/.claude/settings.json in the
                            dead-hook check (default scans project .claude/ only)
  --mcp-server              Start the MCP server (alias: `serve` subcommand)
  --watch                   Re-lint on context file changes
  -V, --version             Output the version number
  -h, --help                Display help

Commands:
  init                 Set up a git pre-commit hook
```

**Available checks:** `paths`, `commands`, `staleness`, `tokens`, `tier-tokens`, `redundancy`, `contradictions`, `frontmatter`, `ci-coverage`, `ci-secrets`, `content-secrets`, `hook-coverage`, `mcp-schema`, `mcp-security`, `mcp-commands`, `mcp-deprecated`, `mcp-env`, `mcp-urls`, `mcp-consistency`, `mcp-redundancy`, `session-missing-secret`, `session-diverged-file`, `session-missing-workflow`, `session-stale-memory`, `session-duplicate-memory`, `session-loop-detection`, `session-memory-index-overflow`, `skill-frontmatter`, `skill-broken-ref`, `skill-trigger-collision`, `skill-orphaned`, `skill-dead-tool-restriction`

Passing any `mcp-*` check name implies `--mcp`. Passing any `session-*` check name implies `--session`. Passing any `skill-*` check name implies `--skills`.

## Watch Mode

```bash
npx @yawlabs/ctxlint@latest --watch
```

Re-lints automatically when any context file, MCP config, or `package.json` changes. Useful during development when you're editing context files alongside code.

## Use in CI

```yaml
- name: Lint context files
  run: npx @yawlabs/ctxlint@latest --strict
```

### Exit Codes

| Code | Meaning                                                              |
| ---- | -------------------------------------------------------------------- |
| `0`  | Success — no issues, or issues below the strict threshold            |
| `1`  | Strict mode caught at least one error or warning (`--strict` is set) |
| `2`  | Config error, invalid CLI option, or internal failure                |

In non-strict mode ctxlint always exits `0` — it's a reporting tool by default. Pass `--strict` to enforce in CI.

### GitHub Action

```yaml
- name: Lint context files
  uses: yawlabs/ctxlint-action@v1
```

Or with options:

```yaml
- name: Lint context files
  uses: yawlabs/ctxlint-action@v1
  with:
    args: '--strict --mcp'
```

### SARIF Output (GitHub Code Scanning)

```yaml
- name: Lint context files
  run: npx @yawlabs/ctxlint@latest --format sarif > ctxlint.sarif

- name: Upload SARIF
  uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: ctxlint.sarif
```

## Auto-fix

```bash
npx @yawlabs/ctxlint@latest --fix
```

When a broken path was renamed in git or has a close match in the project, `--fix` rewrites the context file automatically.

## Pre-commit Hook

### Built-in

```bash
npx @yawlabs/ctxlint@latest init
```

Sets up a git pre-commit hook that runs `ctxlint --strict` before each commit.

### pre-commit framework

Add to your `.pre-commit-config.yaml`:

```yaml
repos:
  - repo: https://github.com/yawlabs/ctxlint
    rev: v0.9.10
    hooks:
      - id: ctxlint
```

## Config File

Create a `.ctxlintrc` or `.ctxlintrc.json` in your project root:

```json
{
  "checks": ["paths", "commands", "tokens", "contradictions", "frontmatter"],
  "ignore": ["redundancy"],
  "strict": true,
  "tokenThresholds": {
    "info": 500,
    "warning": 2000,
    "error": 5000,
    "aggregate": 4000,
    "tierBreakdown": 1000,
    "tierAggregate": 4000
  },
  "contextFiles": ["CONVENTIONS.md", "docs/ai-rules.md"],
  "exclude": ["fixtures/**", "examples/**"]
}
```

The `contextFiles` array adds custom file patterns to scan alongside the built-in list. Useful for project-specific context files like `CONVENTIONS.md`.

The `exclude` array is its counterpart: globs of context files to drop from the scan entirely. Use it for files that are not this project's agent context at all — test fixtures, example projects, vendored templates.

`exclude` removes **files**, where `ignore` / `ignoreRules` / `.ctxlintignore` suppress **findings**. That distinction matters for the cross-file checks: `contradictions` and `redundancy/duplicate-content` compare the discovered set and report against the literal `(project)` path, which no per-file glob can match. Excluding the files is the only way to silence a conflict between two files you never wanted linted. Reach for `.ctxlintignore` when a real context file has one noisy finding; reach for `exclude` when the file shouldn't be in the corpus.

### Config Reference

| Field                           | Type       | Default    | Meaning                                                                                                                                                                                                   |
| ------------------------------- | ---------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `checks`                        | `string[]` | all checks | Checks to run. Check names include `paths`, `commands`, `tokens`, `tier-tokens`, `redundancy`, `contradictions`, `frontmatter`, `staleness`, `ci-coverage`, `ci-secrets`, `content-secrets`, `hook-coverage`, plus any `mcp-*` / `session-*` / `skill-*`. |
| `ignore`                        | `string[]` | `[]`       | Checks to skip, evaluated after `checks`.                                                                                                                                                                 |
| `strict`                        | `boolean`  | `false`    | Exit non-zero on any warning or error.                                                                                                                                                                    |
| `tokenThresholds`               | `object`   | see below  | Per-file and cross-file token thresholds.                                                                                                                                                                 |
| `tokenThresholds.info`          | `number`   | `1000`     | Per-file info threshold for `tokens/info`.                                                                                                                                                                |
| `tokenThresholds.warning`       | `number`   | `3000`     | Per-file warning threshold for `tokens/large`.                                                                                                                                                            |
| `tokenThresholds.error`         | `number`   | `8000`     | Per-file error threshold for `tokens/excessive`.                                                                                                                                                          |
| `tokenThresholds.aggregate`     | `number`   | `5000`     | Cross-file total threshold for `tokens/aggregate`.                                                                                                                                                        |
| `tokenThresholds.tierBreakdown` | `number`   | `1000`     | Always-loaded file threshold for `tier-tokens/section-breakdown`.                                                                                                                                         |
| `tokenThresholds.tierAggregate` | `number`   | `4000`     | Combined always-loaded threshold for `tier-tokens/aggregate`.                                                                                                                                             |
| `contextFiles`                  | `string[]` | `[]`       | Extra glob patterns to scan alongside the built-in list.                                                                                                                                                  |
| `exclude`                       | `string[]` | `[]`       | Globs of context files to drop from the scan entirely, matched against each file's project-relative path. Removes files rather than suppressing findings, so excluded files are also invisible to the cross-file checks. |
| `mcp`                           | `boolean`  | `false`    | Enable MCP config checks by default (same as `--mcp`).                                                                                                                                                    |
| `mcpOnly`                       | `boolean`  | `false`    | Run only MCP config checks, skip context-file checks (same as `--mcp-only`).                                                                                                                              |
| `mcpGlobal`                     | `boolean`  | `false`    | Also scan user/global MCP configs (same as `--mcp-global`).                                                                                                                                               |
| `session`                       | `boolean`  | `false`    | Enable session audit checks (cross-project consistency); same as `--session`.                                                                                                                             |
| `sessionOnly`                   | `boolean`  | `false`    | Run only session checks, skip context and MCP checks (same as `--session-only`).                                                                                                                          |
| `skills`                        | `boolean`  | `false`    | Enable agent-skill checks (`~/.claude/skills` + `~/.claude/agents`); same as `--skills`.                                                                                                                  |
| `skillsOnly`                    | `boolean`  | `false`    | Run only agent-skill checks, skip everything else (same as `--skills-only`).                                                                                                                              |

Config file resolution order: `.ctxlintrc` → `.ctxlintrc.json` in the project root. Use `--config <path>` to point elsewhere. CLI flags override config fields.

CLI flags override config file settings. Use `--config <path>` to load a config from a custom location.

## Use as MCP Server

ctxlint ships with an MCP server that exposes seven tools (`ctxlint_audit`, `ctxlint_mcp_audit`, `ctxlint_session_audit`, `ctxlint_skill_audit`, `ctxlint_validate_path`, `ctxlint_token_report`, `ctxlint_fix`). All read-only tools declare annotations so MCP clients can skip confirmation dialogs.

Launch it with the `serve` subcommand (or the equivalent `--mcp-server` flag, kept for back-compat):

```bash
npx -y @yawlabs/ctxlint@latest serve
```

### With Claude Code

```bash
claude mcp add ctxlint -- npx -y @yawlabs/ctxlint@latest serve
```

### With `.mcp.json` (Claude Code project config, Cursor, Windsurf)

Create `.mcp.json` in your project root:

macOS / Linux / WSL:

```json
{
  "mcpServers": {
    "ctxlint": {
      "command": "npx",
      "args": ["-y", "@yawlabs/ctxlint@latest", "serve"]
    }
  }
}
```

Windows:

```json
{
  "mcpServers": {
    "ctxlint": {
      "command": "cmd",
      "args": ["/c", "npx", "-y", "@yawlabs/ctxlint@latest", "serve"]
    }
  }
}
```

> **Tip:** This file is safe to commit — it contains no secrets.

### With VS Code / GitHub Copilot

Add to `.vscode/mcp.json`:

```json
{
  "servers": {
    "ctxlint": {
      "command": "npx",
      "args": ["-y", "@yawlabs/ctxlint@latest", "serve"]
    }
  }
}
```

### With Claude Desktop

Add to your Claude Desktop config (`claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "ctxlint": {
      "command": "npx",
      "args": ["-y", "@yawlabs/ctxlint@latest", "serve"]
    }
  }
}
```

## JSON Output

```bash
npx @yawlabs/ctxlint@latest --format json
```

Returns structured JSON with all file results, issues, and summary — useful for building integrations or dashboards.

## Specifications

ctxlint is the reference implementation of four open specifications for linting AI agent interfaces. These specs are tool-agnostic — any linter, IDE extension, or CI system can implement them.

| Spec                                                           | What it covers                                                                                                                                                                                                                            |
| -------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **[AI Context File Linting Spec](./CONTEXT_LINT_SPEC.md)**     | 41 rules for validating context files (CLAUDE.md, .cursorrules, AGENTS.md, etc.) across 16 clients. Covers file formats, frontmatter schemas, path/command validation, staleness, token budgets, redundancy, and contradictions.          |
| **[MCP Config Linting Spec](./MCP_CONFIG_LINT_SPEC.md)**       | 29 rules for validating MCP server configs (.mcp.json, .cursor/mcp.json, .vscode/mcp.json, etc.) across 8 clients. Covers schema validation, hardcoded secrets, env var syntax, deprecated transports, and cross-file consistency.        |
| **[Agent Session Linting Spec](./AGENT_SESSION_LINT_SPEC.md)** | 12 rules for auditing agent session data (history, memory) across 8 agents. Covers cross-project secret consistency, config drift, stale memory, and loop detection.                                                                       |
| **[Agent Skill Linting Spec](./AGENT_SKILL_LINT_SPEC.md)**     | 5 rules for auditing Claude Code skill (`SKILL.md`) and agent (`.md`) definitions under `~/.claude`. Covers frontmatter presence, broken refs, trigger-phrase collisions, orphaned skills, and dead tool restrictions. (v1, experimental) |

All specs include machine-readable rule catalogs for programmatic consumption:

- [`context-lint-rules.json`](./context-lint-rules.json) — context file rules and 16 supported format definitions
- [`mcp-config-lint-rules.json`](./mcp-config-lint-rules.json) — MCP config rules and 8 client definitions
- [`agent-session-lint-rules.json`](./agent-session-lint-rules.json) — session lint rules and 8 agent data source definitions
- [`agent-skill-lint-rules.json`](./agent-skill-lint-rules.json) — agent-skill lint rules (`~/.claude/skills`, `~/.claude/agents`)

## Also By Yaw Labs

- [Yaw](https://yaw.sh) — The AI-native terminal
- [Spend](https://spend.sh) — AI spend tracking, cost estimation, and provider comparison across 10+ providers
- [Token Limit News](https://tokenlimit.news) — Weekly AI dev tooling newsletter

## License

MIT
