Repository: lima-vm/lima

Issue:
`limactl shell --preserve-env` should have tests and docs
> Needs an integration test and the document to clarify the block list

_Originally posted by @AkihiroSuda in https://github.com/lima-vm/lima/pull/3830#discussion_r2281264252_
            

Discussion:

Solution patch:
diff --git a/cmd/limactl/clone.go b/cmd/limactl/clone.go
index 04060082..87a7a980 100644
--- a/cmd/limactl/clone.go
+++ b/cmd/limactl/clone.go
@@ -12,11 +12,12 @@ import (
 	"github.com/spf13/cobra"
 
 	"github.com/lima-vm/lima/v2/cmd/limactl/editflags"
+	"github.com/lima-vm/lima/v2/pkg/driverutil"
 	"github.com/lima-vm/lima/v2/pkg/instance"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 	"github.com/lima-vm/lima/v2/pkg/limayaml"
 	networks "github.com/lima-vm/lima/v2/pkg/networks/reconcile"
 	"github.com/lima-vm/lima/v2/pkg/store"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
 	"github.com/lima-vm/lima/v2/pkg/yqutil"
 )
 
@@ -79,6 +80,9 @@ func cloneAction(cmd *cobra.Command, args []string) error {
 		if err != nil {
 			return err
 		}
+		if err := driverutil.ResolveVMType(y, filePath); err != nil {
+			return fmt.Errorf("failed to accept config for %q: %w", filePath, err)
+		}
 		if err := limayaml.Validate(y, true); err != nil {
 			return saveRejectedYAML(yBytes, err)
 		}
diff --git a/cmd/limactl/copy.go b/cmd/limactl/copy.go
index 6d84353b..9d7a0055 100644
--- a/cmd/limactl/copy.go
+++ b/cmd/limactl/copy.go
@@ -17,6 +17,7 @@ import (
 	"github.com/spf13/cobra"
 
 	"github.com/lima-vm/lima/v2/pkg/ioutilx"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 	"github.com/lima-vm/lima/v2/pkg/sshutil"
 	"github.com/lima-vm/lima/v2/pkg/store"
 )
@@ -63,7 +64,7 @@ func copyAction(cmd *cobra.Command, args []string) error {
 	if err != nil {
 		return err
 	}
-	instances := make(map[string]*store.Instance)
+	instances := make(map[string]*limatype.Instance)
 	scpFlags := []string{}
 	scpArgs := []string{}
 	debug, err := cmd.Flags().GetBool("debug")
@@ -114,7 +115,7 @@ func copyAction(cmd *cobra.Command, args []string) error {
 				}
 				return err
 			}
-			if inst.Status == store.StatusStopped {
+			if inst.Status == limatype.StatusStopped {
 				return fmt.Errorf("instance %q is stopped, run `limactl start %s` to start the instance", instName, instName)
 			}
 			if legacySSH {
diff --git a/cmd/limactl/disk.go b/cmd/limactl/disk.go
index 1f8d8e5b..acc78ce2 100644
--- a/cmd/limactl/disk.go
+++ b/cmd/limactl/disk.go
@@ -19,8 +19,9 @@ import (
 	"github.com/spf13/cobra"
 
 	"github.com/lima-vm/lima/v2/pkg/imgutil/proxyimgutil"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 	"github.com/lima-vm/lima/v2/pkg/store"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
 )
 
 func newDiskCommand() *cobra.Command {
@@ -243,7 +244,7 @@ func diskDeleteAction(cmd *cobra.Command, args []string) error {
 	if err != nil {
 		return err
 	}
-	var instances []*store.Instance
+	var instances []*limatype.Instance
 	for _, instName := range instNames {
 		inst, err := store.Inspect(ctx, instName)
 		if err != nil {
@@ -344,7 +345,7 @@ func diskUnlockAction(cmd *cobra.Command, args []string) error {
 					diskName, disk.Instance, inst.Errors)
 				continue
 			}
-			if inst.Status == store.StatusRunning {
+			if inst.Status == limatype.StatusRunning {
 				logrus.Warnf("Cannot unlock disk %q used by running instance %q", diskName, disk.Instance)
 				continue
 			}
@@ -402,7 +403,7 @@ func diskResizeAction(cmd *cobra.Command, args []string) error {
 	if disk.Instance != "" {
 		inst, err := store.Inspect(ctx, disk.Instance)
 		if err == nil {
-			if inst.Status == store.StatusRunning {
+			if inst.Status == limatype.StatusRunning {
 				return fmt.Errorf("cannot resize disk %q used by running instance %q. Please stop the VM instance", diskName, disk.Instance)
 			}
 		}
diff --git a/cmd/limactl/edit.go b/cmd/limactl/edit.go
index 8db0d8f7..8685f17b 100644
--- a/cmd/limactl/edit.go
+++ b/cmd/limactl/edit.go
@@ -14,12 +14,15 @@ import (
 	"github.com/spf13/cobra"
 
 	"github.com/lima-vm/lima/v2/cmd/limactl/editflags"
+	"github.com/lima-vm/lima/v2/pkg/driverutil"
 	"github.com/lima-vm/lima/v2/pkg/editutil"
 	"github.com/lima-vm/lima/v2/pkg/instance"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
+	"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 	"github.com/lima-vm/lima/v2/pkg/limayaml"
 	networks "github.com/lima-vm/lima/v2/pkg/networks/reconcile"
 	"github.com/lima-vm/lima/v2/pkg/store"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
 	"github.com/lima-vm/lima/v2/pkg/uiutil"
 	"github.com/lima-vm/lima/v2/pkg/yqutil"
 )
@@ -46,12 +49,12 @@ func editAction(cmd *cobra.Command, args []string) error {
 
 	var filePath string
 	var err error
-	var inst *store.Instance
+	var inst *limatype.Instance
 
 	if arg == "" {
 		arg = DefaultInstanceName
 	}
-	if err := store.ValidateInstName(arg); err == nil {
+	if err := dirnames.ValidateInstName(arg); err == nil {
 		inst, err = store.Inspect(ctx, arg)
 		if err != nil {
 			if errors.Is(err, os.ErrNotExist) {
@@ -59,7 +62,7 @@ func editAction(cmd *cobra.Command, args []string) error {
 			}
 			return err
 		}
-		if inst.Status == store.StatusRunning {
+		if inst.Status == limatype.StatusRunning {
 			return errors.New("cannot edit a running instance")
 		}
 		filePath = filepath.Join(inst.Dir, filenames.LimaYAML)
@@ -118,6 +121,9 @@ func editAction(cmd *cobra.Command, args []string) error {
 	if err != nil {
 		return err
 	}
+	if err := driverutil.ResolveVMType(y, filePath); err != nil {
+		return fmt.Errorf("failed to accept config for %q: %w", filePath, err)
+	}
 	if err := limayaml.Validate(y, true); err != nil {
 		return saveRejectedYAML(yBytes, err)
 	}
diff --git a/cmd/limactl/editflags/editflags.go b/cmd/limactl/editflags/editflags.go
index eba0042e..7a0f5a07 100644
--- a/cmd/limactl/editflags/editflags.go
+++ b/cmd/limactl/editflags/editflags.go
@@ -15,6 +15,8 @@ import (
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 	flag "github.com/spf13/pflag"
+
+	"github.com/lima-vm/lima/v2/pkg/registry"
 )
 
 // RegisterEdit registers flags related to in-place YAML modification, for `limactl edit`.
@@ -75,6 +77,15 @@ func RegisterEdit(cmd *cobra.Command, commentPrefix string) {
 	_ = cmd.RegisterFlagCompletionFunc("disk", func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) {
 		return []string{"10", "30", "50", "100", "200"}, cobra.ShellCompDirectiveNoFileComp
 	})
+
+	flags.String("vm-type", "", commentPrefix+"Virtual machine type")
+	_ = cmd.RegisterFlagCompletionFunc("vm-type", func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) {
+		var drivers []string
+		for k := range registry.List() {
+			drivers = append(drivers, k)
+		}
+		return drivers, cobra.ShellCompDirectiveNoFileComp
+	})
 }
 
 // RegisterCreate registers flags related to in-place YAML modification, for `limactl create`.
@@ -92,11 +103,6 @@ func RegisterCreate(cmd *cobra.Command, commentPrefix string) {
 		return []string{"user", "system", "user+system", "none"}, cobra.ShellCompDirectiveNoFileComp
 	})
 
-	flags.String("vm-type", "", commentPrefix+"Virtual machine type (qemu, vz)") // colima-compatible
-	_ = cmd.RegisterFlagCompletionFunc("vm-type", func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) {
-		return []string{"qemu", "vz"}, cobra.ShellCompDirectiveNoFileComp
-	})
-
 	flags.Bool("plain", false, commentPrefix+"Plain mode. Disables mounts, port forwarding, containerd, etc.")
 }
 
@@ -177,6 +183,7 @@ func YQExpressions(flags *flag.FlagSet, newInstance bool) ([]string, error) {
 			false,
 		},
 		{"mount-type", d(".mountType = %q"), false, false},
+		{"vm-type", d(".vmType = %q"), false, false},
 		{"mount-inotify", d(".mountInotify = %s"), false, true},
 		{"mount-writable", d(".mounts[].writable = %s"), false, false},
 		{
@@ -262,7 +269,6 @@ func YQExpressions(flags *flag.FlagSet, newInstance bool) ([]string, error) {
 			false,
 		},
 		{"disk", d(".disk= \"%sGiB\""), false, false},
-		{"vm-type", d(".vmType = %q"), true, false},
 		{"plain", d(".plain = %s"), true, false},
 	}
 	var exprs []string
diff --git a/cmd/limactl/factory-reset.go b/cmd/limactl/factory-reset.go
index b774aef1..58e6d1af 100644
--- a/cmd/limactl/factory-reset.go
+++ b/cmd/limactl/factory-reset.go
@@ -14,8 +14,8 @@ import (
 
 	"github.com/lima-vm/lima/v2/pkg/cidata"
 	"github.com/lima-vm/lima/v2/pkg/instance"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 	"github.com/lima-vm/lima/v2/pkg/store"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
 )
 
 func newFactoryResetCommand() *cobra.Command {
diff --git a/cmd/limactl/genschema.go b/cmd/limactl/genschema.go
index 0739023e..d69d74cc 100644
--- a/cmd/limactl/genschema.go
+++ b/cmd/limactl/genschema.go
@@ -15,7 +15,7 @@ import (
 	orderedmap "github.com/wk8/go-ordered-map/v2"
 
 	"github.com/lima-vm/lima/v2/pkg/jsonschemautil"
-	"github.com/lima-vm/lima/v2/pkg/limayaml"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 )
 
 func newGenSchemaCommand() *cobra.Command {
@@ -52,7 +52,7 @@ func genschemaAction(cmd *cobra.Command, args []string) error {
 		return err
 	}
 
-	schema := jsonschema.Reflect(&limayaml.LimaYAML{})
+	schema := jsonschema.Reflect(&limatype.LimaYAML{})
 	// allow Disk to be either string (name) or object (struct)
 	schema.Definitions["Disk"].Type = "" // was: "object"
 	schema.Definitions["Disk"].OneOf = []*jsonschema.Schema{
@@ -72,10 +72,10 @@ func genschemaAction(cmd *cobra.Command, args []string) error {
 		{Type: "object"},
 	}
 	properties := schema.Definitions["LimaYAML"].Properties
-	getProp(properties, "os").Enum = toAny(limayaml.OSTypes)
-	getProp(properties, "arch").Enum = toAny(limayaml.ArchTypes)
-	getProp(properties, "mountType").Enum = toAny(limayaml.MountTypes)
-	getProp(properties, "vmType").Enum = toAny(limayaml.VMTypes)
+	getProp(properties, "os").Enum = toAny(limatype.OSTypes)
+	getProp(properties, "arch").Enum = toAny(limatype.ArchTypes)
+	getProp(properties, "mountType").Enum = toAny(limatype.MountTypes)
+	getProp(properties, "vmType").Enum = toAny(limatype.VMTypes)
 	j, err := json.MarshalIndent(schema, "", "    ")
 	if err != nil {
 		return err
diff --git a/cmd/limactl/list.go b/cmd/limactl/list.go
index 97c6afa5..791d9f01 100644
--- a/cmd/limactl/list.go
+++ b/cmd/limactl/list.go
@@ -16,6 +16,7 @@ import (
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 	"github.com/lima-vm/lima/v2/pkg/store"
 )
 
@@ -172,7 +173,7 @@ func listAction(cmd *cobra.Command, args []string) error {
 	}
 
 	// get the state and config for all the requested instances
-	var instances []*store.Instance
+	var instances []*limatype.Instance
 	for _, instanceName := range instanceNames {
 		instance, err := store.Inspect(ctx, instanceName)
 		if err != nil {
diff --git a/cmd/limactl/main.go b/cmd/limactl/main.go
index 77ac6d43..d5a51ea4 100644
--- a/cmd/limactl/main.go
+++ b/cmd/limactl/main.go
@@ -20,8 +20,8 @@ import (
 	"github.com/lima-vm/lima/v2/pkg/debugutil"
 	"github.com/lima-vm/lima/v2/pkg/driver/external/server"
 	"github.com/lima-vm/lima/v2/pkg/fsutil"
+	"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
 	"github.com/lima-vm/lima/v2/pkg/osutil"
-	"github.com/lima-vm/lima/v2/pkg/store/dirnames"
 	"github.com/lima-vm/lima/v2/pkg/version"
 )
 
@@ -44,6 +44,7 @@ func main() {
 	}
 	rootCmd := newApp()
 	if err := executeWithPluginSupport(rootCmd, os.Args[1:]); err != nil {
+		server.StopAllExternalDrivers()
 		handleExitCoder(err)
 		logrus.Fatal(err)
 	}
@@ -242,16 +243,18 @@ func runExternalPlugin(ctx context.Context, name string, args []string) {
 		return
 	}
 
-	logrus.Debugf("found external command: %s", execPath)
-
 	cmd := exec.CommandContext(ctx, execPath, args...)
 	cmd.Stdin = os.Stdin
 	cmd.Stdout = os.Stdout
 	cmd.Stderr = os.Stderr
 	cmd.Env = os.Environ()
 
-	handleExitCoder(cmd.Run())
-	os.Exit(0) //nolint:revive // it's intentional to call os.Exit in this function
+	err = cmd.Run()
+	handleExitCoder(err)
+	if err == nil {
+		os.Exit(0) //nolint:revive // it's intentional to call os.Exit in this function
+	}
+	logrus.Fatalf("external command %q failed: %v", execPath, err)
 }
 
 func updatePathEnv() error {
diff --git a/cmd/limactl/prune.go b/cmd/limactl/prune.go
index a17f717e..c7ec78f0 100644
--- a/cmd/limactl/prune.go
+++ b/cmd/limactl/prune.go
@@ -5,6 +5,7 @@ package main
 
 import (
 	"context"
+	"fmt"
 	"maps"
 	"os"
 
@@ -12,6 +13,8 @@ import (
 	"github.com/spf13/cobra"
 
 	"github.com/lima-vm/lima/v2/pkg/downloader"
+	"github.com/lima-vm/lima/v2/pkg/driverutil"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 	"github.com/lima-vm/lima/v2/pkg/limayaml"
 	"github.com/lima-vm/lima/v2/pkg/store"
 	"github.com/lima-vm/lima/v2/pkg/templatestore"
@@ -64,8 +67,8 @@ func pruneAction(cmd *cobra.Command, _ []string) error {
 	return nil
 }
 
-func knownLocations(ctx context.Context) (map[string]limayaml.File, error) {
-	locations := make(map[string]limayaml.File)
+func knownLocations(ctx context.Context) (map[string]limatype.File, error) {
+	locations := make(map[string]limatype.File)
 
 	// Collect locations from instances
 	instances, err := store.Instances()
@@ -94,13 +97,16 @@ func knownLocations(ctx context.Context) (map[string]limayaml.File, error) {
 		if err != nil {
 			return nil, err
 		}
+		if err := driverutil.ResolveVMType(y, t.Name); err != nil {
+			return nil, fmt.Errorf("failed to accept config for %q: %w", t.Name, err)
+		}
 		maps.Copy(locations, locationsFromLimaYAML(y))
 	}
 	return locations, nil
 }
 
-func locationsFromLimaYAML(y *limayaml.LimaYAML) map[string]limayaml.File {
-	locations := make(map[string]limayaml.File)
+func locationsFromLimaYAML(y *limatype.LimaYAML) map[string]limatype.File {
+	locations := make(map[string]limatype.File)
 	for _, f := range y.Images {
 		locations[downloader.CacheKey(f.Location)] = f.File
 		if f.Kernel != nil {
diff --git a/cmd/limactl/shell.go b/cmd/limactl/shell.go
index 3019178f..7fe79405 100644
--- a/cmd/limactl/shell.go
+++ b/cmd/limactl/shell.go
@@ -23,7 +23,7 @@ import (
 	"github.com/lima-vm/lima/v2/pkg/envutil"
 	"github.com/lima-vm/lima/v2/pkg/instance"
 	"github.com/lima-vm/lima/v2/pkg/ioutilx"
-	"github.com/lima-vm/lima/v2/pkg/limayaml"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 	networks "github.com/lima-vm/lima/v2/pkg/networks/reconcile"
 	"github.com/lima-vm/lima/v2/pkg/sshutil"
 	"github.com/lima-vm/lima/v2/pkg/store"
@@ -36,6 +36,11 @@ lima command is provided as an alias for limactl shell $LIMA_INSTANCE. $LIMA_INS
 By default, the first 'ssh' executable found in the host's PATH is used to connect to the Lima instance.
 A custom ssh alias can be used instead by setting the $` + sshutil.EnvShellSSH + ` environment variable.
 
+Environment Variables:
+  --preserve-env: Propagates host environment variables to the guest instance.
+                  Use LIMA_SHELLENV_ALLOW to specify which variables to allow.
+                  Use LIMA_SHELLENV_BLOCK to specify which variables to block (extends default blocklist with +).
+
 Hint: try --debug to show the detailed logs, if it seems hanging (mostly due to some SSH issue).
 `
 
@@ -86,7 +91,7 @@ func shellAction(cmd *cobra.Command, args []string) error {
 		}
 		return err
 	}
-	if inst.Status == store.StatusStopped {
+	if inst.Status == limatype.StatusStopped {
 		startNow, err := askWhetherToStart()
 		if err != nil {
 			return err
@@ -142,7 +147,7 @@ func shellAction(cmd *cobra.Command, args []string) error {
 	if workDir != "" {
 		changeDirCmd = fmt.Sprintf("cd %s || exit 1", shellescape.Quote(workDir))
 		// FIXME: check whether y.Mounts contains the home, not just len > 0
-	} else if len(inst.Config.Mounts) > 0 || inst.VMType == limayaml.WSL2 {
+	} else if len(inst.Config.Mounts) > 0 || inst.VMType == limatype.WSL2 {
 		hostCurrentDir, err := os.Getwd()
 		if err == nil && runtime.GOOS == "windows" {
 			hostCurrentDir, err = mountDirFromWindowsDir(ctx, inst, hostCurrentDir)
@@ -265,8 +270,8 @@ func shellAction(cmd *cobra.Command, args []string) error {
 	return sshCmd.Run()
 }
 
-func mountDirFromWindowsDir(ctx context.Context, inst *store.Instance, dir string) (string, error) {
-	if inst.VMType == limayaml.WSL2 {
+func mountDirFromWindowsDir(ctx context.Context, inst *limatype.Instance, dir string) (string, error) {
+	if inst.VMType == limatype.WSL2 {
 		distroName := "lima-" + inst.Name
 		return ioutilx.WindowsSubsystemPathForLinux(ctx, dir, distroName)
 	}
diff --git a/cmd/limactl/show-ssh.go b/cmd/limactl/show-ssh.go
index ff53dff7..ecaf98e4 100644
--- a/cmd/limactl/show-ssh.go
+++ b/cmd/limactl/show-ssh.go
@@ -13,10 +13,10 @@ import (
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 
+	"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 	"github.com/lima-vm/lima/v2/pkg/sshutil"
 	"github.com/lima-vm/lima/v2/pkg/store"
-	"github.com/lima-vm/lima/v2/pkg/store/dirnames"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
 )
 
 const showSSHExample = `
diff --git a/cmd/limactl/start.go b/cmd/limactl/start.go
index 4aaf6233..c3dd8261 100644
--- a/cmd/limactl/start.go
+++ b/cmd/limactl/start.go
@@ -17,14 +17,17 @@ import (
 	"github.com/spf13/pflag"
 
 	"github.com/lima-vm/lima/v2/cmd/limactl/editflags"
+	"github.com/lima-vm/lima/v2/pkg/driverutil"
 	"github.com/lima-vm/lima/v2/pkg/editutil"
 	"github.com/lima-vm/lima/v2/pkg/instance"
 	"github.com/lima-vm/lima/v2/pkg/limatmpl"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
+	"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 	"github.com/lima-vm/lima/v2/pkg/limayaml"
 	networks "github.com/lima-vm/lima/v2/pkg/networks/reconcile"
 	"github.com/lima-vm/lima/v2/pkg/registry"
 	"github.com/lima-vm/lima/v2/pkg/store"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
 	"github.com/lima-vm/lima/v2/pkg/templatestore"
 	"github.com/lima-vm/lima/v2/pkg/uiutil"
 	"github.com/lima-vm/lima/v2/pkg/yqutil"
@@ -203,7 +206,7 @@ func printGlobalFlags(cmd *cobra.Command) {
 	}
 }
 
-func loadOrCreateInstance(cmd *cobra.Command, args []string, createOnly bool) (*store.Instance, error) {
+func loadOrCreateInstance(cmd *cobra.Command, args []string, createOnly bool) (*limatype.Instance, error) {
 	ctx := cmd.Context()
 	var arg string // can be empty
 	if len(args) > 0 {
@@ -223,7 +226,7 @@ func loadOrCreateInstance(cmd *cobra.Command, args []string, createOnly bool) (*
 		return nil, err
 	}
 	if name != "" {
-		err := store.ValidateInstName(name)
+		err := dirnames.ValidateInstName(name)
 		if err != nil {
 			return nil, err
 		}
@@ -258,7 +261,7 @@ func loadOrCreateInstance(cmd *cobra.Command, args []string, createOnly bool) (*
 		tty = false
 	}
 	var tmpl *limatmpl.Template
-	if err := store.ValidateInstName(arg); arg == "" || err == nil {
+	if err := dirnames.ValidateInstName(arg); arg == "" || err == nil {
 		tmpl = &limatmpl.Template{Name: name}
 		if arg == "" {
 			if name == "" {
@@ -313,7 +316,7 @@ func loadOrCreateInstance(cmd *cobra.Command, args []string, createOnly bool) (*
 			if _, err := store.Inspect(ctx, tmpl.Name); err == nil {
 				return nil, fmt.Errorf("instance %q already exists", tmpl.Name)
 			}
-		} else if err := store.ValidateInstName(tmpl.Name); err != nil {
+		} else if err := dirnames.ValidateInstName(tmpl.Name); err != nil {
 			return nil, err
 		}
 	}
@@ -342,7 +345,7 @@ func loadOrCreateInstance(cmd *cobra.Command, args []string, createOnly bool) (*
 	return instance.Create(cmd.Context(), tmpl.Name, tmpl.Bytes, saveBrokenYAML)
 }
 
-func applyYQExpressionToExistingInstance(ctx context.Context, inst *store.Instance, yq string) (*store.Instance, error) {
+func applyYQExpressionToExistingInstance(ctx context.Context, inst *limatype.Instance, yq string) (*limatype.Instance, error) {
 	if strings.TrimSpace(yq) == "" {
 		return inst, nil
 	}
@@ -360,6 +363,9 @@ func applyYQExpressionToExistingInstance(ctx context.Context, inst *store.Instan
 	if err != nil {
 		return nil, err
 	}
+	if err := driverutil.ResolveVMType(y, filePath); err != nil {
+		return nil, fmt.Errorf("failed to accept config for %q: %w", filePath, err)
+	}
 	if err := limayaml.Validate(y, true); err != nil {
 		rejectedYAML := "lima.REJECTED.yaml"
 		if writeErr := os.WriteFile(rejectedYAML, yBytes, 0o644); writeErr != nil {
@@ -563,15 +569,15 @@ func startAction(cmd *cobra.Command, args []string) error {
 		return fmt.Errorf("errors inspecting instance: %+v", inst.Errors)
 	}
 	switch inst.Status {
-	case store.StatusRunning:
+	case limatype.StatusRunning:
 		logrus.Infof("The instance %q is already running. Run `%s` to open the shell.",
 			inst.Name, instance.LimactlShellCmd(inst.Name))
 		// Not an error
 		return nil
-	case store.StatusStopped:
+	case limatype.StatusStopped:
 		// NOP
 	default:
-		logrus.Warnf("expected status %q, got %q", store.StatusStopped, inst.Status)
+		logrus.Warnf("expected status %q, got %q", limatype.StatusStopped, inst.Status)
 	}
 	ctx := cmd.Context()
 	err = networks.Reconcile(ctx, inst.Name)
diff --git a/cmd/limactl/template.go b/cmd/limactl/template.go
index 6b8eb367..7913bf4e 100644
--- a/cmd/limactl/template.go
+++ b/cmd/limactl/template.go
@@ -13,9 +13,10 @@ import (
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 
+	"github.com/lima-vm/lima/v2/pkg/driverutil"
 	"github.com/lima-vm/lima/v2/pkg/limatmpl"
+	"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
 	"github.com/lima-vm/lima/v2/pkg/limayaml"
-	"github.com/lima-vm/lima/v2/pkg/store/dirnames"
 	"github.com/lima-vm/lima/v2/pkg/yqutil"
 )
 
@@ -87,6 +88,10 @@ func fillDefaults(ctx context.Context, tmpl *limatmpl.Template) error {
 	if err == nil {
 		tmpl.Bytes, err = limayaml.Marshal(tmpl.Config, false)
 	}
+	if err := driverutil.ResolveVMType(tmpl.Config, filePath); err != nil {
+		logrus.Warnf("failed to resolve VM type for %q: %v", filePath, err)
+		return nil
+	}
 	return err
 }
 
@@ -246,6 +251,10 @@ func templateValidateAction(cmd *cobra.Command, args []string) error {
 		if err != nil {
 			return err
 		}
+		if err := driverutil.ResolveVMType(y, filePath); err != nil {
+			logrus.Warnf("failed to resolve VM type for %q: %v", filePath, err)
+			return nil
+		}
 		if err := limayaml.Validate(y, false); err != nil {
 			return fmt.Errorf("failed to validate YAML file %q: %w", arg, err)
 		}
diff --git a/cmd/limactl/tunnel.go b/cmd/limactl/tunnel.go
index 43f3555d..68b16cbf 100644
--- a/cmd/limactl/tunnel.go
+++ b/cmd/limactl/tunnel.go
@@ -15,6 +15,7 @@ import (
 	"github.com/spf13/cobra"
 
 	"github.com/lima-vm/lima/v2/pkg/freeport"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 	"github.com/lima-vm/lima/v2/pkg/sshutil"
 	"github.com/lima-vm/lima/v2/pkg/store"
 )
@@ -72,7 +73,7 @@ func tunnelAction(cmd *cobra.Command, args []string) error {
 		}
 		return err
 	}
-	if inst.Status == store.StatusStopped {
+	if inst.Status == limatype.StatusStopped {
 		return fmt.Errorf("instance %q is stopped, run `limactl start %s` to start the instance", instName, instName)
 	}
 
diff --git a/cmd/nerdctl.lima b/cmd/nerdctl.lima
index b398e075..9a5205a6 100755
--- a/cmd/nerdctl.lima
+++ b/cmd/nerdctl.lima
@@ -1,3 +1,4 @@
 #!/bin/sh
 set -eu
+# Use --preserve-env to pass through environment variables from host machine into guest instance
 exec limactl shell --preserve-env default nerdctl "$@"
diff --git a/go.mod b/go.mod
index 315907b0..18107058 100644
--- a/go.mod
+++ b/go.mod
@@ -16,7 +16,7 @@ require (
 	github.com/coreos/go-semver v0.3.1
 	github.com/cpuguy83/go-md2man/v2 v2.0.7
 	github.com/digitalocean/go-qemu v0.0.0-20221209210016-f035778c97f7
-	github.com/diskfs/go-diskfs v1.6.0 // gomodjail:unconfined
+	github.com/diskfs/go-diskfs v1.7.0 // gomodjail:unconfined
 	github.com/docker/go-units v0.5.0
 	github.com/elastic/go-libaudit/v2 v2.6.2
 	github.com/foxcpp/go-mockdns v1.1.0
diff --git a/go.sum b/go.sum
index b41c32d1..95d6e095 100644
--- a/go.sum
+++ b/go.sum
@@ -20,6 +20,8 @@ github.com/alecthomas/participle/v2 v2.1.4 h1:W/H79S8Sat/krZ3el6sQMvMaahJ+XcM9WS
 github.com/alecthomas/participle/v2 v2.1.4/go.mod h1:8tqVbpTX20Ru4NfYQgZf4mP18eXPTBViyMWiArNEgGI=
 github.com/alecthomas/repr v0.5.1 h1:E3G4t2QbHTSNpPKBgMTln5KLkZHLOcU7r37J4pXBuIg=
 github.com/alecthomas/repr v0.5.1/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
+github.com/anchore/go-lzo v0.1.0 h1:NgAacnzqPeGH49Ky19QKLBZEuFRqtTG9cdaucc3Vncs=
+github.com/anchore/go-lzo v0.1.0/go.mod h1:3kLx0bve2oN1iDwgM1U5zGku1Tfbdb0No5qp1eL1fIk=
 github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU=
 github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc=
 github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
@@ -55,8 +57,8 @@ github.com/digitalocean/go-qemu v0.0.0-20221209210016-f035778c97f7 h1:3OVJAbR131
 github.com/digitalocean/go-qemu v0.0.0-20221209210016-f035778c97f7/go.mod h1:K4+o74YGNjOb9N6yyG+LPj1NjHtk+Qz0IYQPvirbaLs=
 github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
 github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
-github.com/diskfs/go-diskfs v1.6.0 h1:YmK5+vLSfkwC6kKKRTRPGaDGNF+Xh8FXeiNHwryDfu4=
-github.com/diskfs/go-diskfs v1.6.0/go.mod h1:bRFumZeGFCO8C2KNswrQeuj2m1WCVr4Ms5IjWMczMDk=
+github.com/diskfs/go-diskfs v1.7.0 h1:vonWmt5CMowXwUc79jWyGrf2DIMeoOjkLlMnQYGVOs8=
+github.com/diskfs/go-diskfs v1.7.0/go.mod h1:LhQyXqOugWFRahYUSw47NyZJPezFzB9UELwhpszLP/k=
 github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c=
 github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0=
 github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
diff --git a/hack/test-preserve-env.sh b/hack/test-preserve-env.sh
new file mode 100755
index 00000000..20959107
--- /dev/null
+++ b/hack/test-preserve-env.sh
@@ -0,0 +1,94 @@
+#!/usr/bin/env bash
+
+# SPDX-FileCopyrightText: Copyright The Lima Authors
+# SPDX-License-Identifier: Apache-2.0
+
+set -eu -o pipefail
+
+scriptdir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+# shellcheck source=common.inc.sh
+source "${scriptdir}/common.inc.sh"
+
+if [ "$#" -ne 1 ]; then
+	ERROR "Usage: $0 NAME"
+	exit 1
+fi
+
+NAME="$1"
+
+INFO "Testing --preserve-env flag"
+
+# Environment variable propagation with --preserve-env
+INFO "=== Environment variable propagation with --preserve-env ==="
+test_var_name="LIMA_TEST_PRESERVE_ENV_VAR"
+test_var_value="test-value-${RANDOM}"
+
+got="$(LIMA_SHELLENV_ALLOW="LIMA_TEST_*" LIMA_TEST_PRESERVE_ENV_VAR="$test_var_value" limactl shell --preserve-env "$NAME" printenv "$test_var_name" 2>/dev/null || echo "NOT_FOUND")"
+INFO "$test_var_name: expected=${test_var_value}, got=${got}"
+if [ "$got" != "$test_var_value" ]; then
+	ERROR "Environment variable was not propagated with --preserve-env"
+	exit 1
+fi
+
+# Clean up before next test
+unset LIMA_TEST_PRESERVE_ENV_VAR
+unset LIMA_SHELLENV_ALLOW
+
+# Environment variable NOT propagated without --preserve-env
+INFO "=== Environment variable NOT propagated without --preserve-env ==="
+got_without_flag="$(LIMA_TEST_PRESERVE_ENV_VAR="$test_var_value" limactl shell "$NAME" printenv "$test_var_name" 2>/dev/null || echo "NOT_FOUND")"
+INFO "$test_var_name without --preserve-env: got=${got_without_flag}"
+if [ "$got_without_flag" != "NOT_FOUND" ]; then
+	ERROR "Environment variable was unexpectedly propagated without --preserve-env"
+	exit 1
+fi
+
+# Blocked environment variables should not be propagated even with --preserve-env
+INFO "=== Blocked environment variables are not propagated with --preserve-env ==="
+blocked_var_name="HOME"
+fake_home="/tmp/fake-home-${RANDOM}"
+got_blocked="$(HOME="$fake_home" limactl shell --preserve-env "$NAME" printenv "$blocked_var_name" 2>/dev/null || echo "NOT_FOUND")"
+INFO "$blocked_var_name: host=${fake_home}, guest=${got_blocked}"
+if [ "$got_blocked" = "$fake_home" ]; then
+	ERROR "Blocked environment variable $blocked_var_name was propagated"
+	exit 1
+fi
+
+# LIMA_SHELLENV_BLOCK functionality
+INFO "=== LIMA_SHELLENV_BLOCK with custom pattern ==="
+custom_test_var="LIMA_TEST_CUSTOM_BLOCK"
+custom_test_value="should-be-blocked"
+got_custom_blocked="$(LIMA_SHELLENV_BLOCK="+LIMA_TEST_CUSTOM_*" LIMA_TEST_CUSTOM_BLOCK="$custom_test_value" limactl shell --preserve-env "$NAME" printenv "$custom_test_var" 2>/dev/null || echo "NOT_FOUND")"
+INFO "$custom_test_var with LIMA_SHELLENV_BLOCK: got=${got_custom_blocked}"
+if [ "$got_custom_blocked" != "NOT_FOUND" ]; then
+	ERROR "Custom blocked environment variable was propagated"
+	exit 1
+fi
+
+# Clean up before next test
+unset LIMA_TEST_CUSTOM_BLOCK 2>/dev/null || true
+unset LIMA_SHELLENV_BLOCK 2>/dev/null || true
+
+# LIMA_SHELLENV_ALLOW functionality
+INFO "=== LIMA_SHELLENV_ALLOW with custom pattern ==="
+allow_test_var="LIMA_TEST_ALLOW_VAR"
+allow_test_value="should-be-allowed"
+got_allowed="$(LIMA_SHELLENV_ALLOW="LIMA_TEST_ALLOW_*" LIMA_TEST_ALLOW_VAR="$allow_test_value" limactl shell --preserve-env "$NAME" printenv "$allow_test_var" 2>/dev/null || echo "NOT_FOUND")"
+INFO "$allow_test_var with LIMA_SHELLENV_ALLOW: got=${got_allowed}"
+if [ "$got_allowed" != "$allow_test_value" ]; then
+	ERROR "Allowed environment variable was not propagated"
+	exit 1
+fi
+
+# Non-allowed variables are blocked when LIMA_SHELLENV_ALLOW is set
+INFO "=== Non-allowed variables are blocked when LIMA_SHELLENV_ALLOW is set ==="
+other_test_var="LIMA_TEST_OTHER_VAR"
+other_test_value="should-be-blocked"
+got_other="$(LIMA_SHELLENV_ALLOW="LIMA_TEST_ALLOW_*" LIMA_TEST_OTHER_VAR="$other_test_value" limactl shell --preserve-env "$NAME" printenv "$other_test_var" 2>/dev/null || echo "NOT_FOUND")"
+INFO "$other_test_var with LIMA_SHELLENV_ALLOW (should be blocked): got=${got_other}"
+if [ "$got_other" != "NOT_FOUND" ]; then
+	ERROR "Non-allowed environment variable was propagated when LIMA_SHELLENV_ALLOW was set"
+	exit 1
+fi
+
+INFO "All --preserve-env tests passed"
diff --git a/hack/test-templates.sh b/hack/test-templates.sh
index 985d3bef..f01d249e 100755
--- a/hack/test-templates.sh
+++ b/hack/test-templates.sh
@@ -58,6 +58,7 @@ declare -A CHECKS=(
 	["provision-data"]=""
 	["param-env-variables"]=""
 	["set-user"]=""
+	["preserve-env"]="1"
 )
 
 case "$NAME" in
@@ -205,8 +206,7 @@ if [[ -n ${CHECKS["param-env-variables"]} ]]; then
 	limactl shell "$NAME" test -e /tmp/param-dependency
 	limactl shell "$NAME" test -e /tmp/param-probe
 	limactl shell "$NAME" test -e /tmp/param-system
-	# TODO re-enable once https://github.com/lima-vm/lima/issues/3308 is fixed
-	# limactl shell "$NAME" test -e /tmp/param-user
+	limactl shell "$NAME" test -e /tmp/param-user
 fi
 
 if [[ -n ${CHECKS["set-user"]} ]]; then
@@ -277,6 +277,10 @@ if [[ -n ${CHECKS["mount-home"]} ]]; then
 	"${scriptdir}"/test-mount-home.sh "$NAME"
 fi
 
+if [[ -n ${CHECKS["preserve-env"]} ]]; then
+	"${scriptdir}"/test-preserve-env.sh "$NAME"
+fi
+
 # Use GHCR to avoid hitting Docker Hub rate limit
 nginx_image="ghcr.io/stargz-containers/nginx:1.19-alpine-org"
 alpine_image="ghcr.io/containerd/alpine:3.14.0"
diff --git a/hack/test-templates/test-misc.yaml b/hack/test-templates/test-misc.yaml
index 92d29184..1de67f10 100644
--- a/hack/test-templates/test-misc.yaml
+++ b/hack/test-templates/test-misc.yaml
@@ -19,8 +19,7 @@ param:
   DEPENDENCY: dependency
   PROBE: probe
   SYSTEM: system
-# TODO re-enable once https://github.com/lima-vm/lima/issues/3308 is fixed
-# USER: user
+  USER: user
 
 provision:
 - mode: ansible
@@ -31,9 +30,8 @@ provision:
   script: "touch /tmp/param-$PARAM_DEPENDENCY"
 - mode: system
   script: "touch /tmp/param-$PARAM_SYSTEM"
-# TODO re-enable once https://github.com/lima-vm/lima/issues/3308 is fixed
-# - mode: user
-#   script: "touch /tmp/param-$PARAM_USER"
+- mode: user
+  script: "touch /tmp/param-$PARAM_USER"
 - mode: data
   path: /etc/sysctl.d/99-inotify.conf
   content: |
diff --git a/hack/test-upgrade.sh b/hack/test-upgrade.sh
index 696295f6..e9be6c15 100755
--- a/hack/test-upgrade.sh
+++ b/hack/test-upgrade.sh
@@ -95,8 +95,11 @@ INFO "==========================================================================
 INFO "Installing the new Lima ${NEWVER}"
 install_lima "${NEWVER}"
 
+INFO "Editing the instance to specify vm-type as qemu explicitly"
+limactl edit --vm-type=qemu "${LIMA_INSTANCE}"
+
 INFO "Restarting the instance"
-limactl start --tty=false "${LIMA_INSTANCE}" || show_lima_log
+limactl start --tty=false --vm-type=qemu "${LIMA_INSTANCE}" || show_lima_log
 lima nerdctl info
 
 INFO "Confirming that the host filesystem is still mounted"
diff --git a/pkg/cidata/cidata.TEMPLATE.d/boot/05-rosetta-volume.sh b/pkg/cidata/cidata.TEMPLATE.d/boot/05-rosetta-volume.sh
index 4a43ff3f..9fa517ae 100755
--- a/pkg/cidata/cidata.TEMPLATE.d/boot/05-rosetta-volume.sh
+++ b/pkg/cidata/cidata.TEMPLATE.d/boot/05-rosetta-volume.sh
@@ -27,7 +27,7 @@ if [ "$LIMA_CIDATA_ROSETTA_BINFMT" = "true" ]; then
 	[ ! -d "$(dirname "$binfmtd_conf")" ] || [ -f "$binfmtd_conf" ] || echo "$rosetta_binfmt" >"$binfmtd_conf"
 else
 	# unregister rosetta from binfmt_misc if it exists
-	[ ! -f "$binfmt_entry" ] || echo -1 | "$binfmt_entry"
+	[ ! -f "$binfmt_entry" ] || echo -1 >"$binfmt_entry"
 	# remove binfmt.d(5) configuration if it exists
 	[ ! -f "$binfmtd_conf" ] || rm "$binfmtd_conf"
 fi
diff --git a/pkg/cidata/cidata.go b/pkg/cidata/cidata.go
index 0a8c57aa..7e633018 100644
--- a/pkg/cidata/cidata.go
+++ b/pkg/cidata/cidata.go
@@ -24,15 +24,17 @@ import (
 	"github.com/sirupsen/logrus"
 
 	"github.com/lima-vm/lima/v2/pkg/debugutil"
+	"github.com/lima-vm/lima/v2/pkg/driver"
 	"github.com/lima-vm/lima/v2/pkg/instance/hostname"
 	"github.com/lima-vm/lima/v2/pkg/iso9660util"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 	"github.com/lima-vm/lima/v2/pkg/limayaml"
 	"github.com/lima-vm/lima/v2/pkg/localpathutil"
 	"github.com/lima-vm/lima/v2/pkg/networks"
 	"github.com/lima-vm/lima/v2/pkg/networks/usernet"
 	"github.com/lima-vm/lima/v2/pkg/osutil"
 	"github.com/lima-vm/lima/v2/pkg/sshutil"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
 )
 
 var netLookupIP = func(host string) []net.IP {
@@ -116,7 +118,7 @@ func setupEnv(instConfigEnv map[string]string, propagateProxyEnv bool, slirpGate
 	return env, nil
 }
 
-func templateArgs(ctx context.Context, bootScripts bool, instDir, name string, instConfig *limayaml.LimaYAML, udpDNSLocalPort, tcpDNSLocalPort, vsockPort int, virtioPort string) (*TemplateArgs, error) {
+func templateArgs(ctx context.Context, bootScripts bool, instDir, name string, instConfig *limatype.LimaYAML, udpDNSLocalPort, tcpDNSLocalPort, vsockPort int, virtioPort string) (*TemplateArgs, error) {
 	if err := limayaml.Validate(instConfig, false); err != nil {
 		return nil, err
 	}
@@ -136,14 +138,19 @@ func templateArgs(ctx context.Context, bootScripts bool, instDir, name string, i
 		Containerd:         Containerd{System: *instConfig.Containerd.System, User: *instConfig.Containerd.User, Archive: archive},
 		SlirpNICName:       networks.SlirpNICName,
 
-		RosettaEnabled: *instConfig.Rosetta.Enabled,
-		RosettaBinFmt:  *instConfig.Rosetta.BinFmt,
-		VMType:         *instConfig.VMType,
-		VSockPort:      vsockPort,
-		VirtioPort:     virtioPort,
-		Plain:          *instConfig.Plain,
-		TimeZone:       *instConfig.TimeZone,
-		Param:          instConfig.Param,
+		VMType:     *instConfig.VMType,
+		VSockPort:  vsockPort,
+		VirtioPort: virtioPort,
+		Plain:      *instConfig.Plain,
+		TimeZone:   *instConfig.TimeZone,
+		Param:      instConfig.Param,
+	}
+
+	if instConfig.VMOpts.VZ.Rosetta.Enabled != nil {
+		args.RosettaEnabled = *instConfig.VMOpts.VZ.Rosetta.Enabled
+	}
+	if instConfig.VMOpts.VZ.Rosetta.BinFmt != nil {
+		args.RosettaEnabled = *instConfig.VMOpts.VZ.Rosetta.BinFmt
 	}
 
 	firstUsernetIndex := limayaml.FirstUsernetIndex(instConfig)
@@ -164,7 +171,7 @@ func templateArgs(ctx context.Context, bootScripts bool, instDir, name string, i
 			return nil, err
 		}
 		args.SlirpGateway = usernet.GatewayIP(subnet)
-		if *instConfig.VMType == limayaml.VZ {
+		if *instConfig.VMType == limatype.VZ {
 			args.SlirpDNS = usernet.GatewayIP(subnet)
 		} else {
 			args.SlirpDNS = usernet.DNSIP(subnet)
@@ -188,11 +195,11 @@ func templateArgs(ctx context.Context, bootScripts bool, instDir, name string, i
 
 	var fstype string
 	switch *instConfig.MountType {
-	case limayaml.REVSSHFS:
+	case limatype.REVSSHFS:
 		fstype = "sshfs"
-	case limayaml.NINEP:
+	case limatype.NINEP:
 		fstype = "9p"
-	case limayaml.VIRTIOFS:
+	case limatype.VIRTIOFS:
 		fstype = "virtiofs"
 	}
 	hostHome, err := localpathutil.Expand("~")
@@ -228,11 +235,11 @@ func templateArgs(ctx context.Context, bootScripts bool, instDir, name string, i
 	}
 
 	switch *instConfig.MountType {
-	case limayaml.REVSSHFS:
+	case limatype.REVSSHFS:
 		args.MountType = "reverse-sshfs"
-	case limayaml.NINEP:
+	case limatype.NINEP:
 		args.MountType = "9p"
-	case limayaml.VIRTIOFS:
+	case limatype.VIRTIOFS:
 		args.MountType = "virtiofs"
 	}
 
@@ -272,7 +279,7 @@ func templateArgs(ctx context.Context, bootScripts bool, instDir, name string, i
 		for _, addr := range instConfig.DNS {
 			args.DNSAddresses = append(args.DNSAddresses, addr.String())
 		}
-	case firstUsernetIndex != -1 || *instConfig.VMType == limayaml.VZ:
+	case firstUsernetIndex != -1 || *instConfig.VMType == limatype.VZ:
 		args.DNSAddresses = append(args.DNSAddresses, args.SlirpDNS)
 	case *instConfig.HostResolver.Enabled:
 		args.UDPDNSLocalPort = udpDNSLocalPort
@@ -316,10 +323,10 @@ func templateArgs(ctx context.Context, bootScripts bool, instDir, name string, i
 	args.BootCmds = getBootCmds(instConfig.Provision)
 
 	for i, f := range instConfig.Provision {
-		if f.Mode == limayaml.ProvisionModeDependency && *f.SkipDefaultDependencyResolution {
+		if f.Mode == limatype.ProvisionModeDependency && *f.SkipDefaultDependencyResolution {
 			args.SkipDefaultDependencyResolution = true
 		}
-		if f.Mode == limayaml.ProvisionModeData {
+		if f.Mode == limatype.ProvisionModeData {
 			args.DataFiles = append(args.DataFiles, DataFile{
 				FileName:    fmt.Sprintf("%08d", i),
 				Overwrite:   strconv.FormatBool(*f.Overwrite),
@@ -333,7 +340,7 @@ func templateArgs(ctx context.Context, bootScripts bool, instDir, name string, i
 	return &args, nil
 }
 
-func GenerateCloudConfig(ctx context.Context, instDir, name string, instConfig *limayaml.LimaYAML) error {
+func GenerateCloudConfig(ctx context.Context, instDir, name string, instConfig *limatype.LimaYAML) error {
 	args, err := templateArgs(ctx, false, instDir, name, instConfig, 0, 0, 0, "")
 	if err != nil {
 		return err
@@ -356,7 +363,7 @@ func GenerateCloudConfig(ctx context.Context, instDir, name string, instConfig *
 	return os.WriteFile(filepath.Join(instDir, filenames.CloudConfig), config, 0o444)
 }
 
-func GenerateISO9660(ctx context.Context, instDir, name string, instConfig *limayaml.LimaYAML, udpDNSLocalPort, tcpDNSLocalPort int, guestAgentBinary, nerdctlArchive string, vsockPort int, virtioPort string) error {
+func GenerateISO9660(ctx context.Context, drv driver.Driver, instDir, name string, instConfig *limatype.LimaYAML, udpDNSLocalPort, tcpDNSLocalPort int, guestAgentBinary, nerdctlArchive string, vsockPort int, virtioPort string) error {
 	args, err := templateArgs(ctx, true, instDir, name, instConfig, udpDNSLocalPort, tcpDNSLocalPort, vsockPort, virtioPort)
 	if err != nil {
 		return err
@@ -371,21 +378,33 @@ func GenerateISO9660(ctx context.Context, instDir, name string, instConfig *lima
 		return err
 	}
 
+	driverScripts, err := drv.BootScripts()
+	if err != nil {
+		return fmt.Errorf("failed to get boot scripts: %w", err)
+	}
+
+	for filename, content := range driverScripts {
+		layout = append(layout, iso9660util.Entry{
+			Path:   fmt.Sprintf("boot/%s", filename),
+			Reader: strings.NewReader(string(content)),
+		})
+	}
+
 	for i, f := range instConfig.Provision {
 		switch f.Mode {
-		case limayaml.ProvisionModeSystem, limayaml.ProvisionModeUser, limayaml.ProvisionModeDependency:
+		case limatype.ProvisionModeSystem, limatype.ProvisionModeUser, limatype.ProvisionModeDependency:
 			layout = append(layout, iso9660util.Entry{
 				Path:   fmt.Sprintf("provision.%s/%08d", f.Mode, i),
 				Reader: strings.NewReader(f.Script),
 			})
-		case limayaml.ProvisionModeData:
+		case limatype.ProvisionModeData:
 			layout = append(layout, iso9660util.Entry{
 				Path:   fmt.Sprintf("provision.%s/%08d", f.Mode, i),
 				Reader: strings.NewReader(*f.Content),
 			})
-		case limayaml.ProvisionModeBoot:
+		case limatype.ProvisionModeBoot:
 			continue
-		case limayaml.ProvisionModeAnsible:
+		case limatype.ProvisionModeAnsible:
 			continue
 		default:
 			return fmt.Errorf("unknown provision mode %q", f.Mode)
@@ -433,7 +452,7 @@ func GenerateISO9660(ctx context.Context, instDir, name string, instConfig *lima
 		})
 	}
 
-	if args.VMType == limayaml.WSL2 {
+	if args.VMType == limatype.WSL2 {
 		layout = append(layout, iso9660util.Entry{
 			Path:   "ssh_authorized_keys",
 			Reader: strings.NewReader(strings.Join(args.SSHPubKeys, "\n")),
@@ -456,10 +475,10 @@ func getCert(content string) Cert {
 	return Cert{Lines: lines}
 }
 
-func getBootCmds(p []limayaml.Provision) []BootCmds {
+func getBootCmds(p []limatype.Provision) []BootCmds {
 	var bootCmds []BootCmds
 	for _, f := range p {
-		if f.Mode == limayaml.ProvisionModeBoot {
+		if f.Mode == limatype.ProvisionModeBoot {
 			lines := []string{}
 			for _, line := range strings.Split(f.Script, "\n") {
 				if line == "" {
diff --git a/pkg/driver/driver.go b/pkg/driver/driver.go
index f9811f6e..63820fd8 100644
--- a/pkg/driver/driver.go
+++ b/pkg/driver/driver.go
@@ -7,7 +7,7 @@ import (
 	"context"
 	"net"
 
-	"github.com/lima-vm/lima/v2/pkg/store"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 )
 
 // Lifecycle defines basic lifecycle operations.
@@ -15,13 +15,13 @@ type Lifecycle interface {
 	// Validate returns error if the current driver isn't support for given config
 	Validate(_ context.Context) error
 
-	// Initialize is called on creating the instance for initialization.
+	// Create is called on creating the instance for the first time.
 	// (e.g., creating "vz-identifier" file)
 	//
-	// Initialize MUST return nil when it is called against an existing instance.
+	// Create MUST return nil when it is called against an existing instance.
 	//
-	// Initialize does not create the disks.
-	Initialize(_ context.Context) error
+	// Create does not create the disks.
+	Create(_ context.Context) error
 
 	// CreateDisk returns error if the current driver fails in creating disk
 	CreateDisk(_ context.Context) error
@@ -34,6 +34,12 @@ type Lifecycle interface {
 	// Stop will terminate the running vm instance.
 	// It returns error if there are any errors during Stop
 	Stop(_ context.Context) error
+
+	Delete(_ context.Context) error
+
+	InspectStatus(_ context.Context, inst *limatype.Instance) string
+
+	BootScripts() (map[string][]byte, error)
 }
 
 // GUI defines GUI-related operations.
@@ -54,12 +60,6 @@ type SnapshotManager interface {
 	ListSnapshots(ctx context.Context) (string, error)
 }
 
-// Registration defines operations for registering and unregistering the driver instance.
-type Registration interface {
-	Register(ctx context.Context) error
-	Unregister(ctx context.Context) error
-}
-
 // GuestAgent defines operations for the guest agent.
 type GuestAgent interface {
 	// ForwardGuestAgent returns if the guest agent sock needs forwarding by host agent.
@@ -74,13 +74,17 @@ type Driver interface {
 	Lifecycle
 	GUI
 	SnapshotManager
-	Registration
 	GuestAgent
 
 	Info() Info
 
-	// SetConfig sets the configuration for the instance.
-	Configure(inst *store.Instance) *ConfiguredDriver
+	// Configure sets the configuration for the instance.
+	Configure(inst *limatype.Instance) *ConfiguredDriver
+
+	AcceptConfig(cfg *limatype.LimaYAML, filePath string) error
+	FillConfig(cfg *limatype.LimaYAML, filePath string) error
+
+	SSHAddress(ctx context.Context) (string, error)
 }
 
 type ConfiguredDriver struct {
@@ -88,9 +92,15 @@ type ConfiguredDriver struct {
 }
 
 type Info struct {
-	DriverName  string `json:"driverName"`
-	CanRunGUI   bool   `json:"canRunGui,omitempty"`
-	VsockPort   int    `json:"vsockPort"`
-	VirtioPort  string `json:"virtioPort"`
-	InstanceDir string `json:"instanceDir,omitempty"`
+	DriverName  string         `json:"driverName"`
+	CanRunGUI   bool           `json:"canRunGui,omitempty"`
+	VsockPort   int            `json:"vsockPort"`
+	VirtioPort  string         `json:"virtioPort"`
+	InstanceDir string         `json:"instanceDir,omitempty"`
+	Features    DriverFeatures `json:"features"`
+}
+
+type DriverFeatures struct {
+	DynamicSSHAddress    bool `json:"dynamicSSHAddress"`
+	SkipSocketForwarding bool `json:"skipSocketForwarding"`
 }
diff --git a/pkg/driver/external/client/methods.go b/pkg/driver/external/client/methods.go
index 2b95f85f..cb251d12 100644
--- a/pkg/driver/external/client/methods.go
+++ b/pkg/driver/external/client/methods.go
@@ -14,7 +14,7 @@ import (
 
 	"github.com/lima-vm/lima/v2/pkg/driver"
 	pb "github.com/lima-vm/lima/v2/pkg/driver/external"
-	"github.com/lima-vm/lima/v2/pkg/store"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 )
 
 func (d *DriverClient) Validate(ctx context.Context) error {
@@ -32,17 +32,8 @@ func (d *DriverClient) Validate(ctx context.Context) error {
 	return nil
 }
 
-func (d *DriverClient) Initialize(ctx context.Context) error {
-	d.logger.Debug("Initializing driver instance")
-
-	_, err := d.DriverSvc.Initialize(ctx, &emptypb.Empty{})
-	if err != nil {
-		d.logger.Errorf("Initialization failed: %v", err)
-		return err
-	}
-
-	d.logger.Debug("Driver instance initialized successfully")
-	return nil
+func (d *DriverClient) Create(_ context.Context) error {
+	return errors.New("create not implemented for external drivers")
 }
 
 func (d *DriverClient) CreateDisk(ctx context.Context) error {
@@ -102,6 +93,18 @@ func (d *DriverClient) Stop(ctx context.Context) error {
 	return nil
 }
 
+func (d *DriverClient) Delete(_ context.Context) error {
+	return errors.New("delete not implemented for external drivers")
+}
+
+func (d *DriverClient) AcceptConfig(_ *limatype.LimaYAML, _ string) error {
+	return errors.New("pre-configured driver action not implemented in client driver")
+}
+
+func (d *DriverClient) FillConfig(_ *limatype.LimaYAML, _ string) error {
+	return errors.New("pre-configured driver action not implemented in client driver")
+}
+
 func (d *DriverClient) RunGUI() error {
 	d.logger.Debug("Running GUI for the driver instance")
 
@@ -204,32 +207,6 @@ func (d *DriverClient) ListSnapshots(ctx context.Context) (string, error) {
 	return resp.Snapshots, nil
 }
 
-func (d *DriverClient) Register(ctx context.Context) error {
-	d.logger.Debug("Registering driver instance")
-
-	_, err := d.DriverSvc.Register(ctx, &emptypb.Empty{})
-	if err != nil {
-		d.logger.Errorf("Failed to register driver instance: %v", err)
-		return err
-	}
-
-	d.logger.Debug("Driver instance registered successfully")
-	return nil
-}
-
-func (d *DriverClient) Unregister(ctx context.Context) error {
-	d.logger.Debug("Unregistering driver instance")
-
-	_, err := d.DriverSvc.Unregister(ctx, &emptypb.Empty{})
-	if err != nil {
-		d.logger.Errorf("Failed to unregister driver instance: %v", err)
-		return err
-	}
-
-	d.logger.Debug("Driver instance unregistered successfully")
-	return nil
-}
-
 func (d *DriverClient) ForwardGuestAgent() bool {
 	d.logger.Debug("Checking if guest agent needs to be forwarded")
 
@@ -278,7 +255,7 @@ func (d *DriverClient) Info() driver.Info {
 	return info
 }
 
-func (d *DriverClient) Configure(inst *store.Instance) *driver.ConfiguredDriver {
+func (d *DriverClient) Configure(inst *limatype.Instance) *driver.ConfiguredDriver {
 	d.logger.Debugf("Setting config for instance %s with SSH local port %d", inst.Name, inst.SSHLocalPort)
 
 	instJSON, err := inst.MarshalJSON()
@@ -303,3 +280,15 @@ func (d *DriverClient) Configure(inst *store.Instance) *driver.ConfiguredDriver
 		Driver: d,
 	}
 }
+
+func (d *DriverClient) InspectStatus(_ context.Context, _ *limatype.Instance) string {
+	return ""
+}
+
+func (d *DriverClient) SSHAddress(_ context.Context) (string, error) {
+	return "", errors.New("sshAddress not implemented for external drivers")
+}
+
+func (d *DriverClient) BootScripts() (map[string][]byte, error) {
+	return nil, errors.New("bootScripts not implemented for external drivers")
+}
diff --git a/pkg/driver/external/server/methods.go b/pkg/driver/external/server/methods.go
index 73cfafed..176b5c9c 100644
--- a/pkg/driver/external/server/methods.go
+++ b/pkg/driver/external/server/methods.go
@@ -16,8 +16,8 @@ import (
 
 	"github.com/lima-vm/lima/v2/pkg/bicopy"
 	pb "github.com/lima-vm/lima/v2/pkg/driver/external"
-	"github.com/lima-vm/lima/v2/pkg/store"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 )
 
 func (s *DriverServer) Start(_ *emptypb.Empty, stream pb.Driver_StartServer) error {
@@ -55,7 +55,7 @@ func (s *DriverServer) Start(_ *emptypb.Empty, stream pb.Driver_StartServer) err
 
 func (s *DriverServer) SetConfig(_ context.Context, req *pb.SetConfigRequest) (*emptypb.Empty, error) {
 	s.logger.Debugf("Received SetConfig request")
-	var inst store.Instance
+	var inst limatype.Instance
 
 	if err := inst.UnmarshalJSON(req.InstanceConfigJson); err != nil {
 		s.logger.Errorf("Failed to unmarshal InstanceConfigJson: %v", err)
@@ -130,7 +130,7 @@ func (s *DriverServer) Validate(ctx context.Context, empty *emptypb.Empty) (*emp
 
 func (s *DriverServer) Initialize(ctx context.Context, empty *emptypb.Empty) (*emptypb.Empty, error) {
 	s.logger.Debug("Received Initialize request")
-	err := s.driver.Initialize(ctx)
+	err := s.driver.Create(ctx)
 	if err != nil {
 		s.logger.Errorf("Initialization failed: %v", err)
 		return empty, err
@@ -238,28 +238,6 @@ func (s *DriverServer) ListSnapshots(ctx context.Context, _ *emptypb.Empty) (*pb
 	return &pb.ListSnapshotsResponse{Snapshots: snapshots}, nil
 }
 
-func (s *DriverServer) Register(ctx context.Context, empty *emptypb.Empty) (*emptypb.Empty, error) {
-	s.logger.Debug("Received Register request")
-	err := s.driver.Register(ctx)
-	if err != nil {
-		s.logger.Errorf("Register failed: %v", err)
-		return empty, err
-	}
-	s.logger.Debug("Register succeeded")
-	return empty, nil
-}
-
-func (s *DriverServer) Unregister(ctx context.Context, empty *emptypb.Empty) (*emptypb.Empty, error) {
-	s.logger.Debug("Received Unregister request")
-	err := s.driver.Unregister(ctx)
-	if err != nil {
-		s.logger.Errorf("Unregister failed: %v", err)
-		return empty, err
-	}
-	s.logger.Debug("Unregister succeeded")
-	return empty, nil
-}
-
 func (s *DriverServer) ForwardGuestAgent(_ context.Context, _ *emptypb.Empty) (*pb.ForwardGuestAgentResponse, error) {
 	s.logger.Debug("Received ForwardGuestAgent request")
 	return &pb.ForwardGuestAgentResponse{ShouldForward: s.driver.ForwardGuestAgent()}, nil
diff --git a/pkg/driver/external/server/server.go b/pkg/driver/external/server/server.go
index a40d4b1b..eaf130eb 100644
--- a/pkg/driver/external/server/server.go
+++ b/pkg/driver/external/server/server.go
@@ -25,9 +25,9 @@ import (
 	"github.com/lima-vm/lima/v2/pkg/driver"
 	pb "github.com/lima-vm/lima/v2/pkg/driver/external"
 	"github.com/lima-vm/lima/v2/pkg/driver/external/client"
+	"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 	"github.com/lima-vm/lima/v2/pkg/registry"
-	"github.com/lima-vm/lima/v2/pkg/store"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
 )
 
 type DriverServer struct {
@@ -164,7 +164,7 @@ func Start(extDriver *registry.ExternalDriver, instName string) error {
 		return fmt.Errorf("failed to create stdout pipe for external driver: %w", err)
 	}
 
-	instanceDir, err := store.InstanceDir(extDriver.InstanceName)
+	instanceDir, err := dirnames.InstanceDir(extDriver.InstanceName)
 	if err != nil {
 		cancel()
 		return fmt.Errorf("failed to determine instance directory: %w", err)
diff --git a/pkg/driver/qemu/qemu.go b/pkg/driver/qemu/qemu.go
index 2138893e..858dad02 100644
--- a/pkg/driver/qemu/qemu.go
+++ b/pkg/driver/qemu/qemu.go
@@ -30,19 +30,20 @@ import (
 
 	"github.com/lima-vm/lima/v2/pkg/fileutils"
 	"github.com/lima-vm/lima/v2/pkg/iso9660util"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 	"github.com/lima-vm/lima/v2/pkg/limayaml"
 	"github.com/lima-vm/lima/v2/pkg/networks"
 	"github.com/lima-vm/lima/v2/pkg/networks/usernet"
 	"github.com/lima-vm/lima/v2/pkg/osutil"
 	"github.com/lima-vm/lima/v2/pkg/qemuimgutil"
 	"github.com/lima-vm/lima/v2/pkg/store"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
 )
 
 type Config struct {
 	Name         string
 	InstanceDir  string
-	LimaYAML     *limayaml.LimaYAML
+	LimaYAML     *limatype.LimaYAML
 	SSHLocalPort int
 	SSHAddress   string
 	VirtioGA     bool
@@ -384,8 +385,8 @@ func adjustMemBytesDarwinARM64HVF(memBytes int64, accel string) int64 {
 }
 
 // qemuMachine returns string to use for -machine.
-func qemuMachine(arch limayaml.Arch) string {
-	if arch == limayaml.X8664 {
+func qemuMachine(arch limatype.Arch) string {
+	if arch == limatype.X8664 {
 		return "q35"
 	}
 	return "virt"
@@ -404,7 +405,7 @@ func audioDevice() string {
 	return "oss"
 }
 
-func defaultCPUType() limayaml.CPUType {
+func defaultCPUType() limatype.CPUType {
 	// x86_64 + TCG + max was previously unstable until 2021.
 	// https://bugzilla.redhat.com/show_bug.cgi?id=1999700
 	// https://bugs.launchpad.net/qemu/+bug/1748296
@@ -417,13 +418,13 @@ func defaultCPUType() limayaml.CPUType {
 		// TODO: remove this if "max" works with the latest qemu
 		defaultX8664 = "qemu64"
 	}
-	cpuType := map[limayaml.Arch]string{
-		limayaml.AARCH64: "max",
-		limayaml.ARMV7L:  "max",
-		limayaml.X8664:   defaultX8664,
-		limayaml.PPC64LE: "max",
-		limayaml.RISCV64: "max",
-		limayaml.S390X:   "max",
+	cpuType := map[limatype.Arch]string{
+		limatype.AARCH64: "max",
+		limatype.ARMV7L:  "max",
+		limatype.X8664:   defaultX8664,
+		limatype.PPC64LE: "max",
+		limatype.RISCV64: "max",
+		limatype.S390X:   "max",
 	}
 	for arch := range cpuType {
 		if limayaml.IsNativeArch(arch) && limayaml.IsAccelOS() {
@@ -431,7 +432,7 @@ func defaultCPUType() limayaml.CPUType {
 				cpuType[arch] = "host"
 			}
 		}
-		if arch == limayaml.X8664 && runtime.GOOS == "darwin" {
+		if arch == limatype.X8664 && runtime.GOOS == "darwin" {
 			// disable AVX-512, since it requires trapping instruction faults in guest
 			// Enterprise Linux requires either v2 (SSE4) or v3 (AVX2), but not yet v4.
 			cpuType[arch] += ",-avx512vl"
@@ -445,11 +446,11 @@ func defaultCPUType() limayaml.CPUType {
 	return cpuType
 }
 
-func resolveCPUType(y *limayaml.LimaYAML) string {
+func resolveCPUType(y *limatype.LimaYAML) string {
 	cpuType := defaultCPUType()
 	var overrideCPUType bool
 	for k, v := range y.VMOpts.QEMU.CPUType {
-		if !slices.Contains(limayaml.ArchTypes, *y.Arch) {
+		if !slices.Contains(limatype.ArchTypes, *y.Arch) {
 			logrus.Warnf("field `vmOpts.qemu.cpuType` uses unsupported arch %q", k)
 			continue
 		}
@@ -508,7 +509,7 @@ func Cmdline(ctx context.Context, cfg Config) (exe string, args []string, err er
 	memBytes = adjustMemBytesDarwinARM64HVF(memBytes, accel)
 	args = appendArgsIfNoConflict(args, "-m", strconv.Itoa(int(memBytes>>20)))
 
-	if *y.MountType == limayaml.VIRTIOFS {
+	if *y.MountType == limatype.VIRTIOFS {
 		args = appendArgsIfNoConflict(args, "-object",
 			fmt.Sprintf("memory-backend-file,id=virtiofs-shm,size=%s,mem-path=/dev/shm,share=on", strconv.Itoa(int(memBytes))))
 		args = appendArgsIfNoConflict(args, "-numa", "node,memdev=virtiofs-shm")
@@ -532,7 +533,7 @@ func Cmdline(ctx context.Context, cfg Config) (exe string, args []string, err er
 
 	// Machine
 	switch *y.Arch {
-	case limayaml.X8664:
+	case limatype.X8664:
 		switch accel {
 		case "tcg":
 			// use q35 machine with vmware io port disabled.
@@ -551,10 +552,10 @@ func Cmdline(ctx context.Context, cfg Config) (exe string, args []string, err er
 		default:
 			args = appendArgsIfNoConflict(args, "-machine", "q35,accel="+accel)
 		}
-	case limayaml.AARCH64:
+	case limatype.AARCH64:
 		machine := "virt,accel=" + accel
 		args = appendArgsIfNoConflict(args, "-machine", machine)
-	case limayaml.RISCV64:
+	case limatype.RISCV64:
 		// https://github.com/tianocore/edk2/blob/edk2-stable202408/OvmfPkg/RiscVVirt/README.md#test
 		// > Note: the `acpi=off` machine property is specified because Linux guest
 		// > support for ACPI (that is, the ACPI consumer side) is a work in progress.
@@ -562,13 +563,13 @@ func Cmdline(ctx context.Context, cfg Config) (exe string, args []string, err er
 		// > yourself.
 		machine := "virt,acpi=off,accel=" + accel
 		args = appendArgsIfNoConflict(args, "-machine", machine)
-	case limayaml.ARMV7L:
+	case limatype.ARMV7L:
 		machine := "virt,accel=" + accel
 		args = appendArgsIfNoConflict(args, "-machine", machine)
-	case limayaml.PPC64LE:
+	case limatype.PPC64LE:
 		machine := "pseries,accel=" + accel
 		args = appendArgsIfNoConflict(args, "-machine", machine)
-	case limayaml.S390X:
+	case limatype.S390X:
 		machine := "s390-ccw-virtio,accel=" + accel
 		args = appendArgsIfNoConflict(args, "-machine", machine)
 	}
@@ -579,11 +580,11 @@ func Cmdline(ctx context.Context, cfg Config) (exe string, args []string, err er
 
 	// Firmware
 	legacyBIOS := *y.Firmware.LegacyBIOS
-	if legacyBIOS && *y.Arch != limayaml.X8664 && *y.Arch != limayaml.ARMV7L {
+	if legacyBIOS && *y.Arch != limatype.X8664 && *y.Arch != limatype.ARMV7L {
 		logrus.Warnf("field `firmware.legacyBIOS` is not supported for architecture %q, ignoring", *y.Arch)
 		legacyBIOS = false
 	}
-	noFirmware := *y.Arch == limayaml.PPC64LE || *y.Arch == limayaml.S390X || legacyBIOS
+	noFirmware := *y.Arch == limatype.PPC64LE || *y.Arch == limatype.S390X || legacyBIOS
 	if !noFirmware {
 		var firmware string
 		firmwareInBios := runtime.GOOS == "windows"
@@ -595,7 +596,7 @@ func Cmdline(ctx context.Context, cfg Config) (exe string, args []string, err er
 				firmwareInBios = b
 			}
 		}
-		firmwareInBios = firmwareInBios && *y.Arch == limayaml.X8664
+		firmwareInBios = firmwareInBios && *y.Arch == limatype.X8664
 		downloadedFirmware := filepath.Join(cfg.InstanceDir, filenames.QemuEfiCodeFD)
 		firmwareWithVars := filepath.Join(cfg.InstanceDir, filenames.QemuEfiFullFD)
 		if firmwareInBios {
@@ -608,7 +609,7 @@ func Cmdline(ctx context.Context, cfg Config) (exe string, args []string, err er
 			loop:
 				for _, f := range y.Firmware.Images {
 					switch f.VMType {
-					case "", limayaml.QEMU:
+					case "", limatype.QEMU:
 						if f.Arch == *y.Arch {
 							if _, err = fileutils.DownloadFile(ctx, downloadedFirmware, f.File, true, "UEFI code "+f.Location, *y.Arch); err != nil {
 								logrus.WithError(err).Warnf("failed to download %q", f.Location)
@@ -768,7 +769,7 @@ func Cmdline(ctx context.Context, cfg Config) (exe string, args []string, err er
 		args = append(args, "-netdev", fmt.Sprintf("socket,id=net0,fd={{ fd_connect %q }}", qemuSock))
 	}
 	virtioNet := "virtio-net-pci"
-	if *y.Arch == limayaml.S390X {
+	if *y.Arch == limatype.S390X {
 		// virtio-net-pci does not work on EL, while it works on Ubuntu
 		// https://github.com/lima-vm/lima/pull/3319/files#r1986388345
 		virtioNet = "virtio-net-ccw"
@@ -854,7 +855,7 @@ func Cmdline(ctx context.Context, cfg Config) (exe string, args []string, err er
 	if *y.Video.Display != "none" {
 		switch *y.Arch {
 		// FIXME: use virtio-gpu on all the architectures
-		case limayaml.X8664, limayaml.RISCV64:
+		case limatype.X8664, limatype.RISCV64:
 			args = append(args, "-device", "virtio-vga")
 		default:
 			args = append(args, "-device", "virtio-gpu")
@@ -885,7 +886,7 @@ func Cmdline(ctx context.Context, cfg Config) (exe string, args []string, err er
 	// On ARM, the default serial is ttyAMA0, this PCI serial is ttyS0.
 	// https://gitlab.com/qemu-project/qemu/-/issues/1801#note_1494720586
 	switch *y.Arch {
-	case limayaml.AARCH64, limayaml.ARMV7L:
+	case limatype.AARCH64, limatype.ARMV7L:
 		serialpSock := filepath.Join(cfg.InstanceDir, filenames.SerialPCISock)
 		if err := os.RemoveAll(serialpSock); err != nil {
 			return "", nil, err
@@ -912,7 +913,7 @@ func Cmdline(ctx context.Context, cfg Config) (exe string, args []string, err er
 	args = append(args, "-chardev", fmt.Sprintf("socket,id=%s,path=%s,server=on,wait=off,logfile=%s", serialvChardev, serialvSock, serialvLog))
 	// max_ports=1 is required for https://github.com/lima-vm/lima/issues/1689 https://github.com/lima-vm/lima/issues/1691
 	serialvMaxPorts := 1
-	if *y.Arch == limayaml.S390X {
+	if *y.Arch == limatype.S390X {
 		serialvMaxPorts++ // needed to avoid `virtio-serial-bus: Out-of-range port id specified, max. allowed: 0`
 	}
 	args = append(args, "-device", fmt.Sprintf("virtio-serial-pci,id=virtio-serial0,max_ports=%d", serialvMaxPorts))
@@ -920,7 +921,7 @@ func Cmdline(ctx context.Context, cfg Config) (exe string, args []string, err er
 
 	// We also want to enable vsock here, but QEMU does not support vsock for macOS hosts
 
-	if *y.MountType == limayaml.NINEP || *y.MountType == limayaml.VIRTIOFS {
+	if *y.MountType == limatype.NINEP || *y.MountType == limatype.VIRTIOFS {
 		for i, f := range y.Mounts {
 			tag := fmt.Sprintf("mount%d", i)
 			if err := os.MkdirAll(f.Location, 0o755); err != nil {
@@ -928,7 +929,7 @@ func Cmdline(ctx context.Context, cfg Config) (exe string, args []string, err er
 			}
 
 			switch *y.MountType {
-			case limayaml.NINEP:
+			case limatype.NINEP:
 				options := "local"
 				options += fmt.Sprintf(",mount_tag=%s", tag)
 				options += fmt.Sprintf(",path=%s", f.Location)
@@ -937,7 +938,7 @@ func Cmdline(ctx context.Context, cfg Config) (exe string, args []string, err er
 					options += ",readonly"
 				}
 				args = append(args, "-virtfs", options)
-			case limayaml.VIRTIOFS:
+			case limatype.VIRTIOFS:
 				// Note that read-only mode is not supported on the QEMU/virtiofsd side yet:
 				// https://gitlab.com/virtio-fs/virtiofsd/-/issues/97
 				chardev := fmt.Sprintf("char-virtiofs-%d", i)
@@ -1067,11 +1068,11 @@ func VirtiofsdCmdline(cfg Config, mountIndex int) ([]string, error) {
 }
 
 // qemuArch returns the arch string used by qemu.
-func qemuArch(arch limayaml.Arch) string {
+func qemuArch(arch limatype.Arch) string {
 	switch arch {
-	case limayaml.ARMV7L:
+	case limatype.ARMV7L:
 		return "arm"
-	case limayaml.PPC64LE:
+	case limatype.PPC64LE:
 		return "ppc64"
 	default:
 		return arch
@@ -1079,14 +1080,14 @@ func qemuArch(arch limayaml.Arch) string {
 }
 
 // qemuEdk2 returns the arch string used by `/usr/local/share/qemu/edk2-*-code.fd`.
-func qemuEdk2Arch(arch limayaml.Arch) string {
-	if arch == limayaml.RISCV64 {
+func qemuEdk2Arch(arch limatype.Arch) string {
+	if arch == limatype.RISCV64 {
 		return "riscv"
 	}
 	return qemuArch(arch)
 }
 
-func Exe(arch limayaml.Arch) (exe string, args []string, err error) {
+func Exe(arch limatype.Arch) (exe string, args []string, err error) {
 	exeBase := "qemu-system-" + qemuArch(arch)
 	envK := "QEMU_SYSTEM_" + strings.ToUpper(qemuArch(arch))
 	if envV := os.Getenv(envK); envV != "" {
@@ -1106,7 +1107,7 @@ func Exe(arch limayaml.Arch) (exe string, args []string, err error) {
 	return exe, args, nil
 }
 
-func Accel(arch limayaml.Arch) string {
+func Accel(arch limatype.Arch) string {
 	if limayaml.IsNativeArch(arch) {
 		switch runtime.GOOS {
 		case "darwin":
@@ -1149,9 +1150,9 @@ func getQemuVersion(ctx context.Context, qemuExe string) (*semver.Version, error
 	return parseQemuVersion(stdout.String())
 }
 
-func getFirmware(qemuExe string, arch limayaml.Arch) (string, error) {
+func getFirmware(qemuExe string, arch limatype.Arch) (string, error) {
 	switch arch {
-	case limayaml.X8664, limayaml.AARCH64, limayaml.ARMV7L, limayaml.RISCV64:
+	case limatype.X8664, limatype.AARCH64, limatype.ARMV7L, limatype.RISCV64:
 	default:
 		return "", fmt.Errorf("unexpected architecture: %q", arch)
 	}
@@ -1174,7 +1175,7 @@ func getFirmware(qemuExe string, arch limayaml.Arch) (string, error) {
 	}
 
 	switch arch {
-	case limayaml.X8664:
+	case limatype.X8664:
 		// Archlinux package "edk2-ovmf"
 		// @see: https://archlinux.org/packages/extra/any/edk2-ovmf/files
 		candidates = append(candidates, "/usr/share/edk2/x64/OVMF_CODE.4m.fd")
@@ -1185,7 +1186,7 @@ func getFirmware(qemuExe string, arch limayaml.Arch) (string, error) {
 		candidates = append(candidates, "/usr/share/edk2/ovmf/OVMF_CODE.fd")
 		// openSUSE package "qemu-ovmf-x86_64"
 		candidates = append(candidates, "/usr/share/qemu/ovmf-x86_64.bin")
-	case limayaml.AARCH64:
+	case limatype.AARCH64:
 		// Archlinux package "edk2-aarch64"
 		// @see: https://archlinux.org/packages/extra/any/edk2-aarch64/files
 		candidates = append(candidates, "/usr/share/edk2/aarch64/QEMU_CODE.fd")
@@ -1194,14 +1195,14 @@ func getFirmware(qemuExe string, arch limayaml.Arch) (string, error) {
 		candidates = append(candidates, "/usr/share/AAVMF/AAVMF_CODE.fd")
 		// Debian package "qemu-efi-aarch64" (unpadded, backwards compatibility)
 		candidates = append(candidates, "/usr/share/qemu-efi-aarch64/QEMU_EFI.fd")
-	case limayaml.ARMV7L:
+	case limatype.ARMV7L:
 		// Archlinux package "edk2-arm"
 		// @see: https://archlinux.org/packages/extra/any/edk2-arm/files
 		candidates = append(candidates, "/usr/share/edk2/arm/QEMU_CODE.fd")
 		// Debian package "qemu-efi-arm"
 		// Fedora package "edk2-arm"
 		candidates = append(candidates, "/usr/share/AAVMF/AAVMF32_CODE.fd")
-	case limayaml.RISCV64:
+	case limatype.RISCV64:
 		// Debian package "qemu-efi-riscv64"
 		candidates = append(candidates, "/usr/share/qemu-efi-riscv64/RISCV_VIRT_CODE.fd")
 		// Fedora package "edk2-riscv64"
@@ -1216,17 +1217,17 @@ func getFirmware(qemuExe string, arch limayaml.Arch) (string, error) {
 		}
 	}
 
-	if arch == limayaml.X8664 {
+	if arch == limatype.X8664 {
 		return "", fmt.Errorf("could not find firmware for %q (hint: try setting `firmware.legacyBIOS` to `true`)", arch)
 	}
 	qemuArch := strings.TrimPrefix(filepath.Base(qemuExe), "qemu-system-")
 	return "", fmt.Errorf("could not find firmware for %q (hint: try copying the \"edk-%s-code.fd\" firmware to $HOME/.local/share/qemu/)", arch, qemuArch)
 }
 
-func getFirmwareVars(qemuExe string, arch limayaml.Arch) (string, error) {
+func getFirmwareVars(qemuExe string, arch limatype.Arch) (string, error) {
 	var targetArch string
 	switch arch {
-	case limayaml.X8664:
+	case limatype.X8664:
 		targetArch = "i386" // vars are unified between i386 and x86_64 and normally only former is bundled
 	default:
 		return "", fmt.Errorf("unexpected architecture: %q", arch)
diff --git a/pkg/driver/qemu/qemu_driver.go b/pkg/driver/qemu/qemu_driver.go
index 8e7f49e2..2310ad6d 100644
--- a/pkg/driver/qemu/qemu_driver.go
+++ b/pkg/driver/qemu/qemu_driver.go
@@ -16,6 +16,7 @@ import (
 	"os/exec"
 	"path/filepath"
 	"runtime"
+	"slices"
 	"strconv"
 	"strings"
 	"text/template"
@@ -29,15 +30,17 @@ import (
 	"github.com/lima-vm/lima/v2/pkg/driver"
 	"github.com/lima-vm/lima/v2/pkg/driver/qemu/entitlementutil"
 	"github.com/lima-vm/lima/v2/pkg/executil"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 	"github.com/lima-vm/lima/v2/pkg/limayaml"
 	"github.com/lima-vm/lima/v2/pkg/networks/usernet"
 	"github.com/lima-vm/lima/v2/pkg/osutil"
-	"github.com/lima-vm/lima/v2/pkg/store"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
+	"github.com/lima-vm/lima/v2/pkg/ptr"
+	"github.com/lima-vm/lima/v2/pkg/version/versionutil"
 )
 
 type LimaQemuDriver struct {
-	Instance     *store.Instance
+	Instance     *limatype.Instance
 	SSHLocalPort int
 	vSockPort    int
 	virtioPort   string
@@ -64,7 +67,7 @@ func New() *LimaQemuDriver {
 	}
 }
 
-func (l *LimaQemuDriver) Configure(inst *store.Instance) *driver.ConfiguredDriver {
+func (l *LimaQemuDriver) Configure(inst *limatype.Instance) *driver.ConfiguredDriver {
 	l.Instance = inst
 	l.SSHLocalPort = inst.SSHLocalPort
 
@@ -79,14 +82,155 @@ func (l *LimaQemuDriver) Validate(ctx context.Context) error {
 			return err
 		}
 	}
+	if err := l.validateMountType(); err != nil {
+		return err
+	}
+
+	return nil
+}
 
-	if *l.Instance.Config.MountType == limayaml.VIRTIOFS && runtime.GOOS != "linux" {
+// Helper method for mount type validation.
+func (l *LimaQemuDriver) validateMountType() error {
+	if l.Instance == nil || l.Instance.Config == nil {
+		return errors.New("instance configuration is not set")
+	}
+
+	cfg := l.Instance.Config
+
+	if cfg.MountType != nil && *cfg.MountType == limatype.VIRTIOFS && runtime.GOOS != "linux" {
 		return fmt.Errorf("field `mountType` must be %q or %q for QEMU driver on non-Linux, got %q",
-			limayaml.REVSSHFS, limayaml.NINEP, *l.Instance.Config.MountType)
+			limatype.REVSSHFS, limatype.NINEP, *cfg.MountType)
+	}
+	if cfg.MountTypesUnsupported != nil && cfg.MountType != nil && slices.Contains(cfg.MountTypesUnsupported, *cfg.MountType) {
+		return fmt.Errorf("mount type %q is explicitly unsupported", *cfg.MountType)
 	}
+	if runtime.GOOS == "windows" && cfg.MountType != nil && *cfg.MountType == limatype.NINEP {
+		return fmt.Errorf("mount type %q is not supported on Windows", limatype.NINEP)
+	}
+
 	return nil
 }
 
+func (l *LimaQemuDriver) FillConfig(cfg *limatype.LimaYAML, filePath string) error {
+	if cfg.VMType == nil {
+		cfg.VMType = ptr.Of(limatype.QEMU)
+	}
+
+	instDir := filepath.Dir(filePath)
+
+	if cfg.Video.VNC.Display == nil || *cfg.Video.VNC.Display == "" {
+		cfg.Video.VNC.Display = ptr.Of("127.0.0.1:0,to=9")
+	}
+
+	if cfg.VMOpts.QEMU.CPUType == nil {
+		cfg.VMOpts.QEMU.CPUType = limatype.CPUType{}
+	}
+
+	//nolint:staticcheck // Migration of top-level CPUTYPE if specified
+	if len(cfg.CPUType) > 0 {
+		logrus.Warn("The top-level `cpuType` field is deprecated and will be removed in a future release. Please migrate to `vmOpts.qemu.cpuType`.")
+		for arch, v := range cfg.CPUType {
+			if v == "" {
+				continue
+			}
+			if existing, ok := cfg.VMOpts.QEMU.CPUType[arch]; ok && existing != "" && existing != v {
+				logrus.Warnf("Conflicting cpuType for arch %q: top-level=%q, vmOpts.qemu=%q; using vmOpts.qemu value", arch, v, existing)
+				continue
+			}
+			cfg.VMOpts.QEMU.CPUType[arch] = v
+		}
+		cfg.CPUType = nil
+	}
+
+	mountTypesUnsupported := make(map[string]struct{})
+	for _, f := range cfg.MountTypesUnsupported {
+		mountTypesUnsupported[f] = struct{}{}
+	}
+
+	if runtime.GOOS == "windows" {
+		// QEMU for Windows does not support 9p
+		mountTypesUnsupported[limatype.NINEP] = struct{}{}
+	}
+
+	if cfg.MountType == nil || *cfg.MountType == "" || *cfg.MountType == "default" {
+		cfg.MountType = ptr.Of(limatype.NINEP)
+		if _, ok := mountTypesUnsupported[limatype.NINEP]; ok {
+			// Use REVSSHFS if the instance does not support 9p
+			cfg.MountType = ptr.Of(limatype.REVSSHFS)
+		} else if limayaml.IsExistingInstanceDir(instDir) && !versionutil.GreaterEqual(limayaml.ExistingLimaVersion(instDir), "1.0.0") {
+			// Use REVSSHFS if the instance was created with Lima prior to v1.0
+			cfg.MountType = ptr.Of(limatype.REVSSHFS)
+		}
+	}
+
+	for i := range cfg.Mounts {
+		mount := &cfg.Mounts[i]
+		if mount.Virtiofs.QueueSize == nil && *cfg.MountType == limatype.VIRTIOFS {
+			cfg.Mounts[i].Virtiofs.QueueSize = ptr.Of(limayaml.DefaultVirtiofsQueueSize)
+		}
+	}
+
+	if _, ok := mountTypesUnsupported[*cfg.MountType]; ok {
+		return fmt.Errorf("mount type %q is explicitly unsupported", *cfg.MountType)
+	}
+
+	return nil
+}
+
+func (l *LimaQemuDriver) AcceptConfig(cfg *limatype.LimaYAML, _ string) error {
+	if l.Instance == nil {
+		l.Instance = &limatype.Instance{}
+	}
+	l.Instance.Config = cfg
+
+	if err := l.Validate(context.Background()); err != nil {
+		return fmt.Errorf("config not supported by the QEMU driver: %w", err)
+	}
+
+	if cfg.VMOpts.QEMU.MinimumVersion != nil {
+		if _, err := semver.NewVersion(*cfg.VMOpts.QEMU.MinimumVersion); err != nil {
+			return fmt.Errorf("field `vmOpts.qemu.minimumVersion` must be a semvar value, got %q: %w", *cfg.VMOpts.QEMU.MinimumVersion, err)
+		}
+	}
+
+	if runtime.GOOS == "darwin" {
+		if cfg.Arch != nil && limayaml.IsNativeArch(*cfg.Arch) {
+			logrus.Debugf("ResolveVMType: resolved VMType %q (non-native arch=%q is specified in []*LimaYAML{o,y,d})", "qemu", *cfg.Arch)
+			return nil
+		}
+		if limayaml.ResolveArch(cfg.Arch) == limatype.X8664 && cfg.Firmware.LegacyBIOS != nil && *cfg.Firmware.LegacyBIOS {
+			logrus.Debugf("ResolveVMType: resolved VMType %q (firmware.legacyBIOS is specified in []*LimaYAML{o,y,d} on x86_64)", "qemu")
+			return nil
+		}
+		if cfg.MountType != nil && *cfg.MountType == limatype.NINEP {
+			logrus.Debugf("ResolveVMType: resolved VMType %q (mountType=%q is specified in []*LimaYAML{o,y,d})", "qemu", limatype.NINEP)
+			return nil
+		}
+		if cfg.Audio.Device != nil {
+			switch *cfg.Audio.Device {
+			case "", "none", "default", "vz":
+				// NOP
+			default:
+				logrus.Debugf("ResolveVMType: resolved VMType %q (audio.device=%q is specified in []*LimaYAML{o,y,d})", "qemu", *cfg.Audio.Device)
+				return nil
+			}
+		}
+		if cfg.Video.Display != nil {
+			display := *cfg.Video.Display
+			if display != "" && display != "none" && display != "default" && display != "vz" {
+				logrus.Debugf("ResolveVMType: resolved VMType %q (video.display=%q is specified in []*LimaYAML{o,y,d})", "qemu", display)
+				return nil
+			}
+		}
+	}
+
+	return nil
+}
+
+func (l *LimaQemuDriver) BootScripts() (map[string][]byte, error) {
+	return nil, nil
+}
+
 func (l *LimaQemuDriver) CreateDisk(ctx context.Context) error {
 	qCfg := Config{
 		Name:        l.Instance.Name,
@@ -118,7 +262,7 @@ func (l *LimaQemuDriver) Start(_ context.Context) (chan error, error) {
 	}
 
 	var vhostCmds []*exec.Cmd
-	if *l.Instance.Config.MountType == limayaml.VIRTIOFS {
+	if *l.Instance.Config.MountType == limatype.VIRTIOFS {
 		vhostExe, err := FindVirtiofsd(ctx, qExe)
 		if err != nil {
 			return nil, err
@@ -276,7 +420,7 @@ func (l *LimaQemuDriver) checkBinarySignature(ctx context.Context) error {
 		return err
 	}
 	// The codesign --xml option is only available on macOS Monterey and later
-	if !macOSProductVersion.LessThan(*semver.New("12.0.0")) {
+	if !macOSProductVersion.LessThan(*semver.New("12.0.0")) && l.Instance.Arch != "" {
 		qExe, _, err := Exe(l.Instance.Arch)
 		if err != nil {
 			return fmt.Errorf("failed to find the QEMU binary for the architecture %q: %w", l.Instance.Arch, err)
@@ -440,7 +584,7 @@ func (l *LimaQemuDriver) DeleteSnapshot(ctx context.Context, tag string) error {
 		InstanceDir: l.Instance.Dir,
 		LimaYAML:    l.Instance.Config,
 	}
-	return Del(ctx, qCfg, l.Instance.Status == store.StatusRunning, tag)
+	return Del(ctx, qCfg, l.Instance.Status == limatype.StatusRunning, tag)
 }
 
 func (l *LimaQemuDriver) CreateSnapshot(ctx context.Context, tag string) error {
@@ -449,7 +593,7 @@ func (l *LimaQemuDriver) CreateSnapshot(ctx context.Context, tag string) error {
 		InstanceDir: l.Instance.Dir,
 		LimaYAML:    l.Instance.Config,
 	}
-	return Save(ctx, qCfg, l.Instance.Status == store.StatusRunning, tag)
+	return Save(ctx, qCfg, l.Instance.Status == limatype.StatusRunning, tag)
 }
 
 func (l *LimaQemuDriver) ApplySnapshot(ctx context.Context, tag string) error {
@@ -458,7 +602,7 @@ func (l *LimaQemuDriver) ApplySnapshot(ctx context.Context, tag string) error {
 		InstanceDir: l.Instance.Dir,
 		LimaYAML:    l.Instance.Config,
 	}
-	return Load(ctx, qCfg, l.Instance.Status == store.StatusRunning, tag)
+	return Load(ctx, qCfg, l.Instance.Status == limatype.StatusRunning, tag)
 }
 
 func (l *LimaQemuDriver) ListSnapshots(ctx context.Context) (string, error) {
@@ -467,7 +611,7 @@ func (l *LimaQemuDriver) ListSnapshots(ctx context.Context) (string, error) {
 		InstanceDir: l.Instance.Dir,
 		LimaYAML:    l.Instance.Config,
 	}
-	return List(ctx, qCfg, l.Instance.Status == store.StatusRunning)
+	return List(ctx, qCfg, l.Instance.Status == limatype.StatusRunning)
 }
 
 func (l *LimaQemuDriver) GuestAgentConn(ctx context.Context) (net.Conn, string, error) {
@@ -537,10 +681,27 @@ func (l *LimaQemuDriver) Info() driver.Info {
 	info.CanRunGUI = false
 	info.VirtioPort = l.virtioPort
 	info.VsockPort = l.vSockPort
+
+	info.Features = driver.DriverFeatures{
+		DynamicSSHAddress:    false,
+		SkipSocketForwarding: false,
+	}
 	return info
 }
 
-func (l *LimaQemuDriver) Initialize(_ context.Context) error {
+func (l *LimaQemuDriver) SSHAddress(_ context.Context) (string, error) {
+	return "127.0.0.1", nil
+}
+
+func (l *LimaQemuDriver) InspectStatus(_ context.Context, _ *limatype.Instance) string {
+	return ""
+}
+
+func (l *LimaQemuDriver) Create(_ context.Context) error {
+	return nil
+}
+
+func (l *LimaQemuDriver) Delete(_ context.Context) error {
 	return nil
 }
 
diff --git a/pkg/driver/vz/boot/05-rosetta-volume.sh b/pkg/driver/vz/boot/05-rosetta-volume.sh
new file mode 100755
index 00000000..9fa517ae
--- /dev/null
+++ b/pkg/driver/vz/boot/05-rosetta-volume.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+# SPDX-FileCopyrightText: Copyright The Lima Authors
+# SPDX-License-Identifier: Apache-2.0
+
+set -eux -o pipefail
+
+if [ "$LIMA_CIDATA_ROSETTA_ENABLED" != "true" ]; then
+	exit 0
+fi
+
+if [ -f /etc/alpine-release ]; then
+	rc-service procfs start --ifnotstarted
+	rc-service qemu-binfmt stop --ifexists --ifstarted
+fi
+
+binfmt_entry=/proc/sys/fs/binfmt_misc/rosetta
+binfmtd_conf=/usr/lib/binfmt.d/rosetta.conf
+if [ "$LIMA_CIDATA_ROSETTA_BINFMT" = "true" ]; then
+	rosetta_binfmt=":rosetta:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00:\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/mnt/lima-rosetta/rosetta:OCF"
+
+	# If rosetta is not registered in binfmt_misc, register it.
+	[ -f "$binfmt_entry" ] || echo "$rosetta_binfmt" >/proc/sys/fs/binfmt_misc/register
+
+	# Create binfmt.d(5) configuration to prioritize rosetta even if qemu-user-static is installed on systemd based systems.
+	# If the binfmt.d directory exists, consider systemd-binfmt.service(8) to be enabled and create the configuration file.
+	[ ! -d "$(dirname "$binfmtd_conf")" ] || [ -f "$binfmtd_conf" ] || echo "$rosetta_binfmt" >"$binfmtd_conf"
+else
+	# unregister rosetta from binfmt_misc if it exists
+	[ ! -f "$binfmt_entry" ] || echo -1 >"$binfmt_entry"
+	# remove binfmt.d(5) configuration if it exists
+	[ ! -f "$binfmtd_conf" ] || rm "$binfmtd_conf"
+fi
diff --git a/pkg/driver/vz/disk.go b/pkg/driver/vz/disk.go
index 35f28f52..9cb81e06 100644
--- a/pkg/driver/vz/disk.go
+++ b/pkg/driver/vz/disk.go
@@ -14,11 +14,11 @@ import (
 
 	"github.com/lima-vm/lima/v2/pkg/imgutil/proxyimgutil"
 	"github.com/lima-vm/lima/v2/pkg/iso9660util"
-	"github.com/lima-vm/lima/v2/pkg/store"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 )
 
-func EnsureDisk(ctx context.Context, inst *store.Instance) error {
+func EnsureDisk(ctx context.Context, inst *limatype.Instance) error {
 	diffDisk := filepath.Join(inst.Dir, filenames.DiffDisk)
 	if _, err := os.Stat(diffDisk); err == nil || !errors.Is(err, os.ErrNotExist) {
 		// disk is already ensured
diff --git a/pkg/driver/vz/vm_darwin.go b/pkg/driver/vz/vm_darwin.go
index aec3a8a0..342f73fe 100644
--- a/pkg/driver/vz/vm_darwin.go
+++ b/pkg/driver/vz/vm_darwin.go
@@ -27,12 +27,13 @@ import (
 
 	"github.com/lima-vm/lima/v2/pkg/imgutil/proxyimgutil"
 	"github.com/lima-vm/lima/v2/pkg/iso9660util"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 	"github.com/lima-vm/lima/v2/pkg/limayaml"
 	"github.com/lima-vm/lima/v2/pkg/networks"
 	"github.com/lima-vm/lima/v2/pkg/networks/usernet"
 	"github.com/lima-vm/lima/v2/pkg/osutil"
 	"github.com/lima-vm/lima/v2/pkg/store"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
 )
 
 // diskImageCachingMode is set to DiskImageCachingModeCached so as to avoid disk corruption on ARM:
@@ -51,7 +52,7 @@ type virtualMachineWrapper struct {
 // Hold all *os.File created via socketpair() so that they won't get garbage collected. f.FD() gets invalid if f gets garbage collected.
 var vmNetworkFiles = make([]*os.File, 1)
 
-func startVM(ctx context.Context, inst *store.Instance, sshLocalPort int) (*virtualMachineWrapper, chan error, error) {
+func startVM(ctx context.Context, inst *limatype.Instance, sshLocalPort int) (*virtualMachineWrapper, chan error, error) {
 	usernetClient, err := startUsernet(ctx, inst)
 	if err != nil {
 		return nil, nil, err
@@ -128,7 +129,7 @@ func startVM(ctx context.Context, inst *store.Instance, sshLocalPort int) (*virt
 	return wrapper, errCh, err
 }
 
-func startUsernet(ctx context.Context, inst *store.Instance) (*usernet.Client, error) {
+func startUsernet(ctx context.Context, inst *limatype.Instance) (*usernet.Client, error) {
 	if firstUsernetIndex := limayaml.FirstUsernetIndex(inst.Config); firstUsernetIndex != -1 {
 		nwName := inst.Config.Networks[firstUsernetIndex].Lima
 		return usernet.NewClientByName(nwName), nil
@@ -161,7 +162,7 @@ func startUsernet(ctx context.Context, inst *store.Instance) (*usernet.Client, e
 	return usernet.NewClient(endpointSock, subnetIP), err
 }
 
-func createVM(ctx context.Context, inst *store.Instance) (*vz.VirtualMachine, error) {
+func createVM(ctx context.Context, inst *limatype.Instance) (*vz.VirtualMachine, error) {
 	vmConfig, err := createInitialConfig(inst)
 	if err != nil {
 		return nil, err
@@ -207,7 +208,7 @@ func createVM(ctx context.Context, inst *store.Instance) (*vz.VirtualMachine, er
 	return vz.NewVirtualMachine(vmConfig)
 }
 
-func createInitialConfig(inst *store.Instance) (*vz.VirtualMachineConfiguration, error) {
+func createInitialConfig(inst *limatype.Instance) (*vz.VirtualMachineConfiguration, error) {
 	bootLoader, err := bootLoader(inst)
 	if err != nil {
 		return nil, err
@@ -229,7 +230,7 @@ func createInitialConfig(inst *store.Instance) (*vz.VirtualMachineConfiguration,
 	return vmConfig, nil
 }
 
-func attachPlatformConfig(inst *store.Instance, vmConfig *vz.VirtualMachineConfiguration) error {
+func attachPlatformConfig(inst *limatype.Instance, vmConfig *vz.VirtualMachineConfiguration) error {
 	machineIdentifier, err := getMachineIdentifier(inst)
 	if err != nil {
 		return err
@@ -264,7 +265,7 @@ func attachPlatformConfig(inst *store.Instance, vmConfig *vz.VirtualMachineConfi
 	return nil
 }
 
-func attachSerialPort(inst *store.Instance, config *vz.VirtualMachineConfiguration) error {
+func attachSerialPort(inst *limatype.Instance, config *vz.VirtualMachineConfiguration) error {
 	path := filepath.Join(inst.Dir, filenames.SerialVirtioLog)
 	serialPortAttachment, err := vz.NewFileSerialPortAttachment(path, false)
 	if err != nil {
@@ -302,7 +303,7 @@ func newVirtioNetworkDeviceConfiguration(attachment vz.NetworkDeviceAttachment,
 	return networkConfig, nil
 }
 
-func attachNetwork(ctx context.Context, inst *store.Instance, vmConfig *vz.VirtualMachineConfiguration) error {
+func attachNetwork(ctx context.Context, inst *limatype.Instance, vmConfig *vz.VirtualMachineConfiguration) error {
 	var configurations []*vz.VirtioNetworkDeviceConfiguration
 
 	// Configure default usernetwork with limayaml.MACAddress(inst.Dir) for eth0 interface
@@ -434,7 +435,7 @@ func validateDiskFormat(diskPath string) error {
 	return nil
 }
 
-func attachDisks(ctx context.Context, inst *store.Instance, vmConfig *vz.VirtualMachineConfiguration) error {
+func attachDisks(ctx context.Context, inst *limatype.Instance, vmConfig *vz.VirtualMachineConfiguration) error {
 	baseDiskPath := filepath.Join(inst.Dir, filenames.BaseDisk)
 	diffDiskPath := filepath.Join(inst.Dir, filenames.DiffDisk)
 	ciDataPath := filepath.Join(inst.Dir, filenames.CIDataISO)
@@ -523,7 +524,7 @@ func attachDisks(ctx context.Context, inst *store.Instance, vmConfig *vz.Virtual
 	return nil
 }
 
-func attachDisplay(inst *store.Instance, vmConfig *vz.VirtualMachineConfiguration) error {
+func attachDisplay(inst *limatype.Instance, vmConfig *vz.VirtualMachineConfiguration) error {
 	switch *inst.Config.Video.Display {
 	case "vz", "default":
 		graphicsDeviceConfiguration, err := vz.NewVirtioGraphicsDeviceConfiguration()
@@ -547,9 +548,9 @@ func attachDisplay(inst *store.Instance, vmConfig *vz.VirtualMachineConfiguratio
 	}
 }
 
-func attachFolderMounts(inst *store.Instance, vmConfig *vz.VirtualMachineConfiguration) error {
+func attachFolderMounts(inst *limatype.Instance, vmConfig *vz.VirtualMachineConfiguration) error {
 	var mounts []vz.DirectorySharingDeviceConfiguration
-	if *inst.Config.MountType == limayaml.VIRTIOFS {
+	if *inst.Config.MountType == limatype.VIRTIOFS {
 		for i, mount := range inst.Config.Mounts {
 			if _, err := os.Stat(mount.Location); errors.Is(err, os.ErrNotExist) {
 				err := os.MkdirAll(mount.Location, 0o750)
@@ -577,7 +578,7 @@ func attachFolderMounts(inst *store.Instance, vmConfig *vz.VirtualMachineConfigu
 		}
 	}
 
-	if *inst.Config.Rosetta.Enabled {
+	if *inst.Config.VMOpts.VZ.Rosetta.Enabled {
 		logrus.Info("Setting up Rosetta share")
 		directorySharingDeviceConfig, err := createRosettaDirectoryShareConfiguration()
 		if err != nil {
@@ -593,7 +594,7 @@ func attachFolderMounts(inst *store.Instance, vmConfig *vz.VirtualMachineConfigu
 	return nil
 }
 
-func attachAudio(inst *store.Instance, config *vz.VirtualMachineConfiguration) error {
+func attachAudio(inst *limatype.Instance, config *vz.VirtualMachineConfiguration) error {
 	switch *inst.Config.Audio.Device {
 	case "vz", "default":
 		outputStream, err := vz.NewVirtioSoundDeviceHostOutputStreamConfiguration()
@@ -616,7 +617,7 @@ func attachAudio(inst *store.Instance, config *vz.VirtualMachineConfiguration) e
 	}
 }
 
-func attachOtherDevices(_ *store.Instance, vmConfig *vz.VirtualMachineConfiguration) error {
+func attachOtherDevices(_ *limatype.Instance, vmConfig *vz.VirtualMachineConfiguration) error {
 	entropyConfig, err := vz.NewVirtioEntropyDeviceConfiguration()
 	if err != nil {
 		return err
@@ -690,7 +691,7 @@ func attachOtherDevices(_ *store.Instance, vmConfig *vz.VirtualMachineConfigurat
 	return nil
 }
 
-func getMachineIdentifier(inst *store.Instance) (*vz.GenericMachineIdentifier, error) {
+func getMachineIdentifier(inst *limatype.Instance) (*vz.GenericMachineIdentifier, error) {
 	identifier := filepath.Join(inst.Dir, filenames.VzIdentifier)
 	// Empty VzIdentifier can be created on cloning an instance.
 	if st, err := os.Stat(identifier); err != nil || (st != nil && st.Size() == 0) {
@@ -710,7 +711,7 @@ func getMachineIdentifier(inst *store.Instance) (*vz.GenericMachineIdentifier, e
 	return vz.NewGenericMachineIdentifierWithDataPath(identifier)
 }
 
-func bootLoader(inst *store.Instance) (vz.BootLoader, error) {
+func bootLoader(inst *limatype.Instance) (vz.BootLoader, error) {
 	linuxBootLoader, err := linuxBootLoader(inst)
 	if linuxBootLoader != nil {
 		return linuxBootLoader, nil
@@ -726,7 +727,7 @@ func bootLoader(inst *store.Instance) (vz.BootLoader, error) {
 	return vz.NewEFIBootLoader(vz.WithEFIVariableStore(efiVariableStore))
 }
 
-func linuxBootLoader(inst *store.Instance) (*vz.LinuxBootLoader, error) {
+func linuxBootLoader(inst *limatype.Instance) (*vz.LinuxBootLoader, error) {
 	kernel := filepath.Join(inst.Dir, filenames.Kernel)
 	kernelCmdline := filepath.Join(inst.Dir, filenames.KernelCmdline)
 	initrd := filepath.Join(inst.Dir, filenames.Initrd)
@@ -751,7 +752,7 @@ func linuxBootLoader(inst *store.Instance) (*vz.LinuxBootLoader, error) {
 	return vz.NewLinuxBootLoader(kernel, opt...)
 }
 
-func getEFI(inst *store.Instance) (*vz.EFIVariableStore, error) {
+func getEFI(inst *limatype.Instance) (*vz.EFIVariableStore, error) {
 	efi := filepath.Join(inst.Dir, filenames.VzEfi)
 	if _, err := os.Stat(efi); os.IsNotExist(err) {
 		return vz.NewEFIVariableStore(efi, vz.WithCreatingEFIVariableStore())
diff --git a/pkg/driver/vz/vz_driver_darwin.go b/pkg/driver/vz/vz_driver_darwin.go
index 17c70ca2..d21870da 100644
--- a/pkg/driver/vz/vz_driver_darwin.go
+++ b/pkg/driver/vz/vz_driver_darwin.go
@@ -7,9 +7,11 @@ package vz
 
 import (
 	"context"
+	"embed"
 	"errors"
 	"fmt"
 	"net"
+	"os"
 	"path/filepath"
 	"runtime"
 	"time"
@@ -19,10 +21,12 @@ import (
 	"github.com/sirupsen/logrus"
 
 	"github.com/lima-vm/lima/v2/pkg/driver"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 	"github.com/lima-vm/lima/v2/pkg/limayaml"
 	"github.com/lima-vm/lima/v2/pkg/osutil"
+	"github.com/lima-vm/lima/v2/pkg/ptr"
 	"github.com/lima-vm/lima/v2/pkg/reflectutil"
-	"github.com/lima-vm/lima/v2/pkg/store"
 )
 
 var knownYamlProperties = []string{
@@ -64,12 +68,13 @@ var knownYamlProperties = []string{
 	"User",
 	"Video",
 	"VMType",
+	"VMOpts",
 }
 
 const Enabled = true
 
 type LimaVzDriver struct {
-	Instance *store.Instance
+	Instance *limatype.Instance
 
 	SSHLocalPort int
 	vSockPort    int
@@ -87,15 +92,126 @@ func New() *LimaVzDriver {
 	}
 }
 
-func (l *LimaVzDriver) Configure(inst *store.Instance) *driver.ConfiguredDriver {
+func (l *LimaVzDriver) Configure(inst *limatype.Instance) *driver.ConfiguredDriver {
 	l.Instance = inst
 	l.SSHLocalPort = inst.SSHLocalPort
 
+	if l.Instance.Config.MountType != nil {
+		mountTypesUnsupported := make(map[string]struct{})
+		for _, f := range l.Instance.Config.MountTypesUnsupported {
+			mountTypesUnsupported[f] = struct{}{}
+		}
+
+		if _, ok := mountTypesUnsupported[*l.Instance.Config.MountType]; ok {
+			// We cannot return an error here, but Validate() will return it.
+			logrus.Warnf("Unsupported mount type: %q", *l.Instance.Config.MountType)
+		}
+	}
+
 	return &driver.ConfiguredDriver{
 		Driver: l,
 	}
 }
 
+func (l *LimaVzDriver) FillConfig(cfg *limatype.LimaYAML, _ string) error {
+	if cfg.VMType == nil {
+		cfg.VMType = ptr.Of(limatype.VZ)
+	}
+
+	if cfg.MountType == nil {
+		cfg.MountType = ptr.Of(limatype.VIRTIOFS)
+	}
+
+	//nolint:staticcheck // Migration of top-level Rosetta if specified
+	if (cfg.VMOpts.VZ.Rosetta.Enabled == nil && cfg.VMOpts.VZ.Rosetta.BinFmt == nil) && (!isEmpty(cfg.Rosetta)) {
+		logrus.Debug("Migrating top-level Rosetta configuration to vmOpts.vz.rosetta")
+		cfg.VMOpts.VZ.Rosetta = cfg.Rosetta
+	}
+	//nolint:staticcheck // Warning about both top-level and vmOpts.vz.Rosetta being set
+	if (cfg.VMOpts.VZ.Rosetta.Enabled != nil && cfg.VMOpts.VZ.Rosetta.BinFmt != nil) && (!isEmpty(cfg.Rosetta)) {
+		logrus.Warn("Both top-level 'rosetta' and 'vmOpts.vz.rosetta' are configured. Using vmOpts.vz.rosetta. Top-level 'rosetta' is deprecated.")
+	}
+
+	if cfg.VMOpts.VZ.Rosetta.Enabled == nil {
+		cfg.VMOpts.VZ.Rosetta.Enabled = ptr.Of(false)
+	}
+	if cfg.VMOpts.VZ.Rosetta.BinFmt == nil {
+		cfg.VMOpts.VZ.Rosetta.BinFmt = ptr.Of(false)
+	}
+
+	return nil
+}
+
+func isEmpty(r limatype.Rosetta) bool {
+	return r.Enabled == nil && r.BinFmt == nil
+}
+
+//go:embed boot/*.sh
+var bootFS embed.FS
+
+func (l *LimaVzDriver) BootScripts() (map[string][]byte, error) {
+	scripts := make(map[string][]byte)
+
+	entries, err := bootFS.ReadDir("boot")
+	if err == nil {
+		for _, entry := range entries {
+			if entry.IsDir() {
+				continue
+			}
+
+			content, err := bootFS.ReadFile("boot/" + entry.Name())
+			if err != nil {
+				return nil, err
+			}
+
+			scripts[entry.Name()] = content
+		}
+	}
+
+	return scripts, nil
+}
+
+func (l *LimaVzDriver) AcceptConfig(cfg *limatype.LimaYAML, filePath string) error {
+	if dir, basename := filepath.Split(filePath); dir != "" && basename == filenames.LimaYAML && limayaml.IsExistingInstanceDir(dir) {
+		vzIdentifier := filepath.Join(dir, filenames.VzIdentifier) // since Lima v0.14
+		if _, err := os.Lstat(vzIdentifier); !errors.Is(err, os.ErrNotExist) {
+			logrus.Debugf("ResolveVMType: resolved VMType %q (existing instance, with %q)", "vz", vzIdentifier)
+		}
+	}
+
+	for i, nw := range cfg.Networks {
+		field := fmt.Sprintf("networks[%d]", i)
+		switch {
+		case nw.Lima != "":
+			if nw.VZNAT != nil && *nw.VZNAT {
+				return fmt.Errorf("field `%s.lima` and field `%s.vzNAT` are mutually exclusive", field, field)
+			}
+		case nw.Socket != "":
+			if nw.VZNAT != nil && *nw.VZNAT {
+				return fmt.Errorf("field `%s.socket` and field `%s.vzNAT` are mutually exclusive", field, field)
+			}
+		case nw.VZNAT != nil && *nw.VZNAT:
+			if nw.Lima != "" {
+				return fmt.Errorf("field `%s.vzNAT` and field `%s.lima` are mutually exclusive", field, field)
+			}
+			if nw.Socket != "" {
+				return fmt.Errorf("field `%s.vzNAT` and field `%s.socket` are mutually exclusive", field, field)
+			}
+		}
+	}
+
+	if l.Instance == nil {
+		l.Instance = &limatype.Instance{}
+	}
+	l.Instance.Config = cfg
+
+	if err := l.Validate(context.Background()); err != nil {
+		return fmt.Errorf("config not supported by the VZ driver: %w", err)
+	}
+
+	return nil
+}
+
 func (l *LimaVzDriver) Validate(_ context.Context) error {
 	macOSProductVersion, err := osutil.ProductVersion()
 	if err != nil {
@@ -109,21 +225,21 @@ func (l *LimaVzDriver) Validate(_ context.Context) error {
 			"Update macOS, or change vmType to \"qemu\" if the VM does not start up. (https://github.com/lima-vm/lima/issues/3334)",
 			*l.Instance.Config.VMType)
 	}
-	if *l.Instance.Config.MountType == limayaml.NINEP {
-		return fmt.Errorf("field `mountType` must be %q or %q for VZ driver , got %q", limayaml.REVSSHFS, limayaml.VIRTIOFS, *l.Instance.Config.MountType)
+	if l.Instance.Config.MountType != nil && *l.Instance.Config.MountType == limatype.NINEP {
+		return fmt.Errorf("field `mountType` must be %q or %q for VZ driver , got %q", limatype.REVSSHFS, limatype.VIRTIOFS, *l.Instance.Config.MountType)
 	}
 	if *l.Instance.Config.Firmware.LegacyBIOS {
 		logrus.Warnf("vmType %s: ignoring `firmware.legacyBIOS`", *l.Instance.Config.VMType)
 	}
 	for _, f := range l.Instance.Config.Firmware.Images {
 		switch f.VMType {
-		case "", limayaml.VZ:
+		case "", limatype.VZ:
 			if f.Arch == *l.Instance.Config.Arch {
 				return errors.New("`firmware.images` configuration is not supported for VZ driver")
 			}
 		}
 	}
-	if unknown := reflectutil.UnknownNonEmptyFields(l.Instance.Config, knownYamlProperties...); len(unknown) > 0 {
+	if unknown := reflectutil.UnknownNonEmptyFields(l.Instance.Config, knownYamlProperties...); l.Instance.Config.VMType != nil && len(unknown) > 0 {
 		logrus.Warnf("vmType %s: ignoring %+v", *l.Instance.Config.VMType, unknown)
 	}
 
@@ -175,7 +291,7 @@ func (l *LimaVzDriver) Validate(_ context.Context) error {
 	return nil
 }
 
-func (l *LimaVzDriver) Initialize(_ context.Context) error {
+func (l *LimaVzDriver) Create(_ context.Context) error {
 	_, err := getMachineIdentifier(l.Instance)
 	return err
 }
@@ -265,9 +381,26 @@ func (l *LimaVzDriver) Info() driver.Info {
 	if l.Instance != nil {
 		info.InstanceDir = l.Instance.Dir
 	}
+
+	info.Features = driver.DriverFeatures{
+		DynamicSSHAddress:    false,
+		SkipSocketForwarding: false,
+	}
 	return info
 }
 
+func (l *LimaVzDriver) SSHAddress(_ context.Context) (string, error) {
+	return "127.0.0.1", nil
+}
+
+func (l *LimaVzDriver) InspectStatus(_ context.Context, _ *limatype.Instance) string {
+	return ""
+}
+
+func (l *LimaVzDriver) Delete(_ context.Context) error {
+	return nil
+}
+
 func (l *LimaVzDriver) Register(_ context.Context) error {
 	return nil
 }
diff --git a/pkg/cidata/cidata.TEMPLATE.d/boot/02-wsl2-setup.sh b/pkg/driver/wsl2/boot/02-wsl2-setup.sh
similarity index 100%
rename from pkg/cidata/cidata.TEMPLATE.d/boot/02-wsl2-setup.sh
rename to pkg/driver/wsl2/boot/02-wsl2-setup.sh
diff --git a/pkg/driver/wsl2/fs.go b/pkg/driver/wsl2/fs.go
index ddbc0bbd..b247b29d 100644
--- a/pkg/driver/wsl2/fs.go
+++ b/pkg/driver/wsl2/fs.go
@@ -12,12 +12,12 @@ import (
 	"github.com/sirupsen/logrus"
 
 	"github.com/lima-vm/lima/v2/pkg/fileutils"
-	"github.com/lima-vm/lima/v2/pkg/store"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 )
 
 // EnsureFs downloads the root fs.
-func EnsureFs(ctx context.Context, inst *store.Instance) error {
+func EnsureFs(ctx context.Context, inst *limatype.Instance) error {
 	baseDisk := filepath.Join(inst.Dir, filenames.BaseDisk)
 	if _, err := os.Stat(baseDisk); errors.Is(err, os.ErrNotExist) {
 		var ensuredBaseDisk bool
diff --git a/pkg/driver/wsl2/vm_windows.go b/pkg/driver/wsl2/vm_windows.go
index 493a8380..63601270 100644
--- a/pkg/driver/wsl2/vm_windows.go
+++ b/pkg/driver/wsl2/vm_windows.go
@@ -10,14 +10,15 @@ import (
 	"os"
 	"os/exec"
 	"path/filepath"
+	"regexp"
 	"strconv"
 	"strings"
 
 	"github.com/sirupsen/logrus"
 
 	"github.com/lima-vm/lima/v2/pkg/executil"
-	"github.com/lima-vm/lima/v2/pkg/store"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 	"github.com/lima-vm/lima/v2/pkg/textutil"
 )
 
@@ -133,8 +134,8 @@ func provisionVM(ctx context.Context, instanceDir, instanceName, distroName stri
 		for {
 			<-ctx.Done()
 			logrus.Info("Context closed, stopping vm")
-			if status, err := store.GetWslStatus(instanceName); err == nil &&
-				status == store.StatusRunning {
+			if status, err := getWslStatus(instanceName); err == nil &&
+				status == limatype.StatusRunning {
 				_ = stopVM(ctx, distroName)
 			}
 		}
@@ -177,3 +178,54 @@ func unregisterVM(ctx context.Context, distroName string) error {
 	}
 	return nil
 }
+
+func getWslStatus(instName string) (string, error) {
+	distroName := "lima-" + instName
+	out, err := executil.RunUTF16leCommand([]string{
+		"wsl.exe",
+		"--list",
+		"--verbose",
+	})
+	if err != nil {
+		return "", fmt.Errorf("failed to run `wsl --list --verbose`, err: %w (out=%q)", err, out)
+	}
+
+	if out == "" {
+		return limatype.StatusBroken, fmt.Errorf("failed to read instance state for instance %q, try running `wsl --list --verbose` to debug, err: %w", instName, err)
+	}
+
+	// Check for edge cases first
+	if strings.Contains(out, "Windows Subsystem for Linux has no installed distributions.") {
+		if strings.Contains(out, "Wsl/WSL_E_DEFAULT_DISTRO_NOT_FOUND") {
+			return limatype.StatusBroken, fmt.Errorf(
+				"failed to read instance state for instance %q because no distro is installed,"+
+					"try running `wsl --install -d Ubuntu` and then re-running Lima", instName)
+		}
+		return limatype.StatusBroken, fmt.Errorf(
+			"failed to read instance state for instance %q because there is no WSL kernel installed,"+
+				"this usually happens when WSL was installed for another user, but never for your user."+
+				"Try running `wsl --install -d Ubuntu` and `wsl --update`, and then re-running Lima", instName)
+	}
+
+	var instState string
+	wslListColsRegex := regexp.MustCompile(`\s+`)
+	// wsl --list --verbose may have different headers depending on localization, just split by line
+	for _, rows := range strings.Split(strings.ReplaceAll(out, "\r\n", "\n"), "\n") {
+		cols := wslListColsRegex.Split(strings.TrimSpace(rows), -1)
+		nameIdx := 0
+		// '*' indicates default instance
+		if cols[0] == "*" {
+			nameIdx = 1
+		}
+		if cols[nameIdx] == distroName {
+			instState = cols[nameIdx+1]
+			break
+		}
+	}
+
+	if instState == "" {
+		return limatype.StatusUninitialized, nil
+	}
+
+	return instState, nil
+}
diff --git a/pkg/driver/wsl2/wsl_driver_windows.go b/pkg/driver/wsl2/wsl_driver_windows.go
index 930a2b84..5d433897 100644
--- a/pkg/driver/wsl2/wsl_driver_windows.go
+++ b/pkg/driver/wsl2/wsl_driver_windows.go
@@ -5,6 +5,7 @@ package wsl2
 
 import (
 	"context"
+	"embed"
 	"fmt"
 	"net"
 	"regexp"
@@ -15,9 +16,10 @@ import (
 
 	"github.com/lima-vm/lima/v2/pkg/driver"
 	"github.com/lima-vm/lima/v2/pkg/freeport"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 	"github.com/lima-vm/lima/v2/pkg/limayaml"
+	"github.com/lima-vm/lima/v2/pkg/ptr"
 	"github.com/lima-vm/lima/v2/pkg/reflectutil"
-	"github.com/lima-vm/lima/v2/pkg/store"
 	"github.com/lima-vm/lima/v2/pkg/windows"
 )
 
@@ -47,7 +49,7 @@ var knownYamlProperties = []string{
 const Enabled = true
 
 type LimaWslDriver struct {
-	Instance *store.Instance
+	Instance *limatype.Instance
 
 	SSHLocalPort int
 	vSockPort    int
@@ -68,7 +70,7 @@ func New() *LimaWslDriver {
 	}
 }
 
-func (l *LimaWslDriver) Configure(inst *store.Instance) *driver.ConfiguredDriver {
+func (l *LimaWslDriver) Configure(inst *limatype.Instance) *driver.ConfiguredDriver {
 	l.Instance = inst
 	l.SSHLocalPort = inst.SSHLocalPort
 
@@ -77,61 +79,162 @@ func (l *LimaWslDriver) Configure(inst *store.Instance) *driver.ConfiguredDriver
 	}
 }
 
+func (l *LimaWslDriver) AcceptConfig(cfg *limatype.LimaYAML, _ string) error {
+	if l.Instance == nil {
+		l.Instance = &limatype.Instance{}
+	}
+	l.Instance.Config = cfg
+
+	if err := l.Validate(context.Background()); err != nil {
+		return fmt.Errorf("config not supported by the WSL2 driver: %w", err)
+	}
+
+	return nil
+}
+
+func (l *LimaWslDriver) FillConfig(cfg *limatype.LimaYAML, _ string) error {
+	if cfg.VMType == nil {
+		cfg.VMType = ptr.Of(limatype.WSL2)
+	}
+	if cfg.MountType == nil {
+		cfg.MountType = ptr.Of(limatype.WSLMount)
+	}
+
+	return nil
+}
+
 func (l *LimaWslDriver) Validate(_ context.Context) error {
-	if *l.Instance.Config.MountType != limayaml.WSLMount {
-		return fmt.Errorf("field `mountType` must be %q for WSL2 driver, got %q", limayaml.WSLMount, *l.Instance.Config.MountType)
+	if l.Instance.Config.MountType != nil && *l.Instance.Config.MountType != limatype.WSLMount {
+		return fmt.Errorf("field `mountType` must be %q for WSL2 driver, got %q", limatype.WSLMount, *l.Instance.Config.MountType)
 	}
 	// TODO: revise this list for WSL2
-	if unknown := reflectutil.UnknownNonEmptyFields(l.Instance.Config, knownYamlProperties...); len(unknown) > 0 {
-		logrus.Warnf("Ignoring: vmType %s: %+v", *l.Instance.Config.VMType, unknown)
+	if l.Instance.Config.VMType != nil {
+		if unknown := reflectutil.UnknownNonEmptyFields(l.Instance.Config, knownYamlProperties...); len(unknown) > 0 {
+			logrus.Warnf("Ignoring: vmType %s: %+v", *l.Instance.Config.VMType, unknown)
+		}
 	}
 
 	if !limayaml.IsNativeArch(*l.Instance.Config.Arch) {
 		return fmt.Errorf("unsupported arch: %q", *l.Instance.Config.Arch)
 	}
 
-	// TODO: real filetype checks
-	tarFileRegex := regexp.MustCompile(`.*tar\.*`)
-	for i, image := range l.Instance.Config.Images {
-		if unknown := reflectutil.UnknownNonEmptyFields(image, "File"); len(unknown) > 0 {
-			logrus.Warnf("Ignoring: vmType %s: images[%d]: %+v", *l.Instance.Config.VMType, i, unknown)
+	if l.Instance.Config.VMType != nil {
+		if l.Instance.Config.Images != nil && l.Instance.Config.Arch != nil {
+			// TODO: real filetype checks
+			tarFileRegex := regexp.MustCompile(`.*tar\.*`)
+			for i, image := range l.Instance.Config.Images {
+				if unknown := reflectutil.UnknownNonEmptyFields(image, "File"); len(unknown) > 0 {
+					logrus.Warnf("Ignoring: vmType %s: images[%d]: %+v", *l.Instance.Config.VMType, i, unknown)
+				}
+				match := tarFileRegex.MatchString(image.Location)
+				if image.Arch == *l.Instance.Config.Arch && !match {
+					return fmt.Errorf("unsupported image type for vmType: %s, tarball root file system required: %q", *l.Instance.Config.VMType, image.Location)
+				}
+			}
 		}
-		match := tarFileRegex.MatchString(image.Location)
-		if image.Arch == *l.Instance.Config.Arch && !match {
-			return fmt.Errorf("unsupported image type for vmType: %s, tarball root file system required: %q", *l.Instance.Config.VMType, image.Location)
+
+		if l.Instance.Config.Mounts != nil {
+			for i, mount := range l.Instance.Config.Mounts {
+				if unknown := reflectutil.UnknownNonEmptyFields(mount); len(unknown) > 0 {
+					logrus.Warnf("Ignoring: vmType %s: mounts[%d]: %+v", *l.Instance.Config.VMType, i, unknown)
+				}
+			}
+		}
+
+		if l.Instance.Config.Networks != nil {
+			for i, network := range l.Instance.Config.Networks {
+				if unknown := reflectutil.UnknownNonEmptyFields(network); len(unknown) > 0 {
+					logrus.Warnf("Ignoring: vmType %s: networks[%d]: %+v", *l.Instance.Config.VMType, i, unknown)
+				}
+			}
+		}
+
+		if l.Instance.Config.Audio.Device != nil {
+			audioDevice := *l.Instance.Config.Audio.Device
+			if audioDevice != "" {
+				logrus.Warnf("Ignoring: vmType %s: `audio.device`: %+v", *l.Instance.Config.VMType, audioDevice)
+			}
 		}
 	}
 
-	for i, mount := range l.Instance.Config.Mounts {
-		if unknown := reflectutil.UnknownNonEmptyFields(mount); len(unknown) > 0 {
-			logrus.Warnf("Ignoring: vmType %s: mounts[%d]: %+v", *l.Instance.Config.VMType, i, unknown)
+	return nil
+}
+
+//go:embed boot/*.sh
+var bootFS embed.FS
+
+func (l *LimaWslDriver) BootScripts() (map[string][]byte, error) {
+	scripts := make(map[string][]byte)
+
+	entries, err := bootFS.ReadDir("boot")
+	if err != nil {
+		return scripts, err
+	}
+
+	for _, entry := range entries {
+		if entry.IsDir() {
+			continue
 		}
+
+		content, err := bootFS.ReadFile("boot/" + entry.Name())
+		if err != nil {
+			return nil, err
+		}
+
+		scripts[entry.Name()] = content
 	}
 
-	for i, network := range l.Instance.Config.Networks {
-		if unknown := reflectutil.UnknownNonEmptyFields(network); len(unknown) > 0 {
-			logrus.Warnf("Ignoring: vmType %s: networks[%d]: %+v", *l.Instance.Config.VMType, i, unknown)
+	return scripts, nil
+}
+
+func (l *LimaWslDriver) InspectStatus(ctx context.Context, inst *limatype.Instance) string {
+	status, err := getWslStatus(inst.Name)
+	if err != nil {
+		inst.Status = limatype.StatusBroken
+		inst.Errors = append(inst.Errors, err)
+	} else {
+		inst.Status = status
+	}
+
+	inst.SSHLocalPort = 22
+
+	if inst.Status == limatype.StatusRunning {
+		sshAddr, err := l.SSHAddress(ctx)
+		if err == nil {
+			inst.SSHAddress = sshAddr
+		} else {
+			inst.Errors = append(inst.Errors, err)
 		}
 	}
 
-	audioDevice := *l.Instance.Config.Audio.Device
-	if audioDevice != "" {
-		logrus.Warnf("Ignoring: vmType %s: `audio.device`: %+v", *l.Instance.Config.VMType, audioDevice)
+	return inst.Status
+}
+
+func (l *LimaWslDriver) Delete(ctx context.Context) error {
+	distroName := "lima-" + l.Instance.Name
+	status, err := getWslStatus(l.Instance.Name)
+	if err != nil {
+		return err
+	}
+	switch status {
+	case limatype.StatusRunning, limatype.StatusStopped, limatype.StatusBroken, limatype.StatusInstalling:
+		return unregisterVM(ctx, distroName)
 	}
 
+	logrus.Info("WSL VM is not running or does not exist, skipping deletion")
 	return nil
 }
 
 func (l *LimaWslDriver) Start(ctx context.Context) (chan error, error) {
 	logrus.Infof("Starting WSL VM")
-	status, err := store.GetWslStatus(l.Instance.Name)
+	status, err := getWslStatus(l.Instance.Name)
 	if err != nil {
 		return nil, err
 	}
 
 	distroName := "lima-" + l.Instance.Name
 
-	if status == store.StatusUninitialized {
+	if status == limatype.StatusUninitialized {
 		if err := EnsureFs(ctx, l.Instance); err != nil {
 			return nil, err
 		}
@@ -177,21 +280,6 @@ func (l *LimaWslDriver) Stop(ctx context.Context) error {
 	return stopVM(ctx, distroName)
 }
 
-func (l *LimaWslDriver) Unregister(ctx context.Context) error {
-	distroName := "lima-" + l.Instance.Name
-	status, err := store.GetWslStatus(l.Instance.Name)
-	if err != nil {
-		return err
-	}
-	switch status {
-	case store.StatusRunning, store.StatusStopped, store.StatusBroken, store.StatusInstalling:
-		return unregisterVM(ctx, distroName)
-	}
-
-	logrus.Info("VM not registered, skipping unregistration")
-	return nil
-}
-
 // GuestAgentConn returns the guest agent connection, or nil (if forwarded by ssh).
 // As of 08-01-2024, github.com/mdlayher/vsock does not natively support vsock on
 // Windows, so use the winio library to create the connection.
@@ -225,18 +313,23 @@ func (l *LimaWslDriver) Info() driver.Info {
 	info.CanRunGUI = l.canRunGUI()
 	info.VirtioPort = l.virtioPort
 	info.VsockPort = l.vSockPort
+
+	info.Features = driver.DriverFeatures{
+		DynamicSSHAddress:    true,
+		SkipSocketForwarding: true,
+	}
 	return info
 }
 
-func (l *LimaWslDriver) Initialize(_ context.Context) error {
-	return nil
+func (l *LimaWslDriver) SSHAddress(_ context.Context) (string, error) {
+	return "127.0.0.1", nil
 }
 
-func (l *LimaWslDriver) CreateDisk(_ context.Context) error {
+func (l *LimaWslDriver) Create(_ context.Context) error {
 	return nil
 }
 
-func (l *LimaWslDriver) Register(_ context.Context) error {
+func (l *LimaWslDriver) CreateDisk(_ context.Context) error {
 	return nil
 }
 
diff --git a/pkg/driverutil/instance.go b/pkg/driverutil/instance.go
index 2d865a80..53ae318c 100644
--- a/pkg/driverutil/instance.go
+++ b/pkg/driverutil/instance.go
@@ -10,12 +10,12 @@ import (
 
 	"github.com/lima-vm/lima/v2/pkg/driver"
 	"github.com/lima-vm/lima/v2/pkg/driver/external/server"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 	"github.com/lima-vm/lima/v2/pkg/registry"
-	"github.com/lima-vm/lima/v2/pkg/store"
 )
 
 // CreateConfiguredDriver creates a driver.ConfiguredDriver for the given instance.
-func CreateConfiguredDriver(inst *store.Instance, sshLocalPort int) (*driver.ConfiguredDriver, error) {
+func CreateConfiguredDriver(inst *limatype.Instance, sshLocalPort int) (*driver.ConfiguredDriver, error) {
 	limaDriver := inst.Config.VMType
 	extDriver, intDriver, exists := registry.Get(*limaDriver)
 	if !exists {
diff --git a/pkg/driverutil/vm.go b/pkg/driverutil/vm.go
new file mode 100644
index 00000000..c1cc5af9
--- /dev/null
+++ b/pkg/driverutil/vm.go
@@ -0,0 +1,66 @@
+// SPDX-FileCopyrightText: Copyright The Lima Authors
+// SPDX-License-Identifier: Apache-2.0
+
+package driverutil
+
+import (
+	"context"
+	"errors"
+	"fmt"
+
+	"github.com/sirupsen/logrus"
+
+	"github.com/lima-vm/lima/v2/pkg/limatype"
+	"github.com/lima-vm/lima/v2/pkg/registry"
+)
+
+func ResolveVMType(y *limatype.LimaYAML, filePath string) error {
+	if y.VMType != nil && *y.VMType != "" {
+		if err := validateConfigAgainstDriver(y, filePath, *y.VMType); err != nil {
+			return err
+		}
+		logrus.Debugf("Using specified vmType %q for %q", *y.VMType, filePath)
+		return nil
+	}
+
+	// If VMType is not specified, we go with the default platform driver.
+	vmType := limatype.DefaultDriver()
+	return validateConfigAgainstDriver(y, filePath, vmType)
+}
+
+func validateConfigAgainstDriver(y *limatype.LimaYAML, filePath, vmType string) error {
+	extDriver, intDriver, exists := registry.Get(vmType)
+	if !exists {
+		return fmt.Errorf("vmType %q is not a registered driver", vmType)
+	}
+
+	if extDriver != nil {
+		return errors.New("not supported for external drivers")
+	}
+
+	if err := intDriver.AcceptConfig(y, filePath); err != nil {
+		return err
+	}
+	if err := intDriver.FillConfig(y, filePath); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func InspectStatus(ctx context.Context, inst *limatype.Instance) (string, error) {
+	if inst == nil || inst.Config == nil || inst.Config.VMType == nil {
+		return "", errors.New("instance or its configuration is not properly initialized")
+	}
+
+	extDriver, intDriver, exists := registry.Get(*inst.Config.VMType)
+	if !exists {
+		return "", fmt.Errorf("unknown or unsupported VM type: %s", *inst.Config.VMType)
+	}
+
+	if extDriver != nil {
+		return "", errors.New("InspectStatus is not supported for external drivers")
+	}
+
+	return intDriver.InspectStatus(ctx, inst), nil
+}
diff --git a/pkg/editutil/editutil.go b/pkg/editutil/editutil.go
index 462b791d..513b99f9 100644
--- a/pkg/editutil/editutil.go
+++ b/pkg/editutil/editutil.go
@@ -15,8 +15,8 @@ import (
 	"github.com/sirupsen/logrus"
 
 	"github.com/lima-vm/lima/v2/pkg/editutil/editorcmd"
-	"github.com/lima-vm/lima/v2/pkg/store/dirnames"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
+	"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 )
 
 func fileWarning(filename string) string {
diff --git a/pkg/fileutils/download.go b/pkg/fileutils/download.go
index 7bf3fea5..e6d47f2b 100644
--- a/pkg/fileutils/download.go
+++ b/pkg/fileutils/download.go
@@ -12,14 +12,14 @@ import (
 	"github.com/sirupsen/logrus"
 
 	"github.com/lima-vm/lima/v2/pkg/downloader"
-	"github.com/lima-vm/lima/v2/pkg/limayaml"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 )
 
 // ErrSkipped is returned when the downloader did not attempt to download the specified file.
 var ErrSkipped = errors.New("skipped to download")
 
 // DownloadFile downloads a file to the cache, optionally copying it to the destination. Returns path in cache.
-func DownloadFile(ctx context.Context, dest string, f limayaml.File, decompress bool, description string, expectedArch limayaml.Arch) (string, error) {
+func DownloadFile(ctx context.Context, dest string, f limatype.File, decompress bool, description string, expectedArch limatype.Arch) (string, error) {
 	if f.Arch != expectedArch {
 		return "", fmt.Errorf("%w: %q: unsupported arch: %q", ErrSkipped, f.Location, f.Arch)
 	}
@@ -47,7 +47,7 @@ func DownloadFile(ctx context.Context, dest string, f limayaml.File, decompress
 }
 
 // CachedFile checks if a file is in the cache, validating the digest if it is available. Returns path in cache.
-func CachedFile(f limayaml.File) (string, error) {
+func CachedFile(f limatype.File) (string, error) {
 	res, err := downloader.Cached(f.Location,
 		downloader.WithCache(),
 		downloader.WithExpectedDigest(f.Digest))
diff --git a/pkg/hostagent/hostagent.go b/pkg/hostagent/hostagent.go
index 4cb8f95c..bdc71e2d 100644
--- a/pkg/hostagent/hostagent.go
+++ b/pkg/hostagent/hostagent.go
@@ -36,18 +36,19 @@ import (
 	"github.com/lima-vm/lima/v2/pkg/hostagent/dns"
 	"github.com/lima-vm/lima/v2/pkg/hostagent/events"
 	"github.com/lima-vm/lima/v2/pkg/instance/hostname"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 	"github.com/lima-vm/lima/v2/pkg/limayaml"
 	"github.com/lima-vm/lima/v2/pkg/networks"
 	"github.com/lima-vm/lima/v2/pkg/osutil"
 	"github.com/lima-vm/lima/v2/pkg/portfwd"
 	"github.com/lima-vm/lima/v2/pkg/sshutil"
 	"github.com/lima-vm/lima/v2/pkg/store"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
 	"github.com/lima-vm/lima/v2/pkg/version/versionutil"
 )
 
 type HostAgent struct {
-	instConfig        *limayaml.LimaYAML
+	instConfig        *limatype.LimaYAML
 	sshLocalPort      int
 	udpDNSLocalPort   int
 	tcpDNSLocalPort   int
@@ -135,7 +136,7 @@ func New(ctx context.Context, instName string, stdout io.Writer, signalCh chan o
 	if err != nil {
 		return nil, err
 	}
-	if *inst.Config.VMType == limayaml.WSL2 {
+	if *inst.Config.VMType == limatype.WSL2 {
 		sshLocalPort = inst.SSHLocalPort
 	}
 
@@ -162,7 +163,7 @@ func New(ctx context.Context, instName string, stdout io.Writer, signalCh chan o
 	if err := cidata.GenerateCloudConfig(ctx, inst.Dir, instName, inst.Config); err != nil {
 		return nil, err
 	}
-	if err := cidata.GenerateISO9660(ctx, inst.Dir, instName, inst.Config, udpDNSLocalPort, tcpDNSLocalPort, o.guestAgentBinary, o.nerdctlArchive, vSockPort, virtioPort); err != nil {
+	if err := cidata.GenerateISO9660(ctx, limaDriver, inst.Dir, instName, inst.Config, udpDNSLocalPort, tcpDNSLocalPort, o.guestAgentBinary, o.nerdctlArchive, vSockPort, virtioPort); err != nil {
 		return nil, err
 	}
 
@@ -194,13 +195,13 @@ func New(ctx context.Context, instName string, stdout io.Writer, signalCh chan o
 	for _, rule := range inst.Config.PortForwards {
 		if rule.Ignore && rule.GuestPortRange[0] == 1 && rule.GuestPortRange[1] == 65535 {
 			switch rule.Proto {
-			case limayaml.ProtoTCP:
+			case limatype.ProtoTCP:
 				ignoreTCP = true
 				logrus.Info("TCP port forwarding is disabled (except for SSH)")
-			case limayaml.ProtoUDP:
+			case limatype.ProtoUDP:
 				ignoreUDP = true
 				logrus.Info("UDP port forwarding is disabled")
-			case limayaml.ProtoAny:
+			case limatype.ProtoAny:
 				ignoreTCP = true
 				ignoreUDP = true
 				logrus.Info("TCP (except for SSH) and UDP port forwarding is disabled")
@@ -209,16 +210,16 @@ func New(ctx context.Context, instName string, stdout io.Writer, signalCh chan o
 			break
 		}
 	}
-	rules := make([]limayaml.PortForward, 0, 3+len(inst.Config.PortForwards))
+	rules := make([]limatype.PortForward, 0, 3+len(inst.Config.PortForwards))
 	// Block ports 22 and sshLocalPort on all IPs
 	for _, port := range []int{sshGuestPort, sshLocalPort} {
-		rule := limayaml.PortForward{GuestIP: net.IPv4zero, GuestPort: port, Ignore: true}
+		rule := limatype.PortForward{GuestIP: net.IPv4zero, GuestPort: port, Ignore: true}
 		limayaml.FillPortForwardDefaults(&rule, inst.Dir, inst.Config.User, inst.Param)
 		rules = append(rules, rule)
 	}
 	rules = append(rules, inst.Config.PortForwards...)
 	// Default forwards for all non-privileged ports from "127.0.0.1" and "::1"
-	rule := limayaml.PortForward{}
+	rule := limatype.PortForward{}
 	limayaml.FillPortForwardDefaults(&rule, inst.Dir, inst.Config.User, inst.Param)
 	rules = append(rules, rule)
 
@@ -310,6 +311,9 @@ func (a *HostAgent) Run(ctx context.Context) error {
 
 	if limayaml.FirstUsernetIndex(a.instConfig) == -1 && *a.instConfig.HostResolver.Enabled {
 		hosts := a.instConfig.HostResolver.Hosts
+		if hosts == nil {
+			hosts = make(map[string]string)
+		}
 		hosts["host.lima.internal"] = networks.SlirpGateway
 		name := hostname.FromInstName(a.instName) // TODO: support customization
 		hosts[name] = networks.SlirpIPAddress
@@ -335,8 +339,8 @@ func (a *HostAgent) Run(ctx context.Context) error {
 	}
 
 	// WSL instance SSH address isn't known until after VM start
-	if *a.instConfig.VMType == limayaml.WSL2 {
-		sshAddr, err := store.GetSSHAddress(ctx, a.instName)
+	if a.driver.Info().Features.DynamicSSHAddress {
+		sshAddr, err := a.driver.SSHAddress(ctx)
 		if err != nil {
 			return err
 		}
@@ -472,7 +476,7 @@ sudo chown -R "${USER}" /run/host-services`
 			errs = append(errs, fmt.Errorf("stdout=%q, stderr=%q: %w", stdout, stderr, err))
 		}
 	}
-	if *a.instConfig.MountType == limayaml.REVSSHFS && !*a.instConfig.Plain {
+	if *a.instConfig.MountType == limatype.REVSSHFS && !*a.instConfig.Plain {
 		mounts, err := a.setupMounts(ctx)
 		if err != nil {
 			errs = append(errs, err)
@@ -571,7 +575,7 @@ func (a *HostAgent) watchGuestAgentEvents(ctx context.Context) {
 	// TODO: use vSock (when QEMU for macOS gets support for vSock)
 
 	// Setup all socket forwards and defer their teardown
-	if *a.instConfig.VMType != limayaml.WSL2 {
+	if !(a.driver.Info().Features.DynamicSSHAddress) {
 		logrus.Debugf("Forwarding unix sockets")
 		for _, rule := range a.instConfig.PortForwards {
 			if rule.GuestSocket != "" {
diff --git a/pkg/hostagent/mount.go b/pkg/hostagent/mount.go
index 92ea6e40..1763e15b 100644
--- a/pkg/hostagent/mount.go
+++ b/pkg/hostagent/mount.go
@@ -14,7 +14,7 @@ import (
 	"github.com/sirupsen/logrus"
 
 	"github.com/lima-vm/lima/v2/pkg/ioutilx"
-	"github.com/lima-vm/lima/v2/pkg/limayaml"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 )
 
 type mount struct {
@@ -37,7 +37,7 @@ func (a *HostAgent) setupMounts(ctx context.Context) ([]*mount, error) {
 	return res, errors.Join(errs...)
 }
 
-func (a *HostAgent) setupMount(ctx context.Context, m limayaml.Mount) (*mount, error) {
+func (a *HostAgent) setupMount(ctx context.Context, m limatype.Mount) (*mount, error) {
 	if err := os.MkdirAll(m.Location, 0o755); err != nil {
 		return nil, err
 	}
diff --git a/pkg/hostagent/port.go b/pkg/hostagent/port.go
index 5a945c24..cf792386 100644
--- a/pkg/hostagent/port.go
+++ b/pkg/hostagent/port.go
@@ -11,22 +11,23 @@ import (
 	"github.com/sirupsen/logrus"
 
 	"github.com/lima-vm/lima/v2/pkg/guestagent/api"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 	"github.com/lima-vm/lima/v2/pkg/limayaml"
 )
 
 type portForwarder struct {
 	sshConfig   *ssh.SSHConfig
 	sshHostPort int
-	rules       []limayaml.PortForward
+	rules       []limatype.PortForward
 	ignore      bool
-	vmType      limayaml.VMType
+	vmType      limatype.VMType
 }
 
 const sshGuestPort = 22
 
 var IPv4loopback1 = limayaml.IPv4loopback1
 
-func newPortForwarder(sshConfig *ssh.SSHConfig, sshHostPort int, rules []limayaml.PortForward, ignore bool, vmType limayaml.VMType) *portForwarder {
+func newPortForwarder(sshConfig *ssh.SSHConfig, sshHostPort int, rules []limatype.PortForward, ignore bool, vmType limatype.VMType) *portForwarder {
 	return &portForwarder{
 		sshConfig:   sshConfig,
 		sshHostPort: sshHostPort,
@@ -36,7 +37,7 @@ func newPortForwarder(sshConfig *ssh.SSHConfig, sshHostPort int, rules []limayam
 	}
 }
 
-func hostAddress(rule limayaml.PortForward, guest *api.IPPort) string {
+func hostAddress(rule limatype.PortForward, guest *api.IPPort) string {
 	if rule.HostSocket != "" {
 		return rule.HostSocket
 	}
@@ -57,7 +58,7 @@ func (pf *portForwarder) forwardingAddresses(guest *api.IPPort) (hostAddr, guest
 			continue
 		}
 		switch rule.Proto {
-		case limayaml.ProtoTCP, limayaml.ProtoAny:
+		case limatype.ProtoTCP, limatype.ProtoAny:
 		default:
 			continue
 		}
diff --git a/pkg/hostagent/requirements.go b/pkg/hostagent/requirements.go
index 1c09b42b..148d6785 100644
--- a/pkg/hostagent/requirements.go
+++ b/pkg/hostagent/requirements.go
@@ -12,7 +12,7 @@ import (
 	"github.com/lima-vm/sshocker/pkg/ssh"
 	"github.com/sirupsen/logrus"
 
-	"github.com/lima-vm/lima/v2/pkg/limayaml"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 )
 
 func (a *HostAgent) waitForRequirements(label string, requirements []requirement) error {
@@ -149,7 +149,7 @@ it must not be created until the session reset is done.
 `,
 		})
 
-	if *a.instConfig.MountType == limayaml.REVSSHFS && len(a.instConfig.Mounts) > 0 {
+	if *a.instConfig.MountType == limatype.REVSSHFS && len(a.instConfig.Mounts) > 0 {
 		req = append(req, requirement{
 			description: "sshfs binary to be installed",
 			script: `#!/bin/bash
@@ -216,7 +216,7 @@ Also see "/var/log/cloud-init-output.log" in the guest.
 			})
 	}
 	for _, probe := range a.instConfig.Probes {
-		if probe.Mode == limayaml.ProbeModeReadiness {
+		if probe.Mode == limatype.ProbeModeReadiness {
 			req = append(req, requirement{
 				description: probe.Description,
 				script:      probe.Script,
diff --git a/pkg/instance/ansible.go b/pkg/instance/ansible.go
index c0f9b0f1..2468804a 100644
--- a/pkg/instance/ansible.go
+++ b/pkg/instance/ansible.go
@@ -13,14 +13,13 @@ import (
 	"github.com/goccy/go-yaml"
 	"github.com/sirupsen/logrus"
 
-	"github.com/lima-vm/lima/v2/pkg/limayaml"
-	"github.com/lima-vm/lima/v2/pkg/store"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 )
 
-func runAnsibleProvision(ctx context.Context, inst *store.Instance) error {
+func runAnsibleProvision(ctx context.Context, inst *limatype.Instance) error {
 	for _, f := range inst.Config.Provision {
-		if f.Mode == limayaml.ProvisionModeAnsible {
+		if f.Mode == limatype.ProvisionModeAnsible {
 			logrus.Infof("Waiting for ansible playbook %q", f.Playbook)
 			if err := runAnsiblePlaybook(ctx, inst, f.Playbook); err != nil {
 				return err
@@ -30,7 +29,7 @@ func runAnsibleProvision(ctx context.Context, inst *store.Instance) error {
 	return nil
 }
 
-func runAnsiblePlaybook(ctx context.Context, inst *store.Instance, playbook string) error {
+func runAnsiblePlaybook(ctx context.Context, inst *limatype.Instance, playbook string) error {
 	inventory, err := createAnsibleInventory(inst)
 	if err != nil {
 		return err
@@ -44,7 +43,7 @@ func runAnsiblePlaybook(ctx context.Context, inst *store.Instance, playbook stri
 	return cmd.Run()
 }
 
-func createAnsibleInventory(inst *store.Instance) (string, error) {
+func createAnsibleInventory(inst *limatype.Instance) (string, error) {
 	vars := map[string]any{
 		"ansible_connection":      "ssh",
 		"ansible_host":            inst.Hostname,
@@ -67,7 +66,7 @@ func createAnsibleInventory(inst *store.Instance) (string, error) {
 	return inventory, os.WriteFile(inventory, bytes, 0o644)
 }
 
-func getAnsibleEnvironment(inst *store.Instance) []string {
+func getAnsibleEnvironment(inst *limatype.Instance) []string {
 	env := os.Environ()
 	for key, val := range inst.Config.Param {
 		env = append(env, fmt.Sprintf("PARAM_%s=%s", key, val))
diff --git a/pkg/instance/clone.go b/pkg/instance/clone.go
index b2f3410b..f4d1a013 100644
--- a/pkg/instance/clone.go
+++ b/pkg/instance/clone.go
@@ -15,23 +15,25 @@ import (
 
 	continuityfs "github.com/containerd/continuity/fs"
 
+	"github.com/lima-vm/lima/v2/pkg/limatype"
+	"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 	"github.com/lima-vm/lima/v2/pkg/osutil"
 	"github.com/lima-vm/lima/v2/pkg/store"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
 )
 
-func Clone(ctx context.Context, oldInst *store.Instance, newInstName string) (*store.Instance, error) {
+func Clone(ctx context.Context, oldInst *limatype.Instance, newInstName string) (*limatype.Instance, error) {
 	if newInstName == "" {
 		return nil, errors.New("got empty instName")
 	}
 	if oldInst.Name == newInstName {
 		return nil, fmt.Errorf("new instance name %q must be different from %q", newInstName, oldInst.Name)
 	}
-	if oldInst.Status == store.StatusRunning {
+	if oldInst.Status == limatype.StatusRunning {
 		return nil, errors.New("cannot clone a running instance")
 	}
 
-	newInstDir, err := store.InstanceDir(newInstName)
+	newInstDir, err := dirnames.InstanceDir(newInstName)
 	if err != nil {
 		return nil, err
 	}
diff --git a/pkg/instance/create.go b/pkg/instance/create.go
index d9064632..8f6ef76e 100644
--- a/pkg/instance/create.go
+++ b/pkg/instance/create.go
@@ -12,14 +12,16 @@ import (
 
 	"github.com/lima-vm/lima/v2/pkg/cidata"
 	"github.com/lima-vm/lima/v2/pkg/driverutil"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
+	"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 	"github.com/lima-vm/lima/v2/pkg/limayaml"
 	"github.com/lima-vm/lima/v2/pkg/osutil"
 	"github.com/lima-vm/lima/v2/pkg/store"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
 	"github.com/lima-vm/lima/v2/pkg/version"
 )
 
-func Create(ctx context.Context, instName string, instConfig []byte, saveBrokenYAML bool) (*store.Instance, error) {
+func Create(ctx context.Context, instName string, instConfig []byte, saveBrokenYAML bool) (*limatype.Instance, error) {
 	if instName == "" {
 		return nil, errors.New("got empty instName")
 	}
@@ -27,7 +29,7 @@ func Create(ctx context.Context, instName string, instConfig []byte, saveBrokenY
 		return nil, errors.New("got empty instConfig")
 	}
 
-	instDir, err := store.InstanceDir(instName)
+	instDir, err := dirnames.InstanceDir(instName)
 	if err != nil {
 		return nil, err
 	}
@@ -47,6 +49,9 @@ func Create(ctx context.Context, instName string, instConfig []byte, saveBrokenY
 	if err != nil {
 		return nil, err
 	}
+	if err := driverutil.ResolveVMType(loadedInstConfig, filePath); err != nil {
+		return nil, fmt.Errorf("failed to accept config for %q: %w", filePath, err)
+	}
 	if err := limayaml.Validate(loadedInstConfig, true); err != nil {
 		if !saveBrokenYAML {
 			return nil, err
@@ -80,7 +85,7 @@ func Create(ctx context.Context, instName string, instConfig []byte, saveBrokenY
 		return nil, fmt.Errorf("failed to create driver instance: %w", err)
 	}
 
-	if err := limaDriver.Register(ctx); err != nil {
+	if err := limaDriver.Create(ctx); err != nil {
 		return nil, err
 	}
 
diff --git a/pkg/instance/delete.go b/pkg/instance/delete.go
index 7c53fdf1..df0954db 100644
--- a/pkg/instance/delete.go
+++ b/pkg/instance/delete.go
@@ -10,15 +10,15 @@ import (
 	"os"
 
 	"github.com/lima-vm/lima/v2/pkg/driverutil"
-	"github.com/lima-vm/lima/v2/pkg/store"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 )
 
-func Delete(ctx context.Context, inst *store.Instance, force bool) error {
+func Delete(ctx context.Context, inst *limatype.Instance, force bool) error {
 	if inst.Protected {
 		return errors.New("instance is protected to prohibit accidental removal (Hint: use `limactl unprotect`)")
 	}
-	if !force && inst.Status != store.StatusStopped {
-		return fmt.Errorf("expected status %q, got %q", store.StatusStopped, inst.Status)
+	if !force && inst.Status != limatype.StatusStopped {
+		return fmt.Errorf("expected status %q, got %q", limatype.StatusStopped, inst.Status)
 	}
 
 	StopForcibly(inst)
@@ -35,11 +35,11 @@ func Delete(ctx context.Context, inst *store.Instance, force bool) error {
 	return nil
 }
 
-func unregister(ctx context.Context, inst *store.Instance) error {
+func unregister(ctx context.Context, inst *limatype.Instance) error {
 	limaDriver, err := driverutil.CreateConfiguredDriver(inst, 0)
 	if err != nil {
 		return fmt.Errorf("failed to create driver instance: %w", err)
 	}
 
-	return limaDriver.Unregister(ctx)
+	return limaDriver.Delete(ctx)
 }
diff --git a/pkg/instance/restart.go b/pkg/instance/restart.go
index 0a5f8b98..310bfd80 100644
--- a/pkg/instance/restart.go
+++ b/pkg/instance/restart.go
@@ -8,8 +8,8 @@ import (
 
 	"github.com/sirupsen/logrus"
 
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 	networks "github.com/lima-vm/lima/v2/pkg/networks/reconcile"
-	"github.com/lima-vm/lima/v2/pkg/store"
 )
 
 const (
@@ -17,7 +17,7 @@ const (
 	showProgress              = false
 )
 
-func Restart(ctx context.Context, inst *store.Instance) error {
+func Restart(ctx context.Context, inst *limatype.Instance) error {
 	if err := StopGracefully(ctx, inst, true); err != nil {
 		return err
 	}
@@ -33,7 +33,7 @@ func Restart(ctx context.Context, inst *store.Instance) error {
 	return nil
 }
 
-func RestartForcibly(ctx context.Context, inst *store.Instance) error {
+func RestartForcibly(ctx context.Context, inst *limatype.Instance) error {
 	logrus.Info("Restarting the instance forcibly")
 	StopForcibly(inst)
 
diff --git a/pkg/instance/start.go b/pkg/instance/start.go
index 4f08219f..a4357e7f 100644
--- a/pkg/instance/start.go
+++ b/pkg/instance/start.go
@@ -26,10 +26,10 @@ import (
 	"github.com/lima-vm/lima/v2/pkg/fileutils"
 	hostagentevents "github.com/lima-vm/lima/v2/pkg/hostagent/events"
 	"github.com/lima-vm/lima/v2/pkg/imgutil/proxyimgutil"
-	"github.com/lima-vm/lima/v2/pkg/limayaml"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 	"github.com/lima-vm/lima/v2/pkg/registry"
 	"github.com/lima-vm/lima/v2/pkg/store"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
 	"github.com/lima-vm/lima/v2/pkg/usrlocalsharelima"
 )
 
@@ -40,7 +40,7 @@ const DefaultWatchHostAgentEventsTimeout = 10 * time.Minute
 // ensureNerdctlArchiveCache prefetches the nerdctl-full-VERSION-GOOS-GOARCH.tar.gz archive
 // into the cache before launching the hostagent process, so that we can show the progress in tty.
 // https://github.com/lima-vm/lima/issues/326
-func ensureNerdctlArchiveCache(ctx context.Context, y *limayaml.LimaYAML, created bool) (string, error) {
+func ensureNerdctlArchiveCache(ctx context.Context, y *limatype.LimaYAML, created bool) (string, error) {
 	if !*y.Containerd.System && !*y.Containerd.User {
 		// nerdctl archive is not needed
 		return "", nil
@@ -79,7 +79,7 @@ type Prepared struct {
 }
 
 // Prepare ensures the disk, the nerdctl archive, etc.
-func Prepare(ctx context.Context, inst *store.Instance) (*Prepared, error) {
+func Prepare(ctx context.Context, inst *limatype.Instance) (*Prepared, error) {
 	var guestAgent string
 	if !*inst.Config.Plain {
 		var err error
@@ -97,7 +97,7 @@ func Prepare(ctx context.Context, inst *store.Instance) (*Prepared, error) {
 		return nil, err
 	}
 
-	if err := limaDriver.Initialize(ctx); err != nil {
+	if err := limaDriver.Create(ctx); err != nil {
 		return nil, err
 	}
 
@@ -179,7 +179,7 @@ func Prepare(ctx context.Context, inst *store.Instance) (*Prepared, error) {
 // shut down again.
 //
 // Start calls Prepare by itself, so you do not need to call Prepare manually before calling Start.
-func Start(ctx context.Context, inst *store.Instance, limactl string, launchHostAgentForeground, showProgress bool) error {
+func Start(ctx context.Context, inst *limatype.Instance, limactl string, launchHostAgentForeground, showProgress bool) error {
 	haPIDPath := filepath.Join(inst.Dir, filenames.HostAgentPID)
 	if _, err := os.Stat(haPIDPath); !errors.Is(err, os.ErrNotExist) {
 		return fmt.Errorf("instance %q seems running (hint: remove %q if the instance is not actually running)", inst.Name, haPIDPath)
@@ -300,7 +300,7 @@ func waitHostAgentStart(_ context.Context, haPIDPath, haStderrPath string) error
 	}
 }
 
-func watchHostAgentEvents(ctx context.Context, inst *store.Instance, haStdoutPath, haStderrPath string, begin time.Time, showProgress bool) error {
+func watchHostAgentEvents(ctx context.Context, inst *limatype.Instance, haStdoutPath, haStderrPath string, begin time.Time, showProgress bool) error {
 	ctx, cancel := context.WithTimeout(ctx, watchHostAgentTimeout(ctx))
 	defer cancel()
 
@@ -411,7 +411,7 @@ func LimactlShellCmd(instName string) string {
 	return shellCmd
 }
 
-func ShowMessage(inst *store.Instance) error {
+func ShowMessage(inst *limatype.Instance) error {
 	if inst.Message == "" {
 		return nil
 	}
@@ -438,7 +438,7 @@ func ShowMessage(inst *store.Instance) error {
 
 // prepareDiffDisk checks the disk size difference between inst.Disk and yaml.Disk.
 // If there is no diffDisk, return nil (the instance has not been initialized or started yet).
-func prepareDiffDisk(ctx context.Context, inst *store.Instance) error {
+func prepareDiffDisk(ctx context.Context, inst *limatype.Instance) error {
 	diffDisk := filepath.Join(inst.Dir, filenames.DiffDisk)
 
 	// Handle the instance initialization
diff --git a/pkg/instance/stop.go b/pkg/instance/stop.go
index b2fb6d04..0b677080 100644
--- a/pkg/instance/stop.go
+++ b/pkg/instance/stop.go
@@ -15,18 +15,19 @@ import (
 	"github.com/sirupsen/logrus"
 
 	hostagentevents "github.com/lima-vm/lima/v2/pkg/hostagent/events"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 	"github.com/lima-vm/lima/v2/pkg/osutil"
 	"github.com/lima-vm/lima/v2/pkg/store"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
 )
 
-func StopGracefully(ctx context.Context, inst *store.Instance, isRestart bool) error {
-	if inst.Status != store.StatusRunning {
+func StopGracefully(ctx context.Context, inst *limatype.Instance, isRestart bool) error {
+	if inst.Status != limatype.StatusRunning {
 		if isRestart {
 			logrus.Warn("The instance is not running, continuing with the restart")
 			return nil
 		}
-		return fmt.Errorf("expected status %q, got %q (maybe use `limactl stop -f`?)", store.StatusRunning, inst.Status)
+		return fmt.Errorf("expected status %q, got %q (maybe use `limactl stop -f`?)", limatype.StatusRunning, inst.Status)
 	}
 
 	begin := time.Now() // used for logrus propagation
@@ -45,7 +46,7 @@ func StopGracefully(ctx context.Context, inst *store.Instance, isRestart bool) e
 	return waitForInstanceShutdown(ctx, inst)
 }
 
-func waitForHostAgentTermination(ctx context.Context, inst *store.Instance, begin time.Time) error {
+func waitForHostAgentTermination(ctx context.Context, inst *limatype.Instance, begin time.Time) error {
 	ctx, cancel := context.WithTimeout(ctx, 3*time.Minute+10*time.Second)
 	defer cancel()
 
@@ -75,7 +76,7 @@ func waitForHostAgentTermination(ctx context.Context, inst *store.Instance, begi
 	return nil
 }
 
-func waitForInstanceShutdown(ctx context.Context, inst *store.Instance) error {
+func waitForInstanceShutdown(ctx context.Context, inst *limatype.Instance) error {
 	ctx, cancel := context.WithTimeout(ctx, 3*time.Minute)
 	defer cancel()
 
@@ -90,7 +91,7 @@ func waitForInstanceShutdown(ctx context.Context, inst *store.Instance) error {
 				return fmt.Errorf("failed to inspect instance status: %w", err)
 			}
 
-			if updatedInst.Status == store.StatusStopped {
+			if updatedInst.Status == limatype.StatusStopped {
 				logrus.Infof("The instance %s has shut down", updatedInst.Name)
 				return nil
 			}
@@ -100,7 +101,7 @@ func waitForInstanceShutdown(ctx context.Context, inst *store.Instance) error {
 	}
 }
 
-func StopForcibly(inst *store.Instance) {
+func StopForcibly(inst *limatype.Instance) {
 	if inst.DriverPID > 0 {
 		logrus.Infof("Sending SIGKILL to the %s driver process %d", inst.VMType, inst.DriverPID)
 		if err := osutil.SysKill(inst.DriverPID, osutil.SigKill); err != nil {
diff --git a/pkg/limainfo/limainfo.go b/pkg/limainfo/limainfo.go
index dda29025..d9a42882 100644
--- a/pkg/limainfo/limainfo.go
+++ b/pkg/limainfo/limainfo.go
@@ -11,9 +11,10 @@ import (
 	"github.com/sirupsen/logrus"
 
 	"github.com/lima-vm/lima/v2/pkg/envutil"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
+	"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
 	"github.com/lima-vm/lima/v2/pkg/limayaml"
 	"github.com/lima-vm/lima/v2/pkg/registry"
-	"github.com/lima-vm/lima/v2/pkg/store/dirnames"
 	"github.com/lima-vm/lima/v2/pkg/templatestore"
 	"github.com/lima-vm/lima/v2/pkg/usrlocalsharelima"
 	"github.com/lima-vm/lima/v2/pkg/version"
@@ -22,11 +23,11 @@ import (
 type LimaInfo struct {
 	Version         string                       `json:"version"`
 	Templates       []templatestore.Template     `json:"templates"`
-	DefaultTemplate *limayaml.LimaYAML           `json:"defaultTemplate"`
+	DefaultTemplate *limatype.LimaYAML           `json:"defaultTemplate"`
 	LimaHome        string                       `json:"limaHome"`
 	VMTypes         []string                     `json:"vmTypes"`     // since Lima v0.14.2
 	VMTypesEx       map[string]DriverExt         `json:"vmTypesEx"`   // since Lima v2.0.0
-	GuestAgents     map[limayaml.Arch]GuestAgent `json:"guestAgents"` // since Lima v1.1.0
+	GuestAgents     map[limatype.Arch]GuestAgent `json:"guestAgents"` // since Lima v1.1.0
 	ShellEnvBlock   []string                     `json:"shellEnvBlock"`
 }
 
@@ -69,7 +70,7 @@ func New(ctx context.Context) (*LimaInfo, error) {
 		DefaultTemplate: y,
 		VMTypes:         vmTypes,
 		VMTypesEx:       vmTypesEx,
-		GuestAgents:     make(map[limayaml.Arch]GuestAgent),
+		GuestAgents:     make(map[limatype.Arch]GuestAgent),
 		ShellEnvBlock:   envutil.GetDefaultBlockList(),
 	}
 	info.Templates, err = templatestore.Templates()
@@ -80,8 +81,8 @@ func New(ctx context.Context) (*LimaInfo, error) {
 	if err != nil {
 		return nil, err
 	}
-	for _, arch := range limayaml.ArchTypes {
-		bin, err := usrlocalsharelima.GuestAgentBinary(limayaml.LINUX, arch)
+	for _, arch := range limatype.ArchTypes {
+		bin, err := usrlocalsharelima.GuestAgentBinary(limatype.LINUX, arch)
 		if err != nil {
 			if errors.Is(err, fs.ErrNotExist) {
 				logrus.WithError(err).Debugf("Failed to resolve the guest agent binary for %q", arch)
diff --git a/pkg/limatmpl/abs.go b/pkg/limatmpl/abs.go
index 2598b377..bfc7060e 100644
--- a/pkg/limatmpl/abs.go
+++ b/pkg/limatmpl/abs.go
@@ -11,6 +11,8 @@ import (
 	"path/filepath"
 	"runtime"
 	"strings"
+
+	"github.com/lima-vm/lima/v2/pkg/localpathutil"
 )
 
 // UseAbsLocators will replace all relative template locators with absolute ones, so this template
@@ -105,6 +107,13 @@ func absPath(locator, basePath string) (string, error) {
 	if err == nil && len(u.Scheme) > 1 {
 		return locator, nil
 	}
+	// Don't expand relative path to absolute. Tilde paths however are absolute paths already.
+	if localpathutil.IsTildePath(locator) {
+		locator, err = localpathutil.Expand(locator)
+		if err != nil {
+			return "", err
+		}
+	}
 	// Check for rooted locator; filepath.IsAbs() returns false on Windows when the volume name is missing
 	volumeLen := len(filepath.VolumeName(locator))
 	if locator[volumeLen] != '/' && locator[volumeLen] != filepath.Separator {
diff --git a/pkg/limatmpl/embed.go b/pkg/limatmpl/embed.go
index 6c2a7b91..9ccbe564 100644
--- a/pkg/limatmpl/embed.go
+++ b/pkg/limatmpl/embed.go
@@ -18,9 +18,9 @@ import (
 	"github.com/coreos/go-semver/semver"
 	"github.com/sirupsen/logrus"
 
-	"github.com/lima-vm/lima/v2/pkg/limayaml"
-	"github.com/lima-vm/lima/v2/pkg/store/dirnames"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
+	"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 	"github.com/lima-vm/lima/v2/pkg/version/versionutil"
 	"github.com/lima-vm/lima/v2/pkg/yqutil"
 )
@@ -106,7 +106,7 @@ func (tmpl *Template) embedAllBases(ctx context.Context, embedAll, defaultBase b
 	return nil
 }
 
-func (tmpl *Template) embedBase(ctx context.Context, baseLocator limayaml.LocatorWithDigest, embedAll bool, seen map[string]bool) error {
+func (tmpl *Template) embedBase(ctx context.Context, baseLocator limatype.LocatorWithDigest, embedAll bool, seen map[string]bool) error {
 	logrus.Debugf("Embedding base %q in template %q", baseLocator.URL, tmpl.Locator)
 	if err := tmpl.Unmarshal(); err != nil {
 		return err
@@ -643,7 +643,7 @@ func (tmpl *Template) embedAllScripts(ctx context.Context, embedAll bool) error
 		}
 		newName := "script"
 		switch p.Mode {
-		case limayaml.ProvisionModeData:
+		case limatype.ProvisionModeData:
 			newName = "content"
 			if p.Content != nil {
 				continue
diff --git a/pkg/limatmpl/locator.go b/pkg/limatmpl/locator.go
index 7940e164..98e664af 100644
--- a/pkg/limatmpl/locator.go
+++ b/pkg/limatmpl/locator.go
@@ -20,6 +20,7 @@ import (
 
 	"github.com/lima-vm/lima/v2/pkg/identifiers"
 	"github.com/lima-vm/lima/v2/pkg/ioutilx"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 	"github.com/lima-vm/lima/v2/pkg/limayaml"
 	"github.com/lima-vm/lima/v2/pkg/templatestore"
 )
@@ -131,17 +132,17 @@ func Read(ctx context.Context, name, locator string) (*Template, error) {
 var imageURLRegex = regexp.MustCompile(`\.(img|qcow2|raw|iso)(\.(gz|xz|bz2|zstd))?$`)
 
 // Image architecture will be guessed based on the presence of arch keywords.
-var archKeywords = map[string]limayaml.Arch{
-	"aarch64": limayaml.AARCH64,
-	"amd64":   limayaml.X8664,
-	"arm64":   limayaml.AARCH64,
-	"armhf":   limayaml.ARMV7L,
-	"armv7l":  limayaml.ARMV7L,
-	"ppc64el": limayaml.PPC64LE,
-	"ppc64le": limayaml.PPC64LE,
-	"riscv64": limayaml.RISCV64,
-	"s390x":   limayaml.S390X,
-	"x86_64":  limayaml.X8664,
+var archKeywords = map[string]limatype.Arch{
+	"aarch64": limatype.AARCH64,
+	"amd64":   limatype.X8664,
+	"arm64":   limatype.AARCH64,
+	"armhf":   limatype.ARMV7L,
+	"armv7l":  limatype.ARMV7L,
+	"ppc64el": limatype.PPC64LE,
+	"ppc64le": limatype.PPC64LE,
+	"riscv64": limatype.RISCV64,
+	"s390x":   limatype.S390X,
+	"x86_64":  limatype.X8664,
 }
 
 // These generic tags will be stripped from an image name before turning it into an instance name.
@@ -174,7 +175,7 @@ func imageTemplate(tmpl *Template, locator string) bool {
 		return false
 	}
 
-	var imageArch limayaml.Arch
+	var imageArch limatype.Arch
 	for keyword, arch := range archKeywords {
 		pattern := fmt.Sprintf(`\b%s\b`, keyword)
 		if regexp.MustCompile(pattern).MatchString(locator) {
@@ -183,7 +184,7 @@ func imageTemplate(tmpl *Template, locator string) bool {
 		}
 	}
 	if imageArch == "" {
-		imageArch = limayaml.NewArch(runtime.GOARCH)
+		imageArch = limatype.NewArch(runtime.GOARCH)
 		logrus.Warnf("cannot determine image arch from URL %q; assuming %q", locator, imageArch)
 	}
 	template := `arch: %q
diff --git a/pkg/limatmpl/template.go b/pkg/limatmpl/template.go
index 1ca56a3c..5ac277f9 100644
--- a/pkg/limatmpl/template.go
+++ b/pkg/limatmpl/template.go
@@ -6,6 +6,7 @@ package limatmpl
 import (
 	"strings"
 
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 	"github.com/lima-vm/lima/v2/pkg/limayaml"
 )
 
@@ -15,7 +16,7 @@ type Template struct {
 
 	// The following fields are only used when the template represents a YAML config file.
 	Name   string // instance name, may be inferred from locator
-	Config *limayaml.LimaYAML
+	Config *limatype.LimaYAML
 
 	expr strings.Builder // yq expression to update template
 }
@@ -33,7 +34,7 @@ func (tmpl *Template) ClearOnError(err error) error {
 // tmpl.Bytes is expected to set tmpl.Config back to nil.
 func (tmpl *Template) Unmarshal() error {
 	if tmpl.Config == nil {
-		tmpl.Config = &limayaml.LimaYAML{}
+		tmpl.Config = &limatype.LimaYAML{}
 		if err := limayaml.Unmarshal(tmpl.Bytes, tmpl.Config, tmpl.Locator); err != nil {
 			tmpl.Config = nil
 			return err
diff --git a/pkg/store/dirnames/dirnames.go b/pkg/limatype/dirnames/dirnames.go
similarity index 66%
rename from pkg/store/dirnames/dirnames.go
rename to pkg/limatype/dirnames/dirnames.go
index 43607f9a..670de227 100644
--- a/pkg/store/dirnames/dirnames.go
+++ b/pkg/limatype/dirnames/dirnames.go
@@ -8,8 +8,10 @@ import (
 	"fmt"
 	"os"
 	"path/filepath"
+	"strings"
 
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
+	"github.com/lima-vm/lima/v2/pkg/identifiers"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 )
 
 // DotLima is a directory that appears under the home directory.
@@ -74,3 +76,30 @@ func LimaTemplatesDir() (string, error) {
 	}
 	return filepath.Join(limaDir, filenames.TemplatesDir), nil
 }
+
+// InstanceDir returns the instance dir.
+// InstanceDir does not check whether the instance exists.
+func InstanceDir(name string) (string, error) {
+	if err := ValidateInstName(name); err != nil {
+		return "", err
+	}
+	limaDir, err := LimaDir()
+	if err != nil {
+		return "", err
+	}
+	dir := filepath.Join(limaDir, name)
+	return dir, nil
+}
+
+// ValidateInstName checks if the name is a valid instance name. For this it needs to
+// be a valid identifier, and not end in .yml or .yaml (case insensitively).
+func ValidateInstName(name string) error {
+	if err := identifiers.Validate(name); err != nil {
+		return fmt.Errorf("instance name %q is not a valid identifier: %w", name, err)
+	}
+	lower := strings.ToLower(name)
+	if strings.HasSuffix(lower, ".yml") || strings.HasSuffix(lower, ".yaml") {
+		return fmt.Errorf("instance name %q must not end with .yml or .yaml suffix", name)
+	}
+	return nil
+}
diff --git a/pkg/store/filenames/filenames.go b/pkg/limatype/filenames/filenames.go
similarity index 100%
rename from pkg/store/filenames/filenames.go
rename to pkg/limatype/filenames/filenames.go
diff --git a/pkg/limatype/lima_instance.go b/pkg/limatype/lima_instance.go
new file mode 100644
index 00000000..308dd21e
--- /dev/null
+++ b/pkg/limatype/lima_instance.go
@@ -0,0 +1,109 @@
+// SPDX-FileCopyrightText: Copyright The Lima Authors
+// SPDX-License-Identifier: Apache-2.0
+
+package limatype
+
+import (
+	"encoding/json"
+	"errors"
+	"os"
+	"path/filepath"
+
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
+)
+
+type Status = string
+
+const (
+	StatusUnknown       Status = ""
+	StatusUninitialized Status = "Uninitialized"
+	StatusInstalling    Status = "Installing"
+	StatusBroken        Status = "Broken"
+	StatusStopped       Status = "Stopped"
+	StatusRunning       Status = "Running"
+)
+
+type Instance struct {
+	Name string `json:"name"`
+	// Hostname, not HostName (corresponds to SSH's naming convention)
+	Hostname        string            `json:"hostname"`
+	Status          Status            `json:"status"`
+	Dir             string            `json:"dir"`
+	VMType          VMType            `json:"vmType"`
+	Arch            Arch              `json:"arch"`
+	CPUs            int               `json:"cpus,omitempty"`
+	Memory          int64             `json:"memory,omitempty"` // bytes
+	Disk            int64             `json:"disk,omitempty"`   // bytes
+	Message         string            `json:"message,omitempty"`
+	AdditionalDisks []Disk            `json:"additionalDisks,omitempty"`
+	Networks        []Network         `json:"network,omitempty"`
+	SSHLocalPort    int               `json:"sshLocalPort,omitempty"`
+	SSHConfigFile   string            `json:"sshConfigFile,omitempty"`
+	HostAgentPID    int               `json:"hostAgentPID,omitempty"`
+	DriverPID       int               `json:"driverPID,omitempty"`
+	Errors          []error           `json:"errors,omitempty"`
+	Config          *LimaYAML         `json:"config,omitempty"`
+	SSHAddress      string            `json:"sshAddress,omitempty"`
+	Protected       bool              `json:"protected"`
+	LimaVersion     string            `json:"limaVersion"`
+	Param           map[string]string `json:"param,omitempty"`
+}
+
+// Protect protects the instance to prohibit accidental removal.
+// Protect does not return an error even when the instance is already protected.
+func (inst *Instance) Protect() error {
+	protected := filepath.Join(inst.Dir, filenames.Protected)
+	// TODO: Do an equivalent of `chmod +a "everyone deny delete,delete_child,file_inherit,directory_inherit"`
+	// https://github.com/lima-vm/lima/issues/1595
+	if err := os.WriteFile(protected, nil, 0o400); err != nil {
+		return err
+	}
+	inst.Protected = true
+	return nil
+}
+
+// Unprotect unprotects the instance.
+// Unprotect does not return an error even when the instance is already unprotected.
+func (inst *Instance) Unprotect() error {
+	protected := filepath.Join(inst.Dir, filenames.Protected)
+	if err := os.RemoveAll(protected); err != nil {
+		return err
+	}
+	inst.Protected = false
+	return nil
+}
+
+func (inst *Instance) MarshalJSON() ([]byte, error) {
+	type Alias Instance
+	errorsAsStrings := make([]string, len(inst.Errors))
+	for i, err := range inst.Errors {
+		if err != nil {
+			errorsAsStrings[i] = err.Error()
+		}
+	}
+	return json.Marshal(&struct {
+		*Alias
+		Errors []string `json:"errors,omitempty"`
+	}{
+		Alias:  (*Alias)(inst),
+		Errors: errorsAsStrings,
+	})
+}
+
+func (inst *Instance) UnmarshalJSON(data []byte) error {
+	type Alias Instance
+	aux := &struct {
+		*Alias
+		Errors []string `json:"errors,omitempty"`
+	}{
+		Alias: (*Alias)(inst),
+	}
+	if err := json.Unmarshal(data, &aux); err != nil {
+		return err
+	}
+	inst.Errors = nil
+	for _, msg := range aux.Errors {
+		inst.Errors = append(inst.Errors, errors.New(msg))
+	}
+	return nil
+}
diff --git a/pkg/limayaml/limayaml.go b/pkg/limatype/lima_yaml.go
similarity index 87%
rename from pkg/limayaml/limayaml.go
rename to pkg/limatype/lima_yaml.go
index a21c4aa5..93008dfe 100644
--- a/pkg/limayaml/limayaml.go
+++ b/pkg/limatype/lima_yaml.go
@@ -1,12 +1,15 @@
 // SPDX-FileCopyrightText: Copyright The Lima Authors
 // SPDX-License-Identifier: Apache-2.0
 
-package limayaml
+package limatype
 
 import (
 	"net"
+	"runtime"
 
 	"github.com/opencontainers/go-digest"
+	"github.com/sirupsen/logrus"
+	"golang.org/x/sys/cpu"
 )
 
 type LimaYAML struct {
@@ -46,13 +49,14 @@ type LimaYAML struct {
 	DNS          []net.IP          `yaml:"dns,omitempty" json:"dns,omitempty"`
 	HostResolver HostResolver      `yaml:"hostResolver,omitempty" json:"hostResolver,omitempty"`
 	// `useHostResolver` was deprecated in Lima v0.8.1, removed in Lima v0.14.0. Use `hostResolver.enabled` instead.
-	PropagateProxyEnv    *bool          `yaml:"propagateProxyEnv,omitempty" json:"propagateProxyEnv,omitempty" jsonschema:"nullable"`
-	CACertificates       CACertificates `yaml:"caCerts,omitempty" json:"caCerts,omitempty"`
-	Rosetta              Rosetta        `yaml:"rosetta,omitempty" json:"rosetta,omitempty"`
-	Plain                *bool          `yaml:"plain,omitempty" json:"plain,omitempty" jsonschema:"nullable"`
-	TimeZone             *string        `yaml:"timezone,omitempty" json:"timezone,omitempty" jsonschema:"nullable"`
-	NestedVirtualization *bool          `yaml:"nestedVirtualization,omitempty" json:"nestedVirtualization,omitempty" jsonschema:"nullable"`
-	User                 User           `yaml:"user,omitempty" json:"user,omitempty"`
+	PropagateProxyEnv *bool          `yaml:"propagateProxyEnv,omitempty" json:"propagateProxyEnv,omitempty" jsonschema:"nullable"`
+	CACertificates    CACertificates `yaml:"caCerts,omitempty" json:"caCerts,omitempty"`
+	// Deprecated: Use VMOpts.VZ.Rosetta instead.
+	Rosetta              Rosetta `yaml:"rosetta,omitempty" json:"rosetta,omitempty"`
+	Plain                *bool   `yaml:"plain,omitempty" json:"plain,omitempty" jsonschema:"nullable"`
+	TimeZone             *string `yaml:"timezone,omitempty" json:"timezone,omitempty" jsonschema:"nullable"`
+	NestedVirtualization *bool   `yaml:"nestedVirtualization,omitempty" json:"nestedVirtualization,omitempty" jsonschema:"nullable"`
+	User                 User    `yaml:"user,omitempty" json:"user,omitempty"`
 }
 
 type BaseTemplates []LocatorWithDigest
@@ -108,6 +112,7 @@ type User struct {
 
 type VMOpts struct {
 	QEMU QEMUOpts `yaml:"qemu,omitempty" json:"qemu,omitempty"`
+	VZ   VZOpts   `yaml:"vz,omitempty" json:"vz,omitempty"`
 }
 
 type QEMUOpts struct {
@@ -115,6 +120,10 @@ type QEMUOpts struct {
 	CPUType        CPUType `yaml:"cpuType,omitempty" json:"cpuType,omitempty" jsonschema:"nullable"`
 }
 
+type VZOpts struct {
+	Rosetta Rosetta `yaml:"rosetta,omitempty" json:"rosetta,omitempty"`
+}
+
 type Rosetta struct {
 	Enabled *bool `yaml:"enabled,omitempty" json:"enabled,omitempty" jsonschema:"nullable"`
 	BinFmt  *bool `yaml:"binfmt,omitempty" json:"binfmt,omitempty" jsonschema:"nullable"`
@@ -319,3 +328,75 @@ type CACertificates struct {
 	Files          []string `yaml:"files,omitempty" json:"files,omitempty" jsonschema:"nullable"`
 	Certs          []string `yaml:"certs,omitempty" json:"certs,omitempty" jsonschema:"nullable"`
 }
+
+type PreConfiguredDriverPayload struct {
+	Config   LimaYAML `json:"config"`
+	FilePath string   `json:"filePath"`
+}
+
+type PreConfiguredDriverResponse struct {
+	Config LimaYAML `json:"config"`
+	Error  string   `json:"error,omitempty"`
+}
+
+func NewOS(osname string) OS {
+	switch osname {
+	case "linux":
+		return LINUX
+	default:
+		logrus.Warnf("Unknown os: %s", osname)
+		return osname
+	}
+}
+
+func Goarm() int {
+	if runtime.GOOS != "linux" {
+		return 0
+	}
+	if runtime.GOARCH != "arm" {
+		return 0
+	}
+	if cpu.ARM.HasVFPv3 {
+		return 7
+	}
+	if cpu.ARM.HasVFP {
+		return 6
+	}
+	return 5 // default
+}
+
+func NewArch(arch string) Arch {
+	switch arch {
+	case "amd64":
+		return X8664
+	case "arm64":
+		return AARCH64
+	case "arm":
+		arm := Goarm()
+		if arm == 7 {
+			return ARMV7L
+		}
+		logrus.Warnf("Unknown arm: %d", arm)
+		return arch
+	case "ppc64le":
+		return PPC64LE
+	case "riscv64":
+		return RISCV64
+	case "s390x":
+		return S390X
+	default:
+		logrus.Warnf("Unknown arch: %s", arch)
+		return arch
+	}
+}
+
+func DefaultDriver() VMType {
+	switch runtime.GOOS {
+	case "darwin":
+		return VZ
+	case "windows":
+		return WSL2
+	default:
+		return QEMU
+	}
+}
diff --git a/pkg/limayaml/defaults.go b/pkg/limayaml/defaults.go
index 8a973128..104a85b1 100644
--- a/pkg/limayaml/defaults.go
+++ b/pkg/limayaml/defaults.go
@@ -22,24 +22,22 @@ import (
 	"sync"
 	"text/template"
 
-	"github.com/coreos/go-semver/semver"
 	"github.com/docker/go-units"
 	"github.com/goccy/go-yaml"
 	"github.com/pbnjay/memory"
 	"github.com/sirupsen/logrus"
-	"golang.org/x/sys/cpu"
 
 	"github.com/lima-vm/lima/v2/pkg/instance/hostname"
 	"github.com/lima-vm/lima/v2/pkg/ioutilx"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
+	"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 	"github.com/lima-vm/lima/v2/pkg/localpathutil"
 	. "github.com/lima-vm/lima/v2/pkg/must"
 	"github.com/lima-vm/lima/v2/pkg/networks"
 	"github.com/lima-vm/lima/v2/pkg/osutil"
 	"github.com/lima-vm/lima/v2/pkg/ptr"
-	"github.com/lima-vm/lima/v2/pkg/store/dirnames"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
 	"github.com/lima-vm/lima/v2/pkg/version"
-	"github.com/lima-vm/lima/v2/pkg/version/versionutil"
 )
 
 const (
@@ -65,10 +63,10 @@ var (
 var defaultContainerdYAML []byte
 
 type ContainerdYAML struct {
-	Archives []File
+	Archives []limatype.File
 }
 
-func defaultContainerdArchives() []File {
+func defaultContainerdArchives() []limatype.File {
 	var containerd ContainerdYAML
 	err := yaml.UnmarshalWithOptions(defaultContainerdYAML, &containerd, yaml.Strict())
 	if err != nil {
@@ -78,8 +76,8 @@ func defaultContainerdArchives() []File {
 }
 
 // FirstUsernetIndex gets the index of first usernet network under l.Network[]. Returns -1 if no usernet network found.
-func FirstUsernetIndex(l *LimaYAML) int {
-	return slices.IndexFunc(l.Networks, func(network Network) bool { return networks.IsUsernet(network.Lima) })
+func FirstUsernetIndex(l *limatype.LimaYAML) int {
+	return slices.IndexFunc(l.Networks, func(network limatype.Network) bool { return networks.IsUsernet(network.Lima) })
 }
 
 func MACAddress(uniqueID string) string {
@@ -138,21 +136,10 @@ func defaultGuestInstallPrefix() string {
 //   - Networks are appended in d, y, o order
 //   - DNS are picked from the highest priority where DNS is not empty.
 //   - CACertificates Files and Certs are uniquely appended in d, y, o order
-func FillDefault(ctx context.Context, y, d, o *LimaYAML, filePath string, warn bool) {
+func FillDefault(ctx context.Context, y, d, o *limatype.LimaYAML, filePath string, warn bool) {
 	instDir := filepath.Dir(filePath)
 
-	// existingLimaVersion can be empty if the instance was created with Lima prior to v0.20,
-	var existingLimaVersion string
-	if !isExistingInstanceDir(instDir) {
-		existingLimaVersion = version.Version
-	} else {
-		limaVersionFile := filepath.Join(instDir, filenames.LimaVersion)
-		if b, err := os.ReadFile(limaVersionFile); err == nil {
-			existingLimaVersion = strings.TrimSpace(string(b))
-		} else if !errors.Is(err, os.ErrNotExist) {
-			logrus.WithError(err).Warnf("Failed to read %q", limaVersionFile)
-		}
-	}
+	existingLimaVersion := ExistingLimaVersion(instDir)
 
 	if y.User.Name == nil {
 		y.User.Name = d.User.Name
@@ -222,7 +209,7 @@ func FillDefault(ctx context.Context, y, d, o *LimaYAML, filePath string, warn b
 	if o.VMType != nil {
 		y.VMType = o.VMType
 	}
-	y.VMType = ptr.Of(ResolveVMType(y, d, o, filePath))
+
 	if y.OS == nil {
 		y.OS = d.OS
 	}
@@ -252,27 +239,6 @@ func FillDefault(ctx context.Context, y, d, o *LimaYAML, filePath string, warn b
 		}
 	}
 
-	if y.VMOpts.QEMU.CPUType == nil {
-		y.VMOpts.QEMU.CPUType = CPUType{}
-	}
-	// TODO: This check should be removed when we completely eliminate `CPUType` from limayaml.
-	if len(y.CPUType) > 0 {
-		if warn {
-			logrus.Warn("The top-level `cpuType` field is deprecated and will be removed in a future release. Please migrate to `vmOpts.qemu.cpuType`.")
-		}
-		for arch, v := range y.CPUType {
-			if v == "" {
-				continue
-			}
-			if existing, ok := y.VMOpts.QEMU.CPUType[arch]; ok && existing != "" && existing != v {
-				logrus.Warnf("Conflicting cpuType for arch %q: top-level=%q, vmOpts.qemu=%q; using vmOpts.qemu value", arch, v, existing)
-				continue
-			}
-			y.VMOpts.QEMU.CPUType[arch] = v
-		}
-		y.CPUType = nil
-	}
-
 	if y.CPUs == nil {
 		y.CPUs = d.CPUs
 	}
@@ -331,9 +297,6 @@ func FillDefault(ctx context.Context, y, d, o *LimaYAML, filePath string, warn b
 	if o.Video.VNC.Display != nil {
 		y.Video.VNC.Display = o.Video.VNC.Display
 	}
-	if (y.Video.VNC.Display == nil || *y.Video.VNC.Display == "") && *y.VMType == QEMU {
-		y.Video.VNC.Display = ptr.Of("127.0.0.1:0,to=9")
-	}
 
 	if y.Firmware.LegacyBIOS == nil {
 		y.Firmware.LegacyBIOS = d.Firmware.LegacyBIOS
@@ -424,12 +387,12 @@ func FillDefault(ctx context.Context, y, d, o *LimaYAML, filePath string, warn b
 	for i := range y.Provision {
 		provision := &y.Provision[i]
 		if provision.Mode == "" {
-			provision.Mode = ProvisionModeSystem
+			provision.Mode = limatype.ProvisionModeSystem
 		}
-		if provision.Mode == ProvisionModeDependency && provision.SkipDefaultDependencyResolution == nil {
+		if provision.Mode == limatype.ProvisionModeDependency && provision.SkipDefaultDependencyResolution == nil {
 			provision.SkipDefaultDependencyResolution = ptr.Of(false)
 		}
-		if provision.Mode == ProvisionModeData {
+		if provision.Mode == limatype.ProvisionModeData {
 			if provision.Content == nil {
 				provision.Content = ptr.Of("")
 			} else {
@@ -510,7 +473,7 @@ func FillDefault(ctx context.Context, y, d, o *LimaYAML, filePath string, warn b
 	}
 	if y.Containerd.User == nil {
 		switch *y.Arch {
-		case X8664, AARCH64:
+		case limatype.X8664, limatype.AARCH64:
 			y.Containerd.User = ptr.Of(true)
 		default:
 			y.Containerd.User = ptr.Of(false)
@@ -532,7 +495,7 @@ func FillDefault(ctx context.Context, y, d, o *LimaYAML, filePath string, warn b
 	for i := range y.Probes {
 		probe := &y.Probes[i]
 		if probe.Mode == "" {
-			probe.Mode = ProbeModeReadiness
+			probe.Mode = limatype.ProbeModeReadiness
 		}
 		if probe.Description == "" {
 			probe.Description = fmt.Sprintf("user probe %d/%d", i+1, len(y.Probes))
@@ -585,7 +548,7 @@ func FillDefault(ctx context.Context, y, d, o *LimaYAML, filePath string, warn b
 		y.PropagateProxyEnv = ptr.Of(true)
 	}
 
-	networks := make([]Network, 0, len(d.Networks)+len(y.Networks)+len(o.Networks))
+	networks := make([]limatype.Network, 0, len(d.Networks)+len(y.Networks)+len(o.Networks))
 	iface := make(map[string]int)
 	for _, nw := range slices.Concat(d.Networks, y.Networks, o.Networks) {
 		if i, ok := iface[nw.Interface]; ok {
@@ -632,15 +595,6 @@ func FillDefault(ctx context.Context, y, d, o *LimaYAML, filePath string, warn b
 	}
 
 	y.MountTypesUnsupported = slices.Concat(o.MountTypesUnsupported, y.MountTypesUnsupported, d.MountTypesUnsupported)
-	mountTypesUnsupported := make(map[string]struct{})
-	for _, f := range y.MountTypesUnsupported {
-		mountTypesUnsupported[f] = struct{}{}
-	}
-
-	if runtime.GOOS == "windows" {
-		// QEMU for Windows does not support 9p
-		mountTypesUnsupported[NINEP] = struct{}{}
-	}
 
 	// MountType has to be resolved before resolving Mounts
 	if y.MountType == nil {
@@ -649,28 +603,6 @@ func FillDefault(ctx context.Context, y, d, o *LimaYAML, filePath string, warn b
 	if o.MountType != nil {
 		y.MountType = o.MountType
 	}
-	if y.MountType == nil || *y.MountType == "" || *y.MountType == "default" {
-		switch *y.VMType {
-		case VZ:
-			y.MountType = ptr.Of(VIRTIOFS)
-		case QEMU:
-			y.MountType = ptr.Of(NINEP)
-			if _, ok := mountTypesUnsupported[NINEP]; ok {
-				// Use REVSSHFS if the instance does not support 9p
-				y.MountType = ptr.Of(REVSSHFS)
-			} else if isExistingInstanceDir(instDir) && !versionutil.GreaterEqual(existingLimaVersion, "1.0.0") {
-				// Use REVSSHFS if the instance was created with Lima prior to v1.0
-				y.MountType = ptr.Of(REVSSHFS)
-			}
-		default:
-			y.MountType = ptr.Of(REVSSHFS)
-		}
-	}
-
-	if _, ok := mountTypesUnsupported[*y.MountType]; ok {
-		// We cannot return an error here, but Validate() will return it.
-		logrus.Warnf("Unsupported mount type: %q", *y.MountType)
-	}
 
 	if y.MountInotify == nil {
 		y.MountInotify = d.MountInotify
@@ -684,7 +616,7 @@ func FillDefault(ctx context.Context, y, d, o *LimaYAML, filePath string, warn b
 
 	// Combine all mounts; highest priority entry determines writable status.
 	// Only works for exact matches; does not normalize case or resolve symlinks.
-	mounts := make([]Mount, 0, len(d.Mounts)+len(y.Mounts)+len(o.Mounts))
+	mounts := make([]limatype.Mount, 0, len(d.Mounts)+len(y.Mounts)+len(o.Mounts))
 	location := make(map[string]int)
 	for _, mount := range slices.Concat(d.Mounts, y.Mounts, o.Mounts) {
 		if out, err := executeHostTemplate(mount.Location, instDir, y.Param); err == nil {
@@ -757,9 +689,6 @@ func FillDefault(ctx context.Context, y, d, o *LimaYAML, filePath string, warn b
 		if mount.NineP.Msize == nil {
 			mounts[i].NineP.Msize = ptr.Of(Default9pMsize)
 		}
-		if mount.Virtiofs.QueueSize == nil && *y.VMType == QEMU && *y.MountType == VIRTIOFS {
-			mounts[i].Virtiofs.QueueSize = ptr.Of(DefaultVirtiofsQueueSize)
-		}
 		if mount.Writable == nil {
 			mount.Writable = ptr.Of(false)
 		}
@@ -821,28 +750,20 @@ func FillDefault(ctx context.Context, y, d, o *LimaYAML, filePath string, warn b
 	y.CACertificates.Files = unique(slices.Concat(d.CACertificates.Files, y.CACertificates.Files, o.CACertificates.Files))
 	y.CACertificates.Certs = unique(slices.Concat(d.CACertificates.Certs, y.CACertificates.Certs, o.CACertificates.Certs))
 
-	if runtime.GOOS == "darwin" && IsNativeArch(AARCH64) {
-		if y.Rosetta.Enabled == nil {
-			y.Rosetta.Enabled = d.Rosetta.Enabled
-		}
-		if o.Rosetta.Enabled != nil {
-			y.Rosetta.Enabled = o.Rosetta.Enabled
+	if runtime.GOOS == "darwin" && IsNativeArch(limatype.AARCH64) {
+		if y.VMOpts.VZ.Rosetta.Enabled == nil {
+			y.VMOpts.VZ.Rosetta.Enabled = d.VMOpts.VZ.Rosetta.Enabled
 		}
-		if y.Rosetta.Enabled == nil {
-			y.Rosetta.Enabled = ptr.Of(false)
+		if o.VMOpts.VZ.Rosetta.Enabled != nil {
+			y.VMOpts.VZ.Rosetta.Enabled = o.VMOpts.VZ.Rosetta.Enabled
 		}
-	} else {
-		y.Rosetta.Enabled = ptr.Of(false)
 	}
 
-	if y.Rosetta.BinFmt == nil {
-		y.Rosetta.BinFmt = d.Rosetta.BinFmt
-	}
-	if o.Rosetta.BinFmt != nil {
-		y.Rosetta.BinFmt = o.Rosetta.BinFmt
+	if y.VMOpts.VZ.Rosetta.BinFmt == nil {
+		y.VMOpts.VZ.Rosetta.BinFmt = d.VMOpts.VZ.Rosetta.BinFmt
 	}
-	if y.Rosetta.BinFmt == nil {
-		y.Rosetta.BinFmt = ptr.Of(false)
+	if o.VMOpts.VZ.Rosetta.BinFmt != nil {
+		y.VMOpts.VZ.Rosetta.BinFmt = o.VMOpts.VZ.Rosetta.BinFmt
 	}
 
 	if y.NestedVirtualization == nil {
@@ -868,7 +789,23 @@ func FillDefault(ctx context.Context, y, d, o *LimaYAML, filePath string, warn b
 	fixUpForPlainMode(y)
 }
 
-func fixUpForPlainMode(y *LimaYAML) {
+// ExistingLimaVersion returns empty if the instance was created with Lima prior to v0.20.
+func ExistingLimaVersion(instDir string) string {
+	if !IsExistingInstanceDir(instDir) {
+		return version.Version
+	}
+
+	limaVersionFile := filepath.Join(instDir, filenames.LimaVersion)
+	if b, err := os.ReadFile(limaVersionFile); err == nil {
+		return strings.TrimSpace(string(b))
+	} else if !errors.Is(err, os.ErrNotExist) {
+		logrus.WithError(err).Warnf("Failed to read %q", limaVersionFile)
+	}
+
+	return version.Version
+}
+
+func fixUpForPlainMode(y *limatype.LimaYAML) {
 	if !*y.Plain {
 		return
 	}
@@ -876,12 +813,12 @@ func fixUpForPlainMode(y *LimaYAML) {
 	y.PortForwards = nil
 	y.Containerd.System = ptr.Of(false)
 	y.Containerd.User = ptr.Of(false)
-	y.Rosetta.BinFmt = ptr.Of(false)
-	y.Rosetta.Enabled = ptr.Of(false)
+	y.VMOpts.VZ.Rosetta.BinFmt = ptr.Of(false)
+	y.VMOpts.VZ.Rosetta.Enabled = ptr.Of(false)
 	y.TimeZone = ptr.Of("")
 }
 
-func executeGuestTemplate(format, instDir string, user User, param map[string]string) (bytes.Buffer, error) {
+func executeGuestTemplate(format, instDir string, user limatype.User, param map[string]string) (bytes.Buffer, error) {
 	tmpl, err := template.New("").Parse(format)
 	if err == nil {
 		name := filepath.Base(instDir)
@@ -933,9 +870,9 @@ func executeHostTemplate(format, instDir string, param map[string]string) (bytes
 	return bytes.Buffer{}, err
 }
 
-func FillPortForwardDefaults(rule *PortForward, instDir string, user User, param map[string]string) {
+func FillPortForwardDefaults(rule *limatype.PortForward, instDir string, user limatype.User, param map[string]string) {
 	if rule.Proto == "" {
-		rule.Proto = ProtoTCP
+		rule.Proto = limatype.ProtoTCP
 	}
 	if rule.GuestIP == nil {
 		if rule.GuestIPMustBeZero {
@@ -983,7 +920,7 @@ func FillPortForwardDefaults(rule *PortForward, instDir string, user User, param
 	}
 }
 
-func FillCopyToHostDefaults(rule *CopyToHost, instDir string, user User, param map[string]string) {
+func FillCopyToHostDefaults(rule *limatype.CopyToHost, instDir string, user limatype.User, param map[string]string) {
 	if rule.GuestFile != "" {
 		if out, err := executeGuestTemplate(rule.GuestFile, instDir, user, param); err == nil {
 			rule.GuestFile = out.String()
@@ -1000,72 +937,7 @@ func FillCopyToHostDefaults(rule *CopyToHost, instDir string, user User, param m
 	}
 }
 
-func NewOS(osname string) OS {
-	switch osname {
-	case "linux":
-		return LINUX
-	default:
-		logrus.Warnf("Unknown os: %s", osname)
-		return osname
-	}
-}
-
-func goarm() int {
-	if runtime.GOOS != "linux" {
-		return 0
-	}
-	if runtime.GOARCH != "arm" {
-		return 0
-	}
-	if cpu.ARM.HasVFPv3 {
-		return 7
-	}
-	if cpu.ARM.HasVFP {
-		return 6
-	}
-	return 5 // default
-}
-
-func NewArch(arch string) Arch {
-	switch arch {
-	case "amd64":
-		return X8664
-	case "arm64":
-		return AARCH64
-	case "arm":
-		arm := goarm()
-		if arm == 7 {
-			return ARMV7L
-		}
-		logrus.Warnf("Unknown arm: %d", arm)
-		return arch
-	case "ppc64le":
-		return PPC64LE
-	case "riscv64":
-		return RISCV64
-	case "s390x":
-		return S390X
-	default:
-		logrus.Warnf("Unknown arch: %s", arch)
-		return arch
-	}
-}
-
-func NewVMType(driver string) VMType {
-	switch driver {
-	case "vz":
-		return VZ
-	case "qemu":
-		return QEMU
-	case "wsl2":
-		return WSL2
-	default:
-		logrus.Warnf("Unknown driver: %s", driver)
-		return driver
-	}
-}
-
-func isExistingInstanceDir(dir string) bool {
+func IsExistingInstanceDir(dir string) bool {
 	// existence of "lima.yaml" does not signify existence of the instance,
 	// because the file is created during the initialization of the instance.
 	for _, f := range []string{
@@ -1080,97 +952,16 @@ func isExistingInstanceDir(dir string) bool {
 	return false
 }
 
-func ResolveVMType(y, d, o *LimaYAML, filePath string) VMType {
-	// Check if the VMType is explicitly specified
-	for i, f := range []*LimaYAML{o, y, d} {
-		if f.VMType != nil && *f.VMType != "" && *f.VMType != "default" {
-			logrus.Debugf("ResolveVMType: resolved VMType %q (explicitly specified in []*LimaYAML{o,y,d}[%d])", *f.VMType, i)
-			return NewVMType(*f.VMType)
-		}
-	}
-
-	// If this is an existing instance, guess the VMType from the contents of the instance directory.
-	if dir, basename := filepath.Split(filePath); dir != "" && basename == filenames.LimaYAML && isExistingInstanceDir(dir) {
-		if runtime.GOOS == "darwin" {
-			vzIdentifier := filepath.Join(dir, filenames.VzIdentifier) // since Lima v0.14
-			if _, err := os.Lstat(vzIdentifier); !errors.Is(err, os.ErrNotExist) {
-				logrus.Debugf("ResolveVMType: resolved VMType %q (existing instance, with %q)", VZ, vzIdentifier)
-				return VZ
-			}
-			logrus.Debugf("ResolveVMType: resolved VMType %q (existing instance, without %q)", QEMU, vzIdentifier)
-			return QEMU
-		}
-		logrus.Debugf("ResolveVMType: resolved VMType %q (existing instance)", QEMU)
-		return QEMU
-	}
-
-	// Resolve the best type, depending on GOOS
-	switch runtime.GOOS {
-	case "darwin":
-		macOSProductVersion, err := osutil.ProductVersion()
-		if err != nil {
-			logrus.WithError(err).Warn("Failed to get macOS product version")
-			logrus.Debugf("ResolveVMType: resolved VMType %q (default for unknown version of macOS)", QEMU)
-			return QEMU
-		}
-		// Virtualization.framework in macOS prior to 13.5 could not boot Linux kernel v6.2 on Intel
-		// https://github.com/lima-vm/lima/issues/1577
-		if macOSProductVersion.LessThan(*semver.New("13.5.0")) {
-			logrus.Debugf("ResolveVMType: resolved VMType %q (default for macOS prior to 13.5)", QEMU)
-			return QEMU
-		}
-		// Use QEMU if the config depends on QEMU
-		for i, f := range []*LimaYAML{o, y, d} {
-			if f.Arch != nil && !IsNativeArch(*f.Arch) {
-				logrus.Debugf("ResolveVMType: resolved VMType %q (non-native arch=%q is specified in []*LimaYAML{o,y,d}[%d])", QEMU, *f.Arch, i)
-				return QEMU
-			}
-			if ResolveArch(f.Arch) == X8664 && f.Firmware.LegacyBIOS != nil && *f.Firmware.LegacyBIOS {
-				logrus.Debugf("ResolveVMType: resolved VMType %q (firmware.legacyBIOS is specified in []*LimaYAML{o,y,d}[%d], on x86_64)", QEMU, i)
-				return QEMU
-			}
-			if f.MountType != nil && *f.MountType == NINEP {
-				logrus.Debugf("ResolveVMType: resolved VMType %q (mountType=%q is specified in []*LimaYAML{o,y,d}[%d])", QEMU, NINEP, i)
-				return QEMU
-			}
-			if f.Audio.Device != nil {
-				switch *f.Audio.Device {
-				case "", "none", "default", "vz":
-					// NOP
-				default:
-					logrus.Debugf("ResolveVMType: resolved VMType %q (audio.device=%q is specified in []*LimaYAML{o,y,d}[%d])", QEMU, *f.Audio.Device, i)
-					return QEMU
-				}
-			}
-			if f.Video.Display != nil {
-				switch *f.Video.Display {
-				case "", "none", "default", "vz":
-					// NOP
-				default:
-					logrus.Debugf("ResolveVMType: resolved VMType %q (video.display=%q is specified in []*LimaYAML{o,y,d}[%d])", QEMU, *f.Video.Display, i)
-					return QEMU
-				}
-			}
-		}
-		// Use VZ if the config is compatible with VZ
-		logrus.Debugf("ResolveVMType: resolved VMType %q (default for macOS 13.5 and later)", VZ)
-		return VZ
-	default:
-		logrus.Debugf("ResolveVMType: resolved VMType %q (default for GOOS=%q)", QEMU, runtime.GOOS)
-		return QEMU
-	}
-}
-
-func ResolveOS(s *string) OS {
+func ResolveOS(s *string) limatype.OS {
 	if s == nil || *s == "" || *s == "default" {
-		return NewOS("linux")
+		return limatype.NewOS("linux")
 	}
 	return *s
 }
 
-func ResolveArch(s *string) Arch {
+func ResolveArch(s *string) limatype.Arch {
 	if s == nil || *s == "" || *s == "default" {
-		return NewArch(runtime.GOARCH)
+		return limatype.NewArch(runtime.GOARCH)
 	}
 	return *s
 }
@@ -1225,13 +1016,13 @@ func HasHostCPU() bool {
 	return false
 }
 
-func IsNativeArch(arch Arch) bool {
-	nativeX8664 := arch == X8664 && runtime.GOARCH == "amd64"
-	nativeAARCH64 := arch == AARCH64 && runtime.GOARCH == "arm64"
-	nativeARMV7L := arch == ARMV7L && runtime.GOARCH == "arm" && goarm() == 7
-	nativePPC64LE := arch == PPC64LE && runtime.GOARCH == "ppc64le"
-	nativeRISCV64 := arch == RISCV64 && runtime.GOARCH == "riscv64"
-	nativeS390X := arch == S390X && runtime.GOARCH == "s390x"
+func IsNativeArch(arch limatype.Arch) bool {
+	nativeX8664 := arch == limatype.X8664 && runtime.GOARCH == "amd64"
+	nativeAARCH64 := arch == limatype.AARCH64 && runtime.GOARCH == "arm64"
+	nativeARMV7L := arch == limatype.ARMV7L && runtime.GOARCH == "arm" && limatype.Goarm() == 7
+	nativePPC64LE := arch == limatype.PPC64LE && runtime.GOARCH == "ppc64le"
+	nativeRISCV64 := arch == limatype.RISCV64 && runtime.GOARCH == "riscv64"
+	nativeS390X := arch == limatype.S390X && runtime.GOARCH == "s390x"
 	return nativeX8664 || nativeAARCH64 || nativeARMV7L || nativePPC64LE || nativeRISCV64 || nativeS390X
 }
 
diff --git a/pkg/limayaml/load.go b/pkg/limayaml/load.go
index 6436d585..78ecce98 100644
--- a/pkg/limayaml/load.go
+++ b/pkg/limayaml/load.go
@@ -12,26 +12,27 @@ import (
 
 	"github.com/sirupsen/logrus"
 
-	"github.com/lima-vm/lima/v2/pkg/store/dirnames"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
+	"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 )
 
 // Load loads the yaml and fulfills unspecified fields with the default values.
 //
 // Load does not validate. Use Validate for validation.
-func Load(ctx context.Context, b []byte, filePath string) (*LimaYAML, error) {
+func Load(ctx context.Context, b []byte, filePath string) (*limatype.LimaYAML, error) {
 	return load(ctx, b, filePath, false)
 }
 
 // LoadWithWarnings will call FillDefaults with warnings enabled (e.g. when
 // the username is not valid on Linux and must be replaced by "Lima").
 // It is called when creating or editing an instance.
-func LoadWithWarnings(ctx context.Context, b []byte, filePath string) (*LimaYAML, error) {
+func LoadWithWarnings(ctx context.Context, b []byte, filePath string) (*limatype.LimaYAML, error) {
 	return load(ctx, b, filePath, true)
 }
 
-func load(ctx context.Context, b []byte, filePath string, warn bool) (*LimaYAML, error) {
-	var y, d, o LimaYAML
+func load(ctx context.Context, b []byte, filePath string, warn bool) (*limatype.LimaYAML, error) {
+	var y, d, o limatype.LimaYAML
 
 	if err := Unmarshal(b, &y, fmt.Sprintf("main file %q", filePath)); err != nil {
 		return nil, err
@@ -69,5 +70,6 @@ func load(ctx context.Context, b []byte, filePath string, warn bool) (*LimaYAML,
 	}
 
 	FillDefault(ctx, &y, &d, &o, filePath, warn)
+
 	return &y, nil
 }
diff --git a/pkg/limayaml/marshal.go b/pkg/limayaml/marshal.go
index efa85530..a43821f3 100644
--- a/pkg/limayaml/marshal.go
+++ b/pkg/limayaml/marshal.go
@@ -9,6 +9,7 @@ import (
 	"github.com/goccy/go-yaml"
 	"github.com/sirupsen/logrus"
 
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 	"github.com/lima-vm/lima/v2/pkg/yqutil"
 )
 
@@ -18,7 +19,7 @@ const (
 )
 
 // Marshal the struct as a YAML document, optionally as a stream.
-func Marshal(y *LimaYAML, stream bool) ([]byte, error) {
+func Marshal(y *limatype.LimaYAML, stream bool) ([]byte, error) {
 	b, err := yaml.Marshal(y)
 	if err != nil {
 		return nil, err
@@ -30,40 +31,40 @@ func Marshal(y *LimaYAML, stream bool) ([]byte, error) {
 	return b, nil
 }
 
-func unmarshalDisk(dst *Disk, b []byte) error {
+func unmarshalDisk(dst *limatype.Disk, b []byte) error {
 	var s string
 	if err := yaml.Unmarshal(b, &s); err == nil {
-		*dst = Disk{Name: s}
+		*dst = limatype.Disk{Name: s}
 		return nil
 	}
 	return yaml.Unmarshal(b, dst)
 }
 
 // unmarshalBaseTemplates unmarshalls `base` which is either a string or a list of Locators.
-func unmarshalBaseTemplates(dst *BaseTemplates, b []byte) error {
+func unmarshalBaseTemplates(dst *limatype.BaseTemplates, b []byte) error {
 	var s string
 	if err := yaml.Unmarshal(b, &s); err == nil {
-		*dst = BaseTemplates{LocatorWithDigest{URL: s}}
+		*dst = limatype.BaseTemplates{limatype.LocatorWithDigest{URL: s}}
 		return nil
 	}
-	return yaml.UnmarshalWithOptions(b, dst, yaml.CustomUnmarshaler[LocatorWithDigest](unmarshalLocatorWithDigest))
+	return yaml.UnmarshalWithOptions(b, dst, yaml.CustomUnmarshaler[limatype.LocatorWithDigest](unmarshalLocatorWithDigest))
 }
 
 // unmarshalLocator unmarshalls a locator which is either a string or a Locator struct.
-func unmarshalLocatorWithDigest(dst *LocatorWithDigest, b []byte) error {
+func unmarshalLocatorWithDigest(dst *limatype.LocatorWithDigest, b []byte) error {
 	var s string
 	if err := yaml.Unmarshal(b, &s); err == nil {
-		*dst = LocatorWithDigest{URL: s}
+		*dst = limatype.LocatorWithDigest{URL: s}
 		return nil
 	}
 	return yaml.Unmarshal(b, dst)
 }
 
-func Unmarshal(data []byte, y *LimaYAML, comment string) error {
+func Unmarshal(data []byte, y *limatype.LimaYAML, comment string) error {
 	opts := []yaml.DecodeOption{
-		yaml.CustomUnmarshaler[BaseTemplates](unmarshalBaseTemplates),
-		yaml.CustomUnmarshaler[Disk](unmarshalDisk),
-		yaml.CustomUnmarshaler[LocatorWithDigest](unmarshalLocatorWithDigest),
+		yaml.CustomUnmarshaler[limatype.BaseTemplates](unmarshalBaseTemplates),
+		yaml.CustomUnmarshaler[limatype.Disk](unmarshalDisk),
+		yaml.CustomUnmarshaler[limatype.LocatorWithDigest](unmarshalLocatorWithDigest),
 	}
 	if err := yaml.UnmarshalWithOptions(data, y, opts...); err != nil {
 		return fmt.Errorf("failed to unmarshal YAML (%s): %w", comment, err)
@@ -75,7 +76,7 @@ func Unmarshal(data []byte, y *LimaYAML, comment string) error {
 	}
 	// Finally log a warning if the YAML file violates the "strict" rules
 	opts = append(opts, yaml.Strict())
-	var ignore LimaYAML
+	var ignore limatype.LimaYAML
 	if err := yaml.UnmarshalWithOptions(data, &ignore, opts...); err != nil {
 		logrus.WithField("comment", comment).WithError(err).Warn("Non-strict YAML detected; please check for typos")
 	}
diff --git a/pkg/limayaml/validate.go b/pkg/limayaml/validate.go
index fa787ba8..cd869ec6 100644
--- a/pkg/limayaml/validate.go
+++ b/pkg/limayaml/validate.go
@@ -18,11 +18,12 @@ import (
 	"strings"
 	"unicode"
 
-	"github.com/coreos/go-semver/semver"
 	"github.com/docker/go-units"
 	"github.com/sirupsen/logrus"
 
+	"github.com/lima-vm/lima/v2/pkg/driverutil"
 	"github.com/lima-vm/lima/v2/pkg/identifiers"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 	"github.com/lima-vm/lima/v2/pkg/localpathutil"
 	"github.com/lima-vm/lima/v2/pkg/networks"
 	"github.com/lima-vm/lima/v2/pkg/osutil"
@@ -30,7 +31,7 @@ import (
 	"github.com/lima-vm/lima/v2/pkg/version/versionutil"
 )
 
-func Validate(y *LimaYAML, warn bool) error {
+func Validate(y *limatype.LimaYAML, warn bool) error {
 	var errs error
 
 	if len(y.Base) > 0 {
@@ -47,30 +48,14 @@ func Validate(y *LimaYAML, warn bool) error {
 			errs = errors.Join(errs, fmt.Errorf("template requires Lima version %q; this is only %q", *y.MinimumLimaVersion, version.Version))
 		}
 	}
-	if y.VMOpts.QEMU.MinimumVersion != nil {
-		if _, err := semver.NewVersion(*y.VMOpts.QEMU.MinimumVersion); err != nil {
-			errs = errors.Join(errs, fmt.Errorf("field `vmOpts.qemu.minimumVersion` must be a semvar value, got %q: %w", *y.VMOpts.QEMU.MinimumVersion, err))
-		}
-	}
+
 	switch *y.OS {
-	case LINUX:
+	case limatype.LINUX:
 	default:
-		errs = errors.Join(errs, fmt.Errorf("field `os` must be %q; got %q", LINUX, *y.OS))
+		errs = errors.Join(errs, fmt.Errorf("field `os` must be %q; got %q", limatype.LINUX, *y.OS))
 	}
-	if !slices.Contains(ArchTypes, *y.Arch) {
-		errs = errors.Join(errs, fmt.Errorf("field `arch` must be one of %v; got %q", ArchTypes, *y.Arch))
-	}
-	switch *y.VMType {
-	case QEMU:
-		// NOP
-	case WSL2:
-		// NOP
-	case VZ:
-		if !IsNativeArch(*y.Arch) {
-			errs = errors.Join(errs, fmt.Errorf("field `arch` must be %q for VZ; got %q", NewArch(runtime.GOARCH), *y.Arch))
-		}
-	default:
-		errs = errors.Join(errs, fmt.Errorf("field `vmType` must be %q, %q, %q; got %q", QEMU, VZ, WSL2, *y.VMType))
+	if !slices.Contains(limatype.ArchTypes, *y.Arch) {
+		errs = errors.Join(errs, fmt.Errorf("field `arch` must be one of %v; got %q", limatype.ArchTypes, *y.Arch))
 	}
 
 	if len(y.Images) == 0 {
@@ -164,14 +149,16 @@ func Validate(y *LimaYAML, warn bool) error {
 		}
 	}
 
-	switch *y.MountType {
-	case REVSSHFS, NINEP, VIRTIOFS, WSLMount:
-	default:
-		errs = errors.Join(errs, fmt.Errorf("field `mountType` must be %q or %q or %q, or %q, got %q", REVSSHFS, NINEP, VIRTIOFS, WSLMount, *y.MountType))
-	}
+	if y.MountType != nil {
+		switch *y.MountType {
+		case limatype.REVSSHFS, limatype.NINEP, limatype.VIRTIOFS, limatype.WSLMount:
+		default:
+			errs = errors.Join(errs, fmt.Errorf("field `mountType` must be %q or %q or %q, or %q, got %q", limatype.REVSSHFS, limatype.NINEP, limatype.VIRTIOFS, limatype.WSLMount, *y.MountType))
+		}
 
-	if slices.Contains(y.MountTypesUnsupported, *y.MountType) {
-		errs = errors.Join(errs, fmt.Errorf("field `mountType` must not be one of %v (`mountTypesUnsupported`), got %q", y.MountTypesUnsupported, *y.MountType))
+		if slices.Contains(y.MountTypesUnsupported, *y.MountType) {
+			errs = errors.Join(errs, fmt.Errorf("field `mountType` must not be one of %v (`mountTypesUnsupported`), got %q", y.MountTypesUnsupported, *y.MountType))
+		}
 	}
 
 	if warn && runtime.GOOS != "linux" {
@@ -194,55 +181,55 @@ func Validate(y *LimaYAML, warn bool) error {
 			}
 		}
 		switch p.Mode {
-		case ProvisionModeSystem, ProvisionModeUser, ProvisionModeBoot, ProvisionModeData, ProvisionModeDependency, ProvisionModeAnsible:
+		case limatype.ProvisionModeSystem, limatype.ProvisionModeUser, limatype.ProvisionModeBoot, limatype.ProvisionModeData, limatype.ProvisionModeDependency, limatype.ProvisionModeAnsible:
 		default:
 			errs = errors.Join(errs, fmt.Errorf("field `provision[%d].mode` must one of %q, %q, %q, %q, %q, or %q",
-				i, ProvisionModeSystem, ProvisionModeUser, ProvisionModeBoot, ProvisionModeData, ProvisionModeDependency, ProvisionModeAnsible))
+				i, limatype.ProvisionModeSystem, limatype.ProvisionModeUser, limatype.ProvisionModeBoot, limatype.ProvisionModeData, limatype.ProvisionModeDependency, limatype.ProvisionModeAnsible))
 		}
-		if p.Mode != ProvisionModeDependency && p.SkipDefaultDependencyResolution != nil {
+		if p.Mode != limatype.ProvisionModeDependency && p.SkipDefaultDependencyResolution != nil {
 			errs = errors.Join(errs, fmt.Errorf("field `provision[%d].mode` cannot set skipDefaultDependencyResolution, only valid on scripts of type %q",
-				i, ProvisionModeDependency))
+				i, limatype.ProvisionModeDependency))
 		}
 
 		// This can lead to fatal Panic if p.Path is nil, better to return an error here
-		if p.Mode == ProvisionModeData {
+		if p.Mode == limatype.ProvisionModeData {
 			if p.Path == nil {
-				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].path` must not be empty when mode is %q", i, ProvisionModeData))
+				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].path` must not be empty when mode is %q", i, limatype.ProvisionModeData))
 				return errs
 			}
 			if !path.IsAbs(*p.Path) {
 				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].path` must be an absolute path", i))
 			}
 			if p.Content == nil {
-				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].content` must not be empty when mode is %q", i, ProvisionModeData))
+				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].content` must not be empty when mode is %q", i, limatype.ProvisionModeData))
 			}
 			// FillDefaults makes sure that p.Permissions is not nil
 			if _, err := strconv.ParseInt(*p.Permissions, 8, 64); err != nil {
 				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].permissions` must be an octal number: %w", i, err))
 			}
 		} else {
-			if p.Script == "" && p.Mode != ProvisionModeAnsible {
+			if p.Script == "" && p.Mode != limatype.ProvisionModeAnsible {
 				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].script` must not be empty", i))
 			}
 			if p.Content != nil {
-				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].content` can only be set when mode is %q", i, ProvisionModeData))
+				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].content` can only be set when mode is %q", i, limatype.ProvisionModeData))
 			}
 			if p.Overwrite != nil {
-				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].overwrite` can only be set when mode is %q", i, ProvisionModeData))
+				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].overwrite` can only be set when mode is %q", i, limatype.ProvisionModeData))
 			}
 			if p.Owner != nil {
-				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].owner` can only be set when mode is %q", i, ProvisionModeData))
+				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].owner` can only be set when mode is %q", i, limatype.ProvisionModeData))
 			}
 			if p.Path != nil {
-				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].path` can only be set when mode is %q", i, ProvisionModeData))
+				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].path` can only be set when mode is %q", i, limatype.ProvisionModeData))
 			}
 			if p.Permissions != nil {
-				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].permissions` can only be set when mode is %q", i, ProvisionModeData))
+				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].permissions` can only be set when mode is %q", i, limatype.ProvisionModeData))
 			}
 		}
 		if p.Playbook != "" {
-			if p.Mode != ProvisionModeAnsible {
-				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].playbook can only be set when mode is %q", i, ProvisionModeAnsible))
+			if p.Mode != limatype.ProvisionModeAnsible {
+				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].playbook can only be set when mode is %q", i, limatype.ProvisionModeAnsible))
 			}
 			if p.Script != "" {
 				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].script must be empty if playbook is set", i))
@@ -251,7 +238,7 @@ func Validate(y *LimaYAML, warn bool) error {
 			if _, err := os.Stat(playbook); err != nil {
 				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].playbook` refers to an inaccessible path: %q: %w", i, playbook, err))
 			}
-			logrus.Warnf("provision mode %q is deprecated, use `ansible-playbook %q` instead", ProvisionModeAnsible, playbook)
+			logrus.Warnf("provision mode %q is deprecated, use `ansible-playbook %q` instead", limatype.ProvisionModeAnsible, playbook)
 		}
 		if strings.Contains(p.Script, "LIMA_CIDATA") {
 			logrus.Warn("provisioning scripts should not reference the LIMA_CIDATA variables")
@@ -282,9 +269,9 @@ func Validate(y *LimaYAML, warn bool) error {
 			errs = errors.Join(errs, fmt.Errorf("field `probe[%d].script` must start with a '#!' line", i))
 		}
 		switch p.Mode {
-		case ProbeModeReadiness:
+		case limatype.ProbeModeReadiness:
 		default:
-			errs = errors.Join(errs, fmt.Errorf("field `probe[%d].mode` can only be %q", i, ProbeModeReadiness))
+			errs = errors.Join(errs, fmt.Errorf("field `probe[%d].mode` can only be %q", i, limatype.ProbeModeReadiness))
 		}
 	}
 	for i, rule := range y.PortForwards {
@@ -355,9 +342,9 @@ func Validate(y *LimaYAML, warn bool) error {
 				field, osutil.UnixPathMax, len(rule.HostSocket)))
 		}
 		switch rule.Proto {
-		case ProtoTCP, ProtoUDP, ProtoAny:
+		case limatype.ProtoTCP, limatype.ProtoUDP, limatype.ProtoAny:
 		default:
-			errs = errors.Join(errs, fmt.Errorf("field `%s.proto` must be %q, %q, or %q", field, ProtoTCP, ProtoUDP, ProtoAny))
+			errs = errors.Join(errs, fmt.Errorf("field `%s.proto` must be %q, %q, or %q", field, limatype.ProtoTCP, limatype.ProtoUDP, limatype.ProtoAny))
 		}
 		if rule.Reverse && rule.GuestSocket == "" {
 			errs = errors.Join(errs, fmt.Errorf("field `%s.reverse` must be %t", field, false))
@@ -412,7 +399,7 @@ func Validate(y *LimaYAML, warn bool) error {
 	return errs
 }
 
-func validateFileObject(f File, fieldName string) error {
+func validateFileObject(f limatype.File, fieldName string) error {
 	var errs error
 	if !strings.Contains(f.Location, "://") {
 		if _, err := localpathutil.Expand(f.Location); err != nil {
@@ -420,8 +407,8 @@ func validateFileObject(f File, fieldName string) error {
 		}
 		// f.Location does NOT need to be accessible, so we do NOT check os.Stat(f.Location)
 	}
-	if !slices.Contains(ArchTypes, f.Arch) {
-		errs = errors.Join(errs, fmt.Errorf("field `arch` must be one of %v; got %q", ArchTypes, f.Arch))
+	if !slices.Contains(limatype.ArchTypes, f.Arch) {
+		errs = errors.Join(errs, fmt.Errorf("field `arch` must be one of %v; got %q", limatype.ArchTypes, f.Arch))
 	}
 	if f.Digest != "" {
 		if err := f.Digest.Validate(); err != nil {
@@ -431,7 +418,7 @@ func validateFileObject(f File, fieldName string) error {
 	return errs
 }
 
-func validateNetwork(y *LimaYAML) error {
+func validateNetwork(y *limatype.LimaYAML) error {
 	var errs error
 	interfaceName := make(map[string]int)
 	for i, nw := range y.Networks {
@@ -455,28 +442,12 @@ func validateNetwork(y *LimaYAML) error {
 			if nw.Socket != "" {
 				errs = errors.Join(errs, fmt.Errorf("field `%s.lima` and field `%s.socket` are mutually exclusive", field, field))
 			}
-			if nw.VZNAT != nil && *nw.VZNAT {
-				errs = errors.Join(errs, fmt.Errorf("field `%s.lima` and field `%s.vzNAT` are mutually exclusive", field, field))
-			}
 		case nw.Socket != "":
-			if nw.VZNAT != nil && *nw.VZNAT {
-				errs = errors.Join(errs, fmt.Errorf("field `%s.socket` and field `%s.vzNAT` are mutually exclusive", field, field))
-			}
 			if fi, err := os.Stat(nw.Socket); err != nil && !errors.Is(err, os.ErrNotExist) {
 				errs = errors.Join(errs, err)
 			} else if err == nil && fi.Mode()&os.ModeSocket == 0 {
 				errs = errors.Join(errs, fmt.Errorf("field `%s.socket` %q points to a non-socket file", field, nw.Socket))
 			}
-		case nw.VZNAT != nil && *nw.VZNAT:
-			if y.VMType == nil || *y.VMType != VZ {
-				errs = errors.Join(errs, fmt.Errorf("field `%s.vzNAT` requires `vmType` to be %q", field, VZ))
-			}
-			if nw.Lima != "" {
-				errs = errors.Join(errs, fmt.Errorf("field `%s.vzNAT` and field `%s.lima` are mutually exclusive", field, field))
-			}
-			if nw.Socket != "" {
-				errs = errors.Join(errs, fmt.Errorf("field `%s.vzNAT` and field `%s.socket` are mutually exclusive", field, field))
-			}
 		default:
 			errs = errors.Join(errs, fmt.Errorf("field `%s.lima` or  field `%s.socket must be set", field, field))
 		}
@@ -510,7 +481,7 @@ func validateNetwork(y *LimaYAML) error {
 
 // validateParamIsUsed checks if the keys in the `param` field are used in any script, probe, copyToHost, or portForward.
 // It should be called before the `y` parameter is passed to FillDefault() that execute template.
-func validateParamIsUsed(y *LimaYAML) error {
+func validateParamIsUsed(y *limatype.LimaYAML) error {
 	for key := range y.Param {
 		re, err := regexp.Compile(`{{[^}]*\.Param\.` + key + `[^}]*}}|\bPARAM_` + key + `\b`)
 		if err != nil {
@@ -522,6 +493,10 @@ func validateParamIsUsed(y *LimaYAML) error {
 				keyIsUsed = true
 				break
 			}
+			if p.Content != nil && re.MatchString(*p.Content) {
+				keyIsUsed = true
+				break
+			}
 			if p.Playbook != "" {
 				playbook, err := os.ReadFile(p.Playbook)
 				if err != nil {
@@ -582,12 +557,12 @@ func validatePort(field string, port int) error {
 	return nil
 }
 
-func warnExperimental(y *LimaYAML) {
-	if *y.MountType == VIRTIOFS && runtime.GOOS == "linux" {
+func warnExperimental(y *limatype.LimaYAML) {
+	if *y.MountType == limatype.VIRTIOFS && runtime.GOOS == "linux" {
 		logrus.Warn("`mountType: virtiofs` on Linux is experimental")
 	}
 	switch *y.Arch {
-	case RISCV64, ARMV7L, S390X, PPC64LE:
+	case limatype.RISCV64, limatype.ARMV7L, limatype.S390X, limatype.PPC64LE:
 		logrus.Warnf("`arch: %s ` is experimental", *y.Arch)
 	}
 	if y.Video.Display != nil && strings.Contains(*y.Video.Display, "vnc") {
@@ -604,36 +579,40 @@ func warnExperimental(y *LimaYAML) {
 // ValidateAgainstLatestConfig validates the values between the latest YAML and the updated(New) YAML.
 // This validates configuration rules that disallow certain changes, such as shrinking the disk.
 func ValidateAgainstLatestConfig(ctx context.Context, yNew, yLatest []byte) error {
-	var n LimaYAML
+	var n limatype.LimaYAML
+	var errs error
 
 	// Load the latest YAML and fill in defaults
 	l, err := LoadWithWarnings(ctx, yLatest, "")
 	if err != nil {
-		return err
+		errs = errors.Join(errs, err)
+	}
+	if err := driverutil.ResolveVMType(l, ""); err != nil {
+		errs = errors.Join(errs, fmt.Errorf("failed to accept config for %q: %w", "", err))
 	}
 	if err := Unmarshal(yNew, &n, "Unmarshal new YAML bytes"); err != nil {
-		return err
+		errs = errors.Join(errs, err)
 	}
 
 	// Handle editing the template without a disk value
 	if n.Disk == nil || l.Disk == nil {
-		return nil
+		return errs
 	}
 
 	// Disk value must be provided, as it is required when creating an instance.
 	nDisk, err := units.RAMInBytes(*n.Disk)
 	if err != nil {
-		return err
+		errs = errors.Join(errs, err)
 	}
 	lDisk, err := units.RAMInBytes(*l.Disk)
 	if err != nil {
-		return err
+		errs = errors.Join(errs, err)
 	}
 
 	// Reject shrinking disk
 	if nDisk < lDisk {
-		return fmt.Errorf("field `disk`: shrinking the disk (%v --> %v) is not supported", *l.Disk, *n.Disk)
+		errs = errors.Join(errs, fmt.Errorf("field `disk`: shrinking the disk (%v --> %v) is not supported", *l.Disk, *n.Disk))
 	}
 
-	return nil
+	return errs
 }
diff --git a/pkg/localpathutil/localpathutil.go b/pkg/localpathutil/localpathutil.go
index 3081763b..baa4ceb1 100644
--- a/pkg/localpathutil/localpathutil.go
+++ b/pkg/localpathutil/localpathutil.go
@@ -11,6 +11,12 @@ import (
 	"strings"
 )
 
+// IsTildePath returns true if the path is "~" or starts with "~/".
+// This means Expand() can expand it with the home directory.
+func IsTildePath(path string) bool {
+	return path == "~" || strings.HasPrefix(path, "~/")
+}
+
 // Expand expands a path like "~", "~/", "~/foo".
 // Paths like "~foo/bar" are unsupported.
 //
@@ -20,13 +26,13 @@ func Expand(orig string) (string, error) {
 	if s == "" {
 		return "", errors.New("empty path")
 	}
-	homeDir, err := os.UserHomeDir()
-	if err != nil {
-		return "", err
-	}
 
 	if strings.HasPrefix(s, "~") {
-		if s == "~" || strings.HasPrefix(s, "~/") {
+		if IsTildePath(s) {
+			homeDir, err := os.UserHomeDir()
+			if err != nil {
+				return "", err
+			}
 			s = strings.Replace(s, "~", homeDir, 1)
 		} else {
 			// Paths like "~foo/bar" are unsupported.
diff --git a/pkg/networks/commands.go b/pkg/networks/commands.go
index 98dbb107..abe34650 100644
--- a/pkg/networks/commands.go
+++ b/pkg/networks/commands.go
@@ -10,8 +10,8 @@ import (
 	"os/exec"
 	"path/filepath"
 
+	"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
 	"github.com/lima-vm/lima/v2/pkg/osutil"
-	"github.com/lima-vm/lima/v2/pkg/store/dirnames"
 )
 
 const (
diff --git a/pkg/networks/config.go b/pkg/networks/config.go
index 34b5f226..6cefe46b 100644
--- a/pkg/networks/config.go
+++ b/pkg/networks/config.go
@@ -15,8 +15,8 @@ import (
 	"github.com/goccy/go-yaml"
 	"github.com/sirupsen/logrus"
 
-	"github.com/lima-vm/lima/v2/pkg/store/dirnames"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
+	"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 	"github.com/lima-vm/lima/v2/pkg/textutil"
 )
 
diff --git a/pkg/networks/reconcile/reconcile.go b/pkg/networks/reconcile/reconcile.go
index c3575571..02076b0b 100644
--- a/pkg/networks/reconcile/reconcile.go
+++ b/pkg/networks/reconcile/reconcile.go
@@ -16,11 +16,12 @@ import (
 
 	"github.com/sirupsen/logrus"
 
+	"github.com/lima-vm/lima/v2/pkg/limatype"
+	"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
 	"github.com/lima-vm/lima/v2/pkg/networks"
 	"github.com/lima-vm/lima/v2/pkg/networks/usernet"
 	"github.com/lima-vm/lima/v2/pkg/osutil"
 	"github.com/lima-vm/lima/v2/pkg/store"
-	"github.com/lima-vm/lima/v2/pkg/store/dirnames"
 )
 
 func Reconcile(ctx context.Context, newInst string) error {
@@ -39,7 +40,7 @@ func Reconcile(ctx context.Context, newInst string) error {
 			return err
 		}
 		// newInst is about to be started, so its networks should be running
-		if instance.Status != store.StatusRunning && instName != newInst {
+		if instance.Status != limatype.StatusRunning && instName != newInst {
 			continue
 		}
 		for _, nw := range instance.Networks {
diff --git a/pkg/networks/usernet/client.go b/pkg/networks/usernet/client.go
index 53333c2f..f556c0a0 100644
--- a/pkg/networks/usernet/client.go
+++ b/pkg/networks/usernet/client.go
@@ -18,9 +18,9 @@ import (
 	"github.com/containers/gvisor-tap-vsock/pkg/types"
 
 	"github.com/lima-vm/lima/v2/pkg/httpclientutil"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 	"github.com/lima-vm/lima/v2/pkg/limayaml"
 	"github.com/lima-vm/lima/v2/pkg/networks/usernet/dnshosts"
-	"github.com/lima-vm/lima/v2/pkg/store"
 )
 
 type Client struct {
@@ -32,7 +32,7 @@ type Client struct {
 	subnet   net.IP
 }
 
-func (c *Client) ConfigureDriver(ctx context.Context, inst *store.Instance, sshLocalPort int) error {
+func (c *Client) ConfigureDriver(ctx context.Context, inst *limatype.Instance, sshLocalPort int) error {
 	macAddress := limayaml.MACAddress(inst.Dir)
 	ipAddress, err := c.ResolveIPAddress(ctx, macAddress)
 	if err != nil {
diff --git a/pkg/networks/usernet/config.go b/pkg/networks/usernet/config.go
index e8304dee..35904494 100644
--- a/pkg/networks/usernet/config.go
+++ b/pkg/networks/usernet/config.go
@@ -10,9 +10,9 @@ import (
 
 	"github.com/apparentlymart/go-cidr/cidr"
 
+	"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
 	"github.com/lima-vm/lima/v2/pkg/networks"
 	"github.com/lima-vm/lima/v2/pkg/osutil"
-	"github.com/lima-vm/lima/v2/pkg/store/dirnames"
 )
 
 type SockType = string
diff --git a/pkg/networks/usernet/recoincile.go b/pkg/networks/usernet/recoincile.go
index 1a8709ad..6f62bd49 100644
--- a/pkg/networks/usernet/recoincile.go
+++ b/pkg/networks/usernet/recoincile.go
@@ -19,9 +19,9 @@ import (
 	"github.com/sirupsen/logrus"
 
 	"github.com/lima-vm/lima/v2/pkg/executil"
+	"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
 	"github.com/lima-vm/lima/v2/pkg/lockutil"
 	"github.com/lima-vm/lima/v2/pkg/store"
-	"github.com/lima-vm/lima/v2/pkg/store/dirnames"
 )
 
 // Start starts a instance a usernet network with the given name.
diff --git a/pkg/portfwd/forward.go b/pkg/portfwd/forward.go
index 1dc44dfa..d20d9a7e 100644
--- a/pkg/portfwd/forward.go
+++ b/pkg/portfwd/forward.go
@@ -12,19 +12,20 @@ import (
 
 	"github.com/lima-vm/lima/v2/pkg/guestagent/api"
 	guestagentclient "github.com/lima-vm/lima/v2/pkg/guestagent/api/client"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 	"github.com/lima-vm/lima/v2/pkg/limayaml"
 )
 
 var IPv4loopback1 = limayaml.IPv4loopback1
 
 type Forwarder struct {
-	rules             []limayaml.PortForward
+	rules             []limatype.PortForward
 	ignoreTCP         bool
 	ignoreUDP         bool
 	closableListeners *ClosableListeners
 }
 
-func NewPortForwarder(rules []limayaml.PortForward, ignoreTCP, ignoreUDP bool) *Forwarder {
+func NewPortForwarder(rules []limatype.PortForward, ignoreTCP, ignoreUDP bool) *Forwarder {
 	return &Forwarder{
 		rules:             rules,
 		ignoreTCP:         ignoreTCP,
@@ -64,7 +65,7 @@ func (fw *Forwarder) forwardingAddresses(guest *api.IPPort) (hostAddr, guestAddr
 		if rule.GuestSocket != "" {
 			continue
 		}
-		if rule.Proto != limayaml.ProtoAny && rule.Proto != guest.Protocol {
+		if rule.Proto != limatype.ProtoAny && rule.Proto != guest.Protocol {
 			continue
 		}
 		if guest.Port < int32(rule.GuestPortRange[0]) || guest.Port > int32(rule.GuestPortRange[1]) {
@@ -91,7 +92,7 @@ func (fw *Forwarder) forwardingAddresses(guest *api.IPPort) (hostAddr, guestAddr
 	return "", guest.HostString()
 }
 
-func hostAddress(rule limayaml.PortForward, guest *api.IPPort) string {
+func hostAddress(rule limatype.PortForward, guest *api.IPPort) string {
 	if rule.HostSocket != "" {
 		return rule.HostSocket
 	}
diff --git a/pkg/snapshot/snapshot.go b/pkg/snapshot/snapshot.go
index 530363f8..e76caa6e 100644
--- a/pkg/snapshot/snapshot.go
+++ b/pkg/snapshot/snapshot.go
@@ -8,10 +8,10 @@ import (
 	"fmt"
 
 	"github.com/lima-vm/lima/v2/pkg/driverutil"
-	"github.com/lima-vm/lima/v2/pkg/store"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 )
 
-func Del(ctx context.Context, inst *store.Instance, tag string) error {
+func Del(ctx context.Context, inst *limatype.Instance, tag string) error {
 	limaDriver, err := driverutil.CreateConfiguredDriver(inst, 0)
 	if err != nil {
 		return fmt.Errorf("failed to create driver instance: %w", err)
@@ -20,7 +20,7 @@ func Del(ctx context.Context, inst *store.Instance, tag string) error {
 	return limaDriver.DeleteSnapshot(ctx, tag)
 }
 
-func Save(ctx context.Context, inst *store.Instance, tag string) error {
+func Save(ctx context.Context, inst *limatype.Instance, tag string) error {
 	limaDriver, err := driverutil.CreateConfiguredDriver(inst, 0)
 	if err != nil {
 		return fmt.Errorf("failed to create driver instance: %w", err)
@@ -28,7 +28,7 @@ func Save(ctx context.Context, inst *store.Instance, tag string) error {
 	return limaDriver.CreateSnapshot(ctx, tag)
 }
 
-func Load(ctx context.Context, inst *store.Instance, tag string) error {
+func Load(ctx context.Context, inst *limatype.Instance, tag string) error {
 	limaDriver, err := driverutil.CreateConfiguredDriver(inst, 0)
 	if err != nil {
 		return fmt.Errorf("failed to create driver instance: %w", err)
@@ -36,7 +36,7 @@ func Load(ctx context.Context, inst *store.Instance, tag string) error {
 	return limaDriver.ApplySnapshot(ctx, tag)
 }
 
-func List(ctx context.Context, inst *store.Instance) (string, error) {
+func List(ctx context.Context, inst *limatype.Instance) (string, error) {
 	limaDriver, err := driverutil.CreateConfiguredDriver(inst, 0)
 	if err != nil {
 		return "", fmt.Errorf("failed to create driver instance: %w", err)
diff --git a/pkg/sshutil/sshutil.go b/pkg/sshutil/sshutil.go
index 103da564..b3d8e8c2 100644
--- a/pkg/sshutil/sshutil.go
+++ b/pkg/sshutil/sshutil.go
@@ -26,10 +26,10 @@ import (
 	"golang.org/x/sys/cpu"
 
 	"github.com/lima-vm/lima/v2/pkg/ioutilx"
+	"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 	"github.com/lima-vm/lima/v2/pkg/lockutil"
 	"github.com/lima-vm/lima/v2/pkg/osutil"
-	"github.com/lima-vm/lima/v2/pkg/store/dirnames"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
 )
 
 // Environment variable that allows configuring the command (alias) to execute
diff --git a/pkg/store/disk.go b/pkg/store/disk.go
index 5df18fbc..20a69f91 100644
--- a/pkg/store/disk.go
+++ b/pkg/store/disk.go
@@ -12,7 +12,7 @@ import (
 
 	"github.com/lima-vm/go-qcow2reader"
 
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 )
 
 type Disk struct {
diff --git a/pkg/store/instance.go b/pkg/store/instance.go
index 04e6b49c..038bb16b 100644
--- a/pkg/store/instance.go
+++ b/pkg/store/instance.go
@@ -5,7 +5,6 @@ package store
 
 import (
 	"context"
-	"encoding/json"
 	"errors"
 	"fmt"
 	"io"
@@ -22,64 +21,27 @@ import (
 	"github.com/docker/go-units"
 	"github.com/sirupsen/logrus"
 
+	"github.com/lima-vm/lima/v2/pkg/driverutil"
 	hostagentclient "github.com/lima-vm/lima/v2/pkg/hostagent/api/client"
 	"github.com/lima-vm/lima/v2/pkg/instance/hostname"
-	"github.com/lima-vm/lima/v2/pkg/limayaml"
-	"github.com/lima-vm/lima/v2/pkg/store/dirnames"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
+	"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 	"github.com/lima-vm/lima/v2/pkg/textutil"
 	"github.com/lima-vm/lima/v2/pkg/version/versionutil"
 )
 
-type Status = string
-
-const (
-	StatusUnknown       Status = ""
-	StatusUninitialized Status = "Uninitialized"
-	StatusInstalling    Status = "Installing"
-	StatusBroken        Status = "Broken"
-	StatusStopped       Status = "Stopped"
-	StatusRunning       Status = "Running"
-)
-
-type Instance struct {
-	Name string `json:"name"`
-	// Hostname, not HostName (corresponds to SSH's naming convention)
-	Hostname        string             `json:"hostname"`
-	Status          Status             `json:"status"`
-	Dir             string             `json:"dir"`
-	VMType          limayaml.VMType    `json:"vmType"`
-	Arch            limayaml.Arch      `json:"arch"`
-	CPUType         string             `json:"cpuType"`
-	CPUs            int                `json:"cpus,omitempty"`
-	Memory          int64              `json:"memory,omitempty"` // bytes
-	Disk            int64              `json:"disk,omitempty"`   // bytes
-	Message         string             `json:"message,omitempty"`
-	AdditionalDisks []limayaml.Disk    `json:"additionalDisks,omitempty"`
-	Networks        []limayaml.Network `json:"network,omitempty"`
-	SSHLocalPort    int                `json:"sshLocalPort,omitempty"`
-	SSHConfigFile   string             `json:"sshConfigFile,omitempty"`
-	HostAgentPID    int                `json:"hostAgentPID,omitempty"`
-	DriverPID       int                `json:"driverPID,omitempty"`
-	Errors          []error            `json:"errors,omitempty"`
-	Config          *limayaml.LimaYAML `json:"config,omitempty"`
-	SSHAddress      string             `json:"sshAddress,omitempty"`
-	Protected       bool               `json:"protected"`
-	LimaVersion     string             `json:"limaVersion"`
-	Param           map[string]string  `json:"param,omitempty"`
-}
-
 // Inspect returns err only when the instance does not exist (os.ErrNotExist).
 // Other errors are returned as *Instance.Errors.
-func Inspect(ctx context.Context, instName string) (*Instance, error) {
-	inst := &Instance{
+func Inspect(ctx context.Context, instName string) (*limatype.Instance, error) {
+	inst := &limatype.Instance{
 		Name: instName,
 		// TODO: support customizing hostname
 		Hostname: hostname.FromInstName(instName),
-		Status:   StatusUnknown,
+		Status:   limatype.StatusUnknown,
 	}
 	// InstanceDir validates the instName but does not check whether the instance exists
-	instDir, err := InstanceDir(instName)
+	instDir, err := dirnames.InstanceDir(instName)
 	if err != nil {
 		return nil, err
 	}
@@ -97,13 +59,12 @@ func Inspect(ctx context.Context, instName string) (*Instance, error) {
 	inst.Config = y
 	inst.Arch = *y.Arch
 	inst.VMType = *y.VMType
-	inst.CPUType = y.VMOpts.QEMU.CPUType[*y.Arch]
 	inst.SSHAddress = "127.0.0.1"
 	inst.SSHLocalPort = *y.SSH.LocalPort // maybe 0
 	inst.SSHConfigFile = filepath.Join(instDir, filenames.SSHConfig)
 	inst.HostAgentPID, err = ReadPIDFile(filepath.Join(instDir, filenames.HostAgentPID))
 	if err != nil {
-		inst.Status = StatusBroken
+		inst.Status = limatype.StatusBroken
 		inst.Errors = append(inst.Errors, err)
 	}
 
@@ -111,14 +72,14 @@ func Inspect(ctx context.Context, instName string) (*Instance, error) {
 		haSock := filepath.Join(instDir, filenames.HostAgentSock)
 		haClient, err := hostagentclient.NewHostAgentClient(haSock)
 		if err != nil {
-			inst.Status = StatusBroken
+			inst.Status = limatype.StatusBroken
 			inst.Errors = append(inst.Errors, fmt.Errorf("failed to connect to %q: %w", haSock, err))
 		} else {
 			ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
 			defer cancel()
 			info, err := haClient.Info(ctx)
 			if err != nil {
-				inst.Status = StatusBroken
+				inst.Status = limatype.StatusBroken
 				inst.Errors = append(inst.Errors, fmt.Errorf("failed to get Info from %q: %w", haSock, err))
 			} else {
 				inst.SSHLocalPort = info.SSHLocalPort
@@ -139,7 +100,7 @@ func Inspect(ctx context.Context, instName string) (*Instance, error) {
 	inst.Networks = y.Networks
 
 	// 0 out values since not configurable on WSL2
-	if inst.VMType == limayaml.WSL2 {
+	if inst.VMType == limatype.WSL2 {
 		inst.Memory = 0
 		inst.CPUs = 0
 		inst.Disk = 0
@@ -155,18 +116,18 @@ func Inspect(ctx context.Context, instName string) (*Instance, error) {
 	tmpl, err := template.New("format").Parse(y.Message)
 	if err != nil {
 		inst.Errors = append(inst.Errors, fmt.Errorf("message %q is not a valid template: %w", y.Message, err))
-		inst.Status = StatusBroken
+		inst.Status = limatype.StatusBroken
 	} else {
 		data, err := AddGlobalFields(inst)
 		if err != nil {
 			inst.Errors = append(inst.Errors, fmt.Errorf("cannot add global fields to instance data: %w", err))
-			inst.Status = StatusBroken
+			inst.Status = limatype.StatusBroken
 		} else {
 			var message strings.Builder
 			err = tmpl.Execute(&message, data)
 			if err != nil {
 				inst.Errors = append(inst.Errors, fmt.Errorf("cannot execute template %q: %w", y.Message, err))
-				inst.Status = StatusBroken
+				inst.Status = limatype.StatusBroken
 			} else {
 				inst.Message = message.String()
 			}
@@ -186,26 +147,42 @@ func Inspect(ctx context.Context, instName string) (*Instance, error) {
 	return inst, nil
 }
 
-func inspectStatusWithPIDFiles(instDir string, inst *Instance, y *limayaml.LimaYAML) {
+func inspectStatus(ctx context.Context, instDir string, inst *limatype.Instance, y *limatype.LimaYAML) {
+	status, err := driverutil.InspectStatus(ctx, inst)
+	if err != nil {
+		inst.Status = limatype.StatusBroken
+		inst.Errors = append(inst.Errors, fmt.Errorf("failed to inspect status: %w", err))
+		return
+	}
+
+	if status == "" {
+		inspectStatusWithPIDFiles(instDir, inst, y)
+		return
+	}
+
+	inst.Status = status
+}
+
+func inspectStatusWithPIDFiles(instDir string, inst *limatype.Instance, y *limatype.LimaYAML) {
 	var err error
 	inst.DriverPID, err = ReadPIDFile(filepath.Join(instDir, filenames.PIDFile(*y.VMType)))
 	if err != nil {
-		inst.Status = StatusBroken
+		inst.Status = limatype.StatusBroken
 		inst.Errors = append(inst.Errors, err)
 	}
 
-	if inst.Status == StatusUnknown {
+	if inst.Status == limatype.StatusUnknown {
 		switch {
 		case inst.HostAgentPID > 0 && inst.DriverPID > 0:
-			inst.Status = StatusRunning
+			inst.Status = limatype.StatusRunning
 		case inst.HostAgentPID == 0 && inst.DriverPID == 0:
-			inst.Status = StatusStopped
+			inst.Status = limatype.StatusStopped
 		case inst.HostAgentPID > 0 && inst.DriverPID == 0:
 			inst.Errors = append(inst.Errors, errors.New("host agent is running but driver is not"))
-			inst.Status = StatusBroken
+			inst.Status = limatype.StatusBroken
 		default:
 			inst.Errors = append(inst.Errors, fmt.Errorf("%s driver is running but host agent is not", inst.VMType))
-			inst.Status = StatusBroken
+			inst.Status = limatype.StatusBroken
 		}
 	}
 }
@@ -248,7 +225,7 @@ func ReadPIDFile(path string) (int, error) {
 }
 
 type FormatData struct {
-	Instance
+	limatype.Instance
 	HostOS       string
 	HostArch     string
 	LimaHome     string
@@ -260,13 +237,13 @@ var FormatHelp = "\n" +
 	textutil.IndentString(2,
 		strings.Join(textutil.FuncHelp, "\n")+"\n")
 
-func AddGlobalFields(inst *Instance) (FormatData, error) {
+func AddGlobalFields(inst *limatype.Instance) (FormatData, error) {
 	var data FormatData
 	data.Instance = *inst
 	// Add HostOS
 	data.HostOS = runtime.GOOS
 	// Add HostArch
-	data.HostArch = limayaml.NewArch(runtime.GOARCH)
+	data.HostArch = limatype.NewArch(runtime.GOARCH)
 	// Add IdentityFile
 	configDir, err := dirnames.LimaConfigDir()
 	if err != nil {
@@ -288,7 +265,7 @@ type PrintOptions struct {
 
 // PrintInstances prints instances in a requested format to a given io.Writer.
 // Supported formats are "json", "yaml", "table", or a go template.
-func PrintInstances(w io.Writer, instances []*Instance, format string, options *PrintOptions) error {
+func PrintInstances(w io.Writer, instances []*limatype.Instance, format string, options *PrintOptions) error {
 	switch format {
 	case "json":
 		format = "{{json .}}"
@@ -322,7 +299,7 @@ func PrintInstances(w io.Writer, instances []*Instance, format string, options *
 			columns++ // VMTYPE
 		}
 		// only hide arch if it is the same as the host arch
-		goarch := limayaml.NewArch(runtime.GOARCH)
+		goarch := limatype.NewArch(runtime.GOARCH)
 		// can we still fit the remaining columns (6)
 		if width == 0 || (columns+6)*columnWidth > width && !all {
 			hideArch = len(archs) == 1 && instances[0].Arch == goarch
@@ -415,62 +392,3 @@ func PrintInstances(w io.Writer, instances []*Instance, format string, options *
 	}
 	return nil
 }
-
-// Protect protects the instance to prohibit accidental removal.
-// Protect does not return an error even when the instance is already protected.
-func (inst *Instance) Protect() error {
-	protected := filepath.Join(inst.Dir, filenames.Protected)
-	// TODO: Do an equivalent of `chmod +a "everyone deny delete,delete_child,file_inherit,directory_inherit"`
-	// https://github.com/lima-vm/lima/issues/1595
-	if err := os.WriteFile(protected, nil, 0o400); err != nil {
-		return err
-	}
-	inst.Protected = true
-	return nil
-}
-
-// Unprotect unprotects the instance.
-// Unprotect does not return an error even when the instance is already unprotected.
-func (inst *Instance) Unprotect() error {
-	protected := filepath.Join(inst.Dir, filenames.Protected)
-	if err := os.RemoveAll(protected); err != nil {
-		return err
-	}
-	inst.Protected = false
-	return nil
-}
-
-func (inst *Instance) MarshalJSON() ([]byte, error) {
-	type Alias Instance
-	errorsAsStrings := make([]string, len(inst.Errors))
-	for i, err := range inst.Errors {
-		if err != nil {
-			errorsAsStrings[i] = err.Error()
-		}
-	}
-	return json.Marshal(&struct {
-		*Alias
-		Errors []string `json:"errors,omitempty"`
-	}{
-		Alias:  (*Alias)(inst),
-		Errors: errorsAsStrings,
-	})
-}
-
-func (inst *Instance) UnmarshalJSON(data []byte) error {
-	type Alias Instance
-	aux := &struct {
-		*Alias
-		Errors []string `json:"errors,omitempty"`
-	}{
-		Alias: (*Alias)(inst),
-	}
-	if err := json.Unmarshal(data, &aux); err != nil {
-		return err
-	}
-	inst.Errors = nil
-	for _, msg := range aux.Errors {
-		inst.Errors = append(inst.Errors, errors.New(msg))
-	}
-	return nil
-}
diff --git a/pkg/store/instance_unix.go b/pkg/store/instance_unix.go
deleted file mode 100644
index 71aaa3df..00000000
--- a/pkg/store/instance_unix.go
+++ /dev/null
@@ -1,20 +0,0 @@
-//go:build !windows
-
-// SPDX-FileCopyrightText: Copyright The Lima Authors
-// SPDX-License-Identifier: Apache-2.0
-
-package store
-
-import (
-	"context"
-
-	"github.com/lima-vm/lima/v2/pkg/limayaml"
-)
-
-func inspectStatus(_ context.Context, instDir string, inst *Instance, y *limayaml.LimaYAML) {
-	inspectStatusWithPIDFiles(instDir, inst, y)
-}
-
-func GetSSHAddress(_ context.Context, _ string) (string, error) {
-	return "127.0.0.1", nil
-}
diff --git a/pkg/store/instance_windows.go b/pkg/store/instance_windows.go
deleted file mode 100644
index b9e963ba..00000000
--- a/pkg/store/instance_windows.go
+++ /dev/null
@@ -1,149 +0,0 @@
-// SPDX-FileCopyrightText: Copyright The Lima Authors
-// SPDX-License-Identifier: Apache-2.0
-
-package store
-
-import (
-	"context"
-	"fmt"
-	"os/exec"
-	"regexp"
-	"strings"
-
-	"github.com/lima-vm/lima/v2/pkg/executil"
-	"github.com/lima-vm/lima/v2/pkg/limayaml"
-)
-
-func inspectStatus(ctx context.Context, instDir string, inst *Instance, y *limayaml.LimaYAML) {
-	if inst.VMType == limayaml.WSL2 {
-		status, err := GetWslStatus(inst.Name)
-		if err != nil {
-			inst.Status = StatusBroken
-			inst.Errors = append(inst.Errors, err)
-		} else {
-			inst.Status = status
-		}
-
-		inst.SSHLocalPort = 22
-
-		if inst.Status == StatusRunning {
-			sshAddr, err := GetSSHAddress(ctx, inst.Name)
-			if err == nil {
-				inst.SSHAddress = sshAddr
-			} else {
-				inst.Errors = append(inst.Errors, err)
-			}
-		}
-	} else {
-		inspectStatusWithPIDFiles(instDir, inst, y)
-	}
-}
-
-// GetWslStatus runs `wsl --list --verbose` and parses its output.
-// There are several possible outputs, all listed with their whitespace preserved output below.
-//
-// (1) Expected output if at least one distro is installed:
-// PS > wsl --list --verbose
-//
-//	NAME      STATE           VERSION
-//
-// * Ubuntu    Stopped         2
-//
-// (2) Expected output when no distros are installed, but WSL is configured properly:
-// PS > wsl --list --verbose
-// Windows Subsystem for Linux has no installed distributions.
-//
-// Use 'wsl.exe --list --online' to list available distributions
-// and 'wsl.exe --install <Distro>' to install.
-//
-// Distributions can also be installed by visiting the Microsoft Store:
-// https://aka.ms/wslstore
-// Error code: Wsl/WSL_E_DEFAULT_DISTRO_NOT_FOUND
-//
-// (3) Expected output when no distros are installed, and WSL2 has no kernel installed:
-//
-// PS > wsl --list --verbose
-// Windows Subsystem for Linux has no installed distributions.
-// Distributions can be installed by visiting the Microsoft Store:
-// https://aka.ms/wslstore
-func GetWslStatus(instName string) (string, error) {
-	distroName := "lima-" + instName
-	out, err := executil.RunUTF16leCommand([]string{
-		"wsl.exe",
-		"--list",
-		"--verbose",
-	})
-	if err != nil {
-		return "", fmt.Errorf("failed to run `wsl --list --verbose`, err: %w (out=%q)", err, out)
-	}
-
-	if out == "" {
-		return StatusBroken, fmt.Errorf("failed to read instance state for instance %q, try running `wsl --list --verbose` to debug, err: %w", instName, err)
-	}
-
-	// Check for edge cases first
-	if strings.Contains(out, "Windows Subsystem for Linux has no installed distributions.") {
-		if strings.Contains(out, "Wsl/WSL_E_DEFAULT_DISTRO_NOT_FOUND") {
-			return StatusBroken, fmt.Errorf(
-				"failed to read instance state for instance %q because no distro is installed,"+
-					"try running `wsl --install -d Ubuntu` and then re-running Lima", instName)
-		}
-		return StatusBroken, fmt.Errorf(
-			"failed to read instance state for instance %q because there is no WSL kernel installed,"+
-				"this usually happens when WSL was installed for another user, but never for your user."+
-				"Try running `wsl --install -d Ubuntu` and `wsl --update`, and then re-running Lima", instName)
-	}
-
-	var instState string
-	wslListColsRegex := regexp.MustCompile(`\s+`)
-	// wsl --list --verbose may have different headers depending on localization, just split by line
-	for _, rows := range strings.Split(strings.ReplaceAll(out, "\r\n", "\n"), "\n") {
-		cols := wslListColsRegex.Split(strings.TrimSpace(rows), -1)
-		nameIdx := 0
-		// '*' indicates default instance
-		if cols[0] == "*" {
-			nameIdx = 1
-		}
-		if cols[nameIdx] == distroName {
-			instState = cols[nameIdx+1]
-			break
-		}
-	}
-
-	if instState == "" {
-		return StatusUninitialized, nil
-	}
-
-	return instState, nil
-}
-
-// GetSSHAddress runs a hostname command to get the IP from inside of a wsl2 VM.
-//
-// Expected output (whitespace preserved, [] for optional):
-// PS > wsl -d <distroName> bash -c hostname -I | cut -d' ' -f1
-// 168.1.1.1 [10.0.0.1]
-// But busybox hostname does not implement --all-ip-addresses:
-// hostname: unrecognized option: I
-func GetSSHAddress(ctx context.Context, instName string) (string, error) {
-	distroName := "lima-" + instName
-	// Ubuntu
-	cmd := exec.CommandContext(ctx, "wsl.exe", "-d", distroName, "bash", "-c", `hostname -I | cut -d ' ' -f1`)
-	out, err := cmd.CombinedOutput()
-	if err == nil {
-		return strings.TrimSpace(string(out)), nil
-	}
-	// Alpine
-	cmd = exec.CommandContext(ctx, "wsl.exe", "-d", distroName, "sh", "-c", `ip route get 1 | awk '{gsub("^.*src ",""); print $1; exit}'`)
-	out, err = cmd.CombinedOutput()
-	if err == nil {
-		return strings.TrimSpace(string(out)), nil
-	}
-	// fallback
-	cmd = exec.CommandContext(ctx, "wsl.exe", "-d", distroName, "hostname", "-i")
-	out, err = cmd.CombinedOutput()
-	if err != nil || strings.HasPrefix(string(out), "127.") {
-		return "", fmt.Errorf("failed to get hostname for instance %q, err: %w (out=%q)", instName, err, string(out))
-	}
-
-	return strings.TrimSpace(string(out)), nil
-}
diff --git a/pkg/store/store.go b/pkg/store/store.go
index 7a4f27c1..af8646da 100644
--- a/pkg/store/store.go
+++ b/pkg/store/store.go
@@ -11,10 +11,12 @@ import (
 	"path/filepath"
 	"strings"
 
+	"github.com/lima-vm/lima/v2/pkg/driverutil"
 	"github.com/lima-vm/lima/v2/pkg/identifiers"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
+	"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 	"github.com/lima-vm/lima/v2/pkg/limayaml"
-	"github.com/lima-vm/lima/v2/pkg/store/dirnames"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
 )
 
 // Directory returns the LimaDir.
@@ -47,19 +49,6 @@ func Validate() error {
 	return nil
 }
 
-// ValidateInstName checks if the name is a valid instance name. For this it needs to
-// be a valid identifier, and not end in .yml or .yaml (case insensitively).
-func ValidateInstName(name string) error {
-	if err := identifiers.Validate(name); err != nil {
-		return fmt.Errorf("instance name %q is not a valid identifier: %w", name, err)
-	}
-	lower := strings.ToLower(name)
-	if strings.HasSuffix(lower, ".yml") || strings.HasSuffix(lower, ".yaml") {
-		return fmt.Errorf("instance name %q must not end with .yml or .yaml suffix", name)
-	}
-	return nil
-}
-
 // Instances returns the names of the instances under LimaDir.
 func Instances() ([]string, error) {
 	limaDir, err := dirnames.LimaDir()
@@ -105,20 +94,6 @@ func Disks() ([]string, error) {
 	return names, nil
 }
 
-// InstanceDir returns the instance dir.
-// InstanceDir does not check whether the instance exists.
-func InstanceDir(name string) (string, error) {
-	if err := ValidateInstName(name); err != nil {
-		return "", err
-	}
-	limaDir, err := dirnames.LimaDir()
-	if err != nil {
-		return "", err
-	}
-	dir := filepath.Join(limaDir, name)
-	return dir, nil
-}
-
 func DiskDir(name string) (string, error) {
 	if err := identifiers.Validate(name); err != nil {
 		return "", err
@@ -132,7 +107,7 @@ func DiskDir(name string) (string, error) {
 }
 
 // LoadYAMLByFilePath loads and validates the yaml.
-func LoadYAMLByFilePath(ctx context.Context, filePath string) (*limayaml.LimaYAML, error) {
+func LoadYAMLByFilePath(ctx context.Context, filePath string) (*limatype.LimaYAML, error) {
 	// We need to use the absolute path because it may be used to determine hostSocket locations.
 	absPath, err := filepath.Abs(filePath)
 	if err != nil {
@@ -146,6 +121,9 @@ func LoadYAMLByFilePath(ctx context.Context, filePath string) (*limayaml.LimaYAM
 	if err != nil {
 		return nil, err
 	}
+	if err := driverutil.ResolveVMType(y, filePath); err != nil {
+		return nil, fmt.Errorf("failed to accept config for %q: %w", filePath, err)
+	}
 	if err := limayaml.Validate(y, false); err != nil {
 		return nil, err
 	}
diff --git a/pkg/usrlocalsharelima/usrlocalsharelima.go b/pkg/usrlocalsharelima/usrlocalsharelima.go
index e22052ce..917fe576 100644
--- a/pkg/usrlocalsharelima/usrlocalsharelima.go
+++ b/pkg/usrlocalsharelima/usrlocalsharelima.go
@@ -16,7 +16,7 @@ import (
 	"github.com/sirupsen/logrus"
 
 	"github.com/lima-vm/lima/v2/pkg/debugutil"
-	"github.com/lima-vm/lima/v2/pkg/limayaml"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 )
 
 // executableViaArgs0 returns the absolute path to the executable used to start this process.
@@ -69,8 +69,8 @@ func Dir() (string, error) {
 		}
 	}
 
-	ostype := limayaml.NewOS("linux")
-	arch := limayaml.NewArch(runtime.GOARCH)
+	ostype := limatype.NewOS("linux")
+	arch := limatype.NewArch(runtime.GOARCH)
 	if arch == "" {
 		return "", fmt.Errorf("failed to get arch for %q", runtime.GOARCH)
 	}
@@ -122,7 +122,7 @@ func Dir() (string, error) {
 }
 
 // GuestAgentBinary returns the absolute path of the guest agent binary, possibly with ".gz" suffix.
-func GuestAgentBinary(ostype limayaml.OS, arch limayaml.Arch) (string, error) {
+func GuestAgentBinary(ostype limatype.OS, arch limatype.Arch) (string, error) {
 	if ostype == "" {
 		return "", errors.New("os must be set")
 	}
diff --git a/templates/default.yaml b/templates/default.yaml
index 2aa5c407..2b9196e7 100644
--- a/templates/default.yaml
+++ b/templates/default.yaml
@@ -329,6 +329,15 @@ vmOpts:
     #   armv7l:  "max" # (or "host" when running on armv7l host)
     #   riscv64: "max" # (or "host" when running on riscv64 host)
     #   x86_64:  "max" # (or "host" when running on x86_64 host; additional options are appended on Intel Mac)
+  vz:
+    rosetta:
+      # Enable Rosetta inside the VM; needs `vmType: vz`
+      # Hint: try `softwareupdate --install-rosetta` if Lima gets stuck at `Installing rosetta...`
+      # 🟢 Builtin default: false
+      enabled: null
+      # Register rosetta to /proc/sys/fs/binfmt_misc
+      # 🟢 Builtin default: false
+      binfmt: null
 
 # OS: "Linux".
 # 🟢 Builtin default: "Linux"
@@ -337,13 +346,9 @@ os: null
 # DEPRECATED: Use vmOpts.qemu.cpuType instead. See the vmOpts.qemu.cpuType section above for configuration.
 cpuType:
 
+# DEPRECATED: Use vmOpts.vz.rosetta instead. See the vmOpts.qemu.cpuType section above for configuration.
 rosetta:
-  # Enable Rosetta inside the VM; needs `vmType: vz`
-  # Hint: try `softwareupdate --install-rosetta` if Lima gets stuck at `Installing rosetta...`
-  # 🟢 Builtin default: false
   enabled: null
-  # Register rosetta to /proc/sys/fs/binfmt_misc
-  # 🟢 Builtin default: false
   binfmt: null
 
 # Specify the timezone name (as used by the zoneinfo database). Specify the empty string
diff --git a/website/content/en/docs/config/environment-variables.md b/website/content/en/docs/config/environment-variables.md
index dcaa128c..064917e9 100644
--- a/website/content/en/docs/config/environment-variables.md
+++ b/website/content/en/docs/config/environment-variables.md
@@ -57,6 +57,45 @@ This page documents the environment variables used in Lima.
   lima
   ```
 
+### `LIMA_SHELLENV_ALLOW`
+
+- **Description**: Specifies a comma-separated list of environment variable patterns to allow when propagating environment variables to the Lima instance with `--preserve-env`. When set, **only** variables matching these patterns will be passed through, completely overriding the default block list behavior. This feature only applies to Lima v2.0.0 or later.
+- **Default**: unset (when using `--preserve-env`, all variables are propagated except those matching the block list patterns)
+- **Usage**:
+  ```sh
+  export LIMA_SHELLENV_ALLOW="FPATH,XAUTHORITY,CUSTOM_*"
+  limactl shell --preserve-env default
+  ```
+- **Behavior**:
+  - **Without `--preserve-env`**: No environment variables are propagated (regardless of this setting)
+  - **With `--preserve-env` and `LIMA_SHELLENV_ALLOW` unset**: All variables are propagated except those in the block list
+  - **With `--preserve-env` and `LIMA_SHELLENV_ALLOW` set**: Only variables matching the allow patterns are propagated (block list is ignored)
+- **Note**: Patterns support wildcards using `*` at the end (e.g., `CUSTOM_*` matches `CUSTOM_VAR`, `CUSTOM_PATH`, etc.).
+
+### `LIMA_SHELLENV_BLOCK`
+
+- **Description**: Specifies a comma-separated list of environment variable patterns to block when propagating environment variables to the Lima instance with `--preserve-env`. Can either replace the default block list or extend it by prefixing with `+`. This feature only applies to Lima v2.0.0 or later.
+- **Default**: A predefined list of system and shell-specific variables that should not be propagated:
+  - Shell variables: `BASH*`, `SHELL`, `SHLVL`, `ZSH*`, `ZDOTDIR`, `FPATH`
+  - System paths: `PATH`, `PWD`, `OLDPWD`, `TMPDIR`
+  - User/system info: `HOME`, `USER`, `LOGNAME`, `UID`, `GID`, `EUID`, `GROUP`, `HOSTNAME`
+  - Display/terminal: `DISPLAY`, `TERM`, `TERMINFO`, `XAUTHORITY`, `XDG_*`
+  - SSH/security: `SSH_*`
+  - Dynamic linker: `DYLD_*`, `LD_*`
+  - Internal variables: `_*` (variables starting with underscore)
+  
+  See [`GetDefaultBlockList()`](https://github.com/lima-vm/lima/blob/master/pkg/envutil/envutil.go#L133) for the complete list.
+- **Usage**:
+  ```sh
+  # Replace default block list entirely (not recommended)
+  export LIMA_SHELLENV_BLOCK="SECRET_*,PRIVATE_*"
+  
+  # Extend default block list (recommended)
+  export LIMA_SHELLENV_BLOCK="+SECRET_*,PRIVATE_*"
+  limactl shell --preserve-env default
+  ```
+- **Note**: Patterns support wildcards using `*` at the end (e.g., `SSH_*` matches `SSH_AUTH_SOCK`, `SSH_AGENT_PID`). Use the `+` prefix to add to the default block list rather than replacing it entirely. This variable only affects the `--preserve-env` flag behavior.
+
 ### `LIMACTL`
 
 - **Description**: Specifies the path to the `limactl` binary.



Test patch:
diff --git a/pkg/envutil/envutil_test.go b/pkg/envutil/envutil_test.go
index b6fb37ea..3530288f 100644
--- a/pkg/envutil/envutil_test.go
+++ b/pkg/envutil/envutil_test.go
@@ -207,7 +207,7 @@ func TestGetDefaultBlockList(t *testing.T) {
 
 	assert.DeepEqual(t, blocklist, defaultBlockList)
 
-	expectedItems := []string{"PATH", "HOME", "SSH_*"}
+	expectedItems := []string{"PATH", "HOME", "SSH_*", "USER"}
 	for _, item := range expectedItems {
 		found := slices.Contains(blocklist, item)
 		assert.Assert(t, found, "Expected builtin blocklist to contain %q", item)
diff --git a/pkg/limatmpl/abs_test.go b/pkg/limatmpl/abs_test.go
index fbf7c19b..5b78e9c1 100644
--- a/pkg/limatmpl/abs_test.go
+++ b/pkg/limatmpl/abs_test.go
@@ -4,6 +4,7 @@
 package limatmpl
 
 import (
+	"os"
 	"path/filepath"
 	"runtime"
 	"strings"
@@ -205,6 +206,15 @@ func TestAbsPath(t *testing.T) {
 		assert.Equal(t, actual, filepath.Clean(volume+"/foo"))
 	})
 
+	t.Run("If the locator starts with ~/, then it will be expanded to an absolute path", func(t *testing.T) {
+		actual, err := absPath("~/foo", volume+"/root")
+		assert.NilError(t, err)
+		homeDir, err := os.UserHomeDir()
+		assert.NilError(t, err)
+		// homeDir already includes the volume
+		assert.Equal(t, actual, filepath.Join(homeDir, "foo"))
+	})
+
 	t.Run("", func(t *testing.T) {
 		actual, err := absPath("template://foo", volume+"/root")
 		assert.NilError(t, err)
diff --git a/pkg/limatmpl/embed_test.go b/pkg/limatmpl/embed_test.go
index 02e28ab1..f6c3b57f 100644
--- a/pkg/limatmpl/embed_test.go
+++ b/pkg/limatmpl/embed_test.go
@@ -14,6 +14,7 @@ import (
 	"gotest.tools/v3/assert"
 	"gotest.tools/v3/assert/cmp"
 
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 	"github.com/lima-vm/lima/v2/pkg/limayaml"
 )
 
@@ -472,7 +473,7 @@ func RunEmbedTest(t *testing.T, tc embedTestCase) {
 	err = tmpl.Unmarshal()
 	assert.NilError(t, err, tc.description)
 
-	var expected limayaml.LimaYAML
+	var expected limatype.LimaYAML
 	err = limayaml.Unmarshal([]byte(tc.expected), &expected, "expected")
 	assert.NilError(t, err, tc.description)
 
diff --git a/pkg/limatmpl/locator_test.go b/pkg/limatmpl/locator_test.go
index b3cf8bda..b611cf3b 100644
--- a/pkg/limatmpl/locator_test.go
+++ b/pkg/limatmpl/locator_test.go
@@ -11,7 +11,7 @@ import (
 	"gotest.tools/v3/assert"
 
 	"github.com/lima-vm/lima/v2/pkg/limatmpl"
-	"github.com/lima-vm/lima/v2/pkg/limayaml"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 )
 
 func TestInstNameFromImageURL(t *testing.T) {
@@ -48,7 +48,7 @@ func TestInstNameFromImageURL(t *testing.T) {
 		assert.Equal(t, name, "my-arch-aarch64")
 	})
 	t.Run("removes native arch", func(t *testing.T) {
-		arch := limayaml.NewArch(runtime.GOARCH)
+		arch := limatype.NewArch(runtime.GOARCH)
 		image := fmt.Sprintf("linux_cloudimg.base-%s.qcow2.gz", arch)
 		name := limatmpl.InstNameFromImageURL(image, arch)
 		assert.Equal(t, name, "linux")
diff --git a/pkg/limayaml/defaults_test.go b/pkg/limayaml/defaults_test.go
index 72031382..f0b2c644 100644
--- a/pkg/limayaml/defaults_test.go
+++ b/pkg/limayaml/defaults_test.go
@@ -20,43 +20,42 @@ import (
 	"gotest.tools/v3/assert"
 
 	"github.com/lima-vm/lima/v2/pkg/ioutilx"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
+	"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 	"github.com/lima-vm/lima/v2/pkg/osutil"
 	"github.com/lima-vm/lima/v2/pkg/ptr"
-	"github.com/lima-vm/lima/v2/pkg/store/dirnames"
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
 )
 
 func TestFillDefault(t *testing.T) {
 	logrus.SetLevel(logrus.DebugLevel)
-	var d, y, o LimaYAML
-
-	defaultVMType := ResolveVMType(&y, &d, &o, "")
+	var d, y, o limatype.LimaYAML
 
 	opts := []cmp.Option{
 		// Consider nil slices and empty slices to be identical
 		cmpopts.EquateEmpty(),
 	}
 
-	var arch Arch
+	var arch limatype.Arch
 	switch runtime.GOARCH {
 	case "amd64":
-		arch = X8664
+		arch = limatype.X8664
 	case "arm64":
-		arch = AARCH64
+		arch = limatype.AARCH64
 	case "arm":
 		if runtime.GOOS != "linux" {
 			t.Skipf("unsupported GOOS: %s", runtime.GOOS)
 		}
-		if arm := goarm(); arm < 7 {
+		if arm := limatype.Goarm(); arm < 7 {
 			t.Skipf("unsupported GOARM: %d", arm)
 		}
-		arch = ARMV7L
+		arch = limatype.ARMV7L
 	case "ppc64le":
-		arch = PPC64LE
+		arch = limatype.PPC64LE
 	case "riscv64":
-		arch = RISCV64
+		arch = limatype.RISCV64
 	case "s390x":
-		arch = S390X
+		arch = limatype.S390X
 	default:
 		t.Skipf("unknown GOARCH: %s", runtime.GOARCH)
 	}
@@ -75,21 +74,20 @@ func TestFillDefault(t *testing.T) {
 	filePath := filepath.Join(instDir, filenames.LimaYAML)
 
 	// Builtin default values
-	builtin := LimaYAML{
-		VMType:             &defaultVMType,
-		OS:                 ptr.Of(LINUX),
+	builtin := limatype.LimaYAML{
+		OS:                 ptr.Of(limatype.LINUX),
 		Arch:               ptr.Of(arch),
 		CPUs:               ptr.Of(defaultCPUs()),
 		Memory:             ptr.Of(defaultMemoryAsString()),
 		Disk:               ptr.Of(defaultDiskSizeAsString()),
 		GuestInstallPrefix: ptr.Of(defaultGuestInstallPrefix()),
 		UpgradePackages:    ptr.Of(false),
-		Containerd: Containerd{
+		Containerd: limatype.Containerd{
 			System:   ptr.Of(false),
 			User:     ptr.Of(true),
 			Archives: defaultContainerdArchives(),
 		},
-		SSH: SSH{
+		SSH: limatype.SSH{
 			LocalPort:         ptr.Of(0),
 			LoadDotSSHPubKeys: ptr.Of(false),
 			ForwardAgent:      ptr.Of(false),
@@ -97,29 +95,26 @@ func TestFillDefault(t *testing.T) {
 			ForwardX11Trusted: ptr.Of(false),
 		},
 		TimeZone: ptr.Of(hostTimeZone()),
-		Firmware: Firmware{
+		Firmware: limatype.Firmware{
 			LegacyBIOS: ptr.Of(false),
 		},
-		Audio: Audio{
+		Audio: limatype.Audio{
 			Device: ptr.Of(""),
 		},
-		Video: Video{
+		Video: limatype.Video{
 			Display: ptr.Of("none"),
-			VNC: VNCOptions{
-				Display: ptr.Of("127.0.0.1:0,to=9"),
-			},
 		},
-		HostResolver: HostResolver{
+		HostResolver: limatype.HostResolver{
 			Enabled: ptr.Of(true),
 			IPv6:    ptr.Of(false),
 		},
 		PropagateProxyEnv: ptr.Of(true),
-		CACertificates: CACertificates{
+		CACertificates: limatype.CACertificates{
 			RemoveDefaults: ptr.Of(false),
 		},
 		NestedVirtualization: ptr.Of(false),
 		Plain:                ptr.Of(false),
-		User: User{
+		User: limatype.User{
 			Name:    ptr.Of(user.Username),
 			Comment: ptr.Of(user.Name),
 			Home:    ptr.Of(user.HomeDir),
@@ -128,12 +123,12 @@ func TestFillDefault(t *testing.T) {
 		},
 	}
 
-	defaultPortForward := PortForward{
+	defaultPortForward := limatype.PortForward{
 		GuestIP:        IPv4loopback1,
 		GuestPortRange: [2]int{1, 65535},
 		HostIP:         IPv4loopback1,
 		HostPortRange:  [2]int{1, 65535},
-		Proto:          ProtoTCP,
+		Proto:          limatype.ProtoTCP,
 		Reverse:        false,
 	}
 
@@ -142,31 +137,31 @@ func TestFillDefault(t *testing.T) {
 
 	// All these slices and maps are empty in "builtin". Add minimal entries here to see that
 	// their values are retained and defaults for their fields are applied correctly.
-	y = LimaYAML{
-		HostResolver: HostResolver{
+	y = limatype.LimaYAML{
+		HostResolver: limatype.HostResolver{
 			Hosts: map[string]string{
 				"MY.Host": "host.lima.internal",
 			},
 		},
-		Mounts: []Mount{
+		Mounts: []limatype.Mount{
 			//nolint:usetesting // We need the OS temp directory name here; it is not used to create temp files for testing
 			{Location: filepath.Clean(os.TempDir())},
 			{Location: filepath.Clean("{{.Dir}}/{{.Param.ONE}}"), MountPoint: ptr.Of("/mnt/{{.Param.ONE}}")},
 		},
-		MountType: ptr.Of(NINEP),
-		Provision: []Provision{
+		MountType: ptr.Of(limatype.NINEP),
+		Provision: []limatype.Provision{
 			{Script: "#!/bin/true # {{.Param.ONE}}"},
 		},
-		Probes: []Probe{
+		Probes: []limatype.Probe{
 			{Script: "#!/bin/false # {{.Param.ONE}}"},
 		},
-		Networks: []Network{
+		Networks: []limatype.Network{
 			{Lima: "shared"},
 		},
 		DNS: []net.IP{
 			net.ParseIP("1.0.1.0"),
 		},
-		PortForwards: []PortForward{
+		PortForwards: []limatype.PortForward{
 			{},
 			{GuestPort: 80},
 			{GuestPort: 8080, HostPort: 8888},
@@ -175,7 +170,7 @@ func TestFillDefault(t *testing.T) {
 				HostSocket:  "{{.Home}} | {{.Dir}} | {{.Name}} | {{.UID}} | {{.User}} | {{.Param.ONE}}",
 			},
 		},
-		CopyToHost: []CopyToHost{
+		CopyToHost: []limatype.CopyToHost{
 			{
 				GuestFile: "{{.Home}} | {{.UID}} | {{.User}} | {{.Param.ONE}}",
 				HostFile:  "{{.Home}} | {{.Dir}} | {{.Name}} | {{.UID}} | {{.User}} | {{.Param.ONE}}",
@@ -187,38 +182,18 @@ func TestFillDefault(t *testing.T) {
 		Param: map[string]string{
 			"ONE": "Eins",
 		},
-		CACertificates: CACertificates{
+		CACertificates: limatype.CACertificates{
 			Files: []string{"ca.crt"},
 			Certs: []string{
 				"-----BEGIN CERTIFICATE-----\nYOUR-ORGS-TRUSTED-CA-CERT\n-----END CERTIFICATE-----\n",
 			},
 		},
 		TimeZone: ptr.Of("Antarctica/Troll"),
-		Firmware: Firmware{
-			LegacyBIOS: ptr.Of(false),
-			Images: []FileWithVMType{
-				{
-					File: File{
-						Location: "https://gitlab.com/kraxel/qemu/-/raw/704f7cad5105246822686f65765ab92045f71a3b/pc-bios/edk2-aarch64-code.fd.bz2",
-						Arch:     AARCH64,
-						Digest:   "sha256:a5fc228623891297f2d82e22ea56ec57cde93fea5ec01abf543e4ed5cacaf277",
-					},
-					VMType: QEMU,
-				},
-				{
-					File: File{
-						Location: "https://github.com/AkihiroSuda/qemu/raw/704f7cad5105246822686f65765ab92045f71a3b/pc-bios/edk2-aarch64-code.fd.bz2",
-						Arch:     AARCH64,
-						Digest:   "sha256:a5fc228623891297f2d82e22ea56ec57cde93fea5ec01abf543e4ed5cacaf277",
-					},
-					VMType: QEMU,
-				},
-			},
-		},
 	}
 
 	expect := builtin
-	expect.VMType = ptr.Of(QEMU) // due to NINEP
+	// VMType should remain nil when not explicitly set (will be resolved by ValidateVMType later)
+	expect.VMType = nil
 	expect.HostResolver.Hosts = map[string]string{
 		"MY.Host": "host.lima.internal",
 	}
@@ -253,16 +228,16 @@ func TestFillDefault(t *testing.T) {
 	expect.Mounts[1].NineP.Cache = ptr.Of(Default9pCacheForRO)
 	expect.Mounts[1].Virtiofs.QueueSize = nil
 
-	expect.MountType = ptr.Of(NINEP)
+	expect.MountType = ptr.Of(limatype.NINEP)
 
 	expect.MountInotify = ptr.Of(false)
 
 	expect.Provision = slices.Clone(y.Provision)
-	expect.Provision[0].Mode = ProvisionModeSystem
+	expect.Provision[0].Mode = limatype.ProvisionModeSystem
 	expect.Provision[0].Script = "#!/bin/true # Eins"
 
 	expect.Probes = slices.Clone(y.Probes)
-	expect.Probes[0].Mode = ProbeModeReadiness
+	expect.Probes[0].Mode = limatype.ProbeModeReadiness
 	expect.Probes[0].Description = "user probe 1/1"
 	expect.Probes[0].Script = "#!/bin/false # Eins"
 
@@ -272,13 +247,13 @@ func TestFillDefault(t *testing.T) {
 	expect.Networks[0].Metric = ptr.Of(uint32(100))
 
 	expect.DNS = slices.Clone(y.DNS)
-	expect.PortForwards = []PortForward{
+	expect.PortForwards = []limatype.PortForward{
 		defaultPortForward,
 		defaultPortForward,
 		defaultPortForward,
 		defaultPortForward,
 	}
-	expect.CopyToHost = []CopyToHost{
+	expect.CopyToHost = []limatype.CopyToHost{
 		{},
 	}
 
@@ -303,7 +278,7 @@ func TestFillDefault(t *testing.T) {
 
 	expect.Param = y.Param
 
-	expect.CACertificates = CACertificates{
+	expect.CACertificates = limatype.CACertificates{
 		RemoveDefaults: ptr.Of(false),
 		Files:          []string{"ca.crt"},
 		Certs: []string{
@@ -312,17 +287,16 @@ func TestFillDefault(t *testing.T) {
 	}
 
 	expect.TimeZone = y.TimeZone
-	expect.Firmware = y.Firmware
-	expect.Firmware.Images = slices.Clone(y.Firmware.Images)
-
-	expect.Rosetta = Rosetta{
-		Enabled: ptr.Of(false),
-		BinFmt:  ptr.Of(false),
+	// Set firmware expectations to match what FillDefault actually does
+	// FillDefault uses the builtin default values, which include LegacyBIOS: ptr.Of(false)
+	expect.Firmware = limatype.Firmware{
+		LegacyBIOS: ptr.Of(false), // This matches what FillDefault actually sets
+		Images:     nil,
 	}
 
 	expect.NestedVirtualization = ptr.Of(false)
 
-	FillDefault(t.Context(), &y, &LimaYAML{}, &LimaYAML{}, filePath, false)
+	FillDefault(t.Context(), &y, &limatype.LimaYAML{}, &limatype.LimaYAML{}, filePath, false)
 	assert.DeepEqual(t, &y, &expect, opts...)
 
 	filledDefaults := y
@@ -334,26 +308,26 @@ func TestFillDefault(t *testing.T) {
 
 	// Calling filepath.Abs() to add a drive letter on Windows
 	varLog, _ := filepath.Abs("/var/log")
-	d = LimaYAML{
-		VMType: ptr.Of("vz"),
+	d = limatype.LimaYAML{
+		// Remove driver-specific VMType from defaults test
 		OS:     ptr.Of("unknown"),
 		Arch:   ptr.Of("unknown"),
 		CPUs:   ptr.Of(7),
 		Memory: ptr.Of("5GiB"),
 		Disk:   ptr.Of("105GiB"),
-		AdditionalDisks: []Disk{
+		AdditionalDisks: []limatype.Disk{
 			{Name: "data"},
 		},
 		GuestInstallPrefix: ptr.Of("/opt"),
 		UpgradePackages:    ptr.Of(true),
-		Containerd: Containerd{
+		Containerd: limatype.Containerd{
 			System: ptr.Of(true),
 			User:   ptr.Of(false),
-			Archives: []File{
+			Archives: []limatype.File{
 				{Location: "/tmp/nerdctl.tgz"},
 			},
 		},
-		SSH: SSH{
+		SSH: limatype.SSH{
 			LocalPort:         ptr.Of(888),
 			LoadDotSSHPubKeys: ptr.Of(false),
 			ForwardAgent:      ptr.Of(true),
@@ -361,27 +335,18 @@ func TestFillDefault(t *testing.T) {
 			ForwardX11Trusted: ptr.Of(false),
 		},
 		TimeZone: ptr.Of("Zulu"),
-		Firmware: Firmware{
+		Firmware: limatype.Firmware{
 			LegacyBIOS: ptr.Of(true),
-			Images: []FileWithVMType{
-				{
-					File: File{
-						Location: "/dummy",
-						Arch:     X8664,
-					},
-				},
-			},
+			// Remove driver-specific firmware images from defaults
 		},
-		Audio: Audio{
+		Audio: limatype.Audio{
 			Device: ptr.Of("coreaudio"),
 		},
-		Video: Video{
+		Video: limatype.Video{
 			Display: ptr.Of("cocoa"),
-			VNC: VNCOptions{
-				Display: ptr.Of("none"),
-			},
+			// Remove driver-specific VNC configuration
 		},
-		HostResolver: HostResolver{
+		HostResolver: limatype.HostResolver{
 			Enabled: ptr.Of(false),
 			IPv6:    ptr.Of(true),
 			Hosts: map[string]string{
@@ -390,26 +355,26 @@ func TestFillDefault(t *testing.T) {
 		},
 		PropagateProxyEnv: ptr.Of(false),
 
-		Mounts: []Mount{
+		Mounts: []limatype.Mount{
 			{
 				Location: varLog,
 				Writable: ptr.Of(false),
 			},
 		},
-		Provision: []Provision{
+		Provision: []limatype.Provision{
 			{
 				Script: "#!/bin/true",
-				Mode:   ProvisionModeUser,
+				Mode:   limatype.ProvisionModeUser,
 			},
 		},
-		Probes: []Probe{
+		Probes: []limatype.Probe{
 			{
 				Script:      "#!/bin/false",
-				Mode:        ProbeModeReadiness,
+				Mode:        limatype.ProbeModeReadiness,
 				Description: "User Probe",
 			},
 		},
-		Networks: []Network{
+		Networks: []limatype.Network{
 			{
 				MACAddress: "11:22:33:44:55:66",
 				Interface:  "def0",
@@ -419,16 +384,16 @@ func TestFillDefault(t *testing.T) {
 		DNS: []net.IP{
 			net.ParseIP("1.1.1.1"),
 		},
-		PortForwards: []PortForward{{
+		PortForwards: []limatype.PortForward{{
 			GuestIP:        IPv4loopback1,
 			GuestPort:      80,
 			GuestPortRange: [2]int{80, 80},
 			HostIP:         IPv4loopback1,
 			HostPort:       80,
 			HostPortRange:  [2]int{80, 80},
-			Proto:          ProtoTCP,
+			Proto:          limatype.ProtoTCP,
 		}},
-		CopyToHost: []CopyToHost{{}},
+		CopyToHost: []limatype.CopyToHost{{}},
 		Env: map[string]string{
 			"ONE": "one",
 			"TWO": "two",
@@ -437,18 +402,14 @@ func TestFillDefault(t *testing.T) {
 			"ONE": "one",
 			"TWO": "two",
 		},
-		CACertificates: CACertificates{
+		CACertificates: limatype.CACertificates{
 			RemoveDefaults: ptr.Of(true),
 			Certs: []string{
 				"-----BEGIN CERTIFICATE-----\nYOUR-ORGS-TRUSTED-CA-CERT\n-----END CERTIFICATE-----\n",
 			},
 		},
-		Rosetta: Rosetta{
-			Enabled: ptr.Of(true),
-			BinFmt:  ptr.Of(true),
-		},
 		NestedVirtualization: ptr.Of(true),
-		User: User{
+		User: limatype.User{
 			Name:    ptr.Of("xxx"),
 			Comment: ptr.Of("Foo Bar"),
 			Home:    ptr.Of("/tmp"),
@@ -458,6 +419,8 @@ func TestFillDefault(t *testing.T) {
 	}
 
 	expect = d
+	// VMType should remain nil when not explicitly set
+	expect.VMType = nil
 	// Also verify that archive arch is filled in
 	expect.Containerd.Archives = slices.Clone(d.Containerd.Archives)
 	expect.Containerd.Archives[0].Arch = *d.Arch
@@ -480,88 +443,78 @@ func TestFillDefault(t *testing.T) {
 	expect.HostResolver.Hosts = map[string]string{
 		"default": d.HostResolver.Hosts["default"],
 	}
-	expect.MountType = ptr.Of(VIRTIOFS)
+	// Remove driver-specific mount type from defaults test
+	expect.MountType = nil
 	expect.MountInotify = ptr.Of(false)
 	expect.CACertificates.RemoveDefaults = ptr.Of(true)
 	expect.CACertificates.Certs = []string{
 		"-----BEGIN CERTIFICATE-----\nYOUR-ORGS-TRUSTED-CA-CERT\n-----END CERTIFICATE-----\n",
 	}
 
-	if runtime.GOOS == "darwin" && IsNativeArch(AARCH64) {
-		expect.Rosetta = Rosetta{
-			Enabled: ptr.Of(true),
-			BinFmt:  ptr.Of(true),
-		}
-	} else {
-		expect.Rosetta = Rosetta{
-			Enabled: ptr.Of(false),
-			BinFmt:  ptr.Of(true),
-		}
-	}
 	expect.Plain = ptr.Of(false)
 
-	y = LimaYAML{}
-	FillDefault(t.Context(), &y, &d, &LimaYAML{}, filePath, false)
+	y = limatype.LimaYAML{}
+	FillDefault(t.Context(), &y, &d, &limatype.LimaYAML{}, filePath, false)
 	assert.DeepEqual(t, &y, &expect, opts...)
 
-	dExpect := expect
+	dExpected := expect
 
 	// ------------------------------------------------------------------------------------
 	// User-provided defaults should not override user-provided config values
 
 	y = filledDefaults
 	y.DNS = []net.IP{net.ParseIP("8.8.8.8")}
-	y.AdditionalDisks = []Disk{{Name: "overridden"}}
+	y.AdditionalDisks = []limatype.Disk{{Name: "overridden"}}
 	y.User.Home = ptr.Of("/root")
 
 	expect = y
 
-	expect.Provision = slices.Concat(y.Provision, dExpect.Provision)
-	expect.Probes = slices.Concat(y.Probes, dExpect.Probes)
-	expect.PortForwards = slices.Concat(y.PortForwards, dExpect.PortForwards)
-	expect.CopyToHost = slices.Concat(y.CopyToHost, dExpect.CopyToHost)
-	expect.Containerd.Archives = slices.Concat(y.Containerd.Archives, dExpect.Containerd.Archives)
+	expect.Provision = slices.Concat(y.Provision, dExpected.Provision)
+	expect.Probes = slices.Concat(y.Probes, dExpected.Probes)
+	expect.PortForwards = slices.Concat(y.PortForwards, dExpected.PortForwards)
+	expect.CopyToHost = slices.Concat(y.CopyToHost, dExpected.CopyToHost)
+	expect.Containerd.Archives = slices.Concat(y.Containerd.Archives, dExpected.Containerd.Archives)
 	expect.Containerd.Archives[2].Arch = *expect.Arch
-	expect.AdditionalDisks = slices.Concat(y.AdditionalDisks, dExpect.AdditionalDisks)
-	expect.Firmware.Images = slices.Concat(y.Firmware.Images, dExpect.Firmware.Images)
+	expect.AdditionalDisks = slices.Concat(y.AdditionalDisks, dExpected.AdditionalDisks)
+	expect.Firmware.Images = slices.Concat(y.Firmware.Images, dExpected.Firmware.Images)
 
 	// Mounts and Networks start with lowest priority first, so higher priority entries can overwrite
-	expect.Mounts = slices.Concat(dExpect.Mounts, y.Mounts)
-	expect.Networks = slices.Concat(dExpect.Networks, y.Networks)
+	expect.Mounts = slices.Concat(dExpected.Mounts, y.Mounts)
+	expect.Networks = slices.Concat(dExpected.Networks, y.Networks)
 
-	expect.HostResolver.Hosts["default"] = dExpect.HostResolver.Hosts["default"]
+	expect.HostResolver.Hosts["default"] = dExpected.HostResolver.Hosts["default"]
 
-	// dExpect.DNS will be ignored, and not appended to y.DNS
+	// dExpected.DNS will be ignored, and not appended to y.DNS
 
-	// "TWO" does not exist in filledDefaults.Env, so is set from dExpect.Env
-	expect.Env["TWO"] = dExpect.Env["TWO"]
+	// "TWO" does not exist in filledDefaults.Env, so is set from dExpected.Env
+	expect.Env["TWO"] = dExpected.Env["TWO"]
 
-	expect.Param["TWO"] = dExpect.Param["TWO"]
+	expect.Param["TWO"] = dExpected.Param["TWO"]
 
-	t.Logf("d.vmType=%q, y.vmType=%q, expect.vmType=%q", *d.VMType, *y.VMType, *expect.VMType)
+	t.Logf("d.vmType=%v, y.vmType=%v, expect.vmType=%v", d.VMType, y.VMType, expect.VMType)
 
-	FillDefault(t.Context(), &y, &d, &LimaYAML{}, filePath, false)
+	FillDefault(t.Context(), &y, &d, &limatype.LimaYAML{}, filePath, false)
 	assert.DeepEqual(t, &y, &expect, opts...)
 
 	// ------------------------------------------------------------------------------------
 	// User-provided overrides should override user-provided config settings
 
-	o = LimaYAML{
-		VMType: ptr.Of("qemu"),
-		OS:     ptr.Of(LINUX),
+	o = limatype.LimaYAML{
+		// Remove driver-specific VMType from override test
+		OS:     ptr.Of(limatype.LINUX),
 		Arch:   ptr.Of(arch),
 		CPUs:   ptr.Of(12),
 		Memory: ptr.Of("7GiB"),
 		Disk:   ptr.Of("117GiB"),
-		AdditionalDisks: []Disk{
+		AdditionalDisks: []limatype.Disk{
 			{Name: "test"},
 		},
 		GuestInstallPrefix: ptr.Of("/usr"),
 		UpgradePackages:    ptr.Of(true),
-		Containerd: Containerd{
+		Containerd: limatype.Containerd{
 			System: ptr.Of(true),
 			User:   ptr.Of(false),
-			Archives: []File{
+			Archives: []limatype.File{
 				{
 					Arch:     arch,
 					Location: "/tmp/nerdctl.tgz",
@@ -569,7 +522,7 @@ func TestFillDefault(t *testing.T) {
 				},
 			},
 		},
-		SSH: SSH{
+		SSH: limatype.SSH{
 			LocalPort:         ptr.Of(4433),
 			LoadDotSSHPubKeys: ptr.Of(true),
 			ForwardAgent:      ptr.Of(true),
@@ -577,19 +530,17 @@ func TestFillDefault(t *testing.T) {
 			ForwardX11Trusted: ptr.Of(false),
 		},
 		TimeZone: ptr.Of("Universal"),
-		Firmware: Firmware{
+		Firmware: limatype.Firmware{
 			LegacyBIOS: ptr.Of(true),
 		},
-		Audio: Audio{
+		Audio: limatype.Audio{
 			Device: ptr.Of("coreaudio"),
 		},
-		Video: Video{
+		Video: limatype.Video{
 			Display: ptr.Of("cocoa"),
-			VNC: VNCOptions{
-				Display: ptr.Of("none"),
-			},
+			// Remove driver-specific VNC configuration
 		},
-		HostResolver: HostResolver{
+		HostResolver: limatype.HostResolver{
 			Enabled: ptr.Of(false),
 			IPv6:    ptr.Of(false),
 			Hosts: map[string]string{
@@ -598,40 +549,40 @@ func TestFillDefault(t *testing.T) {
 		},
 		PropagateProxyEnv: ptr.Of(false),
 
-		Mounts: []Mount{
+		Mounts: []limatype.Mount{
 			{
 				Location: varLog,
 				Writable: ptr.Of(true),
-				SSHFS: SSHFS{
+				SSHFS: limatype.SSHFS{
 					Cache:          ptr.Of(false),
 					FollowSymlinks: ptr.Of(true),
 				},
-				NineP: NineP{
+				NineP: limatype.NineP{
 					SecurityModel:   ptr.Of("mapped-file"),
 					ProtocolVersion: ptr.Of("9p2000"),
 					Msize:           ptr.Of("8KiB"),
 					Cache:           ptr.Of("none"),
 				},
-				Virtiofs: Virtiofs{
+				Virtiofs: limatype.Virtiofs{
 					QueueSize: ptr.Of(2048),
 				},
 			},
 		},
 		MountInotify: ptr.Of(true),
-		Provision: []Provision{
+		Provision: []limatype.Provision{
 			{
 				Script: "#!/bin/true",
-				Mode:   ProvisionModeSystem,
+				Mode:   limatype.ProvisionModeSystem,
 			},
 		},
-		Probes: []Probe{
+		Probes: []limatype.Probe{
 			{
 				Script:      "#!/bin/false",
-				Mode:        ProbeModeReadiness,
+				Mode:        limatype.ProbeModeReadiness,
 				Description: "Another Probe",
 			},
 		},
-		Networks: []Network{
+		Networks: []limatype.Network{
 			{
 				Lima:       "shared",
 				MACAddress: "10:20:30:40:50:60",
@@ -646,16 +597,16 @@ func TestFillDefault(t *testing.T) {
 		DNS: []net.IP{
 			net.ParseIP("2.2.2.2"),
 		},
-		PortForwards: []PortForward{{
+		PortForwards: []limatype.PortForward{{
 			GuestIP:        IPv4loopback1,
 			GuestPort:      88,
 			GuestPortRange: [2]int{88, 88},
 			HostIP:         IPv4loopback1,
 			HostPort:       8080,
 			HostPortRange:  [2]int{8080, 8080},
-			Proto:          ProtoTCP,
+			Proto:          limatype.ProtoTCP,
 		}},
-		CopyToHost: []CopyToHost{{}},
+		CopyToHost: []limatype.CopyToHost{{}},
 		Env: map[string]string{
 			"TWO":   "deux",
 			"THREE": "trois",
@@ -664,15 +615,11 @@ func TestFillDefault(t *testing.T) {
 			"TWO":   "deux",
 			"THREE": "trois",
 		},
-		CACertificates: CACertificates{
+		CACertificates: limatype.CACertificates{
 			RemoveDefaults: ptr.Of(true),
 		},
-		Rosetta: Rosetta{
-			Enabled: ptr.Of(false),
-			BinFmt:  ptr.Of(false),
-		},
 		NestedVirtualization: ptr.Of(false),
-		User: User{
+		User: limatype.User{
 			Name:    ptr.Of("foo"),
 			Comment: ptr.Of("foo bar baz"),
 			Home:    ptr.Of("/override"),
@@ -685,20 +632,20 @@ func TestFillDefault(t *testing.T) {
 
 	expect = o
 
-	expect.Provision = slices.Concat(o.Provision, y.Provision, dExpect.Provision)
-	expect.Probes = slices.Concat(o.Probes, y.Probes, dExpect.Probes)
-	expect.PortForwards = slices.Concat(o.PortForwards, y.PortForwards, dExpect.PortForwards)
-	expect.CopyToHost = slices.Concat(o.CopyToHost, y.CopyToHost, dExpect.CopyToHost)
-	expect.Containerd.Archives = slices.Concat(o.Containerd.Archives, y.Containerd.Archives, dExpect.Containerd.Archives)
+	expect.Provision = slices.Concat(o.Provision, y.Provision, dExpected.Provision)
+	expect.Probes = slices.Concat(o.Probes, y.Probes, dExpected.Probes)
+	expect.PortForwards = slices.Concat(o.PortForwards, y.PortForwards, dExpected.PortForwards)
+	expect.CopyToHost = slices.Concat(o.CopyToHost, y.CopyToHost, dExpected.CopyToHost)
+	expect.Containerd.Archives = slices.Concat(o.Containerd.Archives, y.Containerd.Archives, dExpected.Containerd.Archives)
 	expect.Containerd.Archives[3].Arch = *expect.Arch
-	expect.AdditionalDisks = slices.Concat(o.AdditionalDisks, y.AdditionalDisks, dExpect.AdditionalDisks)
-	expect.Firmware.Images = slices.Concat(o.Firmware.Images, y.Firmware.Images, dExpect.Firmware.Images)
+	expect.AdditionalDisks = slices.Concat(o.AdditionalDisks, y.AdditionalDisks, dExpected.AdditionalDisks)
+	expect.Firmware.Images = slices.Concat(o.Firmware.Images, y.Firmware.Images, dExpected.Firmware.Images)
 
-	expect.HostResolver.Hosts["default"] = dExpect.HostResolver.Hosts["default"]
-	expect.HostResolver.Hosts["MY.Host"] = dExpect.HostResolver.Hosts["host.lima.internal"]
+	expect.HostResolver.Hosts["default"] = dExpected.HostResolver.Hosts["default"]
+	expect.HostResolver.Hosts["MY.Host"] = dExpected.HostResolver.Hosts["host.lima.internal"]
 
-	// o.Mounts just makes dExpect.Mounts[0] writable because the Location matches
-	expect.Mounts = slices.Concat(dExpect.Mounts, y.Mounts)
+	// o.Mounts just makes dExpected.Mounts[0] writable because the Location matches
+	expect.Mounts = slices.Concat(dExpected.Mounts, y.Mounts)
 	expect.Mounts[0].Writable = ptr.Of(true)
 	expect.Mounts[0].SSHFS.Cache = ptr.Of(false)
 	expect.Mounts[0].SSHFS.FollowSymlinks = ptr.Of(true)
@@ -708,11 +655,11 @@ func TestFillDefault(t *testing.T) {
 	expect.Mounts[0].NineP.Cache = ptr.Of("none")
 	expect.Mounts[0].Virtiofs.QueueSize = ptr.Of(2048)
 
-	expect.MountType = ptr.Of(NINEP)
+	expect.MountType = ptr.Of(limatype.NINEP)
 	expect.MountInotify = ptr.Of(true)
 
-	// o.Networks[1] is overriding the dExpect.Networks[0].Lima entry for the "def0" interface
-	expect.Networks = slices.Concat(dExpect.Networks, y.Networks, []Network{o.Networks[0]})
+	// o.Networks[1] is overriding the dExpected.Networks[0].Lima entry for the "def0" interface
+	expect.Networks = slices.Concat(dExpected.Networks, y.Networks, []limatype.Network{o.Networks[0]})
 	expect.Networks[0].Lima = o.Networks[1].Lima
 
 	// Only highest prio DNS are retained
@@ -729,10 +676,6 @@ func TestFillDefault(t *testing.T) {
 		"-----BEGIN CERTIFICATE-----\nYOUR-ORGS-TRUSTED-CA-CERT\n-----END CERTIFICATE-----\n",
 	}
 
-	expect.Rosetta = Rosetta{
-		Enabled: ptr.Of(false),
-		BinFmt:  ptr.Of(false),
-	}
 	expect.Plain = ptr.Of(false)
 
 	expect.NestedVirtualization = ptr.Of(false)
diff --git a/pkg/limayaml/limayaml_test.go b/pkg/limayaml/limayaml_test.go
index 2fbeebf0..97fd8bae 100644
--- a/pkg/limayaml/limayaml_test.go
+++ b/pkg/limayaml/limayaml_test.go
@@ -12,6 +12,8 @@ import (
 	"testing"
 
 	"gotest.tools/v3/assert"
+
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 )
 
 func dumpJSON(t *testing.T, d any) string {
@@ -23,7 +25,7 @@ func dumpJSON(t *testing.T, d any) string {
 const emptyYAML = "{}\n"
 
 func TestEmptyYAML(t *testing.T) {
-	var y LimaYAML
+	var y limatype.LimaYAML
 	t.Log(dumpJSON(t, y))
 	b, err := Marshal(&y, false)
 	assert.NilError(t, err)
@@ -43,7 +45,7 @@ func TestDefaultYAML(t *testing.T) {
 		assert.NilError(t, err)
 	}
 
-	var y LimaYAML
+	var y limatype.LimaYAML
 	err = Unmarshal(content, &y, "")
 	assert.NilError(t, err)
 	y.Images = nil                // remove default images
diff --git a/pkg/limayaml/marshal_test.go b/pkg/limayaml/marshal_test.go
index 7e778ae0..4ad8f3ab 100644
--- a/pkg/limayaml/marshal_test.go
+++ b/pkg/limayaml/marshal_test.go
@@ -8,17 +8,18 @@ import (
 
 	"gotest.tools/v3/assert"
 
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 	"github.com/lima-vm/lima/v2/pkg/ptr"
 )
 
 func TestMarshalEmpty(t *testing.T) {
-	_, err := Marshal(&LimaYAML{}, false)
+	_, err := Marshal(&limatype.LimaYAML{}, false)
 	assert.NilError(t, err)
 }
 
 func TestMarshalTilde(t *testing.T) {
-	y := LimaYAML{
-		Mounts: []Mount{
+	y := limatype.LimaYAML{
+		Mounts: []limatype.Mount{
 			{Location: "~", Writable: ptr.Of(false)},
 			{Location: "/tmp/lima", Writable: ptr.Of(true)},
 			{Location: "null"},
diff --git a/pkg/limayaml/validate_test.go b/pkg/limayaml/validate_test.go
index 7cb1755c..943786b6 100644
--- a/pkg/limayaml/validate_test.go
+++ b/pkg/limayaml/validate_test.go
@@ -4,11 +4,12 @@
 package limayaml
 
 import (
-	"errors"
+	"fmt"
 	"testing"
 
 	"gotest.tools/v3/assert"
 
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 	"github.com/lima-vm/lima/v2/pkg/version"
 )
 
@@ -312,7 +313,6 @@ func TestValidateMultipleErrors(t *testing.T) {
 	yamlWithMultipleErrors := `
 os: windows
 arch: unsupported_arch
-vmType: invalid_type
 portForwards:
   - guestPort: 22
     hostPort: 2222
@@ -328,10 +328,10 @@ provision:
 	y, err := Load(t.Context(), []byte(yamlWithMultipleErrors), "multiple-errors.yaml")
 	assert.NilError(t, err)
 	err = Validate(y, false)
+	t.Logf("Validation errors: %v", err)
 
 	assert.Error(t, err, "field `os` must be \"Linux\"; got \"windows\"\n"+
 		"field `arch` must be one of [x86_64 aarch64 armv7l ppc64le riscv64 s390x]; got \"unsupported_arch\"\n"+
-		"field `vmType` must be \"qemu\", \"vz\", \"wsl2\"; got \"invalid_type\"\n"+
 		"field `images` must be set\n"+
 		"field `provision[0].mode` must one of \"system\", \"user\", \"boot\", \"data\", \"dependency\", or \"ansible\"\n"+
 		"field `provision[1].path` must not be empty when mode is \"data\"")
@@ -342,49 +342,51 @@ func TestValidateAgainstLatestConfig(t *testing.T) {
 		name    string
 		yNew    string
 		yLatest string
-		wantErr error
+		wantErr string
 	}{
 		{
 			name:    "Valid disk size unchanged",
 			yNew:    `disk: 100GiB`,
 			yLatest: `disk: 100GiB`,
+			wantErr: fmt.Sprintf("failed to accept config for \"\": vmType %q is not a registered driver", limatype.DefaultDriver()),
 		},
 		{
 			name:    "Valid disk size increased",
 			yNew:    `disk: 200GiB`,
 			yLatest: `disk: 100GiB`,
+			wantErr: fmt.Sprintf("failed to accept config for \"\": vmType %q is not a registered driver", limatype.DefaultDriver()),
 		},
 		{
 			name:    "No disk field in both YAMLs",
 			yNew:    ``,
 			yLatest: ``,
+			wantErr: fmt.Sprintf("failed to accept config for \"\": vmType %q is not a registered driver", limatype.DefaultDriver()),
 		},
 		{
 			name:    "No disk field in new YAMLs",
 			yNew:    ``,
 			yLatest: `disk: 100GiB`,
+			wantErr: fmt.Sprintf("failed to accept config for \"\": vmType %q is not a registered driver", limatype.DefaultDriver()),
 		},
 		{
 			name:    "No disk field in latest YAMLs",
 			yNew:    `disk: 100GiB`,
 			yLatest: ``,
+			wantErr: fmt.Sprintf("failed to accept config for \"\": vmType %q is not a registered driver", limatype.DefaultDriver()),
 		},
 		{
 			name:    "Disk size shrunk",
 			yNew:    `disk: 50GiB`,
 			yLatest: `disk: 100GiB`,
-			wantErr: errors.New("field `disk`: shrinking the disk (100GiB --> 50GiB) is not supported"),
+			wantErr: fmt.Sprintf("failed to accept config for \"\": vmType %q is not a registered driver\n", limatype.DefaultDriver()) +
+				"field `disk`: shrinking the disk (100GiB --> 50GiB) is not supported",
 		},
 	}
 
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			err := ValidateAgainstLatestConfig(t.Context(), []byte(tt.yNew), []byte(tt.yLatest))
-			if tt.wantErr == nil {
-				assert.NilError(t, err)
-			} else {
-				assert.Error(t, err, tt.wantErr.Error())
-			}
+			assert.Error(t, err, tt.wantErr)
 		})
 	}
 }
diff --git a/pkg/networks/commands_test.go b/pkg/networks/commands_test.go
index 2f9877e6..4d5667d9 100644
--- a/pkg/networks/commands_test.go
+++ b/pkg/networks/commands_test.go
@@ -10,7 +10,7 @@ import (
 
 	"gotest.tools/v3/assert"
 
-	"github.com/lima-vm/lima/v2/pkg/store/dirnames"
+	"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
 )
 
 func TestCheck(t *testing.T) {
diff --git a/pkg/registry/registry_test.go b/pkg/registry/registry_test.go
index c872e62d..c672e971 100644
--- a/pkg/registry/registry_test.go
+++ b/pkg/registry/registry_test.go
@@ -14,7 +14,7 @@ import (
 	"gotest.tools/v3/assert"
 
 	"github.com/lima-vm/lima/v2/pkg/driver"
-	"github.com/lima-vm/lima/v2/pkg/store"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 )
 
 type mockDriver struct {
@@ -27,24 +27,30 @@ func newMockDriver(name string) *mockDriver {
 
 var _ driver.Driver = (*mockDriver)(nil)
 
-func (m *mockDriver) Validate(_ context.Context) error                           { return nil }
-func (m *mockDriver) Initialize(_ context.Context) error                         { return nil }
-func (m *mockDriver) CreateDisk(_ context.Context) error                         { return nil }
-func (m *mockDriver) Start(_ context.Context) (chan error, error)                { return nil, nil }
-func (m *mockDriver) Stop(_ context.Context) error                               { return nil }
-func (m *mockDriver) RunGUI() error                                              { return nil }
-func (m *mockDriver) ChangeDisplayPassword(_ context.Context, _ string) error    { return nil }
-func (m *mockDriver) DisplayConnection(_ context.Context) (string, error)        { return "", nil }
-func (m *mockDriver) CreateSnapshot(_ context.Context, _ string) error           { return nil }
-func (m *mockDriver) ApplySnapshot(_ context.Context, _ string) error            { return nil }
-func (m *mockDriver) DeleteSnapshot(_ context.Context, _ string) error           { return nil }
-func (m *mockDriver) ListSnapshots(_ context.Context) (string, error)            { return "", nil }
-func (m *mockDriver) Register(_ context.Context) error                           { return nil }
-func (m *mockDriver) Unregister(_ context.Context) error                         { return nil }
-func (m *mockDriver) ForwardGuestAgent() bool                                    { return false }
-func (m *mockDriver) GuestAgentConn(_ context.Context) (net.Conn, string, error) { return nil, "", nil }
-func (m *mockDriver) Info() driver.Info                                          { return driver.Info{DriverName: m.Name} }
-func (m *mockDriver) Configure(_ *store.Instance) *driver.ConfiguredDriver       { return nil }
+func (m *mockDriver) Validate(_ context.Context) error                             { return nil }
+func (m *mockDriver) Create(_ context.Context) error                               { return nil }
+func (m *mockDriver) Delete(_ context.Context) error                               { return nil }
+func (m *mockDriver) CreateDisk(_ context.Context) error                           { return nil }
+func (m *mockDriver) Start(_ context.Context) (chan error, error)                  { return nil, nil }
+func (m *mockDriver) Stop(_ context.Context) error                                 { return nil }
+func (m *mockDriver) RunGUI() error                                                { return nil }
+func (m *mockDriver) ChangeDisplayPassword(_ context.Context, _ string) error      { return nil }
+func (m *mockDriver) DisplayConnection(_ context.Context) (string, error)          { return "", nil }
+func (m *mockDriver) CreateSnapshot(_ context.Context, _ string) error             { return nil }
+func (m *mockDriver) ApplySnapshot(_ context.Context, _ string) error              { return nil }
+func (m *mockDriver) DeleteSnapshot(_ context.Context, _ string) error             { return nil }
+func (m *mockDriver) ListSnapshots(_ context.Context) (string, error)              { return "", nil }
+func (m *mockDriver) Register(_ context.Context) error                             { return nil }
+func (m *mockDriver) Unregister(_ context.Context) error                           { return nil }
+func (m *mockDriver) ForwardGuestAgent() bool                                      { return false }
+func (m *mockDriver) GuestAgentConn(_ context.Context) (net.Conn, string, error)   { return nil, "", nil }
+func (m *mockDriver) Info() driver.Info                                            { return driver.Info{DriverName: m.Name} }
+func (m *mockDriver) Configure(_ *limatype.Instance) *driver.ConfiguredDriver      { return nil }
+func (m *mockDriver) AcceptConfig(_ *limatype.LimaYAML, _ string) error            { return nil }
+func (m *mockDriver) FillConfig(_ *limatype.LimaYAML, _ string) error              { return nil }
+func (m *mockDriver) InspectStatus(_ context.Context, _ *limatype.Instance) string { return "" }
+func (m *mockDriver) SSHAddress(_ context.Context) (string, error)                 { return "", nil }
+func (m *mockDriver) BootScripts() (map[string][]byte, error)                      { return nil, nil }
 
 func TestRegister(t *testing.T) {
 	BackupRegistry(t)
diff --git a/pkg/store/fuzz_test.go b/pkg/store/fuzz_test.go
index 62b007d5..7f1083ee 100644
--- a/pkg/store/fuzz_test.go
+++ b/pkg/store/fuzz_test.go
@@ -10,7 +10,7 @@ import (
 
 	"gotest.tools/v3/assert"
 
-	"github.com/lima-vm/lima/v2/pkg/store/filenames"
+	"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
 )
 
 func FuzzLoadYAMLByFilePath(f *testing.F) {
diff --git a/pkg/store/instance_test.go b/pkg/store/instance_test.go
index 55b7e57b..28ffcb7a 100644
--- a/pkg/store/instance_test.go
+++ b/pkg/store/instance_test.go
@@ -13,20 +13,20 @@ import (
 
 	"gotest.tools/v3/assert"
 
-	"github.com/lima-vm/lima/v2/pkg/limayaml"
+	"github.com/lima-vm/lima/v2/pkg/limatype"
 )
 
 const separator = string(filepath.Separator)
 
 var (
-	vmtype = limayaml.QEMU
-	goarch = limayaml.NewArch(runtime.GOARCH)
+	vmtype = limatype.QEMU
+	goarch = limatype.NewArch(runtime.GOARCH)
 	space  = strings.Repeat(" ", len(goarch)-4)
 )
 
-var instance = Instance{
+var instance = limatype.Instance{
 	Name:       "foo",
-	Status:     StatusStopped,
+	Status:     limatype.StatusStopped,
 	VMType:     vmtype,
 	Arch:       goarch,
 	Dir:        "dir",
@@ -68,7 +68,7 @@ var tableTwo = "NAME    STATUS     SSH            VMTYPE    ARCH       CPUS    M
 
 func TestPrintInstanceTable(t *testing.T) {
 	var buf bytes.Buffer
-	instances := []*Instance{&instance}
+	instances := []*limatype.Instance{&instance}
 	err := PrintInstances(&buf, instances, "table", nil)
 	assert.NilError(t, err)
 	assert.Equal(t, table, buf.String())
@@ -78,7 +78,7 @@ func TestPrintInstanceTableEmu(t *testing.T) {
 	var buf bytes.Buffer
 	instance1 := instance
 	instance1.Arch = "unknown"
-	instances := []*Instance{&instance1}
+	instances := []*limatype.Instance{&instance1}
 	err := PrintInstances(&buf, instances, "table", nil)
 	assert.NilError(t, err)
 	assert.Equal(t, tableEmu, buf.String())
@@ -90,7 +90,7 @@ func TestPrintInstanceTableHome(t *testing.T) {
 	assert.NilError(t, err)
 	instance1 := instance
 	instance1.Dir = filepath.Join(homeDir, "dir")
-	instances := []*Instance{&instance1}
+	instances := []*limatype.Instance{&instance1}
 	err = PrintInstances(&buf, instances, "table", nil)
 	assert.NilError(t, err)
 	assert.Equal(t, tableHome, buf.String())
@@ -98,7 +98,7 @@ func TestPrintInstanceTableHome(t *testing.T) {
 
 func TestPrintInstanceTable60(t *testing.T) {
 	var buf bytes.Buffer
-	instances := []*Instance{&instance}
+	instances := []*limatype.Instance{&instance}
 	options := PrintOptions{TerminalWidth: 60}
 	err := PrintInstances(&buf, instances, "table", &options)
 	assert.NilError(t, err)
@@ -107,7 +107,7 @@ func TestPrintInstanceTable60(t *testing.T) {
 
 func TestPrintInstanceTable80SameArch(t *testing.T) {
 	var buf bytes.Buffer
-	instances := []*Instance{&instance}
+	instances := []*limatype.Instance{&instance}
 	options := PrintOptions{TerminalWidth: 80}
 	err := PrintInstances(&buf, instances, "table", &options)
 	assert.NilError(t, err)
@@ -117,8 +117,8 @@ func TestPrintInstanceTable80SameArch(t *testing.T) {
 func TestPrintInstanceTable80DiffArch(t *testing.T) {
 	var buf bytes.Buffer
 	instance1 := instance
-	instance1.Arch = limayaml.NewArch("unknown")
-	instances := []*Instance{&instance1}
+	instance1.Arch = limatype.NewArch("unknown")
+	instances := []*limatype.Instance{&instance1}
 	options := PrintOptions{TerminalWidth: 80}
 	err := PrintInstances(&buf, instances, "table", &options)
 	assert.NilError(t, err)
@@ -127,7 +127,7 @@ func TestPrintInstanceTable80DiffArch(t *testing.T) {
 
 func TestPrintInstanceTable100(t *testing.T) {
 	var buf bytes.Buffer
-	instances := []*Instance{&instance}
+	instances := []*limatype.Instance{&instance}
 	options := PrintOptions{TerminalWidth: 100}
 	err := PrintInstances(&buf, instances, "table", &options)
 	assert.NilError(t, err)
@@ -136,7 +136,7 @@ func TestPrintInstanceTable100(t *testing.T) {
 
 func TestPrintInstanceTableAll(t *testing.T) {
 	var buf bytes.Buffer
-	instances := []*Instance{&instance}
+	instances := []*limatype.Instance{&instance}
 	options := PrintOptions{TerminalWidth: 40, AllFields: true}
 	err := PrintInstances(&buf, instances, "table", &options)
 	assert.NilError(t, err)
@@ -147,13 +147,13 @@ func TestPrintInstanceTableTwo(t *testing.T) {
 	var buf bytes.Buffer
 	instance1 := instance
 	instance1.Name = "foo"
-	instance1.VMType = limayaml.QEMU
-	instance1.Arch = limayaml.X8664
+	instance1.VMType = limatype.QEMU
+	instance1.Arch = limatype.X8664
 	instance2 := instance
 	instance2.Name = "bar"
-	instance2.VMType = limayaml.VZ
-	instance2.Arch = limayaml.AARCH64
-	instances := []*Instance{&instance1, &instance2}
+	instance2.VMType = limatype.VZ
+	instance2.Arch = limatype.AARCH64
+	instances := []*limatype.Instance{&instance1, &instance2}
 	options := PrintOptions{TerminalWidth: 80}
 	err := PrintInstances(&buf, instances, "table", &options)
 	assert.NilError(t, err)
diff --git a/pkg/store/store_test.go b/pkg/store/store_test.go
index 4dfe1eea..9879bf25 100644
--- a/pkg/store/store_test.go
+++ b/pkg/store/store_test.go
@@ -7,6 +7,8 @@ import (
 	"testing"
 
 	"gotest.tools/v3/assert"
+
+	"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
 )
 
 func TestValidateInstName(t *testing.T) {
@@ -22,7 +24,7 @@ func TestValidateInstName(t *testing.T) {
 	}
 	for _, arg := range instNames {
 		t.Run(arg, func(t *testing.T) {
-			err := ValidateInstName(arg)
+			err := dirnames.ValidateInstName(arg)
 			assert.NilError(t, err)
 		})
 	}
@@ -43,7 +45,7 @@ func TestValidateInstName(t *testing.T) {
 	}
 	for _, arg := range invalidIdentifiers {
 		t.Run(arg, func(t *testing.T) {
-			err := ValidateInstName(arg)
+			err := dirnames.ValidateInstName(arg)
 			assert.ErrorContains(t, err, "not a valid identifier")
 		})
 	}
@@ -54,7 +56,7 @@ func TestValidateInstName(t *testing.T) {
 	}
 	for _, arg := range yamlNames {
 		t.Run(arg, func(t *testing.T) {
-			err := ValidateInstName(arg)
+			err := dirnames.ValidateInstName(arg)
 			assert.ErrorContains(t, err, "must not end with .y")
 		})
 	}
diff --git a/pkg/templatestore/templatestore.go b/pkg/templatestore/templatestore.go
index a61eeb2c..9591a59a 100644
--- a/pkg/templatestore/templatestore.go
+++ b/pkg/templatestore/templatestore.go
@@ -14,7 +14,7 @@ import (
 	"strings"
 	"unicode"
 
-	"github.com/lima-vm/lima/v2/pkg/store/dirnames"
+	"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
 	"github.com/lima-vm/lima/v2/pkg/usrlocalsharelima"
 )