How to Scan a Directory with Multiple AI Agent Skills Using SkillSpector
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 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 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 (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.mdexists in the target directory. - Multi-skill mode: Activated when there is no root
SKILL.mdand at least two immediate sub-directories each contain aSKILL.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, 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:
skillspector scan ./my-skill-collection/ --recursive -o report.json
Use the pretty-text formatter instead of JSON:
skillspector scan ./my-skill-collection/ --recursive -f pretty -o report.txt
Enable verbose mode to see progress details for each sub-skill:
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:
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) and batch processing capabilities found in 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()inmulti_skill.pyto identify directories containing multipleSKILL.mdfiles when no root-level skill file exists. - The
--recursiveCLI flag triggers automatic batch processing via_scan_multi_skill()incli.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 file, with no SKILL.md present in the root directory being scanned. The detect_skills() function explicitly checks for this pattern in 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 exists, SkillSpector operates in single-skill mode and scans only that root skill, ignoring any skills in sub-directories. Remove the root 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.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →