Skip to content

Composition & Include Resolution Specification ​

Status: Stable Spec Version: 1 Last Updated: 2026-03-20

This document specifies how skill includes are resolved during composition.

1. Include Syntax ​

Skills declare dependencies via the includes frontmatter field:

yaml
includes: [base-instructions, coding-standards]

Each entry is a slug referencing another skill in the same project.

2. Resolution Algorithm ​

When a skill is resolved, its includes are processed in array order:

resolve(skill, visited=[], depth=0):
  1. If depth > MAX_DEPTH (5):
       Return "<!-- Include depth limit exceeded -->\n\n" + skill.body
  2. If skill.includes is empty:
       Return skill.body
  3. Add skill.slug to visited
  4. For each slug in skill.includes:
     a. If slug is in visited:
          Append "<!-- Circular include skipped: {slug} -->"
          Continue to next
     b. Look up skill by slug in the same project
     c. If not found:
          Append "<!-- Include not found: {slug} -->"
          Continue to next
     d. Recursively resolve the included skill:
          Append resolve(included_skill, visited, depth + 1)
  5. Append skill.body
  6. Join all sections with "\n\n", filtering empty strings
  7. Return joined result

3. Resolution Order ​

Included content is prepended before the skill's own body. Given:

skill A includes [B, C]

The resolved output is:

{resolved body of B}

{resolved body of C}

{body of A}

This means base/shared instructions come first, and the skill's specific instructions come last — allowing the skill to override or specialize shared rules.

4. Max Depth ​

Implementations MUST enforce a maximum include depth of 5 levels. When the depth limit is exceeded, implementations MUST:

  1. Stop recursing.
  2. Include the current skill's body without further resolution.
  3. Insert a comment: <!-- Include depth limit exceeded -->.

5. Circular Dependency Detection ​

Circular dependencies occur when skill A includes B, which includes C, which includes A.

Implementations MUST detect circular dependencies by tracking visited slugs during resolution. When a circular dependency is detected:

  1. The circular include MUST be skipped.
  2. A comment MUST be inserted: <!-- Circular include skipped: {slug} -->.
  3. Resolution MUST continue with remaining includes (do not abort).

5.1 Validation ​

Implementations SHOULD provide a validation function that detects cycles before resolution:

detectCycles(skill, path=[skill.slug], errors=[]):
  For each slug in skill.includes:
    If slug is in path:
      errors.push("Circular dependency: " + path.join(" -> ") + " -> " + slug)
      Continue
    Look up included skill
    If found and included.includes is non-empty:
      detectCycles(included, [...path, slug], errors)

6. Missing Includes ​

When a referenced slug does not exist in the project:

  1. The missing include MUST be skipped.
  2. A comment MUST be inserted: <!-- Include not found: {slug} -->.
  3. Implementations SHOULD emit a warning to stderr or the lint output.
  4. Resolution MUST continue with remaining includes.

7. Self-Include ​

A skill MUST NOT include itself. If skill.includes contains the skill's own slug:

  1. Implementations MUST treat it as a circular dependency.
  2. The self-include MUST be skipped with the circular include comment.

8. Diamond Dependencies ​

If skill A includes B and C, and both B and C include D, then D's body appears twice in the resolved output. This is the expected behavior — implementations MUST NOT deduplicate included content.

Rationale: Deduplication would require tracking content identity across the resolution tree, adding complexity without clear benefit. Skill authors should structure includes to avoid unintended duplication.

9. Cross-Project Includes ​

Includes MUST be resolved within the same project only. Cross-project references are NOT supported. An include slug that does not match any skill in the current project MUST be treated as a missing include (Section 6).

10. Include Resolution Timing ​

Include resolution happens at sync time and test time, not at edit time. The raw includes array is stored in frontmatter and resolved on demand.

Released under the MIT License.