diff --git a/modules/misc/news/2025/11/2025-11-04_16-44-03.nix b/modules/misc/news/2025/11/2025-11-04_16-44-03.nix
new file mode 100644
index 000000000000..fd169e993bf2
--- /dev/null
+++ b/modules/misc/news/2025/11/2025-11-04_16-44-03.nix
@@ -0,0 +1,34 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+{
+ time = "2025-11-04T15:44:03+00:00";
+ condition = true;
+ message = ''
+ The 'services.podman' module now supports Darwin (macOS) with declarative
+ machine management.
+
+ On Darwin, podman requires running containers inside a virtual machine.
+ The new configuration options allow you to declaratively manage podman
+ machines with automatic creation, configuration, and startup.
+
+ By default, a machine named 'podman-machine-default' will be created
+ automatically. You can customize machines or disable the default with:
+
+ services.podman.useDefaultMachine = false;
+ services.podman.machines = {
+ "my-machine" = {
+ cpus = 4;
+ memory = 8192;
+ diskSize = 100;
+ autoStart = true;
+ };
+ };
+
+ The module includes a launchd-based watchdog service that automatically
+ starts configured machines on login and keeps them running.
+ '';
+}
diff --git a/modules/services/podman/darwin.nix b/modules/services/podman/darwin.nix
new file mode 100644
index 000000000000..564430c8b3e0
--- /dev/null
+++ b/modules/services/podman/darwin.nix
@@ -0,0 +1,324 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+let
+ inherit (lib)
+ attrNames
+ concatStringsSep
+ filterAttrs
+ mapAttrs'
+ mkIf
+ mkOption
+ nameValuePair
+ optionalString
+ types
+ ;
+
+ cfg = config.services.podman;
+
+ machineDefinitionType = types.submodule {
+ options = {
+ cpus = mkOption {
+ type = types.ints.positive;
+ default = 4;
+ example = 2;
+ description = "Number of CPUs to allocate to the machine.";
+ };
+
+ diskSize = mkOption {
+ type = types.ints.positive;
+ default = 100;
+ example = 200;
+ description = "Disk size in GB for the machine.";
+ };
+
+ image = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ description = "Bootable image to use for the machine. If null, uses podman's default.";
+ };
+
+ memory = mkOption {
+ type = types.ints.positive;
+ default = 2048;
+ example = 8192;
+ description = "Memory in MB to allocate to the machine.";
+ };
+
+ rootful = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether to run the machine in rootful mode.
+ Rootful mode runs containers as root inside the VM.
+ '';
+ };
+
+ swap = mkOption {
+ type = types.nullOr types.ints.positive;
+ default = null;
+ example = 2048;
+ description = "Swap size in MB for the machine.";
+ };
+
+ timezone = mkOption {
+ type = types.str;
+ default = "local";
+ example = "UTC";
+ description = "Timezone to set in the machine.";
+ };
+
+ userModeNetworking = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether to use user-mode networking, routing traffic through a host user-space process.
+ This may be required for certain network configurations.
+ '';
+ };
+
+ username = mkOption {
+ type = types.str;
+ default = "core";
+ description = "Username used in the machine image.";
+ };
+
+ volumes = mkOption {
+ type = types.listOf types.str;
+ default = [ ];
+ example = [
+ "/Users:/Users"
+ "/private:/private"
+ "/var/folders:/var/folders"
+ ];
+ description = ''
+ Volumes to mount in the machine, specified as source:target pairs.
+ If empty, podman will use its default volume mounts.
+ '';
+ };
+
+ autoStart = mkOption {
+ type = types.bool;
+ default = true;
+ description = "Whether to automatically start this machine on login.";
+ };
+
+ watchdogInterval = mkOption {
+ type = types.ints.positive;
+ default = 30;
+ example = 60;
+ description = "Interval in seconds to check if the machine is running.";
+ };
+ };
+ };
+
+ mkWatchdogScript =
+ name: machine:
+ pkgs.writeShellScript "podman-machine-watchdog-${name}" ''
+ set -euo pipefail
+
+ MACHINE_NAME="${name}"
+ INTERVAL=${toString machine.watchdogInterval}
+ PODMAN="${lib.getExe cfg.package}"
+
+ log() {
+ echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >&2
+ }
+
+ check_and_start() {
+ local state
+ state=$($PODMAN machine inspect "$MACHINE_NAME" --format '{{.State}}' 2>/dev/null || echo "unknown")
+
+ case "$state" in
+ running)
+ return 0
+ ;;
+ stopped|unknown)
+ log "Machine '$MACHINE_NAME' is starting..."
+ if $PODMAN machine start "$MACHINE_NAME" 2>&1 | while IFS= read -r line; do log "$line"; done; then
+ log "Machine '$MACHINE_NAME' started successfully"
+ return 0
+ else
+ log "Failed to start machine '$MACHINE_NAME'"
+ return 1
+ fi
+ ;;
+ *)
+ log "Machine '$MACHINE_NAME' is $state"
+ return 1
+ ;;
+ esac
+ }
+
+ log "Starting watchdog for machine '$MACHINE_NAME' (check interval: ''${INTERVAL}s)"
+
+ while true; do
+ check_and_start || true
+ sleep "$INTERVAL"
+ done
+ '';
+in
+{
+ options.services.podman = {
+ useDefaultMachine = mkOption {
+ type = types.bool;
+ default = pkgs.stdenv.hostPlatform.isDarwin;
+ description = ''
+ Whether to create and use the default podman machine.
+
+ The default machine will be named `podman-machine-default` and configured with:
+ - 4 CPUs
+ - 2048 MB RAM
+ - 100 GB disk
+ - Rootless mode
+ - Auto-start enabled
+ - No swap
+ - Local timezone
+ - Standard networking (not user-mode)
+ - Default username (core)
+ - Default volume mounts
+ '';
+ };
+
+ machines = mkOption {
+ type = types.attrsOf machineDefinitionType;
+ default = { };
+ description = "Declarative podman machine configurations.";
+ example = lib.literalExpression ''
+ {
+ "dev-machine" = {
+ cpus = 4;
+ diskSize = 100;
+ memory = 8192;
+ rootful = false;
+ swap = 2048;
+ timezone = "UTC";
+ userModeNetworking = false;
+ volumes = [
+ "/Users:/Users"
+ "/private:/private"
+ ];
+ autoStart = true;
+ watchdogInterval = 30;
+ };
+ "testing" = {
+ cpus = 2;
+ diskSize = 50;
+ image = "ghcr.io/your-org/custom-image:latest";
+ memory = 4096;
+ rootful = false;
+ username = "podman";
+ autoStart = false;
+ };
+ }
+ '';
+ };
+ };
+
+ config =
+ let
+ podmanCmd = lib.getExe cfg.package;
+ allMachines =
+ cfg.machines
+ // (
+ if cfg.useDefaultMachine then
+ {
+ "podman-machine-default" = {
+ cpus = 4;
+ diskSize = 100;
+ image = null;
+ memory = 2048;
+ rootful = false;
+ swap = null;
+ timezone = "local";
+ userModeNetworking = false;
+ username = "core";
+ volumes = [ ];
+ autoStart = true;
+ watchdogInterval = 30;
+ };
+ }
+ else
+ { }
+ );
+ autoStartMachines = filterAttrs (_name: machine: machine.autoStart) allMachines;
+ in
+ mkIf (cfg.enable && pkgs.stdenv.hostPlatform.isDarwin) {
+ assertions = [
+ {
+ assertion = pkgs.stdenv.hostPlatform.isDarwin;
+ message = ''
+ Podman Darwin-specific options are configured, but you are not on a Darwin (macOS) system.
+ The following options are only available on macOS:
+ - services.podman.machines
+ - services.podman.useDefaultMachine
+
+ Please remove these Darwin-specific configurations from your home-manager configuration.
+ '';
+ }
+ ];
+
+ home.activation.podmanMachines =
+ let
+ mkMachineInitScript =
+ name: machine:
+ let
+ # Automatically mount host's container config into the VM
+ configVolume = "$HOME/.config/containers:/home/${machine.username}/.config/containers";
+ allVolumes = [ configVolume ] ++ machine.volumes;
+ in
+ ''
+ if ! ${podmanCmd} machine list --format '{{.Name}}' 2>/dev/null | sed 's/\*$//' | grep -q '^${name}$'; then
+ echo "Creating podman machine: ${name}"
+ ${podmanCmd} machine init ${name} \
+ --cpus ${toString machine.cpus} \
+ --disk-size ${toString machine.diskSize} \
+ ${optionalString (machine.image != null) "--image ${machine.image}"} \
+ --memory ${toString machine.memory} \
+ ${optionalString machine.rootful "--rootful"} \
+ ${optionalString (machine.swap != null) "--swap ${toString machine.swap}"} \
+ --timezone "${machine.timezone}" \
+ ${optionalString machine.userModeNetworking "--user-mode-networking"} \
+ --username "${machine.username}" \
+ ${concatStringsSep " " (map (v: "--volume \"${v}\"") allVolumes)}
+ fi
+ '';
+
+ in
+ lib.hm.dag.entryAfter [ "writeBoundary" ] ''
+ PATH="${cfg.package}/bin:$PATH"
+
+ ${concatStringsSep "\n" (lib.mapAttrsToList mkMachineInitScript allMachines)}
+
+ MANAGED_MACHINES="${concatStringsSep " " (attrNames allMachines)}"
+ EXISTING_MACHINES=$(${podmanCmd} machine list --format '{{.Name}}' 2>/dev/null | sed 's/\*$//' || echo "")
+
+ for machine in $EXISTING_MACHINES; do
+ if [[ ! " $MANAGED_MACHINES " =~ " $machine " ]]; then
+ echo "Removing unmanaged podman machine: $machine"
+ ${podmanCmd} machine stop "$machine" 2>/dev/null || true
+ ${podmanCmd} machine rm -f "$machine"
+ fi
+ done
+ '';
+
+ launchd.agents = mapAttrs' (
+ name: machine:
+ nameValuePair "podman-machine-${name}" {
+ enable = true;
+ config = {
+ ProgramArguments = [ "${mkWatchdogScript name machine}" ];
+ KeepAlive = {
+ Crashed = true;
+ SuccessfulExit = false;
+ };
+ ProcessType = "Background";
+ RunAtLoad = true;
+ };
+ }
+ ) autoStartMachines;
+ };
+}
diff --git a/modules/services/podman-linux/default.nix b/modules/services/podman/default.nix
similarity index 85%
rename from modules/services/podman-linux/default.nix
rename to modules/services/podman/default.nix
index ecabeec99bed..b7f2a67ca0ec 100644
--- a/modules/services/podman-linux/default.nix
+++ b/modules/services/podman/default.nix
@@ -1,7 +1,7 @@
{
config,
- pkgs,
lib,
+ pkgs,
...
}:
let
@@ -12,21 +12,19 @@ in
meta.maintainers = [
lib.hm.maintainers.bamhm182
lib.maintainers.n-hass
+ lib.maintainers.delafthi
];
imports = [
- ./builds.nix
- ./containers.nix
- ./images.nix
- ./install-quadlet.nix
- ./networks.nix
- ./services.nix
- ./volumes.nix
+ ./linux/default.nix
+ ./darwin.nix
];
options.services.podman = {
enable = lib.mkEnableOption "Podman, a daemonless container engine";
+ package = lib.mkPackageOption pkgs "podman" { };
+
settings = {
containers = lib.mkOption {
type = toml.type;
@@ -94,14 +92,14 @@ in
};
config = lib.mkIf cfg.enable {
- assertions = [ (lib.hm.assertions.assertPlatform "podman" pkgs lib.platforms.linux) ];
-
home.packages = [ cfg.package ];
- services.podman.settings.storage = {
- storage.driver = lib.mkDefault "overlay";
- };
+ services.podman.settings.storage.storage.driver = lib.mkDefault "overlay";
+ # Configuration files are written to `$XDG_CONFIG_HOME/.config/containers`
+ # On Linux: podman reads them directly from this location
+ # On Darwin: these files are automatically mounted into the podman machine VM
+ # (see darwin.nix for the volume mount configuration)
xdg.configFile = {
"containers/policy.json".source =
if cfg.settings.policy != { } then
diff --git a/modules/services/podman-linux/activation.nix b/modules/services/podman/linux/activation.nix
similarity index 100%
rename from modules/services/podman-linux/activation.nix
rename to modules/services/podman/linux/activation.nix
diff --git a/modules/services/podman-linux/builds.nix b/modules/services/podman/linux/builds.nix
similarity index 98%
rename from modules/services/podman-linux/builds.nix
rename to modules/services/podman/linux/builds.nix
index 087f7b68e68f..be5d3e87c793 100644
--- a/modules/services/podman-linux/builds.nix
+++ b/modules/services/podman/linux/builds.nix
@@ -182,7 +182,7 @@ in
let
buildQuadlets = lib.mapAttrsToList toQuadletInternal cfg.builds;
in
- lib.mkIf cfg.enable {
+ lib.mkIf (cfg.enable && pkgs.stdenv.hostPlatform.isLinux) {
services.podman.internal.quadletDefinitions = buildQuadlets;
assertions = lib.flatten (map (build: build.assertions) buildQuadlets);
diff --git a/modules/services/podman-linux/containers.nix b/modules/services/podman/linux/containers.nix
similarity index 99%
rename from modules/services/podman-linux/containers.nix
rename to modules/services/podman/linux/containers.nix
index 384190f33ffe..329bb939a11d 100644
--- a/modules/services/podman-linux/containers.nix
+++ b/modules/services/podman/linux/containers.nix
@@ -401,7 +401,7 @@ in
let
containerQuadlets = lib.mapAttrsToList toQuadletInternal cfg.containers;
in
- lib.mkIf cfg.enable {
+ lib.mkIf (cfg.enable && pkgs.stdenv.hostPlatform.isLinux) {
services.podman.internal.quadletDefinitions = containerQuadlets;
assertions = lib.flatten (map (container: container.assertions) containerQuadlets);
diff --git a/modules/services/podman/linux/default.nix b/modules/services/podman/linux/default.nix
new file mode 100644
index 000000000000..fcbd59bdf8c6
--- /dev/null
+++ b/modules/services/podman/linux/default.nix
@@ -0,0 +1,12 @@
+{
+ imports = [
+ ./options.nix
+ ./builds.nix
+ ./containers.nix
+ ./images.nix
+ ./install-quadlet.nix
+ ./networks.nix
+ ./services.nix
+ ./volumes.nix
+ ];
+}
diff --git a/modules/services/podman-linux/images.nix b/modules/services/podman/linux/images.nix
similarity index 98%
rename from modules/services/podman-linux/images.nix
rename to modules/services/podman/linux/images.nix
index 275896183051..4493feeafac6 100644
--- a/modules/services/podman-linux/images.nix
+++ b/modules/services/podman/linux/images.nix
@@ -165,7 +165,7 @@ in
let
imageQuadlets = lib.mapAttrsToList toQuadletInternal cfg.images;
in
- lib.mkIf cfg.enable {
+ lib.mkIf (cfg.enable && pkgs.stdenv.hostPlatform.isLinux) {
services.podman.internal.quadletDefinitions = imageQuadlets;
assertions = lib.flatten (map (image: image.assertions) imageQuadlets);
};
diff --git a/modules/services/podman-linux/install-quadlet.nix b/modules/services/podman/linux/install-quadlet.nix
similarity index 98%
rename from modules/services/podman-linux/install-quadlet.nix
rename to modules/services/podman/linux/install-quadlet.nix
index a5326121f87b..5e7ade3de06b 100644
--- a/modules/services/podman-linux/install-quadlet.nix
+++ b/modules/services/podman/linux/install-quadlet.nix
@@ -99,7 +99,7 @@ in
{
imports = [ ./options.nix ];
- config = lib.mkIf cfg.enable {
+ config = lib.mkIf (cfg.enable && pkgs.stdenv.hostPlatform.isLinux) {
home.file = generateSystemdFileLinks allUnitFiles;
# if the length of builtQuadlets is 0, then we don't need register the activation script
diff --git a/modules/services/podman-linux/networks.nix b/modules/services/podman/linux/networks.nix
similarity index 98%
rename from modules/services/podman-linux/networks.nix
rename to modules/services/podman/linux/networks.nix
index f495553de921..f142d45086f2 100644
--- a/modules/services/podman-linux/networks.nix
+++ b/modules/services/podman/linux/networks.nix
@@ -180,7 +180,7 @@ in
let
networkQuadlets = lib.mapAttrsToList toQuadletInternal cfg.networks;
in
- lib.mkIf cfg.enable {
+ lib.mkIf (cfg.enable && pkgs.stdenv.hostPlatform.isLinux) {
services.podman.internal.quadletDefinitions = networkQuadlets;
assertions = lib.flatten (map (network: network.assertions) networkQuadlets);
diff --git a/modules/services/podman-linux/options.nix b/modules/services/podman/linux/options.nix
similarity index 60%
rename from modules/services/podman-linux/options.nix
rename to modules/services/podman/linux/options.nix
index 35bc2c95d2dd..b25233c29bfe 100644
--- a/modules/services/podman-linux/options.nix
+++ b/modules/services/podman/linux/options.nix
@@ -1,6 +1,13 @@
-{ lib, pkgs, ... }:
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
let
+ cfg = config.services.podman;
+
# Define the systemd service type
quadletInternalType = lib.types.submodule {
options = {
@@ -38,6 +45,15 @@ let
};
};
};
+
+ # Check if any Linux-specific options are configured
+ hasLinuxConfig =
+ cfg.containers != { }
+ || cfg.builds != { }
+ || cfg.images != { }
+ || cfg.networks != { }
+ || cfg.volumes != { }
+ || cfg.enableTypeChecks;
in
{
options.services.podman = {
@@ -56,8 +72,27 @@ in
};
};
- package = lib.mkPackageOption pkgs "podman" { };
-
enableTypeChecks = lib.mkEnableOption "type checks for podman quadlets";
};
+
+ config = lib.mkIf (cfg.enable && hasLinuxConfig) {
+ assertions = [
+ {
+ assertion = pkgs.stdenv.hostPlatform.isLinux;
+ message = ''
+ Podman Linux-specific options (quadlets) are configured, but you are not on a Linux system.
+ The following options are only available on Linux:
+ - services.podman.containers
+ - services.podman.builds
+ - services.podman.images
+ - services.podman.networks
+ - services.podman.volumes
+ - services.podman.enableTypeChecks
+ - services.podman.autoUpdate
+
+ Please remove these Linux-specific configurations from your home-manager configuration.
+ '';
+ }
+ ];
+ };
}
diff --git a/modules/services/podman-linux/podman-lib.nix b/modules/services/podman/linux/podman-lib.nix
similarity index 100%
rename from modules/services/podman-linux/podman-lib.nix
rename to modules/services/podman/linux/podman-lib.nix
diff --git a/modules/services/podman-linux/services.nix b/modules/services/podman/linux/services.nix
similarity index 97%
rename from modules/services/podman-linux/services.nix
rename to modules/services/podman/linux/services.nix
index 1ffb001dd4d5..4eb36912d8a9 100644
--- a/modules/services/podman-linux/services.nix
+++ b/modules/services/podman/linux/services.nix
@@ -27,7 +27,7 @@ in
};
};
- config = lib.mkIf cfg.enable (
+ config = lib.mkIf (cfg.enable && pkgs.stdenv.hostPlatform.isLinux) (
lib.mkMerge [
(lib.mkIf cfg.autoUpdate.enable {
systemd.user.services."podman-auto-update" = {
diff --git a/modules/services/podman-linux/volumes.nix b/modules/services/podman/linux/volumes.nix
similarity index 98%
rename from modules/services/podman-linux/volumes.nix
rename to modules/services/podman/linux/volumes.nix
index 91cfd6bc204a..86dc710369ee 100644
--- a/modules/services/podman-linux/volumes.nix
+++ b/modules/services/podman/linux/volumes.nix
@@ -192,7 +192,7 @@ in
let
volumeQuadlets = lib.mapAttrsToList toQuadletInternal cfg.volumes;
in
- lib.mkIf cfg.enable {
+ lib.mkIf (cfg.enable && pkgs.stdenv.hostPlatform.isLinux) {
services.podman.internal.quadletDefinitions = volumeQuadlets;
assertions = lib.flatten (map (volume: volume.assertions) volumeQuadlets);
diff --git a/tests/modules/services/podman-linux/configuration-containers-expected.conf b/tests/modules/services/podman/configuration-containers-expected.conf
similarity index 100%
rename from tests/modules/services/podman-linux/configuration-containers-expected.conf
rename to tests/modules/services/podman/configuration-containers-expected.conf
diff --git a/tests/modules/services/podman-linux/configuration-mounts-expected.conf b/tests/modules/services/podman/configuration-mounts-expected.conf
similarity index 100%
rename from tests/modules/services/podman-linux/configuration-mounts-expected.conf
rename to tests/modules/services/podman/configuration-mounts-expected.conf
diff --git a/tests/modules/services/podman-linux/configuration-policy-expected.json b/tests/modules/services/podman/configuration-policy-expected.json
similarity index 100%
rename from tests/modules/services/podman-linux/configuration-policy-expected.json
rename to tests/modules/services/podman/configuration-policy-expected.json
diff --git a/tests/modules/services/podman-linux/configuration-registries-expected.conf b/tests/modules/services/podman/configuration-registries-expected.conf
similarity index 100%
rename from tests/modules/services/podman-linux/configuration-registries-expected.conf
rename to tests/modules/services/podman/configuration-registries-expected.conf
diff --git a/tests/modules/services/podman-linux/configuration-storage-expected.conf b/tests/modules/services/podman/configuration-storage-expected.conf
similarity index 100%
rename from tests/modules/services/podman-linux/configuration-storage-expected.conf
rename to tests/modules/services/podman/configuration-storage-expected.conf
diff --git a/tests/modules/services/podman-linux/configuration.nix b/tests/modules/services/podman/configuration.nix
similarity index 82%
rename from tests/modules/services/podman-linux/configuration.nix
rename to tests/modules/services/podman/configuration.nix
index cbbac2be3f9f..001d032ff9c2 100644
--- a/tests/modules/services/podman-linux/configuration.nix
+++ b/tests/modules/services/podman/configuration.nix
@@ -1,3 +1,4 @@
+{ pkgs, ... }:
{
services.podman = {
enable = true;
@@ -46,6 +47,7 @@
storageFile=$configPath/storage.conf
mountsFile=$configPath/mounts.conf
+ # Check that config files are generated on both platforms
assertFileExists $containersFile
assertFileExists $policyFile
assertFileExists $registriesFile
@@ -63,5 +65,16 @@
assertFileContent $registriesFile ${./configuration-registries-expected.conf}
assertFileContent $storageFile ${./configuration-storage-expected.conf}
assertFileContent $mountsFile ${./configuration-mounts-expected.conf}
+
+ ${
+ if pkgs.stdenv.hostPlatform.isDarwin then
+ ''
+ # Darwin-specific: verify that config directory is automatically mounted into podman machines
+ assertFileExists activate
+ assertFileRegex activate '\$HOME/\.config/containers:/home/core/\.config/containers'
+ ''
+ else
+ ""
+ }
'';
}
diff --git a/tests/modules/services/podman/darwin/basic-expected-agent.plist b/tests/modules/services/podman/darwin/basic-expected-agent.plist
new file mode 100644
index 000000000000..146a182749c0
--- /dev/null
+++ b/tests/modules/services/podman/darwin/basic-expected-agent.plist
@@ -0,0 +1,23 @@
+
+
+
+
+ KeepAlive
+
+ Crashed
+
+ SuccessfulExit
+
+
+ Label
+ org.nix-community.home.podman-machine-podman-machine-default
+ ProcessType
+ Background
+ ProgramArguments
+
+ /nix/store/00000000000000000000000000000000-podman-machine-watchdog-podman-machine-default
+
+ RunAtLoad
+
+
+
\ No newline at end of file
diff --git a/tests/modules/services/podman/darwin/basic.nix b/tests/modules/services/podman/darwin/basic.nix
new file mode 100644
index 000000000000..3b16dee51311
--- /dev/null
+++ b/tests/modules/services/podman/darwin/basic.nix
@@ -0,0 +1,29 @@
+{
+ services.podman = {
+ enable = true;
+ useDefaultMachine = true;
+ };
+
+ nmt.script = ''
+ serviceDir=LaunchAgents
+
+ # Check that the default machine watchdog launchd service exists
+ agentFile=$serviceDir/org.nix-community.home.podman-machine-podman-machine-default.plist
+ assertFileExists $agentFile
+
+ # Normalize and verify agent file content
+ agentFileNormalized=$(normalizeStorePaths "$agentFile")
+ assertFileContent "$agentFileNormalized" ${./basic-expected-agent.plist}
+
+ # Verify home activation creates the default machine
+ assertFileExists activate
+ assertFileRegex activate 'podman-machine-default'
+ assertFileRegex activate 'podman machine init podman-machine-default'
+ assertFileRegex activate '[-][-]cpus 4'
+ assertFileRegex activate '[-][-]memory 2048'
+ assertFileRegex activate '[-][-]disk-size 100'
+
+ # Verify that config directory is automatically mounted into the machine
+ assertFileRegex activate '\$HOME/\.config/containers:/home/core/\.config/containers'
+ '';
+}
diff --git a/tests/modules/services/podman/darwin/custom-machines-dev-expected-agent.plist b/tests/modules/services/podman/darwin/custom-machines-dev-expected-agent.plist
new file mode 100644
index 000000000000..056846e085b5
--- /dev/null
+++ b/tests/modules/services/podman/darwin/custom-machines-dev-expected-agent.plist
@@ -0,0 +1,23 @@
+
+
+
+
+ KeepAlive
+
+ Crashed
+
+ SuccessfulExit
+
+
+ Label
+ org.nix-community.home.podman-machine-dev-machine
+ ProcessType
+ Background
+ ProgramArguments
+
+ /nix/store/00000000000000000000000000000000-podman-machine-watchdog-dev-machine
+
+ RunAtLoad
+
+
+
\ No newline at end of file
diff --git a/tests/modules/services/podman/darwin/custom-machines.nix b/tests/modules/services/podman/darwin/custom-machines.nix
new file mode 100644
index 000000000000..9756c87f5555
--- /dev/null
+++ b/tests/modules/services/podman/darwin/custom-machines.nix
@@ -0,0 +1,64 @@
+{
+ services.podman = {
+ enable = true;
+ useDefaultMachine = false;
+ machines = {
+ "dev-machine" = {
+ cpus = 8;
+ memory = 8192;
+ diskSize = 200;
+ rootful = true;
+ autoStart = true;
+ watchdogInterval = 60;
+ };
+ "test-machine" = {
+ cpus = 2;
+ memory = 4096;
+ diskSize = 50;
+ rootful = false;
+ autoStart = false;
+ watchdogInterval = 30;
+ };
+ };
+ };
+
+ nmt.script = ''
+ serviceDir=LaunchAgents
+
+ # Check that dev-machine watchdog exists (has autoStart = true)
+ devAgentFile=$serviceDir/org.nix-community.home.podman-machine-dev-machine.plist
+ assertFileExists $devAgentFile
+
+ # Normalize and verify dev-machine agent file content
+ devAgentFileNormalized=$(normalizeStorePaths "$devAgentFile")
+ assertFileContent "$devAgentFileNormalized" ${./custom-machines-dev-expected-agent.plist}
+
+ # Check that test-machine watchdog does NOT exist (has autoStart = false)
+ testAgentFile=$serviceDir/org.nix-community.home.podman-machine-test-machine.plist
+ assertPathNotExists $testAgentFile
+
+ # Verify home activation creates both machines
+ assertFileExists activate
+
+ # Check dev-machine initialization with custom parameters
+ assertFileRegex activate 'dev-machine'
+ assertFileRegex activate 'podman machine init dev-machine'
+ assertFileRegex activate '[-][-]cpus 8'
+ assertFileRegex activate '[-][-]memory 8192'
+ assertFileRegex activate '[-][-]disk-size 200'
+ assertFileRegex activate '[-][-]rootful'
+
+ # Check test-machine initialization
+ assertFileRegex activate 'test-machine'
+ assertFileRegex activate 'podman machine init test-machine'
+ assertFileRegex activate '[-][-]cpus 2'
+ assertFileRegex activate '[-][-]memory 4096'
+ assertFileRegex activate '[-][-]disk-size 50'
+
+ # Verify default machine is NOT created
+ assertFileNotRegex activate 'podman-machine-default'
+
+ # Verify that config directory is automatically mounted into all machines
+ assertFileRegex activate '\$HOME/\.config/containers:/home/core/\.config/containers'
+ '';
+}
diff --git a/tests/modules/services/podman/darwin/default.nix b/tests/modules/services/podman/darwin/default.nix
new file mode 100644
index 000000000000..7a30377e0414
--- /dev/null
+++ b/tests/modules/services/podman/darwin/default.nix
@@ -0,0 +1,5 @@
+{
+ podman-darwin-basic = ./basic.nix;
+ podman-darwin-custom-machines = ./custom-machines.nix;
+ podman-darwin-no-default-machine = ./no-default-machine.nix;
+}
diff --git a/tests/modules/services/podman/darwin/no-default-machine.nix b/tests/modules/services/podman/darwin/no-default-machine.nix
new file mode 100644
index 000000000000..eba64885fdd8
--- /dev/null
+++ b/tests/modules/services/podman/darwin/no-default-machine.nix
@@ -0,0 +1,20 @@
+{
+ services.podman = {
+ enable = true;
+ useDefaultMachine = false;
+ machines = { };
+ };
+
+ nmt.script = ''
+ serviceDir=LaunchAgents
+
+ # Check that the default machine watchdog launchd service does not exists
+ agentFile=$serviceDir/org.nix-community.home.podman-machine-podman-machine-default.plist
+ assertPathNotExists $agentFile
+
+ # Verify home activation script doesn't create default machine
+ activationScript=activate
+ assertFileExists $activationScript
+ assertFileNotRegex $activationScript 'podman-machine-default'
+ '';
+}
diff --git a/tests/modules/services/podman/default.nix b/tests/modules/services/podman/default.nix
new file mode 100644
index 000000000000..c5d8550e92aa
--- /dev/null
+++ b/tests/modules/services/podman/default.nix
@@ -0,0 +1,6 @@
+{ lib, pkgs, ... }:
+{
+ podman-configuration = ./configuration.nix;
+}
+// (lib.optionalAttrs pkgs.stdenv.hostPlatform.isDarwin (import ./darwin/default.nix))
+// (lib.optionalAttrs pkgs.stdenv.hostPlatform.isLinux (import ./linux/default.nix))
diff --git a/tests/modules/services/podman-linux/build-expected.service b/tests/modules/services/podman/linux/build-expected.service
similarity index 100%
rename from tests/modules/services/podman-linux/build-expected.service
rename to tests/modules/services/podman/linux/build-expected.service
diff --git a/tests/modules/services/podman-linux/build.nix b/tests/modules/services/podman/linux/build.nix
similarity index 100%
rename from tests/modules/services/podman-linux/build.nix
rename to tests/modules/services/podman/linux/build.nix
diff --git a/tests/modules/services/podman-linux/container-expected.service b/tests/modules/services/podman/linux/container-expected.service
similarity index 100%
rename from tests/modules/services/podman-linux/container-expected.service
rename to tests/modules/services/podman/linux/container-expected.service
diff --git a/tests/modules/services/podman-linux/container.nix b/tests/modules/services/podman/linux/container.nix
similarity index 100%
rename from tests/modules/services/podman-linux/container.nix
rename to tests/modules/services/podman/linux/container.nix
diff --git a/tests/modules/services/podman-linux/default.nix b/tests/modules/services/podman/linux/default.nix
similarity index 67%
rename from tests/modules/services/podman-linux/default.nix
rename to tests/modules/services/podman/linux/default.nix
index c4d832d4dbdf..d5c9b4948677 100644
--- a/tests/modules/services/podman-linux/default.nix
+++ b/tests/modules/services/podman/linux/default.nix
@@ -1,7 +1,4 @@
-{ lib, pkgs, ... }:
-
-lib.optionalAttrs pkgs.stdenv.hostPlatform.isLinux {
- podman-configuration = ./configuration.nix;
+{
podman-container = ./container.nix;
podman-build = ./build.nix;
podman-image = ./image.nix;
diff --git a/tests/modules/services/podman-linux/image-expected.service b/tests/modules/services/podman/linux/image-expected.service
similarity index 100%
rename from tests/modules/services/podman-linux/image-expected.service
rename to tests/modules/services/podman/linux/image-expected.service
diff --git a/tests/modules/services/podman-linux/image.nix b/tests/modules/services/podman/linux/image.nix
similarity index 100%
rename from tests/modules/services/podman-linux/image.nix
rename to tests/modules/services/podman/linux/image.nix
diff --git a/tests/modules/services/podman-linux/integration-build-expected.service b/tests/modules/services/podman/linux/integration-build-expected.service
similarity index 100%
rename from tests/modules/services/podman-linux/integration-build-expected.service
rename to tests/modules/services/podman/linux/integration-build-expected.service
diff --git a/tests/modules/services/podman-linux/integration-container-bld-expected.service b/tests/modules/services/podman/linux/integration-container-bld-expected.service
similarity index 100%
rename from tests/modules/services/podman-linux/integration-container-bld-expected.service
rename to tests/modules/services/podman/linux/integration-container-bld-expected.service
diff --git a/tests/modules/services/podman-linux/integration-container-expected.service b/tests/modules/services/podman/linux/integration-container-expected.service
similarity index 100%
rename from tests/modules/services/podman-linux/integration-container-expected.service
rename to tests/modules/services/podman/linux/integration-container-expected.service
diff --git a/tests/modules/services/podman-linux/integration-image-expected.service b/tests/modules/services/podman/linux/integration-image-expected.service
similarity index 100%
rename from tests/modules/services/podman-linux/integration-image-expected.service
rename to tests/modules/services/podman/linux/integration-image-expected.service
diff --git a/tests/modules/services/podman-linux/integration-network-expected.service b/tests/modules/services/podman/linux/integration-network-expected.service
similarity index 100%
rename from tests/modules/services/podman-linux/integration-network-expected.service
rename to tests/modules/services/podman/linux/integration-network-expected.service
diff --git a/tests/modules/services/podman-linux/integration-volume-expected.service b/tests/modules/services/podman/linux/integration-volume-expected.service
similarity index 100%
rename from tests/modules/services/podman-linux/integration-volume-expected.service
rename to tests/modules/services/podman/linux/integration-volume-expected.service
diff --git a/tests/modules/services/podman-linux/integration.nix b/tests/modules/services/podman/linux/integration.nix
similarity index 100%
rename from tests/modules/services/podman-linux/integration.nix
rename to tests/modules/services/podman/linux/integration.nix
diff --git a/tests/modules/services/podman-linux/manifest.nix b/tests/modules/services/podman/linux/manifest.nix
similarity index 100%
rename from tests/modules/services/podman-linux/manifest.nix
rename to tests/modules/services/podman/linux/manifest.nix
diff --git a/tests/modules/services/podman-linux/network-expected.service b/tests/modules/services/podman/linux/network-expected.service
similarity index 100%
rename from tests/modules/services/podman-linux/network-expected.service
rename to tests/modules/services/podman/linux/network-expected.service
diff --git a/tests/modules/services/podman-linux/network.nix b/tests/modules/services/podman/linux/network.nix
similarity index 100%
rename from tests/modules/services/podman-linux/network.nix
rename to tests/modules/services/podman/linux/network.nix
diff --git a/tests/modules/services/podman-linux/podman-stubs.nix b/tests/modules/services/podman/linux/podman-stubs.nix
similarity index 100%
rename from tests/modules/services/podman-linux/podman-stubs.nix
rename to tests/modules/services/podman/linux/podman-stubs.nix
diff --git a/tests/modules/services/podman-linux/volume-expected.service b/tests/modules/services/podman/linux/volume-expected.service
similarity index 100%
rename from tests/modules/services/podman-linux/volume-expected.service
rename to tests/modules/services/podman/linux/volume-expected.service
diff --git a/tests/modules/services/podman-linux/volume.nix b/tests/modules/services/podman/linux/volume.nix
similarity index 100%
rename from tests/modules/services/podman-linux/volume.nix
rename to tests/modules/services/podman/linux/volume.nix