How to Contribute to the BitChat Project: A Complete Developer Guide

Contribute to BitChat by forking the repository, setting up a Swift/Xcode environment, running the test suite, and submitting pull requests that follow the dual-transport architecture (Bluetooth mesh + Nostr protocol).

BitChat is a Swift-based, peer-to-peer messaging app that combines Bluetooth Mesh for offline communication and the Nostr protocol for online routing. This guide walks through the exact steps to contribute to BitChat, referencing the actual source files in permissionlesstech/bitchat so you can navigate the codebase with confidence.


Prerequisites for Contributing to BitChat

Before writing any code, ensure your environment matches the project's requirements:

  • Xcode 15+ or Swift 5.9+
  • macOS for iOS/macOS builds
  • just (optional task runner) for convenient commands like just test-ios
  • Git and a GitHub account

The project uses standard SwiftPM for dependency management, defined in [Package.swift](https://github.com/permissionlesstech/bitchat/blob/main/Package.swift).


Understanding BitChat's Codebase Architecture

BitChat's source code is organized into logical groups. Knowing these helps you locate where to make changes when you contribute to BitChat.

Group Purpose Key Files
Core networking Dual-transport logic, path selection, fallback handling [Sync/GossipSyncManager.swift](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Sync/GossipSyncManager.swift), [Sync/RequestSyncManager.swift](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Sync/RequestSyncManager.swift)
Nostr integration Relay handling, private envelopes, proof-of-work [Nostr/NostrProtocol.swift](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Nostr/NostrProtocol.swift), [Nostr/NostrRelayManager.swift](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Nostr/NostrRelayManager.swift)
Bluetooth mesh BLE scanning, connections, Noise-wrapped packets [Nostr/GeoRelayDirectory.swift](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Nostr/GeoRelayDirectory.swift) (geohash-aware relay discovery)
Models Messages, peers, receipts, media attachments Models/BitchatMessage+Media.swift, [Models/BitchatPeer.swift](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Models/BitchatPeer.swift)
Tests Unit and integration tests [bitchatTests/VoiceRecorderTests.swift](https://github.com/permissionlesstech/bitchat/blob/main/bitchatTests/VoiceRecorderTests.swift), [bitchatTests/ViewSmokeTests.swift](https://github.com/permissionlesstech/bitchat/blob/main/bitchatTests/ViewSmokeTests.swift)
Documentation Architecture docs and whitepaper [docs/ARCHITECTURE_V2.md](https://github.com/permissionlesstech/bitchat/blob/main/docs/ARCHITECTURE_V2.md), [WHITEPAPER.md](https://github.com/permissionlesstech/bitchat/blob/main/WHITEPAPER.md)

Step-by-Step: How to Contribute to BitChat

1. Fork and Clone the Repository

Click Fork on GitHub, then clone your fork:

git clone https://github.com/<your-username>/bitchat.git
cd bitchat

2. Configure Local Build Settings

Copy the example configuration to avoid modifying tracked files:

cp Configs/Local.xcconfig.example Configs/Local.xcconfig

The entitlements already use $(APP_GROUP_ID), so no additional changes are needed.

3. Build and Test Before Making Changes

Verify everything works on a clean clone:


# macOS debug build (no code signing required)

xcodebuild -project bitchat.xcodeproj -scheme "bitchat (macOS)" \
    -configuration Debug CODE_SIGNING_ALLOWED=NO build

# Run full SwiftPM test suite

swift test

For iOS-specific testing, use:

just test-ios

4. Find an Issue to Work On

Check the Issues tab on GitHub for:

  • Bug reports
  • Feature requests
  • Documentation gaps

5. Create a Feature Branch

Follow standard Git flow:

git checkout -b feat/add-new-command

6. Implement Your Change

Edit the appropriate Swift files. The exact files depend on your contribution type.

7. Run Tests Again

Ensure your changes don't break existing functionality. The CI will reject PRs that reduce test coverage.

8. Commit, Push, and Open a PR

Write a concise commit message, push your branch, and open a Pull Request against main.

9. Address Review Feedback

Apply requested tweaks, push new commits, and wait for merge.


Code Examples: Common Contribution Patterns

Adding a New Slash Command

Edit [bitchat/Models/CommandInfo.swift](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Models/CommandInfo.swift):

enum CommandInfo: String {
    case help = "/help"
    case slap = "/slap"
    // NEW: greet command
    case greet = "/greet"
}

Extending the Nostr Private Envelope

Edit [bitchat/Nostr/NostrProtocol.swift](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Nostr/NostrProtocol.swift):

extension NostrProtocol {
    static let privateEnvelopeKind = 1059      // existing BitChat envelope kind
    // NEW: custom encryption identifier
    static let customEncryptionTag = "xchaCha20-poly1305"
}

Writing a Unit Test for Your Feature

Create [bitchatTests/CommandInfoTests.swift](https://github.com/permissionlesstech/bitchat/blob/main/bitchatTests/):

import XCTest
@testable import bitchat

final class CommandInfoTests: XCTestCase {
    func testGreetCommandIsRecognized() {
        XCTAssertEqual(CommandInfo(rawValue: "/greet"), .greet)
    }
}

Adding User-Facing Strings

Update bitchat/Localizable.xcstrings:

{
    "app_info.features.greet.title": {
        "type": "text",
        "value": "Send a friendly greeting"
    }
}

Best Practices for BitChat Contributors

  • Stay on the main branch — CI runs on every PR against main
  • Never edit tracked configuration files directly — use Local.xcconfig for local overrides
  • Write tests — coverage requirements are enforced in CI
  • Respect the dual-transport architecture — new features must work over both Bluetooth mesh and Nostr; add transport-agnostic logic to the Sync layer (e.g., GossipSyncManager)

Key Documentation Resources

Resource Purpose
[README.md](https://github.com/permissionlesstech/bitchat/blob/main/README.md) Project overview and quick-start
[docs/ARCHITECTURE_V2.md](https://github.com/permissionlesstech/bitchat/blob/main/docs/ARCHITECTURE_V2.md) Detailed architecture diagrams
[WHITEPAPER.md](https://github.com/permissionlesstech/bitchat/blob/main/WHITEPAPER.md) Cryptography, privacy, and mesh design

Summary

  • Fork and clone permissionlesstech/bitchat to begin
  • Use Local.xcconfig for local build settings without modifying tracked files
  • Build with xcodebuild or just test-ios to verify your environment
  • Reference the six code groups (Core networking, Nostr, Bluetooth, Models, Tests, Documentation) to find where changes belong
  • Add tests for every feature — CI enforces coverage requirements
  • Maintain dual-transport compatibility — use GossipSyncManager for transport-agnostic logic

Frequently Asked Questions

What programming language is BitChat written in?

BitChat is written in Swift and uses SwiftPM for dependency management. The minimum required version is Swift 5.9 or Xcode 15.

Do I need an iOS device to contribute to BitChat?

No. You can build and test the macOS target without code signing using CODE_SIGNING_ALLOWED=NO, or run the SwiftPM test suite with swift test. Physical iOS devices are only needed for testing Bluetooth mesh functionality.

Where should I add new networking features in BitChat?

Add transport-agnostic logic to [Sync/GossipSyncManager.swift](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Sync/GossipSyncManager.swift). This is the canonical location for features that must work over both Bluetooth mesh and Nostr relays. Transport-specific code belongs in [Nostr/NostrProtocol.swift](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Nostr/NostrProtocol.swift) or the BLE implementation files.

How does BitChat handle configuration without exposing secrets?

The project uses a layered configuration system. Copy Configs/Local.xcconfig.example to Configs/Local.xcconfig for your local settings. This file is gitignored, so your changes stay local. The entitlements reference $(APP_GROUP_ID) which resolves through this local config.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →