# How the SkillSpector Input Resolver Handles Git URLs, Zip Files, and Directories

> Learn how the SkillSpector input resolver unifies Git URLs, zip files, and directories into a single local path for seamless analysis. Understand the InputHandler class.

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

---

**The SkillSpector input resolver normalizes Git URLs, zip archives, and local directories into a unified local directory path using the `InputHandler` class, enabling the analysis pipeline to treat any input source as a scannable filesystem.**

The NVIDIA SkillSpector input resolver serves as the entry point for the analysis graph, converting diverse input formats into a standardized local directory. Implemented in [`src/skillspector/input_handler.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/input_handler.py), the `InputHandler` class detects whether the user provided a remote Git repository, a compressed archive, or a local folder, then transforms it into a path ready for scanning. This normalization ensures that downstream nodes never handle protocol-specific logic or archive extraction.

## Entry Point: The `resolve_input` Node

When the analysis graph starts, the `resolve_input` node in [`src/skillspector/nodes/resolve_input.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/resolve_input.py) extracts `state["input_path"]` and instantiates `InputHandler` to process it. Lines 46-57 of this file orchestrate the resolution:

```python
handler = InputHandler()
resolved, source_type = handler.resolve(input_path.strip())

```

The handler returns a **Path** object pointing to a local directory and a **source_type** string (`"git"`, `"url"`, `"zip"`, `"file"`, or `"directory"`). The node records this as `skill_path` and stores any temporary directory in `temp_dir_for_cleanup` so the CLI can purge it after analysis completes.

## Input Type Detection Logic

The `InputHandler.resolve` method examines the input string in a strict priority order to determine the source type. Lines 75-87 of [`input_handler.py`](https://github.com/NVIDIA/SkillSpector/blob/main/input_handler.py) implement the following checks:

- **Git URL**: Validated by `_is_git_url` (lines 105-117), which matches `http(s)://` or `git@` patterns from hosts like **github.com**, **gitlab.com**, or **bitbucket.org**, excluding raw file URLs.
- **File URL**: Any `http(s)://` that is not a Git repository (lines 119-124).
- **Local zip file**: Detected via `input_path.endswith(".zip")` (line 77).
- **Single markdown file**: Detected via `input_path.endswith(".md")` (line 79).
- **Directory**: Verified using `Path(input_path).is_dir()` (line 80).
- **Fallback file**: Any other existing file passed to `Path(input_path).is_file()` (line 83).

If none match, the resolver raises a `ValueError` (lines 85-87).

## Handling Git URLs

When `_is_git_url` returns `True`, `resolve` delegates to `_clone_git` (lines 125-149 of [`input_handler.py`](https://github.com/NVIDIA/SkillSpector/blob/main/input_handler.py)). This method creates a temporary workspace, executes `git clone --depth 1 <url> <temp_dir>/repo`, and returns the path to the cloned repository. The `"git"` source type signals that the content originated from a remote repository.

Errors such as missing Git binaries, authentication failures, or network timeouts are caught, logged, and re-raised as `ValueError` instances to halt the graph with a clear message.

## Handling Zip Files

The SkillSpector input resolver processes zip archives from two sources: local files ending in `.zip` (line 77) and remote URLs that download zip payloads (lines 63-66). Both routes invoke `_extract_zip` (lines 173-189):

```python
return self._extract_zip(Path(input_path)), "zip"

```

The `_extract_zip` method extracts the archive into `<temp_dir>/extracted` using `zipfile.ZipFile`. It implements **smart extraction**: if the archive contains exactly one top-level directory, the method returns that folder's path (common for GitHub "download zip" packages); otherwise, it returns the full extraction directory. Malformed archives trigger a `ValueError`.

## Handling Local Directories

For existing directories, the resolver takes the simplest path. When `Path(input_path).is_dir()` evaluates to `True` (line 80), the method returns the resolved absolute path immediately:

```python
return Path(input_path).resolve(), "directory"

```

No temporary directory is created, and the source directory becomes the scan root. This avoids unnecessary copying and preserves file metadata for local analysis.

## Temporary Directory Management

All operations requiring sandboxing—Git cloning, file downloads, zip extraction, and single-file wrapping—share a lazily-created temporary directory. The `_get_temp_dir` method (lines 95-103) creates this directory under the system temp area with a `skillspector_` prefix.

The `resolve_input` node retrieves this path via `handler.temp_dir_for_cleanup()` and stores it in the graph state. After the analysis completes, the CLI ([`src/skillspector/cli.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/cli.py)) deletes this folder to prevent disk pollution.

## Practical Code Examples

### Direct Use of `InputHandler`

```python
from skillspector.input_handler import InputHandler

handler = InputHandler()

# Clone a Git repository

git_path, src_type = handler.resolve("https://github.com/NVIDIA/SkillSpector.git")
print(f"Cloned to {git_path}, type: {src_type}")

# Extract a remote zip archive

zip_path, src_type = handler.resolve("https://example.com/skills/archive.zip")
print(f"Extracted to {zip_path}, type: {src_type}")

# Reference a local directory

local_path, src_type = handler.resolve("/home/user/my-skill")
print(f"Scanning {local_path}, type: {src_type}")

```

### CLI Integration

When running `skill-spector scan <input_path>`, the CLI initializes the state and triggers the resolver:

```python

# Simplified from src/skillspector/cli.py

state = {"input_path": args.input_path}
updates = resolve_input(state)  # Returns skill_path and temp_dir_for_cleanup

state.update(updates)

```

## Summary

- **The `InputHandler` class** in [`src/skillspector/input_handler.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/input_handler.py) centralizes all input resolution logic for Git URLs, zip files, and directories.
- **Detection priority** follows a strict order: Git URLs first, then remote file URLs, then local zip files, markdown files, and finally directories.
- **Git repositories** are cloned with `--depth 1` into temporary directories prefixed with `skillspector_`.
- **Zip archives** are extracted intelligently, returning the sole root folder if one exists to flatten unnecessary nesting.
- **Local directories** are passed through unchanged after absolute path resolution.
- **Cleanup** is managed via `temp_dir_for_cleanup`, ensuring temporary resources are deleted after the analysis graph completes.

## Frequently Asked Questions

### Does SkillSpector support private Git repositories?

Yes. The `_clone_git` method invokes the system `git` command directly (lines 125-149 of [`input_handler.py`](https://github.com/NVIDIA/SkillSpector/blob/main/input_handler.py)). If your Git credentials are configured in the environment (SSH keys or Git credential helpers), the clone will authenticate automatically. Authentication failures are caught and raised as `ValueError` with the underlying Git error message.

### What happens if a zip file contains multiple root directories?

If the archive contains more than one top-level entry, the `_extract_zip` method (lines 173-189) returns the full extraction directory path rather than drilling into a single subfolder. This ensures no files are lost during extraction, though your skill configuration must account for the directory structure.

### How does the resolver handle single markdown files?

When the input path ends with `.md` (line 79 of [`input_handler.py`](https://github.com/NVIDIA/SkillSpector/blob/main/input_handler.py)), the resolver treats it as a **single-file skill**. The file is wrapped in a temporary directory structure so the analysis graph can process it as a standard skill package, returning the source type `"file"`.

### Where are temporary files stored during processing?

Temporary directories are created under the system's default temp location using the prefix `skillspector_` (lines 99-103 of [`input_handler.py`](https://github.com/NVIDIA/SkillSpector/blob/main/input_handler.py)). The `resolve_input` node stores this path in `temp_dir_for_cleanup`, which the CLI uses to purge all downloaded or extracted data after the analysis completes.