Understanding the Plugin Architecture for Runtime, Network, and Image Services in apple/container

The apple/container project implements an XPC-based plugin architecture where the container-apiserver launch agent dynamically loads separate helper services for image management, virtual networking, and per-container runtime operations.

The apple/container repository provides a lightweight container runtime for macOS that separates high-level CLI operations from low-level system services. This separation is realized through a modular plugin architecture that uses macOS XPC services to isolate platform-specific functionality. Understanding this architecture is essential for extending the runtime with custom network drivers, image stores, or container runtimes.

Core Components of the XPC Plugin Architecture

The architecture centers on the container-apiserver, a launch agent that owns the public client APIs and coordinates helper plugins via XPC connections. According to the technical documentation in docs/technical-overview.md (lines 45-48), the apiserver launches distinct XPC helpers for each major service domain.

container-apiserver (the orchestrator)

The container-apiserver acts as the central coordinator, starting automatically when container system start is issued. It maintains XPC connections to helper services and routes client requests to the appropriate plugin based on registered identifiers.

container-core-images (image service)

The container-core-images helper implements the default image service, handling OCI image pulling, pushing, and content-addressable storage. This XPC service registers itself with the apiserver using a unique identifier, functioning as the default image plugin referenced in docs/technical-overview.md (lines 45-48).

container-network-vmnet (network service)

For virtual networking, the container-network-vmnet helper wraps the macOS vmnet framework to provide network interfaces to containers. The apiserver spawns this helper during boot, and it registers as the default network plugin unless overridden. The build system compiles this helper as a separate target, as noted in BUILDING.md (lines 168-170).

container-runtime-linux (runtime service)

Each container receives its own runtime helper instance. When a container is created, the apiserver launches a container-runtime-linux helper inside the lightweight VM, which exposes APIs for process launch, exec operations, and signal handling. As documented in docs/technical-overview.md (lines 47-48), this per-container isolation ensures runtime failures do not affect the host or other containers.

Plugin Registration and Discovery

Each helper registers itself with the apiserver using a unique identifier. For example, the network helper registers as com.apple.container:NetworkVmnetHelper. The apiserver logs these registrations and maintains a routing table to forward client requests to the correct XPC endpoint.

Selecting Custom Plugins via CLI

The CLI supports overriding default plugins through the --plugin flag. As documented in docs/command-reference.md (lines 78-90), you can specify alternative implementations when creating network resources.


# Use the default network plugin

container network create mynet

# Specify a custom network plugin (must be an installed XPC service)

container network create mynet --plugin my-custom-network-plugin

# Inspect which plugin a network is using

container network inspect mynet | jq '.plugin'

Because helpers are ordinary XPC services, custom implementations must conform to the same XPC interface and be registered with launchd to appear as available plugins. The architecture also permits future extension of the image service via the same mechanism:


# Example: using a custom image plugin

container image pull myimage:latest --plugin my-image-plugin

Runtime Flow and Request Handling

The request lifecycle follows a strict multi-step process:

  1. System Initialization: container system start triggers launchd to spawn container-apiserver.
  2. Helper Initialization: The apiserver spawns container-core-images and container-network-vmnet, which register via XPC.
  3. Container Creation: For each new container, the apiserver launches a dedicated container-runtime-linux helper inside the VM.
  4. Request Routing: When the CLI executes container run, the request marshals to the apiserver, which forwards it to the appropriate plugin (network, image, or runtime) via XPC.
  5. Execution: The plugin performs the operation (e.g., allocating a vmnet attachment or pulling an image layer) and returns results through the XPC connection back to the CLI.

This flow is illustrated in runtime logs showing container-network-vmnet allocation activity documented in docs/how-to.md (lines 696-702).

Extending the Architecture with Custom Plugins

The XPC-based design enables straightforward extensibility without modifying core apiserver code.

Adding a network plugin: Implement an XPC service conforming to the network-plugin protocol, bundle it with the container binary, and invoke container network create --plugin <your-plugin>.

Adding an image plugin: Follow the same pattern using the image service protocol defined by container-core-images.

Runtime customization: While not exposed as a CLI flag today, the architecture supports swapping the container-runtime-linux helper by providing a different XPC service binary within the VM image.

Summary

  • The apple/container architecture uses XPC-based plugins to isolate image, network, and runtime services from the main CLI.
  • The container-apiserver launch agent orchestrates all plugin registration and request routing.
  • Default implementations include container-core-images, container-network-vmnet, and container-runtime-linux.
  • Custom plugins override defaults via the --plugin flag documented in docs/command-reference.md.
  • Each plugin registers using a unique identifier (e.g., com.apple.container:NetworkVmnetHelper) over XPC.

Frequently Asked Questions

How does the container-apiserver communicate with plugins?

The apiserver communicates via macOS XPC services, an inter-process communication mechanism that provides type-safe message passing between processes. Each helper plugin registers itself with a unique identifier such as com.apple.container:NetworkVmnetHelper, and the apiserver maintains these connections to route client requests to the appropriate service.

Can I replace the default network plugin with a custom implementation?

Yes. You can specify a custom network plugin using the --plugin flag when creating a network. Your custom plugin must be implemented as a macOS XPC service conforming to the network-plugin protocol and registered with launchd. For example: container network create mynet --plugin my-custom-network-plugin.

What is the difference between the image service and runtime service plugins?

The image service (container-core-images) is a singleton helper that manages the global image store for all containers, while the runtime service (container-runtime-linux) is instantiated per-container inside the lightweight VM to handle process execution, signals, and container lifecycle operations.

Where are the plugin interfaces documented?

The plugin architecture is documented in docs/technical-overview.md (lines 45-48), which describes the relationship between the apiserver and XPC helpers. The command-line interface for plugin selection is documented in docs/command-reference.md (lines 78-90), while build instructions for the network plugin appear in BUILDING.md (lines 168-170).

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 →