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

> Learn how to contribute to the BitChat project with our developer guide. Follow our 12-step workflow for setting up, testing, and submitting your code for a successful pull request.

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

---

**Contributing to BitChat requires setting up a Swift development environment with Xcode, running `just check` to validate your setup, and following a 12-step workflow that includes building the app, running tests with `just test`, linting with SwiftLint, and scanning for dead code with Periphery before submitting a pull request.**

BitChat is an open-source, dual-transport messaging app that combines **Bluetooth mesh networking** with **Nostr protocol** integration. This guide walks you through the complete contribution workflow as implemented in the [permissionlesstech/bitchat](https://github.com/permissionlesstech/bitchat) repository, from initial setup to merged pull request.

## Fork and Clone the Repository

Start by creating your own copy of the codebase. Fork the repository on GitHub, then clone your fork locally:

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

```

Working on a fork keeps the upstream history clean and allows you to propose changes through pull requests.

## Install Development Dependencies

BitChat's build system relies on several tools that must be installed before you can compile or test the code:

- **Xcode 13+** — provides the Swift toolchain used by CI
- **just** — runs reproducible build and test commands (`brew install just`)
- **SwiftLint** — enforces style guidelines (`brew install swiftlint`)
- **Periphery** — detects unused Swift symbols (`brew install periphery`)

These tools are referenced throughout the `Justfile` and CI configuration, ensuring consistency between local development and automated checks.

## Validate Your Environment

Before making changes, confirm your setup is complete:

```bash
just check

```

This command verifies that Xcode is selected, `xcodebuild` is available, and you have a full Xcode installation. A full install is required because BitChat's Bluetooth and UI tests depend on frameworks that ship only with the complete Xcode bundle, not the command-line tools alone.

## Build and Run the App Locally

Verify the project compiles with your current configuration:

```bash
just build    # macOS Debug build (no signing needed)

just run      # launches the built app

```

The macOS build is the fastest way to test changes during development. If the app launches successfully, you can proceed to automated testing.

## Run the Test Suite

BitChat uses **Swift Package Manager** for dependency management and testing. Execute the full test suite with:

```bash
just test

```

This runs unit tests for core logic including cryptography, sync mechanisms, and mesh routing. The same command executes in CI via [`.github/workflows/swift-tests.yml`](https://github.com/permissionlesstech/bitchat/blob/main/.github/workflows/swift-tests.yml), so local failures will block your pull request.

### iOS Simulator Tests

For changes affecting the UI layer or Bluetooth handling, run iOS-specific tests:

```bash
just test-ios

```

This targets the "iPhone 17" simulator by default, validating iOS-specific code paths that the macOS build cannot exercise.

## Enforce Code Quality Standards

BitChat maintains strict quality gates that run automatically in CI. You must pass these locally before submitting.

### Lint with SwiftLint

```bash
swiftlint lint --strict

```

The [`.swiftlint.yml`](https://github.com/permissionlesstech/bitchat/blob/main/.swiftlint.yml) configuration intentionally disables several rules (`line_length`, `type_name`, `force_try`) but CI will reject any violations of enabled rules. Respect the disabled rules in your code — they may be enabled in future versions.

### Scan for Dead Code

```bash
periphery scan

```

Periphery detects unused Swift symbols. The repository includes a baseline file ([`.periphery.baseline.json`](https://github.com/permissionlesstech/bitchat/blob/main/.periphery.baseline.json)) that documents known dead code. New dead code must either be removed or added to the baseline with justification.

## Update Documentation

BitChat relies on self-contained documentation in the `docs/` directory. Update relevant files when you:

- Add public-facing features
- Change build steps
- Modify architecture patterns

Key documentation files include:

- [`docs/VERIFYING-A-BUILD.md`](https://github.com/permissionlesstech/bitchat/blob/main/docs/VERIFYING-A-BUILD.md) — build verification steps
- [`docs/BITCHAT-ARCHITECTURE.md`](https://github.com/permissionlesstech/bitchat/blob/main/docs/BITCHAT-ARCHITECTURE.md) — technical architecture overview
- [`README.md`](https://github.com/permissionlesstech/bitchat/blob/main/README.md) — project overview and quick start

Keeping documentation current prevents broken builds for downstream users.

## Commit and Push Your Changes

Create a descriptive branch name that indicates the change type:

```bash
git checkout -b feature/mesh-routing-improvements

# or

git checkout -b fix/swiftlint-warnings

```

After making changes and running all local checks:

```bash
git add .
git commit -m "feat: improve mesh routing efficiency for large networks"
git push origin feature/mesh-routing-improvements

```

Use clear commit messages that describe what changed and why.

## Open and Complete a Pull Request

On GitHub, open a pull request against the `main` branch. Include in your description:

- Concise summary of changes
- Related issue number (if applicable)
- Verification checklist: tests pass, lint passes, docs updated

CI automatically runs the full test matrix, lint, and Periphery checks. A green check suite is required before maintainers can merge. Respond promptly to reviewer feedback, re-running `just test` and `swiftlint` locally before pushing updates.

## Key Contribution Practices

Follow these practices to ensure smooth integration:

- **Never commit generated files** — use `just clean` or `just nuke` to purge `.DerivedData`, `.build`, and package caches
- **Run performance checks** — execute [`scripts/check-perf-floors.sh`](https://github.com/permissionlesstech/bitchat/blob/main/scripts/check-perf-floors.sh) if you modify message handling, compression, or routing algorithms
- **Add unit tests** — place tests in `bitchatTests/` following the existing module structure (`Sync`, `Models`, `VoiceCapture`)
- **Preserve `Local.xcconfig.example`** — only modify the actual `Local.xcconfig` which is ignored by Git

## Essential Files for Contributors

| File | Purpose |
|------|---------|
| `Justfile` | Developer command shortcuts (`just build`, `just test`, `just check`) |
| [`.swiftlint.yml`](https://github.com/permissionlesstech/bitchat/blob/main/.swiftlint.yml) | Style configuration and disabled rules |
| [`.periphery.yml`](https://github.com/permissionlesstech/bitchat/blob/main/.periphery.yml) | Dead-code scan configuration |
| [`.github/workflows/swift-tests.yml`](https://github.com/permissionlesstech/bitchat/blob/main/.github/workflows/swift-tests.yml) | CI matrix definition |
| [`Package.swift`](https://github.com/permissionlesstech/bitchat/blob/main/Package.swift) | SwiftPM dependencies and targets |
| `bitchat/` | Core app source |
| `bitchatTests/` | Unit and integration tests |
| `docs/` | Architecture and verification documentation |
| `scripts/` | Performance and validation scripts |

## Summary

- **Fork and clone** the repository to your GitHub account
- **Install Xcode, just, SwiftLint, and Periphery** for the complete toolchain
- **Run `just check`** to validate your environment before making changes
- **Build with `just build` and test with `just test`** to verify functionality
- **Enforce quality with `swiftlint lint --strict` and `periphery scan`**
- **Update documentation** in `docs/` when changing public APIs or build steps
- **Submit a clean pull request** with descriptive commits and a green CI check suite

## Frequently Asked Questions

### What is the minimum Xcode version required to contribute to BitChat?

BitChat requires **Xcode 13 or later**. The project uses Swift features and frameworks that depend on the toolchain shipped with recent Xcode versions. CI specifically validates against the latest stable Xcode, so staying current avoids unexpected build failures.

### Why does BitChat use `just` instead of Make or npm scripts?

The `Justfile` provides **reproducible, cross-platform command shortcuts** that work identically on developer machines and CI runners. Commands like `just test` abstract the underlying `xcodebuild` or `swift test` invocation, ensuring everyone runs the same test configuration regardless of local setup differences.

### What happens if I forget to run SwiftLint before committing?

CI will fail the lint check and block your pull request from merging. Run `swiftlint lint --strict` locally to catch violations early. The `--strict` flag treats warnings as errors, matching the CI behavior exactly. Fix violations before pushing, or use `swiftlint --fix` for auto-correctable issues.

### How do I handle dead code that Periphery reports but I can't remove?

Add intentional dead code to [`.periphery.baseline.json`](https://github.com/permissionlesstech/bitchat/blob/main/.periphery.baseline.json) with a comment explaining why it must remain. The baseline file is part of the repository and reviewed in pull requests. Justification examples include: public API surfaces reserved for future use, or symbols referenced only through runtime reflection that static analysis cannot detect.