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:
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 result3. 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:
- Stop recursing.
- Include the current skill's body without further resolution.
- 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:
- The circular include MUST be skipped.
- A comment MUST be inserted:
<!-- Circular include skipped: {slug} -->. - 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:
- The missing include MUST be skipped.
- A comment MUST be inserted:
<!-- Include not found: {slug} -->. - Implementations SHOULD emit a warning to stderr or the lint output.
- Resolution MUST continue with remaining includes.
7. Self-Include
A skill MUST NOT include itself. If skill.includes contains the skill's own slug:
- Implementations MUST treat it as a circular dependency.
- 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.