diff --git a/.planning/phases/01-foundation/01-01-PLAN.md b/.planning/phases/01-foundation/01-01-PLAN.md
new file mode 100644
index 0000000..87ae3d1
--- /dev/null
+++ b/.planning/phases/01-foundation/01-01-PLAN.md
@@ -0,0 +1,132 @@
+---
+phase: 01-foundation
+plan: 01
+type: execute
+---
+
+
+Set up project scaffolding with pyproject.toml, ruff, pre-commit, and src layout.
+
+Purpose: Establish consistent tooling from day one—linting, formatting, testing infrastructure.
+Output: Working Python project structure with `uv sync` installing all deps, ruff/pre-commit configured.
+
+
+
+~/.claude/get-shit-done/workflows/execute-phase.md
+~/.claude/get-shit-done/templates/summary.md
+
+
+
+@.planning/PROJECT.md
+@.planning/ROADMAP.md
+@SPEC.md
+@CLAUDE.md
+
+**Constraints from PROJECT.md:**
+- Python 3.11+
+- ruff (line length 100)
+- pytest, 80%+ coverage on core logic
+- Type hints required on public functions
+- Docstrings required on modules and classes
+- Dependencies unpinned unless security required
+
+
+
+
+
+ Task 1: Create pyproject.toml with dependencies and tool config
+ pyproject.toml
+
+Create pyproject.toml with:
+
+**[project] section:**
+- name = "moai"
+- version = "0.1.0"
+- description = "Multi-AI collaborative brainstorming platform"
+- requires-python = ">=3.11"
+- dependencies: python-telegram-bot, sqlalchemy, httpx, aiosqlite (for async SQLite)
+
+**[project.optional-dependencies]:**
+- dev: pytest, pytest-cov, pytest-asyncio, ruff, pre-commit
+
+**[tool.ruff] section:**
+- line-length = 100
+- target-version = "py311"
+
+**[tool.ruff.lint]:**
+- select = ["E", "F", "I", "N", "W", "UP"]
+
+**[tool.pytest.ini_options]:**
+- testpaths = ["tests"]
+- asyncio_mode = "auto"
+
+**[build-system]:**
+- requires = ["hatchling"]
+- build-backend = "hatchling.build"
+
+Use hatchling as build backend (modern, works well with uv).
+Do NOT pin dependency versions.
+
+ uv sync completes without errors
+ pyproject.toml valid, all dependencies installable
+
+
+
+ Task 2: Create pre-commit configuration
+ .pre-commit-config.yaml
+
+Create .pre-commit-config.yaml with:
+
+**Hooks:**
+1. ruff (linting): repo = https://github.com/astral-sh/ruff-pre-commit, hooks = [ruff, ruff-format]
+2. Standard pre-commit hooks: trailing-whitespace, end-of-file-fixer, check-yaml
+
+Use latest rev for ruff-pre-commit (check GitHub for current version, approximately v0.11.x).
+
+Do NOT add pytest hook—running tests on every commit is too slow. Tests run manually or in CI.
+
+ pre-commit install && pre-commit run --all-files passes
+ Pre-commit hooks installed and passing
+
+
+
+ Task 3: Create src layout and package structure
+ src/moai/__init__.py, src/moai/bot/__init__.py, src/moai/bot/handlers/__init__.py, src/moai/core/__init__.py, tests/__init__.py
+
+Create directory structure per SPEC.md:
+
+src/moai/__init__.py - Package marker with __version__ = "0.1.0"
+src/moai/bot/__init__.py - Bot subpackage marker (docstring: "Telegram bot handlers and entry point")
+src/moai/bot/handlers/__init__.py - Handlers subpackage marker
+src/moai/core/__init__.py - Core subpackage marker (docstring: "Core business logic, models, and services")
+tests/__init__.py - Test package marker
+
+Each __init__.py should have a module docstring describing its purpose.
+Use triple-quoted docstrings at the top of each file.
+
+ python -c "import moai; print(moai.__version__)" prints "0.1.0"
+ Package importable, structure matches SPEC.md
+
+
+
+
+
+Before declaring plan complete:
+- [ ] `uv sync` succeeds without errors
+- [ ] `pre-commit run --all-files` passes
+- [ ] `python -c "import moai"` succeeds
+- [ ] `ruff check src tests` passes
+- [ ] Directory structure matches SPEC.md file structure
+
+
+
+
+- All tasks completed
+- All verification checks pass
+- No linting errors
+- Package installable and importable
+
+
+
diff --git a/.planning/phases/01-foundation/01-02-PLAN.md b/.planning/phases/01-foundation/01-02-PLAN.md
new file mode 100644
index 0000000..b28852d
--- /dev/null
+++ b/.planning/phases/01-foundation/01-02-PLAN.md
@@ -0,0 +1,163 @@
+---
+phase: 01-foundation
+plan: 02
+type: execute
+---
+
+
+Create SQLAlchemy models for Project, Discussion, Round, Message, and Consensus.
+
+Purpose: Define the data model that powers all discussion features.
+Output: Complete models.py with all relationships, ready for database creation.
+
+
+
+~/.claude/get-shit-done/workflows/execute-phase.md
+~/.claude/get-shit-done/templates/summary.md
+
+
+
+@.planning/PROJECT.md
+@.planning/ROADMAP.md
+@SPEC.md
+@CLAUDE.md
+
+**Data model from SPEC.md:**
+```
+Project (has many) -> Discussion (has many) -> Round (has many) -> Message
+ \-> Discussion (has one) -> Consensus
+```
+
+**Field specifications:**
+- Project: id (uuid), name, created_at, updated_at, models (JSON array), settings (JSON)
+- Discussion: id, project_id (FK), question, type (open|discuss), status (active|completed), created_at
+- Round: id, discussion_id (FK), round_number, type (parallel|sequential)
+- Message: id, round_id (FK), model, content, timestamp, is_direct
+- Consensus: id, discussion_id (FK), agreements (JSON array), disagreements (JSON array), generated_at, generated_by
+
+**Constraints:**
+- Use SQLAlchemy 2.0 style (mapped_column, DeclarativeBase)
+- Type hints required
+- SQLite compatible (use JSON type, not ARRAY)
+
+
+
+
+
+ Task 1: Create base model and enums
+ src/moai/core/models.py
+
+Create src/moai/core/models.py with:
+
+**Imports:** SQLAlchemy 2.0 style (DeclarativeBase, Mapped, mapped_column, relationship), uuid, datetime, enum
+
+**Base class:**
+- class Base(DeclarativeBase): pass
+
+**Enums (use Python Enum, store as string):**
+- DiscussionType: OPEN = "open", DISCUSS = "discuss"
+- DiscussionStatus: ACTIVE = "active", COMPLETED = "completed"
+- RoundType: PARALLEL = "parallel", SEQUENTIAL = "sequential"
+
+**UUID helper:**
+- Use uuid4() for default IDs
+- Store as String(36) for SQLite compatibility (NOT native UUID type)
+
+Add module docstring explaining the data model.
+
+ python -c "from moai.core.models import Base, DiscussionType, DiscussionStatus, RoundType"
+ Base class and enums importable
+
+
+
+ Task 2: Create Project and Discussion models
+ src/moai/core/models.py
+
+Add to models.py:
+
+**Project model:**
+- id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4()))
+- name: Mapped[str] = mapped_column(String(255))
+- created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
+- updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
+- models: Mapped[list] = mapped_column(JSON, default=list) - stores ["claude", "gpt", "gemini"]
+- settings: Mapped[dict] = mapped_column(JSON, default=dict) - stores {default_rounds, consensus_threshold, system_prompt_override}
+- discussions: Mapped[list["Discussion"]] = relationship(back_populates="project", cascade="all, delete-orphan")
+
+**Discussion model:**
+- id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4()))
+- project_id: Mapped[str] = mapped_column(ForeignKey("project.id"))
+- question: Mapped[str] = mapped_column(Text)
+- type: Mapped[DiscussionType] = mapped_column(Enum(DiscussionType))
+- status: Mapped[DiscussionStatus] = mapped_column(Enum(DiscussionStatus), default=DiscussionStatus.ACTIVE)
+- created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
+- project: Mapped["Project"] = relationship(back_populates="discussions")
+- rounds: Mapped[list["Round"]] = relationship(back_populates="discussion", cascade="all, delete-orphan")
+- consensus: Mapped["Consensus"] = relationship(back_populates="discussion", uselist=False, cascade="all, delete-orphan")
+
+Use __tablename__ = "project" and "discussion" (singular, lowercase).
+
+ python -c "from moai.core.models import Project, Discussion; print(Project.__tablename__, Discussion.__tablename__)"
+ Project and Discussion models defined with bidirectional relationships
+
+
+
+ Task 3: Create Round, Message, and Consensus models
+ src/moai/core/models.py
+
+Add to models.py:
+
+**Round model:**
+- id: Mapped[str] (uuid, primary key)
+- discussion_id: Mapped[str] = mapped_column(ForeignKey("discussion.id"))
+- round_number: Mapped[int]
+- type: Mapped[RoundType] = mapped_column(Enum(RoundType))
+- discussion: Mapped["Discussion"] = relationship(back_populates="rounds")
+- messages: Mapped[list["Message"]] = relationship(back_populates="round", cascade="all, delete-orphan")
+
+**Message model:**
+- id: Mapped[str] (uuid, primary key)
+- round_id: Mapped[str] = mapped_column(ForeignKey("round.id"))
+- model: Mapped[str] = mapped_column(String(50)) - e.g., "claude", "gpt", "gemini"
+- content: Mapped[str] = mapped_column(Text)
+- timestamp: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
+- is_direct: Mapped[bool] = mapped_column(Boolean, default=False) - true if @mentioned
+- round: Mapped["Round"] = relationship(back_populates="messages")
+
+**Consensus model:**
+- id: Mapped[str] (uuid, primary key)
+- discussion_id: Mapped[str] = mapped_column(ForeignKey("discussion.id"), unique=True)
+- agreements: Mapped[list] = mapped_column(JSON, default=list) - bullet point strings
+- disagreements: Mapped[list] = mapped_column(JSON, default=list) - [{topic, positions: {model: position}}]
+- generated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
+- generated_by: Mapped[str] = mapped_column(String(50)) - which model summarized
+- discussion: Mapped["Discussion"] = relationship(back_populates="consensus")
+
+Use __tablename__ = "round", "message", "consensus" (singular, lowercase).
+
+ python -c "from moai.core.models import Round, Message, Consensus; print('All models imported')"
+ All 5 models defined with complete relationships
+
+
+
+
+
+Before declaring plan complete:
+- [ ] `python -c "from moai.core.models import Base, Project, Discussion, Round, Message, Consensus"` succeeds
+- [ ] `ruff check src/moai/core/models.py` passes
+- [ ] All foreign keys reference correct tables
+- [ ] All relationships are bidirectional
+- [ ] All fields have type hints
+
+
+
+
+- All tasks completed
+- All 5 models importable
+- No linting errors
+- Relationships match SPEC.md data model diagram
+
+
+
diff --git a/.planning/phases/01-foundation/01-03-PLAN.md b/.planning/phases/01-foundation/01-03-PLAN.md
new file mode 100644
index 0000000..341017d
--- /dev/null
+++ b/.planning/phases/01-foundation/01-03-PLAN.md
@@ -0,0 +1,184 @@
+---
+phase: 01-foundation
+plan: 03
+type: execute
+---
+
+
+Create database module with async session management and write model tests.
+
+Purpose: Enable database operations and validate models work correctly.
+Output: Working database.py with async session factory, passing model tests.
+
+
+
+~/.claude/get-shit-done/workflows/execute-phase.md
+~/.claude/get-shit-done/templates/summary.md
+
+
+
+@.planning/PROJECT.md
+@.planning/ROADMAP.md
+@SPEC.md
+@CLAUDE.md
+@src/moai/core/models.py
+
+**Tech choices:**
+- SQLAlchemy 2.0 async (create_async_engine, AsyncSession)
+- aiosqlite for async SQLite
+- pytest-asyncio for async tests
+
+**From CLAUDE.md:**
+- Testing: pytest, target 80%+ coverage on core logic
+- Database: SQLAlchemy + SQLite, upgrades to PostgreSQL in Phase 2
+
+
+
+
+
+ Task 1: Create database module with async session management
+ src/moai/core/database.py
+
+Create src/moai/core/database.py with:
+
+**Imports:** sqlalchemy.ext.asyncio (create_async_engine, AsyncSession, async_sessionmaker), contextlib
+
+**Module-level:**
+- DATABASE_URL: str = "sqlite+aiosqlite:///./moai.db" (default, can be overridden)
+- engine: AsyncEngine = None (initialized lazily)
+- async_session_factory: async_sessionmaker = None
+
+**Functions:**
+1. init_db(url: str | None = None) -> None:
+ - Creates engine with echo=False
+ - Creates async_session_factory
+ - Stores in module globals
+ - Use: `create_async_engine(url, echo=False)`
+
+2. async create_tables() -> None:
+ - Imports Base from models
+ - Runs `async with engine.begin() as conn: await conn.run_sync(Base.metadata.create_all)`
+
+3. @contextlib.asynccontextmanager
+ async def get_session() -> AsyncGenerator[AsyncSession, None]:
+ - Yields session from factory
+ - Handles commit on success, rollback on exception
+ - Pattern: `async with async_session_factory() as session: yield session; await session.commit()`
+
+4. async def close_db() -> None:
+ - Disposes engine: `await engine.dispose()`
+
+Add module docstring explaining session management pattern.
+
+ python -c "from moai.core.database import init_db, create_tables, get_session, close_db"
+ Database module importable with all functions
+
+
+
+ Task 2: Create model tests with in-memory database
+ tests/test_models.py
+
+Create tests/test_models.py with:
+
+**Fixtures:**
+- @pytest.fixture
+ async def db_session():
+ - init_db("sqlite+aiosqlite:///:memory:")
+ - await create_tables()
+ - async with get_session() as session: yield session
+ - await close_db()
+
+**Test cases:**
+
+1. test_create_project:
+ - Create Project(name="Test Project", models=["claude", "gpt"])
+ - Add to session, commit
+ - Assert id is set (UUID string), name correct, models correct
+
+2. test_create_discussion_with_project:
+ - Create Project, add Discussion linked to it
+ - Assert discussion.project_id matches project.id
+ - Assert project.discussions contains the discussion
+
+3. test_create_full_discussion_chain:
+ - Create Project -> Discussion -> Round -> Message
+ - Verify all relationships work
+ - Verify cascade (all linked when navigating relationships)
+
+4. test_create_consensus:
+ - Create Discussion with Consensus
+ - Assert discussion.consensus is set
+ - Assert consensus.discussion links back
+
+5. test_project_cascade_delete:
+ - Create Project with Discussion with Round with Message
+ - Delete Project
+ - Assert all children deleted (cascade)
+
+Use pytest.mark.asyncio on all async tests.
+Import all models and database functions.
+
+ pytest tests/test_models.py -v passes all tests
+ 5 model tests passing, cascade behavior verified
+
+
+
+ Task 3: Add .gitignore entries and verify full test suite
+ .gitignore
+
+Update .gitignore to add:
+
+```
+# Database
+*.db
+*.sqlite
+*.sqlite3
+
+# Python
+__pycache__/
+*.pyc
+.pytest_cache/
+.coverage
+htmlcov/
+
+# Virtual environments
+.venv/
+venv/
+
+# IDE
+.idea/
+.vscode/
+*.swp
+```
+
+Then run full test suite with coverage to verify everything works together.
+
+ pytest --cov=moai --cov-report=term-missing shows coverage, all tests pass
+ .gitignore updated, tests pass with coverage report
+
+
+
+
+
+Before declaring plan complete:
+- [ ] `pytest tests/test_models.py -v` passes all 5 tests
+- [ ] `pytest --cov=moai --cov-report=term-missing` runs successfully
+- [ ] `ruff check src tests` passes
+- [ ] Database file (moai.db) is gitignored
+- [ ] Phase 1 complete: scaffolding, models, database all working
+
+
+
+
+- All tasks completed
+- All tests pass
+- No linting errors
+- Phase 1: Foundation complete
+
+
+