---
name: uv-script-generator
description: Generate single-file uv scripts with inline dependencies for use in Claude Code skills. Creates script + test pairs with shared type/lint configuration. Use when creating Python utilities for skills' scripts/ directories.
allowed-tools: Read, Write, Edit, Bash(python:*), Bash(uv:*), Glob, Grep
---

# UV Script Generator

Generate standalone Python scripts with bundled dependencies for use in Claude Code skills' `scripts/` directories or any target directory for prototyping.

## Purpose

This skill creates **single-file uv scripts** that:
- Bundle all dependencies using PEP 723 inline metadata
- Work in Claude Code skills without consuming context (zero-context execution)
- Include full IDE support via shared type/lint configuration
- Come with corresponding test files for vibe coding iterations

## What Gets Generated

When you ask to generate a script, you get (generated in your **target location**, never in uv-script-generator):

1. **Main script** - Single-file uv script with inline dependencies
2. **Test file** - Corresponding test harness (also a uv script)
3. **pyproject.toml** - Shared type/lint config (created if doesn't exist)
4. **.gitignore** - Python dev gitignore (created if doesn't exist)
5. **SKILL.md update** - Documentation added (when integrating with a skill)

**Example for a skill:**
```
.claude/skills/<target-skill>/
├── SKILL.md                 # Updated with script documentation
├── pyproject.toml           # Shared config for all scripts in this skill
├── .gitignore               # Python dev gitignore
└── scripts/
    ├── my_script.py         # Generated: main script
    └── test_my_script.py    # Generated: test harness
```

**Example for prototyping (any directory):**
```
<target-directory>/
├── pyproject.toml           # Type/lint config
├── .gitignore               # Python dev gitignore
├── my_script.py             # Generated: main script
└── test_my_script.py        # Generated: test harness
```

## Usage Instructions

### For Claude: Generating Scripts

**CRITICAL: Scripts are NEVER generated in the uv-script-generator skill itself. They are ALWAYS generated in OTHER locations.**

When the user asks to generate a uv script:

1. **Identify target location:**
   Ask the user where they want to generate the script:

   **Option A: Existing skill**
   - List available skills found in `.claude/skills/` (excluding uv-script-generator)
   - Generate in `<skill-directory>/scripts/`

   **Option B: New skill**
   - Ask for skill name
   - Create `.claude/skills/<skill-name>/` directory structure
   - Generate in `<skill-name>/scripts/`

   **Option C: Any directory (prototyping)**
   - Ask for target directory path
   - Generate directly in that directory
   - Inform user they can later integrate with a skill using option D

   **Option D: Integrate existing script into skill**
   - Ask for script path and target skill
   - Verify script has up-to-date inline dependencies (see "Development Workflow" below)
   - Copy/sync script (and test if exists) to `<skill-directory>/scripts/`
   - Update `<skill-directory>/pyproject.toml` if needed
   - Create `<skill-directory>/.gitignore` if it doesn't exist (see template below)
   - Update `<skill-directory>/SKILL.md` to document the script's purpose and usage

   **NEVER default to generating in uv-script-generator/scripts/**

2. **Gather requirements:**
   - Script name and purpose
   - Required Python dependencies (e.g., requests, pandas, httpx)
   - Python version requirement (default: >=3.11)

3. **Determine target paths based on option:**
   - **Option A/B (skill)**:
     - Script: `<skill-directory>/scripts/<script-name>.py`
     - Test: `<skill-directory>/scripts/test_<script-name>.py`
     - Config: `<skill-directory>/pyproject.toml`
     - Gitignore: `<skill-directory>/.gitignore`
   - **Option C (any directory)**:
     - Script: `<target-directory>/<script-name>.py`
     - Test: `<target-directory>/test_<script-name>.py`
     - Config: `<target-directory>/pyproject.toml`
     - Gitignore: `<target-directory>/.gitignore`
   - **Option D (integrate)**:
     - Copy from source to `<skill-directory>/scripts/`
     - Update `<skill-directory>/pyproject.toml`
     - Create `<skill-directory>/.gitignore` if needed

4. **Generate the main script** with this structure:

```python
#!/usr/bin/env -S uv run
# /// script
# requires-python = ">=3.11"
# dependencies = [
#   "requests>=2.31.0",
#   "httpx>=0.25.0",
# ]
# ///

"""
Brief description of what this script does.

Usage:
    uv run <script-name>.py [args]
"""

import sys
import requests
import httpx

def main():
    """Main entry point."""
    # Implementation here
    pass

if __name__ == "__main__":
    main()
```

5. **Generate the test file** with this structure:

```python
#!/usr/bin/env -S uv run
# /// script
# requires-python = ">=3.11"
# dependencies = [
#   "pytest>=7.4.0",
#   "requests>=2.31.0",  # Match main script deps
#   "httpx>=0.25.0",
# ]
# ///

"""
Tests for my_script.py

Usage:
    uv run test_my_script.py
"""

import pytest
import sys
from pathlib import Path

# Allow importing the script being tested
sys.path.insert(0, str(Path(__file__).parent))
import my_script

def test_basic_functionality():
    """Test basic operation."""
    # TODO: Implement test
    assert True

if __name__ == "__main__":
    pytest.main([__file__, "-v"])
```

6. **Generate or update pyproject.toml** at the target location (if not exists):

```toml
[tool.mypy]
strict = true
python_version = "3.11"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true

[tool.ruff]
line-length = 100
target-version = "py311"

[tool.ruff.lint]
select = ["E", "F", "I", "N", "W", "B", "C4", "UP"]
per-file-ignores = {"test_*.py" = ["D"]}  # Don't require docstrings in tests

[tool.pytest.ini_options]
testpaths = ["scripts"]
python_files = "test_*.py"
```

7. **Generate .gitignore** at the target location (if not exists):

```gitignore
# Virtual environment
.venv/

# Python
__pycache__/
*.pyc

# Tool caches
.pytest_cache/
.mypy_cache/
.ruff_cache/

# Generated files
*.png

# macOS
.DS_Store
```

8. **Update skill SKILL.md** (for Options A, B, D only):
   - Add documentation about the new script in the skill's SKILL.md
   - Include the script's purpose, usage examples, and required dependencies
   - Keep the documentation concise and focused on how to use the script
   - Skip this step for Option C (prototyping in any directory)

### For Users: Running Scripts

**Run the script:**
```bash
uv run scripts/my_script.py [args]
```

**Run tests during development:**
```bash
uv run scripts/test_my_script.py
```

**Type check:**
```bash
mypy scripts/my_script.py
```

**Lint:**
```bash
ruff check scripts/
```

## Development Workflow (Option C → D)

When prototyping scripts (Option C) before integrating into a skill (Option D), use this workflow for the best IDE and testing experience:

### Phase 1: Development Setup

After generating your script in a prototype directory, set up a development environment:

1. **Add project metadata and dev dependencies to pyproject.toml:**

```toml
[project]
name = "my-prototype"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = []  # Keep empty - scripts remain self-contained

[dependency-groups]
dev = [
    "pytest>=7.4.0",
    "mypy>=1.7.0",
    "ruff>=0.1.0",
    "matplotlib>=3.8.0",  # Match your script's inline dependencies
    "numpy>=1.26.0",
    "scipy>=1.11.0",
]

[tool.mypy]
strict = true
python_version = "3.11"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true

[tool.ruff]
line-length = 100
target-version = "py311"

[tool.ruff.lint]
select = ["E", "F", "I", "N", "W", "B", "C4", "UP"]
per-file-ignores = {"test_*.py" = ["D"]}  # Don't require docstrings in tests

[tool.pytest.ini_options]
testpaths = ["scripts"]  # or "." if scripts are in root
python_files = "test_*.py"
```

2. **Create and sync the development environment:**

```bash
# Create virtual environment
uv venv

# Install all dev dependencies (syncs from pyproject.toml)
uv sync
```

3. **Configure VS Code:**
   - Press `Cmd+Shift+P` (macOS) or `Ctrl+Shift+P` (Windows/Linux)
   - Type "Python: Select Interpreter"
   - Choose `.venv/bin/python`

**Benefits:**
- ✅ Pylance autocomplete and import resolution
- ✅ VS Code Testing panel works (discover and run tests)
- ✅ Conventional test running: `uv run pytest`
- ✅ Type checking: `uv run mypy my_script.py`
- ✅ Linting: `uv run ruff check .`

### Phase 2: Pre-Integration Checklist

Before integrating into a skill (Option D), verify your script is properly self-contained:

1. **Verify inline dependencies are current:**
   - Open your script's `# dependencies` section
   - Ensure all imports are listed with appropriate versions
   - Match versions from your working dev environment if needed

2. **Update usage documentation:**
   - Ensure the script's docstring has clear usage examples
   - Document all CLI arguments and expected inputs/outputs
   - Include any environment variable requirements

3. **Run quality checks:**
   ```bash
   # Type checking
   uv run mypy my_script.py

   # Linting
   uv run ruff check my_script.py

   # Auto-fix lint issues if desired
   uv run ruff check --fix my_script.py
   ```

4. **Test self-contained execution:**
   ```bash
   # Run without relying on venv - tests inline deps
   uv run my_script.py [args]

   # Verify tests also work standalone
   uv run test_my_script.py

   # Run all tests via pytest
   uv run pytest
   ```

5. **Review test coverage:**
   - Ensure test file has matching inline dependencies
   - Verify tests pass in isolation

**Example inline dependency block (should be in your script):**
```python
#!/usr/bin/env -S uv run
# /// script
# requires-python = ">=3.11"
# dependencies = [
#   "matplotlib>=3.8.0",
#   "numpy>=1.26.0",
#   "scipy>=1.11.0",
# ]
# ///
```

### Why This Workflow?

- **Development (Phase 1):** Use pyproject.toml + venv for modern Python IDE/testing experience
- **Deployment (Phase 2):** Inline dependencies ensure scripts work anywhere with just `uv run`
- **No Conflicts:** Each skill's scripts remain independent and portable
- **VS Code Integration:** Testing panel, Pylance, and debugger all work seamlessly

## Key Design Principles

### Single-File Portability
- Each script is fully self-contained with inline dependencies
- Can be copied to any skill's `scripts/` directory and just works
- `uv run` automatically creates temporary venv with required deps

### IDE Support Without Complexity
- **Dependencies**: Inline PEP 723 metadata (VS Code, PyCharm understand this)
- **Type/Lint Config**: Shared `pyproject.toml` at skill root
- Result: Full autocomplete, type checking, linting without per-script overhead

### Vibe Coding Friendly
- Script + test co-located in same directory
- Fast iteration: edit script → run test → get immediate feedback
- No need to switch contexts or manage separate test infrastructure

### Zero-Context Execution in Skills
- When Claude Code executes these scripts via a skill, only output is shown
- Script contents don't consume context tokens
- Perfect for utility operations: API calls, data processing, file manipulation

## Template Scripts

You can use `scripts/generate.py` to scaffold new scripts programmatically:

```bash
# Generate a new script with interactive prompts
python scripts/generate.py

# Generate with CLI args
python scripts/generate.py --name fetch_data --deps "requests,pandas" --purpose "Fetch and process API data"
```

## Version Management

For production use, consider:
- Tagging working versions with git SHA in script docstrings
- Maintaining a releases/ directory with known-good versions
- Using a sync skill to distribute updates across multiple skills

## Examples

### Example 1: Generate Script for Existing Skill (Option A)

User: "Generate a JIRA ticket creation script for my project-automation skill"

Claude asks: "Where would you like to generate this script?"
- Lists available skills (excluding uv-script-generator)
- User selects "project-automation" skill

Response generates in `.claude/skills/project-automation/`:
- `scripts/create_jira_ticket.py` - Uses requests, parses markdown, creates ticket
- `scripts/test_create_jira_ticket.py` - Mocks JIRA API, validates parsing
- `pyproject.toml` - Type checking and linting rules
- `.gitignore` - Python dev gitignore
- Updates `SKILL.md` with script documentation

### Example 2: Create New Skill with Script (Option B)

User: "Create a data-processing skill with a CSV to Parquet converter"

Claude asks: "Where would you like to generate this script?"
User selects: "New skill"
Claude asks: "What should the skill be named?"
User: "data-processing"

Response creates `.claude/skills/data-processing/`:
- `SKILL.md` - Basic skill documentation
- `scripts/csv_to_parquet.py` - Uses pandas, pyarrow, validates schema
- `scripts/test_csv_to_parquet.py` - Sample CSV fixtures, schema tests
- `pyproject.toml` - Shared config
- `.gitignore` - Python dev gitignore

### Example 3: Prototype Script in Any Directory (Option C)

User: "Generate a script to analyze log files, I want to prototype it first"

Claude asks: "Where would you like to generate this script?"
User selects: "Any directory (prototyping)"
Claude asks: "What directory?"
User: "./prototypes"

Response generates in `./prototypes/`:
- `analyze_logs.py` - Parses and analyzes log files
- `test_analyze_logs.py` - Tests with sample log data
- `pyproject.toml` - Config file
- `.gitignore` - Python dev gitignore

Claude: "Script generated in ./prototypes/. When ready, use Option D to integrate it into a skill."

### Example 4: Integrate Existing Script into Skill (Option D)

User: "Move my analyze_logs.py script into my monitoring skill"

Claude asks: "Where would you like to generate this script?"
User selects: "Integrate existing script into skill"
Claude asks: "What's the script path?"
User: "./prototypes/analyze_logs.py"
Claude asks: "Which skill?"
User: "monitoring"

Claude performs pre-integration checks:
1. Reads `analyze_logs.py` to verify inline dependencies are present and current
2. Checks that usage documentation in docstring is complete
3. Runs quality checks: `uv run mypy analyze_logs.py` and `uv run ruff check analyze_logs.py`
4. Runs tests: `uv run test_analyze_logs.py`
5. Optionally runs `uv run analyze_logs.py --help` to verify it works standalone

Response:
- Copies `analyze_logs.py` and `test_analyze_logs.py` to `.claude/skills/monitoring/scripts/`
- Updates `.claude/skills/monitoring/pyproject.toml` with any new dependencies
- Creates `.claude/skills/monitoring/.gitignore` if it doesn't exist
- Updates `.claude/skills/monitoring/SKILL.md` to document the new script
- Reminds user that the script's inline dependencies make it self-contained

## Troubleshooting

**Pylance/IDE import errors ("could not be resolved"):**
- Create a development venv: `uv venv && uv sync`
- Select the interpreter in VS Code: `Cmd+Shift+P` → "Python: Select Interpreter" → `.venv/bin/python`
- Ensure `[dependency-groups]` dev section in pyproject.toml includes all your script's dependencies
- The venv is only for IDE support; scripts still use inline dependencies at runtime

**VS Code Testing panel not working:**
- Ensure pytest is in your dev dependencies: `uv pip install pytest`
- Check `[tool.pytest.ini_options]` in pyproject.toml has correct `testpaths`
- Reload VS Code window after selecting the interpreter
- Run `uv run pytest` to verify tests work from command line first

**IDE not recognizing dependencies (alternate approach):**
- Ensure Python extension is installed and active
- Try opening just the script file (not whole directory) in some IDEs
- Check that `uv` is installed: `uv --version`

**Type checking errors:**
- Run `mypy scripts/my_script.py` to see specific issues
- Adjust strictness in `pyproject.toml` if needed for prototyping

**Import errors in tests:**
- Ensure test file includes the sys.path manipulation shown in template
- Verify both script and test have matching dependency versions

**Script works in venv but fails with `uv run`:**
- Check that inline `# dependencies` in script header match what you installed
- The inline dependencies must be complete and current for standalone execution
- Run `uv run --isolated my_script.py` to test with fresh environment

## Notes

- This skill is optimized for **prototyping and vibe coding** with rusty Python skills
- Scripts are meant to be **used in other Claude Code skills**, not run standalone as applications
- Tests are co-located for fast iteration, can be moved to separate directory later for release management
