# How to Contribute to SkillSpector: A Developer's Guide to NVIDIA's LangGraph Security Scanner

> Contribute to SkillSpector a powerful NVIDIA LangGraph security scanner. Clone the repo install dev dependencies extend the scanning pipeline by adding new analyzer modules.

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

---

**To contribute to SkillSpector, clone the NVIDIA repository, install development dependencies with `make install-dev`, and extend the scanning pipeline by creating new analyzer modules in `src/skillspector/nodes/analyzers/` and registering them in the analyzer registry.**

SkillSpector is a **LangGraph-based security scanner** for AI-agent skills developed by NVIDIA. The tool resolves skills from Git repositories, ZIP files, or local directories, then executes a directed acyclic graph (DAG) of **22 parallel analyzers** to detect vulnerabilities and emit SARIF/JSON/Markdown reports. Contributing to SkillSpector involves extending its modular analyzer suite, improving the graph workflow in [`src/skillspector/graph.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/graph.py), or enhancing the risk-scoring logic in the report node.

## Setting Up Your Development Environment

Begin by cloning the repository and creating an isolated Python environment. The project prefers `uv` for virtual environment management, though standard `venv` works equally well.

```bash

# Clone the repository

git clone https://github.com/NVIDIA/SkillSpector.git
cd SkillSpector

# Create and activate virtual environment (uv preferred)

uv venv .venv && source .venv/bin/activate

# Alternative: python3 -m venv .venv && source .venv/bin/activate

# Install development dependencies

make install-dev

```

All `make` targets assume an active virtual environment. For detailed build commands and environment variables, consult [`docs/DEVELOPMENT.md`](https://github.com/NVIDIA/SkillSpector/blob/main/docs/DEVELOPMENT.md).

## Understanding the SkillSpector Architecture

SkillSpector processes skills through a **state-driven DAG** defined in [`src/skillspector/graph.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/graph.py). The workflow passes a `SkillspectorState` (a TypedDict defined in [`src/skillspector/state.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/state.py)) through five distinct stages:

1. **Input resolution** – [`src/skillspector/input_handler.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/input_handler.py) clones Git repos, extracts ZIPs, and normalizes inputs into local directories.
2. **Context building** – [`src/skillspector/nodes/build_context.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/build_context.py) walks the directory, caches file contents, builds ASTs, and flags executable scripts.
3. **Parallel analysis** – **22 analyzer nodes** (static regex/YARA, AST-based behavioral checks, CVE lookups, and MCP checks) each emit `Finding` objects defined in [`src/skillspector/models.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/models.py).
4. **Meta-analysis** – [`src/skillspector/nodes/meta_analyzer.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/meta_analyzer.py) optionally filters false positives using an LLM provider configured in `src/skillspector/providers/`.
5. **Reporting** – [`src/skillspector/nodes/report.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/report.py) applies baseline suppression, computes a numeric risk score, and renders the final output.

All state transitions use LangGraph’s **reducer pattern**, ensuring pure functions without side effects. This architecture makes the pipeline trivial to unit test and extend.

## Adding a New Security Analyzer

The most common contribution is adding a new static analyzer to detect specific vulnerability patterns. Analyzers reside in `src/skillspector/nodes/analyzers/` and follow a standardized interface.

### Creating the Analyzer Module

Create a new Python file in the analyzers directory implementing the `analyze` function signature:

```python

# src/skillspector/nodes/analyzers/static_patterns_secret_leak.py

from .common import AnalyzerFinding, Location, Severity
from .pattern_defaults import CATEGORY, EXPLANATION, REMEDIATION

def analyze(content: str, file_path: str, file_type: str) -> list[AnalyzerFinding]:
    findings: list[AnalyzerFinding] = []
    
    # Detect hard-coded AWS access key patterns

    if "AKIA" in content:
        lines = content.splitlines()
        for line_no, line in enumerate(lines, 1):
            if "AKIA" in line:
                findings.append(
                    AnalyzerFinding(
                        location=Location(file=file_path, line=line_no),
                        severity=Severity.HIGH,
                        rule_id="SEC1",
                        message="Hard-coded AWS access key detected",
                        category=CATEGORY,
                        explanation=EXPLANATION,
                        remediation=REMEDIATION,
                    )
                )
                break
    return findings

```

The function receives the file content, absolute path, and detected MIME type, then returns a list of `AnalyzerFinding` objects containing the location, severity, and remediation guidance.

### Registering Your Analyzer

Make the new analyzer available to the graph by updating the registry in [`src/skillspector/nodes/analyzers/__init__.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/analyzers/__init__.py):

```python
from . import static_patterns_secret_leak

ANALYZER_NODE_IDS.append("static_secret_leak")
ANALYZER_NODES["static_secret_leak"] = static_runner.run_static_patterns(
    static_patterns_secret_leak.analyze
)

```

The `ANALYZER_NODE_IDS` list controls execution order, while the `ANALYZER_NODES` dictionary maps the node ID to the LangGraph node function.

### Writing Unit Tests

Create a corresponding test file under `tests/nodes/analyzers/`:

```python

# tests/nodes/analyzers/test_static_secret_leak.py

from skillspector.nodes.analyzers import static_patterns_secret_leak

def test_detects_aws_key():
    content = "aws_access_key_id = 'AKIAIOSFODNN7EXAMPLE'"
    findings = static_patterns_secret_leak.analyze(content, "test.py", "text/x-python")
    
    assert len(findings) == 1
    assert findings[0].rule_id == "SEC1"
    assert findings[0].severity.name == "HIGH"

```

Run the specific test with `pytest tests/nodes/analyzers/test_static_secret_leak.py` or execute the full suite with `make test`.

## Testing Your Contributions Locally

Verify your changes using the CLI or the interactive LangGraph development server.

**Scan a local skill with your new analyzer:**

```bash

# Run with static analysis only (fastest iteration)

skillspector scan ./examples/my-skill/ --no-llm

# Generate structured JSON output

skillspector scan ./examples/my-skill/ --format json -o report.json

```

**Launch LangGraph Studio for interactive debugging:**

```bash
make langgraph-dev

```

This starts a local HTTP server and opens LangGraph Studio, where you can step through individual nodes, inspect the `SkillspectorState` at each stage, and invoke the graph with custom inputs such as:

```json
{
  "input_path": "/absolute/path/to/skill",
  "output_format": "json",
  "use_llm": false
}

```

## Documentation and Pull Request Guidelines

Before submitting, ensure your contribution meets the repository's quality standards:

- **Update documentation** – Add an entry to [`docs/DEVELOPMENT.md`](https://github.com/NVIDIA/SkillSpector/blob/main/docs/DEVELOPMENT.md) describing the analyzer's detection logic and any configuration flags. Update [`README.md`](https://github.com/NVIDIA/SkillSpector/blob/main/README.md) if you introduce new CLI options.
- **Code quality** – Run the linting and formatting tools: `make lint && make format`.
- **Full test suite** – Execute `make test` to verify no regressions in the **risk-score gating** model.

Submit your contribution by forking the repository, creating a feature branch (`feature/my-new-analyzer`), and opening a pull request against `main`. Reviewers will verify that new rules correctly categorize findings and do not introduce false positives that could skew the final risk calculation.

## Summary

- **Setup** – Clone NVIDIA/SkillSpector, create a virtual environment, and run `make install-dev` to install dependencies.
- **Architecture** – SkillSpector uses a LangGraph DAG with **22 analyzer nodes** processing a `SkillspectorState` through resolution, context building, analysis, and reporting stages.
- **Development** – Add new detectors by implementing the `analyze` function in `src/skillspector/nodes/analyzers/`, then register them in [`__init__.py`](https://github.com/NVIDIA/SkillSpector/blob/main/__init__.py) and write unit tests under `tests/nodes/analyzers/`.
- **Testing** – Use `make langgraph-dev` for interactive debugging and `make test` for regression testing; use `--no-llm` for rapid static analysis iteration.
- **Submission** – Follow the guidelines in [`CONTRIBUTING.md`](https://github.com/NVIDIA/SkillSpector/blob/main/CONTRIBUTING.md), update relevant documentation, and ensure CI checks pass before requesting review.

## Frequently Asked Questions

### What programming language is SkillSpector written in?

SkillSpector is implemented in **Python 3** using the **LangGraph** framework for orchestrating the security scanning workflow. The codebase leverages Pydantic models in [`src/skillspector/models.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/models.py) for structured data validation and uses standard AST libraries for code analysis.

### Do I need an LLM API key to contribute to SkillSpector?

No. While SkillSpector supports LLM-based meta-analysis via providers in `src/skillspector/providers/`, you can develop and test static analyzers without API keys by using the `--no-llm` flag. This mode runs only the static pattern matchers, AST detectors, and YARA rules, making it ideal for rapid development cycles.

### How does the risk score calculation work?

The risk score is computed in [`src/skillspector/nodes/report.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/report.py) based on the aggregated severity of findings after baseline suppression. Each `Finding` object carries a severity level (LOW, MEDIUM, HIGH, CRITICAL) that maps to numeric weights; the final score determines the severity rating and recommendation shown in SARIF or Markdown outputs.

### Can I contribute bug fixes or documentation without adding new analyzers?

Yes. Contributions to improve error handling in [`src/skillspector/input_handler.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/input_handler.py), enhance the **reducer pattern** logic in the state management, clarify documentation in [`docs/DEVELOPMENT.md`](https://github.com/NVIDIA/SkillSpector/blob/main/docs/DEVELOPMENT.md), or fix edge cases in existing analyzers are welcome. All pull requests undergo the same risk-score gating review process to ensure code quality.