title: Fields at the top of a skill file
description: Every field a SKILL.md's YAML frontmatter may carry, generated from the skill loader's own schema.
url: https://legalquants.github.io/lq-ai/reference/skill-frontmatter/
checked-against: 671eab0d (2026-10-25)
status: draft
kind: explanation
sources: docs/site/reference/skill-frontmatter.intro.md, api/app/skills/schema.py, docs/skill-authoring-guide.md

Naming a file format in a skill's frontmatter doesn't make the app accept
that format — the upload pipeline decides what it will actually ingest, and
the two can disagree.

**File formats still depend on the app, not the skill.** The upload parser
accepts a PDF with extractable text, or plain text and Markdown saved as
valid UTF-8; an encrypted or image-only PDF, or a text file that isn't valid
UTF-8, fails ingestion (`api/app/pipeline/ingest.py`,
`api/app/pipeline/parsers.py`). DOCX is not ingested today — a skill's
instructions or a declared input can mention a `.docx` file, but that
mention does not add Word-document upload support. DOCX ingest via Pandoc
is an accepted design
([ADR 0017](https://github.com/LegalQuants/lq-ai/blob/671eab0d/docs/adr/0017-docx-ingest-via-pandoc.md)), not a shipped one;
its implementation is tracked separately from the decision to build it.

Generated from [`api/app/skills/schema.py`](https://github.com/LegalQuants/lq-ai/blob/671eab0d/api/app/skills/schema.py) — the loader's own schema, which is what accepts or rejects a skill at load time. The conventions an author should follow are in the [skill-authoring guide](https://github.com/LegalQuants/lq-ai/blob/671eab0d/docs/skill-authoring-guide.md); this page is the floor the product enforces underneath them.

## Top level

The two required keys, plus the `lq_ai:` block everything else nests under.

Top-level frontmatter shape. Two required fields — `name` and `description`. `name` is the skill's stable identifier (matches the folder name); `description` is the one-sentence trigger statement. Everything else nests under `lq_ai:` per the authoring guide.

<!-- table: records -->
| Field | Type | Required | Default | What it is |
|---|---|---|---|---|
| `name` | `str` | required | — | — |
| `description` | `str` | required | — | — |
| `lq_ai` | `LQAIFrontmatter` | optional | `LQAIFrontmatter()` | — |

## The `lq_ai:` block

Every field is optional. A skill that declares none still loads.

The `lq_ai:` namespace inside a SKILL.md's frontmatter. All fields are optional. The skill-authoring guide documents recommended values, but the M1 starter skill corpus uses a broader range — strict validation would reject most of it. The summary endpoint surfaces what is present; missing fields are simply not in the response.

<!-- table: records -->
| Field | Type | Required | Default | What it is |
|---|---|---|---|---|
| `capabilities` | `SkillCapabilities` | optional | `SkillCapabilities()` | — |
| `title` | `str \| None` | optional | `None` | Human-readable display name for the UI. Defaults to `name` rendered title-cased when missing. |
| `version` | `str \| None` | optional | `None` | Semver string, e.g. '1.0.0'. Free-form so we can surface non-conforming values without rejecting them. |
| `author` | `str \| None` | optional | `None` | — |
| `tags` | `list[str]` | optional | `list()` | Discovery tags. Empty if not declared. |
| `jurisdiction` | `str \| None` | optional | `None` | Free-form per the corpus reality (`us`, `regime-aware`, `agnostic`, `regime-dependent`, `US-default`, etc.). |
| `output_format` | `str \| None` | optional | `None` | Free-form per corpus (`report`, `markdown`, `structured_checklist`, `redline`, `table`, etc.). The `table` value (M3-C1) signals to the Tabular Review surface that this skill produces a grid; the column spec lives in `columns`. |
| `columns` | `list[ColumnSpec] \| None` | optional | `None` | Column definitions for an `output_format: table` skill (M3-C1). `None` for non-table skills. The loader (`app/skills/loader.py`) emits a WARNING and skips the skill when `output_format == 'table'` but `columns` is missing or empty — mirroring the existing pattern for required-but-missing fields. A non-table skill may carry a `columns` value (e.g., a skill author iterating on output mode); downstream surfaces ignore it unless `output_format == 'table'`. |
| `minimum_inference_tier` | `int \| None` | optional | `None` | Tier-floor declaration; the gateway's tier-floor enforcement (D1) consults this. C1 only surfaces the value. |
| `ensemble_verification` | `bool \| None` | optional | `None` | When true, the Citation Engine runs Stage 4 (ensemble verification) for citations produced from chats using this skill. Per M2-D1, OR'd against the chat's project ensemble flag and the gateway's deployment default. None means 'no opinion' (treated as false at the OR site). Stage 4 only runs when the gateway's judge_models list (in the citation_engine.ensemble_verification block) is configured; it defaults to empty, which disables Stage 4 even when this flag is true. |
| `use_organization_profile` | `bool \| None` | optional | `None` | — |
| `is_organization_profile` | `bool \| None` | optional | `None` | — |
| `self_improvement` | `bool \| None` | optional | `None` | — |
| `trigger_examples` | `list[str]` | optional | `list()` | — |
| `tool_usage` | `list[str] \| None` | optional | `None` | C5 (PR6d) — connector identifiers this skill calls (e.g. ['courtlistener'], extensible to MCP server names). Parsed and SURFACED against the operator's configured connectors; never enforced (a skill with an unconfigured connector still loads and runs). |

## A column, for an `output_format: table` skill

Required only when `output_format: table`; the loader skips a table-mode skill whose `columns` list is missing or empty.

One column in an `output_format: table` Skill (M3-C1). A table-mode skill produces a row-per-document by column-per-spec grid; each column carries its own per-row extraction query plus optional overrides for the skill-level `ensemble_verification` and `minimum_inference_tier`. The Tabular Review LangGraph workflow (M3-C2) dispatches one Citation-Engine-grounded extraction per `(document, column)` cell. Per Decision C-1 (Phase C prep, 2026-05-21): every cell value is a string in v0.3.0; typed columns are a follow-on DE if user-attorney walkthrough surfaces the need.

<!-- table: records -->
| Field | Type | Required | Default | What it is |
|---|---|---|---|---|
| `name` | `str` | required | — | The grid column header. Required. |
| `query` | `str` | required | — | The per-row extraction prompt instantiated against each document. Required. |
| `ensemble_verification` | `bool \| None` | optional | `None` | When `True`, this column's cells route through Stage 4 of the Citation Engine cascade (ensemble verification). Overrides the skill-level field when both are set. `None` means 'inherit from skill / project / deployment default'. Stage 4 only runs when the gateway's `judge_models` list (in the `citation_engine.ensemble_verification` block) is configured; it defaults to empty, which disables Stage 4 regardless of this flag. |
| `minimum_inference_tier` | `int \| None` | optional | `None` | Per-column tier floor (1-5). Overrides the skill-level tier floor when both are set. Lower numbers are stricter (PRD §1.5.2): a floor of N allows Tier N and any lower-numbered tier and refuses higher-numbered ones. High-stakes columns can demand Tier 1 or 2 while routine columns leave the floor unset. |

## A declared input

What the skill-input form renders against. Read from `inputs:` at the top level or under `lq_ai:` — the corpus uses both.

One declared input — the shape the skill-input form renders against. Fields per `docs/skill-authoring-guide.md` + observed corpus variance. `name` is the only strictly required field; the form can render a text input as the default when `type` is absent.

<!-- table: records -->
| Field | Type | Required | Default | What it is |
|---|---|---|---|---|
| `name` | `str` | required | — | — |
| `type` | `str \| None` | optional | `None` | One of `text` \| `enum` \| `boolean` \| `integer` \| `structured` \| `file` — free-form per corpus reality; the form renderer chooses a sensible default when null. |
| `required` | `bool` | optional | `False` | — |
| `description` | `str \| None` | optional | `None` | — |
| `enum` | `list[str] \| None` | optional | `None` | — |
| `default` | `Any \| None` | optional | `None` | — |

## Next

- [Author your first skill](/lq-ai/skills/author-your-first-skill/)
- [Skill catalogue](/lq-ai/skills/catalogue/) — the frontmatter of every shipped skill, rendered.
- [Configuration reference](/lq-ai/reference/configuration/)
