# Task Recon: Initialize Python Project Structure

**Task ID:** 1
**Status:** pending
**Generated:** 2026-01-28T20:00:00Z
**Agent:** claude-sonnet-4-20250514

---

## Task Summary

Initialize a Python CLI project using the uv package manager with proper project metadata, dependencies, tooling configuration (ruff, mypy), and pre-commit hooks. This establishes the foundation for the Teams Phone CLI application following modern Python best practices.

### Dependencies
- Depends on: None (first task in the project)

### Acceptance Criteria
1. `pyproject.toml` exists with complete project metadata and all required dependencies
2. Directory structure matches architecture specification (src/teams_phone/ with subdirs, tests/ with subdirs)
3. Ruff linter/formatter is configured in pyproject.toml
4. Mypy type checker is configured in strict mode
5. `.pre-commit-config.yaml` is created with hooks for ruff and mypy
6. All stub Python files (`__init__.py`, `__main__.py`, etc.) are created
7. Test verification passes: `uv sync`, `uv run python -c "import teams_phone"`, `uv run ruff check .`, `uv run mypy src/`

---

## Insights from Previous Tasks

### Dependency Task Notes
No previous implementation notes available for dependency tasks.

### Reusable Patterns from Dependencies
This is the first task - no patterns available yet.

### Warnings and Gotchas
None - greenfield project initialization.

### Open Items Inherited
None - this is the foundational task.

---

## Architecture Context

### Relevant Design Decisions

**From Architecture Document (`.taskmaster/docs/architecture/`):**

1. **Greenfield Python Project** (1-introduction.md:10-12)
   - No starter template being used
   - Standard Python project conventions
   - Tech stack: Python 3.10+, Typer, httpx, MSAL

2. **Tech Stack Definitive Choices** (3-tech-stack.md:3)
   - This section is the SINGLE SOURCE OF TRUTH for all technology selections
   - Language: Python 3.10+ (currently have Python 3.14.0 installed)
   - Package Manager: uv ^0.1.0 (currently have uv 0.9.17 installed)
   - Linting/Formatting: Ruff ^0.1.0 (replaces flake8, black, isort)
   - Type Checking: mypy ^1.7.0 with strict mode

3. **Directory Structure** (9-source-tree.md:3-76)
   - Package name: `teams_phone` (NOT `teams-phone`)
   - Source root: `src/teams_phone/`
   - Test root: `tests/` (with unit/, integration/, contract/, fixtures/)
   - Configuration: `pyproject.toml` at project root
   - Dependencies lockfile: `uv.lock`

4. **Development Tools** (3-tech-stack.md:31-38)
   - uv: Package management + virtual environments
   - Ruff: Single tool for linting AND formatting
   - mypy: Type checking in strict mode
   - pre-commit: Git hooks for quality checks

### Module Structure

**Project Layout (per source tree specification):**

```
teams-phone-cli/
├── src/
│   └── teams_phone/              # Main package (note: underscore, not dash)
│       ├── __init__.py           # Package version, metadata
│       ├── __main__.py           # Entry point: python -m teams_phone
│       ├── cli/                  # CLI Layer (Typer commands)
│       │   └── __init__.py
│       ├── services/             # Service Layer (business logic)
│       │   └── __init__.py
│       ├── infrastructure/       # Infrastructure Layer
│       │   └── __init__.py
│       ├── models/               # Pydantic models
│       │   └── __init__.py
│       ├── exceptions.py         # Custom exception hierarchy
│       ├── constants.py          # API URLs, exit codes, defaults
│       └── utils.py              # Phone number normalization, helpers
│
├── tests/
│   ├── __init__.py
│   ├── conftest.py               # Pytest fixtures
│   ├── unit/                     # Unit tests (mocked)
│   ├── integration/              # Integration tests (real API)
│   └── fixtures/                 # Test data files
│
├── pyproject.toml                # Project metadata, dependencies
├── uv.lock                       # Dependency lockfile (auto-generated)
└── .pre-commit-config.yaml       # Pre-commit hooks config
```

**Current State:**
- Directories already exist (src/teams_phone/ with subdirs, tests/ with subdirs)
- No Python files created yet
- No `pyproject.toml` yet
- No `.pre-commit-config.yaml` yet
- `.venv` already exists (created by someone previously)

### Conventions to Follow

**From Coding Standards (12-coding-standards.md):**

1. **Pydantic for ALL API responses** (line 16)
   - Never use raw dicts
   - Always validate with `extra='forbid'`

2. **Pydantic Model Standards** (lines 27-41)
   ```python
   from pydantic import BaseModel, Field, ConfigDict

   class Example(BaseModel):
       model_config = ConfigDict(
           extra="forbid",           # CRITICAL: Fail on unknown fields
           populate_by_name=True,    # Allow both snake_case and camelCase
       )
   ```

3. **Python Version** (line 7)
   - Python 3.10+ required (we have 3.14.0)
   - Use modern syntax

4. **Type Checking** (line 9)
   - mypy in strict mode
   - All functions should have type hints

---

## Related Code References

### Primary References (Must Read)

**IMPORTANT:** This is a greenfield project - no existing code to reference. The directory structure has been created but contains no Python files yet.

| File | Status | Notes |
|------|--------|-------|
| `src/teams_phone/` | Empty dirs exist | Need to create __init__.py, __main__.py, exceptions.py, constants.py, utils.py |
| `src/teams_phone/cli/` | Empty dir exists | Need __init__.py |
| `src/teams_phone/services/` | Empty dir exists | Need __init__.py |
| `src/teams_phone/infrastructure/` | Empty dir exists | Need __init__.py |
| `src/teams_phone/models/` | Empty dir exists | Need __init__.py |
| `tests/` | Empty dirs exist | Need conftest.py and __init__.py in subdirs |

### Secondary References (Documentation)

| File | Lines | Purpose |
|------|-------|---------|
| `.taskmaster/docs/architecture/3-tech-stack.md` | 1-49 | Complete technology stack specification (DEFINITIVE) |
| `.taskmaster/docs/architecture/9-source-tree.md` | 1-79 | Complete source tree structure |
| `.taskmaster/docs/architecture/12-coding-standards.md` | 1-44 | Coding standards and patterns |
| `.taskmaster/docs/architecture/13-test-strategy.md` | 1-32 | Test organization and markers |

### Code Patterns to Follow

**Example pyproject.toml structure (from Context7 docs):**

```toml
[project]
name = "teams-phone-cli"
version = "0.1.0"
description = "CLI tool for managing Microsoft Teams Phone configurations"
readme = "README.md"
requires-python = ">=3.10"
dependencies = [
    "typer>=0.9.0",
    "httpx>=0.25.0",
    "msal>=1.24.0",
    "rich>=13.0.0",
    "pydantic>=2.0.0",
]

[dependency-groups]
dev = [
    "pytest>=7.4.0",
    "pytest-mock>=3.12.0",
    "pytest-asyncio>=0.21.0",
    "respx>=0.20.0",
    "ruff>=0.1.0",
    "mypy>=1.7.0",
]

[build-system]
requires = ["uv_build>=0.9.26,<0.10.0"]
build-backend = "uv_build"

[tool.ruff]
line-length = 88
target-version = "py310"

[tool.ruff.lint]
select = ["E4", "E7", "E9", "F"]
fixable = ["ALL"]

[tool.mypy]
python_version = "3.10"
strict = true
warn_return_any = true
warn_unused_configs = true
```

**Example .pre-commit-config.yaml (from web research):**

```yaml
repos:
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.14.14
    hooks:
      - id: ruff-check
        args: [--fix]
      - id: ruff-format

  - repo: https://github.com/pre-commit/mirrors-mypy
    rev: v1.11.0
    hooks:
      - id: mypy
        args: [--strict]
```

---

## Dependencies

### Internal Modules
None - this task creates the foundation. No internal dependencies yet.

### External Packages

**Production Dependencies** (from tech-stack.md:16-22):
- `typer ^0.9.0` - CLI framework with auto-completion and Rich integration
- `httpx ^0.25.0` - Async HTTP client for Graph API calls
- `msal ^1.24.0` - Microsoft Authentication Library for Entra ID auth
- `rich ^13.0.0` - Terminal UI (tables, progress bars, colored output)
- `pydantic ^2.0.0` - Data validation and serialization

**Development Dependencies** (from tech-stack.md:23-29):
- `pytest ^7.4.0` - Testing framework
- `pytest-mock ^3.12.0` - Mocking utilities for pytest
- `pytest-asyncio ^0.21.0` - Async testing support
- `respx ^0.20.0` - HTTP mocking for httpx
- `ruff ^0.1.0` - Linter and formatter (single tool)
- `mypy ^1.7.0` - Static type checker

**Note on Version Constraints:**
- Use `>=` (greater than or equal) for production dependencies per modern uv best practices
- The `^` notation in the task description is from older package managers
- uv prefers explicit version ranges: `>=0.9.0` instead of `^0.9.0`

### New Dependencies Needed
None - all dependencies are specified above and should be added to pyproject.toml.

---

## Testing Guidance

### Test File Location
**Note:** No test files exist yet. This task creates the structure.

**Expected test structure** (from 13-test-strategy.md):
```
tests/
├── __init__.py             # Make tests a package
├── conftest.py             # Pytest fixtures (CREATE THIS)
├── unit/                   # Fast tests with mocked dependencies
│   └── __init__.py
├── integration/            # Real Graph API calls against test tenant
│   └── __init__.py
└── fixtures/               # Test data files
    └── __init__.py
```

### Test Patterns in Use

**Test Markers** (from 13-test-strategy.md:22-29):
```python
# In conftest.py, define markers:
pytest_plugins = []

def pytest_configure(config):
    config.addinivalue_line("markers", "unit: Fast unit tests with mocks")
    config.addinivalue_line("markers", "integration: Tests requiring real API")
    config.addinivalue_line("markers", "contract: API contract validation tests")
```

**Coverage Goals** (from 13-test-strategy.md:3-11):
- Services: >90%
- Infrastructure: >85%
- CLI: >75%
- Models: >95%
- Overall: >80%

### Fixtures Available
None yet - this task creates the initial conftest.py

### Test Utilities
**Initial conftest.py should include:**
- pytest configuration
- Test markers definition
- Common fixtures for future tests (will be expanded in later tasks)

---

## Risks and Blockers

### Technical Risks
- [x] **Python Version Compatibility:** Architecture specifies Python 3.10+, we have 3.14.0 installed. This is fine - we should set `requires-python = ">=3.10"` to allow 3.10+.
- [x] **uv Version:** Architecture specifies uv ^0.1.0, we have uv 0.9.17. Modern uv uses different pyproject.toml syntax (dependency-groups instead of optional-dependencies). Use current uv best practices.
- [x] **Package Name Mismatch:** PyPI package names use dashes (`teams-phone-cli`) but Python import names use underscores (`teams_phone`). This is standard Python convention - package as `teams-phone-cli`, import as `teams_phone`.

### Dependency Risks
None - this is task 1 with no dependencies.

### Open Questions
- [x] **Should we create a README.md?** - Not specified in task details, but typical for Python projects. **Decision:** Skip for now, likely covered in a documentation task later.
- [x] **Should we create a LICENSE file?** - Not specified in task details. **Decision:** Skip for now, likely covered in a separate task.
- [x] **What version number to use?** - Task doesn't specify. **Decision:** Use `0.1.0` as standard for initial projects.
- [x] **Should __init__.py files have content?** - For now, create empty files to make directories Python packages. Version metadata will be added to `src/teams_phone/__init__.py` in later tasks.
- [x] **Ruff configuration completeness:** The task says "configure ruff" but doesn't specify which rules. **Decision:** Use Ruff's default configuration (E4, E7, E9, F) as a starting point. Can be expanded later.
- [x] **Mypy configuration completeness:** Task says "strict mode" but no other details. **Decision:** Use `strict = true` with basic strict options.

---

## Implementation Recommendations

### Suggested Approach

1. **Create pyproject.toml**
   - Define [project] section with metadata
   - Add production dependencies using `>=` version constraints
   - Add dev dependencies in [dependency-groups] section (modern uv syntax)
   - Add [build-system] section for uv
   - Add [tool.ruff] and [tool.ruff.lint] configuration
   - Add [tool.mypy] configuration with strict mode

2. **Create stub Python files**
   - `src/teams_phone/__init__.py` - Empty for now (version will be added later)
   - `src/teams_phone/__main__.py` - Empty for now (CLI entry point added later)
   - `src/teams_phone/exceptions.py` - Empty stub
   - `src/teams_phone/constants.py` - Empty stub
   - `src/teams_phone/utils.py` - Empty stub
   - `src/teams_phone/cli/__init__.py` - Empty
   - `src/teams_phone/services/__init__.py` - Empty
   - `src/teams_phone/infrastructure/__init__.py` - Empty
   - `src/teams_phone/models/__init__.py` - Empty

3. **Create test infrastructure**
   - `tests/__init__.py` - Empty
   - `tests/conftest.py` - With pytest markers configuration
   - `tests/unit/__init__.py` - Empty
   - `tests/integration/__init__.py` - Empty
   - `tests/fixtures/__init__.py` - Empty

4. **Create .pre-commit-config.yaml**
   - Add ruff-pre-commit hook with ruff-check and ruff-format
   - Add mypy hook with strict args

5. **Update .gitignore**
   - Current .gitignore is for Node.js (has npm, yarn references)
   - Add Python-specific entries: `__pycache__/`, `*.pyc`, `*.pyo`, `.pytest_cache/`, `.mypy_cache/`, `.ruff_cache/`, `dist/`, `build/`, `*.egg-info/`, `.venv/`, `venv/`, `uv.lock`

6. **Verify setup**
   - Run `uv sync` to install dependencies and verify pyproject.toml is valid
   - Run `uv run python -c "import teams_phone"` to verify package imports
   - Run `uv run ruff check .` to verify ruff works (should pass with no files to check)
   - Run `uv run mypy src/` to verify mypy works (should pass with empty files)

### Files to Create/Modify

| Action | File | Reason |
|--------|------|--------|
| Create | `pyproject.toml` | Project metadata, dependencies, tool configuration |
| Create | `.pre-commit-config.yaml` | Git hooks for code quality |
| Modify | `.gitignore` | Add Python-specific ignore patterns |
| Create | `src/teams_phone/__init__.py` | Package root |
| Create | `src/teams_phone/__main__.py` | CLI entry point stub |
| Create | `src/teams_phone/exceptions.py` | Exception hierarchy stub |
| Create | `src/teams_phone/constants.py` | Constants stub |
| Create | `src/teams_phone/utils.py` | Utilities stub |
| Create | `src/teams_phone/cli/__init__.py` | CLI module marker |
| Create | `src/teams_phone/services/__init__.py` | Services module marker |
| Create | `src/teams_phone/infrastructure/__init__.py` | Infrastructure module marker |
| Create | `src/teams_phone/models/__init__.py` | Models module marker |
| Create | `tests/__init__.py` | Test package marker |
| Create | `tests/conftest.py` | Pytest configuration and fixtures |
| Create | `tests/unit/__init__.py` | Unit test package marker |
| Create | `tests/integration/__init__.py` | Integration test package marker |
| Create | `tests/fixtures/__init__.py` | Test fixtures package marker |

### Quick Wins
1. **Start with pyproject.toml** - This is the foundation everything else depends on
2. **Run `uv sync` immediately after** - Validates the pyproject.toml and creates uv.lock
3. **Create all __init__.py files** - Simple, quick, enables imports
4. **Test import works** - Immediate validation that package structure is correct

---

## Cheat Sheet

### Key Commands

```bash
# Install dependencies and create lockfile
uv sync

# Run Python with project dependencies
uv run python -c "import teams_phone"

# Run linter
uv run ruff check .

# Run linter with auto-fix
uv run ruff check --fix .

# Run formatter
uv run ruff format .

# Run type checker
uv run mypy src/

# Install pre-commit hooks (after creating .pre-commit-config.yaml)
uv run pre-commit install
```

### Key Configuration Sections

**pyproject.toml structure:**
```toml
[project]                    # Project metadata and dependencies
[dependency-groups]          # Dev dependencies (modern uv syntax)
[build-system]               # Build backend configuration
[tool.ruff]                  # Ruff general settings
[tool.ruff.lint]             # Ruff linting rules
[tool.mypy]                  # Mypy type checker settings
```

**Critical pyproject.toml values:**
- `name = "teams-phone-cli"` (PyPI name with dashes)
- `requires-python = ">=3.10"` (minimum Python version)
- `target-version = "py310"` (Ruff setting)
- `strict = true` (mypy setting)

### Common Patterns

**Empty __init__.py file:**
```python
# Empty - makes directory a Python package
```

**Basic conftest.py:**
```python
import pytest

def pytest_configure(config):
    config.addinivalue_line("markers", "unit: Fast unit tests with mocks")
    config.addinivalue_line("markers", "integration: Integration tests with real API")
    config.addinivalue_line("markers", "contract: API contract validation tests")
```

### File Naming Conventions
- Package name (PyPI): `teams-phone-cli` (with dashes)
- Import name: `teams_phone` (with underscores)
- Source directory: `src/teams_phone/` (with underscores)
- Python files: `snake_case.py`
- Classes: `PascalCase`
- Functions/variables: `snake_case`

---

## External Resources Referenced

### Web Search Results
1. [Configuring projects | uv](https://docs.astral.sh/uv/concepts/projects/config/) - uv project configuration guide
2. [Working on projects | uv](https://docs.astral.sh/uv/guides/projects/) - uv project workflow
3. [Managing Python Projects With uv: An All-in-One Solution – Real Python](https://realpython.com/python-uv/) - Comprehensive uv tutorial
4. [Ruff Configuration](https://docs.astral.sh/ruff/configuration) - Default Ruff configuration
5. [Ruff Tutorial](https://docs.astral.sh/ruff/tutorial) - Ruff setup and usage
6. [astral-sh/ruff-pre-commit](https://github.com/astral-sh/ruff-pre-commit) - Ruff pre-commit hook
7. [Running Mypy in Pre-commit | Jared Khan](https://jaredkhan.com/blog/mypy-pre-commit) - Mypy pre-commit setup

### Context7 Documentation Queries
- uv library (/llmstxt/astral_sh_uv_llms_txt): pyproject.toml examples, dependency groups, CLI configuration
- Ruff library (/websites/astral_sh_ruff): Configuration examples, linting rules, formatting options

---

*Generated by task-recon (claude-sonnet-4-20250514) | Ready for implementation*
