# GodotIQ PyPI Distribution — Implementation Plan

## 1. Context and Goal

GodotIQ is an MCP (Model Context Protocol) server for AI-assisted Godot 4.x game development. It currently runs from source via `uv run`. This plan packages it for PyPI distribution so users can install with `pip install godotiq` and AI clients can launch it via `uvx godotiq`.

The package ships two components:
1. **Python MCP server** — 35 tools across 9 categories, spawned by AI clients as a subprocess
2. **Godot editor addon** — 6 GDScript files bundled as package data, installed into Godot projects via a CLI command

After this work, the installation flow is:
```
pip install godotiq                          # or: uvx godotiq (for MCP clients)
godotiq install-addon /path/to/godot/project # copies addon + rules to Godot project
```

## 2. Current State

### Build System
- Hatchling build backend (already configured)
- src-layout: `src/godotiq/`
- `pyproject.toml` exists with basic metadata
- Console script: `godotiq = "godotiq.server:main"` (already defined)
- `__main__.py` exists for `python -m godotiq`

### What's Missing
- Package data config for addon files (outside `src/`)
- CLI subcommand routing (currently `godotiq` only starts server)
- Dynamic `__version__` in `__init__.py`
- Full PyPI metadata (author, URLs, classifiers, keywords)
- README installation instructions
- Verification that prompts `.md` files are included in the wheel
- Hardcoded `"version": "0.1.0"` in `godotiq_ping` tool needs to use dynamic version

## 3. Package Data Strategy

### Addon Files
The addon lives at `godot-addon/addons/godotiq/` — outside the Python package tree. Hatchling's `force-include` maps external paths into the wheel:

```
Source: godot-addon/addons/godotiq/  →  Wheel: godotiq/addon/
```

Files to include: all files in the directory (`plugin.cfg`, 5x `.gd`, `.gitkeep`). The `.gitkeep` is harmless and not worth adding exclusion config for.

An `__init__.py` is created at `src/godotiq/addon/__init__.py` so `Path(__file__).parent` resolves the addon directory at runtime. This avoids `importlib.resources` complexity.

### Prompt Files
Already inside `src/godotiq/prompts/`. Hatchling includes VCS-tracked files by default. The existing loading code (`Path(__file__).parent / "prompts" / "godot_development.md"`) will work without changes. Must verify inclusion in built wheel. **Fallback:** if prompts are missing from the wheel, add them to `force-include` explicitly.

## 4. CLI Architecture

### Design
Currently, `server.py:main()` directly calls `mcp.run(transport="stdio")`. The CLI must support:
- `godotiq` (no args) → starts MCP server (backward compatible — this is what AI clients call)
- `godotiq install-addon <path>` → copies addon files and rules to a Godot project
- `godotiq --version` → prints version string

### New Module: `cli.py`

```python
def cli_main() -> None:
    """Parse args and dispatch to serve or install-addon."""
```

Uses stdlib `argparse` with subcommands. If no subcommand is given, defaults to starting the server (preserving backward compatibility with existing `.mcp.json` configs that call `godotiq` with no args).

Includes `--version` flag: `parser.add_argument("--version", action="version", version=__version__)`.

The `[project.scripts]` entry point changes from `godotiq.server:main` to `godotiq.cli:cli_main`.

**CRITICAL: Lazy imports.** `cli.py` must NOT import `server.py` at module scope. The `server.py` module performs side-effectful imports that register all 35 MCP tools, load parsers, and initialize the bridge subsystem. Importing it for the `install-addon` path would add seconds of unnecessary startup latency.

The serve dispatch must use a local import:
```python
def _serve() -> None:
    """Start the MCP server (lazy import to avoid loading all tools for other subcommands)."""
    # Import here, not at module scope
```

### `__main__.py` Update
Changes to call `cli_main()` instead of `server.main()` directly.

**Note:** `server.py` line 61 has a `sys.modules.setdefault` hack for the `python -m` double-import scenario. After this change, `python -m godotiq` loads `__main__.py` → `cli_main()` → `server.main()`, so `server.py` is always loaded under its canonical name `godotiq.server`. The hack becomes a harmless no-op. It should NOT be removed in this sprint to avoid scope creep — just verify it doesn't interfere.

### install-addon Subcommand Behavior

```python
def install_addon(target_dir: str, dry_run: bool = False) -> None:
    """Copy addon files and GODOTIQ_RULES.md to a Godot project."""
```

1. Resolves `target_dir` with `Path(target_dir).resolve()` for safety
2. Validates target exists and contains `project.godot` (confirms it's a Godot project)
3. If `--dry-run`: prints what would be copied and exits
4. Creates `<target_dir>/addons/godotiq/` if missing
5. Copies all addon files (`.gd` + `plugin.cfg`) from `godotiq/addon/` package data
6. Copies `godot_development.md` from `godotiq/prompts/` as `<target_dir>/GODOTIQ_RULES.md`
7. Prints summary of copied files (distinguishes "added" vs "updated" for each file)
8. If files already exist, overwrites with a warning (enables updates)

Flags:
- `--dry-run`: list files that would be copied without actually copying

Uses `shutil.copy2` for file copying. Uses `Path(__file__)` relative paths to locate package data.

## 5. Version Exposure

Add `__version__` to `src/godotiq/__init__.py` using dynamic resolution:

```python
def _get_version() -> str:
    """Read version from package metadata (single source of truth: pyproject.toml)."""

__version__: str = _get_version()
```

Uses `importlib.metadata.version("godotiq")`. Falls back to `"0.0.0-dev"` if package is not installed (editable installs during development should work fine since `pip install -e .` registers metadata).

**Also update `server.py`:** The `godotiq_ping` tool has a hardcoded `"version": "0.1.0"`. Change it to use `from godotiq import __version__` and return `{"status": "ok", "version": __version__}`. This prevents version drift.

## 6. pyproject.toml Changes

### Metadata Additions
- `authors`: Salvatore Farruggio (coolvolve.info@gmail.com)
- `keywords`: godot, mcp, game-development, ai, godot-engine
- `classifiers`: Development Status 4-Beta, Python 3.10/3.11/3.12, MIT, Games/Entertainment, Topic :: Software Development :: Libraries
- `[project.urls]`: Homepage, Repository, Issues → github.com/godotiq/godotiq

### Build Configuration
```toml
[tool.hatch.build.targets.wheel]
packages = ["src/godotiq"]

[tool.hatch.build.targets.wheel.force-include]
"godot-addon/addons/godotiq" = "godotiq/addon"
```

### Entry Point Update
```toml
[project.scripts]
godotiq = "godotiq.cli:cli_main"
```

### Dev Dependencies Addition
Add `build` to `[project.optional-dependencies] dev` for local wheel building.

## 7. README Update

Add a new "Installation" section near the top:
- `pip install godotiq` for direct install
- `.mcp.json` configuration example with `uvx`
- `godotiq install-addon /path/to/godot/project` usage
- Brief explanation of what the addon provides
- Fix tool count references from 32 to the actual current count (35)

Keep all existing content. Insert installation section before technical details.

## 8. Verification Plan

### 8.1 Build Verification
1. `python -m build` succeeds, produces `.whl` and `.tar.gz` in `dist/`
2. `unzip -l dist/godotiq-0.1.0-py3-none-any.whl` shows:
   - All `godotiq/*.py` modules
   - `godotiq/addon/plugin.cfg`, `godotiq/addon/*.gd`
   - `godotiq/prompts/*.md`
3. No unexpected files (no tests, no docs, no `.git`)

### 8.2 Install Verification
1. `pip install dist/godotiq-0.1.0-py3-none-any.whl` in a clean venv
2. `godotiq --help` shows subcommands
3. `godotiq --version` prints `0.1.0`
4. `godotiq` starts MCP server (responds to ping, registers 35 tools)
5. `godotiq install-addon /tmp/test-godot-project/` copies all files correctly
6. `godotiq install-addon --dry-run /tmp/test-godot-project/` lists files without copying
7. `python -c "from godotiq import __version__; print(__version__)"` prints `0.1.0`

### 8.3 Test Verification
1. All 1128 existing tests pass
2. New tests for:
   - `cli.py` argument parsing (default=serve, install-addon subcommand, --version, --help)
   - `install-addon` file copying (correct files, correct destinations, GODOTIQ_RULES.md)
   - `install-addon` validation (non-existent path, non-Godot project)
   - `install-addon --dry-run` (no files created)
   - `__version__` is accessible and equals `"0.1.0"`

## 9. Risk Analysis

| Risk | Mitigation |
|------|------------|
| Addon files not included in wheel | Verify with `unzip -l` after build. The `force-include` config is deterministic. |
| Prompt .md files missing from wheel | Hatchling includes VCS-tracked files. Verify after build. Fallback: add to `force-include`. |
| `godotiq` command breaks for existing users | Default (no args) still starts server. No behavioral change for AI clients. |
| `importlib.metadata` fails in editable install | `pip install -e .` registers metadata. Fallback to `"0.0.0-dev"` for safety. |
| `uvx godotiq` doesn't find entry point | Package name matches console_scripts name — this works automatically. |
| `cli.py` importing `server.py` slows down `install-addon` | Lazy import: `server.main` imported inside function body, not at module scope. |

## 10. File Change Summary

| File | Action | Section |
|------|--------|---------|
| `pyproject.toml` | Modify | Metadata, force-include, entry point, dev deps |
| `src/godotiq/__init__.py` | Modify | Add `__version__` |
| `src/godotiq/server.py` | Modify | Use `__version__` in `godotiq_ping` |
| `src/godotiq/cli.py` | **Create** | argparse CLI with serve + install-addon + --version |
| `src/godotiq/__main__.py` | Modify | Route through cli.py |
| `src/godotiq/addon/__init__.py` | **Create** | Empty init for path resolution |
| `README.md` | Modify | Add installation section, fix tool count |
| `tests/test_cli.py` | **Create** | CLI + install-addon tests |

## 11. Implementation Order

1. **pyproject.toml** — metadata, force-include, entry point change
2. **addon/__init__.py** — create empty package marker
3. **__init__.py** — add dynamic `__version__`
4. **server.py** — use `__version__` in `godotiq_ping`
5. **cli.py** — create CLI module with subcommands (lazy imports!)
6. **__main__.py** — update to use cli
7. **Build + verify wheel** — confirm all files included
8. **tests/test_cli.py** — test CLI and install-addon
9. **README.md** — update with installation instructions, fix tool count
10. **Final: run all 1128+ tests** — confirm nothing broke
