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

> Learn how to contribute to the BitChat project. Fork the repo, set up Swift/Xcode, run tests, and submit pull requests following the dual-transport architecture. Your guide to joining BitChat development.

- Repository: [permissionlesstech/bitchat](https://github.com/permissionlesstech/bitchat)
- Tags: how-to-guide
- Published: 2026-08-01

---

**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)](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/Sync/GossipSyncManager.swift)](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Sync/GossipSyncManager.swift), [[`Sync/RequestSyncManager.swift`](https://github.com/permissionlesstech/bitchat/blob/main/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/Nostr/NostrProtocol.swift)](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Nostr/NostrProtocol.swift), [[`Nostr/NostrRelayManager.swift`](https://github.com/permissionlesstech/bitchat/blob/main/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/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`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Models/BitchatMessage%2BMedia.swift), [[`Models/BitchatPeer.swift`](https://github.com/permissionlesstech/bitchat/blob/main/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)](https://github.com/permissionlesstech/bitchat/blob/main/bitchatTests/VoiceRecorderTests.swift), [[`bitchatTests/ViewSmokeTests.swift`](https://github.com/permissionlesstech/bitchat/blob/main/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)](https://github.com/permissionlesstech/bitchat/blob/main/docs/ARCHITECTURE_V2.md), [[`WHITEPAPER.md`](https://github.com/permissionlesstech/bitchat/blob/main/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:

```bash
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:

```bash
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:

```bash

# 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:

```bash
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:

```bash
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)](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Models/CommandInfo.swift):

```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)](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Nostr/NostrProtocol.swift):

```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/CommandInfoTests.swift)](https://github.com/permissionlesstech/bitchat/blob/main/bitchatTests/):

```swift
import XCTest
@testable import bitchat

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

```

### Adding User-Facing Strings

Update [`bitchat/Localizable.xcstrings`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Localizable.xcstrings):

```json
{
    "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)](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)](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)](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/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/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.