Drop direct `import Postbox` from four leaf consumer submodules, routing data access through TelegramEngine/TelegramCore. Behavior-preserving. Consumers migrated: - ChatInterfaceState - ChatSendMessageActionUI - ContactListUI - DrawingUI TelegramCore additions (typealiases + one EngineData item): - EngineMemoryBuffer, EnginePostboxDecoder, EnginePostboxEncoder, EngineAdaptedPostboxDecoder (narrow utility aliases for coding support) - EngineData.Item.Configuration.ContactsSettings Six planned modules were abandoned in wave 1 with reasons recorded in the plan: ActionSheetPeerItem, ChatListSearchRecentPeersNode, DirectMediaImageCache, FetchManagerImpl, GalleryData, ICloudResources. Each either has a public API that leaks `Postbox`/`Account`/`MediaBox` (banned umbrella-type aliases) or cascades into out-of-wave modules. CLAUDE.md now records the wave rules, typealias cheat sheet, and the wave-selection guidance learned from this pass. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
4.5 KiB
CLAUDE.md
This file provides guidance to AI assistants when working with code in this repository.
Build
The app is built using Bazel.
Code Style Guidelines
- Naming: PascalCase for types, camelCase for variables/methods
- Imports: Group and sort imports at the top of files
- Error Handling: Properly handle errors with appropriate redaction of sensitive data
- Formatting: Use standard Swift/Objective-C formatting and spacing
- Types: Prefer strong typing and explicit type annotations where needed
- Documentation: Document public APIs with comments
Project Structure
- Core launch and application extensions code is in
Telegram/directory - Most code is organized into libraries in
submodules/ - External code is located in
third-party/ - No tests are used at the moment
Postbox → TelegramEngine refactor (in progress)
A gradual migration is underway to eliminate direct import Postbox from consumer submodules in favor of TelegramEngine. See:
- Spec:
docs/superpowers/specs/2026-04-16-postbox-to-telegramengine-refactor-wave-1-design.md - Plan:
docs/superpowers/plans/2026-04-16-postbox-to-telegramengine-refactor-wave-1.md
Rules that apply to every wave
TelegramCoredoes not@_exported import Postbox. Once a consumer dropsimport Postbox, every remaining Postbox-type reference must use an engine-typealiased equivalent.- Never typealias
Postbox,Account, orMediaBox. These umbrella types rename without encapsulating. Narrow utility typealiases (MemoryBuffer,PostboxDecoder,PostboxEncoder,AdaptedPostboxDecoder,MediaResource, …) remain allowed and expected. - No new engine wrapper structs unless the wave's spec explicitly allows — only typealiases and thin forwarding methods.
- Discovery first: before adding any new engine wrapper/typealias, grep
submodules/TelegramCore/Sources/TelegramEngine/for existing equivalents. Record the search result in the commit message. - Abandonment protocol: if a module can only be refactored by violating rule 2 or by editing a module outside the current wave's list, mark the task Abandoned with a recorded reason. Do NOT substitute a new module mid-wave.
- Full project build per module. No unit tests exist in this project.
Engine typealias cheat sheet (existing aliases)
PeerId → EnginePeer.Id
MessageId → EngineMessage.Id
MessageIndex → EngineMessage.Index
MessageTags → EngineMessage.Tags
MessageAttribute → EngineMessage.Attribute
MessageFlags → EngineMessage.Flags
MessageForwardInfo → EngineMessage.ForwardInfo
MediaId → EngineMedia.Id
PreferencesEntry → EnginePreferencesEntry
TempBox → EngineTempBox
PinnedItemId → EngineChatList.PinnedItem.Id
MemoryBuffer → EngineMemoryBuffer (added 2026-04)
PostboxDecoder → EnginePostboxDecoder (added 2026-04)
PostboxEncoder → EnginePostboxEncoder (added 2026-04)
AdaptedPostboxDecoder → EngineAdaptedPostboxDecoder (added 2026-04)
For the MediaResource Postbox protocol, prefer the TelegramCore subtype TelegramMediaResource when the consumer's usage allows (note: EngineMediaResource is a wrapper class, not a typealias, so it is not interchangeable with the protocol).
Wave-selection guidance (learned from wave 1)
The "leaf module, drop Postbox in isolation" approach only works for modules whose public API doesn't leak Postbox domain types. Most candidate leaf modules DO leak such types (postbox: Postbox / account: Account in public inits, Media/Message in public function parameters). Those modules need paired caller-migration waves, not isolated refactors.
Before selecting a wave's module list, grep each candidate for:
:\s*Postbox\b,:\s*Account\b,:\s*MediaBox\bin public signatures → abandon candidateMedia/Messageas public parameter types → likely needs paired wave with callers
Wave 1 outcome (2026-04-16)
4 modules done: ChatInterfaceState, ChatSendMessageActionUI, ContactListUI, DrawingUI.
6 modules abandoned with recorded reasons in the wave-1 plan: ActionSheetPeerItem, ChatListSearchRecentPeersNode, DirectMediaImageCache, FetchManagerImpl, GalleryData, ICloudResources.
Build environment quirk
The build needs TELEGRAM_CODESIGNING_GIT_PASSWORD in the environment. It is set in ~/.zshrc but Claude Code's bash tool does NOT source shell config by default. Prefix build commands with source ~/.zshrc 2>/dev/null; to pick it up.