Meltlight

SKILL.md frontmatter reference: every field, and which ones upload

Updated

The problem

You are writing a SKILL.md and want to know which frontmatter fields exist, which are required, and what values they take. Or you uploaded a skill to claude.ai or the Claude API and got:

Unexpected key(s) in SKILL.md frontmatter: argument-hint. Allowed properties are: allowed-tools, compatibility, description, license, metadata, name

The short answer

There are two sets of fields. The Claude API and claude.ai accept six keys — name, description, license, compatibility, metadata and allowed-tools — and reject an upload with any other key. Claude Code reads those six plus about a dozen more, and silently ignores any key it does not recognize. A skill that uses Claude Code-only keys works in Claude Code and fails to upload anywhere else.

Why it happens

The fields below are from the Claude Code skills docs and the Agent Skills overview. I have not run every field in every product myself.

Where the frontmatter must be

The frontmatter is read only if the opening --- is the very first line of the file. Anything before it — a blank line, a title — and the whole file is treated as content, with no name or description.

If the YAML does not parse, Claude Code still loads the skill, but with no fields set. You can still run it as /skill-name, but Claude cannot match it from its description. The usual cause is an unquoted colon inside the description. Run claude --debug to see the parse error.

The six portable fields

These work everywhere: Claude Code, claude.ai uploads, the Skills API and package_skill.py.

  • name — required outside Claude Code. At most 64 characters; lowercase letters, numbers and hyphens only; no XML tags; must not contain "anthropic" or "claude". In Claude Code it defaults to the directory name and becomes the slash command.
  • description — required outside Claude Code. Non-empty, at most 1,024 characters, no XML tags. Say what the skill does and when to use it.
  • license — accepted. Claude Code does not act on it.
  • compatibility — at most 500 characters. Claude Code does not act on it.
  • metadata — a map of extra keys. In Claude Code, a value that is not a map is dropped.
  • allowed-tools — tools Claude can use without asking permission during the turn that invokes the skill.

Fields only Claude Code reads

  • when_to_use — extra trigger phrases or example requests, appended to the description in the skill listing.
  • argument-hint — hint shown during autocomplete for the arguments, such as [issue-number].
  • arguments — named positional arguments, substituted as $name in the skill content.
  • disable-model-invocation — true takes the description out of Claude's context, so Claude never runs the skill on its own; you run it with /skill-name. Default false.
  • user-invocable — false hides the skill from the / menu, so only Claude can invoke it. Default true.
  • disallowed-tools — tools removed from Claude's pool while the skill is active.
  • model — the model to use for the rest of the turn that invokes the skill.
  • effort — low, medium, high, xhigh or max.
  • context — fork runs the skill in a forked subagent context.
  • agent — which subagent type to use when context: fork is set.
  • background — only applies with context: fork. A forked skill runs in the background by default; false waits for its result in the same turn (v2.1.218+).
  • hooks — hooks registered when the skill is invoked; they keep running for the rest of the session.
  • paths — glob patterns. When set, Claude loads the skill automatically only when working with matching files.
  • shell — the shell for the skill's inline commands: bash (default) or powershell.

Booleans also accept yes/no, on/off and 1/0 (v2.1.218+). In Claude Code every field is optional, and if description is missing it uses the first non-empty line of the body.

Limits that are not fields

  • Claude Code cuts description plus when_to_use at 1,536 characters in the skill listing. Text past that point is never seen when Claude decides whether to use the skill.
  • The docs recommend writing the description in the third person ("Extracts tables from PDFs…", not "I can help…" or "You can use…") and keeping the body of SKILL.md under 500 lines.

Why an unknown key does not error in Claude Code

Field names must match exactly, and Claude Code ignores a field it does not recognize without reporting anything. A typo such as disable-model-invokation therefore does nothing, silently. The upload path for claude.ai and the API is strict instead: any key outside the six is a hard error.

Check it with the tool

Paste your SKILL.md into Kanon (beta), the free SKILL.md linter on this site, and choose the target you will ship to. It runs in your browser and sends nothing anywhere.

  • API & claude.ai target: Kanon reports unknown-keys as an error for any key outside the six — the same rejection as the upload. If every extra key is a Claude Code key, it tells you to switch the target instead.
  • Claude Code target: Kanon warns unknown-key for each key Claude Code would ignore, and names the real field when the key differs from one only in case, - or _ (such as when-to-use for when_to_use). It does not catch other misspellings, so check the key names in the list above. Rules that only the API enforces, such as reserved words in name, become portability warnings.
  • Either target: fm-first-line and yaml-parse catch frontmatter that would be read as no fields at all, and effort-enum, context-enum, shell-enum, bool and fork-only check the values in the table above.

What to do next

  1. Decide where the skill will run. If it must also upload to claude.ai or the API, use only the six portable fields.
  2. Put --- on line 1 and quote any description that contains a colon.
  3. Write the description in the third person, with what the skill does and a "Use when…" sentence, inside 1,024 characters.
  4. If you need a Claude Code-only field, keep that skill in .claude/skills/<name>/SKILL.md or ~/.claude/skills/<name>/SKILL.md rather than uploading it.
  5. Paste the file into Kanon with the matching target and fix every error before you ship it.