How the Skill Shadowing Mechanism Works in Superpowers

Superpowers uses a shadowing system where personal skills automatically override core skills with identical names, while the superpowers: prefix forces core directory lookups.

The skill shadowing mechanism in the obra/superpowers repository allows developers to customize built-in functionality without modifying the core codebase. By placing a skill in your personal directory with the same name as a core skill, you override the default behavior while maintaining the ability to fall back to the original implementation when needed.

What Is Skill Shadowing in Superpowers?

Superpowers loads skills from two distinct locations:

  • Core directory – The built-in collection of reusable skills shipped with the framework
  • Personal directory – Your own skill folder that customizes or extends the core set

When you request a skill by name, the system checks your personal directory first. If a SKILL.md file exists there, Superpowers uses your version and ignores the core equivalent. This shadowing behavior ensures that personal customizations take precedence without requiring changes to the core repository.

How the resolveSkillPath Function Implements Skill Shadowing

The shadowing logic lives in lib/skills-core.js within the resolveSkillPath function (lines 108–139). This utility determines which physical file path to load based on the requested skill name and available directories.

Step 1: Detecting Explicit Core Requests

The function first checks whether you explicitly requested a core skill by prefixing the name with superpowers::

const forceSuperpowers = skillName.startsWith('superpowers:');
const actualSkillName = forceSuperpowers 
  ? skillName.replace(/^superpowers:/, '') 
  : skillName;

If the prefix is present, the lookup bypasses your personal directory entirely and searches only the core location.

Step 2: Checking the Personal Directory

When no prefix forces the core lookup, the function examines your personal folder:

if (!forceSuperpowers && personalDir) {
  const personalSkillFile = path.join(personalDir, actualSkillName, 'SKILL.md');
  if (fs.existsSync(personalSkillFile)) {
    return {
      skillFile: personalSkillFile,
      sourceType: 'personal',
      skillName: actualSkillName
    };
  }
}

If SKILL.md exists in your personal directory, the function returns that path immediately. This is the skill shadowing mechanism in action—your personal version shadows the core implementation.

Step 3: Falling Back to the Core Directory

If no personal version exists (or if the superpowers: prefix was used), the function checks the core directory:

if (superpowersDir) {
  const superpowersSkillFile = path.join(superpowersDir, actualSkillName, 'SKILL.md');
  if (fs.existsSync(superpowersSkillFile)) {
    return {
      skillFile: superpowersSkillFile,
      sourceType: 'superpowers',
      skillName: actualSkillName
    };
  }
}

If found, the core skill is returned. If neither location contains the skill, the function returns null.

Code Examples: Skill Shadowing in Practice

Personal Skill Shadows Core Skill

When you create a custom version of a built-in skill:

// Directory structure:
//   ~/personal-skills/hello-world/SKILL.md    (your custom version)
//   /usr/lib/superpowers/skills/hello-world/SKILL.md  (core version)

const resolved = resolveSkillPath('hello-world', superpowersDir, personalDir);
// Result:
// {
//   skillFile: "~/personal-skills/hello-world/SKILL.md",
//   sourceType: "personal"
// }

Your personal hello-world skill shadows the core implementation.

Forcing the Core Implementation

To bypass your personal shadow and use the original core skill:

const forced = resolveSkillPath('superpowers:hello-world', superpowersDir, personalDir);
// Result:
// {
//   skillFile: "/usr/lib/superpowers/skills/hello-world/SKILL.md",
//   sourceType: "superpowers"
// }

The superpowers: prefix forces the lookup to the core directory regardless of personal overrides.

Handling Non-Existent Skills

When requesting a skill that exists in neither location:

const missing = resolveSkillPath('nonexistent-skill', superpowersDir, personalDir);
// Result: null

The function returns null, allowing the caller to handle the missing skill appropriately.

These scenarios are verified by the test suite in tests/opencode/test-skills-core.sh (lines 19–53), which validates that personal skills correctly shadow core implementations and that the superpowers: prefix functions as expected.

Summary

  • The skill shadowing mechanism allows personal skills to override core skills with identical names automatically.
  • The resolveSkillPath function in lib/skills-core.js (lines 108–139) implements the lookup logic using a personal-first, core-second priority.
  • Prefixing a skill name with superpowers: bypasses shadowing and forces the system to load the core version exclusively.
  • Shadowing requires only placing a SKILL.md file in your personal skills directory; no configuration changes are needed.

Frequently Asked Questions

What happens if a personal skill has the same name as a core skill?

Superpowers automatically uses the personal version. When resolveSkillPath detects a SKILL.md file in your personal directory, it returns that path immediately without checking the core directory. This shadowing behavior ensures your customizations take precedence over built-in defaults.

How do I force Superpowers to use the core version of a skill?

Prefix the skill name with superpowers: when calling resolveSkillPath. For example, requesting superpowers:hello-world strips the prefix and searches only the core directory, bypassing any personal skill that might shadow it. This explicit namespace ensures you can always access the original implementation.

Where is the skill shadowing logic implemented in the codebase?

The shadowing mechanism lives in lib/skills-core.js within the resolveSkillPath function, specifically lines 108 through 139. This function handles the priority logic: checking for the superpowers: prefix, looking up personal skills first, and falling back to core skills when necessary.

Can I disable skill shadowing entirely?

No, shadowing is an integral part of the Superpowers resolution system and cannot be globally disabled. However, you can effectively bypass it on a per-call basis by using the superpowers: prefix to force core directory lookups. If you need to prevent specific skills from being shadowed, ensure no identically-named directories exist in your personal skills folder.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →