badoo/Chatto
A lightweight framework to build chat applications, made in Swift
Healthy across the board
Permissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 5w ago
- ✓8 active contributors
- ✓Distributed ownership (top contributor 46% of recent commits)
Show 3 more →Show less
- ✓MIT licensed
- ✓CI configured
- ✓Tests present
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/badoo/chatto)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/badoo/chatto on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: badoo/Chatto
Generated by RepoPilot · 2026-05-10 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/badoo/Chatto shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across the board
- Last commit 5w ago
- 8 active contributors
- Distributed ownership (top contributor 46% of recent commits)
- MIT licensed
- CI configured
- Tests present
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live badoo/Chatto
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/badoo/Chatto.
What it runs against: a local clone of badoo/Chatto — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in badoo/Chatto | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 67 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of badoo/Chatto. If you don't
# have one yet, run these first:
#
# git clone https://github.com/badoo/Chatto.git
# cd Chatto
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of badoo/Chatto and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "badoo/Chatto(\\.git)?\\b" \\
&& ok "origin remote is badoo/Chatto" \\
|| miss "origin remote is not badoo/Chatto (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "Chatto/sources/ChatController/BaseChatViewController.swift" \\
&& ok "Chatto/sources/ChatController/BaseChatViewController.swift" \\
|| miss "missing critical file: Chatto/sources/ChatController/BaseChatViewController.swift"
test -f "Chatto/sources/Chat Items/ChatItemProtocolDefinitions.swift" \\
&& ok "Chatto/sources/Chat Items/ChatItemProtocolDefinitions.swift" \\
|| miss "missing critical file: Chatto/sources/Chat Items/ChatItemProtocolDefinitions.swift"
test -f "Chatto/sources/ChatController/ChatMessages/ChatMessageCollectionAdapter.swift" \\
&& ok "Chatto/sources/ChatController/ChatMessages/ChatMessageCollectionAdapter.swift" \\
|| miss "missing critical file: Chatto/sources/ChatController/ChatMessages/ChatMessageCollectionAdapter.swift"
test -f "Chatto/sources/ChatController/Collaborators/ChatCollectionViewLayout.swift" \\
&& ok "Chatto/sources/ChatController/Collaborators/ChatCollectionViewLayout.swift" \\
|| miss "missing critical file: Chatto/sources/ChatController/Collaborators/ChatCollectionViewLayout.swift"
test -f "Chatto/sources/ChatController/ChatMessages/New/CollectionUpdateProvider.swift" \\
&& ok "Chatto/sources/ChatController/ChatMessages/New/CollectionUpdateProvider.swift" \\
|| miss "missing critical file: Chatto/sources/ChatController/ChatMessages/New/CollectionUpdateProvider.swift"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 67 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~37d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/badoo/Chatto"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Chatto is a lightweight Swift framework for building chat applications with efficient UICollectionView-based message rendering, background layout calculation, and bidirectional pagination support. It solves the core problem of rendering thousands of chat messages performantly by calculating collection view changes and layouts off the main thread, with companion framework ChattoAdditions providing text/photo bubbles and an extensible input bar. Two-framework monorepo: Chatto/sources contains core chat controller (BaseChatViewController → ChatMessagesViewController), chat items protocol system (ChatItemProtocolDefinitions), and collection view layout logic (ChatCollectionViewLayoutModelFactory, CollectionUpdateProvider). ChattoAdditions (mentioned but separate target) extends with concrete cell implementations. Tests mirror source structure under Chatto/Tests with unit tests for each major component.
👥Who it's for
iOS developers building chat applications in Swift who need a production-ready foundation with built-in pagination, keyboard handling, and custom message cell support without building UICollectionView management from scratch.
🌱Maturity & risk
Production-ready and actively maintained: CocoaPods version 4.1.0 released for Swift 5, Swift Package Manager support added, comprehensive test coverage (Tests/ directory with unit tests for ChatController, ChatItemPresenter, CollectionChanges), CI/CD via GitHub Actions (.github/workflows/swift.yml), and codecov integration. Last activity appears current based on Swift 5 support and modern build configuration.
Low-to-moderate risk for active projects: single organization (Badoo) maintains it, but no visible GitHub stars/watchers count in provided data. Monolithic Swift codebase (1M+ LOC) with tight coupling between BaseChatViewController and ChatMessagesViewController may create refactoring friction. No breaking changes documented in CHANGELOG.md snippet, but deprecation path for future Swift versions unknown.
Active areas of work
Active Swift 5 maintenance with CocoaPods/SPM/Carthage distribution. GitHub Actions CI enabled (.github/workflows/swift.yml). No specific open PRs visible in file list, but contribution guidelines exist (.github/CONTRIBUTING.md), indicating ongoing community engagement.
🚀Get running
git clone https://github.com/badoo/Chatto.git && cd Chatto && pod install && open Chatto.xcworkspace (for CocoaPods) OR use .swiftpm/xcode/package.xcworkspace for SPM. For bleeding-edge: include :git => 'https://github.com/badoo/Chatto', :branch => 'master' in Podfile.
Daily commands: Open Chatto.xcworkspace in Xcode and run scheme 'Chatto' (iOS target) or 'ChattoAdditions' for the companion framework. Unit tests: Xcode Test navigator or xcodebuild test -workspace Chatto.xcworkspace -scheme Chatto -configuration Debug.
🗺️Map of the codebase
Chatto/sources/ChatController/BaseChatViewController.swift— Core view controller orchestrating the entire chat UI, manages message display, input handling, and layout—every contributor must understand this entry pointChatto/sources/Chat Items/ChatItemProtocolDefinitions.swift— Defines the protocol contract for chat items (models, presenters, cells)—foundational abstraction that all message types depend onChatto/sources/ChatController/ChatMessages/ChatMessageCollectionAdapter.swift— Bridges data model changes to UICollectionView updates; handles batch insertions/deletions that power the reactive message displayChatto/sources/ChatController/Collaborators/ChatCollectionViewLayout.swift— Custom UICollectionViewLayout computing bubble sizes and positioning; critical for performance and correct message layoutChatto/sources/ChatController/ChatMessages/New/CollectionUpdateProvider.swift— Calculates UICollectionView changes (insertions, deletions, moves) from diff data; key to efficient incremental updatesChattoAdditions/sources/Chat Items/BaseMessage/BaseMessagePresenter.swift— Template presenter for common message patterns (text, photo); demonstrates the extension pattern for custom message typesChatto/sources/ChatItemCompanionCollection.swift— Registry mapping chat item models to their presenter/cell implementations; enables pluggable message type support
🛠️How to make changes
Add a Custom Message Type
- Create a model conforming to ChatItem protocol (or extend BaseMessage if using ChattoAdditions) (
Chatto/sources/Chat Items/ChatItemProtocolDefinitions.swift) - Create a presenter subclassing BaseChatItemPresenter, implementing layout and cell binding (
Chatto/sources/Chat Items/BaseChatItemPresenter.swift) - Create a UICollectionViewCell subclass for rendering the message view (
ChattoAdditions/sources/Chat Items/TextMessages/TextMessagePresenter.swift) - Register the ChatItemCompanion in your ChatItemCompanionCollection instance (
Chatto/sources/ChatItemCompanionCollection.swift) - Pass companions to BaseChatViewController via its data source or configuration (
Chatto/sources/ChatController/BaseChatViewController.swift)
Style Messages and Input Bar
- For message styling, create a style object conforming to the presenter's style protocol (e.g., MessageCollectionViewCellStyle) (
ChattoAdditions/sources/Chat Items/BaseMessage/Styling) - Pass the style to the presenter's initializer or configuration (
ChattoAdditions/sources/Chat Items/BaseMessage/BaseMessagePresenter.swift) - For input bar, implement ChatInputBarPresenterProtocol and configure animations via SpringChatInputBarAnimation (
Chatto/sources/ChatController/InputBar/ChatInputBarPresentingController.swift)
Optimize Collection View Performance
- Ensure presenters implement the sizing protocol correctly and cache height calculations (
Chatto/sources/Chat Items/BaseChatItemPresenter.swift) - Use CollectionUpdateProvider to batch changes instead of reloading entire collection (
Chatto/sources/ChatController/ChatMessages/New/CollectionUpdateProvider.swift) - Configure ChatLayoutConfiguration with appropriate section insets and inter-item spacing (
Chatto/sources/ChatController/ChatLayoutConfiguration.swift) - Monitor and profile using the ChatCollectionViewLayout's metrics (
Chatto/sources/ChatController/Collaborators/ChatCollectionViewLayout.swift)
🔧Why these technologies
- UICollectionView with custom UICollectionViewLayout — Provides efficient cell recycling and custom layout control necessary for right-aligned/left-aligned message bubbles with variable heights
- Protocol-based presenter pattern (ChatItemPresenter) — Decouples message models from their UI representation, enabling extensibility without modifying core framework code
- Observable + SerialTaskQueue for reactive updates — Ensures data changes trigger UI updates serially, preventing race conditions and maintaining consistent state
- KeyboardTracker for keyboard frame observation — Enables responsive input bar positioning and scroll adjustments without manual KVO or notifications boilerplate
⚖️Trade-offs already made
-
Custom UICollectionViewLayout vs. UITableView
- Why: Messages require arbitrary horizontal positioning (bubbles aligned left/right) and complex sizing based on content and sender
- Consequence: More complex layout code but greater flexibility; UITableView constraints would force linear vertical layout only
-
Synchronous batch collection updates vs. diffable data source (iOS 13+)
- Why: Framework targets broader iOS versions; provides fine-grained control over insertion/deletion order
- Consequence: Manual changeset computation is verbose but predictable; diffable data source unavailable for older iOS targets
-
Companion pattern (model + presenter + cell) vs. single cell class
- Why: Separates concerns and allows multiple cell implementations per model type (e.g., compact vs. detailed)
- Consequence: Three classes per message type but clear single responsibility; enables style variants without duplicating logic
🚫Non-goals (don't propose these)
- Real-time synchronization or multiplayer conflict resolution
- End-to-end encryption or security features
- Push notifications or background message delivery
- Media upload/download or file transfer—
🪤Traps & gotchas
No environment variables required, but UICollectionView performance depends on background thread layout calculation completing before scroll events—slow model binding can cause main thread stalls. Memory footprint grows with message count even with 'contention' optimization mentioned in README; pagination window size must be tuned per deployment target. SwiftLint config (.swiftlint.yml) enforces line length and complexity rules; PRs failing linting won't merge. SPM and CocoaPods versions may drift if not coordinated during releases.
🏗️Architecture
💡Concepts to learn
- Off-main-thread layout calculation — Chatto's core performance optimization: CollectionUpdateProvider and ChatCollectionViewLayoutModelFactory pre-compute cell sizes and diffs on background threads to prevent UI jank when rendering thousands of messages
- UICollectionView diffing & change calculation — CollectionChangesTests.swift validates Chatto's custom diffing algorithm for batch updates (inserts/deletes/reloads) rather than reloadData(), critical for smooth pagination animations
- Presenter pattern (Model-View-Presenter) — BaseChatItemPresenter decouples message model logic from cell display, enabling extensibility: new message types require only a new presenter, not modifying core framework
- Bidirectional pagination (top & bottom loading) — Chatto supports loading older messages upward and new messages downward in the same UICollectionView without full reload, using scroll position tracking and message count contention
- Serial task queuing — SerialTaskQueue (tested in SerialTaskQueueTests.swift) ensures layout calculations and view updates happen in order despite async execution, preventing race conditions in fast-scrolling scenarios
- Protocol-oriented collection view adapter — ChatMessagesCollectionProtocol abstracts UICollectionView details (data source, delegate) behind a protocol, allowing Chatto to swap implementations or inject test doubles
- Message count contention — Chatto mentions this optimization for 'fast pagination and rotation with thousands of messages'—likely limits in-memory message count while maintaining scroll position, trading memory for performance
🔗Related repos
MessageKit/MessageKit— Direct competitor: modern Swift chat framework with similar UICollectionView foundation but includes UI components out-of-box vs. Chatto's minimalist approachAsyncDisplayKit/Texture— Predecessor inspiration for off-main-thread layout calculation; Chatto applies this pattern specifically to chat UIsbadoo/SByteBuffer— Badoo-maintained sibling framework; may share architectural patterns or be used for message serialization in Chatto extensionsrealm/realm-swift— Common companion for Chatto projects needing local message persistence and reactive updates to chat data modelsRxSwift/RxSwift— Frequently paired with Chatto for reactive binding of messages and input events (SerialTaskQueue in Chatto suggests similar concurrency patterns)
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add unit tests for ChatCollectionViewLayout and layout configuration edge cases
ChatCollectionViewLayout.swift is a critical component for chat UI rendering, but there's no dedicated test file for it despite existing tests for ChatMessagesViewController. Edge cases like dynamic type changes, orientation changes, and extreme message sizes should be tested to prevent layout regressions.
- [ ] Create Chatto/Tests/ChatController/ChatCollectionViewLayoutTests.swift (file exists but may be incomplete)
- [ ] Add tests for layout invalidation on orientation changes
- [ ] Add tests for ChatLayoutConfiguration edge cases (zero heights, extreme sizes)
- [ ] Add tests for scroll position preservation during layout updates
- [ ] Verify test coverage includes ChatCollectionViewLayoutModelFactory.swift
Add comprehensive integration tests for NewChatMessageCollectionAdapter with CollectionUpdateProvider
The new message collection adapter (Chatto/sources/ChatController/ChatMessages/New/) is a recent addition with multiple interdependent classes (NewChatMessageCollectionAdapter.swift, CollectionUpdateProvider.swift, NewChatMessageCollectionAdapterConfiguration.swift), but there are no visible integration tests validating their combined behavior, especially around collection update batching and animation.
- [ ] Create Chatto/Tests/ChatController/NewChatMessageCollectionAdapterTests.swift
- [ ] Test CollectionUpdateProvider correctly batches updates for insertions/deletions/moves
- [ ] Test NewChatMessageCollectionAdapter configuration options affect update delivery
- [ ] Add tests for edge cases: empty updates, duplicate UIDs, out-of-order operations
- [ ] Verify interaction between NewChatMessageCollectionAdapter and ChatCollectionViewLayout
Add missing tests for CellPanGestureHandler and ChatPanGestureRecogniserHandler gesture recognition logic
Two gesture handler classes (CellPanGestureHandler.swift and ChatPanGestureRecogniserHandler.swift) in the Collaborators folder have no corresponding test files, yet they handle critical user interaction logic. This creates risk for gesture recognition bugs and swipe gesture regressions.
- [ ] Create Chatto/Tests/ChatController/CellPanGestureHandlerTests.swift
- [ ] Create Chatto/Tests/ChatController/ChatPanGestureRecogniserHandlerTests.swift
- [ ] Test gesture state transitions (began → changed → ended/cancelled)
- [ ] Test velocity thresholds and drag distance calculations
- [ ] Test interaction with ReplyFeedbackGenerator.swift for haptic feedback
- [ ] Add tests for concurrent gesture handling edge cases
🌿Good first issues
- Add unit tests for ChatMessagesViewModel (referenced in file list but no dedicated test file found—create Chatto/Tests/ChatController/ChatMessagesViewModelTests.swift covering data source mutations and layout invalidation)
- Document the ChatItemCompanion registration API with inline code examples in a new Chatto/sources/Chat Items/README.md, as the protocol-registration pattern is non-obvious for new presenters
- Create an example SwiftUI wrapper around BaseChatViewController in Examples/ showing how to bridge UIKit Chatto into modern Swift concurrency (async/await support is missing)
⭐Top contributors
Click to expand
Top contributors
- @jrcmramos-bumble — 46 commits
- @wiruzx — 39 commits
- @rmenezes — 8 commits
- @Wisors — 2 commits
- @Ssimboss — 2 commits
📝Recent commits
Click to expand
Recent commits
9235560— Merge pull request #796 from badoo/bugfix/Remove-extra-space-between-scope-and-accessor (jrcmramos-bumble)a2d4032— Remove extra space between scope and accessor (jrcmramos-bumble)fcbcbad— Merge pull request #794 from rmenezes/wrong_text_calculation_attributed_string (mike-bumble)6651359— Bumped simulator to fix CI tests (rmenezes)941a6f2— Merge branch 'badoo:master' into wrong_text_calculation_attributed_string (rmenezes)2858ca7— Add option to pass original NSAttributedString instead of creating a internal one for text calculation (rmenezes)28e0eaa— Fix cancellation support (wiruzx)e7b929a— Use NSEC_PER_SEC (wiruzx)61d7634— Rename asyncStream() to values (wiruzx)3e9456d— Add explicit self (wiruzx)
🔒Security observations
The Chatto framework demonstrates reasonable security posture as an open-source Swift framework. No critical vulnerabilities were identified in the visible codebase structure. The main concerns are moderate: lack of visible dependency lock files which could introduce supply chain risks, and limited visibility into security automation in the CI/CD pipeline. The codebase follows standard iOS development practices with SwiftLint integration. As a UI framework handling chat data, it should be reviewed for proper input validation and secure data handling when used in production applications, though the framework itself is primarily a UI abstraction layer with lower inherent injection risks than data-handling code.
- Medium · Missing Dependency Lock File or Version Pinning —
Dependency management configuration (Chatto.podspec, ChattoAdditions.podspec). The repository uses CocoaPods and Carthage for dependency management, but no Podfile.lock or Cartfile.resolved is visible in the provided file structure. This could allow transitive dependency vulnerabilities to be introduced during installation if package versions are not strictly pinned. Fix: Ensure Podfile.lock and Cartfile.resolved are committed to version control. Use exact version pinning for all dependencies and regularly audit them with tools like pod outdated or carthage outdated. - Low · Potential Information Disclosure in Public Repository —
.codecov.yml, .github/workflows/swift.yml. The repository is publicly available on GitHub (badoo/Chatto). While this is intentional for open-source projects, the presence of .codecov.yml and build configuration files could expose CI/CD pipeline details that might aid attackers in reconnaissance. Fix: Review CI/CD workflow files for exposed credentials or sensitive information. Use GitHub secrets for any sensitive values. Ensure build logs do not contain secrets. - Low · No Security Policy or SECURITY.md —
Repository root. There is no visible SECURITY.md or security policy file in the provided file structure. This makes it unclear how security vulnerabilities should be reported. Fix: Create a SECURITY.md file following GitHub's security policy guidelines to guide researchers on responsible disclosure of vulnerabilities. - Low · Limited Visibility into SwiftLint Configuration —
.swiftlint.yml, Chatto/.swiftlint.yml, ChattoAdditions/.swiftlint.yml. While .swiftlint.yml files are present, their content is not shown. SwiftLint can enforce security-related rules, but misconfiguration could allow unsafe patterns. Fix: Review SwiftLint configurations to ensure they enable security-focused rules such as force_unwrapping, force_cast, and implicitly_unwrapped_optional detection. - Low · No Apparent Static Analysis Integration —
.github/workflows/swift.yml. No evidence of integrated static analysis tools (SAST) beyond SwiftLint in the CI/CD pipeline visible in the provided structure. Swift-specific security issues may not be caught automatically. Fix: Integrate additional static analysis tools such as Swift Package Manager security scanning, or commercial SAST tools designed for Swift code analysis into the CI/CD pipeline.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.