CLAUDE.md 5.6 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

IMPORTANT: before you do anything else, run the beans prime command and heed its output. Tasks for this project are tracked in .beans/ via the beans CLI.

Project Overview

chattolib is an async Python client library for the Chatto webchat GraphQL API (https://chat.chatto.run/api/graphql). It wraps the full Chatto GraphQL schema — queries, mutations, and subscriptions — into a typed, Pythonic async interface.

Build & Development

# Install in development mode
pip install -e ".[dev]"

# Run all tests
pytest

# Run a single test
pytest tests/test_foo.py::test_bar -v

# Lint & format
ruff check .
ruff format .

# Type checking
mypy src/chattolib

Architecture

The library uses httpx for async HTTP and websockets for GraphQL subscriptions (real-time events via WebSocket).

Package layout: src/chattolib/

  • client.py — Main ChattoClient async class. Holds the httpx session, auth token, and base URL. All API methods live here or are mixed in from domain modules.
  • types.py — Dataclasses mirroring GraphQL object types (Room, User, Message, Attachment, etc.). Field names are snake_case translations of the schema's camelCase.
  • queries.py — Raw GraphQL query/mutation/subscription strings as constants.
  • subscriptions.py — WebSocket subscription handling for real-time events (server events, instance events, typing indicators, presence changes, etc.).
  • exceptions.py — Library-specific exception hierarchy wrapping GraphQL error responses.

Key API domains (from the Chatto GraphQL schema)

Domain Queries Mutations Subscriptions
Server server, server.profile updateServerConfig, uploadServerLogo, deleteServerLogo, uploadServerBanner, deleteServerBanner ServerUpdatedEvent, RoomGroupsUpdatedEvent
Rooms room, room.events, room.event, room.eventsAround createRoom, updateRoom, archiveRoom, unarchiveRoom, joinRoom, leaveRoom, banRoomMember, unbanRoomMember, markRoomAsRead myEvents
Room groups server.roomGroups createRoomGroup, updateRoomGroup, deleteRoomGroup, reorderRoomGroups, moveRoomToGroup, reorderRoomsInGroup, joinGroup RoomGroupsUpdatedEvent
Messages (via room.events) postMessage, updateMessage, deleteMessage, deleteAttachment, deleteLinkPreview MessagePostedEvent, MessageEditedEvent, MessageRetractedEvent
Assets (via attachment IDs) (server-driven) AssetProcessingStartedEvent, AssetProcessingSucceededEvent, AssetProcessingFailedEvent, AssetDeletedEvent
Reactions (on message events) addReaction, removeReaction ReactionAddedEvent, ReactionRemovedEvent
Threads room.event.threadReplies (via MessagePostedEvent), viewer.followedThreads followThread, unfollowThread, markThreadAsRead ThreadCreatedEvent, ThreadFollowChangedEvent
Users viewer.user, user(id), userByLogin, server.members updateProfile, uploadAvatar, deleteAvatar, updateSettings, requestAccountDeletion, deleteMyAccount UserCreatedEvent, UserDeletedEvent, UserProfileUpdatedEvent, PresenceChangedEvent
DMs (via rooms) startDM NewDirectMessageNotificationEvent
Notifications viewer.notifications (connection), viewer.hasNotifications dismissNotification, dismissAllNotifications, setServerNotificationLevel, setRoomNotificationLevel NotificationCreatedEvent, NotificationDismissedEvent, NotificationLevelChangedEvent, MentionStatusClearedEvent
Push — subscribeToPush, unsubscribeFromPush —
Permissions/Roles admin.rbac, server.roles grantPermission, revokePermission, createRole, updateRole, deleteRole, assignRole, plus room/user/group variants —
Voice calls room.voiceCallToken, activeCallRoomIds, room.callParticipants — CallParticipantJoinedEvent, CallParticipantLeftEvent
Admin admin.systemInfo, admin.serverConfig, admin.eventLog, admin.roomBans, admin.projections admin.updateUser, admin.updateBlockedUsernames, admin.clearUsernameCooldown via myEvents

GraphQL conventions

  • IDs are opaque strings (ID scalar).
  • Large integers use Int64 scalar (e.g., byte counts) — map to Python int.
  • File uploads use a custom Upload scalar (multipart form).
  • Pagination uses limit/before/after on room events (before/after are Time scalars, ISO timestamps).
  • All mutations take a single input argument with a corresponding *Input type.
  • Single unified subscription: myEvents for all server, room, and instance events.
  • Rooms have a type field: CHANNEL or DM. Channels live inside a RoomGroup (groupId is required at creation).
  • Threads are addressed by threadRootEventId (no separate inThread field on messages).
  • Presence: PresenceStatus (OFFLINE/ONLINE/AWAY/DO_NOT_DISTURB) is the observable type; PresenceStatusInput (no OFFLINE) is what callers can set via updateMyPresence.
  • Image URLs accept optional width, height, fit (enum: CONTAIN, COVER, EXACT) for server-side resizing.

Naming conventions

  • Python field/method names: snake_case (translated from GraphQL camelCase)
  • Type classes: PascalCase matching the GraphQL type names
  • Query/mutation method names on the client: verb_noun style (e.g., create_room, post_message, mark_room_as_read)