# How to Contribute to Apple's Container Project: A Step-by-Step Guide

> Learn how to contribute to Apple's container project. Follow our step-by-step guide to fork the repo, set up your environment, and submit a successful pull request for the apple/container repository.

- Repository: [Apple/container](https://github.com/apple/container)
- Tags: how-to-guide
- Published: 2026-06-16

---

**To contribute to Apple's container project, fork the repository on GitHub, set up the Swift development environment for macOS 26 or newer, create a feature branch, and submit a pull request that passes the CI test suite and follows the coding standards.**

Apple's **container** repository is an open-source Swift command-line tool that runs OCI-compatible containers as lightweight virtual machines on Apple Silicon Macs. Understanding how to contribute to this project requires familiarity with its three-layer architecture and the XPC-based communication system. This guide walks you through the complete contribution workflow based on the actual source code structure.

## Understanding the Project Architecture

Before submitting code, understand how the three major layers interact:

- **CLI & Command Handling**: Parses user commands and drives the system service via [`Sources/ContainerXPC/XPCClient.swift`](https://github.com/apple/container/blob/main/Sources/ContainerXPC/XPCClient.swift)
- **Container Runtime**: Manages low-level VM operations through the separate containerization Swift package
- **Plugins & Extension Points**: Enables third-party services to plug into the core via XPC using [`Sources/ContainerPlugin/PluginLoader.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPlugin/PluginLoader.swift) and [`Sources/ContainerPlugin/PluginFactory.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPlugin/PluginFactory.swift)

The **XPCClient** serves as a thin wrapper around macOS XPC that the CLI uses to communicate with the background daemon. It implements async request/response handling, timeout logic, and graceful disconnect handling in [`Sources/ContainerXPC/XPCClient.swift`](https://github.com/apple/container/blob/main/Sources/ContainerXPC/XPCClient.swift).

## Setting Up Your Development Environment

You need macOS with the Swift toolchain installed. The project uses Swift Package Manager for dependency management and building.

Install the Swift toolchain for macOS 26 or newer, then clone and build:

```bash
git clone https://github.com/<your-username>/container.git
cd container
swift build   # builds the CLI and its runtime

swift test    # runs the unit-test suite

```

The test suite resides under `Tests/` (e.g., `Tests/ContainerPluginTests/`). Running the full suite verifies that changes do not break existing functionality.

## Contribution Workflow Step-by-Step

Follow this workflow to ensure your changes align with the project's standards:

1. **Read the contribution guide** – Start with [`CONTRIBUTING.md`](https://github.com/apple/container/blob/main/CONTRIBUTING.md) in the root directory, which points to the detailed guide in the containerization repository.

2. **Fork and clone** the repository using the commands above.

3. **Create a feature branch** with a descriptive name:

   ```bash
   git checkout -b feature/my-new-feature
   ```

4. **Make your changes** in the appropriate directories:
   - `Sources/ContainerPlugin/` – Add a new plugin or modify the plugin loader
   - `Sources/ContainerXPC/` – Change XPC communication or add new message types
   - `docs/` – Improve documentation or add tutorials

   Keep Swift code idiomatic and well-documented using `///` doc comments for public APIs.

5. **Run tests locally** before committing:

   ```bash
   swift test -c debug   # run with debug symbols for better stack traces

   ```

   If you add new functionality, write at least one new test case in the appropriate folder (e.g., `Tests/ContainerPluginTests/`).

6. **Commit and push** your changes:

   ```bash
   git add .
   git commit -m "Brief description of change"
   git push origin feature/my-new-feature
   ```

7. **Open a Pull Request** targeting the `main` branch. The PR template ([`.github/pull_request_template.md`](https://github.com/apple/container/blob/main/.github/pull_request_template.md)) requires you to fill in a description, link to related issues, and indicate test coverage.

8. **Address CI feedback** – The repository runs GitHub Actions workflows that execute `swift test`, `swift build`, and `swift lint`. Fix any failures before the PR can be merged.

## Code Example: Creating a Custom Plugin

Here is a minimal example of a new plugin that prints a greeting when the container daemon starts. This demonstrates how to register the plugin via `PluginFactory` and expose a command through XPC.

```swift
// File: Sources/ContainerPlugin/GreetingPlugin.swift
import ContainerXPC
import ContainerPlugin

public final class GreetingPlugin: Plugin {
    public static let identifier = "com.apple.container.greeting"

    public init() {}

    public func start() async throws {
        // Use XPC to send a log message to the daemon
        let client = XPCClient(service: "com.apple.container.daemon")
        let msg = XPCMessage()
        msg.setString("Greeting from plugin!", forKey: "message")
        try await client.send(msg)
    }
}

// Register the plugin (see PluginFactory.swift for the registration API)
PluginFactory.register(GreetingPlugin.self, for: GreetingPlugin.identifier)

```

The `Plugin` protocol (defined in [`Sources/ContainerPlugin/Plugin.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPlugin/Plugin.swift)) requires a `start()` method that the daemon calls when loading the plugin. The `XPCClient` class provides async message sending with automatic timeout handling, which matches what the daemon expects for inter-process communication.

## Key Files Every Contributor Should Know

Understanding these specific files helps you navigate the codebase effectively:

- [`CONTRIBUTING.md`](https://github.com/apple/container/blob/main/CONTRIBUTING.md) – Entry point for contribution guidelines
- [`Package.swift`](https://github.com/apple/container/blob/main/Package.swift) – Declares Swift packages, dependencies, and the tool target
- [`Sources/ContainerXPC/XPCClient.swift`](https://github.com/apple/container/blob/main/Sources/ContainerXPC/XPCClient.swift) – Core XPC wrapper handling connection lifecycle and async operations
- [`Sources/ContainerPlugin/PluginLoader.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPlugin/PluginLoader.swift) – Dynamically loads plugins from the bundle directory
- [`Sources/ContainerPlugin/PluginFactory.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPlugin/PluginFactory.swift) – Registry mapping identifiers to concrete plugin types
- [`Tests/ContainerPluginTests/PluginLoaderTest.swift`](https://github.com/apple/container/blob/main/Tests/ContainerPluginTests/PluginLoaderTest.swift) – Example unit test ensuring plugins load correctly
- [`docs/how-to.md`](https://github.com/apple/container/blob/main/docs/how-to.md) – Practical usage guide for documentation contributions
- [`scripts/update-container.sh`](https://github.com/apple/container/blob/main/scripts/update-container.sh) – Helper script for binary upgrades that may need updates when release assets change

## Summary

- **Fork the repository** and set up the Swift environment for macOS 26+ before contributing to Apple's container project
- **Understand the three-layer architecture**: CLI, runtime, and plugin system centered around XPC communication
- **Target specific directories** for changes: `Sources/ContainerPlugin/` for extensions, `Sources/ContainerXPC/` for communication logic
- **Always run tests** using `swift test` and add new test cases for functionality you introduce
- **Follow the PR template** and ensure CI passes with `swift build`, `swift test`, and `swift lint`

## Frequently Asked Questions

### What programming language does the container project use?

The Apple container project is written entirely in **Swift**. It uses Swift Package Manager for building and depends on the `ContainerXPC` module for inter-process communication. All contributions should follow Swift idioms and include `///` documentation comments for public APIs.

### Do I need an Apple Silicon Mac to contribute?

Yes, you need an Apple Silicon Mac running macOS 26 or newer to build and test the project locally. The tool specifically runs OCI-compatible containers as lightweight virtual machines on Apple Silicon, so the development environment requires compatible hardware and the latest Swift toolchain.

### How do I test my changes locally?

Run `swift test` from the repository root to execute the unit test suite. Use `swift test -c debug` for debug symbols and better stack traces if tests fail. The test files reside in `Tests/` with subdirectories like `Tests/ContainerPluginTests/` for plugin-specific validation. You must add new test cases when introducing functionality.

### Where should I add new functionality?

Add new plugins to `Sources/ContainerPlugin/`, XPC communication changes to `Sources/ContainerXPC/`, and documentation updates to `docs/`. If you modify the plugin system, you may need to update both [`PluginLoader.swift`](https://github.com/apple/container/blob/main/PluginLoader.swift) for loading logic and [`PluginFactory.swift`](https://github.com/apple/container/blob/main/PluginFactory.swift) for registration. Always ensure changes to these core files maintain backward compatibility with existing plugin identifiers.