# How Skills Are Discovered Recursively in Superpowers: A Deep Dive into the Filesystem Scanner

> Discover how Superpowers recursively finds skills by scanning the filesystem up to three levels deep, parsing SKILL.md files to build a capability catalog.

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

---

**Superpowers discovers skills by recursively walking the filesystem up to a depth of three levels, locating every [`SKILL.md`](https://github.com/obra/superpowers/blob/main/SKILL.md) file, and parsing its frontmatter to build a catalog of available capabilities.**

The `obra/superpowers` repository implements a dynamic skill discovery system that eliminates hardcoded lists by scanning directories at runtime. Understanding how skills are discovered recursively in Superpowers is essential for developers extending the agent's capabilities or integrating custom skill repositories.

## The Core Discovery Mechanism in [`lib/skills-core.js`](https://github.com/obra/superpowers/blob/main/lib/skills-core.js)

The entire discovery logic resides in **[`lib/skills-core.js`](https://github.com/obra/superpowers/blob/main/lib/skills-core.js)**, which exports the primary entry point for filesystem traversal and skill metadata extraction.

### Recursive Directory Traversal with `findSkillsInDir`

The `findSkillsInDir(dir, sourceType, maxDepth = 3)` function initiates a controlled recursive search starting from a specified base directory. The implementation uses an internal `recurse` helper that iterates over directory entries, descends into subdirectories, and enforces the depth limit to prevent infinite recursion or excessive filesystem traversal.

The default `maxDepth` of **3 levels** provides a balance between discovery thoroughness and performance, ensuring that deeply nested dependency folders or version control directories do not trigger unnecessary scans.

### Skill Detection and Frontmatter Parsing

During the recursive walk, every visited directory is checked for the presence of a **[`SKILL.md`](https://github.com/obra/superpowers/blob/main/SKILL.md)** file. When found, the system invokes `extractFrontmatter` to parse the YAML frontmatter at the top of the markdown file. This metadata includes the skill's display name, description, and configuration parameters.

The parsing logic validates essential fields and normalizes the data before constructing the skill descriptor, ensuring that malformed skill definitions are handled gracefully without interrupting the discovery process.

### The Skill Descriptor Object Structure

Each discovered skill yields a standardized object containing:

- **`path`** – Absolute filesystem path to the skill's containing folder
- **`skillFile`** – Full path to the [`SKILL.md`](https://github.com/obra/superpowers/blob/main/SKILL.md) manifest
- **`name`** – Explicit frontmatter name or fallback to the directory name
- **`description`** – Frontmatter description field (if provided)
- **`sourceType`** – Classification as `'personal'` or `'superpowers'`, indicating the origin repository

The function returns an aggregated array of these descriptors, which serves as the authoritative catalog for the runtime skill selection logic.

## Integration Points and Runtime Usage

The recursive discovery system integrates with the broader Superpowers architecture through bootstrap plugins and runtime API calls.

### Bootstrap Plugin Initialization

The **[`plugins/superpowers.js`](https://github.com/obra/superpowers/blob/main/plugins/superpowers.js)** bootstrap plugin determines the canonical location of the Superpowers skill directory (resolved as `../../skills` relative to the plugin file). During agent initialization, this plugin registers the skill path with the OpenCode environment, preparing the system for dynamic capability loading.

The plugin does not perform the scan itself; rather, it configures the environment so that subsequent calls to the native *skill* tool can trigger the filesystem walk as needed.

### Runtime Skill Catalog Building

When the agent requires knowledge of available capabilities, it invokes `skillsCore.findSkillsInDir(superpowersDir, 'superpowers')` for bundled skills, or the equivalent call with `'personal'` for user-defined extensions. The returned catalog drives the skill-selection logic that determines which capability to invoke based on the current task context.

This deferred discovery pattern ensures that skill manifests are loaded fresh for each session, accommodating changes to the filesystem without requiring agent restarts or code modifications.

## Practical Code Examples

### Directly Invoking the Discovery Function

```javascript
import * as skillsCore from './lib/skills-core.js';
import path from 'path';

// Absolute path to the bundled Superpowers skills folder
const superpowersDir = path.resolve(import.meta.url, '../../skills');

// Discover all Superpowers-provided skills (recursively, up to depth 3)
const allSuperpowers = skillsCore.findSkillsInDir(superpowersDir, 'superpowers');

console.log('Found', allSuperpowers.length, 'Superpowers skills:');
allSuperpowers.forEach(s => console.log(`- ${s.name} (${s.path})`));

```

This returns an array of skill objects representing capabilities such as `brainstorming`, `writing-plans`, and others defined in the repository.

### Merging Personal and Superpowers Skill Sets

```javascript
import * as skillsCore from './lib/skills-core.js';
import path from 'path';

const superpowersDir = path.resolve('../../skills');
const personalDir = path.resolve('~/.config/opencode/skills/personal');

const superSkills = skillsCore.findSkillsInDir(superpowersDir, 'superpowers');
const personalSkills = skillsCore.findSkillsInDir(personalDir, 'personal');

// Personal skills shadow Superpowers ones if names clash
const merged = [...personalSkills];
for (const sp of superSkills) {
  if (!merged.find(s => s.name === sp.name)) merged.push(sp);
}

```

This pattern allows users to override bundled capabilities with custom implementations while maintaining the recursive discovery mechanism for both sources.

### Using the OpenCode Skill Tool Wrapper

```javascript
// Inside an OpenCode agent script
const skills = await skill('list-skills', {
  directory: '/home/user/.config/opencode/skills',
  source: 'superpowers'   // or 'personal'
});
console.log('Available skills:', skills.map(s => s.name));

```

The underlying implementation of `skill('list-skills')` delegates directly to `findSkillsInDir`, providing a high-level API over the recursive filesystem scanner.

## Summary

- **Superpowers discovers skills recursively** by walking the filesystem from a configurable root directory, defaulting to a maximum depth of three levels to balance thoroughness with performance.
- **The core logic resides in [`lib/skills-core.js`](https://github.com/obra/superpowers/blob/main/lib/skills-core.js)**, specifically within the `findSkillsInDir` function, which uses an internal `recurse` helper to traverse directories and identify [`SKILL.md`](https://github.com/obra/superpowers/blob/main/SKILL.md) manifest files.
- **Each discovered skill yields a standardized descriptor object** containing the absolute path, manifest location, name, description, and source type, enabling the runtime to build a unified catalog of capabilities.
- **Integration occurs through [`plugins/superpowers.js`](https://github.com/obra/superpowers/blob/main/plugins/superpowers.js)**, which configures the skill directory path, and through runtime calls to the discovery function that enable dynamic skill loading without hardcoded lists.

## Frequently Asked Questions

### How does Superpowers prevent infinite recursion when scanning for skills?

The `findSkillsInDir` function enforces a default `maxDepth` parameter of **3**, which limits how many directory levels the recursive walker descends. The internal `recurse` helper checks the current depth against this limit before entering subdirectories, ensuring the scanner stops at a reasonable boundary even if the filesystem contains deeply nested structures.

### What file does Superpowers look for to identify a valid skill directory?

Superpowers searches for a file named exactly **[`SKILL.md`](https://github.com/obra/superpowers/blob/main/SKILL.md)** in every directory visited during the recursive walk. When this file is found, the system parses its YAML frontmatter using the `extractFrontmatter` function to extract metadata such as the skill name and description. Directories without a [`SKILL.md`](https://github.com/obra/superpowers/blob/main/SKILL.md) file are skipped and not included in the final skill catalog.

### Can I override the default depth limit for skill discovery?

Yes, the `findSkillsInDir` function accepts an optional third parameter `maxDepth` that defaults to 3. You can pass a higher or lower integer to adjust the search depth according to your directory structure. For example, calling `skillsCore.findSkillsInDir(dir, 'personal', 5)` would scan five levels deep instead of the default three, useful if your skills are organized in a deeply nested taxonomy.

### Where does the recursive skill scanner integrate with the OpenCode runtime?

The discovery mechanism integrates through the **[`plugins/superpowers.js`](https://github.com/obra/superpowers/blob/main/plugins/superpowers.js)** bootstrap module, which resolves the path to the bundled skills directory (`../../skills`) and makes it available to the agent. At runtime, when the agent needs to enumerate capabilities, it invokes `skillsCore.findSkillsInDir` with the configured directory and a `sourceType` of `'superpowers'` or `'personal'`. This deferred execution pattern ensures the filesystem scan occurs fresh for each session, reflecting any changes to skill definitions without requiring a restart.