Initial project structure

Scaffold all modules, route stubs, data models, and config.
No logic implemented yet — all core methods raise NotImplementedError.
Establishes the full directory layout matching the architecture in CLAUDE.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Jaroslav Benes
2026-04-08 14:48:48 +02:00
commit 083cbb1fa7
32 changed files with 1507 additions and 0 deletions

43
fellowship/core/queue.py Normal file
View File

@@ -0,0 +1,43 @@
"""
Talker message queue — holds incoming talker messages in arrival order.
The session loop drains this queue one message at a time.
"""
import asyncio
import logging
from dataclasses import dataclass
logger = logging.getLogger(__name__)
@dataclass
class QueuedMessage:
talker_id: str
talker_name: str
content: str
class MessageQueue:
def __init__(self) -> None:
self._queue: asyncio.Queue[QueuedMessage] = asyncio.Queue()
def enqueue(self, message: QueuedMessage) -> None:
"""Add a talker message to the queue. Non-blocking."""
self._queue.put_nowait(message)
async def dequeue(self) -> QueuedMessage:
"""Wait for and return the next message. Blocks until one is available."""
return await self._queue.get()
def dequeue_nowait(self) -> QueuedMessage | None:
"""Return the next message without waiting, or None if the queue is empty."""
try:
return self._queue.get_nowait()
except asyncio.QueueEmpty:
return None
def is_empty(self) -> bool:
return self._queue.empty()
def size(self) -> int:
return self._queue.qsize()