diff --git a/.planning/phases/06-consensus-export/06-01-PLAN.md b/.planning/phases/06-consensus-export/06-01-PLAN.md new file mode 100644 index 0000000..e8dea3a --- /dev/null +++ b/.planning/phases/06-consensus-export/06-01-PLAN.md @@ -0,0 +1,129 @@ +--- +phase: 06-consensus-export +plan: 01 +type: execute +--- + + +Implement consensus generation for multi-model discussions. + +Purpose: Enable users to synthesize discussion outcomes into structured agreements/disagreements (M6 milestone). +Output: Working /consensus command that generates and displays AI-summarized consensus. + + + +~/.claude/get-shit-done/workflows/execute-phase.md +~/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md + +# Prior phase context (discussion infrastructure): +@.planning/phases/05-multi-model-discussions/05-03-SUMMARY.md + +# Source files to modify/reference: +@src/moai/core/models.py +@src/moai/core/orchestrator.py +@src/moai/core/services/discussion.py +@src/moai/bot/handlers/discussion.py +@src/moai/bot/handlers/commands.py + +**Tech stack available:** python-telegram-bot, sqlalchemy, openai SDK, asyncio +**Established patterns:** Service layer in core/services/, orchestrator for AI calls, handler delegation to services + +**Constraining decisions:** +- Phase 05-03: build_context() assembles discussion history for AI context +- Phase 05-01: Discussion service with eager loading via selectinload +- Phase 04-01: AI client singleton pattern, MODEL_MAP for short names + +**SPEC.md consensus format:** +- agreements: string[] (bullet points) +- disagreements: [{topic, positions: {model: position}}] +- Consensus model already exists with these fields + + + + + + Task 1: Add consensus generation to orchestrator and service + src/moai/core/orchestrator.py, src/moai/core/services/discussion.py + +1. In orchestrator.py, add CONSENSUS_PROMPT constant with instructions to analyze discussion and return JSON with "agreements" (list of strings) and "disagreements" (list of {topic, positions} objects). + +2. Add `generate_consensus(discussion: Discussion, model: str = "claude") -> dict` function: + - Build context from discussion using existing build_context() + - Append CONSENSUS_PROMPT as final user message + - Call AI client with system prompt explaining the task + - Parse JSON response (handle parsing errors gracefully) + - Return dict with "agreements" and "disagreements" keys + +3. In discussion.py service, add: + - `save_consensus(discussion_id: str, agreements: list, disagreements: list, generated_by: str) -> Consensus` + - `get_consensus(discussion_id: str) -> Consensus | None` + +Use existing session patterns (async with get_session()). Import Consensus model. + + Python imports succeed: `python -c "from moai.core.orchestrator import generate_consensus; from moai.core.services.discussion import save_consensus, get_consensus"` + generate_consensus() returns dict with agreements/disagreements, save_consensus() persists to DB, get_consensus() retrieves + + + + Task 2: Create /consensus command handler + src/moai/bot/handlers/discussion.py, src/moai/bot/handlers/commands.py, src/moai/bot/handlers/__init__.py + +1. In discussion.py handlers, add `consensus_command(update, context)`: + - Get selected project (error if none) + - Get active discussion for project (error if none, suggest /open or /discuss first) + - Check if consensus already exists (get_consensus) - if so, display existing + - Otherwise call generate_consensus() with discussion + - Save consensus via save_consensus() + - Format and display: + ``` + **Consensus Summary** + + **Agreements:** + - point 1 + - point 2 + + **Disagreements:** + - **Topic:** {topic} + - Claude: {position} + - GPT: {position} + + _Generated by {model}_ + ``` + - Show typing indicator while generating + +2. Register handler in __init__.py: `CommandHandler("consensus", consensus_command)` + +3. Update HELP_TEXT in commands.py to add consensus under Output section: + `/consensus` - Generate consensus summary + + Bot responds to /consensus with either consensus output or appropriate error message + /consensus generates and displays consensus for active discussion, or shows existing if already generated + + + + + +Before declaring plan complete: +- [ ] `ruff check src/moai/core/orchestrator.py src/moai/core/services/discussion.py src/moai/bot/handlers/` +- [ ] `python -c "from moai.core.orchestrator import generate_consensus"` succeeds +- [ ] `python -c "from moai.core.services.discussion import save_consensus, get_consensus"` succeeds + + + + +- generate_consensus() calls AI and returns structured dict +- Consensus persisted to database via save_consensus() +- /consensus command displays formatted consensus +- Help text updated +- No ruff errors + + + +After completion, create `.planning/phases/06-consensus-export/06-01-SUMMARY.md` + diff --git a/.planning/phases/06-consensus-export/06-02-PLAN.md b/.planning/phases/06-consensus-export/06-02-PLAN.md new file mode 100644 index 0000000..bdeccee --- /dev/null +++ b/.planning/phases/06-consensus-export/06-02-PLAN.md @@ -0,0 +1,157 @@ +--- +phase: 06-consensus-export +plan: 02 +type: execute +--- + + +Implement markdown export for discussions and projects. + +Purpose: Enable users to export discussion history and consensus to shareable markdown documents (M7 milestone). +Output: Working /export command that generates and sends markdown files via Telegram. + + + +~/.claude/get-shit-done/workflows/execute-phase.md +~/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md + +# Prior plan context: +@.planning/phases/06-consensus-export/06-01-SUMMARY.md + +# Source files to reference: +@src/moai/core/models.py +@src/moai/core/services/discussion.py +@src/moai/core/services/project.py +@src/moai/bot/handlers/__init__.py +@src/moai/bot/handlers/commands.py + +**Tech stack available:** python-telegram-bot, sqlalchemy +**Established patterns:** Service layer, handler registration, get_selected_project helper + +**SPEC.md export format:** +```markdown +# {Project Name} + +**Date:** {date} +**Models:** Claude, GPT, Gemini +**Discussions:** {count} + +--- + +## Discussion 1: {Question} + +### Initial Responses (Open) +**Claude:** +> {response} + +### Discussion (N rounds) +**Round 1:** +**Claude:** {response} +**GPT:** {response} + +### Consensus +**Agreements:** +- point 1 + +**Disagreements:** +- **Topic:** {topic} + - Claude: {position} +``` + + + + + + Task 1: Create exporter module + src/moai/core/exporter.py + +Create new file src/moai/core/exporter.py with: + +1. Module docstring explaining markdown export functionality. + +2. `export_discussion(discussion: Discussion) -> str` function: + - Format discussion as markdown following SPEC format + - Include question as heading + - Group messages by round, label round type (parallel = "Initial Responses", sequential = "Round N") + - Format each message as `**Model:** response` + - Include consensus section if consensus exists (agreements as bullets, disagreements with positions) + - Return markdown string + +3. `export_project(project: Project, discussions: list[Discussion]) -> str` function: + - Header with project name, date, models list, discussion count + - Separator (---) + - Each discussion formatted via export_discussion() + - Separators between discussions + - Return full markdown string + +4. Helper `_format_consensus(consensus: Consensus) -> str`: + - Format agreements as bullet list + - Format disagreements with topic and model positions + - Return formatted string or empty if no consensus + +Use datetime.now().strftime("%Y-%m-%d") for date formatting. + + `python -c "from moai.core.exporter import export_discussion, export_project"` succeeds + Exporter module creates properly formatted markdown matching SPEC format + + + + Task 2: Create /export command handler + src/moai/bot/handlers/export.py, src/moai/bot/handlers/__init__.py, src/moai/bot/handlers/commands.py + +1. Create new file src/moai/bot/handlers/export.py with: + - Import exporter functions, services, telegram types + - `export_command(update, context)` handler: + - Get selected project (error if none) + - Parse args: no args = export active discussion, "project" = export full project + - For discussion export: + - Get active discussion (error if none) + - Call export_discussion() + - Send as document: `update.message.reply_document(io.BytesIO(md.encode()), filename=f"{project.name}-discussion.md")` + - For project export: + - Get all discussions for project via list_discussions() + - Fetch each with full eager loading via get_discussion() + - Call export_project() + - Send as document with filename `{project.name}-export.md` + - Use io.BytesIO for in-memory file, import io module + +2. Update handlers/__init__.py: + - Import export_command from export module + - Register `CommandHandler("export", export_command)` + +3. Update HELP_TEXT in commands.py, Output section: + `/export` - Export current discussion as markdown + `/export project` - Export entire project as markdown + + Bot responds to /export with a markdown document attachment + /export sends discussion markdown, /export project sends full project markdown as Telegram documents + + + + + +Before declaring plan complete: +- [ ] `ruff check src/moai/core/exporter.py src/moai/bot/handlers/export.py` +- [ ] `python -c "from moai.core.exporter import export_discussion, export_project"` succeeds +- [ ] `python -c "from moai.bot.handlers.export import export_command"` succeeds + + + + +- Exporter module generates SPEC-compliant markdown +- /export sends discussion as .md document +- /export project sends full project as .md document +- Help text updated +- No ruff errors +- Phase 6 complete (M6 + M7 milestones) + + + +After completion, create `.planning/phases/06-consensus-export/06-02-SUMMARY.md` +