# Task Recon: Set up __main__.py entry point and command group registration

**Task ID:** 11.2
**Status:** pending
**Generated:** 2026-01-28T12:00:00Z
**Agent:** claude-opus-4-5-20251101

---

## Task Summary

Create the `src/teams_phone/__main__.py` entry point that imports and runs the CLI app, and register all command group sub-applications (users, numbers, policies, locations, tenants, auth) to the main app.

### Parent Task Context

**Parent Task:** Implement Root CLI App with Global Options (ID: 11)
**Parent Goal:** Create the main Typer CLI application with global options (--json, --verbose, --tenant, --no-color) and command group registration.
**This Subtask's Role:** After subtask 11.1 created the main Typer app with the callback for global options, this subtask completes the CLI setup by: (1) creating the `__main__.py` entry point to enable `python -m teams_phone` invocation, and (2) registering all six command group sub-applications (users, numbers, policies, locations, tenants, auth) to provide the hierarchical command structure.

### Dependencies
- Depends on: 11.1 (Create main Typer app with global options callback) - **DONE**

### Acceptance Criteria
- `__main__.py` imports app from `teams_phone.cli.main` and calls `app()` when run as module
- All six command groups (users, numbers, policies, locations, tenants, auth) are registered via `app.add_typer()`
- `python -m teams_phone --help` shows all command groups
- `python -m teams_phone <group> --help` shows subcommand help for each group
- Unit tests verify command group registration using CliRunner

---

## Insights from Previous Tasks

### Dependency Task Notes
| Task ID | Title | Key Insight |
|---------|-------|-------------|
| 11.1 | Create main Typer app with global options callback | Context uses `ctx.obj["json"]` key naming (concise), exit code 2 for no_args_is_help is expected Click behavior |

### Reusable Patterns from Dependencies
- **Context key naming**: Use concise keys like `ctx.obj["json"]` not `ctx.obj["json_output"]` - established in `src/teams_phone/cli/main.py:52-56`
- **Test fixture for context**: Test fixture creates a copy of the app with test command to capture context values - see `tests/unit/test_cli_main.py:77-100`
- **CliRunner usage**: Use `from typer.testing import CliRunner` and `runner = CliRunner()` - see `tests/unit/test_cli_main.py:7-12`

### Warnings and Gotchas
- **Exit code 2 for no_args_is_help**: When testing with no arguments or just options (no subcommand), Typer returns exit code 2 not 0 - this is expected behavior from Click
- **Short option -j for --json**: Added `-j` short form which wasn't in original task spec but matches `cli-specification/global-options.md`

### Open Items Inherited
- [ ] Command group registration (users, numbers, policies, locations, tenants, auth) - **This is what we're implementing now**

---

## Architecture Context

### Relevant Design Decisions
- **Layered Monolith Architecture**: CLI layer (`src/teams_phone/cli/`) contains Typer commands that invoke services
- **Command structure**: Uses `<noun> <verb> [args] [--flags]` pattern per CLI specification
- **Six command groups**: users, numbers, policies, locations, tenants, auth

### Module Structure
```
src/teams_phone/
├── __main__.py          # Entry point (to be completed)
├── __init__.py          # Package init with __version__
└── cli/
    ├── __init__.py      # Exports app
    ├── main.py          # Main Typer app with callback (exists)
    ├── users.py         # Will be created later (placeholder for now)
    ├── numbers.py       # Will be created later (placeholder for now)
    ├── policies.py      # Will be created later (placeholder for now)
    ├── locations.py     # Will be created later (placeholder for now)
    ├── tenants.py       # Will be created later (placeholder for now)
    └── auth.py          # Will be created later (placeholder for now)
```

### Conventions to Follow
- **Module docstrings**: Start with triple-quoted docstring explaining module purpose
- **Future annotations**: Use `from __future__ import annotations` at top
- **Type hints**: All functions must have type hints (strict mypy mode)
- **Import style**: Use absolute imports from `teams_phone.*`

---

## Related Code References

### Primary References (Must Read)
| File | Lines | Purpose |
|------|-------|---------|
| `src/teams_phone/cli/main.py` | 1-57 | Existing main app with callback - add sub-apps here |
| `src/teams_phone/__main__.py` | 1-2 | Existing incomplete entry point - needs app import/call |
| `src/teams_phone/cli/__init__.py` | 1-5 | CLI package exports - may need to update |
| `tests/unit/test_cli_main.py` | 1-193 | Test patterns for CLI testing with CliRunner |

### Secondary References (Helpful Context)
| File | Lines | Purpose |
|------|-------|---------|
| `.taskmaster/docs/cli-specification/command-summary.md` | 1-40 | Complete list of commands per group |
| `.taskmaster/docs/architecture/5-components.md` | 3-20 | CLI layer architecture |
| `src/teams_phone/infrastructure/output_formatter.py` | 1-60 | Help text style (imperative sentences ending with period) |

### Code Patterns to Follow

```python
# From Context7 Typer documentation - registering sub-apps
import typer

# Create sub-apps (placeholder apps for now)
users_app = typer.Typer()
numbers_app = typer.Typer()

# Main app already exists
app = typer.Typer(...)

# Register sub-apps with name and help text
app.add_typer(users_app, name="users", help="Manage Teams users.")
app.add_typer(numbers_app, name="numbers", help="Manage phone numbers.")
```

```python
# Entry point pattern from task spec (__main__.py)
from teams_phone.cli.main import app

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

---

## Dependencies

### Internal Modules
- `teams_phone.cli.main` - provides the `app` Typer instance
- `teams_phone.cli` - package that exports `app`

### External Packages
- `typer>=0.9.0` - CLI framework (already in pyproject.toml)

### New Dependencies Needed
- None required

---

## Testing Guidance

### Test File Location
`tests/unit/test_cli_main.py` - extend existing file with command group tests

### Test Patterns in Use
```python
# Example test structure (tests/unit/test_cli_main.py:25-29)
class TestAppNoArgsShowsHelp:
    @pytest.mark.unit
    def test_app_no_args_shows_help(self) -> None:
        """App shows help when no arguments provided."""
        result = runner.invoke(app, [])
        # Typer returns exit code 2 for no_args_is_help
        assert result.exit_code == 2
        assert "Usage:" in result.stdout
```

```python
# Pattern for testing command groups exist in help
@pytest.mark.unit
def test_command_groups_in_help(self) -> None:
    """All command groups appear in help output."""
    result = runner.invoke(app, ["--help"])
    assert result.exit_code == 0
    assert "users" in result.stdout
    assert "numbers" in result.stdout
    assert "policies" in result.stdout
    assert "locations" in result.stdout
    assert "tenants" in result.stdout
    assert "auth" in result.stdout
```

```python
# Pattern for testing subcommand help (per task test strategy)
@pytest.mark.unit
def test_users_subcommand_help(self) -> None:
    """users --help shows users subcommand help."""
    result = runner.invoke(app, ["users", "--help"])
    assert result.exit_code == 0
    assert "Manage Teams users" in result.stdout
```

### Fixtures Available
- No specific fixtures needed - use `runner = CliRunner()` directly

### Test Utilities
- `typer.testing.CliRunner` - standard Typer test runner
- `pytest.mark.unit` - marker for unit tests

---

## Risks and Blockers

### Technical Risks
- [ ] **Placeholder sub-apps behavior**: Since actual command implementations don't exist yet, sub-apps will be empty Typer() instances. This is expected - they'll show `no_args_is_help` behavior until commands are added.

### Dependency Risks
- [ ] None - task 11.1 is complete and provides the foundation

### Open Questions
- None identified - task details are clear

---

## Implementation Recommendations

### Suggested Approach
1. Complete `src/teams_phone/__main__.py` with proper entry point
2. Create placeholder sub-apps in `src/teams_phone/cli/main.py` and register them with `app.add_typer()`
3. Add tests for command group registration to `tests/unit/test_cli_main.py`
4. Verify `python -m teams_phone --help` shows all groups
5. Run `ruff check` and `mypy` to ensure code quality

### Files to Create/Modify
| Action | File | Reason |
|--------|------|--------|
| Modify | `src/teams_phone/__main__.py` | Add app import and call |
| Modify | `src/teams_phone/cli/main.py` | Add sub-app registration |
| Modify | `tests/unit/test_cli_main.py` | Add command group tests |

### Quick Wins
- Start with `__main__.py` - just 3-4 lines of code
- Then add the 6 placeholder sub-apps with `add_typer()` calls

---

## Cheat Sheet

### Key Imports
```python
# In main.py - no new imports needed, typer already imported
import typer

# In __main__.py
from teams_phone.cli.main import app
```

### Key Functions to Use
- `typer.Typer()` - Create a new Typer sub-application
- `app.add_typer(sub_app, name="...", help="...")` - Register sub-app with main app

### Command Group Help Text (from CLI specs)
| Group | Name | Help Text |
|-------|------|-----------|
| users | `users` | `Manage Teams users.` |
| numbers | `numbers` | `Manage phone numbers.` |
| policies | `policies` | `Manage voice policies.` |
| locations | `locations` | `Manage emergency locations.` |
| tenants | `tenants` | `Manage tenant profiles.` |
| auth | `auth` | `Authentication commands.` |

### Common Patterns
- **Sub-app registration**: See Context7 docs above - `app.add_typer(sub_app, name="...", help="...")`
- **Test with CliRunner**: `result = runner.invoke(app, ["--help"])`
- **Check exit code**: Exit 0 for --help, exit 2 for no_args_is_help

---

*Generated by task-recon (claude-opus-4-5-20251101) | Ready for implementation*
