How Multi-Skill Directories Are Detected and Scanned Independently in SkillSpector

SkillSpector detects multi-skill directories by verifying the absence of a root SKILL.md file alongside the presence of two or more subdirectories each containing their own SKILL.md, then scans each skill independently using the detect_skills function and _scan_multi_skill helper in the NVIDIA/SkillSpector codebase.

SkillSpector, NVIDIA’s open-source skill analysis tool, provides specialized handling for repositories that contain multiple independent skills rather than a single monolithic skill definition. Understanding how the tool differentiates between single-skill and multi-skill hierarchies is essential for CI/CD pipelines and bulk analysis workflows.

Detection Logic in multi_skill.py

The detection mechanism resides in src/skillspector/multi_skill.py, where the public API determines whether a directory represents a collection of independent skills.

The detect_skills Function

The entry point for multi-skill detection is the detect_skills function, which accepts a Path object and returns a MultiSkillDetectionResult. According to the source implementation, this function walks the immediate children of the supplied directory, skipping non-directories and hidden folders, and constructs a list of SkillDirectory objects containing the path, name, and relative_path for each candidate skill.

Detection Rules and Criteria

The specific detection algorithm (lines 54-57) applies two Boolean rules:

  1. The top-level directory must not contain a SKILL.md (or skill.md) file. If a root skill definition exists, the directory is treated as a single skill regardless of nested structures.
  2. At least two immediate subdirectories must each contain their own SKILL.md (or skill.md) file. Only when multiple sub-skills are identified does the detection return a positive result.

The MultiSkillDetectionResult object returned includes three critical fields: is_multi_skill (Boolean), skills (list of SkillDirectory objects), and has_root_skill (Boolean flag indicating whether a root-level skill file was found).

Independent Scanning in cli.py

Once detection completes, the CLI layer in src/skillspector/cli.py orchestrates the independent scanning of each discovered skill.

The _scan_multi_skill Helper

When invoking skillspector scan <path> --recursive, the CLI logic (lines 76-84) first calls detect_skills. If detection.is_multi_skill evaluates to True, the code delegates to the private helper _scan_multi_skill (lines 355-430) rather than executing a standard single-skill scan.

The _scan_multi_skill function iterates over every SkillDirectory in the detection result and performs the following operations for each entry:

  • Prints a progress header identifying the current skill being analyzed
  • Initializes a fresh scan state (_scan_state) pointing at the specific sub-skill’s folder
  • Invokes the graph engine via graph.invoke to execute the full analysis pipeline on that skill alone
  • Extracts the risk score, severity level, and finding count from the results

Aggregating Results and Exit Codes

After processing all sub-skills, the CLI aggregates the individual results into a combined output format. If the output format is JSON, the tool generates a merged report containing each skill’s name, path, risk score, severity, and finding count. For human-readable output, the CLI concatenates the individual reports into a unified summary table.

The exit behavior mirrors single-skill scanning: if any individual skill’s risk score exceeds the global RISK_THRESHOLD, the CLI exits with a non-zero status code, ensuring that CI/CD systems can detect security or quality issues across the entire multi-skill repository.

Programmatic Usage Example

You can leverage the detection API directly without invoking the CLI:

from pathlib import Path
from skillspector.multi_skill import detect_skills

# Analyze a directory that potentially contains multiple skills

root = Path("/path/to/skill-collection")
result = detect_skills(root)

if result.is_multi_skill:
    print(f"Found {len(result.skills)} independent skills:")
    for skill in result.skills:
        print(f" - {skill.name} ({skill.relative_path})")
else:
    if result.has_root_skill:
        print("Single-skill directory detected.")
    else:
        print("No valid skill structure found.")

When running via the CLI with the --recursive flag on the same directory, SkillSpector automatically invokes the same detection logic and executes _scan_multi_skill to process each skill independently.

Summary

  • Detection requires two conditions: No SKILL.md at the root, and at least two subdirectories containing their own SKILL.md files.
  • Core detection function: detect_skills in src/skillspector/multi_skill.py returns structured metadata about each discovered skill.
  • Independent scanning: The _scan_multi_skill helper in src/skillspector/cli.py (lines 355-430) instantiates fresh scan states and invokes the graph engine separately for each skill.
  • Unified reporting: Results are aggregated into either JSON or human-readable formats while preserving individual risk scores and severities.
  • Consistent exit codes: The CLI maintains standard exit behavior across single and multi-skill scans, failing if any skill exceeds the risk threshold.

Frequently Asked Questions

What defines a multi-skill directory in SkillSpector?

A multi-skill directory is defined as a folder that lacks a root-level SKILL.md file but contains at least two immediate subdirectories, each housing its own SKILL.md (or skill.md) file. This structure indicates that the repository contains multiple independent skills rather than a single composite skill.

How does SkillSpector handle a root SKILL.md versus nested skill directories?

If a root SKILL.md exists at the top level of the scanned directory, SkillSpector treats the entire directory as a single skill regardless of any nested SKILL.md files found in subdirectories. The has_root_skill flag in the MultiSkillDetectionResult object tracks this condition explicitly.

Can I scan multi-skill directories programmatically without using the CLI?

Yes. Import the detect_skills function from skillspector.multi_skill to identify skill boundaries programmatically. While the independent scanning logic (_scan_multi_skill) is internal to the CLI module, you can replicate its behavior by iterating over the skills list in the detection result and invoking the analysis engine separately for each SkillDirectory path.

How are results aggregated when scanning multiple skills independently?

When scanning multi-skill directories, SkillSpector collects individual results from each sub-skill analysis and merges them into a single output. For JSON output, this produces a unified report containing arrays of findings per skill. For console output, the CLI prints concatenated reports with clear headers identifying each skill, followed by a summary table showing risk scores and severities across all discovered skills.

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 →