# How to Invoke SkillSpector Programmatically Using the Python API

> Learn how to invoke SkillSpector programmatically using Python API. Import the graph object and call invoke with your SkillspectorState for seamless integration.

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

---

**You can invoke SkillSpector programmatically by importing the compiled LangGraph `graph` object from `skillspector.graph` and calling `graph.invoke(state)` with a dictionary matching the `SkillspectorState` schema.**

SkillSpector is NVIDIA's open-source security scanner for AI skill bundles. While the tool provides a command-line interface, you can integrate it directly into Python workflows by leveraging its underlying LangGraph architecture and the programmatic API exposed in [`src/skillspector/graph.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/graph.py).

## Understanding the SkillSpector Python API Architecture

The SkillSpector Python API is built around a **LangGraph** workflow that processes security scans through a series of interconnected nodes. Understanding this architecture helps you construct valid inputs and interpret results correctly.

### Core Components

The programmatic interface consists of three main components defined in the source code:

1. **Package Entry Point** – [`src/skillspector/__init__.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/__init__.py) exposes the compiled graph via `graph` and a `create_graph` factory function for advanced customization.

2. **State Schema** – All data exchanged between nodes follows the `SkillspectorState` TypedDict defined in [`src/skillspector/state.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/state.py). This schema validates that required fields like `skill_path` and `output_format` are present while carrying intermediate data between analysis stages.

3. **Graph Construction** – [`src/skillspector/graph.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/graph.py) builds a `StateGraph` connecting nodes for input handling, context building, static analyzers, LLM-based meta-analysis, and reporting. The `graph.invoke()` method in this file executes the entire pipeline.

### Invocation Pattern

When you call `graph.invoke(state, config=trace_cfg)`, the method accepts a state dictionary and an optional `RunnableConfig` for tracing. The graph runs synchronously and returns a plain Python `dict` containing final fields such as `findings`, `report_body`, `sarif_report`, and `risk_score`. This mirrors the behavior of [`src/skillspector/cli.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/cli.py), which serves as a thin wrapper that prepares state and delegates to `graph.invoke`.

## Step-by-Step Implementation Guide

Follow these steps to embed SkillSpector into your Python applications.

### Import the Compiled Graph

Access the pre-configured graph instance directly from the package:

```python
from skillspector.graph import graph

```

Alternatively, import `create_graph` from `skillspector` to build a custom graph instance with modified node configurations.

### Build the Initial State

Construct a dictionary that satisfies the `SkillspectorState` schema. Only a few keys are required to initiate a scan:

- `skill_path`: String path to the local skill directory or remote git URL
- `output_format`: One of `terminal`, `json`, `markdown`, or `sarif`
- `use_llm`: Boolean flag to enable or disable LLM-based semantic analysis

Optional keys include `yara_rules_dir` for custom rule paths and `model_config` for provider-specific settings.

### Configure LLM Provider (Optional)

Set environment variables to control which model powers the analysis, as implemented in [`src/skillspector/providers/base.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/providers/base.py):

```python
import os

os.environ["SKILLSPECTOR_PROVIDER"] = "openai"
os.environ["SKILLSPECTOR_MODEL"] = "gpt-4o-mini"

```

The internal provider registry resolves these variables to instantiate the correct `ChatModelProvider` without requiring additional code.

### Invoke and Read Results

Execute the scan and extract the results:

```python
result = graph.invoke(state, config={"run_name": "security-scan"})
findings = result["findings"]  # List of Finding objects

report = result["report_body"]  # Human-readable report

sarif = result["sarif_report"]  # SARIF JSON output

```

The `Finding` objects are defined in [`src/skillspector/models.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/models.py) and contain severity ratings, location data, and remediation suggestions.

## Practical Code Examples

### Minimal Scan of a Local Skill Directory

This example demonstrates the minimal code required to scan a local skill bundle and print results:

```python
from pathlib import Path
from skillspector.graph import graph

# Build minimal required state

state = {
    "skill_path": str(Path("./my_skill").resolve()),
    "output_format": "terminal",
    "use_llm": True,
}

# Optional tracing configuration

trace_cfg = {
    "run_name": "my-skill-scan",
    "tags": ["skillspector", "example"],
    "metadata": {"skill_path": state["skill_path"]},
}

# Execute scan

result = graph.invoke(state, config=trace_cfg)

# Output results

print("=== Report ===")
print(result.get("report_body", ""))

print("\n=== Findings ===")
for f in result.get("findings", []):
    print(f"- [{f.severity}] {f.title}: {f.description}")

```

This implementation mirrors the CLI behavior in [`src/skillspector/cli.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/cli.py) while providing direct access to the result dictionary.

### Programmatic Use with Custom LLM Provider

Configure the analysis backend programmatically using environment variables recognized by [`src/skillspector/providers/base.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/providers/base.py):

```python
import os
from skillspector.graph import graph

# Configure provider via environment (same mechanism as CLI)

os.environ["SKILLSPECTOR_PROVIDER"] = "openai"
os.environ["SKILLSPECTOR_MODEL"] = "gpt-4o-mini"

# State supports remote git URLs

state = {
    "skill_path": "https://github.com/example/malicious-skill",
    "output_format": "json",
    "use_llm": True,
}

result = graph.invoke(state)

# JSON report stored in report_body field

print(result["report_body"])

```

### Static-Only Scan Without LLM Analysis

Disable LLM-based nodes for faster execution when only static pattern matching is required:

```python
from skillspector.graph import graph

state = {
    "skill_path": "./some_skill",
    "output_format": "sarif",
    "use_llm": False,  # Disables meta_analyzer and semantic analyzers

}

result = graph.invoke(state)

# Access SARIF output directly

sarif = result["sarif_report"]
print(sarif)

```

Setting `use_llm` to `False` skips the `meta_analyzer` node and all LLM-dependent semantic analyzers, executing only YARA and pattern-based checks as handled in [`src/skillspector/cli.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/cli.py).

## Summary

- **Import the graph** from `skillspector.graph` to access the compiled LangGraph workflow defined in [`src/skillspector/graph.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/graph.py).
- **Construct state** using the `SkillspectorState` schema from [`src/skillspector/state.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/state.py), providing at minimum `skill_path`, `output_format`, and `use_llm`.
- **Configure providers** via `SKILLSPECTOR_PROVIDER` and `SKILLSPECTOR_MODEL` environment variables handled by [`src/skillspector/providers/base.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/providers/base.py).
- **Call `graph.invoke(state)`** to execute the scan and receive a dictionary containing `findings`, `report_body`, `sarif_report`, and `risk_score`.
- **Disable LLMs** by setting `use_llm: False` in state to run static analysis only, matching the CLI `--no-llm` flag behavior.

## Frequently Asked Questions

### What is the minimum required state to invoke SkillSpector?

You must provide a dictionary with three keys: `skill_path` (string pointing to the skill directory or URL), `output_format` (string: `terminal`, `json`, `markdown`, or `sarif`), and `use_llm` (boolean). These fields are defined in [`src/skillspector/state.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/state.py) as part of the `SkillspectorState` TypedDict. Additional optional keys like `yara_rules_dir` can customize the analysis behavior.

### How do I configure a custom LLM provider when using the Python API?

Set the `SKILLSPECTOR_PROVIDER` and `SKILLSPECTOR_MODEL` environment variables before invoking the graph, as the provider registry in [`src/skillspector/providers/base.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/providers/base.py) resolves these at runtime. Alternatively, include a `model_config` entry in your state dictionary to override defaults programmatically without modifying environment variables.

### Can I run SkillSpector without LLM analysis for faster execution?

Yes. Set `"use_llm": False` in your state dictionary before calling `graph.invoke()`. This configuration skips the `meta_analyzer` node and all LLM-based semantic analyzers, executing only static YARA and pattern checks. This programmatic approach corresponds to the `--no-llm` CLI flag implemented in [`src/skillspector/cli.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/cli.py).

### What does the `graph.invoke()` method return?

The method returns a plain Python dictionary containing the final state after graph execution. Key fields include `findings` (list of `Finding` objects from [`src/skillspector/models.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/models.py)), `report_body` (human-readable text), `sarif_report` (SARIF JSON), and `risk_score` (numeric assessment). The structure matches the output schema defined in [`src/skillspector/state.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/state.py).