diff --git a/pmb/build/__init__.py b/pmb/build/__init__.py
index 2ff3e1d9b85a09ca1b3829a5b348ab858e4918b3..4768660026393934d9bf6e6a50583f14080915e8 100644
--- a/pmb/build/__init__.py
+++ b/pmb/build/__init__.py
@@ -2,7 +2,6 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 from pmb.build.init import init, init_abuild_minimal, init_compiler
 from pmb.build.envkernel import package_kernel
-from pmb.build.kconfig import menuconfig
 from pmb.build.newapkbuild import newapkbuild
 from pmb.build.other import copy_to_buildpath, get_status, index_repo
 from .backend import mount_pmaports
diff --git a/pmb/build/kconfig.py b/pmb/build/kconfig.py
index c19664c91a8c0c0ae7d42f2765a56630d9a2bb6e..de1aeb0e5f5d5c0f8db6a509f711853e82ad676a 100644
--- a/pmb/build/kconfig.py
+++ b/pmb/build/kconfig.py
@@ -1,10 +1,11 @@
 # Copyright 2023 Oliver Smith
 # SPDX-License-Identifier: GPL-3.0-or-later
+import enum
 import os
+from pathlib import Path
 from pmb.core.arch import Arch
 from pmb.core.context import get_context
 from pmb.helpers import logging
-from pathlib import Path
 from typing import Any
 
 import pmb.build
@@ -13,13 +14,33 @@ import pmb.build.checksum
 import pmb.chroot
 import pmb.chroot.apk
 import pmb.chroot.other
-from pmb.types import PmbArgs
 import pmb.helpers.pmaports
 import pmb.helpers.run
 import pmb.parse
 from pmb.core import Chroot
 
 
+class KConfigUI(enum.Enum):
+    Menu = "menuconfig"
+    Qt = "xconfig"
+    Ncurses = "nconfig"
+
+    def is_graphical(self) -> bool:
+        graphical = [KConfigUI.Qt]
+        return self in graphical
+
+    def depends(self) -> list[str]:
+        mapping = {
+            KConfigUI.Menu: ["ncurses-dev"],
+            KConfigUI.Qt: ["qt5-qtbase-dev", "font-noto"],
+            KConfigUI.Ncurses: ["ncurses-dev"],
+        }
+        return mapping[self]
+
+    def __str__(self) -> str:
+        return self.value
+
+
 def get_arch(apkbuild) -> Arch:
     """Take the architecture from the APKBUILD or complain if it's ambiguous.
 
@@ -109,15 +130,41 @@ def extract_and_patch_sources(pkgname: str, arch) -> None:
     )
 
 
-def menuconfig(args: PmbArgs, pkgname: str, use_oldconfig) -> None:
+def _make(chroot: pmb.core.Chroot, make_command: str, env, pkgname, arch, apkbuild) -> None:
+    aport = pmb.helpers.pmaports.find(pkgname)
+    outputdir = get_outputdir(pkgname, apkbuild)
+
+    logging.info("(native) make " + make_command)
+
+    pmb.chroot.user(["make", str(make_command)], chroot, outputdir, output="tui", env=env)
+
+    # Find the updated config
+    source = Chroot.native() / outputdir / ".config"
+    if not source.exists():
+        raise RuntimeError(f"No kernel config generated: {source}")
+
+    # Update the aport (config and checksum)
+    logging.info("Copy kernel config back to aport-folder")
+    config = f"config-{apkbuild['_flavor']}.{arch}"
+    target = aport / config
+    pmb.helpers.run.user(["cp", source, target])
+    pmb.build.checksum.update(pkgname)
+
+
+def _init(pkgname: str, arch: Arch | None) -> tuple[str, Arch, Any, Chroot, dict[str, str]]:
+    """
+    :returns: pkgname, arch, apkbuild, chroot, env
+    """
     # Pkgname: allow omitting "linux-" prefix
     if not pkgname.startswith("linux-"):
         pkgname = "linux-" + pkgname
 
-    # Read apkbuild
     aport = pmb.helpers.pmaports.find(pkgname)
     apkbuild = pmb.parse.apkbuild(aport / "APKBUILD")
-    arch = args.arch or get_arch(apkbuild)
+
+    if arch is None:
+        arch = get_arch(apkbuild)
+
     chroot = pmb.build.autodetect.chroot(apkbuild, arch)
     cross = pmb.build.autodetect.crosscompile(apkbuild, arch)
     hostspec = arch.alpine_triple()
@@ -128,56 +175,44 @@ def menuconfig(args: PmbArgs, pkgname: str, use_oldconfig) -> None:
         pmb.build.init_compiler(get_context(), [], cross, arch)
 
     depends = apkbuild["makedepends"] + ["gcc", "make"]
-    copy_xauth = False
-
-    if use_oldconfig:
-        kopt = "oldconfig"
-    else:
-        kopt = "menuconfig"
-        if args.xconfig:
-            depends += ["qt5-qtbase-dev", "font-noto"]
-            kopt = "xconfig"
-            copy_xauth = True
-        elif args.nconfig:
-            kopt = "nconfig"
-            depends += ["ncurses-dev"]
-        else:
-            depends += ["ncurses-dev"]
-
-    pmb.chroot.apk.install(depends, Chroot.native())
 
-    # Copy host's .xauthority into native
-    if copy_xauth:
-        pmb.chroot.other.copy_xauthority(args)
+    pmb.chroot.apk.install(depends, chroot)
 
     extract_and_patch_sources(pkgname, arch)
 
-    # Check for background color variable
-    color = os.environ.get("MENUCONFIG_COLOR")
-
-    # Run make menuconfig
-    outputdir = get_outputdir(pkgname, apkbuild)
-    logging.info("(native) make " + kopt)
     env = {
         "ARCH": arch.kernel(),
-        "DISPLAY": os.environ.get("DISPLAY"),
-        "XAUTHORITY": "/home/pmos/.Xauthority",
     }
+
     if cross:
         env["CROSS_COMPILE"] = f"{hostspec}-"
         env["CC"] = f"{hostspec}-gcc"
+
+    return pkgname, arch, apkbuild, chroot, env
+
+
+def migrate_config(pkgname: str, arch: Arch | None) -> None:
+    pkgname, arch, apkbuild, chroot, env = _init(pkgname, arch)
+    _make(chroot, "oldconfig", env, pkgname, arch, apkbuild)
+    pass
+
+def edit_config(pkgname: str, arch: Arch | None, config_ui: KConfigUI) -> None:
+    pkgname, arch, apkbuild, chroot, env = _init(pkgname, arch)
+
+    pmb.chroot.apk.install(config_ui.depends, chroot)
+
+    # Copy host's .xauthority into native
+    if config_ui.is_graphical():
+        pmb.chroot.other.copy_xauthority(chroot)
+        env["DISPLAY"] = os.environ.get("DISPLAY") or ":0"
+        env["XAUTHORITY"] = "/home/pmos/.Xauthority"
+
+    # Check for background color variable
+    color = os.environ.get("MENUCONFIG_COLOR")
     if color:
         env["MENUCONFIG_COLOR"] = color
-    pmb.chroot.user(["make", kopt], Chroot.native(), outputdir, output="tui", env=env)
-
-    # Find the updated config
-    source = Chroot.native() / outputdir / ".config"
-    if not source.exists():
-        raise RuntimeError(f"No kernel config generated: {source}")
+    mode = os.environ.get("MENUCONFIG_MODE")
+    if mode:
+        env["MENUCONFIG_MODE"] = mode
 
-    # Update the aport (config and checksum)
-    logging.info("Copy kernel config back to aport-folder")
-    config = f"config-{apkbuild['_flavor']}.{arch}"
-    target = aport / config
-    pmb.helpers.run.user(["cp", source, target])
-    pmb.build.checksum.update(pkgname)
+    _make(chroot, str(config_ui), env, pkgname, arch, apkbuild)
diff --git a/pmb/chroot/other.py b/pmb/chroot/other.py
index 10d6d37825726bd51b2a47857cae850dcb552b17..2277c5e50205f4452a59ba0788afdbd5fd76411a 100644
--- a/pmb/chroot/other.py
+++ b/pmb/chroot/other.py
@@ -4,7 +4,6 @@ import os
 from pmb.core.context import get_context
 from pmb.helpers import logging
 import pmb.chroot.apk
-from pmb.types import PmbArgs
 import pmb.install
 from pmb.core import Chroot
 
@@ -34,7 +33,7 @@ def kernel_flavor_installed(chroot: Chroot, autoinstall=True):
     return glob_result[0].name if glob_result else None
 
 
-def copy_xauthority(args: PmbArgs):
+def copy_xauthority(chroot: Chroot):
     """
     Copy the host system's Xauthority file to the pmos user inside the chroot,
     so we can start X11 applications from there.
@@ -60,7 +59,7 @@ def copy_xauthority(args: PmbArgs):
         )
 
     # Copy to chroot and chown
-    copy = Chroot.native() / "home/pmos/.Xauthority"
+    copy = chroot / "home/pmos/.Xauthority"
     if os.path.exists(copy):
         pmb.helpers.run.root(["rm", copy])
     pmb.helpers.run.root(["cp", original, copy])
diff --git a/pmb/commands/__init__.py b/pmb/commands/__init__.py
index 1c379e153250e82045282ae3c7a3ae87d427bae5..1360b65d5e1ce819f2805182e847faaf4c8a49ea 100644
--- a/pmb/commands/__init__.py
+++ b/pmb/commands/__init__.py
@@ -16,8 +16,7 @@ from .repo_bootstrap import RepoBootstrap
 from .shutdown import Shutdown
 from .test import Test
 from .pull import Pull
-from .kconfig_check import KConfigCheck
-from .kconfig_edit import KConfigEdit
+from .kconfig import KConfigCheck, KConfigEdit, KConfigMigrate
 
 """New way to model pmbootstrap subcommands that can be invoked without PmbArgs."""
 
@@ -78,8 +77,12 @@ def run_command(args: PmbArgs):
         command = Pull()
     elif args.action == "kconfig" and args.action_kconfig == "check":
         command = KConfigCheck(args.kconfig_check_details, args.file, args.package)
-    elif args.action == "kconfig" and args.action_kconfig in ["edit", "migrate"]:
-        command = KConfigEdit(args.package, args.action_kconfig == "migrate")
+    elif args.action == "kconfig" and args.action_kconfig == "edit":
+        command = KConfigEdit(
+            args.package, args.arch, {"nconfig": args.nconfig, "xconfig": args.xconfig}
+        )
+    elif args.action == "kconfig" and args.action_kconfig == "migrate":
+        command = KConfigMigrate(args.package, args.arch)
     else:
         raise NotImplementedError(f"Command '{args.action}' is not implemented.")
 
diff --git a/pmb/commands/kconfig_check.py b/pmb/commands/kconfig.py
similarity index 57%
rename from pmb/commands/kconfig_check.py
rename to pmb/commands/kconfig.py
index d9194de5a23d3d81aff3360f6b9411a2256b7d37..c44f43b0f966af032a20841b6f7e1ac41699f0a2 100644
--- a/pmb/commands/kconfig_check.py
+++ b/pmb/commands/kconfig.py
@@ -4,9 +4,12 @@
 from __future__ import annotations
 from pmb import commands
 from pmb.core.context import get_context
+from pmb.core.arch import Arch
+from pmb.build.kconfig import KConfigUI
 import pmb.helpers.git
 import pmb.config
 import logging
+from typing import Any
 
 
 class KConfigCheck(commands.Command):
@@ -61,3 +64,53 @@ class KConfigCheck(commands.Command):
                     " (consider 'pmbootstrap kconfig check -f')"
                 )
             logging.info("kconfig check succeeded!")
+
+
+class KConfigEdit(commands.Command):
+    pkgnames: list[str]
+    arch: Arch | None
+    config_ui: KConfigUI
+
+    def __init__(self, pkgname: str | list[str], arch: Arch | None, ui_choose: Any):
+        if isinstance(pkgname, str):
+            self.pkgnames = [ pkgname ]
+        else:
+            self.pkgnames = pkgname
+
+        self.arch = arch
+
+        config_ui = None
+        # make sure only one is set
+        for key, value in ui_choose:
+            if value:
+                if config_ui is not None:
+                    raise ValueError("Multiple kconfig UIs are specified, don't know what to do.")
+                if key == "nconfig":
+                    config_ui = KConfigUI.Ncurses
+                elif key == "xconfig":
+                    config_ui = KConfigUI.Qt
+
+        # set default
+        if config_ui is None:
+            config_ui = KConfigUI.Menu
+
+        self.config_ui = config_ui
+
+    def run(self) -> None:
+        for pkgname in self.pkgnames:
+            pmb.build.kconfig.edit_config(pkgname, self.arch, self.config_ui)
+
+
+class KConfigMigrate(commands.Command):
+    pkgnames: list[str]
+
+    def __init__(self, pkgname: str | list[str], arch: Arch | None):
+        if isinstance(pkgname, str):
+            self.pkgnames = [ pkgname ]
+        else:
+            self.pkgnames = pkgname
+        self.arch = arch
+
+    def run(self):        
+        for pkgname in self.pkgnames:
+            pmb.build.kconfig.migrate_config(pkgname, self.arch)
diff --git a/pmb/commands/kconfig_edit.py b/pmb/commands/kconfig_edit.py
deleted file mode 100644
index b3f0f195a114c35d4438af861c3c1a772d6fa6f2..0000000000000000000000000000000000000000
--- a/pmb/commands/kconfig_edit.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright 2024 Oliver Smith
-# SPDX-License-Identifier: GPL-3.0-or-later
-
-from __future__ import annotations
-from pmb import commands
-import pmb.build
-import pmb.helpers.args
-
-
-class KConfigEdit(commands.Command):
-    pkgname: str
-    use_oldconfig: bool
-
-    def __init__(self, pkgname, use_oldconfig):
-        self.pkgname = pkgname
-        self.use_oldconfig = use_oldconfig
-        pass
-
-    def run(self):
-        args = pmb.helpers.args.please_i_really_need_args()
-        pmb.build.menuconfig(args, self.pkgname, self.use_oldconfig)
diff --git a/pmb/helpers/frontend.py b/pmb/helpers/frontend.py
index 4392e2674c52daf1528f24a4b28e12414b643bfa..501e7e8a22cd25067e374245e797668a38af057b 100644
--- a/pmb/helpers/frontend.py
+++ b/pmb/helpers/frontend.py
@@ -196,7 +196,7 @@ def chroot(args: PmbArgs):
     # Xauthority
     env = {}
     if args.xauth:
-        pmb.chroot.other.copy_xauthority(args)
+        pmb.chroot.other.copy_xauthority(chroot)
         env["DISPLAY"] = os.environ.get("DISPLAY")
         env["XAUTHORITY"] = "/home/pmos/.Xauthority"