surfaces/.planning/codebase/STRUCTURE.md
Mikhail Putilovskij c9072d51ea docs: add codebase map to .planning/codebase/
7 documents covering stack, integrations, architecture, structure,
conventions, testing, and concerns.
2026-04-02 00:00:51 +03:00

10 KiB

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.pyPlatformClient Protocol; defines the API surface for the real SDK
  • sdk/mock.pyMockPlatformClient; current runtime implementation

Dispatcher Registration:

  • core/handlers/__init__.pyregister_all() for platform-agnostic handlers
  • adapter/matrix/handlers/__init__.pyregister_matrix_handlers() for Matrix overrides

Persistence:

  • core/store.pyStateStore 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.pysys.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