File formats

This page lists the files SkillCatalog reads, their fields, and the rules and limits it enforces. skc validate --path <folder> checks a catalog folder against these rules, and skc validate --manifest checks the team manifest in the current folder. JSON schemas describe the same shapes for editors and other tools. See skillcatalog.dev/schemas/index.json.

Skill folders

Each skill is a folder, skills/<slug>/, named after the skill's slug. It holds a SKILL.md and any companion files: every other file in the folder, such as a template or a script.

skills/
  review-checklist/
    SKILL.md
    templates/
      review-comment.md

SKILL.md starts with YAML front matter between two --- lines, followed by the Markdown body. Its schema is skill-frontmatter.schema.json.

---
name: review-checklist
description: Checklist for reviewing a pull request at Acme. Use when reviewing code changes.
metadata:
  skillcatalog/category: quality
  skillcatalog/owner: platform
  skillcatalog/tags: '["review"]'
---

# Review checklist

1. Read the pull request description.
2. Check that tests cover the change.
3. Use the comment template in @skill-dir/templates/review-comment.md.
FieldRequiredRules
nameYesThe folder name, at most 64 bytes.
descriptionYesWhat the skill does and when to use it. At most 500 characters and 1,024 bytes.
licenseNoFree text.
compatibilityNoFree text, at most 500 bytes.
allowed-toolsNoFree text, delivered as written.
metadataNoA map of text values. Keys that start with skillcatalog/ are reserved and listed below. Other keys are free, and values such as true or 3 are kept as text.

SkillCatalog ignores other top-level fields. It does not deliver them, and the desktop app removes them when it saves the skill.

Metadata keyValue
skillcatalog/display_nameThe name SkillCatalog shows. Without it, SkillCatalog uses the first level-one heading of the body, then the slug in title case.
skillcatalog/categoryThe slug of a category in catalog.yaml.
skillcatalog/ownerThe slug of an owner in catalog.yaml.
skillcatalog/authorFree text, at most 500 characters.
skillcatalog/tagsA JSON array of tag slugs written as a YAML string, such as '["review", "security"]'. Each tag must be defined in catalog.yaml.
skillcatalog/created_at, skillcatalog/updated_atRFC 3339 timestamps, such as 2026-09-23T09:00:00Z. updated_at cannot be earlier than created_at. Without them, SkillCatalog uses the file's times.
skillcatalog/validationContent checks to turn off (false) or on (true) for this skill: a JSON object written as a YAML string, such as '{"validation.body.too-long": false}'. It wins over the catalog's validation map. See Content checks.

Any other key that starts with skillcatalog/ is an error. The body can be empty and is at most 1 MiB (1,048,576 bytes).

Each delivered SKILL.md gets new front matter with name, description, license, compatibility, allowed-tools, and metadata. In that copy only, SkillCatalog fills in skillcatalog/display_name, skillcatalog/created_at, and skillcatalog/updated_at when the source lacks them. Delivery also replaces two tokens in the body of SKILL.md, not in companion files:

TokenDelivered as
@skill:<slug>The path of that skill's SKILL.md for the same tool and profile. In the Home profile's Claude Code copy, that is ~/.claude/skills/<slug>/SKILL.md; in a project profile, an absolute path.
@skill-dirThe absolute path of this skill's delivered folder, such as /Users/dana/.claude/skills/review-checklist.

SkillCatalog recognizes @skill:<slug> at the start of the body, after a space, tab, or line break, and right after one of (, [, {, ", ', <, code blocks included. After any other character, such as a backtick or the * of bold text, the text stays as written and is not checked. skc validate reports a reference to a skill that the catalog does not have, and a skill that refers to itself.

SkillCatalog replaces @skill-dir wherever no letter, digit, -, or _ touches it, even inside backticks, so @skill-directory and user@skill-dir stay as written. See Refer to other skills.

To write either token as text, put a backslash before it: \@skill-dir and \@skill:<slug>. Delivery removes the backslash and replaces nothing, so the delivered copy shows @skill-dir and @skill:<slug>, and skc validate does not check an escaped reference. A backslash before any other text stays as written.

Delivery copies companion files byte for byte and keeps their executable bit. It never copies a symbolic link: when a skill folder holds one anywhere, delivery withholds that skill, leaves its delivered files as they are, delivers the other skills, and reports the skill as failed. skc validate reports the link as an error. See A skill folder holds a symbolic link.

A special file, such as a named pipe, or a file over 10 MiB in a skill folder stops the whole delivery run until you remove it, and skc validate reports neither. Delivery skips these files:

SkippedWhere
SCORE.json, the skill's score historyAt the top of the skill folder
.DS_Store, and file names that end in .pyc, .pyo, .pyd, .swp, or ~Anywhere in the skill folder
Everything inside a folder named .git, node_modules, or __pycache__Anywhere in the skill folder
Files and folders that Git ignores in the catalog cloneAnywhere in the skill folder

If Git ignores the SKILL.md itself, delivery stops with an error. See Add scripts and other companion files.

Stack files

A stack is a file stacks/<slug>.yaml. SkillCatalog reads only files that end in .yaml and skips a .yml file without a message. The file holds front matter between --- lines, then a YAML body with the list of skills. Its schema is stack.schema.json.

---
name: Code review
description: Skills for reviewing Acme pull requests.
author: Dana Reyes
owner: platform
tags: [review]
created_at: 2026-09-23T09:00:00Z
updated_at: 2026-09-23T09:00:00Z
---
skills:
  - review-checklist
  - review-security
FieldRequiredRules
nameNoThe display name, at most 500 characters. Without it, the slug.
descriptionYesAt most 500 characters.
authorYesFree text, at most 500 characters.
created_at, updated_atYesRFC 3339 timestamps. updated_at cannot be earlier than created_at.
ownerNoThe slug of an owner in catalog.yaml.
tagsNoA YAML list of tag slugs defined in catalog.yaml.
skills (in the body)YesThe skills, in order: slugs of skills in the same catalog, at least one, no duplicates.

When a skill in the stack refers to another skill with @skill:, that skill must be in the stack too. Other fields are ignored.

Bundle files

A bundle is a file bundles/<slug>.yaml with the same layout as a stack. It lists stacks in its body and has no tags. Its schema is bundle.schema.json.

---
name: Reviewers
description: Everything an Acme reviewer needs.
author: Dana Reyes
created_at: 2026-09-23T09:00:00Z
updated_at: 2026-09-23T09:00:00Z
---
stacks:
  - code-review

name, description, author, owner, created_at, and updated_at follow the stack rules. stacks lists stacks of the same catalog: at least one, no duplicates. Each of those stacks must include, on its own, every skill that its skills refer to.

A skill, a stack, and a bundle in one catalog cannot share a slug. See Group skills into stacks and bundles.

catalog.yaml

catalog.yaml sits at the root of a catalog. Its schema is catalog.schema.json.

id: acme-skills
name: Acme Skills
description: Review and release skills for Acme engineers.
taxonomy:
  categories:
    - slug: quality
      name: Quality
      children:
        - slug: security
          name: Security
  owners:
    - slug: platform
      name: Platform team
  tags: [review, release]
validation:
  validation.body.too-long: false
metrics_url: http://metrics.acme.internal:9090/api/v1/otlp/v1/metrics
FieldRequiredRules
idYesThe catalog id: a slug of 2 to 64 characters. Profiles and manifests refer to the catalog by it.
nameYesThe display name, at most 500 characters.
descriptionNoAt most 500 characters.
taxonomyNoThe categories, owners, and tags that skills, stacks, and bundles may use.
validationNoContent checks to turn off (false) or on (true) for every skill in the catalog. See Content checks.
metrics_urlNoThe metrics address that receives anonymous usage counts from everyone who has the catalog and has usage metrics on. The rules are below the table.

In taxonomy, each category and owner has a slug and a name, and may have children one level deep. Slugs cannot repeat within categories or within owners.

tags is a list of names, and each name becomes a slug: Code Review becomes code-review. Two names cannot give the same slug, and skills and stacks refer to tags by slug. SkillCatalog ignores other keys, including categories, owners, or tags placed outside taxonomy.

A metrics_url is valid when it starts with http:// or https://, names a host, has a path that ends in /v1/metrics, has no user name, password, query, fragment, or surrounding spaces, and is at most 2,048 bytes. A blank value, null, or no key means the catalog has no address. SkillCatalog ignores any other value, such as a list or an address that breaks a rule: the catalog stays readable, no counts are sent for it, and skc validate --path warns about it. See Collect usage counts for your catalog.

A catalog also needs a skills/ folder next to catalog.yaml. Git does not keep empty folders, so keep a file such as .gitkeep in it. A registered catalog whose clone lacks skills/ cannot be read. stacks/ and bundles/ are optional: a missing one counts as empty. When present, none of the three can be a symbolic link or a file. README.md is optional.

Content checks

skc validate runs these four checks on every skill:

CheckWhat it findsLevel
validation.body.too-longA SKILL.md body over 500 linesWarning
validation.reference.depth-too-deepA link from SKILL.md to a file more than one folder downWarning
validation.reference.missing-tocA linked Markdown file over 200 lines without a contents headingWarning
validation.time-sensitive.outside-old-patternsA date, an "as of", or a version pin such as v1.2.3 in prose, outside sections headed Old patterns, History, Historical, or DeprecatedInfo

All four run by default. false turns a check off, and true turns it back on for a skill in a catalog that turned it off. A skill's skillcatalog/validation metadata wins over the catalog's validation map. An unknown check id makes catalog.yaml unreadable, and a skill with one fails skc validate.

skc validate also runs validation.conflict-markers, which cannot be turned off. It reports an error for a leftover Git conflict block in a SKILL.md: a <<<<<<< line, then a ======= line, then a >>>>>>> line, each marker at the start of its line. A <<<<<<< line inside a fenced code block starts no block, so marker examples belong in fenced code, and a real conflict inside a fenced code block goes unreported. The check reads only SKILL.md, not companion files. See A commit stops on leftover conflict markers.

See Check a skill before you share it.

Team manifest

The team manifest is .skillcatalog/skillcatalog.yml in a repository. It lists the entries that repository wants for everyone. Its schema is skillcatalog-yml.schema.json.

profile:
  id: payments-api
  display_name: Payments API
catalogs:
  acme-skills:
    source: git@github.com:acme/acme-skills.git
entries:
  - catalog_id: acme-skills
    kind: skill
    slug: release-notes
FieldRequiredRules
profile.idYesThe project profile id: a slug other than home.
profile.display_nameYesAt most 500 characters.
catalogsWhen entries is not emptyA map from catalog id to source. Each key must equal the id in that catalog's catalog.yaml.
catalogs.<catalog-id>.sourceYesThe catalog's remote Git URL. Each URL can appear once. SkillCatalog compares it with the registered URL as text, so SSH and HTTPS forms of one repository do not match. See Names and limits.
entriesYesThe skills, stacks, and bundles to deliver, in order; the list can be empty. Each entry has catalog_id (a key of catalogs), kind (skill, stack, or bundle), and slug. The same entry cannot appear twice.

Unknown keys make the manifest invalid. SkillCatalog also reads a skillcatalog.yml at the repository root when .skillcatalog/skillcatalog.yml does not exist. When both exist, skc install, skc update, and skc update --check fail. skc init refuses to write when either file exists.

skc init writes this file from its flags. It pairs each --source with the --catalog-id in the same position. A --catalog-id without a paired --source uses the URL registered for that catalog. See Add skills to a team manifest.

Local manifest

The local manifest is .skillcatalog/skillcatalog.local.yml: your own additions and exclusions for one checkout. SkillCatalog adds it to the checkout's .gitignore when it first writes it. Every key is optional. Its schema is skillcatalog-local-yml.schema.json.

catalogs:
  acme-skills:
    source: git@github.com:acme/acme-skills.git
entries:
  - catalog_id: acme-skills
    kind: stack
    slug: code-review
excludes:
  - catalog_id: acme-skills
    kind: skill
    slug: release-notes
FieldRules
catalogsAs in the team manifest. An entry here must use a catalog declared in this file, even when the team manifest declares it too. When both files declare a catalog id, the URLs must be the same.
entriesAs in the team manifest.
excludesTeam manifest entries to leave out of delivery, with the same three keys. An exclusion needs no catalog declaration.
profileOptional. When present, it follows the team manifest's rules.

Unknown keys make the file invalid. A skillcatalog.local.yml at the repository root is read when this file does not exist. Both at once is an error. See Make personal changes.

settings.toml

~/.skillcatalog/settings.toml holds your settings. SkillCatalog creates it when you first change a setting, and you may edit it by hand. SkillCatalog ignores keys it does not know and keeps them when it saves the file.

[targets.claude_code]
enabled = true

[targets.cursor]
enabled = false

[targets.codex]
enabled = false

[scoring.enabled_providers.claude-code-local]
enabled = true
model = "sonnet"
effort = "high"

[proposals]
archive_retention_days = 30
remote_only_discovery_cap = 200

[telemetry]
enabled = false
KeyDefaultMeaning
targets.claude_code.enabled, targets.cursor.enabled, targets.codex.enabledfalseWhether SkillCatalog delivers to Claude Code, Cursor, and Codex. skc settings enable <tool> and skc settings disable <tool> set them.
scoring.enabled_providers.<provider-id>.enabledfalseWhether an AI provider may score skills. The ids are claude-code-local and codex-local.
scoring.enabled_providers.<provider-id>.modelNoneThe model name passed to the provider's tool.
scoring.enabled_providers.<provider-id>.effortNoneThe effort level. Each provider accepts its own values. skc scoring providers set-effort lists them when you give another one.
proposals.archive_retention_days30Days SkillCatalog keeps records of proposals that are merged, closed, or discarded.
proposals.remote_only_discovery_cap200The most proposal branches without a record on this machine that one listing shows.
telemetry.enabledtrueWhether SkillCatalog sends usage counts to the metrics addresses that your catalogs name. skc settings telemetry --enable and --disable set it. See Stop sending usage counts.
onboarding_completedfalseWhether the desktop app's first-launch setup finished.

A [proposals] table must hold both of its keys, because with only one, every command that reads settings fails. SkillCatalog ignores a theme key.

The desktop app opens two kinds of skc:// links. Values in a link are URL-encoded. A fragment, a repeated parameter, or a parameter not listed here makes a link invalid.

LinkParameters
skc://catalog/add?source=<url>&name=<name>source (required): the catalog's remote Git URL. name (optional): the name the confirmation shows, 2 to 100 characters, without line breaks, /, \, or null characters, and not . or ... Without it, the app shows the repository name.
skc://share/install?v=1&kind=<kind>&catalog_id=<catalog-id>&slug=<slug>&source=<url>All required. v: 1. kind: skill, stack, or bundle. catalog_id: the catalog id. slug: the item's slug. source: the catalog's remote Git URL.

For example, these links add the Acme catalog and install its review checklist:

skc://catalog/add?source=git%40github.com%3Aacme%2Facme-skills.git&name=Acme%20Skills
skc://share/install?v=1&kind=skill&catalog_id=acme-skills&slug=review-checklist&source=git%40github.com%3Aacme%2Facme-skills.git

The desktop app makes share links for skills, stacks, and bundles. No command makes catalog links, so write them yourself. See Share with a link.

Names and limits

NameRule
Slug: skill, stack, bundle, category, owner, tag, profile idLowercase letters, digits, and hyphens, 1 to 128 characters. It starts with a letter or digit, and has no hyphen at the end and no two hyphens in a row.
Catalog idA slug of 2 to 64 characters.
Skill nameEqual to the skill's folder name; at most 64 bytes.
Names, display names, and descriptionsNot empty; at most 500 characters.
Remote Git URL, in skc catalog add, manifests, and linksgit@<host>:<path>, or a URL that starts with ssh://, http://, or https://. No spaces, passwords, tokens, query strings, or fragments, and no user name in an http:// or https:// URL. Local paths and file:// URLs are refused.
Commit message for skc syncNot empty; at most 1,000 bytes after trimming.
File limitValue
SKILL.md body1 MiB (1,048,576 bytes)
Any other file in a catalog, including companion files10 MiB
Path inside a catalog4,096 bytes, with at most 32 parts of up to 255 bytes each
Entries in one folder4,096

Reading a symbolic link, a special file, or a file with more than one hard link inside a catalog fails.