apple-compose is a Swift CLI that reads modern Docker Compose files and rolls them out with Apple's container CLI.
The implementation is intentionally strict by default. Docker Compose has features that require Docker Engine, Swarm, healthcheck state, secret/config stores, namespace controls, or Linux kernel flags that Apple container 1.0.0 does not expose. apple-compose up refuses those exact-semantic gaps unless you opt into --compatibility-mode best-effort.
swift build -c release
.build/release/apple-compose --helpApple's container CLI must be installed and configured separately.
scripts/smoke-test.shThis environment's SwiftPM toolchain does not expose Testing or XCTest, so the repository currently uses a shell smoke test that builds the CLI, checks representative command planning, and verifies strict rejection of unsupported healthchecks.
# Show compatibility findings and the Apple container commands that would run.
apple-compose plan -f compose.yaml
# Apply the project. Strict mode is the default.
apple-compose up -f compose.yaml
# Apply one service and its dependencies.
apple-compose up api
# Apply only the named service.
apple-compose up --no-deps api
# Apply while allowing documented best-effort behavior.
apple-compose up -f compose.yaml --compatibility-mode best-effort
# Print commands without executing them.
apple-compose up --dry-run
# Stop and delete project containers/networks.
apple-compose down
# Also delete named project volumes.
apple-compose down --volumes
# Print merged, interpolated Compose YAML for active profiles or selected services.
apple-compose config
apple-compose config apiDefault file discovery matches modern Compose names: compose.yaml, compose.yml, docker-compose.yaml, and docker-compose.yml.
The current Swift implementation parses and plans the core modern Compose model:
- multiple
-ffiles with Compose merge rules for maps, appended sequences, shell-command overrides, uniqueports/volumes/secrets/configsentries, and!reset/!overridetags - validated
includeshort syntax and long syntax with string/listpath, stringproject_directory, and string/listenv_file, evaluated after selected Compose files are merged, with colliding included resources merged using Compose merge rules and local definitions overriding included values - validated service
extendsstring and mapping syntax for same-file and external-file base services, including Compose's healthcheck disable restriction, target/path resource overrides for ports, volumes, secrets, configs, devices, and blkio device-limit lists, duplicate removal for Compose-defined sequence fields, and duplicate-preserving DNS/env/tmpfs list merges - Compose-relative path resolution for included/extended build contexts, env files, label files, bind mounts, configs, and secrets, with relative
build.dockerfilepaths resolved from the build context .env,--env-file, Compose env-file syntax including shell/earlier-value interpolation and single-quoted multiline values, and Compose-style${VAR},${VAR:-default},${VAR?error}, nested defaults/replacements, and related interpolation- predefined Compose environment variables for file/profile/env-file selection:
COMPOSE_FILE,COMPOSE_PATH_SEPARATOR, Compose-validatedCOMPOSE_PROFILES,COMPOSE_ENV_FILES, andCOMPOSE_DISABLE_ENV_FILE COMPOSE_PROJECT_NAMEinterpolation from-p/COMPOSE_PROJECT_NAME/ top-levelname/ directory fallback project names- Compose-reserved
com.docker.composelabel prefix validation for service, network, and volume labels - explicit empty values for known unsupported top-level/service
models, empty/null servicedevelop, Compose-compatibleproviderrequired-field and option shapes with empty provider type/options accepted as default behavior, develop watch required fields/action/target/exec shapes plus empty ignore/include patterns and empty exec user/working-directory defaults, other service attributes, and build attributes when they request no behavior after Compose merge/anchor expansion - strict scalar, string-only, boolean/boolean-string, integer, string-list, map-or-list, top-level
name/version, service/model/resource/dependency identifier, cgroup/network namespace values, IPC/PID/network namespaceservice:<name>references validated as required dependencies, IPC namespace strings includinghost/shareable/service:<name>, UTS namespace strings, realtime CPU duration/microsecond, short/long device mapping/CDI, device cgroup rule, GPU request and option forms including empty capability/device-id entries, string/numbergroup_addentries with empty entries treated as no-ops, sysctls list-or-dict forms, logging option value, credential-spec source/key, Compose-compatibleexternal_linksstring syntax,volumes_fromaccess-mode, deploy subtree known-key validation, model required-field/known-key validation including top-level model names, literal integercontext_size, empty-string model defaults with null scalar values rejected, and service model references, provider/develop shape and known-key validation, unsupported service subtree known-key validation, service network/volume/secret/config/build-secret reference validation against top-level definitions with Compose's implicitdefaultnetwork exception, and external-resource shape/local-attribute validation including deprecatedexternal.namemappings andname/external.nameconflict checks for planner-significant service fields, build fields, known unsupported service fields, long-formdepends_onflags, and top-level resource names/drivers/sources/IPAM fields serviceswithimage,build, Compose-validatedpull_policyvalues including local-image preflight fornever, Compose'slatestand inspect-before-pull behavior for default/missing/if_not_present, pull-then-build fallback for default/missing/if_not_presentimage+buildservices, explicitimage+buildhandling foralways/never/build,buildwhen a build section exists, and time-baseddaily/weekly/every_<duration>plusrefreshpulls with optionalpull_refresh_after, including zero intervals such asevery_0sand barerefresh, tracked under.apple-compose/<project>/pull-state,container_namewith Compose validation and scale restriction, validatedattachbooleans/boolean strings with attached service logs followed by default duringup,attach: falseomitted from log following, andup --detachavailable for detached rollout, validatedcommandandentrypointstring/list/null shapes, validatedenvironmentmap/list syntax including valueless keys resolved from the project environment or unset when unresolved and Compose list-form empty keys reported as Apple gaps, validated Compose-parsedenv_fileincluding non-empty long-formpath/requiredvalues, empty/defaultformat, optional files, single-quoted multiline values, andformat: raw, validatedlabelswith map-form empty keys rejected and Compose list-form empty keys reported as Apple gaps, Compose-parsed non-emptylabel_filepaths including env-file-style delimiters and interpolation, validated numericportsshort/long syntax, host IP values, protocol values including Compose-preserved whitespace protocol gaps, explicitmode: host, IPv6 publish formatting, and long-form field shapes including exact-empty metadata/published defaults with null metadata/published values rejected plus explicit fixed host/container mappings and fixed equivalent ranges, Compose-compatible string/numberexposeas intra-network metadata without publishing host ports,volumeswith Compose-style bind host-path creation defaults, short-syntax empty source/target rejection, long-form bind source requirements with explicit empty bind source resolved to the project directory, required long-form mounttype, Compose-validated long-form mount types and entry keys, validated nested long-form volume/bind/tmpfs/image option shapes including service-level volume labels, bind recursive modes, bind SELinuxz/Z, byte-value tmpfs sizes including decimal andt/psuffix forms, and string/number tmpfs modes, plus service-formvolumes_fromexpansion for explicit source-service volume mounts withro/rwaccess modes, validatedtmpfsstring/list syntax with active mode/uid/gid options reported as Apple gaps, validatednetworkslist/map syntax including string/number service-level and attachmentdriver_opts.mtu, aliases with empty entries treated as no-ops, static IP address syntax, network MAC address syntax, Compose-truncated numericpriorityordering plus service-level MAC selection, Compose-truncated numeric gateway priority, interface names, and link-local IPs, validatednetwork_modestring shape and Compose'snetwork_mode/networksmutual exclusion with onlynonemapped exactly, validateddepends_onlist/map syntax with required long-form condition values and boolean/boolean-stringrestartplus booleanrequired, start ordering, and skipped/warned missingrequired: falsedependencies, validated legacylinksservice/alias syntax with empty aliases treated as plain dependency links on shared networks, validated disabled and empty/no-ophealthcheckforms,healthcheck.teststring/list syntax with empty command arguments, healthcheck durations, and non-negative retries, Compose-compatibleprofileshandling with exact CLI profile values, comma-splitCOMPOSE_PROFILES, wildcard activation, empty profile entries treated as default/no-profile behavior, active-profile inclusion, and explicit selected-service activation, validatedplatformsyntax with OS-only values mapped to Apple--osand amd64/x86_64 platforms enabling Rosetta,runtime,mac_addresssyntax with network priority selection,working_dir,user, Compose-preserved whitespace scalar values, and exact empty string unset/default forms for service scalar fields such as namespace, host, platform, runtime, user, and working-directory settings with explicit nulls rejected where Compose requires strings, validatedinit,read_only,tty, andstdin_openbooleans/boolean strings, Compose-compatiblehostname/domainnamestring handling, Compose-compatible DNS server/search/option strings, and Compose-compatibleextra_hostsstring/list/mapping syntax including list-valued mappings and bracketed IPv6 normalization, with valid host mappings materialized as generated/etc/hostsbind mounts anddomainnamemapped to Apple--dns-domain, Compose-compatible capabilities with empty entries treated as no-ops, validated integer/string and soft/hardulimits, validated non-negativecpusquantities, non-negative integercpu_count, string/number Linux CFS CPU controls, and boundedcpu_percent, Compose-normalized byte-value memory limits/reservations and shared memory plus PID limits with config-time deploy-resource consistency checks, validated zero CPU/memory/reservation values, zero low-level CPU controls, emptycpuset, andmem_swappiness: 0as Compose default/no-op settings, validated explicit false/defaultprivileged, Compose-compatible string-onlyrestartfield handling with active policies reported as Apple gaps and explicitrestart: "no"or exact empty restart strings accepted as default behavior, validated explicit false/defaultoom_kill_disable,use_api_socket, validatedsecurity_optlist syntax with empty andno-new-privileges=falseentries accepted as default behavior, validatedstorage_optmapping shape, empty logging driver/options accepted as default behavior, byte-valuememswap_limitincluding0and-1plus positive-value memory-limit consistency, string/numberpids_limitand matching deploy PID limits including0and-1,oom_score_adj: 0, Compose-compatiblestop_signalstring validation including empty-string unset behavior, and Compose-durationstop_grace_periodwith Compose's 10-second default- Compose-compatible boolean strings use the modern Docker Compose grammar:
true/false,yes/no,y/n, andon/off; invalid or numeric boolean strings remain config errors - Compose-compatible boolean strings for
depends_on.<service>.required, such as"false", are accepted; invalid strings remain config errors - local build contexts, Dockerfiles, inline Dockerfiles with Compose's
dockerfile/dockerfile_inlinemutual exclusion, empty string/default build selector values forbuild,context,dockerfile,dockerfile_inline,network,target, andisolation, validated build args including valueless args resolved from the project environment or omitted when unresolved and Compose list-form empty keys reported as Apple gaps, validated build labels with Compose list-form empty keys reported as Apple gaps, target stage, one selected platform used for both build and run commands, validated service-selectedbuild.platformssyntax, validated no-cache/pull and privileged booleans/boolean strings, validated Compose byte-value build shared memory with0accepted as default and active values reported as Apple gaps, validated integer/string soft/hard build ulimit shapes with active values reported as Apple gaps, Compose-compatible build tag lists with empty tags omitted from Apple tag commands, validated BuildKit option shapes foradditional_contextsmapping with non-empty names and empty values plusNAME=VALUElist syntax with empty names/values accepted,cache_from,cache_to, andentitlementsincluding all-empty lists as no-ops, Compose-compatibleextra_hostssyntax,isolation, scalar/list/mapsshincludingdefault,ID=pathlist entries with empty sides, and scalar/null map values, boolean/string provenance/SBOM attestations with false or empty values accepted as defaults, ignored non-empty cache hints with warnings as permitted by Compose Build, file/env-backed build secrets with string-only uid/gid and without uid/gid/mode overrides, and validated explicit default build network mode - selected service rollout for
up/plan, with compatibility checks scoped to the planned services/resources, active provider-delegated services reported but omitted from generated Apple container commands, dependencies included by default,--no-depsavailable when you want only the named services, andconfigoutput filtered by active profiles or selected services with unused top-level resources pruned - best-effort
post_startandpre_stoplifecycle hooks usingcontainer exec, including validated hook list/mapping form plus command/string-user/privileged/working-directory/environment shapes, exact empty hookuser/working_dirvalues treated as defaults, and service-leveluser/working_dirdefaults - top-level
networkswith validated empty/mapping definitions, names, Compose-managed resource labels, validated user labels, boolean network flags includingattachable,internal,enable_ipv4, andenable_ipv6, internal mode, Compose networkdrivermapped to Apple network plugins for non-default drivers with empty strings treated as default/unset behavior, validated string/number driver options passed as Apple network--optionvalues, validated string-only IPAM driver options withdriver: default, empty driver strings, and empty option maps accepted as defaults, validated IPAM config shapes and IP/CIDR values including subnet, IP range, gateway, and auxiliary addresses, one IPv4 plus one IPv6 subnet with unsupported extra same-family subnets reported as strict rollout gaps, and external-resource existence preflight - top-level
volumeswith validated empty/mapping definitions, names, Compose-managed resource labels, validated user labels, local/default/empty driver values accepted as default behavior, validated string/number driver options including Apple-ssize mapping fromdriver_opts.size, and external-resource existence preflight - file-backed
secretsandconfigs, with validated top-level definitions including labels plus secret driver/options and config/secret template-driver metadata with empty driver/template strings accepted as default behavior, secret source validation matching Compose's file/environment/external requirement, and service/build grant list syntax plus source/target/uid/gid and string/integer mode shapes checked against those definitions, Compose-style short/long mount targets mounted read-only as bind mounts, Docker Compose's documented ignore behavior for file-backed secret uid/gid/mode options, generated secret/config mode materialization, and file-backed config mode materialization through generated read-only artifacts - environment-backed
secrets, plus file-backed, inlinecontent, and environment-backedconfigs, with validated top-level definitions, exactly-one-source validation, and materialization under.apple-compose/<project>/...as read-only mounts - validated deploy enum values, duration values, non-negative deploy counts, failure ratios, and shapes for
deploy.mode,deploy.labels,deploy.endpoint_mode,deploy.placementincludingmax_replicas_per_node,deploy.restart_policywithcondition: noneaccepted as the default no-restart behavior,deploy.update_config,deploy.rollback_config, deploy CPU and byte-value memory resource limits, and CPU, byte-value memory, generic resource, and device reservations including option map/list forms, empty deploy labels/orchestration maps plus exact empty restart/update/rollback policy defaults accepted as no-ops,deploy.replicas/scalefor local replicas including zero replicas that skip resource/container/image/artifact work when those values are consistent and host ports do not conflict, with activedeploy.labelsservice metadata reported as a strict rollout gap downcleanup for containers, networks, and optionally volumes
These Compose features are currently impossible to support exactly with Apple container 1.0.0 and are reported by plan; strict up treats them as errors:
- active container healthchecks,
depends_onconditions other thanservice_startedfor defined/active dependencies, anddepends_on.<service>.restart: truedependency restart propagation; validated disabled healthcheck forms (disable: trueortest: ["NONE"]) and empty/no-op healthcheck maps are accepted - remote/Git build contexts; Apple
container buildaccepts a local context directory - active restart policies such as
always,on-failure,unless-stopped, and activedeploy.restart_policyvalues; Applecontainerhas no restart-policy manager, so only Compose's explicit no/default restart policy is accepted - Swarm/orchestrator deployment settings such as placement, update/rollback config, endpoint mode, replicated-job/global modes, CPU/memory/generic resource reservations, active deploy PID limits, and device reservations
deploy.labelsservice metadata; Applecontainerhas container labels but no separate service object, and Compose deploy labels are not inherited by containers- empty environment variable, build-argument, and label keys from Compose list form; Apple container CLI flags require non-empty
key=valueentries, so apple-compose reports strict rollout gaps and omits those keys from generated commands - external secret/config stores and top-level secret/config resource labels
- service secret/config uid/gid ownership remapping; Apple
container --mountbind mounts do not expose container-visible ownership remapping - container annotations; Apple
container1.0.0 exposes labels but no annotation flag - privileged lifecycle hooks; Apple
container exechas no privileged mode - per-service network aliases including legacy link aliases, static IP assignment, service-level and attachment driver options other than
mtu, Dockernetwork_modevalues other thannone, gateway priority, interface names, and link-local IPs are strict rollout gaps because Applecontainer --networkonly exposes network name, MAC address, and MTU - service tmpfs mode/uid/gid options and long-form tmpfs size/mode are strict rollout gaps; Apple
container --tmpfsaccepts only a target path - Docker volume drivers other than local/default, image/npipe/cluster mount types, active volume subpath/nocopy strict rollout gaps, service-level volume labels on external volumes, active bind propagation and non-default bind recursive modes as strict rollout gaps, and SELinux relabeling as a documented no-op on non-SELinux Apple hosts
- disabled IPv4,
enable_ipv6without an explicit IPv6 subnet, custom IPAM drivers/options, Docker IPAM fields other than subnet, and extra same-family IPAM subnets beyond Applecontainer network create's one IPv4--subnetplus one IPv6--subnet-v6 - non-empty secret resource drivers/options/template drivers and config template drivers; Apple
containerhas no secret/config driver API, so apple-compose can only materialize file, inline-content, or environment-backed resources as bind mounts - privileged mode when enabled, device passthrough, namespace modes (
pid,ipc,cgroup,uts), active/customsecurity_opt, sysctls, active OOM score tuning, active PID limits, non-empty logging drivers/options, Windows-onlycredential_spec, andexternal_links - cgroup parent/mode settings, supplementary groups, block I/O controls, Linux CFS/realtime CPU controls, CPU pinning, memory reservations/swappiness/active swap limits, GPU passthrough, storage driver options, enabled Docker API socket delegation, and enabled OOM killer configuration
- any unrecognized non-extension service attribute is rejected during config parsing instead of being silently ignored
- any unrecognized non-extension nested service attribute in long-form ports, volumes, networks, env files, dependencies, lifecycle hooks, ulimits, or secret/config grants is rejected during config parsing or reported as a strict compatibility error instead of being silently ignored
- automatic/random host port allocation from target-only ports or non-fixed published port ranges, Compose's
network_mode: hostplus port mapping runtime error, long-formports[].modevalues other thanhost, and non-TCP/UDP published port protocols; Applecontainer --publishrequires an explicit host port and container port and only maps documented local TCP/UDP host publishing - empty
commandorentrypointoverrides ([]or''), because Applecontainer rundoes not expose a documented way to clear image CMD/ENTRYPOINT without replacing them - custom hostnames
- external-container
volumes_fromreferences; Applecontainerhas no Docker volumes-from flag, so apple-compose can only expand explicit volume mounts from referenced Compose services - multi-platform image builds unless
services.<name>.platformselects one listedbuild.platformsentry for the local rollout - BuildKit/build-container features not exposed by
container build, including additional contexts, build SSH, build shared-memory sizing, build ulimits, build secret uid/gid/mode ownership overrides, non-default build network modes, build extra hosts, build entitlements, and enabled privileged builds or configured provenance/SBOM attestations - any unrecognized non-extension build attribute is rejected during config parsing instead of being silently ignored
- Compose
develop,models, and non-emptyproviderdelegation; active provider services are reported as unsupported and skipped by generated Apple container commands because provider setup/teardown and dependent-service environment injection require Compose's external provider mechanism - any unrecognized non-extension top-level attribute is rejected during config parsing instead of being silently ignored
- any unrecognized non-extension top-level network, volume, config, secret, or IPAM attribute is rejected during config parsing instead of being silently ignored
Best-effort mode still prints the same findings before running commands.