# How the Skill Shadowing Mechanism Works in Superpowers

> Discover how Superpowers skill shadowing works. Learn how personal skills override core skills and how the superpowers prefix enforces core directory lookups for a seamless development experience.

- Repository: [Jesse Vincent/superpowers](https://github.com/obra/superpowers)
- Tags: internals
- Published: 2026-02-16

---

**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](https://github.com/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`](https://github.com/obra/superpowers/blob/main/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`](https://github.com/obra/superpowers/blob/main/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:`:

```javascript
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:

```javascript
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`](https://github.com/obra/superpowers/blob/main/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:

```javascript
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:

```javascript
// 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:

```javascript
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:

```javascript
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`](https://github.com/obra/superpowers/blob/main/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`](https://github.com/obra/superpowers/blob/main/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`](https://github.com/obra/superpowers/blob/main/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`](https://github.com/obra/superpowers/blob/main/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`](https://github.com/obra/superpowers/blob/main/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.