# How to Scan a Directory with Multiple AI Agent Skills Using SkillSpector

> Learn how to scan directories with multiple AI agent skills using SkillSpector and its recursive flag. Automatically detect and audit individual skills for robust security analysis.

- Repository: [NVIDIA Corporation/SkillSpector](https://github.com/NVIDIA/SkillSpector)
- Tags: how-to-guide
- Published: 2026-07-11

---

**SkillSpector automatically discovers and scans directories containing multiple AI agent skills using the `--recursive` flag, which triggers the `detect_skills()` helper to identify each sub-directory with a [`SKILL.md`](https://github.com/NVIDIA/SkillSpector/blob/main/SKILL.md) file and process them as individual security audits before aggregating the results.**

NVIDIA's SkillSpector is an open-source security analysis tool designed to audit AI agent skills defined in [`SKILL.md`](https://github.com/NVIDIA/SkillSpector/blob/main/SKILL.md) files. When managing a collection of independent skills in a single repository or folder, you can scan them all at once using multi-skill detection rather than executing separate commands for each skill.

## Understanding Multi-Skill Detection Logic

At the core of this capability is the `detect_skills()` function implemented in [`src/skillspector/multi_skill.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/multi_skill.py) (lines 51-90). This helper walks the target directory and returns a `MultiSkillDetectionResult` object containing three key attributes: `is_multi_skill`, `skills`, and `has_root_skill`.

The detection logic works as follows:

- **Single-skill mode**: Triggered when a root-level [`SKILL.md`](https://github.com/NVIDIA/SkillSpector/blob/main/SKILL.md) exists in the target directory.
- **Multi-skill mode**: Activated when there is **no** root [`SKILL.md`](https://github.com/NVIDIA/SkillSpector/blob/main/SKILL.md) and at least two immediate sub-directories each contain a [`SKILL.md`](https://github.com/NVIDIA/SkillSpector/blob/main/SKILL.md).

Each discovered skill is represented as a `SkillDirectory` object containing the skill name and file path, allowing the scanner to treat the collection as a batch operation.

## Running Recursive Scans from the CLI

The command-line interface integrates multi-skill detection through the `--recursive` (or `-r`) flag. When you execute `skillspector scan` against a directory, the CLI checks this flag and calls `detect_skills()` (see [`src/skillspector/cli.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/cli.py), lines 77-84).

If `detect_skills()` returns `is_multi_skill=True`, the CLI delegates processing to `_scan_multi_skill()` (lines 55-64 in the same file). This function iterates over every detected `SkillDirectory`, constructs an individual scan state via `_scan_state()`, and invokes the analysis graph with `graph.invoke(state)`.

After processing all sub-skills, SkillSpector produces a consolidated report. For JSON output, it generates a combined object recording each skill’s name, path, risk score, severity, and finding count (lines 90-108). The tool exits with a non-zero status code if any skill exceeds the configured `RISK_THRESHOLD`.

### Command Examples

Execute a basic recursive scan of a skill collection:

```bash
skillspector scan ./my-skill-collection/ --recursive -o report.json

```

Use the pretty-text formatter instead of JSON:

```bash
skillspector scan ./my-skill-collection/ --recursive -f pretty -o report.txt

```

Enable verbose mode to see progress details for each sub-skill:

```bash
skillspector scan ./my-skill-collection/ -r -V

```

## Programmatic Directory Scanning

You can implement the same multi-skill workflow in Python scripts by importing the detection and scanning utilities directly from the source code:

```python
from pathlib import Path
from skillspector.multi_skill import detect_skills
from skillspector.cli import _scan_state, _build_trace_config
from skillspector.graph import graph

root = Path("./my-skill-collection")
detection = detect_skills(root)

if detection.is_multi_skill:
    for skill in detection.skills:
        state = _scan_state(str(skill.path), format="json", no_llm=False)
        config = _build_trace_config(str(skill.path), format="json", no_llm=False)
        result = graph.invoke(state, config=config)
        # Process individual skill results...

else:
    # Fallback to single-skill scan

    state = _scan_state(str(root), format="json", no_llm=False)
    result = graph.invoke(state)

```

This approach mirrors the CLI's internal logic, giving you programmatic access to the analysis graph ([`src/skillspector/graph.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/graph.py)) and batch processing capabilities found in [`contrib/batch_scan/runner.py`](https://github.com/NVIDIA/SkillSpector/blob/main/contrib/batch_scan/runner.py).

## How Results Are Aggregated

When scanning multiple skills, SkillSpector handles output aggregation automatically. The `_scan_multi_skill()` function collects results from each individual skill analysis and formats them according to your specified output mode.

**JSON output** produces a combined report object containing per-skill metadata including risk scores and severity classifications. **Text output** concatenates individual reports into a single file. In both cases, the CLI prints a consolidated summary table to stdout showing the status of all scanned skills.

The tool respects the global `RISK_THRESHOLD` configuration, failing the entire batch scan if any single skill exceeds the risk limit, which is critical for CI/CD pipelines enforcing security gates across multiple agent implementations.

## Summary

- **Multi-skill detection** relies on `detect_skills()` in [`multi_skill.py`](https://github.com/NVIDIA/SkillSpector/blob/main/multi_skill.py) to identify directories containing multiple [`SKILL.md`](https://github.com/NVIDIA/SkillSpector/blob/main/SKILL.md) files when no root-level skill file exists.
- The `--recursive` CLI flag triggers automatic batch processing via `_scan_multi_skill()` in [`cli.py`](https://github.com/NVIDIA/SkillSpector/blob/main/cli.py).
- Each skill receives individual analysis through the LangGraph pipeline (`graph.invoke`), with results aggregated into unified reports.
- SkillSpector exits with non-zero codes if any skill in the directory exceeds risk thresholds, enabling automated security enforcement.

## Frequently Asked Questions

### What directory structure is required for multi-skill detection?

SkillSpector requires at least two immediate sub-directories, each containing a [`SKILL.md`](https://github.com/NVIDIA/SkillSpector/blob/main/SKILL.md) file, with no [`SKILL.md`](https://github.com/NVIDIA/SkillSpector/blob/main/SKILL.md) present in the root directory being scanned. The `detect_skills()` function explicitly checks for this pattern in [`src/skillspector/multi_skill.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/multi_skill.py) to distinguish between single-skill and multi-skill scenarios.

### How does SkillSpector handle mixed environments with both root and sub-directory skills?

If a root-level [`SKILL.md`](https://github.com/NVIDIA/SkillSpector/blob/main/SKILL.md) exists, SkillSpector operates in single-skill mode and scans only that root skill, ignoring any skills in sub-directories. Remove the root [`SKILL.md`](https://github.com/NVIDIA/SkillSpector/blob/main/SKILL.md) to enable multi-skill detection for sub-directory scanning.

### Can I customize output formats when scanning multiple skills?

Yes. The `--format` (or `-f`) flag accepts `json`, `pretty`, or other supported formatters. When using `--recursive`, the `_scan_multi_skill()` function ensures each skill's output is formatted consistently and combined into a single report file specified via `--output`.

### What exit codes does SkillSpector return for multi-skill scans?

SkillSpector returns a non-zero exit code if any individual skill in the batch exceeds the `RISK_THRESHOLD` configured for the scan. This applies whether processing a single skill or an entire directory, making it suitable for automated pipeline gates that must block deployments containing high-risk agent implementations.