diff --git a/cmd/gotk/bootstrap.go b/cmd/gotk/bootstrap.go
index 2dce249aa985ccc01ec1aee38ded69e5d2a902f5..06af444e3517fafc1d81ee2f8c04f85827788f90 100644
--- a/cmd/gotk/bootstrap.go
+++ b/cmd/gotk/bootstrap.go
@@ -38,6 +38,8 @@ import (
 	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
 	sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
 
+	"github.com/fluxcd/toolkit/internal/flags"
+	"github.com/fluxcd/toolkit/internal/utils"
 	"github.com/fluxcd/toolkit/pkg/install"
 )
 
@@ -52,11 +54,11 @@ var (
 	bootstrapComponents         []string
 	bootstrapRegistry           string
 	bootstrapImagePullSecret    string
-	bootstrapArch               string
+	bootstrapArch               flags.Arch = "amd64"
 	bootstrapBranch             string
 	bootstrapWatchAllNamespaces bool
 	bootstrapNetworkPolicy      bool
-	bootstrapLogLevel           string
+	bootstrapLogLevel           flags.LogLevel = "info"
 	bootstrapManifestsPath      string
 	bootstrapRequiredComponents = []string{"source-controller", "kustomize-controller"}
 )
@@ -77,8 +79,7 @@ func init() {
 		"container registry where the toolkit images are published")
 	bootstrapCmd.PersistentFlags().StringVar(&bootstrapImagePullSecret, "image-pull-secret", "",
 		"Kubernetes secret name used for pulling the toolkit images from a private registry")
-	bootstrapCmd.PersistentFlags().StringVar(&bootstrapArch, "arch", "amd64",
-		"arch can be amd64 or arm64")
+	bootstrapCmd.PersistentFlags().Var(&bootstrapArch, "arch", bootstrapArch.Description())
 	bootstrapCmd.PersistentFlags().StringVar(&bootstrapBranch, "branch", bootstrapDefaultBranch,
 		"default branch (for GitHub this must match the default branch setting for the organization)")
 	rootCmd.AddCommand(bootstrapCmd)
@@ -86,22 +87,14 @@ func init() {
 		"watch for custom resources in all namespaces, if set to false it will only watch the namespace where the toolkit is installed")
 	bootstrapCmd.PersistentFlags().BoolVar(&bootstrapNetworkPolicy, "network-policy", true,
 		"deny ingress access to the toolkit controllers from other namespaces using network policies")
-	bootstrapCmd.PersistentFlags().StringVar(&bootstrapLogLevel, "log-level", "info", "set the controllers log level")
+	bootstrapCmd.PersistentFlags().Var(&bootstrapLogLevel, "log-level", bootstrapLogLevel.Description())
 	bootstrapCmd.PersistentFlags().StringVar(&bootstrapManifestsPath, "manifests", "", "path to the manifest directory")
 	bootstrapCmd.PersistentFlags().MarkHidden("manifests")
 }
 
 func bootstrapValidate() error {
-	if !utils.containsItemString(supportedArch, bootstrapArch) {
-		return fmt.Errorf("arch %s is not supported, can be %v", bootstrapArch, supportedArch)
-	}
-
-	if !utils.containsItemString(supportedLogLevels, bootstrapLogLevel) {
-		return fmt.Errorf("log level %s is not supported, can be %v", bootstrapLogLevel, supportedLogLevels)
-	}
-
 	for _, component := range bootstrapRequiredComponents {
-		if !utils.containsItemString(bootstrapComponents, component) {
+		if !utils.ContainsItemString(bootstrapComponents, component) {
 			return fmt.Errorf("component %s is required", component)
 		}
 	}
@@ -124,10 +117,10 @@ func generateInstallManifests(targetPath, namespace, tmpDir string, localManifes
 		Components:             bootstrapComponents,
 		Registry:               bootstrapRegistry,
 		ImagePullSecret:        bootstrapImagePullSecret,
-		Arch:                   bootstrapArch,
+		Arch:                   bootstrapArch.String(),
 		WatchAllNamespaces:     bootstrapWatchAllNamespaces,
 		NetworkPolicy:          bootstrapNetworkPolicy,
-		LogLevel:               bootstrapLogLevel,
+		LogLevel:               bootstrapLogLevel.String(),
 		NotificationController: defaultNotification,
 		ManifestsFile:          fmt.Sprintf("%s.yaml", namespace),
 		Timeout:                timeout,
@@ -151,13 +144,13 @@ func generateInstallManifests(targetPath, namespace, tmpDir string, localManifes
 
 func applyInstallManifests(ctx context.Context, manifestPath string, components []string) error {
 	kubectlArgs := []string{"apply", "-f", manifestPath}
-	if _, err := utils.execKubectlCommand(ctx, ModeOS, kubectlArgs...); err != nil {
+	if _, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, kubectlArgs...); err != nil {
 		return fmt.Errorf("install failed")
 	}
 
 	for _, deployment := range components {
 		kubectlArgs = []string{"-n", namespace, "rollout", "status", "deployment", deployment, "--timeout", timeout.String()}
-		if _, err := utils.execKubectlCommand(ctx, ModeOS, kubectlArgs...); err != nil {
+		if _, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, kubectlArgs...); err != nil {
 			return fmt.Errorf("install failed")
 		}
 	}
@@ -194,7 +187,7 @@ func generateSyncManifests(url, branch, name, namespace, targetPath, tmpDir stri
 		return err
 	}
 
-	if err := utils.writeFile(string(gitData), filepath.Join(tmpDir, targetPath, namespace, bootstrapSourceManifest)); err != nil {
+	if err := utils.WriteFile(string(gitData), filepath.Join(tmpDir, targetPath, namespace, bootstrapSourceManifest)); err != nil {
 		return err
 	}
 
@@ -227,11 +220,11 @@ func generateSyncManifests(url, branch, name, namespace, targetPath, tmpDir stri
 		return err
 	}
 
-	if err := utils.writeFile(string(ksData), filepath.Join(tmpDir, targetPath, namespace, bootstrapKustomizationManifest)); err != nil {
+	if err := utils.WriteFile(string(ksData), filepath.Join(tmpDir, targetPath, namespace, bootstrapKustomizationManifest)); err != nil {
 		return err
 	}
 
-	if err := utils.generateKustomizationYaml(filepath.Join(tmpDir, targetPath, namespace)); err != nil {
+	if err := utils.GenerateKustomizationYaml(filepath.Join(tmpDir, targetPath, namespace)); err != nil {
 		return err
 	}
 
@@ -240,7 +233,7 @@ func generateSyncManifests(url, branch, name, namespace, targetPath, tmpDir stri
 
 func applySyncManifests(ctx context.Context, kubeClient client.Client, name, namespace, targetPath, tmpDir string) error {
 	kubectlArgs := []string{"apply", "-k", filepath.Join(tmpDir, targetPath, namespace)}
-	if _, err := utils.execKubectlCommand(ctx, ModeStderrOS, kubectlArgs...); err != nil {
+	if _, err := utils.ExecKubectlCommand(ctx, utils.ModeStderrOS, kubectlArgs...); err != nil {
 		return err
 	}
 
diff --git a/cmd/gotk/bootstrap_github.go b/cmd/gotk/bootstrap_github.go
index eca646ea0a7028ccdb33829b205f3688f76c2b15..c111269e95190c760fb0b6a20adcab8a460c359f 100644
--- a/cmd/gotk/bootstrap_github.go
+++ b/cmd/gotk/bootstrap_github.go
@@ -28,6 +28,7 @@ import (
 	"github.com/spf13/cobra"
 
 	"github.com/fluxcd/pkg/git"
+	"github.com/fluxcd/toolkit/internal/utils"
 )
 
 var bootstrapGitHubCmd = &cobra.Command{
@@ -183,7 +184,7 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
 		logger.Successf("components are up to date")
 	}
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/bootstrap_gitlab.go b/cmd/gotk/bootstrap_gitlab.go
index 3426b7f4e1fa052566214bf18630d80855a2127f..35893f47387d99113520e3fd80f3483a089b551f 100644
--- a/cmd/gotk/bootstrap_gitlab.go
+++ b/cmd/gotk/bootstrap_gitlab.go
@@ -30,6 +30,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
 	"github.com/fluxcd/pkg/git"
+	"github.com/fluxcd/toolkit/internal/utils"
 )
 
 var bootstrapGitLabCmd = &cobra.Command{
@@ -112,7 +113,7 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
 		IsPersonal: glPersonal,
 	}
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/check.go b/cmd/gotk/check.go
index 64b86b5cbe406bf393a5500825eaf2479468dc40..9ec51398ebe96b7a3fbe47642b115e63254218b9 100644
--- a/cmd/gotk/check.go
+++ b/cmd/gotk/check.go
@@ -24,6 +24,7 @@ import (
 	"strings"
 
 	"github.com/blang/semver/v4"
+	"github.com/fluxcd/toolkit/internal/utils"
 	"github.com/spf13/cobra"
 	apimachineryversion "k8s.io/apimachinery/pkg/version"
 	"k8s.io/client-go/kubernetes"
@@ -103,7 +104,7 @@ func kubectlCheck(ctx context.Context, version string) bool {
 	}
 
 	kubectlArgs := []string{"version", "--client", "--output", "json"}
-	output, err := utils.execKubectlCommand(ctx, ModeCapture, kubectlArgs...)
+	output, err := utils.ExecKubectlCommand(ctx, utils.ModeCapture, kubectlArgs...)
 	if err != nil {
 		logger.Failuref("kubectl version can't be determined")
 		return false
@@ -173,7 +174,7 @@ func componentsCheck() bool {
 	ok := true
 	for _, deployment := range checkComponents {
 		kubectlArgs := []string{"-n", namespace, "rollout", "status", "deployment", deployment, "--timeout", timeout.String()}
-		if output, err := utils.execKubectlCommand(ctx, ModeCapture, kubectlArgs...); err != nil {
+		if output, err := utils.ExecKubectlCommand(ctx, utils.ModeCapture, kubectlArgs...); err != nil {
 			logger.Failuref("%s: %s", deployment, strings.TrimSuffix(output, "\n"))
 			ok = false
 		} else {
diff --git a/cmd/gotk/create_alert.go b/cmd/gotk/create_alert.go
index 9a943b210e6eefc08ffef3749c32fa6e1f589469..cae14bc71b0bce17a2d95c2a69ebc13b00553302 100644
--- a/cmd/gotk/create_alert.go
+++ b/cmd/gotk/create_alert.go
@@ -19,7 +19,9 @@ package main
 import (
 	"context"
 	"fmt"
+
 	"github.com/fluxcd/pkg/apis/meta"
+	"github.com/fluxcd/toolkit/internal/utils"
 
 	"github.com/spf13/cobra"
 	corev1 "k8s.io/api/core/v1"
@@ -71,7 +73,7 @@ func createAlertCmdRun(cmd *cobra.Command, args []string) error {
 
 	eventSources := []notificationv1.CrossNamespaceObjectReference{}
 	for _, eventSource := range aEventSources {
-		kind, name := utils.parseObjectKindName(eventSource)
+		kind, name := utils.ParseObjectKindName(eventSource)
 		if kind == "" {
 			return fmt.Errorf("invalid event source '%s', must be in format <kind>/<name>", eventSource)
 		}
@@ -118,7 +120,7 @@ func createAlertCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/create_alertprovider.go b/cmd/gotk/create_alertprovider.go
index 9c28782ea6e931f12d32be85a2baba9289472913..f1ab8c6a126ce2824449d09c643a3f86b32fb4e9 100644
--- a/cmd/gotk/create_alertprovider.go
+++ b/cmd/gotk/create_alertprovider.go
@@ -30,6 +30,7 @@ import (
 
 	notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
 	"github.com/fluxcd/pkg/apis/meta"
+	"github.com/fluxcd/toolkit/internal/utils"
 )
 
 var createAlertProviderCmd = &cobra.Command{
@@ -115,7 +116,7 @@ func createAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/create_helmrelease.go b/cmd/gotk/create_helmrelease.go
index 8d77ad312a011e1c08a7f9b468ea4ab32e110425..9776f751e2c88502244542d2695257f65afb0dd2 100644
--- a/cmd/gotk/create_helmrelease.go
+++ b/cmd/gotk/create_helmrelease.go
@@ -22,6 +22,7 @@ import (
 	"io/ioutil"
 
 	"github.com/fluxcd/pkg/apis/meta"
+	"github.com/fluxcd/toolkit/internal/utils"
 
 	"github.com/spf13/cobra"
 	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
@@ -117,11 +118,11 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
 	if hrSource == "" {
 		return fmt.Errorf("source is required")
 	}
-	sourceKind, sourceName := utils.parseObjectKindName(hrSource)
+	sourceKind, sourceName := utils.ParseObjectKindName(hrSource)
 	if sourceKind == "" {
 		return fmt.Errorf("invalid source '%s', must be in format <kind>/<name>", hrSource)
 	}
-	if !utils.containsItemString(supportedHelmChartSourceKinds, sourceKind) {
+	if !utils.ContainsItemString(supportedHelmChartSourceKinds, sourceKind) {
 		return fmt.Errorf("source kind %s is not supported, can be %v",
 			sourceKind, supportedHelmChartSourceKinds)
 	}
@@ -146,7 +147,7 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
 		},
 		Spec: helmv2.HelmReleaseSpec{
 			ReleaseName: hrName,
-			DependsOn:   utils.makeDependsOn(hrDependsOn),
+			DependsOn:   utils.MakeDependsOn(hrDependsOn),
 			Interval: metav1.Duration{
 				Duration: interval,
 			},
@@ -186,7 +187,7 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/create_kustomization.go b/cmd/gotk/create_kustomization.go
index d3fdd0c6be30606094765cbedc82a1a98578aa96..26f6315d3322b2eb41033c8d245e199e5a9500f4 100644
--- a/cmd/gotk/create_kustomization.go
+++ b/cmd/gotk/create_kustomization.go
@@ -34,6 +34,7 @@ import (
 	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
 	"github.com/fluxcd/pkg/apis/meta"
 	sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
+	"github.com/fluxcd/toolkit/internal/utils"
 )
 
 var createKsCmd = &cobra.Command{
@@ -110,11 +111,11 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
 		return fmt.Errorf("source is required")
 	}
 
-	sourceKind, sourceName := utils.parseObjectKindName(ksSource)
+	sourceKind, sourceName := utils.ParseObjectKindName(ksSource)
 	if sourceKind == "" {
 		sourceKind = sourcev1.GitRepositoryKind
 	}
-	if !utils.containsItemString(supportedKustomizationSourceKinds, sourceKind) {
+	if !utils.ContainsItemString(supportedKustomizationSourceKinds, sourceKind) {
 		return fmt.Errorf("source kind %s is not supported, can be %v",
 			sourceKind, supportedKustomizationSourceKinds)
 	}
@@ -142,7 +143,7 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
 			Labels:    ksLabels,
 		},
 		Spec: kustomizev1.KustomizationSpec{
-			DependsOn: utils.makeDependsOn(ksDependsOn),
+			DependsOn: utils.MakeDependsOn(ksDependsOn),
 			Interval: metav1.Duration{
 				Duration: interval,
 			},
@@ -206,7 +207,7 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
 	}
 
 	if ksDecryptionProvider != "" {
-		if !utils.containsItemString(supportedDecryptionProviders, ksDecryptionProvider) {
+		if !utils.ContainsItemString(supportedDecryptionProviders, ksDecryptionProvider) {
 			return fmt.Errorf("decryption provider %s is not supported, can be %v",
 				ksDecryptionProvider, supportedDecryptionProviders)
 		}
@@ -227,7 +228,7 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/create_receiver.go b/cmd/gotk/create_receiver.go
index 08595bfe0206bf9f8b78f256e753f55cef152c2d..697860ea87997a60d4af61228f719400c4fbf7f5 100644
--- a/cmd/gotk/create_receiver.go
+++ b/cmd/gotk/create_receiver.go
@@ -30,6 +30,7 @@ import (
 
 	notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
 	"github.com/fluxcd/pkg/apis/meta"
+	"github.com/fluxcd/toolkit/internal/utils"
 )
 
 var createReceiverCmd = &cobra.Command{
@@ -79,7 +80,7 @@ func createReceiverCmdRun(cmd *cobra.Command, args []string) error {
 
 	resources := []notificationv1.CrossNamespaceObjectReference{}
 	for _, resource := range rcvResources {
-		kind, name := utils.parseObjectKindName(resource)
+		kind, name := utils.ParseObjectKindName(resource)
 		if kind == "" {
 			return fmt.Errorf("invalid event source '%s', must be in format <kind>/<name>", resource)
 		}
@@ -127,7 +128,7 @@ func createReceiverCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/create_source_bucket.go b/cmd/gotk/create_source_bucket.go
index 32a06ea100902ee38bc7e4bd8cfec651724e45fd..7a467e876e25410aa313f2267d8e727452401303 100644
--- a/cmd/gotk/create_source_bucket.go
+++ b/cmd/gotk/create_source_bucket.go
@@ -31,6 +31,7 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
+	"github.com/fluxcd/toolkit/internal/utils"
 )
 
 var createSourceBucketCmd = &cobra.Command{
@@ -88,7 +89,7 @@ func createSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
 	name := args[0]
 	secretName := fmt.Sprintf("bucket-%s", name)
 
-	if !utils.containsItemString(supportedSourceBucketProviders, sourceBucketProvider) {
+	if !utils.ContainsItemString(supportedSourceBucketProviders, sourceBucketProvider) {
 		return fmt.Errorf("Bucket provider %s is not supported, can be %v",
 			sourceBucketProvider, supportedSourceBucketProviders)
 	}
@@ -137,7 +138,7 @@ func createSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/create_source_git.go b/cmd/gotk/create_source_git.go
index ad78484134345632e14832a7c979814c25df55eb..5330b5ad00484cdcf4c0a52dd6883b7877e8072e 100644
--- a/cmd/gotk/create_source_git.go
+++ b/cmd/gotk/create_source_git.go
@@ -20,12 +20,15 @@ import (
 	"context"
 	"crypto/elliptic"
 	"fmt"
-	"github.com/fluxcd/pkg/apis/meta"
 	"io/ioutil"
 	"net/url"
 	"os"
 	"time"
 
+	"github.com/fluxcd/pkg/apis/meta"
+	"github.com/fluxcd/toolkit/internal/flags"
+	"github.com/fluxcd/toolkit/internal/utils"
+
 	sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
 	"github.com/manifoldco/promptui"
 	"github.com/spf13/cobra"
@@ -90,9 +93,9 @@ var (
 	sourceGitSemver       string
 	sourceGitUsername     string
 	sourceGitPassword     string
-	sourceGitKeyAlgorithm PublicKeyAlgorithm = "rsa"
-	sourceGitRSABits      RSAKeyBits         = 2048
-	sourceGitECDSACurve                      = ECDSACurve{elliptic.P384()}
+	sourceGitKeyAlgorithm flags.PublicKeyAlgorithm = "rsa"
+	sourceGitRSABits      flags.RSAKeyBits         = 2048
+	sourceGitECDSACurve                            = flags.ECDSACurve{Curve: elliptic.P384()}
 )
 
 func init() {
@@ -165,7 +168,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/create_source_helm.go b/cmd/gotk/create_source_helm.go
index bc6c9a081f28cd1fa3f8d4b6d5c71cf7d070512e..e8e61f416b2a7b2cc40090b5381b4c3e9fb13d2b 100644
--- a/cmd/gotk/create_source_helm.go
+++ b/cmd/gotk/create_source_helm.go
@@ -32,6 +32,7 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
+	"github.com/fluxcd/toolkit/internal/utils"
 )
 
 var createSourceHelmCmd = &cobra.Command{
@@ -128,7 +129,7 @@ func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/create_tenant.go b/cmd/gotk/create_tenant.go
index 8119c7fa9ba6f6f0b167c899f008eea9c172fd83..8abf61e4dd08f3308f304dffe1cfccc389abd1bb 100644
--- a/cmd/gotk/create_tenant.go
+++ b/cmd/gotk/create_tenant.go
@@ -21,6 +21,7 @@ import (
 	"context"
 	"fmt"
 
+	"github.com/fluxcd/toolkit/internal/utils"
 	"github.com/spf13/cobra"
 	corev1 "k8s.io/api/core/v1"
 	rbacv1 "k8s.io/api/rbac/v1"
@@ -144,7 +145,7 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/delete_alert.go b/cmd/gotk/delete_alert.go
index b918f2b7ce2767985de5ca1e2df4b8d6e90d7494..242969d5d9b182a209110f64bed14b312b05521e 100644
--- a/cmd/gotk/delete_alert.go
+++ b/cmd/gotk/delete_alert.go
@@ -25,6 +25,7 @@ import (
 	"k8s.io/apimachinery/pkg/types"
 
 	notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
+	"github.com/fluxcd/toolkit/internal/utils"
 )
 
 var deleteAlertCmd = &cobra.Command{
@@ -50,7 +51,7 @@ func deleteAlertCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/delete_alertprovider.go b/cmd/gotk/delete_alertprovider.go
index 1b641529c5a19d115d9593ff66bc184f5cc3f9cf..9cd7e15398c74ce205d51384c362446b861102d9 100644
--- a/cmd/gotk/delete_alertprovider.go
+++ b/cmd/gotk/delete_alertprovider.go
@@ -25,6 +25,7 @@ import (
 	"k8s.io/apimachinery/pkg/types"
 
 	notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
+	"github.com/fluxcd/toolkit/internal/utils"
 )
 
 var deleteAlertProviderCmd = &cobra.Command{
@@ -50,7 +51,7 @@ func deleteAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/delete_helmrelease.go b/cmd/gotk/delete_helmrelease.go
index 86ec663c1fdf9c6cd76d078815255cf4276cd3ca..efc7fe87bccf540e28d29faf2fb3335098aca5d9 100644
--- a/cmd/gotk/delete_helmrelease.go
+++ b/cmd/gotk/delete_helmrelease.go
@@ -25,6 +25,7 @@ import (
 	"k8s.io/apimachinery/pkg/types"
 
 	helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
+	"github.com/fluxcd/toolkit/internal/utils"
 )
 
 var deleteHelmReleaseCmd = &cobra.Command{
@@ -51,7 +52,7 @@ func deleteHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/delete_kustomization.go b/cmd/gotk/delete_kustomization.go
index 743827a2b28e4cb5b72e486b9cba72460d1f773a..07b0acaaf3de2ce6439692c35919a353ba778b65 100644
--- a/cmd/gotk/delete_kustomization.go
+++ b/cmd/gotk/delete_kustomization.go
@@ -21,6 +21,7 @@ import (
 	"fmt"
 
 	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
+	"github.com/fluxcd/toolkit/internal/utils"
 	"github.com/manifoldco/promptui"
 	"github.com/spf13/cobra"
 	"k8s.io/apimachinery/pkg/types"
@@ -50,7 +51,7 @@ func deleteKsCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/delete_receiver.go b/cmd/gotk/delete_receiver.go
index 253308e01188da2e744d3ec1245533f2497cb054..d4c0bd1d273d20c23cd2ba95aab3b2fe7b46f287 100644
--- a/cmd/gotk/delete_receiver.go
+++ b/cmd/gotk/delete_receiver.go
@@ -25,6 +25,7 @@ import (
 	"k8s.io/apimachinery/pkg/types"
 
 	notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
+	"github.com/fluxcd/toolkit/internal/utils"
 )
 
 var deleteReceiverCmd = &cobra.Command{
@@ -50,7 +51,7 @@ func deleteReceiverCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/delete_source_bucket.go b/cmd/gotk/delete_source_bucket.go
index 7614e4835d60ed7e5180d1a0bcdedd6fc5fffe50..a2c2fd29974cb9e9b8b7df0b7269b547761546e5 100644
--- a/cmd/gotk/delete_source_bucket.go
+++ b/cmd/gotk/delete_source_bucket.go
@@ -21,6 +21,7 @@ import (
 	"fmt"
 
 	sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
+	"github.com/fluxcd/toolkit/internal/utils"
 	"github.com/manifoldco/promptui"
 	"github.com/spf13/cobra"
 	"k8s.io/apimachinery/pkg/types"
@@ -49,7 +50,7 @@ func deleteSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/delete_source_git.go b/cmd/gotk/delete_source_git.go
index 73000fbf8936ac9259a1b547240243113d520ddd..7d393bb919d72b1ffd9f4f7feda555ca29dca423 100644
--- a/cmd/gotk/delete_source_git.go
+++ b/cmd/gotk/delete_source_git.go
@@ -21,6 +21,7 @@ import (
 	"fmt"
 
 	sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
+	"github.com/fluxcd/toolkit/internal/utils"
 	"github.com/manifoldco/promptui"
 	"github.com/spf13/cobra"
 	"k8s.io/apimachinery/pkg/types"
@@ -49,7 +50,7 @@ func deleteSourceGitCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/delete_source_helm.go b/cmd/gotk/delete_source_helm.go
index 5a9427cacb1c094aebe48c07e158d10223d0e7d3..058876967108dc87fa8bb461774994ad2bf831a0 100644
--- a/cmd/gotk/delete_source_helm.go
+++ b/cmd/gotk/delete_source_helm.go
@@ -21,6 +21,7 @@ import (
 	"fmt"
 
 	sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
+	"github.com/fluxcd/toolkit/internal/utils"
 	"github.com/manifoldco/promptui"
 	"github.com/spf13/cobra"
 	"k8s.io/apimachinery/pkg/types"
@@ -49,7 +50,7 @@ func deleteSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/export_alert.go b/cmd/gotk/export_alert.go
index e5a69f07c4b05f492aef254b7a93b9966ac20317..c837473f819845948f753016a3e65bdcfa9c062b 100644
--- a/cmd/gotk/export_alert.go
+++ b/cmd/gotk/export_alert.go
@@ -27,6 +27,7 @@ import (
 	"sigs.k8s.io/yaml"
 
 	notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
+	"github.com/fluxcd/toolkit/internal/utils"
 )
 
 var exportAlertCmd = &cobra.Command{
@@ -54,7 +55,7 @@ func exportAlertCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/export_alertprovider.go b/cmd/gotk/export_alertprovider.go
index 88a61182673627b8213840cf81ec45424e8f8a5b..3d212d63faabfba92cb4a4cdc10d17d1c7512e1a 100644
--- a/cmd/gotk/export_alertprovider.go
+++ b/cmd/gotk/export_alertprovider.go
@@ -27,6 +27,7 @@ import (
 	"sigs.k8s.io/yaml"
 
 	notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
+	"github.com/fluxcd/toolkit/internal/utils"
 )
 
 var exportAlertProviderCmd = &cobra.Command{
@@ -54,7 +55,7 @@ func exportAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/export_helmrelease.go b/cmd/gotk/export_helmrelease.go
index 8911c52e407cea8717f29cacde813f59a52c536e..54bce9e3598cf992bec627ce121886ce6ed43cc4 100644
--- a/cmd/gotk/export_helmrelease.go
+++ b/cmd/gotk/export_helmrelease.go
@@ -27,6 +27,7 @@ import (
 	"sigs.k8s.io/yaml"
 
 	helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
+	"github.com/fluxcd/toolkit/internal/utils"
 )
 
 var exportHelmReleaseCmd = &cobra.Command{
@@ -55,7 +56,7 @@ func exportHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/export_kustomization.go b/cmd/gotk/export_kustomization.go
index b47a70763c6814b841e2bda6c393a21b117a5734..a059e3a9e0eee72b7400abbc40223acb04543b32 100644
--- a/cmd/gotk/export_kustomization.go
+++ b/cmd/gotk/export_kustomization.go
@@ -27,6 +27,7 @@ import (
 	"sigs.k8s.io/yaml"
 
 	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
+	"github.com/fluxcd/toolkit/internal/utils"
 )
 
 var exportKsCmd = &cobra.Command{
@@ -55,7 +56,7 @@ func exportKsCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/export_receiver.go b/cmd/gotk/export_receiver.go
index 1acfb164e247c90fa5c6e9cfcf0a576ca6b8ef96..e8e35e013b1deb17cd20ea2e3ee5dda3ae68ea62 100644
--- a/cmd/gotk/export_receiver.go
+++ b/cmd/gotk/export_receiver.go
@@ -27,6 +27,7 @@ import (
 	"sigs.k8s.io/yaml"
 
 	notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
+	"github.com/fluxcd/toolkit/internal/utils"
 )
 
 var exportReceiverCmd = &cobra.Command{
@@ -54,7 +55,7 @@ func exportReceiverCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/export_source_bucket.go b/cmd/gotk/export_source_bucket.go
index af9f78d0503c0fccfdf085d70f15af69d7bb566b..3350cdb7dc0b9c7454b9fda4aa837999f8ca1f8d 100644
--- a/cmd/gotk/export_source_bucket.go
+++ b/cmd/gotk/export_source_bucket.go
@@ -28,6 +28,7 @@ import (
 	"sigs.k8s.io/yaml"
 
 	sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
+	"github.com/fluxcd/toolkit/internal/utils"
 )
 
 var exportSourceBucketCmd = &cobra.Command{
@@ -55,7 +56,7 @@ func exportSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/export_source_git.go b/cmd/gotk/export_source_git.go
index 1aeff810d74a31e790a4ae6829fe701683f4b006..2cf023a6141496dcf5ab28baa778347b98dc2eb1 100644
--- a/cmd/gotk/export_source_git.go
+++ b/cmd/gotk/export_source_git.go
@@ -28,6 +28,7 @@ import (
 	"sigs.k8s.io/yaml"
 
 	sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
+	"github.com/fluxcd/toolkit/internal/utils"
 )
 
 var exportSourceGitCmd = &cobra.Command{
@@ -55,7 +56,7 @@ func exportSourceGitCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/export_source_helm.go b/cmd/gotk/export_source_helm.go
index 53df16e4b48d84aa352b3357f0250e8207c4dcaf..1b313942de414b834ba1648b763aff7d2aefcf51 100644
--- a/cmd/gotk/export_source_helm.go
+++ b/cmd/gotk/export_source_helm.go
@@ -28,6 +28,7 @@ import (
 	"sigs.k8s.io/yaml"
 
 	sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
+	"github.com/fluxcd/toolkit/internal/utils"
 )
 
 var exportSourceHelmCmd = &cobra.Command{
@@ -55,7 +56,7 @@ func exportSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/get_alert.go b/cmd/gotk/get_alert.go
index c30b322613bde51950399fba8f5634a64f9f3b4d..20c188de2bb90afa7ccacebb4b3ff46b963a09fa 100644
--- a/cmd/gotk/get_alert.go
+++ b/cmd/gotk/get_alert.go
@@ -28,6 +28,7 @@ import (
 
 	notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
 	"github.com/fluxcd/pkg/apis/meta"
+	"github.com/fluxcd/toolkit/internal/utils"
 )
 
 var getAlertCmd = &cobra.Command{
@@ -48,7 +49,7 @@ func getAlertCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
@@ -97,6 +98,6 @@ func getAlertCmdRun(cmd *cobra.Command, args []string) error {
 		}
 		rows = append(rows, row)
 	}
-	utils.printTable(os.Stdout, header, rows)
+	utils.PrintTable(os.Stdout, header, rows)
 	return nil
 }
diff --git a/cmd/gotk/get_alertprovider.go b/cmd/gotk/get_alertprovider.go
index a9421d81093ad65ccf45eadec1afafef8598c141..6871e4454e66229bdff667c70f839756ea6e5dda 100644
--- a/cmd/gotk/get_alertprovider.go
+++ b/cmd/gotk/get_alertprovider.go
@@ -26,6 +26,7 @@ import (
 
 	notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
 	"github.com/fluxcd/pkg/apis/meta"
+	"github.com/fluxcd/toolkit/internal/utils"
 )
 
 var getAlertProviderCmd = &cobra.Command{
@@ -46,7 +47,7 @@ func getAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
@@ -91,6 +92,6 @@ func getAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
 		}
 		rows = append(rows, row)
 	}
-	utils.printTable(os.Stdout, header, rows)
+	utils.PrintTable(os.Stdout, header, rows)
 	return nil
 }
diff --git a/cmd/gotk/get_helmrelease.go b/cmd/gotk/get_helmrelease.go
index d810e598002b10ea94972680780a307a6eccc540..b838f57b039d16fc8da1f6c8d5b05c1f7eef19e3 100644
--- a/cmd/gotk/get_helmrelease.go
+++ b/cmd/gotk/get_helmrelease.go
@@ -23,6 +23,7 @@ import (
 	"strings"
 
 	"github.com/fluxcd/pkg/apis/meta"
+	"github.com/fluxcd/toolkit/internal/utils"
 
 	"github.com/spf13/cobra"
 	corev1 "k8s.io/api/core/v1"
@@ -50,7 +51,7 @@ func getHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
@@ -99,6 +100,6 @@ func getHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
 		}
 		rows = append(rows, row)
 	}
-	utils.printTable(os.Stdout, header, rows)
+	utils.PrintTable(os.Stdout, header, rows)
 	return nil
 }
diff --git a/cmd/gotk/get_kustomization.go b/cmd/gotk/get_kustomization.go
index ac8374cdcee1e6a56edfc92a2b42875eb0b9f567..9bee84c14e4c5ffddf37a5edf6a5b6756f2ace9b 100644
--- a/cmd/gotk/get_kustomization.go
+++ b/cmd/gotk/get_kustomization.go
@@ -23,6 +23,7 @@ import (
 	"strings"
 
 	"github.com/fluxcd/pkg/apis/meta"
+	"github.com/fluxcd/toolkit/internal/utils"
 
 	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
 	"github.com/spf13/cobra"
@@ -49,7 +50,7 @@ func getKsCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
@@ -98,6 +99,6 @@ func getKsCmdRun(cmd *cobra.Command, args []string) error {
 		}
 		rows = append(rows, row)
 	}
-	utils.printTable(os.Stdout, header, rows)
+	utils.PrintTable(os.Stdout, header, rows)
 	return nil
 }
diff --git a/cmd/gotk/get_receiver.go b/cmd/gotk/get_receiver.go
index c41bdce0945e9e0d5f2539260a1ceed2087ffba1..8f53d96c65e0df1a2b5c7e66efa69b222acdeeca 100644
--- a/cmd/gotk/get_receiver.go
+++ b/cmd/gotk/get_receiver.go
@@ -28,6 +28,7 @@ import (
 
 	notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
 	"github.com/fluxcd/pkg/apis/meta"
+	"github.com/fluxcd/toolkit/internal/utils"
 )
 
 var getReceiverCmd = &cobra.Command{
@@ -48,7 +49,7 @@ func getReceiverCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
@@ -92,6 +93,6 @@ func getReceiverCmdRun(cmd *cobra.Command, args []string) error {
 		}
 		rows = append(rows, row)
 	}
-	utils.printTable(os.Stdout, header, rows)
+	utils.PrintTable(os.Stdout, header, rows)
 	return nil
 }
diff --git a/cmd/gotk/get_source_bucket.go b/cmd/gotk/get_source_bucket.go
index e4323285edc84b404d08c8f57595834f249bbae6..76eb7dde91cbebc912707f8d28a16d6d211a37bf 100644
--- a/cmd/gotk/get_source_bucket.go
+++ b/cmd/gotk/get_source_bucket.go
@@ -21,6 +21,7 @@ import (
 	"os"
 
 	"github.com/fluxcd/pkg/apis/meta"
+	"github.com/fluxcd/toolkit/internal/utils"
 
 	sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
 	"github.com/spf13/cobra"
@@ -46,7 +47,7 @@ func getSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
@@ -97,6 +98,6 @@ func getSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
 		}
 		rows = append(rows, row)
 	}
-	utils.printTable(os.Stdout, header, rows)
+	utils.PrintTable(os.Stdout, header, rows)
 	return nil
 }
diff --git a/cmd/gotk/get_source_git.go b/cmd/gotk/get_source_git.go
index 4afe14fbc6ae8f7fa582e711acabcb1eb2f15ef5..f32a7c6207631646cbd04cd9188b83e433bc90b6 100644
--- a/cmd/gotk/get_source_git.go
+++ b/cmd/gotk/get_source_git.go
@@ -21,6 +21,7 @@ import (
 	"os"
 
 	"github.com/fluxcd/pkg/apis/meta"
+	"github.com/fluxcd/toolkit/internal/utils"
 
 	sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
 	"github.com/spf13/cobra"
@@ -46,7 +47,7 @@ func getSourceGitCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
@@ -97,6 +98,6 @@ func getSourceGitCmdRun(cmd *cobra.Command, args []string) error {
 		}
 		rows = append(rows, row)
 	}
-	utils.printTable(os.Stdout, header, rows)
+	utils.PrintTable(os.Stdout, header, rows)
 	return nil
 }
diff --git a/cmd/gotk/get_source_helm.go b/cmd/gotk/get_source_helm.go
index 10e3b2b19359d02027c8c5912883b76e706247c5..b3c67fd40f6e1d5e220579704622468603c6ce1f 100644
--- a/cmd/gotk/get_source_helm.go
+++ b/cmd/gotk/get_source_helm.go
@@ -21,6 +21,7 @@ import (
 	"os"
 
 	"github.com/fluxcd/pkg/apis/meta"
+	"github.com/fluxcd/toolkit/internal/utils"
 
 	sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
 	"github.com/spf13/cobra"
@@ -46,7 +47,7 @@ func getSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
@@ -97,6 +98,6 @@ func getSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
 		}
 		rows = append(rows, row)
 	}
-	utils.printTable(os.Stdout, header, rows)
+	utils.PrintTable(os.Stdout, header, rows)
 	return nil
 }
diff --git a/cmd/gotk/install.go b/cmd/gotk/install.go
index 72a87be5e4eceb88128d84809792acc54f507cb0..fdd6426f56539f7b3b7dd630497d737edb5789e1 100644
--- a/cmd/gotk/install.go
+++ b/cmd/gotk/install.go
@@ -26,6 +26,8 @@ import (
 
 	"github.com/spf13/cobra"
 
+	"github.com/fluxcd/toolkit/internal/flags"
+	"github.com/fluxcd/toolkit/internal/utils"
 	"github.com/fluxcd/toolkit/pkg/install"
 )
 
@@ -57,10 +59,10 @@ var (
 	installComponents         []string
 	installRegistry           string
 	installImagePullSecret    string
-	installArch               string
+	installArch               flags.Arch = "amd64"
 	installWatchAllNamespaces bool
 	installNetworkPolicy      bool
-	installLogLevel           string
+	installLogLevel           flags.LogLevel = "info"
 )
 
 func init() {
@@ -78,25 +80,16 @@ func init() {
 		"container registry where the toolkit images are published")
 	installCmd.Flags().StringVar(&installImagePullSecret, "image-pull-secret", "",
 		"Kubernetes secret name used for pulling the toolkit images from a private registry")
-	installCmd.Flags().StringVar(&installArch, "arch", "amd64",
-		"arch can be amd64 or arm64")
+	installCmd.Flags().Var(&installArch, "arch", installArch.Description())
 	installCmd.Flags().BoolVar(&installWatchAllNamespaces, "watch-all-namespaces", true,
 		"watch for custom resources in all namespaces, if set to false it will only watch the namespace where the toolkit is installed")
-	installCmd.Flags().StringVar(&installLogLevel, "log-level", "info", "set the controllers log level")
+	installCmd.Flags().Var(&installLogLevel, "log-level", installLogLevel.Description())
 	installCmd.Flags().BoolVar(&installNetworkPolicy, "network-policy", true,
 		"deny ingress access to the toolkit controllers from other namespaces using network policies")
 	rootCmd.AddCommand(installCmd)
 }
 
 func installCmdRun(cmd *cobra.Command, args []string) error {
-	if !utils.containsItemString(supportedArch, installArch) {
-		return fmt.Errorf("arch %s is not supported, can be %v", installArch, supportedArch)
-	}
-
-	if !utils.containsItemString(supportedLogLevels, installLogLevel) {
-		return fmt.Errorf("log level %s is not supported, can be %v", bootstrapLogLevel, installLogLevel)
-	}
-
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
@@ -117,10 +110,10 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
 		Components:             installComponents,
 		Registry:               installRegistry,
 		ImagePullSecret:        installImagePullSecret,
-		Arch:                   installArch,
+		Arch:                   installArch.String(),
 		WatchAllNamespaces:     installWatchAllNamespaces,
 		NetworkPolicy:          installNetworkPolicy,
-		LogLevel:               installLogLevel,
+		LogLevel:               installLogLevel.String(),
 		NotificationController: defaultNotification,
 		ManifestsFile:          fmt.Sprintf("%s.yaml", namespace),
 		Timeout:                timeout,
@@ -154,17 +147,17 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
 
 	logger.Successf("manifests build completed")
 	logger.Actionf("installing components in %s namespace", namespace)
-	applyOutput := ModeStderrOS
+	applyOutput := utils.ModeStderrOS
 	if verbose {
-		applyOutput = ModeOS
+		applyOutput = utils.ModeOS
 	}
 
 	kubectlArgs := []string{"apply", "-f", manifest}
 	if installDryRun {
 		args = append(args, "--dry-run=client")
-		applyOutput = ModeOS
+		applyOutput = utils.ModeOS
 	}
-	if _, err := utils.execKubectlCommand(ctx, applyOutput, kubectlArgs...); err != nil {
+	if _, err := utils.ExecKubectlCommand(ctx, applyOutput, kubectlArgs...); err != nil {
 		return fmt.Errorf("install failed")
 	}
 
@@ -178,7 +171,7 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
 	logger.Waitingf("verifying installation")
 	for _, deployment := range installComponents {
 		kubectlArgs = []string{"-n", namespace, "rollout", "status", "deployment", deployment, "--timeout", timeout.String()}
-		if _, err := utils.execKubectlCommand(ctx, applyOutput, kubectlArgs...); err != nil {
+		if _, err := utils.ExecKubectlCommand(ctx, applyOutput, kubectlArgs...); err != nil {
 			return fmt.Errorf("install failed")
 		} else {
 			logger.Successf("%s ready", deployment)
diff --git a/cmd/gotk/main.go b/cmd/gotk/main.go
index 491c31fbd99dcf2ada284e5b22a2e9b56893008a..0b305fc9af48724fb31cce5ad93f13ab73ed1840 100644
--- a/cmd/gotk/main.go
+++ b/cmd/gotk/main.go
@@ -100,18 +100,16 @@ var (
 	namespace    string
 	timeout      time.Duration
 	verbose      bool
-	utils        Utils
 	pollInterval                = 2 * time.Second
 	logger       gotklog.Logger = printLogger{}
 )
 
 var (
-	defaultComponents                 = []string{"source-controller", "kustomize-controller", "helm-controller", "notification-controller"}
-	defaultVersion                    = "latest"
-	defaultNamespace                  = "gotk-system"
-	defaultNotification               = "notification-controller"
-	supportedLogLevels                = []string{"debug", "info", "error"}
-	supportedArch                     = []string{"amd64", "arm", "arm64"}
+	defaultComponents   = []string{"source-controller", "kustomize-controller", "helm-controller", "notification-controller"}
+	defaultVersion      = "latest"
+	defaultNamespace    = "gotk-system"
+	defaultNotification = "notification-controller"
+
 	supportedDecryptionProviders      = []string{"sops"}
 	supportedKustomizationSourceKinds = []string{sourcev1.GitRepositoryKind, sourcev1.BucketKind}
 	supportedHelmChartSourceKinds     = []string{sourcev1.HelmRepositoryKind, sourcev1.GitRepositoryKind, sourcev1.BucketKind}
diff --git a/cmd/gotk/reconcile_alert.go b/cmd/gotk/reconcile_alert.go
index fc6e56db0eab2f00854946b1b582fc4dfbd568d4..4b5b75d6373de17a57204221687c9593858698cd 100644
--- a/cmd/gotk/reconcile_alert.go
+++ b/cmd/gotk/reconcile_alert.go
@@ -19,9 +19,11 @@ package main
 import (
 	"context"
 	"fmt"
-	"github.com/fluxcd/pkg/apis/meta"
 	"time"
 
+	"github.com/fluxcd/pkg/apis/meta"
+	"github.com/fluxcd/toolkit/internal/utils"
+
 	"github.com/spf13/cobra"
 	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/apimachinery/pkg/util/wait"
@@ -52,7 +54,7 @@ func reconcileAlertCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/reconcile_alertprovider.go b/cmd/gotk/reconcile_alertprovider.go
index c8f4e9efed935d7d327af0d22369827d93e5c700..b85a374f9da4529ff01b9f950f65956cead11020 100644
--- a/cmd/gotk/reconcile_alertprovider.go
+++ b/cmd/gotk/reconcile_alertprovider.go
@@ -19,9 +19,11 @@ package main
 import (
 	"context"
 	"fmt"
-	"github.com/fluxcd/pkg/apis/meta"
 	"time"
 
+	"github.com/fluxcd/pkg/apis/meta"
+	"github.com/fluxcd/toolkit/internal/utils"
+
 	"github.com/spf13/cobra"
 	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/apimachinery/pkg/util/wait"
@@ -52,7 +54,7 @@ func reconcileAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/reconcile_helmrelease.go b/cmd/gotk/reconcile_helmrelease.go
index af4273ce0ec1e5559c1e67acd31e8508965c799c..b4a8cb5ff08af3bb31fc6c913d0dfb8c2f6c2d27 100644
--- a/cmd/gotk/reconcile_helmrelease.go
+++ b/cmd/gotk/reconcile_helmrelease.go
@@ -29,6 +29,7 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	"github.com/fluxcd/pkg/apis/meta"
+	"github.com/fluxcd/toolkit/internal/utils"
 
 	helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
 	sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
@@ -68,7 +69,7 @@ func reconcileHrCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/reconcile_kustomization.go b/cmd/gotk/reconcile_kustomization.go
index ff4e5586703e52fed33b190f84891a65b1b8a9d2..81e4e9d172d942b35a9814b0f169fbbfe1b12959 100644
--- a/cmd/gotk/reconcile_kustomization.go
+++ b/cmd/gotk/reconcile_kustomization.go
@@ -26,6 +26,7 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	"github.com/fluxcd/pkg/apis/meta"
+	"github.com/fluxcd/toolkit/internal/utils"
 	"github.com/spf13/cobra"
 	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/apimachinery/pkg/util/wait"
@@ -68,7 +69,7 @@ func reconcileKsCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/reconcile_receiver.go b/cmd/gotk/reconcile_receiver.go
index 9b151ab7d5ba4705faee688f6a151036cd52d29d..3022edba6997ae6a98ae3b084a8ddcd8e3e11a3c 100644
--- a/cmd/gotk/reconcile_receiver.go
+++ b/cmd/gotk/reconcile_receiver.go
@@ -19,9 +19,11 @@ package main
 import (
 	"context"
 	"fmt"
-	"github.com/fluxcd/pkg/apis/meta"
 	"time"
 
+	"github.com/fluxcd/pkg/apis/meta"
+	"github.com/fluxcd/toolkit/internal/utils"
+
 	"github.com/spf13/cobra"
 	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/apimachinery/pkg/util/wait"
@@ -52,7 +54,7 @@ func reconcileReceiverCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/reconcile_source_bucket.go b/cmd/gotk/reconcile_source_bucket.go
index c823806f5d3b33a9fa6e043011511c391b9a8202..70adc7ec054e927f20fc81f65b435ba9f2cd4b9f 100644
--- a/cmd/gotk/reconcile_source_bucket.go
+++ b/cmd/gotk/reconcile_source_bucket.go
@@ -19,9 +19,11 @@ package main
 import (
 	"context"
 	"fmt"
-	"github.com/fluxcd/pkg/apis/meta"
 	"time"
 
+	"github.com/fluxcd/pkg/apis/meta"
+	"github.com/fluxcd/toolkit/internal/utils"
+
 	"github.com/spf13/cobra"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/types"
@@ -54,7 +56,7 @@ func reconcileSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/reconcile_source_git.go b/cmd/gotk/reconcile_source_git.go
index b586861ffb3fde0fb700f805982c48cba3a0baea..91632ab80d3f746888b13f1589088752cb87aa5d 100644
--- a/cmd/gotk/reconcile_source_git.go
+++ b/cmd/gotk/reconcile_source_git.go
@@ -19,9 +19,11 @@ package main
 import (
 	"context"
 	"fmt"
-	"github.com/fluxcd/pkg/apis/meta"
 	"time"
 
+	"github.com/fluxcd/pkg/apis/meta"
+	"github.com/fluxcd/toolkit/internal/utils"
+
 	"github.com/spf13/cobra"
 	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/apimachinery/pkg/util/wait"
@@ -52,7 +54,7 @@ func reconcileSourceGitCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/reconcile_source_helm.go b/cmd/gotk/reconcile_source_helm.go
index 3f1fe13a631963cf8bb1130817ea55276b8c94a5..ea2ed6e79f5f6de56ca3d7a0a51081d7427b74ab 100644
--- a/cmd/gotk/reconcile_source_helm.go
+++ b/cmd/gotk/reconcile_source_helm.go
@@ -19,9 +19,11 @@ package main
 import (
 	"context"
 	"fmt"
-	"github.com/fluxcd/pkg/apis/meta"
 	"time"
 
+	"github.com/fluxcd/pkg/apis/meta"
+	"github.com/fluxcd/toolkit/internal/utils"
+
 	"github.com/spf13/cobra"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/types"
@@ -54,7 +56,7 @@ func reconcileSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/resume_alert.go b/cmd/gotk/resume_alert.go
index 7624a45c76c12f3c34d2c911aae9932a19d5f83b..34f05418c8697a12a046a0751ead8f5b6947439b 100644
--- a/cmd/gotk/resume_alert.go
+++ b/cmd/gotk/resume_alert.go
@@ -19,7 +19,9 @@ package main
 import (
 	"context"
 	"fmt"
+
 	"github.com/fluxcd/pkg/apis/meta"
+	"github.com/fluxcd/toolkit/internal/utils"
 
 	"github.com/spf13/cobra"
 	corev1 "k8s.io/api/core/v1"
@@ -54,7 +56,7 @@ func resumeAlertCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/resume_helmrelease.go b/cmd/gotk/resume_helmrelease.go
index 46f9c4ba99cc4514ad266e44bd12d4fae05bc376..7a9595600d50eafdfbcfa465eb31f88c1be052ed 100644
--- a/cmd/gotk/resume_helmrelease.go
+++ b/cmd/gotk/resume_helmrelease.go
@@ -19,7 +19,9 @@ package main
 import (
 	"context"
 	"fmt"
+
 	"github.com/fluxcd/pkg/apis/meta"
+	"github.com/fluxcd/toolkit/internal/utils"
 
 	"github.com/spf13/cobra"
 	corev1 "k8s.io/api/core/v1"
@@ -55,7 +57,7 @@ func resumeHrCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/resume_kustomization.go b/cmd/gotk/resume_kustomization.go
index b683defbe4035160eb49a38d643f2735a76145cf..2ac3bc3c3325e5ea98c3030c8c9fb465015fee20 100644
--- a/cmd/gotk/resume_kustomization.go
+++ b/cmd/gotk/resume_kustomization.go
@@ -19,7 +19,9 @@ package main
 import (
 	"context"
 	"fmt"
+
 	"github.com/fluxcd/pkg/apis/meta"
+	"github.com/fluxcd/toolkit/internal/utils"
 
 	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
 	"github.com/spf13/cobra"
@@ -54,7 +56,7 @@ func resumeKsCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/resume_receiver.go b/cmd/gotk/resume_receiver.go
index 25c40daa61c1a8ca36a0e463bc612bd4249c9585..f2f4ff749c510e99fb148ac9178bf535ae89070a 100644
--- a/cmd/gotk/resume_receiver.go
+++ b/cmd/gotk/resume_receiver.go
@@ -19,7 +19,9 @@ package main
 import (
 	"context"
 	"fmt"
+
 	"github.com/fluxcd/pkg/apis/meta"
+	"github.com/fluxcd/toolkit/internal/utils"
 
 	"github.com/spf13/cobra"
 	corev1 "k8s.io/api/core/v1"
@@ -54,7 +56,7 @@ func resumeReceiverCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/suspend_alert.go b/cmd/gotk/suspend_alert.go
index 9e7a2388cbe748504c6621b45b337f60275ac3e3..cfbe03f9e34bbe752dc25d9d454e4030f7a375aa 100644
--- a/cmd/gotk/suspend_alert.go
+++ b/cmd/gotk/suspend_alert.go
@@ -24,6 +24,7 @@ import (
 	"k8s.io/apimachinery/pkg/types"
 
 	notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
+	"github.com/fluxcd/toolkit/internal/utils"
 )
 
 var suspendAlertCmd = &cobra.Command{
@@ -49,7 +50,7 @@ func suspendAlertCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/suspend_helmrelease.go b/cmd/gotk/suspend_helmrelease.go
index 0763b74dc9756378007d0e6680e4da7cced726b3..be6dedf8626634575bac8b2f6ee5443a7bb9cb55 100644
--- a/cmd/gotk/suspend_helmrelease.go
+++ b/cmd/gotk/suspend_helmrelease.go
@@ -24,6 +24,7 @@ import (
 	"k8s.io/apimachinery/pkg/types"
 
 	helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
+	"github.com/fluxcd/toolkit/internal/utils"
 )
 
 var suspendHrCmd = &cobra.Command{
@@ -50,7 +51,7 @@ func suspendHrCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/suspend_kustomization.go b/cmd/gotk/suspend_kustomization.go
index 3b0c0d9afbed713a83f136b7860edbaf09257e79..7b416fdc93fffc31bdc21d4e331887f90b33100c 100644
--- a/cmd/gotk/suspend_kustomization.go
+++ b/cmd/gotk/suspend_kustomization.go
@@ -19,7 +19,9 @@ package main
 import (
 	"context"
 	"fmt"
+
 	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
+	"github.com/fluxcd/toolkit/internal/utils"
 	"github.com/spf13/cobra"
 	"k8s.io/apimachinery/pkg/types"
 )
@@ -48,7 +50,7 @@ func suspendKsCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/suspend_receiver.go b/cmd/gotk/suspend_receiver.go
index bb9d0c0bea6c5db1011270f72a4ce32cba2978b4..893c8db3e75d05220f8cdba674aa1955ccecd4da 100644
--- a/cmd/gotk/suspend_receiver.go
+++ b/cmd/gotk/suspend_receiver.go
@@ -24,6 +24,7 @@ import (
 	"k8s.io/apimachinery/pkg/types"
 
 	notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
+	"github.com/fluxcd/toolkit/internal/utils"
 )
 
 var suspendReceiverCmd = &cobra.Command{
@@ -49,7 +50,7 @@ func suspendReceiverCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/gotk/uninstall.go b/cmd/gotk/uninstall.go
index 89e1aa9743ffab6af372c61f2988f99a19910394..789c966cd8d534fc35d8cd099624c8136c3365ea 100644
--- a/cmd/gotk/uninstall.go
+++ b/cmd/gotk/uninstall.go
@@ -27,6 +27,7 @@ import (
 	helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
 	kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
 	sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
+	"github.com/fluxcd/toolkit/internal/utils"
 )
 
 var uninstallCmd = &cobra.Command{
@@ -66,7 +67,7 @@ func uninstallCmdRun(cmd *cobra.Command, args []string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), timeout)
 	defer cancel()
 
-	kubeClient, err := utils.kubeClient(kubeconfig)
+	kubeClient, err := utils.KubeClient(kubeconfig)
 	if err != nil {
 		return err
 	}
@@ -111,7 +112,7 @@ func uninstallCmdRun(cmd *cobra.Command, args []string) error {
 			if uninstallDryRun {
 				kubectlArgs = append(kubectlArgs, dryRun)
 			}
-			if _, err := utils.execKubectlCommand(ctx, ModeOS, kubectlArgs...); err != nil {
+			if _, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, kubectlArgs...); err != nil {
 				return fmt.Errorf("uninstall failed: %w", err)
 			}
 		}
@@ -135,7 +136,7 @@ func uninstallCmdRun(cmd *cobra.Command, args []string) error {
 		if uninstallDryRun {
 			kubectlArgs = append(kubectlArgs, dryRun)
 		}
-		if _, err := utils.execKubectlCommand(ctx, ModeOS, kubectlArgs...); err != nil {
+		if _, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, kubectlArgs...); err != nil {
 			return fmt.Errorf("uninstall failed: %w", err)
 		}
 	}
diff --git a/internal/flags/arch.go b/internal/flags/arch.go
new file mode 100644
index 0000000000000000000000000000000000000000..543ef444922b318468fe30f8f668ae78c6719ac8
--- /dev/null
+++ b/internal/flags/arch.go
@@ -0,0 +1,54 @@
+/*
+Copyright 2020 The Flux CD contributors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package flags
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/fluxcd/toolkit/internal/utils"
+)
+
+var supportedArchs = []string{"amd64", "arm", "arm64"}
+
+type Arch string
+
+func (a *Arch) String() string {
+	return string(*a)
+}
+
+func (a *Arch) Set(str string) error {
+	if strings.TrimSpace(str) == "" {
+		return fmt.Errorf("no arch given, must be one of: %s",
+			strings.Join(supportedArchs, ", "))
+	}
+	if !utils.ContainsItemString(supportedArchs, str) {
+		return fmt.Errorf("unsupported arch '%s', must be one of: %s",
+			str, strings.Join(supportedArchs, ", "))
+
+	}
+	*a = Arch(str)
+	return nil
+}
+
+func (a *Arch) Type() string {
+	return "arch"
+}
+
+func (a *Arch) Description() string {
+	return fmt.Sprintf("cluster architecture, available options are: (%s)", strings.Join(supportedArchs, ", "))
+}
diff --git a/cmd/gotk/flags.go b/internal/flags/ecdsa_curve.go
similarity index 51%
rename from cmd/gotk/flags.go
rename to internal/flags/ecdsa_curve.go
index 991aa730736d2f457960165b8b311b22f32d29ba..a67e55ef780806a8099e5ebd583c0edf216e28ab 100644
--- a/cmd/gotk/flags.go
+++ b/internal/flags/ecdsa_curve.go
@@ -14,79 +14,15 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-package main
+package flags
 
 import (
 	"crypto/elliptic"
 	"fmt"
 	"sort"
-	"strconv"
 	"strings"
 )
 
-var supportedPublicKeyAlgorithms = []string{"rsa", "ecdsa", "ed25519"}
-
-type PublicKeyAlgorithm string
-
-func (a *PublicKeyAlgorithm) String() string {
-	return string(*a)
-}
-
-func (a *PublicKeyAlgorithm) Set(str string) error {
-	if strings.TrimSpace(str) == "" {
-		return fmt.Errorf("no public key algorithm given, must be one of: %s",
-			strings.Join(supportedPublicKeyAlgorithms, ", "))
-	}
-	for _, v := range supportedPublicKeyAlgorithms {
-		if str == v {
-			*a = PublicKeyAlgorithm(str)
-			return nil
-		}
-	}
-	return fmt.Errorf("unsupported public key algorithm '%s', must be one of: %s",
-		str, strings.Join(supportedPublicKeyAlgorithms, ", "))
-}
-
-func (a *PublicKeyAlgorithm) Type() string {
-	return "publicKeyAlgorithm"
-}
-
-func (a *PublicKeyAlgorithm) Description() string {
-	return fmt.Sprintf("SSH public key algorithm (%s)", strings.Join(supportedPublicKeyAlgorithms, ", "))
-}
-
-var defaultRSAKeyBits = 2048
-
-type RSAKeyBits int
-
-func (b *RSAKeyBits) String() string {
-	return strconv.Itoa(int(*b))
-}
-
-func (b *RSAKeyBits) Set(str string) error {
-	if strings.TrimSpace(str) == "" {
-		*b = RSAKeyBits(defaultRSAKeyBits)
-		return nil
-	}
-	bits, err := strconv.Atoi(str)
-	if err != nil {
-		return err
-	}
-	if bits%8 != 0 {
-		return fmt.Errorf("RSA key bit size should be a multiples of 8")
-	}
-	*b = RSAKeyBits(bits)
-	return nil
-}
-
-func (b *RSAKeyBits) Type() string {
-	return "rsaKeyBits"
-}
-
-func (b *RSAKeyBits) Description() string {
-	return "SSH RSA public key bit size (multiplies of 8)"
-}
-
 type ECDSACurve struct {
 	elliptic.Curve
 }
diff --git a/internal/flags/log_level.go b/internal/flags/log_level.go
new file mode 100644
index 0000000000000000000000000000000000000000..37d2a6eb953a15036cd4caf74e176b014905d150
--- /dev/null
+++ b/internal/flags/log_level.go
@@ -0,0 +1,54 @@
+/*
+Copyright 2020 The Flux CD contributors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package flags
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/fluxcd/toolkit/internal/utils"
+)
+
+var supportedLogLevels = []string{"debug", "info", "error"}
+
+type LogLevel string
+
+func (l *LogLevel) String() string {
+	return string(*l)
+}
+
+func (l *LogLevel) Set(str string) error {
+	if strings.TrimSpace(str) == "" {
+		return fmt.Errorf("no log level given, must be one of: %s",
+			strings.Join(supportedLogLevels, ", "))
+	}
+	if !utils.ContainsItemString(supportedLogLevels, str) {
+		return fmt.Errorf("unsupported log level '%s', must be one of: %s",
+			str, strings.Join(supportedLogLevels, ", "))
+
+	}
+	*l = LogLevel(str)
+	return nil
+}
+
+func (l *LogLevel) Type() string {
+	return "logLevel"
+}
+
+func (l *LogLevel) Description() string {
+	return fmt.Sprintf("log level, available options are: (%s)", strings.Join(supportedArchs, ", "))
+}
diff --git a/internal/flags/public_key_algorithm.go b/internal/flags/public_key_algorithm.go
new file mode 100644
index 0000000000000000000000000000000000000000..545a627b97f25b7777459d4cff03d415cd1b43d5
--- /dev/null
+++ b/internal/flags/public_key_algorithm.go
@@ -0,0 +1,53 @@
+/*
+Copyright 2020 The Flux CD contributors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package flags
+
+import (
+	"fmt"
+	"strings"
+)
+
+var supportedPublicKeyAlgorithms = []string{"rsa", "ecdsa", "ed25519"}
+
+type PublicKeyAlgorithm string
+
+func (a *PublicKeyAlgorithm) String() string {
+	return string(*a)
+}
+
+func (a *PublicKeyAlgorithm) Set(str string) error {
+	if strings.TrimSpace(str) == "" {
+		return fmt.Errorf("no public key algorithm given, must be one of: %s",
+			strings.Join(supportedPublicKeyAlgorithms, ", "))
+	}
+	for _, v := range supportedPublicKeyAlgorithms {
+		if str == v {
+			*a = PublicKeyAlgorithm(str)
+			return nil
+		}
+	}
+	return fmt.Errorf("unsupported public key algorithm '%s', must be one of: %s",
+		str, strings.Join(supportedPublicKeyAlgorithms, ", "))
+}
+
+func (a *PublicKeyAlgorithm) Type() string {
+	return "publicKeyAlgorithm"
+}
+
+func (a *PublicKeyAlgorithm) Description() string {
+	return fmt.Sprintf("SSH public key algorithm (%s)", strings.Join(supportedPublicKeyAlgorithms, ", "))
+}
diff --git a/internal/flags/rsa_key_bits.go b/internal/flags/rsa_key_bits.go
new file mode 100644
index 0000000000000000000000000000000000000000..6ba142901af92cb9187a263fcba67a6991d35ffa
--- /dev/null
+++ b/internal/flags/rsa_key_bits.go
@@ -0,0 +1,55 @@
+/*
+Copyright 2020 The Flux CD contributors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package flags
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+)
+
+var defaultRSAKeyBits = 2048
+
+type RSAKeyBits int
+
+func (b *RSAKeyBits) String() string {
+	return strconv.Itoa(int(*b))
+}
+
+func (b *RSAKeyBits) Set(str string) error {
+	if strings.TrimSpace(str) == "" {
+		*b = RSAKeyBits(defaultRSAKeyBits)
+		return nil
+	}
+	bits, err := strconv.Atoi(str)
+	if err != nil {
+		return err
+	}
+	if bits%8 != 0 {
+		return fmt.Errorf("RSA key bit size should be a multiples of 8")
+	}
+	*b = RSAKeyBits(bits)
+	return nil
+}
+
+func (b *RSAKeyBits) Type() string {
+	return "rsaKeyBits"
+}
+
+func (b *RSAKeyBits) Description() string {
+	return "SSH RSA public key bit size (multiplies of 8)"
+}
diff --git a/cmd/gotk/utils.go b/internal/utils/utils.go
similarity index 87%
rename from cmd/gotk/utils.go
rename to internal/utils/utils.go
index 45c01f3af134c32b016b60a303980df69edcc747..7b53de9cfbf701a21c056868ab6ae7bc0572880a 100644
--- a/cmd/gotk/utils.go
+++ b/internal/utils/utils.go
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-package main
+package utils
 
 import (
 	"bufio"
@@ -60,7 +60,7 @@ const (
 	ModeCapture  ExecMode = "capture.stderr|stdout"
 )
 
-func (*Utils) execKubectlCommand(ctx context.Context, mode ExecMode, args ...string) (string, error) {
+func ExecKubectlCommand(ctx context.Context, mode ExecMode, args ...string) (string, error) {
 	var stdoutBuf, stderrBuf bytes.Buffer
 
 	c := exec.CommandContext(ctx, "kubectl", args...)
@@ -94,7 +94,7 @@ func (*Utils) execKubectlCommand(ctx context.Context, mode ExecMode, args ...str
 	return "", nil
 }
 
-func (*Utils) execTemplate(obj interface{}, tmpl, filename string) error {
+func ExecTemplate(obj interface{}, tmpl, filename string) error {
 	t, err := template.New("tmpl").Parse(tmpl)
 	if err != nil {
 		return err
@@ -124,8 +124,8 @@ func (*Utils) execTemplate(obj interface{}, tmpl, filename string) error {
 	return file.Sync()
 }
 
-func (*Utils) kubeClient(kubeConfigPath string) (client.Client, error) {
-	configFiles := utils.splitKubeConfigPath(kubeConfigPath)
+func KubeClient(kubeConfigPath string) (client.Client, error) {
+	configFiles := SplitKubeConfigPath(kubeConfigPath)
 	cfg, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
 		&clientcmd.ClientConfigLoadingRules{Precedence: configFiles},
 		&clientcmd.ConfigOverrides{}).ClientConfig()
@@ -151,11 +151,11 @@ func (*Utils) kubeClient(kubeConfigPath string) (client.Client, error) {
 	return kubeClient, nil
 }
 
-// splitKubeConfigPath splits the given KUBECONFIG path based on the runtime OS
+// SplitKubeConfigPath splits the given KUBECONFIG path based on the runtime OS
 // target.
 //
 // Ref: https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/#the-kubeconfig-environment-variable
-func (*Utils) splitKubeConfigPath(path string) []string {
+func SplitKubeConfigPath(path string) []string {
 	var sep string
 	switch runtime.GOOS {
 	case "windows":
@@ -166,7 +166,7 @@ func (*Utils) splitKubeConfigPath(path string) []string {
 	return strings.Split(path, sep)
 }
 
-func (*Utils) writeFile(content, filename string) error {
+func WriteFile(content, filename string) error {
 	file, err := os.Create(filename)
 	if err != nil {
 		return err
@@ -181,7 +181,7 @@ func (*Utils) writeFile(content, filename string) error {
 	return file.Sync()
 }
 
-func (*Utils) copyFile(src, dst string) error {
+func CopyFile(src, dst string) error {
 	in, err := os.Open(src)
 	if err != nil {
 		return err
@@ -201,7 +201,7 @@ func (*Utils) copyFile(src, dst string) error {
 	return out.Close()
 }
 
-func (*Utils) containsItemString(s []string, e string) bool {
+func ContainsItemString(s []string, e string) bool {
 	for _, a := range s {
 		if a == e {
 			return true
@@ -210,7 +210,7 @@ func (*Utils) containsItemString(s []string, e string) bool {
 	return false
 }
 
-func (*Utils) parseObjectKindName(input string) (string, string) {
+func ParseObjectKindName(input string) (string, string) {
 	kind := ""
 	name := input
 	parts := strings.Split(input, "/")
@@ -221,7 +221,7 @@ func (*Utils) parseObjectKindName(input string) (string, string) {
 	return kind, name
 }
 
-func (*Utils) makeDependsOn(deps []string) []dependency.CrossNamespaceDependencyReference {
+func MakeDependsOn(deps []string) []dependency.CrossNamespaceDependencyReference {
 	refs := []dependency.CrossNamespaceDependencyReference{}
 	for _, dep := range deps {
 		parts := strings.Split(dep, "/")
@@ -241,9 +241,9 @@ func (*Utils) makeDependsOn(deps []string) []dependency.CrossNamespaceDependency
 	return refs
 }
 
-// generateKustomizationYaml is the equivalent of running
+// GenerateKustomizationYaml is the equivalent of running
 // 'kustomize create --autodetect' in the specified dir
-func (*Utils) generateKustomizationYaml(dirPath string) error {
+func GenerateKustomizationYaml(dirPath string) error {
 	fs := filesys.MakeFsOnDisk()
 	kfile := filepath.Join(dirPath, "kustomization.yaml")
 
@@ -321,7 +321,7 @@ func (*Utils) generateKustomizationYaml(dirPath string) error {
 	return nil
 }
 
-func (*Utils) printTable(writer io.Writer, header []string, rows [][]string) {
+func PrintTable(writer io.Writer, header []string, rows [][]string) {
 	table := tablewriter.NewWriter(writer)
 	table.SetHeader(header)
 	table.SetAutoWrapText(false)