signalapp/Signal-iOS
A private messenger for iOS.
Mixed signals — read the receipts
worst of 4 axescopyleft license (AGPL-3.0) — review compatibility; no tests detected
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 2d ago
- ✓10 active contributors
- ✓Distributed ownership (top contributor 35% of recent commits)
Show 4 more →Show less
- ✓AGPL-3.0 licensed
- ✓CI configured
- ⚠AGPL-3.0 is copyleft — check downstream compatibility
- ⚠No test directory detected
What would change the summary?
- →Use as dependency Concerns → Mixed if: relicense under MIT/Apache-2.0 (rare for established libs)
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 "Forkable" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/signalapp/signal-ios)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/signalapp/signal-ios on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: signalapp/Signal-iOS
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/signalapp/Signal-iOS 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
WAIT — Mixed signals — read the receipts
- Last commit 2d ago
- 10 active contributors
- Distributed ownership (top contributor 35% of recent commits)
- AGPL-3.0 licensed
- CI configured
- ⚠ AGPL-3.0 is copyleft — check downstream compatibility
- ⚠ No test directory detected
<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 signalapp/Signal-iOS
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/signalapp/Signal-iOS.
What it runs against: a local clone of signalapp/Signal-iOS — 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 signalapp/Signal-iOS | Confirms the artifact applies here, not a fork |
| 2 | License is still AGPL-3.0 | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 32 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of signalapp/Signal-iOS. If you don't
# have one yet, run these first:
#
# git clone https://github.com/signalapp/Signal-iOS.git
# cd Signal-iOS
#
# 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 signalapp/Signal-iOS and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "signalapp/Signal-iOS(\\.git)?\\b" \\
&& ok "origin remote is signalapp/Signal-iOS" \\
|| miss "origin remote is not signalapp/Signal-iOS (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(AGPL-3\\.0)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"AGPL-3\\.0\"" package.json 2>/dev/null) \\
&& ok "license is AGPL-3.0" \\
|| miss "license drift — was AGPL-3.0 at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "Signal.xcodeproj/project.pbxproj" \\
&& ok "Signal.xcodeproj/project.pbxproj" \\
|| miss "missing critical file: Signal.xcodeproj/project.pbxproj"
test -f "Podfile" \\
&& ok "Podfile" \\
|| miss "missing critical file: Podfile"
test -f "BUILDING.md" \\
&& ok "BUILDING.md" \\
|| miss "missing critical file: BUILDING.md"
test -f "Config/Project.xcconfig" \\
&& ok "Config/Project.xcconfig" \\
|| miss "missing critical file: Config/Project.xcconfig"
test -f ".github/workflows/main.yml" \\
&& ok ".github/workflows/main.yml" \\
|| miss "missing critical file: .github/workflows/main.yml"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 32 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~2d)"
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/signalapp/Signal-iOS"
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
Signal iOS is the official end-to-end encrypted messaging client for Apple devices, built in Swift and Objective-C. It implements the Signal Protocol for secure peer-to-peer communication, supporting encrypted 1:1 messages, group chats, voice/video calls, and file sharing with zero-knowledge architecture—meaning Signal servers cannot decrypt user messages. Monolithic iOS app structure: Signal.xcodeproj is the single Xcode project spanning ~29K Swift files and 400K Objective-C files organized by feature (messaging, calls, settings, contacts). Source code lives in a flat hierarchy with Config/ for Xcode build settings, Scripts/ for build automation (Python, Shell, Ruby), and Podfile managing CocoaPods dependencies. State management and crypto integration use Foundation frameworks and custom Signal Protocol bindings.
👥Who it's for
iOS users who prioritize privacy and want encrypted messaging without surveillance, and iOS developers contributing to the Signal ecosystem who need to understand mobile cryptographic implementation, UI patterns for secure communication, or integration with the Signal Protocol library.
🌱Maturity & risk
Highly mature and production-ready: Signal iOS is actively maintained by Signal Messenger, LLC with continuous deployment to the App Store (29.4M lines of Swift, active CI/CD in .github/workflows/), and serves millions of daily users. The codebase shows professional practices: automated testing pipelines, code style enforcement (.swiftformat, .clang-format), protobuf validation, and translation management. Verdict: production-grade, actively developed.
Minimal risk as a consumer; high responsibility as a contributor. This handles cryptographic keys and secure message state—any change risks user security. The build requires exact Xcode version (.xcode-version enforced), and the 29MB Swift codebase creates long compilation times. The GNU AGPLv3 license requires careful consideration for derivative works, and the repo uses git submodules (.gitmodules) which can complicate cloning and updates.
Active areas of work
Active CI/CD and build validation: .github/workflows/ show main branch testing, precommit linting (Scripts/precommit.py), protobuf schema validation (protobuf-check.yml), translation synchronization (translation-tool.yml, translation-validator.yml), and stale issue cleanup. The build system enforces version pinning (.ruby-version, .xcode-version) and integrates emoji data generation (Scripts/EmojiGenerator.swift). Recent work focuses on translation management, code quality checks, and feature flag management across deployment tiers (Scripts/feature_flags_*.py).
🚀Get running
git clone https://github.com/signalapp/Signal-iOS.git && cd Signal-iOS && pod install && open Signal.xcworkspace (or follow BUILDING.md for exact Xcode/Ruby versions). Ensure your .xcode-version matches the pinned version and Ruby version is set via .ruby-version (uses rbenv/rvm).
Daily commands: xcodebuild -workspace Signal.xcworkspace -scheme Signal -configuration Debug build (or use Xcode GUI). Scripts/build-and-test.sh automates building and parsing test results. See BUILDING.md for Xcode version, minimum iOS deployment target, and provisioning profile setup required.
🗺️Map of the codebase
Signal.xcodeproj/project.pbxproj— Master Xcode project configuration defining all targets, build phases, and dependencies—essential for understanding how the app is built and linked.Podfile— CocoaPods dependency manifest declaring all third-party libraries and their versions; changes here affect the entire project's external dependencies.BUILDING.md— Setup and build instructions for developers; required reading before attempting to compile or develop the app.Config/Project.xcconfig— Xcode build configuration containing project-wide compiler flags, signing identities, and bundle identifiers shared across all targets..github/workflows/main.yml— Primary CI/CD pipeline defining automated build, test, and release workflows; governs merge-gate checks and artifact generation.Scripts/sds_codegen/sds_config/sds-config.json— Data model schema and code generation configuration for Signal's Secure Data Store; critical for understanding model layer generation.CONTRIBUTING.md— Contribution guidelines and coding standards for the project; mandatory reference for pull requests and code review expectations.
🛠️How to make changes
Add a New Data Model
- Define the new model schema in the SDS configuration file under the appropriate entity section (
Scripts/sds_codegen/sds_config/sds-config.json) - Add type mappings if using custom types in the record type map (
Scripts/sds_codegen/sds_config/sds_record_type_map.json) - Run the code generator to create model classes and database accessors (
Scripts/sds_codegen/sds_regenerate.sh) - The generated models will be created in the appropriate source folders; import and use them in your feature code
Add a New CI/CD Check
- Create a new workflow file in .github/workflows/ following existing patterns (e.g., main.yml, precommit.yml) (
.github/workflows) - Define the trigger conditions (on: [push, pull_request]) and job steps with appropriate actions (
.github/workflows/main.yml) - If adding a linting rule, update the pre-commit scripts and configuration (
Scripts/precommit.py) - Test the workflow by pushing to a feature branch and verifying the action runs correctly
Integrate a New Dependency
- Add the pod dependency and version constraints to Podfile (
Podfile) - If the dependency uses bridging headers or requires Xcode config, update the build settings (
Config/Project.xcconfig) - Run 'pod install' to update Podfile.lock and regenerate workspace (
Podfile.lock) - Update or add build phases in the Xcode project if the dependency requires custom build steps (
Signal.xcodeproj/project.pbxproj)
Add a New Translation String
- Add the string key and English value to the appropriate Localizable.strings resource file (
Scripts/translation-tool/src/TranslatableFile.swift) - Use the translation tool to push the source strings to the translation service (
Scripts/translation/push-translation-source) - Run the translation sync script to pull translated strings once available (
Scripts/translation/sync-translations) - Validate all translations with the translation validator before merging (
Scripts/translation-validator/src/TranslationValidator.swift)
🔧Why these technologies
- Xcode + Swift + Objective-C — Native iOS development platform with direct API access to UIKit/SwiftUI, CryptoKit, and Signal Protocol; allows tight integration with iOS security and privacy features.
- CocoaPods — Mature Objective-C/Swift dependency manager widely used in iOS ecosystem; provides deterministic builds via Podfile.lock and pod specs for cryptography, networking, and UI libraries.
- Secure Data Store (SDS) + SQLite — Custom ORM-like framework for encrypted local storage of messages and metadata; provides schema versioning and code generation to reduce data access boilerplate.
- GitHub Actions — Native CI/CD for GitHub repos; enables automated builds, linting, protobuf validation, and app signing with minimal external service dependencies.
- Protocol Buffers — Compact binary serialization for Signal Protocol messages and API payloads; language-agnostic and backward-compatible for protocol evolution.
⚖️Trade-offs already made
-
Mixed Swift + Objective-C codebase
- Why: Signal iOS has a long history predating Swift adoption; existing Objective-C code provides stability and proven patterns while new features can be written in Swift.
- Consequence: Requires understanding of both languages, bridging headers, and interop; slower migration to modern Swift-only patterns but reduced rewrite risk.
-
Custom SDS instead of Core Data or Realm
- Why: SDS is tightly coupled to Signal's encryption and data residency requirements; provides fine-grained control over storage and schema evolution.
- Consequence: Not reusable outside Signal; developers must learn SDS schema and code generation; but ensures compliance with privacy model and reduces dependency on third-party frameworks for critical data.
-
Strict local-first architecture (no cloud storage)
- Why: Privacy and security design: messages and keys remain on device; Signal servers are intentionally stateless and cannot access user data.
- Consequence: No built-in cloud backup or cross-device sync (requires manual setup); limits offline functionality but eliminates entire classes of breach vectors.
-
App Store only distribution (no sideload in repo)
- Why: Simplifies code signing, update delivery, and regulatory compliance; leverages App Store's security review and sandbox.
- Consequence: Users cannot build and self-distribute; relies on App Store approval for each release; limits rapid security patching but ensures consistent versioning.
🚫Non-goals (don't propose these)
- Server-side functionality—Signal servers are stateless and run separately (not in this repo)
- Android implementation—separate repo at signalapp/signal-android
- Desktop client—separate repo at signalapp/signal-desktop
🪤Traps & gotchas
Exact Xcode version required (.xcode-version); building with a different version will fail. Requires Ruby (version in .ruby-version) and CocoaPods for dependency installation. Git submodules in .gitmodules must be cloned with --recurse-submodules flag. The Signal Protocol library is a compiled C dependency (libsignal-ios) vendored via CocoaPods—network connectivity needed during pod install. Build system uses custom Ruby scripts and Python automation (Scripts/) which may require system Python 3. Provisioning profiles and Apple Developer Team ID required for physical device testing. The app uses feature flags (Scripts/feature_flags_*.py) that vary per deployment target (QA/Beta/Production), so local builds may not enable all features.
🏗️Architecture
💡Concepts to learn
- Signal Protocol — The cryptographic protocol underlying end-to-end encryption in Signal-iOS; understanding double ratchet algorithm, session keys, and forward secrecy is essential for any crypto-related changes
- End-to-End Encryption (E2EE) — Signal-iOS' core security feature where messages are encrypted on the sender's device and decrypted only on the recipient's device; no unencrypted data reaches servers
- Perfect Forward Secrecy — Signal Protocol property ensuring compromised long-term keys don't expose past messages; critical for Signal-iOS' security model and key rotation strategy
- CocoaPods Dependency Management — Signal-iOS uses CocoaPods (not Swift Package Manager) for vendor libraries including libsignal-ios; understanding Podfile versioning and pod install mechanics is required for dependency updates
- Core Data Persistence — Signal-iOS stores encrypted conversation state, contacts, and message metadata in Core Data; understanding relationships, migrations, and thread safety is critical for data layer changes
- Git Hooks and Pre-commit Validation — Scripts/precommit.py enforces code style and lint rules before commits; understanding hook automation and swiftformat configuration prevents CI failures
- Feature Flags (Tiered Deployment) — Signal-iOS uses feature_flags_*.py scripts to manage QA/Beta/Production feature rollout; understanding flag architecture is essential for shipping features incrementally and safely
🔗Related repos
signalapp/libsignal— Core Signal Protocol cryptographic library (Rust + Swift bindings) that Signal-iOS depends on via CocoaPods for end-to-end encryptionsignalapp/Signal-Android— Parallel Signal messenger implementation for Android; feature parity and architecture decisions often mirror iOS for cross-platform consistencysignalapp/Signal-Desktop— Electron-based desktop Signal client; shares backend protocol and UI/UX principles with iOS, useful for understanding multi-platform design decisionssignalapp/signal-server— Backend server handling authentication, message relay, and metadata; iOS app communicates with this for push notifications and server-side featuressignalapp/signal-ui-kit— Shared UI component library and design system referenced across Signal platforms for consistent visual language and accessibility standards
🪄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 comprehensive unit tests for Scripts/sds_codegen/ code generation pipeline
The Scripts/sds_codegen/ directory contains critical code generation logic (sds_generate.py, sds_parse_objc.py, sds_parse_swift_bridging.py) that transforms database schema definitions into Swift/Objective-C models. These scripts lack visible unit test coverage, creating risk of silent failures during model generation. Adding tests would catch regressions in the codegen pipeline that affect the entire app's data layer.
- [ ] Create Tests/Scripts/sds_codegen_tests.py with unit tests for sds_generate.py functions
- [ ] Add tests for sds_parse_objc.py covering Objective-C property parsing edge cases
- [ ] Add tests for sds_parse_swift_bridging.py covering Swift bridging header generation
- [ ] Create test fixtures using sds_config/ sample schemas
- [ ] Add GitHub Action workflow to Scripts/precommit.py to run these tests on PRs
Add GitHub Action workflow for Swift linting and code formatting validation
.swiftformat and .clang-format configuration files exist but there's no visible CI enforcement. The repo has Scripts/lint/ for license headers but no Swift code style checking in .github/workflows/. Adding a workflow would prevent style inconsistencies from merging, especially important for a large team open source project with CONTRIBUTING.md guidelines.
- [ ] Create .github/workflows/swift-lint.yml workflow
- [ ] Integrate swiftformat validation using the .swiftformat config file
- [ ] Add swiftlint integration for rule compliance (configure .swiftlint.yml if missing)
- [ ] Run on pull requests and main branch pushes
- [ ] Reference the workflow in CONTRIBUTING.md build instructions section
Add missing CI workflow for Scripts/build-and-test.sh end-to-end validation
Scripts/build-and-test.sh exists but isn't referenced in any visible .github/workflows/ file. The main.yml workflow likely exists but there's no dedicated workflow file shown that validates the documented build process works. This creates a gap where local builds might work but CI could silently fail. Adding explicit validation of the build script helps catch Xcode version mismatches (see .xcode-version and Scripts/check_xcode_version.py).
- [ ] Create .github/workflows/build-validation.yml
- [ ] Call Scripts/build-and-test.sh with appropriate parameters
- [ ] Validate .xcode-version matches runner environment using Scripts/check_xcode_version.py
- [ ] Cache CocoaPods dependencies (Podfile.lock) for faster builds
- [ ] Add conditional job for macOS runners with Xcode version matrix testing
🌿Good first issues
- Add missing unit tests for the feature_flags_*.py Python scripts in Scripts/ by creating a test_feature_flags.py file that validates flag parsing and tier-specific configuration
- Improve BUILDING.md documentation by adding troubleshooting section for common pod install failures, Xcode version mismatches, and M1/M2 chip-specific build issues
- Create a Makefile target to run Scripts/precommit.py automatically before committing, reducing friction for contributors unfamiliar with git hooks setup
⭐Top contributors
Click to expand
Top contributors
- @max-signal — 35 commits
- @sashaweiss-signal — 16 commits
- @pete-signal — 15 commits
- @igor-signal — 15 commits
- @kate-signal — 9 commits
📝Recent commits
Click to expand
Recent commits
4bcc837— Update translations (elaine-signal)9bd58dc— Update release notes (elaine-signal)416083d— Use "=/#" in place of "0/O" in Recovery Keys (sashaweiss-signal)d9d7620— Skip redundant identity key storage service update (max-signal)3394d45— Pass UInt64 around for file size display (pete-signal)4f23af1— Skip redundant merge storage service update (max-signal)489271d— Fix userProfileWriter for message-sourced changes (max-signal)5495a6a— Skip redundant verification storage service update (max-signal)f6ca5c7— Productionize "Save to Password Manager" option for Recovery Keys (sashaweiss-signal)4dd9610— Deprioritize speaker video when there is a screenshare presenting (adel-signal)
🔒Security observations
Signal iOS demonstrates good security practices as an open-source messaging application with active security considerations. The codebase includes secure configuration management patterns (xcconfig files), automated CI/CD workflows, and proper use of dependency locks. However, there are areas for improvement: (1) credential handling in Python build scripts should be audited and secured, (2) dependency vulnerability scanning should be automated in CI/CD, (3) custom git hooks should be reviewed and documented, and (4) development tools (Ruby, Xcode) should be kept current. The overall security posture is solid but would benefit from enhanced secrets management and automated security scanning in the development pipeline.
- Medium · Hardcoded Sample Configuration File —
Config/User.xcconfig.sample. The repository contains 'Config/User.xcconfig.sample' which is a template file. If developers copy this to 'User.xcconfig' without proper review, sensitive configuration values or build secrets could be accidentally committed or exposed. Fix: Ensure User.xcconfig is in .gitignore. Add clear documentation in CONTRIBUTING.md or BUILDING.md about configuration setup. Consider using environment variables or secure credential management for sensitive build configurations. - Medium · Potential Secrets in Python Build Scripts —
Scripts/bump_build_tag.py, Scripts/feature_flags_*.py, Scripts/setup_private_pods. Multiple Python scripts in Scripts/ directory (feature_flags_*.py, bump_build_tag.py, etc.) handle configuration and build processes. These scripts may process or access API keys, signing credentials, or other sensitive data that could be exposed in logs or script output. Fix: Audit all Python scripts for credential handling. Use secure secret management (e.g., AWS Secrets Manager, GitHub Secrets). Never log or print sensitive values. Ensure CI/CD workflows mask secrets in logs (.github/workflows/). - Medium · Git Hooks Pre-commit Script —
Scripts/git_hooks/pre-commit. Custom pre-commit hook found at Scripts/git_hooks/pre-commit. If this script has vulnerabilities or executes untrusted code, it could compromise the development environment. The hook's contents and permissions are not visible for verification. Fix: Review the pre-commit hook for security issues. Use well-maintained tools (pre-commit framework). Ensure the script has proper permissions (755) and is signed if possible. Document what the hook does in Scripts/git_hooks/README.md. - Low · Dependency Management via Podfile —
Podfile, Podfile.lock, .github/workflows/. The project uses CocoaPods for dependency management (Podfile and Podfile.lock present). While Podfile.lock is good for reproducibility, there's no visible evidence of automated dependency vulnerability scanning in the CI/CD configuration. Fix: Implement automated dependency vulnerability scanning in CI/CD (e.g., using tools like CocoaPods Security Scanner or Snyk). Regularly update dependencies and review security advisories. Consider adding a dependency scanning workflow. - Low · Ruby Version Management —
.ruby-version, Gemfile, Gemfile.lock. The .ruby-version file specifies a fixed Ruby version for scripts. If this version becomes unsupported or has known vulnerabilities, the build environment could be compromised. Fix: Regularly update Ruby version to the latest stable release. Monitor Ruby security advisories. Verify that all gems in Gemfile.lock are from trusted sources and kept up-to-date. Consider using tool versions in CI/CD that auto-validate. - Low · Xcode Version Pinning —
.xcode-version, Scripts/check_xcode_version.py. The .xcode-version file pins a specific Xcode version. While this ensures consistency, outdated Xcode versions may contain unpatched security vulnerabilities in the compiler or build tools. Fix: Keep Xcode version updated to the latest stable release. Subscribe to Apple security updates. Verify the version used in CI/CD (.github/workflows/) matches and is current. Document the rationale for any version constraints.
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.