CLAUDE.md 4.0 KB

CLAUDE.md

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

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 updateServer, logo/banner uploads myEvents
Rooms room, room.events, room.event, room.eventsAround createRoom, updateRoom, archiveRoom, joinRoom, leaveRoom, markRoomAsRead myEvents
Messages (via room.events) postMessage, editMessage, deleteMessage MessagePostedEvent, MessageUpdatedEvent, MessageDeletedEvent
Reactions (on message events) addReaction, removeReaction ReactionAddedEvent, ReactionRemovedEvent
Threads room.event.threadReplies, viewer.followedThreads followThread, unfollowThread, markThreadAsRead ThreadFollowChangedEvent
Users viewer.user, user(id), userByLogin, users updateProfile, uploadAvatar, deleteAvatar UserProfileUpdatedEvent, PresenceChangedEvent
DMs (via rooms) startDM NewDirectMessageNotificationEvent
Notifications viewer.notifications, viewer.hasNotifications dismissNotification, dismissAllNotifications NotificationCreatedEvent, NotificationDismissedEvent
Permissions/Roles via admin query, server.roles grantPermission, createRole, assignRole —
Voice calls room.voiceCallToken, activeCallRoomIds, room.callParticipants — CallParticipantJoinedEvent, CallParticipantLeftEvent
Admin admin.systemInfo, admin.serverConfig, admin.roles admin.updateServerConfig, admin.resetServerConfig 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.
  • 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)