# Codebase Structure **Analysis Date:** 2026-04-01 ## Directory Layout ``` surfaces-bot/ ├── adapter/ │ ├── __init__.py │ └── matrix/ # matrix-nio adapter (merged to main) │ ├── __init__.py │ ├── bot.py # Entry point, MatrixBot class, send_outgoing() │ ├── converter.py # nio Event → IncomingEvent │ ├── reactions.py # Emoji constants, skills text builder │ ├── room_router.py # room_id → chat_id resolution │ ├── store.py # Matrix-specific StateStore helpers (room meta, user meta) │ └── handlers/ │ ├── __init__.py # register_matrix_handlers() │ ├── auth.py # handle_invite (invite member event) │ ├── chat.py # Chat creation (creates real Matrix rooms) │ ├── confirm.py # Confirmation flow callbacks │ └── settings.py # Settings sub-commands and toggle_skill ├── core/ │ ├── auth.py # AuthManager: start_flow, confirm, is_authenticated │ ├── chat.py # ChatManager: get_or_create, list_active, rename, archive │ ├── handler.py # EventDispatcher: register, dispatch, _routing_key │ ├── protocol.py # All shared dataclasses and type aliases │ ├── settings.py # SettingsManager: get (cached), apply (invalidates cache) │ ├── store.py # StateStore Protocol, InMemoryStore, SQLiteStore │ └── handlers/ │ ├── __init__.py # register_all() — binds all core handlers to dispatcher │ ├── callback.py # handle_confirm, handle_cancel, handle_toggle_skill │ ├── chat.py # handle_new_chat, handle_rename, handle_archive, handle_list_chats │ ├── message.py # handle_message — auth guard + platform.send_message │ ├── settings.py # handle_settings — displays settings menu │ └── start.py # handle_start — get_or_create_user + welcome message ├── sdk/ │ ├── __init__.py │ ├── interface.py # PlatformClient Protocol, WebhookReceiver Protocol, Pydantic models │ └── mock.py # MockPlatformClient — full in-memory implementation ├── tests/ │ ├── __init__.py │ ├── conftest.py # (root conftest — sys.path fix for local sdk/ shadowing stdlib) │ ├── adapter/ │ │ ├── __init__.py │ │ ├── matrix/ │ │ │ ├── __init__.py │ │ │ ├── test_converter.py │ │ │ ├── test_dispatcher.py │ │ │ ├── test_reactions.py │ │ │ └── test_store.py │ │ └── test_forum_db.py # untracked — forum DB exploration │ ├── core/ │ │ ├── test_auth.py │ │ ├── test_chat.py │ │ ├── test_dispatcher.py │ │ ├── test_integration.py │ │ ├── test_protocol.py │ │ ├── test_settings.py │ │ ├── test_store.py │ │ └── test_voice_slot.py │ └── platform/ │ └── test_mock.py ├── docs/ # All human documentation ├── .planning/ # GSD planning artefacts │ └── codebase/ # Codebase map documents (this directory) ├── .claude/ │ └── agents/ # Agent configuration files ├── .worktrees/ │ └── telegram/ # Telegram adapter on feat/telegram-adapter branch │ └── ... # Mirrors main layout; merged separately ├── conftest.py # Root pytest conftest: sys.path hack for local sdk/ ├── pyproject.toml # Project metadata, dependencies, ruff + pytest config ├── uv.lock # Lockfile (uv) ├── lambda_matrix.db # SQLite DB written by Matrix bot (gitignored) └── .env.example # Environment variable template ``` ## Directory Purposes **`core/`:** - Purpose: Platform-neutral business logic. Never imports from `adapter/`. - Key files: `protocol.py` (all shared types), `handler.py` (dispatcher), `store.py` (persistence interface) - Add new domain logic here; keep it free of aiogram/matrix-nio imports **`core/handlers/`:** - Purpose: One async function per command/callback/message type. Each returns `list[OutgoingEvent]`. - Registration: `register_all()` in `core/handlers/__init__.py` binds them to the dispatcher - Adapters can override any key by calling `dispatcher.register(event_type, key, fn)` after `register_all()` **`sdk/`:** - Purpose: Contract (`interface.py`) and mock (`mock.py`) for the Lambda AI platform SDK - Note: The directory is named `sdk/` in actual code (not `platform/` as CLAUDE.md describes); `handler.py` imports from `sdk.interface` - When real SDK arrives: replace `sdk/mock.py` only; `sdk/interface.py` must not change unless the contract changes **`adapter/matrix/`:** - Purpose: Everything matrix-nio-specific. Translates between nio and core protocol. - `bot.py` owns `MatrixBot`, `build_runtime()`, `send_outgoing()`, and `main()` - `store.py` provides key-namespaced helpers on top of `StateStore` (not a separate store implementation) - `room_router.py` maintains the `room_id → chat_id` mapping persisted in `StateStore` **`adapter/telegram/`:** - Purpose: aiogram 3.x adapter. Lives in `.worktrees/telegram/` on `feat/telegram-adapter` branch. - Uses aiogram FSM states (`states.py`) and inline keyboards (`keyboards/`) - Not yet merged to `main` **`tests/`:** - Purpose: pytest test suite mirroring the source tree - `tests/core/` — unit tests for each core module - `tests/adapter/matrix/` — Matrix adapter tests (converter, dispatcher, reactions, store) - `tests/platform/` — MockPlatformClient tests **`docs/`:** - Purpose: Human-readable design documents; not consumed by code - Key docs: `docs/surface-protocol.md` (unification rationale), `docs/api-contract.md` (SDK contract), `docs/telegram-prototype.md`, `docs/matrix-prototype.md` ## Key File Locations **Entry Points:** - `adapter/matrix/bot.py` — Matrix bot `main()`, run via `python -m adapter.matrix.bot` - `.worktrees/telegram/adapter/telegram/bot.py` — Telegram bot entry (feature branch) **Shared Protocol:** - `core/protocol.py` — single source of truth for all inter-layer data types **SDK Contract:** - `sdk/interface.py` — `PlatformClient` Protocol; defines the API surface for the real SDK - `sdk/mock.py` — `MockPlatformClient`; current runtime implementation **Dispatcher Registration:** - `core/handlers/__init__.py` — `register_all()` for platform-agnostic handlers - `adapter/matrix/handlers/__init__.py` — `register_matrix_handlers()` for Matrix overrides **Persistence:** - `core/store.py` — `StateStore` Protocol, `InMemoryStore`, `SQLiteStore` - `adapter/matrix/store.py` — Matrix-specific store helper functions (not a store implementation) **Configuration:** - `pyproject.toml` — dependencies, pytest config (`asyncio_mode = "auto"`, `pythonpath = ["."]`), ruff config - `conftest.py` — `sys.path` insert so local `sdk/` shadows stdlib `platform` module ## Naming Conventions **Files:** - Modules: `snake_case.py` - Entry points: `bot.py` per adapter - Converter: `converter.py` per adapter - Handlers directory: `handlers/` per layer **Classes:** - Managers: `{Domain}Manager` (e.g. `ChatManager`, `AuthManager`, `SettingsManager`) - Bot runtime: `{Platform}Bot` (e.g. `MatrixBot`) - Protocol types: PascalCase dataclasses (e.g. `IncomingMessage`, `OutgoingUI`) - SDK types: PascalCase Pydantic models (e.g. `MessageResponse`, `UserSettings`) **Handler functions:** - `handle_{command}` for command handlers (e.g. `handle_start`, `handle_new_chat`) - `make_handle_{command}` for factory functions that close over adapter state (e.g. `make_handle_new_chat(client, store)`) **State keys:** - `"{namespace}:{discriminator}"` — always use the prefix constants defined in `adapter/matrix/store.py` ## Where to Add New Code **New core command handler:** 1. Add `async def handle_{cmd}(event, chat_mgr, auth_mgr, settings_mgr, platform) -> list` in `core/handlers/{category}.py` 2. Register it in `core/handlers/__init__.py:register_all()` with `dispatcher.register(IncomingCommand, "{cmd}", handle_{cmd})` 3. Write tests in `tests/core/test_dispatcher.py` or a dedicated `tests/core/test_{category}.py` **New Matrix-specific handler (needs nio client or matrix store):** 1. Add handler in `adapter/matrix/handlers/{category}.py` 2. Register in `adapter/matrix/handlers/__init__.py:register_matrix_handlers()` — this overrides the core handler for that key **New protocol type:** - Add dataclass to `core/protocol.py`; update `IncomingEvent` or `OutgoingEvent` union aliases if it crosses layer boundaries - Update `EventDispatcher._routing_key()` if it requires a new dispatch strategy **New StateStore key namespace:** - Add prefix constant and helper functions in `adapter/matrix/store.py` (for Matrix-specific state) or directly in the relevant manager (for core state) **New test:** - Unit tests for core logic: `tests/core/test_{module}.py` - Adapter tests: `tests/adapter/matrix/test_{module}.py` - Use `InMemoryStore` as the store; use `MockPlatformClient` as the platform client ## Special Directories **`.worktrees/telegram/`:** - Purpose: Git worktree for `feat/telegram-adapter` branch; full copy of the repo root - Generated: Yes (via `git worktree add`) - Committed: No (worktrees are local) **`.planning/`:** - Purpose: GSD planning artefacts — phase plans and codebase maps - Generated: Yes (by `/gsd:` commands) - Committed: Yes (tracked with the repo) **`.claude/agents/`:** - Purpose: Agent role configuration files for the multi-agent workflow - Committed: Yes **`src/`:** - Purpose: Contains only `surfaces_bot.egg-info/` (setuptools build artefact); no source code - Generated: Yes - Committed: No --- *Structure analysis: 2026-04-01*