---
phase: 11-pypi-packaging
plan: 02
type: execute
wave: 2
depends_on:
  - 11-01
files_modified:
  - README.md
  - dist/vmcluster_mcp-1.0.0-py3-none-any.whl
  - dist/vmcluster_mcp-1.0.0.tar.gz
autonomous: false
requirements:
  - INST-01

user_setup:
  - service: pypi
    why: "Publish vmcluster-mcp package to PyPI (first publish requires account-wide token)"
    env_vars:
      - name: UV_PUBLISH_TOKEN
        source: "PyPI account — https://pypi.org/manage/account/token/ — create an account-wide token (not project-scoped) for first upload"
    dashboard_config:
      - task: "Create PyPI API token"
        location: "https://pypi.org/manage/account/token/ — Account Settings -> API tokens -> Add API token"
        notes: "Use 'Entire account' scope for first publish. After vmcluster-mcp exists on PyPI, create a project-scoped token for future publishes."

must_haves:
  truths:
    - "README.md Installation section shows pip install vmcluster-mcp as primary install path"
    - "README.md Installation section shows uvx vmcluster-mcp as zero-install alternative"
    - "uv build produces dist/vmcluster_mcp-1.0.0-py3-none-any.whl and dist/vmcluster_mcp-1.0.0.tar.gz without errors"
    - "Wheel contains all vmcluster_mcp/ subpackages (artifact, cluster, exec, net, observe, snapshot, topology)"
    - "vmcluster-mcp package exists on PyPI at https://pypi.org/project/vmcluster-mcp/"
  artifacts:
    - path: "README.md"
      provides: "Updated Installation section with pip/uvx install paths"
      contains: "pip install vmcluster-mcp"
    - path: "dist/vmcluster_mcp-1.0.0-py3-none-any.whl"
      provides: "Installable wheel for PyPI upload"
  key_links:
    - from: "dist/vmcluster_mcp-1.0.0-py3-none-any.whl"
      to: "PyPI"
      via: "uv publish --token $UV_PUBLISH_TOKEN"
      pattern: "vmcluster_mcp-1.0.0-py3-none-any.whl"
---

<objective>
Update README Installation section to reflect PyPI availability, build the distribution artifacts with uv build, verify wheel contents, then publish to PyPI via uv publish.

Purpose: Completes INST-01 — the package becomes installable with pip install vmcluster-mcp and runnable with uvx vmcluster-mcp.
Output: Updated README.md, dist/ artifacts, live PyPI package at https://pypi.org/project/vmcluster-mcp/
</objective>

<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/phases/11-pypi-packaging/11-01-SUMMARY.md
@.planning/phases/11-pypi-packaging/11-VALIDATION.md
</context>

<tasks>

<task type="auto">
  <name>Task 1: Update README Installation section for PyPI</name>
  <files>README.md</files>
  <read_first>
    - README.md (read the full Installation section before editing — lines ~68-95 contain the current install instructions)
  </read_first>
  <action>
Replace the `## Installation` section of README.md. The current section (lines ~68-95) shows only source-based install. Replace the entire `## Installation` section with this content, preserving everything before and after the section:

```markdown
## Installation

### From PyPI (recommended)

Install the latest release:

```bash
pip install vmcluster-mcp
```

Or run directly without installing (via [uv](https://docs.astral.sh/uv/)):

```bash
uvx vmcluster-mcp
```

> **Prerequisite:** `libvirt-python` requires system-level development headers. Install them before running `pip install`:
>
> ```bash
> # Ubuntu/Debian
> sudo apt-get install -y libvirt-dev pkg-config gcc
>
> # Fedora/RHEL
> sudo dnf install -y libvirt-devel pkgconf-pkg-config gcc
>
> # Arch Linux
> sudo pacman -S libvirt pkgconf gcc
> ```

### From source (development)

```bash
git clone https://github.com/hornc/vmcluster-mcp.git
cd vmcluster-mcp

# Create virtual environment and install
uv venv
uv pip install -e .
```
```

Note: the three backtick code fences must be actual markdown code fences. Do not alter any other section of README.md.
  </action>
  <verify>
    <automated>grep -n "pip install vmcluster-mcp" README.md && grep -n "uvx vmcluster-mcp" README.md</automated>
  </verify>
  <acceptance_criteria>
    - README.md contains `pip install vmcluster-mcp` (grep-verifiable)
    - README.md contains `uvx vmcluster-mcp` (grep-verifiable)
    - README.md contains `libvirt-python` in the Installation section (grep-verifiable — D-12 prerequisite note)
    - README.md contains `libvirt-dev` (grep-verifiable — apt package name for Ubuntu/Debian)
    - README.md still contains `## Quick Start` heading (no accidental truncation)
    - README.md still contains `## Prerequisites` heading (no accidental truncation)
  </acceptance_criteria>
  <done>README.md Installation section shows pip install + uvx as primary paths, with libvirt-dev prerequisite note and source install as secondary option.</done>
</task>

<task type="auto">
  <name>Task 2: Build distribution artifacts and verify wheel contents</name>
  <files>dist/vmcluster_mcp-1.0.0-py3-none-any.whl, dist/vmcluster_mcp-1.0.0.tar.gz</files>
  <read_first>
    - pyproject.toml (confirm version = "1.0.0" and [project.scripts] are present before building)
  </read_first>
  <action>
Run the following commands in sequence. Stop and report any failure:

1. Clean any stale artifacts:
   ```bash
   rm -rf dist/
   ```

2. Build sdist and wheel:
   ```bash
   uv build
   ```
   Expected output ends with: `Successfully built dist/vmcluster_mcp-1.0.0.tar.gz` and `dist/vmcluster_mcp-1.0.0-py3-none-any.whl`

3. Inspect wheel contents — all subpackages must be present:
   ```bash
   unzip -l dist/vmcluster_mcp-1.0.0-py3-none-any.whl | grep vmcluster_mcp/
   ```
   Expected: lines for vmcluster_mcp/__init__.py, __main__.py, server.py, models.py, config.py AND all subpackages: artifact/, cluster/, exec/, net/, observe/, snapshot/, topology/

4. Run the full test suite to confirm nothing broke:
   ```bash
   .venv/bin/pytest tests/ -q
   ```

If any step fails, do NOT proceed to the checkpoint — report the exact error output.
  </action>
  <verify>
    <automated>.venv/bin/pytest tests/ -q && unzip -l dist/vmcluster_mcp-1.0.0-py3-none-any.whl | grep "vmcluster_mcp/" | grep -E "(artifact|cluster|exec|net|observe|snapshot|topology)"</automated>
  </verify>
  <acceptance_criteria>
    - dist/vmcluster_mcp-1.0.0-py3-none-any.whl exists (file exists check)
    - dist/vmcluster_mcp-1.0.0.tar.gz exists (file exists check)
    - `unzip -l dist/vmcluster_mcp-1.0.0-py3-none-any.whl` output contains `vmcluster_mcp/artifact/` (grep-verifiable)
    - `unzip -l dist/vmcluster_mcp-1.0.0-py3-none-any.whl` output contains `vmcluster_mcp/cluster/` (grep-verifiable)
    - `unzip -l dist/vmcluster_mcp-1.0.0-py3-none-any.whl` output contains `vmcluster_mcp/topology/` (grep-verifiable)
    - `unzip -l dist/vmcluster_mcp-1.0.0-py3-none-any.whl` output contains `vmcluster_mcp/__main__.py` (grep-verifiable)
    - .venv/bin/pytest tests/ -q exits 0 (full suite green)
  </acceptance_criteria>
  <done>dist/ contains both sdist and wheel; wheel contains all vmcluster_mcp/ subpackages; full test suite passes.</done>
</task>

<task type="checkpoint:human-verify" gate="blocking">
  <name>Task 3: Human verify and publish to PyPI</name>
  <files>dist/vmcluster_mcp-1.0.0-py3-none-any.whl, dist/vmcluster_mcp-1.0.0.tar.gz</files>
  <action>
Human publishes to PyPI using the instructions in how-to-verify. Claude cannot perform this step — it requires a PyPI API token that only the user holds. Claude has already built and verified the distribution artifacts in Task 2.
  </action>
  <verify>
    <automated>curl -s https://pypi.org/pypi/vmcluster-mcp/json | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['info']['version'])"</automated>
  </verify>
  <done>vmcluster-mcp 1.0.0 is live on PyPI; curl to PyPI JSON API returns version 1.0.0.</done>
  <what-built>
    - README.md updated with pip install + uvx install paths and libvirt-dev prereq note
    - dist/vmcluster_mcp-1.0.0-py3-none-any.whl and dist/vmcluster_mcp-1.0.0.tar.gz built
    - All wheel subpackages verified present
    - Full test suite green
  </what-built>
  <how-to-verify>
    **Before publishing, verify manually:**

    1. Confirm wheel contents look correct:
       ```bash
       unzip -l dist/vmcluster_mcp-1.0.0-py3-none-any.whl
       ```

    2. Confirm the entry point exists in wheel metadata:
       ```bash
       unzip -p dist/vmcluster_mcp-1.0.0-py3-none-any.whl "vmcluster_mcp-1.0.0.dist-info/entry_points.txt"
       ```
       Expected output contains: `vmcluster-mcp = vmcluster_mcp.__main__:main`

    3. Get a PyPI account-wide API token from https://pypi.org/manage/account/token/
       (Account scope required for first publish — project scope not yet available)

    4. Publish:
       ```bash
       UV_PUBLISH_TOKEN=pypi-your-token-here uv publish
       ```
       Expected: "Uploading vmcluster_mcp-1.0.0-py3-none-any.whl... 200 OK"
                 "Uploading vmcluster_mcp-1.0.0.tar.gz... 200 OK"

    5. Verify on PyPI:
       ```bash
       curl -s https://pypi.org/pypi/vmcluster-mcp/json | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['info']['version'])"
       ```
       Expected output: `1.0.0`

    6. Verify installable from PyPI (in a clean temp env):
       ```bash
       uv run --with vmcluster-mcp --no-project python -c "from vmcluster_mcp.__main__ import main; print('entry point ok:', callable(main))"
       ```
       Expected: `entry point ok: True`

    **If publish fails with 403:** Token is project-scoped or invalid. Use an account-wide token.
    **If package name taken:** The name vmcluster-mcp was available on 2026-03-24. If taken, report back.
  </how-to-verify>
  <resume-signal>Type "published" when PyPI shows version 1.0.0, or describe any errors encountered.</resume-signal>
</task>

</tasks>

<verification>
After checkpoint approval:
- curl -s https://pypi.org/pypi/vmcluster-mcp/json returns JSON with version 1.0.0
- README.md contains "pip install vmcluster-mcp"
- .venv/bin/pytest tests/ -q exits 0
</verification>

<success_criteria>
- vmcluster-mcp 1.0.0 is live on PyPI at https://pypi.org/project/vmcluster-mcp/
- pip install vmcluster-mcp installs without errors (given system libvirt headers)
- uvx vmcluster-mcp works post-publish
- README.md documents the PyPI install path as primary
- INST-01 is satisfied: single-command install from PyPI
</success_criteria>

<output>
After completion, create `.planning/phases/11-pypi-packaging/11-02-SUMMARY.md`
</output>
