Skill Overlays Guide¶
Learn how to extend, customize, and govern skills across multiple registry layers using @extend with skill-aware merge semantics.
Overview¶
In multi-layer architectures (company → product → BU → project), each layer may need to customize skills defined by a lower layer without replacing them entirely. Skill overlays allow higher layers to:
- Replace properties like
contentordescription - Append to
referencesandrequireslists - Merge parameter and contract definitions
- Negate specific entries from lower layers
- Seal properties to prevent overrides
Basic Overlay¶
Import a base skill and extend it:
@use @company/skills as base
@extend base.skills.code-review {
description: "Code review with stricter security checks"
content: """
Enhanced review workflow for the security team.
"""
}
Resolution Order¶
When multiple @use and @extend declarations target the same skill, priority is determined by declaration order in the .prs file:
@usedeclarations are processed top-to-bottom — later imports override earlier ones for block name conflicts@extendblocks are applied sequentially — later extends override earlier ones for replace-strategy properties, and append to earlier ones for append-strategy properties
@use @bu-retail/skills as retail
@use @bu-travel/skills as travel
# Applied in order: retail first, travel second
@extend retail.skills.code-review {
description: "Retail review"
references: ["retail-patterns.md"]
}
@extend travel.skills.code-review {
description: "Travel review" # wins (later replace)
references: ["travel-patterns.md"] # appended after retail
}
Result: description = "Travel review" (last replace wins), references includes both retail-patterns.md and travel-patterns.md (append accumulates).
Rule of thumb: put the highest-priority registry's @extend last in the file.
Merge Strategies¶
When @extend targets a skill, each property follows a specific merge strategy:
| Strategy | Properties | Behavior |
|---|---|---|
| Replace | content, description, trigger, userInvocable, allowedTools, disableModelInvocation, context, agent | Extension value wins outright |
| Append | references, requires | Extension entries added to base |
| Shallow merge | params, inputs, outputs | Extension keys added/overwritten |
Replace Example¶
@extend base.skills.deploy {
content: """
New deployment workflow replacing the base.
"""
allowedTools: ["Bash", "Read", "Write"]
}
The overlay's content and allowedTools completely replace the base values.
Append Example¶
@extend base.skills.architecture-review {
references: [
"references/bu-architecture.md"
"references/bu-modules.md"
]
requires: ["security-scan"]
}
The overlay's references and requires are appended to the base lists (deduplicated).
Shallow Merge Example¶
@extend base.skills.code-review {
inputs: {
severity: {
description: "Minimum severity"
type: enum
options: [low, medium, high]
}
}
}
New input fields are added to the base. Existing fields with the same key are overwritten.
Reference Negation¶
Use the ! prefix to remove entries from a lower layer's append-strategy arrays:
@extend base.skills.code-review {
references: [
"!references/deprecated-patterns.md"
"references/new-patterns.md"
]
requires: [
"!legacy-tool"
"modern-tool"
]
}
Path Matching¶
Negation uses normalized path matching — "!./references/foo.md" matches "references/foo.md". Paths are compared after stripping ./, resolving ../, and collapsing //.
Unmatched Negations¶
If a negation doesn't match any base entry, a warning is logged during compilation:
This usually means the base skill was updated and the entry you're negating no longer exists. Remove the negation or update it to match the current base.
Rules¶
- Negation only works in
@extendblocks — using!in a base skill definition triggers validator warning PS028 - Only applies to append-strategy properties (
references,requires) - Multiple negations in the same array are supported
Sealed Properties¶
The sealed property prevents higher layers from replacing specified skill properties:
@skills {
deploy: {
description: "Production deployment workflow"
content: """
Critical deployment procedure — do not modify.
"""
sealed: ["content", "description"]
}
}
Boolean Shorthand¶
sealed: true seals all replace-strategy properties at once:
@skills {
compliance-check: {
description: "Compliance verification"
content: """..."""
sealed: true
}
}
Enforcement¶
If an @extend block attempts to override a sealed property, compilation fails:
Rules¶
- Only replace-strategy properties can be sealed — append-strategy properties (
references,requires) remain extendable even whensealed: true - Only the base skill author can set
sealed— overlays cannot add or modify it sealedis a hard error, not a warning — the overlay must remove the conflicting override- Validator PS029 warns when
sealedcontains non-replace-strategy property names
Multi-Layer Example¶
A 4-layer enterprise architecture:
Layer 1: @company — organization-wide skill definitions
Layer 2: @product — product-specific customizations
Layer 3: @bu — business unit references and context
Layer 4: project — local project overrides
Layer 1: Company Base¶
# @company/skills/code-review.prs
@meta { id: "@company/code-review" syntax: "1.1.0" }
@skills {
code-review: {
description: "Standard code review"
content: """
Review code for quality, security, and maintainability.
"""
references: ["references/company-standards.md"]
requires: ["lint-check"]
sealed: ["content"]
}
}
Layer 2: Product Overlay¶
# @product/skills/code-review.prs
@meta { id: "@product/code-review" syntax: "1.1.0" }
@use @company/skills/code-review as base
@extend base.skills.code-review {
description: "Product-specific code review"
references: ["references/product-patterns.md"]
}
Layer 2 replaces description (allowed), appends to references, but cannot replace content (sealed by Layer 1).
Layer 3: BU Overlay¶
# @bu/skills/code-review.prs
@meta { id: "@bu/code-review" syntax: "1.1.0" }
@use @product/skills/code-review as base
@extend base.skills.code-review {
references: [
"!references/product-patterns.md"
"references/bu-architecture.md"
"references/bu-modules.md"
]
requires: ["security-scan"]
}
Layer 3 removes a Layer 2 reference via negation, adds BU-specific references, and appends a new requirement.
Composed Result¶
description: "Product-specific code review" ← Layer 2 (replaced)
content: (Layer 1 original — sealed) ← Layer 1 (protected)
references:
- references/company-standards.md ← Layer 1
- references/bu-architecture.md ← Layer 3
- references/bu-modules.md ← Layer 3
requires:
- lint-check ← Layer 1
- security-scan ← Layer 3
Debugging with prs inspect¶
Use prs inspect to see how layers compose a skill:
# Property-level view (default) — shows each property with source
prs inspect code-review
# Layer-level view — groups changes by source file
prs inspect code-review --layers
# JSON output for tooling
prs inspect code-review --format json
The property view shows each property's current value, merge strategy, and which file contributed it. The layer view shows what each @extend changed, using symbols: + added, ~ replaced, - negated.
Governance: Managing Multi-Layer Skills¶
When skills span multiple registry layers, structural changes in a base skill can break overlays that depend on its content. PromptScript provides tooling to detect and prevent problems, but organizational process is equally important.
Preventing Breakage¶
Seal critical properties. If a base skill's content should never be replaced by overlays, seal it:
@skills {
code-review: {
content: """
Critical review workflow — protected from overrides.
"""
sealed: ["content"]
}
}
This ensures no @extend can silently replace the core instructions.
Use references instead of inline content. Rather than putting all context in content, move supplementary information to references files. Overlays can then append, negate, or replace individual reference files without touching the sealed content:
@skills {
code-review: {
content: """
Core review workflow (sealed).
"""
references: ["references/patterns.md", "references/standards.md"]
sealed: ["content"]
}
}
Detecting Problems After Base Updates¶
Use prs inspect after updating a base registry. When a base skill changes, run inspect on each overlay skill to verify the layer composition still makes sense:
# After pulling a registry update
prs pull
# Check how the overlay composes with the updated base
prs inspect code-review --layers
Look for:
- Properties that were previously from the base but are now missing
- Reference files that may no longer match the base skill's context
- Unexpected changes in the layer count
Use prs diff to see compilation changes. After pulling updates, compare the compiled output against the previous version:
This shows exactly what changed in the final output, making it easy to spot when a base update broke an overlay.
Organizational Best Practices¶
Version your registry skills. Use a version field in skill descriptions to communicate breaking changes:
@skills {
code-review: {
description: "Code review v2.0 — restructured workflow"
content: """..."""
}
}
When you make breaking changes (removing sections, restructuring content, changing property types), bump the version in the description and communicate via your team's changelog.
Maintain a registry changelog. Keep a CHANGELOG.md at the root of each registry documenting skill changes:
# @company Registry Changelog
## 2026-04-01 — v2.0.0
### Breaking
- code-review: removed "## Legacy Patterns" section
- code-review: restructured workflow into 3 phases (was 5)
### Added
- code-review: sealed content property
- deploy: new skill for deployment workflows
Coordinate between layers. When Layer 2 maintains a skill that Layer 3 extends:
- Layer 2 communicates planned breaking changes before deploying
- Layer 3 runs
prs inspect --layersto verify compatibility - Both layers use
prs diffin CI to detect unexpected changes
Test overlays in CI. Add a CI step that compiles the overlay project and verifies the output is valid:
# .github/workflows/validate-overlay.yml
- run: prs validate --strict
- run: prs compile --dry-run
- run: prs inspect code-review --format json | jq '.sealed'
When Things Break¶
If an overlay becomes incompatible after a base update:
- Run
prs inspect skill-name --layersto see the current layer composition - Check sealed properties — if the base added
sealedto a property your overlay was overriding, you'll get a compilation error with a clear message - Check references — use negation (
!path) to remove references that no longer apply, and add new ones that match the updated base - Review the base changelog — look for breaking changes that affect your overlay
- Consider using
sealedin your overlay to protect properties from further changes by downstream layers
Overlay Consistency Warnings¶
The resolver emits warnings during compilation when an overlay becomes structurally inconsistent with its base. These warnings help detect drift after a Layer 2 update. They are always shown — no --verbose flag required.
Orphaned extend — @extend targets a block that doesn't exist:
@extend target "base.skills.code-review" not found — overlay will be ignored.
If the base skill was removed or renamed, update or remove this @extend block.
This means the overlay is silently dropped. Either update the path or remove the @extend.
Stale skill target — @extend creates a new skill in @skills that the base doesn't define:
@extend creates new skill "deploy-prod" — base does not define it.
If this was an overlay targeting an existing skill, verify the base still defines "deploy-prod".
This usually means the base renamed or removed the skill. The overlay accidentally creates a new skill rather than extending an existing one.
Negation orphan — see Unmatched Negations above.
Validation Rules¶
| Rule | Name | Description |
|---|---|---|
| PS025 | valid-skill-references | Reference paths must use allowed extensions and exist on disk |
| PS026 | safe-reference-content | Reference files must not contain PRS directives (prompt injection risk) |
| PS028 | valid-append-negation | ! prefix is only effective in @extend blocks |
| PS029 | valid-sealed-property | Sealed property names must be replace-strategy properties |
Note: The overlay consistency warnings above are emitted by the resolver, not the validator. They appear during
prs compile(always shown, not gated by--strict), while validator warnings (PS0XX) appear duringprs validate.