# What Is the meta_analyzer Node in SkillSpector? LLM-Driven Security Filtering Explained

> Understand the meta_analyzer node in SkillSpector. This LLM-driven filter validates findings, assigns scores, and provides remediation advice for robust security analysis.

- Repository: [NVIDIA Corporation/SkillSpector](https://github.com/NVIDIA/SkillSpector)
- Tags: internals
- Published: 2026-06-23

---

**The `meta_analyzer` node is the final LLM-powered validation and enrichment step that filters static analysis findings, assigns confidence scores, and generates remediation advice before report generation.**

The `meta_analyzer` node serves as the critical quality gate in NVIDIA's SkillSpector security analysis pipeline. Located in [`src/skillspector/nodes/meta_analyzer.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/meta_analyzer.py), this component evaluates raw findings from parallel static analyzers using configurable large language models (LLMs) to eliminate false positives and produce high-confidence security assessments.

## Where the meta_analyzer Node Lives in the Architecture

The node occupies a central position in SkillSpector’s directed analysis graph, positioned between parallel static analyzers and the final report generator.

### Source Code Locations

- **[`src/skillspector/nodes/meta_analyzer.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/meta_analyzer.py)** — Contains the `LLMMetaAnalyzer` class and the public `meta_analyzer(state)` entry point that implements filtering logic, prompt construction, and fallback handling.
- **[`src/skillspector/graph.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/graph.py)** — Defines the LangGraph workflow topology where analyzer nodes fan-out, then fan-in to `meta_analyzer`, which subsequently feeds the `report` node.
- **[`src/skillspector/state.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/state.py)** — Defines the `SkillspectorState` dictionary that carries `findings`, `use_llm`, `model_config`, and other parameters consumed by the node.
- **[`src/skillspector/llm_analyzer_base.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/llm_analyzer_base.py)** — Provides the `LLMAnalyzerBase` parent class that handles token budgeting, batching, and asynchronous LLM execution for the meta-analyzer.

## What the meta_analyzer Node Does

The node executes a six-stage pipeline to refine raw security findings into actionable intelligence:

1. **Collects per-file findings** — Aggregates outputs from preceding static analyzers (YARA, pattern matchers) contained in `state["findings"]`.
2. **Conditional LLM invocation** — When `state["use_llm"]` is `True`, sends each file with findings to the LLM configured in `state["model_config"]["meta_analyzer"]` using the `PER_FILE_ANALYSIS_PROMPT`.
3. **Structured response parsing** — Validates LLM output against the Pydantic `MetaAnalyzerResult` schema to extract structured data.
4. **Confidence-based filtering** — Retains only findings where the LLM marks `is_vulnerability=True` **and** assigns a confidence score ≥ 0.6.
5. **Finding enrichment** — Appends LLM-generated fields including `explanation`, `remediation`, and refined `confidence` scores to retained findings.
6. **Safe fallback execution** — Applies heuristic filtering (`_fallback_filtered`) when `--no-llm` mode is active, or passes findings through with default remediations (`_passthrough_with_defaults`) when LLM calls fail.

According to the SkillSpector source code, this architecture allows the meta-analyzer to act as a "human-in-the-loop" substitute, converting noisy static analysis output into concise, validated security reports.

## Integration in the SkillSpector Pipeline

The node serves as the crucial bridge between raw analysis and final reporting in the directed acyclic graph:

```

resolve_input → build_context → [parallel static analyzers] → meta_analyzer → report

```

As implemented in [`src/skillspector/graph.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/graph.py), all static analyzer nodes produce raw `Finding` objects that flow into the `meta_analyzer` node. After processing, the node emits `filtered_findings` to the `report` node, which serializes results into SARIF or human-readable formats.

## Implementation Details and Fallback Mechanisms

The `LLMMetaAnalyzer` class extends `LLMAnalyzerBase` to inherit sophisticated LLM management capabilities while implementing domain-specific security logic.

### Key Classes and Methods

- **`meta_analyzer(state)`** — The public entry point function that orchestrates filtering logic based on `SkillspectorState` configuration.
- **`LLMMetaAnalyzer`** — The analyzer class that constructs per-file prompts and parses `MetaAnalyzerResult` objects.
- **`_fallback_filtered`** — Heuristic filtering method applied when `use_llm=False`, dropping low-confidence non-critical findings based on static severity rules.
- **`_passthrough_with_defaults`** — Failure-recovery method that returns all original findings with default remediations drawn from [`src/skillspector/nodes/analyzers/pattern_defaults.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/analyzers/pattern_defaults.py) when LLM calls error out.

### Configuration Requirements

The node respects the `model_config["meta_analyzer"]` key for LLM selection (e.g., `deepseek-ai/deepseek-v4-pro`) and requires raw file content in `state["file_cache"]` to populate analysis prompts with source context.

## Practical Usage Examples

### Programmatic Invocation via Python API

To call the `meta_analyzer` node directly in custom scripts:

```python
from skillspector.state import SkillspectorState
from skillspector.nodes.meta_analyzer import meta_analyzer

state = SkillspectorState(
    findings=[
        {
            "rule_id": "E2",
            "message": "Hard-coded credential",
            "severity": "HIGH",
            "confidence": 0.9,
            "file": "skill.py",
            "start_line": 12,
            "end_line": 12,
            "remediation": None,
        }
    ],
    use_llm=True,
    model_config={"meta_analyzer": "deepseek-ai/deepseek-v4-pro"},
    manifest={"name": "example-skill"},
    file_cache={"skill.py": "def foo(): pass"},
)

filtered = meta_analyzer(state)
print(filtered["filtered_findings"])

```

This returns a list containing only LLM-validated findings, each enriched with `explanation`, `remediation`, and updated confidence scores.

### Standard CLI Execution

Run the complete analysis pipeline including the meta-analyzer:

```bash
skill-spector scan ./my-skill \
    --model-config meta_analyzer=deepseek-ai/deepseek-v4-pro \
    --output-format sarif

```

The CLI automatically wires the node into the graph as defined in [`graph.py`](https://github.com/NVIDIA/SkillSpector/blob/main/graph.py), executing it after all static analyzers complete.

### Disabling LLM Processing (Heuristic Mode)

To bypass LLM calls and rely on static heuristics:

```bash
skill-spector scan ./my-skill --no-llm

```

With `use_llm=False`, the node invokes `_fallback_filtered`, applying confidence-based heuristics without external API calls.

## Summary

- The `meta_analyzer` node in SkillSpector functions as the final LLM-powered validation gate in the security analysis pipeline.
- Located in [`src/skillspector/nodes/meta_analyzer.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/meta_analyzer.py), it filters findings using a confidence threshold of 0.6 and the `is_vulnerability` boolean from parsed `MetaAnalyzerResult` objects.
- The node enriches retained findings with AI-generated explanations and remediations while providing safe fallbacks for offline or failure scenarios.
- It integrates between parallel static analyzers and the report generator in the LangGraph workflow defined in [`src/skillspector/graph.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/graph.py).

## Frequently Asked Questions

### What triggers the meta_analyzer node to run in SkillSpector?

The `meta_analyzer` node executes automatically after all parallel static analyzer nodes complete their execution, as defined by the graph edges in [`src/skillspector/graph.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/graph.py). The node consumes the aggregated `findings` list from `SkillspectorState` and triggers regardless of whether LLM processing is enabled, though its internal logic selects between LLM-based or heuristic filtering based on the `use_llm` flag.

### How does the meta_analyzer node filter false positives?

The node sends static findings to an LLM using the `PER_FILE_ANALYSIS_PROMPT`, which instructs the model to re-evaluate each finding and return a structured `MetaAnalyzerResult`. Only findings where the LLM returns `is_vulnerability=True` and assigns a confidence score of at least 0.6 are retained. Findings failing either criterion are discarded from the final output.

### What happens if the LLM service is unavailable?

When LLM calls fail or timeout, the `meta_analyzer` node executes `_passthrough_with_defaults`, which returns all original findings with default remediations sourced from [`src/skillspector/nodes/analyzers/pattern_defaults.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/analyzers/pattern_defaults.py). This ensures the pipeline completes successfully even during API outages, though without AI-generated enrichment.

### Can I use SkillSpector without an LLM for the meta-analysis step?

Yes, by passing the `--no-llm` flag or setting `use_llm=False` in the state, the node bypasses LLM calls and executes `_fallback_filtered` instead. This mode applies static heuristics to drop low-confidence non-critical findings, providing a lightweight analysis option that requires no external API keys or network connectivity.