# intent validate

`intent validate` checks `SKILL.md` files and artifacts for structural problems, broken relative links, and code examples that no longer match the library API.

```sh
npx @tanstack/intent@latest validate [<dir>] [--github-summary] [--fix] [--check] [--set-version <version>]
```

## Arguments

- `<dir>`: directory containing skills; without it, discover the applicable root and workspace skill directories
- Relative paths are resolved from the current working directory

## Options

- `--github-summary`: write a GitHub Actions step summary when `GITHUB_STEP_SUMMARY` is set
- `--check`: fail if any `SKILL.md` has fixable frontmatter migrations pending, without writing files
- `--fix`: rewrite fixable `SKILL.md` frontmatter migrations, then validate the result
- `--set-version <version>`: set `metadata.library_version` on the matched skills, then validate the result; cannot be combined with `--check`

## Set the library version

Use `--set-version` in a release step to stamp the version the skills describe:

```sh
npx @tanstack/intent@latest validate packages/query/skills --set-version 5.62.0
```

The value must be a non-empty string. Skills whose `metadata` is not a mapping are skipped. `--check` only reports pending changes and never writes, so the two options cannot be combined.

## Frontmatter migration fixes

Use `--check` in CI to detect mechanical frontmatter migrations that have not been applied:

```sh
npx @tanstack/intent@latest validate --check
```

Use `--fix` locally to apply the mechanical frontmatter migrations:

```sh
npx @tanstack/intent@latest validate --fix
```

`--fix` applies these frontmatter migrations:

- `name` values are rewritten to the parent directory leaf when the parent directory is already a legal skill name
- Top-level string fields `type`, `library`, `library_version`, and `framework` are moved under `metadata`

Equal top-level and nested values are deduplicated. If they disagree, the entire file is preserved and the conflict is reported for assessment. A successful migration does not establish that the skill's guidance is accurate for its recorded library version. Use [intent repair](./intent-repair) for a lightweight repair plan or reviewable patch without full validation.

`--fix` does not rewrite authoring-judgment validation errors:

- Missing or invalid `description`
- Length-limit failures
- Invalid `metadata` shape or non-string `metadata` values
- Missing `requires` for framework skills
- Artifact validation failures

## Validation checks

### File structure

- Frontmatter delimiter and structure are valid
- YAML frontmatter parses successfully
- Required fields exist: `name`, `description`
- `name` is a single leaf segment matching the skill's parent directory (no slashes); the namespace is carried by the directory path
- `name` uses only lowercase letters, numbers, and hyphens and is at most 64 characters

### Field rules

- Standard top-level fields are `name`, `description`, `license`, `compatibility`, `metadata`, and `allowed-tools`. Intent also accepts top-level `sources` and `requires` arrays. Intent-specific scalars (`type`, `library`, `library_version`, `framework`) must live under `metadata`
- `metadata`, when present, is a mapping of string values
- `description` length is at most 1024 characters
- `type: framework` requires `requires` to be an array
- Total file length is at most 500 lines

### Code examples and links

TypeScript and JavaScript fences (`ts`, `tsx`, `typescript`, `js`, `jsx`, and `javascript`) are checked as separate source files in one compiler context per package, against the library's source or tracked public declarations. Workspace imports resolve to their owning packages. Missing exports, incompatible options, and syntax errors fail validation with the skill path and line number; deprecated imports produce warnings. Names and external modules intentionally omitted from partial examples are tolerated. JavaScript libraries can supply JSDoc contracts without a separate type declaration entry. JSX and TSX examples check component props and syntax; they do not render components or prove framework behavior. Standalone backtick and tilde fences support longer closing markers and end-of-file closure, while nested fences inside a Markdown example remain data. The checker does not execute examples.

The checker enables strict null checks because some library APIs require them, while tolerating omitted names, shorthand values, and implicit parameter types. Each code fence represents one example. Separate before/after implementations into distinct fences; use `diff` or `text` for deliberately invalid code or fragments that cannot be checked as a source file. The checker does not infer those distinctions from prose or comments.

A property after the fence language changes how one example is checked:

| Fence | Behavior |
| --- | --- |
| ` ```ts no-check ` | The example is not typechecked. Use it for a fragment that is not a complete source file, such as a single class member. |
| ` ```ts expect-error ` | The example must report at least one error. Validation fails when it compiles, so a `Wrong:` example that a library change made valid is reported. |
| ` ```ts expect-error=TS2322 ` | The example must report that error code. List several codes with commas (`expect-error=TS2322,TS2345`); quotes around the value are optional. |

An `expect-error` example reports nothing else: its errors and deprecation warnings are the expected result. Errors that Intent tolerates in partial examples, such as an undeclared name, do not count as the expected error. A syntax error satisfies the plain `expect-error`, so name the code when the example must fail for a specific reason.

Module augmentations and global declarations still share the package compiler context. Two examples that pass separately can conflict when checked together. Verify those examples in isolated fixtures before treating the combined diagnostics as defects in the guidance; separate fences alone do not isolate their augmentations.

TypeScript 5.0 or newer must be available in the repository for code checking. If it or the library type entry is unavailable, Intent reports why those checks were skipped; this is not a successful typecheck. Prose-only skills do not load TypeScript. With TypeScript 7.0, Intent checks examples through the compiler API that TypeScript 7 publishes as unstable; Node.js 24 or newer is supported. When `@typescript/typescript6` is installed beside TypeScript 7, Intent uses that package instead. If neither API can run, Intent reports that the checks were skipped. TypeScript 7.1 is not supported at this time.

Relative Markdown links outside fenced examples must point to an existing file or directory. The target must also be inside the package that owns the skill. Only the package is installed in a consumer project, so a link to a file elsewhere in the repository fails with `Link target is outside the package: <target>` even when the file exists. The boundary is the package root directory; the `files` list in `package.json` is not consulted. External URLs and anchors are not checked. Link checks still run when TypeScript is unavailable. Repeated validations read current source files and link targets.

### Reference files

Every `.md` file under a skill's `references/` directory, at any depth, is checked with its skill. No planning artifacts are required.

- The file is plain Markdown: it does not begin with YAML frontmatter
- The body of the owning `SKILL.md` links to the file with a direct relative Markdown link outside fenced examples, such as `[retry behavior](references/retries.md)`. A path in backticks or a link from another reference file does not count, because an agent finds a reference only through that link. A reference file can also link to another reference file
- TypeScript and JavaScript fences are checked with the skill's fences, under the rules in [Code examples and links](#code-examples-and-links). Errors name the reference file and line. Relative links inside a reference file are not checked

A `skill_tree.yaml` entry lists the skill's reference files in a `references` key, as paths relative to the skill directory:

```yaml
skills:
  - name: React Table State
    slug: table-state
    package: packages/react-table
    path: skills/table-state/SKILL.md
    references:
      - references/reactivity.md
```

Intent reads the tree from `<dir>/_artifacts` and, in a monorepo, from `_artifacts` at the workspace root. It matches an entry to a skill by the resolved `path`, so two packages can use the same slug. When a skill has a tree entry, the entry must agree with the files:

- An entry for a skill that has reference files has a `references` key. The error shows the YAML lines to add
- `references`, when present, is a list of strings

- Each path has the form `references/<name>.md`, stays inside the skill directory (no absolute path and no `..` segment), and is listed once
- Each listed file exists
- Each `.md` file under `references/` is listed

A skill without reference files needs no `references` key. A skill without a tree entry, or a repository without planning artifacts, gets only the file checks above.

Upgrade impact: a repository that already has reference files fails validation when a reference file is not linked directly from its `SKILL.md`, begins with frontmatter, or contains a code example that does not typecheck, or when a matching `skill_tree.yaml` entry does not list the skill's reference files.

### Artifacts

When `<dir>/_artifacts` exists, Intent also checks:

- Required files: `domain_map.yaml`, `skill_spec.md`, `skill_tree.yaml`
- Required files must be non-empty
- `.yaml` artifacts must parse successfully

## Packaging warnings

Packaging warnings are computed from the `package.json` that owns the validated skills:

- `@tanstack/intent` missing from `devDependencies` (in a monorepo, the workspace root's `devDependencies` also count)
- Missing `tanstack-intent` in keywords array
- A skill directory not covered by the `files` array, when that array exists. Either `skills` or the per-skill `skills/<name>` entries that `intent maintainer sync` writes cover a skill; the warning names the uncovered directory.
- Missing `!skills/_artifacts` when the whole `skills` directory is published, `skills/_artifacts` exists, and the package is not in a monorepo

Warnings are informational; they are printed on both pass and fail paths.

## Common errors

- Missing target directory: `Skills directory not found: <abs-path>`
- No skill files discovered: `No SKILL.md files found`
- Validation failures: aggregated file-specific errors and count

## Related

- [intent maintainer](./intent-maintainer)
- [setup commands](./intent-setup)
