# How the Apple Container Project Structures Its CLI Commands: A Deep Dive

> Explore the apple/container project's CLI command structure. Learn how Swift structs and a hierarchical tree organize commands for Container, Image, Machine, and more.

- Repository: [Apple/container](https://github.com/apple/container)
- Tags: deep-dive
- Published: 2026-07-06

---

**The apple/container project organizes its CLI into a hierarchical tree of Swift structs conforming to `AsyncLoggableCommand`, anchored by a root `Application` command that groups subcommands into Container, Image, Machine, Volume, and Other categories.**

The `container` command-line tool is Apple's open-source container platform for macOS, built on top of Swift ArgumentParser. Understanding the structure of commands in the apple/container project reveals how the tool manages containers, images, and virtual machines through a type-safe, declarative interface. Each command is implemented as a Swift struct that declares its behavior via static configuration properties, creating a discoverable command tree that scales from simple container creation to complex system management.

## Root Command Architecture

The entire command hierarchy is anchored in **`Application`**, the root command representing the `container` binary itself. Located in [`Sources/ContainerCommands/Application.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Application.swift) (lines 45-53), this struct conforms to `AsyncLoggableCommand` and declares a static `configuration` property of type `CommandConfiguration`.

This configuration defines the command name, abstract, version information, and the complete subcommand tree:

```swift
public static let configuration = CommandConfiguration(
    commandName: "container",
    abstract: "A container platform for macOS",
    version: ReleaseVersion.singleLine(appName: "container CLI"),
    subcommands: [
        DefaultCommand.self,
        HelpCommand.self,
    ],
    groupedSubcommands: [
        CommandGroup(name: "Container", subcommands: [ … ]),
        CommandGroup(name: "Image",     subcommands: [ … ]),
        CommandGroup(name: "Machine",   subcommands: [ … ]),
        CommandGroup(name: "Volume",    subcommands: [ … ]),
        CommandGroup(name: "Other",     subcommands: Self.otherCommands())
    ],
    defaultSubcommand: DefaultCommand.self
)

```

The root configuration includes two special top-level items: `DefaultCommand` (which handles unknown input for plugin loading) and `HelpCommand` (which implements `container help …`).

## Command Group Organization

The apple/container project organizes functionality into five distinct command groups. Each group aggregates related subcommands, making the CLI discoverable and consistent with container ecosystem conventions.

### Container Group

The **Container** group houses commands that operate on container lifecycles, including create, start, stop, exec, and prune operations. Each subcommand lives in `Sources/ContainerCommands/Container/` and follows a consistent pattern.

For example, `ContainerCreate` (defined in [`ContainerCreate.swift`](https://github.com/apple/container/blob/main/ContainerCreate.swift), lines 30-33) declares its interface as:

```swift
public struct ContainerCreate: AsyncLoggableCommand {
    public static let configuration = CommandConfiguration(
        commandName: "create",
        abstract: "Create a new container"
    )
    // ...
}

```

Other container commands such as `ContainerStart`, `ContainerStop`, `ContainerRun`, and `ContainerLogs` follow this identical structure in the same directory, each implementing a `run()` method that performs the requested action via `ContainerAPIClient`.

### Image Group

The **Image** group handles image-related operations including build, pull, push, tag, and prune. Rather than registering subcommands directly with the root, this group uses an entry point called `ImageCommand`, which aggregates its subcommands in [`Sources/ContainerCommands/Image/ImageCommand.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Image/ImageCommand.swift) (lines 34-40).

This pattern allows the image commands to share common flags and validation logic before dispatching to specific implementations like `ImageBuild` or `ImagePull`.

### Machine Group

The **Machine** group manages the underlying virtual machine that powers the container runtime on macOS. Commands like `MachineRun`, `MachineStart`, and `MachineStop` reside in `Sources/ContainerCommands/Machine/` and control the VM lifecycle independently of individual containers.

### Volume Group

The **Volume** group provides volume lifecycle management through commands like `VolumeCreate`, `VolumeList`, `VolumeInspect`, and `VolumeDelete`. These implementations are located in `Sources/ContainerCommands/Volume/` and follow the same `AsyncLoggableCommand` pattern as container commands.

### Other Group

The **Other** group contains platform-specific commands that vary by macOS version. The `otherCommands()` method in [`Application.swift`](https://github.com/apple/container/blob/main/Application.swift) (lines 223-236) dynamically returns:

- **`BuilderCommand`** – Builder lifecycle management
- **`NetworkCommand`** – Network subcommands (list, create, inspect), available only on macOS 26+
- **`SystemCommand`** – System daemon control (`container system start|stop|status`)

This conditional grouping ensures that network commands only appear on supported platforms while maintaining a consistent CLI structure across versions.

## Command Resolution and Help System

When the binary executes, Swift ArgumentParser builds a command tree from these static configurations. The `HelpCommand` (located in [`Sources/ContainerCommands/HelpCommand.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/HelpCommand.swift)) resolves paths like `container help image pull` by walking the tree using `resolveSubcommand` (lines 44-52).

This resolution mechanism allows the help system to locate any subcommand regardless of nesting depth, printing the appropriate help text for the target command. The tree structure ensures that command paths follow logical groupings: `container container create`, `container image pull`, or `container system start`.

## Summary

- The root `Application` command in [`Sources/ContainerCommands/Application.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Application.swift) defines the entire CLI hierarchy using `CommandConfiguration`.
- Commands are organized into five groups: **Container**, **Image**, **Machine**, **Volume**, and **Other**.
- Each command is a Swift struct conforming to `AsyncLoggableCommand` with a static `configuration` property declaring its name and abstract.
- The **Other** group dynamically includes platform-specific commands (Network, System, Builder) based on the host macOS version.
- `HelpCommand` uses `resolveSubcommand` to traverse the command tree and display contextual help for any nested subcommand.

## Frequently Asked Questions

### How does the container CLI handle unknown commands?

The `Application` configuration specifies `DefaultCommand` as the `defaultSubcommand`. This command catches unknown input and attempts plugin loading, allowing the CLI to be extended without modifying the core command tree.

### Why are some commands missing on older macOS versions?

The `otherCommands()` method in [`Application.swift`](https://github.com/apple/container/blob/main/Application.swift) conditionally excludes `NetworkCommand` on macOS versions prior to 26. This dynamic grouping ensures that platform-specific features only appear when the underlying system supports them.

### Where is the actual command execution logic implemented?

While the command structure and argument parsing are defined in `Sources/ContainerCommands/`, each leaf command's `run()` method typically delegates to a client from `ContainerAPIClient`. This separation keeps the CLI layer focused on argument parsing and validation while the API client handles the actual container operations.

### How can I add a new subcommand to the container CLI?

Create a new Swift struct conforming to `AsyncLoggableCommand` in the appropriate group directory (e.g., `Sources/ContainerCommands/Container/`), define its `CommandConfiguration` with a unique `commandName`, and add it to the corresponding `CommandGroup` array in [`Application.swift`](https://github.com/apple/container/blob/main/Application.swift). The ArgumentParser framework automatically integrates it into the help system and command tree.