diff --git a/src/client/cmdMisc/ls.go b/src/client/cmdMisc/ls.go
index ebcc84e55d0ef433de4ac18650c895e1dac2814a..e3a5e30916afe44cd0dfb6ee6cd8450dfdda19e2 100644
--- a/src/client/cmdMisc/ls.go
+++ b/src/client/cmdMisc/ls.go
@@ -14,7 +14,7 @@ func (cmd *Ls) GetName() string {
 }
 
 func (cmd *Ls) GetDesc() []string {
-	return []string{"List files in the specified dir or in the current dir if no argument is specified."}
+	return []string{"Lists files in the specified dir or in the current dir if no argument is specified."}
 }
 
 func (cmd *Ls) PrintUsage() {
@@ -24,7 +24,6 @@ func (cmd *Ls) PrintUsage() {
 	u.PrintlnErr("―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――")
 	u.PrintlnErr("USAGE: ", cmd.GetName(), " [dir]")
 	u.PrintlnErr("―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――")
-	u.PrintlnErr("List files in the specified dir or in the current dir if no argument is specified.")
 }
 
 func (cmd *Ls) Run(args []string) int {
diff --git a/src/client/cmdUser/userList.go b/src/client/cmdUser/userList.go
index 17f2648da79e17aef468a1b4e5bf3cf356235a2c..81150c91409504a8dd7e95f40f149aeb34a15df2 100644
--- a/src/client/cmdUser/userList.go
+++ b/src/client/cmdUser/userList.go
@@ -2,7 +2,6 @@ package cmdUser
 
 import (
 	"fmt"
-	"nexus-client/cmd"
 	u "nexus-client/utils"
 	"nexus-common/params"
 	libclient "nexus-libclient/user"
@@ -124,15 +123,6 @@ func (cmd *List) Run(args []string) int {
 	return 0
 }
 
-func printRegexUsage(c cmd.Command) {
-	for _, desc := range c.GetDesc() {
-		u.PrintlnErr(desc)
-	}
-	u.PrintlnErr("―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――")
-	u.PrintlnErr("USAGE: ", c.GetName(), " [regex ...]")
-	u.PrintlnErr("―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――")
-}
-
 func printRegexUsageDetails() {
 	const usage string = `Only users matching the specified regexes will be listed.
 Any number of regexes can be specified.
diff --git a/src/client/cmdUser/userSetCaps.go b/src/client/cmdUser/userSetCaps.go
index 6e3ddec91dc940783a67659e978168bac47f4517..adfa2edd05deb9aa4f71946a44f2387a7c78be20 100644
--- a/src/client/cmdUser/userSetCaps.go
+++ b/src/client/cmdUser/userSetCaps.go
@@ -106,7 +106,7 @@ func (cmd *SetCaps) Run(args []string) int {
 				continue
 			}
 
-			userCaps := &params.UserSetCaps{make(map[string]int)}
+			userCaps := &params.UserSetCaps{Caps: make(map[string]int)}
 
 			capsStr := strings.TrimSpace(columns[1])
 			if len(capsStr) > 0 {
@@ -134,7 +134,7 @@ func (cmd *SetCaps) Run(args []string) int {
 		// Argument is an email address
 		email := args[0]
 
-		userCaps := &params.UserSetCaps{make(map[string]int)}
+		userCaps := &params.UserSetCaps{Caps: make(map[string]int)}
 		for _, cap := range args[1:] {
 			userCaps.Caps[cap] = 1
 		}
diff --git a/src/client/cmdVM/helper.go b/src/client/cmdVM/helper.go
index 9259f42dccf1ef15243c9b39cb4a5e894d08ef59..27149c74892827f6289a4f3b85790bfd8e52859e 100644
--- a/src/client/cmdVM/helper.go
+++ b/src/client/cmdVM/helper.go
@@ -47,7 +47,7 @@ Regex examples:
 //	"bla" -> matches any VM name containing "bla"
 func getFilteredVMs(filteredVMsFunc GetVMs, patterns []string) ([]vm.VMNetworkSerialized, error) {
 	if len(patterns) < 1 {
-		return nil, errors.New("At least one ID or regex must be specified")
+		return nil, errors.New("at least one ID or regex must be specified")
 	}
 
 	var ids []string
@@ -110,7 +110,7 @@ func getFilteredVMs(filteredVMsFunc GetVMs, patterns []string) ([]vm.VMNetworkSe
 //	"bla" -> matches any VM name containing "bla"
 func getFilteredVMCredentials(patterns []string) ([]vm.VMAttachCredentialsSerialized, error) {
 	if len(patterns) < 1 {
-		return nil, errors.New("At least one ID or regex must be specified")
+		return nil, errors.New("at least one ID or regex must be specified")
 	}
 
 	var ids []string
diff --git a/src/client/cmdVM/vmAddAccess.go b/src/client/cmdVM/vmAddAccess.go
index ec290e443bf49ae12866a3458b3d8c2ca794f07c..1bd100c9859f896579e75541340c7cf70c20f5ea 100644
--- a/src/client/cmdVM/vmAddAccess.go
+++ b/src/client/cmdVM/vmAddAccess.go
@@ -114,7 +114,7 @@ func (cmd *AddAccess) Run(args []string) int {
 				continue
 			}
 
-			vmAccessCaps := &params.VMAddAccess{make(caps.Capabilities)}
+			vmAccessCaps := &params.VMAddAccess{Access: make(caps.Capabilities)}
 
 			capsStr := strings.TrimSpace(columns[2])
 			if len(capsStr) > 0 {
@@ -151,7 +151,7 @@ func (cmd *AddAccess) Run(args []string) int {
 			return 1
 		}
 
-		vmAccessCaps := &params.VMAddAccess{make(caps.Capabilities)}
+		vmAccessCaps := &params.VMAddAccess{Access: make(caps.Capabilities)}
 		for _, cap := range capabilities {
 			vmAccessCaps.Access[cap] = 1
 		}
@@ -194,7 +194,7 @@ func (cmd *AddAccess) parseArgs(args []string) (string, []string, []string, erro
 	}
 
 	if !emailFound {
-		return "", nil, nil, errors.New("An email address must be specified")
+		return "", nil, nil, errors.New("an email address must be specified")
 	}
 
 	return email, capabilities, patterns, nil
diff --git a/src/client/cmdVM/vmAttachFromPwd.go b/src/client/cmdVM/vmAttachFromPwd.go
index 1bbf3f4726c6b418fe7181aef39020986c476d49..89245d4fdb7fec30488e2702e90c7acb4afe9a03 100644
--- a/src/client/cmdVM/vmAttachFromPwd.go
+++ b/src/client/cmdVM/vmAttachFromPwd.go
@@ -2,7 +2,6 @@ package cmdVM
 
 import (
 	"nexus-client/exec"
-	e "nexus-client/exec"
 	u "nexus-client/utils"
 	"nexus-common/params"
 	"nexus-common/vm"
@@ -57,7 +56,7 @@ func (cmd *AttachFromPwd) Run(args []string) int {
 		return 1
 	} else {
 		go func(creds vm.VMSpiceCredentialsSerialized) {
-			_, err := e.RunRemoteViewer(hostname, cert, creds.Name, creds.SpicePort, creds.SpicePwd, true)
+			_, err := exec.RunRemoteViewer(hostname, cert, creds.Name, creds.SpicePort, creds.SpicePwd, true)
 			if err != nil {
 				u.PrintlnErr("Failed executing remote-viewer: " + err.Error())
 			}
diff --git a/src/client/cmdVM/vmDelAccess.go b/src/client/cmdVM/vmDelAccess.go
index 7d16a31c81ee86d91140a2ca9101e058633386e8..2e6d2e324059c22d678018dcf847b79c00de8ee5 100644
--- a/src/client/cmdVM/vmDelAccess.go
+++ b/src/client/cmdVM/vmDelAccess.go
@@ -145,7 +145,7 @@ func (cmd *DelAccess) parseArgs(args []string) (string, []string, error) {
 		} else {
 			// An email address was found
 			if emailFound {
-				return "", nil, errors.New("Only one email address must be specified")
+				return "", nil, errors.New("only one email address must be specified")
 			}
 			email = parsed.Address
 			emailFound = true
@@ -153,7 +153,7 @@ func (cmd *DelAccess) parseArgs(args []string) (string, []string, error) {
 	}
 
 	if !emailFound {
-		return "", nil, errors.New("An email address must be specified")
+		return "", nil, errors.New("an email address must be specified")
 	}
 
 	return email, patterns, nil
diff --git a/src/client/cmdVM/vmEdit.go b/src/client/cmdVM/vmEdit.go
index 9cc00938994df74f13232a04819a9ad21da37fe2..d4d3352d551fdba58b7c7a1cbcd0780e1ddef434 100644
--- a/src/client/cmdVM/vmEdit.go
+++ b/src/client/cmdVM/vmEdit.go
@@ -121,7 +121,7 @@ func (cmd *Edit) parseArgs(args []string) (*params.VMEdit, []string, error) {
 		if s != "" {
 			cpus, err := strconv.Atoi(s)
 			if err != nil || cpus < 1 {
-				return nil, nil, errors.New("Error: invalid number of CPU(s)!")
+				return nil, nil, errors.New("error: invalid number of CPU(s)")
 			}
 			vmParams.Cpus = cpus
 			atLeastOneArg = true
@@ -131,7 +131,7 @@ func (cmd *Edit) parseArgs(args []string) (*params.VMEdit, []string, error) {
 		if s != "" {
 			ram, err := strconv.Atoi(s)
 			if err != nil || ram < 1 {
-				return nil, nil, errors.New("Error: invalid amount of RAM!")
+				return nil, nil, errors.New("error: invalid amount of RAM")
 			}
 			vmParams.Ram = ram
 			atLeastOneArg = true
diff --git a/src/client/cmdVM/vmList.go b/src/client/cmdVM/vmList.go
index e9312f658caafc11714d8f9eb73143a5682a7492..379c090aebd2202bf9c0658a1dd990bb97d1225b 100644
--- a/src/client/cmdVM/vmList.go
+++ b/src/client/cmdVM/vmList.go
@@ -33,12 +33,12 @@ func (cmd *List) PrintUsage() {
 }
 
 func (cmd *List) Run(args []string) int {
-	return cmd.printFilteredVMs(args, "/vms")
+	return cmd.printFilteredVMs(args)
 }
 
 // Prints a list of filtered VMs for a given route.
 // Return 0 if everything went well or 1 in case of failure.
-func (cmd *List) printFilteredVMs(args []string, route string) int {
+func (cmd *List) printFilteredVMs(args []string) int {
 	if len(args) < 1 {
 		cmd.PrintUsage()
 		return 1
diff --git a/src/client/cmdVM/vmStartWithCreds.go b/src/client/cmdVM/vmStartWithCreds.go
index b583fdaad4679fcf71a597361845abe7e0647f21..8b693a80bec86e712dda41dfaede1b3022397057 100644
--- a/src/client/cmdVM/vmStartWithCreds.go
+++ b/src/client/cmdVM/vmStartWithCreds.go
@@ -47,7 +47,7 @@ func (cmd *StartWithCreds) parseCSVFile(csvFile string) ([]string, []string, err
 	}
 	count := len(vmIDs)
 	if len(pwds) != count {
-		return nil, nil, errors.New("Invalid CSV file: all columns must have the same number of entries!")
+		return nil, nil, errors.New("invalid CSV file: all columns must have the same number of entries")
 	}
 	return vmIDs, pwds, nil
 }
diff --git a/src/client/cmdVersion/version.go b/src/client/cmdVersion/version.go
index 758be04213d76e91874d6d3d32e171b3f627e1c1..29677e653c179cabef7542872077ce6d81c9074b 100644
--- a/src/client/cmdVersion/version.go
+++ b/src/client/cmdVersion/version.go
@@ -15,8 +15,7 @@ func (cmd *Version) GetName() string {
 }
 
 func (cmd *Version) GetDesc() []string {
-	return []string{
-		"Display nexus server and client's versions."}
+	return []string{"Display nexus server and client's versions."}
 }
 
 func (cmd *Version) PrintUsage() {
diff --git a/src/client/go.mod b/src/client/go.mod
index e11566dbb2826ea926cf8cf1e924e59cf60aceff..4e105cb3ea930e72fec55b28422a00c8eedfb291 100644
--- a/src/client/go.mod
+++ b/src/client/go.mod
@@ -9,7 +9,7 @@ replace nexus-libclient => ../libclient
 require (
 	fyne.io/fyne/v2 v2.5.2
 	github.com/go-pdf/fpdf v0.9.0
-	github.com/go-playground/validator/v10 v10.23.0
+	github.com/go-playground/validator/v10 v10.23.0 // indirect
 	github.com/go-resty/resty/v2 v2.16.2
 	github.com/google/uuid v1.6.0
 	github.com/peterh/liner v1.2.2
diff --git a/src/client/nexus-cli/nexus-cli.go b/src/client/nexus-cli/nexus-cli.go
index 8b4bca9657d5f0c85e7533dbc0383512542db803..fe66f9fefbe3b776f64a92e34836fb7bf7b3a242 100644
--- a/src/client/nexus-cli/nexus-cli.go
+++ b/src/client/nexus-cli/nexus-cli.go
@@ -23,53 +23,53 @@ import (
 )
 
 var cmdList = []cmd.Command{
-	&cmdMisc.HelpHeader{"!═════╡ GENERAL commands ╞═════════════════════════════════════════════════════════════════"},
+	&cmdMisc.HelpHeader{Name: "!═════╡ GENERAL commands ╞═════════════════════════════════════════════════════════════════"},
 	// Commands in this block are specific to nexus-cli
-	&cmdLogin.Login{"login"},
+	&cmdLogin.Login{Name: "login"},
 	// End of nexus-cli specific commands
 
-	&cmdToken.Refresh{"refresh"},
-	&cmdVersion.Version{"version"},
-
-	&cmdMisc.HelpHeader{"!═════╡ USER commands ╞═════════════════════════════════════════════════════════════════"},
-	&cmdUser.Whoami{"whoami"},
-	&cmdUser.UpdatePwd{"passwd"},
-	&cmdUser.List{"userlist"},
-	&cmdUser.Add{"usercreate"},
-	&cmdUser.Del{"userdel"},
-	&cmdUser.ResetPwd{"userresetpwd"},
-	&cmdUser.SetCaps{"usersetcaps"},
-	&cmdUser.Unlock{"userunlock"},
-
-	&cmdMisc.HelpHeader{"!═════╡ TEMPLATE commands ╞═════════════════════════════════════════════════════════════════"},
-	&cmdTemplate.Create{"tplcreate"},
-	&cmdTemplate.Del{"tpldel"},
-	&cmdTemplate.Edit{"tpledit"},
-	&cmdTemplate.ExportDisk{"tplexportdisk"},
-	&cmdTemplate.List{"tpllist"},
-	// &cmdTemplate.ListSingle{"tpllistsingle"},   // for testing the route only
-
-	&cmdMisc.HelpHeader{"!═════╡ VM commands ╞═════════════════════════════════════════════════════════════════"},
-	&cmdVM.AddAccess{"vmaddaccess"},
-	&cmdVM.AttachAsync{"vmattach"},
-	// &cmdVM.AttachAsyncSingle{"vmattachsingle"},   // for testing the route only
-	// &cmdVM.AttachFromPwd{"vmattachfrompwd"},    // for testing the route only
-	&cmdVM.Create{"vmcreate"},
-	&cmdVM.Creds2pdf{"vmcreds2pdf"},
-	&cmdVM.Creds2csv{"vmcreds2csv"},
-	&cmdVM.Del{"vmdel"},
-	&cmdVM.DelAccess{"vmdelaccess"},
-	&cmdVM.Edit{"vmedit"},
-	&cmdVM.ExportDir{"vmexportdir"},
-	&cmdVM.ImportDir{"vmimportdir"},
-	&cmdVM.Stop{"vmkill"},
-	&cmdVM.List{"vmlist"},
-	// &cmdVM.ListSingle{"vmlistsingle"},   // for testing the route only
-	&cmdVM.Reboot{"vmreboot"},
-	&cmdVM.Shutdown{"vmshutdown"},
-	&cmdVM.Start{"vmstart"},
-	&cmdVM.StartAttach{"vmstartattach"},
-	&cmdVM.StartWithCreds{"vmstartwithcreds"},
+	&cmdToken.Refresh{Name: "refresh"},
+	&cmdVersion.Version{Name: "version"},
+
+	&cmdMisc.HelpHeader{Name: "!═════╡ USER commands ╞═════════════════════════════════════════════════════════════════"},
+	&cmdUser.Whoami{Name: "whoami"},
+	&cmdUser.UpdatePwd{Name: "passwd"},
+	&cmdUser.List{Name: "userlist"},
+	&cmdUser.Add{Name: "usercreate"},
+	&cmdUser.Del{Name: "userdel"},
+	&cmdUser.ResetPwd{Name: "userresetpwd"},
+	&cmdUser.SetCaps{Name: "usersetcaps"},
+	&cmdUser.Unlock{Name: "userunlock"},
+
+	&cmdMisc.HelpHeader{Name: "!═════╡ TEMPLATE commands ╞═════════════════════════════════════════════════════════════════"},
+	&cmdTemplate.Create{Name: "tplcreate"},
+	&cmdTemplate.Del{Name: "tpldel"},
+	&cmdTemplate.Edit{Name: "tpledit"},
+	&cmdTemplate.ExportDisk{Name: "tplexportdisk"},
+	&cmdTemplate.List{Name: "tpllist"},
+	// &cmdTemplate.ListSingle{Name: "tpllistsingle"},   // for testing the route only
+
+	&cmdMisc.HelpHeader{Name: "!═════╡ VM commands ╞═════════════════════════════════════════════════════════════════"},
+	&cmdVM.AddAccess{Name: "vmaddaccess"},
+	&cmdVM.AttachAsync{Name: "vmattach"},
+	// &cmdVM.AttachAsyncSingle{Name: "vmattachsingle"},   // for testing the route only
+	// &cmdVM.AttachFromPwd{Name: "vmattachfrompwd"},    // for testing the route only
+	&cmdVM.Create{Name: "vmcreate"},
+	&cmdVM.Creds2pdf{Name: "vmcreds2pdf"},
+	&cmdVM.Creds2csv{Name: "vmcreds2csv"},
+	&cmdVM.Del{Name: "vmdel"},
+	&cmdVM.DelAccess{Name: "vmdelaccess"},
+	&cmdVM.Edit{Name: "vmedit"},
+	&cmdVM.ExportDir{Name: "vmexportdir"},
+	&cmdVM.ImportDir{Name: "vmimportdir"},
+	&cmdVM.Stop{Name: "vmkill"},
+	&cmdVM.List{Name: "vmlist"},
+	// &cmdVM.ListSingle{Name: "vmlistsingle"},   // for testing the route only
+	&cmdVM.Reboot{Name: "vmreboot"},
+	&cmdVM.Shutdown{Name: "vmshutdown"},
+	&cmdVM.Start{Name: "vmstart"},
+	&cmdVM.StartAttach{Name: "vmstartattach"},
+	&cmdVM.StartWithCreds{Name: "vmstartwithcreds"},
 }
 
 func run() int {
diff --git a/src/client/nexush/nexush.go b/src/client/nexush/nexush.go
index c37a8b97a544aeb068eca4c66efa4a065f4fa3c4..ee4a51a9804364ed913d3e6919f7943b93649922 100644
--- a/src/client/nexush/nexush.go
+++ b/src/client/nexush/nexush.go
@@ -30,53 +30,53 @@ import (
 )
 
 var cmdList = []cmd.Command{
-	&cmdMisc.HelpHeader{"!═════╡ GENERAL commands ╞═════════════════════════════════════════════════════════════════"},
+	&cmdMisc.HelpHeader{Name: "!═════╡ GENERAL commands ╞═════════════════════════════════════════════════════════════════"},
 	// Commands in this block are specific to nexush:
-	&cmdMisc.Ls{"ls"},
+	&cmdMisc.Ls{Name: "ls"},
 	// End of nexush specific commands
 
-	&cmdToken.Refresh{"refresh"},
-	&cmdVersion.Version{"version"},
-
-	&cmdMisc.HelpHeader{"!═════╡ USER commands ╞═════════════════════════════════════════════════════════════════"},
-	&cmdUser.Whoami{"whoami"},
-	&cmdUser.UpdatePwd{"passwd"},
-	&cmdUser.List{"userlist"},
-	&cmdUser.Add{"usercreate"},
-	&cmdUser.Del{"userdel"},
-	&cmdUser.ResetPwd{"userresetpwd"},
-	&cmdUser.SetCaps{"usersetcaps"},
-	&cmdUser.Unlock{"userunlock"},
-
-	&cmdMisc.HelpHeader{"!═════╡ TEMPLATE commands ╞═════════════════════════════════════════════════════════════════"},
-	&cmdTemplate.Create{"tplcreate"},
-	&cmdTemplate.Del{"tpldel"},
-	&cmdTemplate.Edit{"tpledit"},
-	&cmdTemplate.ExportDisk{"tplexportdisk"},
-	&cmdTemplate.List{"tpllist"},
-	// &cmdTemplate.ListSingle{"tpllistsingle"}, // for testing the route only
-
-	&cmdMisc.HelpHeader{"!═════╡ VM commands ╞═════════════════════════════════════════════════════════════════"},
-	&cmdVM.AddAccess{"vmaddaccess"},
-	&cmdVM.AttachAsync{"vmattach"},
-	// &cmdVM.AttachAsyncSingle{"vmattachsingle"},   // for testing the route only
-	// &cmdVM.AttachFromPwd{"vmattachfrompwd"}, // for testing the route only
-	&cmdVM.Create{"vmcreate"},
-	&cmdVM.Creds2pdf{"vmcreds2pdf"},
-	&cmdVM.Creds2csv{"vmcreds2csv"},
-	&cmdVM.Del{"vmdel"},
-	&cmdVM.DelAccess{"vmdelaccess"},
-	&cmdVM.Edit{"vmedit"},
-	&cmdVM.ExportDir{"vmexportdir"},
-	&cmdVM.ImportDir{"vmimportdir"},
-	&cmdVM.Stop{"vmkill"},
-	&cmdVM.List{"vmlist"},
-	// &cmdVM.ListSingle{"vmlistsingle"},   // for testing the route only
-	&cmdVM.Reboot{"vmreboot"},
-	&cmdVM.Shutdown{"vmshutdown"},
-	&cmdVM.Start{"vmstart"},
-	&cmdVM.StartAttach{"vmstartattach"},
-	&cmdVM.StartWithCreds{"vmstartwithcreds"},
+	&cmdToken.Refresh{Name: "refresh"},
+	&cmdVersion.Version{Name: "version"},
+
+	&cmdMisc.HelpHeader{Name: "!═════╡ USER commands ╞═════════════════════════════════════════════════════════════════"},
+	&cmdUser.Whoami{Name: "whoami"},
+	&cmdUser.UpdatePwd{Name: "passwd"},
+	&cmdUser.List{Name: "userlist"},
+	&cmdUser.Add{Name: "usercreate"},
+	&cmdUser.Del{Name: "userdel"},
+	&cmdUser.ResetPwd{Name: "userresetpwd"},
+	&cmdUser.SetCaps{Name: "usersetcaps"},
+	&cmdUser.Unlock{Name: "userunlock"},
+
+	&cmdMisc.HelpHeader{Name: "!═════╡ TEMPLATE commands ╞═════════════════════════════════════════════════════════════════"},
+	&cmdTemplate.Create{Name: "tplcreate"},
+	&cmdTemplate.Del{Name: "tpldel"},
+	&cmdTemplate.Edit{Name: "tpledit"},
+	&cmdTemplate.ExportDisk{Name: "tplexportdisk"},
+	&cmdTemplate.List{Name: "tpllist"},
+	// &cmdTemplate.ListSingle{Name: "tpllistsingle"}, // for testing the route only
+
+	&cmdMisc.HelpHeader{Name: "!═════╡ VM commands ╞═════════════════════════════════════════════════════════════════"},
+	&cmdVM.AddAccess{Name: "vmaddaccess"},
+	&cmdVM.AttachAsync{Name: "vmattach"},
+	// &cmdVM.AttachAsyncSingle{Name: "vmattachsingle"},   // for testing the route only
+	// &cmdVM.AttachFromPwd{Name: "vmattachfrompwd"}, // for testing the route only
+	&cmdVM.Create{Name: "vmcreate"},
+	&cmdVM.Creds2pdf{Name: "vmcreds2pdf"},
+	&cmdVM.Creds2csv{Name: "vmcreds2csv"},
+	&cmdVM.Del{Name: "vmdel"},
+	&cmdVM.DelAccess{Name: "vmdelaccess"},
+	&cmdVM.Edit{Name: "vmedit"},
+	&cmdVM.ExportDir{Name: "vmexportdir"},
+	&cmdVM.ImportDir{Name: "vmimportdir"},
+	&cmdVM.Stop{Name: "vmkill"},
+	&cmdVM.List{Name: "vmlist"},
+	// &cmdVM.ListSingle{Name: "vmlistsingle"},   // for testing the route only
+	&cmdVM.Reboot{Name: "vmreboot"},
+	&cmdVM.Shutdown{Name: "vmshutdown"},
+	&cmdVM.Start{Name: "vmstart"},
+	&cmdVM.StartAttach{Name: "vmstartattach"},
+	&cmdVM.StartWithCreds{Name: "vmstartwithcreds"},
 }
 
 var prompt *liner.State = nil
@@ -162,7 +162,7 @@ func run() int {
 
 	// Obtains password from cmd line.
 	email := os.Args[1]
-	fmt.Printf(email + "'s password: ")
+	fmt.Printf("%s", email+"'s password: ")
 	bytePwd, err := term.ReadPassword(int(syscall.Stdin))
 	if err != nil {
 		u.PrintlnErr(err)
diff --git a/src/common/caps/caps.go b/src/common/caps/caps.go
index 77628ca17b55ae0cc09af130f0456ec52fd2d6fe..e8e13fe52269efb5334a401301d23caac748b20f 100644
--- a/src/common/caps/caps.go
+++ b/src/common/caps/caps.go
@@ -9,45 +9,45 @@ type Capabilities map[string]int
 
 const (
 	CAP_USER_CREATE   string = "USER_CREATE"
-	CAP_USER_DESTROY         = "USER_DESTROY"
-	CAP_USER_SET_CAPS        = "USER_SET_CAPS"
-	CAP_USER_UNLOCK          = "USER_UNLOCK"
-	CAP_USER_RESETPWD        = "USER_RESETPWD"
-	CAP_USER_LIST            = "USER_LIST"
-
-	CAP_VM_LIST           = "VM_LIST"
-	CAP_VM_LIST_ANY       = "VM_LIST_ANY"
-	CAP_VM_ATTACH         = "VM_ATTACH"
-	CAP_VM_ATTACH_ANY     = "VM_ATTACH_ANY"
-	CAP_VM_START          = "VM_START"
-	CAP_VM_START_ANY      = "VM_START_ANY"
-	CAP_VM_STOP           = "VM_STOP"
-	CAP_VM_STOP_ANY       = "VM_STOP_ANY"
-	CAP_VM_REBOOT         = "VM_REBOOT"
-	CAP_VM_REBOOT_ANY     = "VM_REBOOT_ANY"
-	CAP_VM_CREATE         = "VM_CREATE"
-	CAP_VM_DESTROY        = "VM_DESTROY"
-	CAP_VM_DESTROY_ANY    = "VM_DESTROY_ANY"
-	CAP_VM_EDIT           = "VM_EDIT"
-	CAP_VM_EDIT_ANY       = "VM_EDIT_ANY"
-	CAP_VM_SET_ACCESS     = "VM_SET_ACCESS"
-	CAP_VM_SET_ACCESS_ANY = "VM_SET_ACCESS_ANY"
-	CAP_VM_READFS         = "VM_READFS"
-	CAP_VM_READFS_ANY     = "VM_READFS_ANY"
-	CAP_VM_WRITEFS        = "VM_WRITEFS"
-	CAP_VM_WRITEFS_ANY    = "VM_WRITEFS_ANY"
-
-	CAP_EXAM_ATTACH = "EXAM_ATTACH"
-
-	CAP_TPL_CREATE      = "TPL_CREATE"
-	CAP_TPL_EDIT        = "TPL_EDIT"
-	CAP_TPL_EDIT_ANY    = "TPL_EDIT_ANY"
-	CAP_TPL_LIST        = "TPL_LIST"
-	CAP_TPL_LIST_ANY    = "TPL_LIST_ANY"
-	CAP_TPL_DESTROY     = "TPL_DESTROY"
-	CAP_TPL_DESTROY_ANY = "TPL_DESTROY_ANY"
-	CAP_TPL_READFS      = "TPL_READFS"
-	CAP_TPL_READFS_ANY  = "TPL_READFS_ANY"
+	CAP_USER_DESTROY  string = "USER_DESTROY"
+	CAP_USER_SET_CAPS string = "USER_SET_CAPS"
+	CAP_USER_UNLOCK   string = "USER_UNLOCK"
+	CAP_USER_RESETPWD string = "USER_RESETPWD"
+	CAP_USER_LIST     string = "USER_LIST"
+
+	CAP_VM_LIST           string = "VM_LIST"
+	CAP_VM_LIST_ANY       string = "VM_LIST_ANY"
+	CAP_VM_ATTACH         string = "VM_ATTACH"
+	CAP_VM_ATTACH_ANY     string = "VM_ATTACH_ANY"
+	CAP_VM_START          string = "VM_START"
+	CAP_VM_START_ANY      string = "VM_START_ANY"
+	CAP_VM_STOP           string = "VM_STOP"
+	CAP_VM_STOP_ANY       string = "VM_STOP_ANY"
+	CAP_VM_REBOOT         string = "VM_REBOOT"
+	CAP_VM_REBOOT_ANY     string = "VM_REBOOT_ANY"
+	CAP_VM_CREATE         string = "VM_CREATE"
+	CAP_VM_DESTROY        string = "VM_DESTROY"
+	CAP_VM_DESTROY_ANY    string = "VM_DESTROY_ANY"
+	CAP_VM_EDIT           string = "VM_EDIT"
+	CAP_VM_EDIT_ANY       string = "VM_EDIT_ANY"
+	CAP_VM_SET_ACCESS     string = "VM_SET_ACCESS"
+	CAP_VM_SET_ACCESS_ANY string = "VM_SET_ACCESS_ANY"
+	CAP_VM_READFS         string = "VM_READFS"
+	CAP_VM_READFS_ANY     string = "VM_READFS_ANY"
+	CAP_VM_WRITEFS        string = "VM_WRITEFS"
+	CAP_VM_WRITEFS_ANY    string = "VM_WRITEFS_ANY"
+
+	CAP_EXAM_ATTACH string = "EXAM_ATTACH"
+
+	CAP_TPL_CREATE      string = "TPL_CREATE"
+	CAP_TPL_EDIT        string = "TPL_EDIT"
+	CAP_TPL_EDIT_ANY    string = "TPL_EDIT_ANY"
+	CAP_TPL_LIST        string = "TPL_LIST"
+	CAP_TPL_LIST_ANY    string = "TPL_LIST_ANY"
+	CAP_TPL_DESTROY     string = "TPL_DESTROY"
+	CAP_TPL_DESTROY_ANY string = "TPL_DESTROY_ANY"
+	CAP_TPL_READFS      string = "TPL_READFS"
+	CAP_TPL_READFS_ANY  string = "TPL_READFS_ANY"
 )
 
 // Capabilities stored in the user config
@@ -113,7 +113,7 @@ func IsVMAccessCapValid(cap string) bool {
 
 // Validates all user capabilities.
 func ValidateUserCaps(caps Capabilities) error {
-	for cap, _ := range caps {
+	for cap := range caps {
 		if !IsUserCapValid(cap) {
 			return errors.New("Invalid capability: " + cap)
 		}
@@ -123,7 +123,7 @@ func ValidateUserCaps(caps Capabilities) error {
 
 // Validates all VM access capabilities.
 func ValidateVMAccessCaps(caps Capabilities) error {
-	for cap, _ := range caps {
+	for cap := range caps {
 		if !IsVMAccessCapValid(cap) {
 			return errors.New("Invalid capability: " + cap)
 		}
@@ -133,7 +133,7 @@ func ValidateVMAccessCaps(caps Capabilities) error {
 
 func GetUserCapsNames() []string {
 	caps := []string{}
-	for key, _ := range userCaps {
+	for key := range userCaps {
 		caps = append(caps, key)
 	}
 
@@ -147,7 +147,7 @@ func GetUserCapsNames() []string {
 
 func GetVMAccessCapsNames() []string {
 	caps := []string{}
-	for key, _ := range vmAccessCaps {
+	for key := range vmAccessCaps {
 		caps = append(caps, key)
 	}
 
diff --git a/src/common/params/vms.go b/src/common/params/vms.go
index e25c9764539e5cc673655692c622b4854a17b891..52ebc93efef44df5734361f48b8288efd0e4d2fc 100644
--- a/src/common/params/vms.go
+++ b/src/common/params/vms.go
@@ -11,8 +11,8 @@ type VMCreate struct {
 	Name       string     `json:"name"       validate:"required,min=1,max=256"`
 	Cpus       int        `json:"cpus"       validate:"required,gte=1,lte=32"`
 	Ram        int        `json:"ram"        validate:"required,gte=128,lte=32768"`
-	Nic        vm.NicType `json:"nic"        validate:"required`
-	UsbDevs    []string   `json:"usbDevs"    validate:"required`
+	Nic        vm.NicType `json:"nic"`
+	UsbDevs    []string   `json:"usbDevs"`
 	TemplateID uuid.UUID  `json:"templateID" validate:"required"`
 }
 
@@ -28,8 +28,8 @@ type VMEdit struct {
 	Name    string     `json:"name"       validate:"required,min=1,max=256"`
 	Cpus    int        `json:"cpus"       validate:"required,gte=1,lte=32"`
 	Ram     int        `json:"ram"        validate:"required,gte=128,lte=32768"`
-	Nic     vm.NicType `json:"nic"        validate:"required`
-	UsbDevs []string   `json:"usbDevs"    validate:"required`
+	Nic     vm.NicType `json:"nic"`
+	UsbDevs []string   `json:"usbDevs"`
 }
 
 type VMAddAccess struct {
diff --git a/src/libclient/go.mod b/src/libclient/go.mod
index 14915045c7c5d748b5efc1087ea1361c28d6c10a..c70650134288db7317bc630162112b449fd69d52 100644
--- a/src/libclient/go.mod
+++ b/src/libclient/go.mod
@@ -6,4 +6,9 @@ replace nexus-common => ../common
 
 require nexus-common v0.0.0-00010101000000-000000000000
 
-require github.com/google/uuid v1.6.0 // indirect
+require golang.org/x/net v0.27.0 // indirect
+
+require (
+	github.com/go-resty/resty/v2 v2.16.2
+	github.com/google/uuid v1.6.0 // indirect
+)
diff --git a/src/libclient/go.sum b/src/libclient/go.sum
index 7790d7c3e03900e267f0aade3acce649895b2246..5060da736650c97cec6eb978d30c4256168b46a3 100644
--- a/src/libclient/go.sum
+++ b/src/libclient/go.sum
@@ -1,2 +1,6 @@
+github.com/go-resty/resty/v2 v2.16.2 h1:CpRqTjIzq/rweXUt9+GxzzQdlkqMdt8Lm/fuK/CAbAg=
+github.com/go-resty/resty/v2 v2.16.2/go.mod h1:0fHAoK7JoBy/Ch36N8VFeMsK7xQOHhvWaC3iOktwmIU=
 github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
+golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
diff --git a/src/server/exec/QemuImg.go b/src/server/exec/QemuImg.go
index e9c222ad38b23a851926d90b28bf697d846f35db..90f3794e1271fa0ed43ac4a16a249d803bf418f8 100644
--- a/src/server/exec/QemuImg.go
+++ b/src/server/exec/QemuImg.go
@@ -25,12 +25,12 @@ func CheckQemuImg() error {
 	lines := strings.Split(out, "\n")
 	fields := strings.Split(lines[0], " ")
 	if len(fields) < 3 {
-		return errors.New("Failed extracting " + conf.Tools.QemuImg + " version number!")
+		return errors.New("failed extracting " + conf.Tools.QemuImg + " version number")
 	}
 	v := fields[2]
 	majorVersionNumber, err := strconv.Atoi(string(v[0]))
 	if err != nil {
-		return errors.New("Failed extracting " + conf.Tools.QemuImg + " version number: " + err.Error())
+		return errors.New("failed extracting " + conf.Tools.QemuImg + " version number: " + err.Error())
 	}
 	if majorVersionNumber < qemuimgBinaryMinVersion {
 		return errors.New(conf.Tools.QemuImg + " " + strconv.Itoa(qemuimgBinaryMinVersion) + ".0.0 or newer is required. Found version " + v + ".")
@@ -45,7 +45,7 @@ func QemuImgCreate(templateDiskFile, vmDiskFile string) error {
 	if err != nil {
 		output := fmt.Sprintf("[%s]", stdoutStderr)
 		log.Error("Failed creating VM disk image: " + output)
-		return errors.New("Failed creating VM disk image")
+		return errors.New("failed creating VM disk image")
 	}
 	return nil
 }
@@ -57,7 +57,7 @@ func QemuImgRebase(overlayFile string) error {
 	if err != nil {
 		output := fmt.Sprintf("[%s]", stdoutStderr)
 		log.Error("Failed rebasing template disk from VM: " + ": " + output)
-		return errors.New("Failed rebasing template disk from VM")
+		return errors.New("failed rebasing template disk from VM")
 	}
 	return nil
 }
diff --git a/src/server/exec/QemuSystem.go b/src/server/exec/QemuSystem.go
index 40dde35e1528b33cc1b87a2b5cc4bc29de5ffa65..a76c4a854e3d7b0e55f4b34bf23b1d1db681731c 100644
--- a/src/server/exec/QemuSystem.go
+++ b/src/server/exec/QemuSystem.go
@@ -46,7 +46,7 @@ func NewQemuSystem(qgaSock string, cpus, ram int, nic string, usbDevs []string,
 	if nic == "user" {
 		addr, err := utils.RandMacAddress()
 		if err != nil {
-			return nil, errors.New("Failed executing VM: MAC address generation error")
+			return nil, errors.New("failed executing VM: MAC address generation error")
 		}
 		nicArgs = "user,mac=" + addr + ",model=virtio-net-pci"
 	}
@@ -71,7 +71,7 @@ func NewQemuSystem(qgaSock string, cpus, ram int, nic string, usbDevs []string,
 		filter.WriteString("-1:-1:-1:-1:0")
 
 		// Generate QEMU's arguments for the USB devices
-		for i, _ := range usbDevs {
+		for i := range usbDevs {
 			idx := strconv.Itoa(i + 1)
 			usb = append(usb, "-chardev", "spicevmc,name=usbredir,id=usbredir"+idx)
 			usb = append(usb, "-device", "usb-redir,filter="+filter.String()+",chardev=usbredir"+idx)
diff --git a/src/server/users/user.go b/src/server/users/user.go
index 557112713fc4b14a0c6ea62cd1d6ae20f0cd6e9d..a8f182df7391377729763a3e68984b68b482bdda 100644
--- a/src/server/users/user.go
+++ b/src/server/users/user.go
@@ -34,7 +34,7 @@ func (user *User) HasCapability(capability string) bool {
 
 func (user *User) GetVMAccessCapabilities() []string {
 	caps := []string{}
-	for key, _ := range user.Caps {
+	for key := range user.Caps {
 		caps = append(caps, key)
 	}
 	return caps
diff --git a/src/server/vms/template.go b/src/server/vms/template.go
index ba083570e1d4b72460c715eab6b0479870569930..234dc6cf36a557b540a39d0a575a32813e7c4ae5 100644
--- a/src/server/vms/template.go
+++ b/src/server/vms/template.go
@@ -35,13 +35,13 @@ func NewTemplateFromVM(name, owner, access string, vm *VM) (*Template, error) {
 
 	if vm.IsRunning() {
 		vm.mutex.Unlock()
-		return nil, errors.New("Failed creating template: VM must be stopped")
+		return nil, errors.New("failed creating template: VM must be stopped")
 	}
 
 	// Marks VM as "busy", meaning its disk file is being accessed for a possibly long time.
 	if vm.IsDiskBusy() {
 		vm.mutex.Unlock()
-		return nil, errors.New("Failed creating template: VM disk is in use (busy)")
+		return nil, errors.New("failed creating template: VM disk is in use (busy)")
 	}
 	vm.DiskBusy = true
 
@@ -131,7 +131,7 @@ func NewTemplateFromQCOW(name, owner, access, qcowFile string) (*Template, error
 // Concurrency: safe
 func ValidateTemplateAccess(access string) error {
 	if access != templatePrivate && access != templatePublic {
-		return errors.New("Wrong template access type")
+		return errors.New("wrong template access type")
 	}
 	return nil
 }
@@ -169,7 +169,7 @@ func newTemplate(name, owner, access string) (*Template, error) {
 		return nil, err
 	}
 
-	template := &Template{template.TemplateSerialized{id, name, owner, access, time.Now()}}
+	template := &Template{template.TemplateSerialized{ID: id, Name: name, Owner: owner, Access: access, CreationTime: time.Now()}}
 
 	if err := template.validate(); err != nil {
 		return nil, errors.New("Failed validating template: " + err.Error())
diff --git a/src/server/vms/templates.go b/src/server/vms/templates.go
index 61cc4ba24ad8fdd3686aa45ce282666d04793760..8227293d63d9ba13f94aac4d74001a4193dbf846 100644
--- a/src/server/vms/templates.go
+++ b/src/server/vms/templates.go
@@ -126,7 +126,7 @@ func (templates *Templates) DeleteTemplate(tplID uuid.UUID, vms *VMs) error {
 	template, exists := templates.m[id]
 	if exists {
 		if vms.IsTemplateUsed(id) {
-			return errors.New("Failed: template still used by one or more VMs")
+			return errors.New("failed: template still used by one or more VMs")
 		}
 		// Removes the template's files (and directory).
 		if err := template.delete(); err != nil {
@@ -137,7 +137,7 @@ func (templates *Templates) DeleteTemplate(tplID uuid.UUID, vms *VMs) error {
 		return nil
 	}
 
-	return errors.New("Failed: template not found")
+	return errors.New("failed: template not found")
 }
 
 // Adds a template, create its on-disk directory and config file.
diff --git a/src/server/vms/vm.go b/src/server/vms/vm.go
index e76ac00785d3c0a52d6692aeb59a11abbf0034c0..b42acca20902a7150eddaa29b38267c18a7f1d3e 100644
--- a/src/server/vms/vm.go
+++ b/src/server/vms/vm.go
@@ -39,8 +39,6 @@ type (
 		AttachPwd string // Password required to attach to this VM
 		StartTime time.Time
 	}
-
-	endOfExecCallback func(vm *VM)
 )
 
 const (
@@ -235,7 +233,7 @@ func (vm *VM) validate() error {
 	for email, accessCaps := range vm.v.Access {
 		_, err := mail.ParseAddress(email)
 		if err != nil {
-			return errors.New("Invalid email")
+			return errors.New("invalid email")
 		}
 		if err := caps.ValidateVMAccessCaps(accessCaps); err != nil {
 			return err
@@ -350,11 +348,11 @@ func validateUsbDevs(devs []string) error {
 	for _, dev := range devs {
 		ids := strings.Split(dev, ":") // Extracts vendorID (vid) and productID (pid)
 		if len(ids) != 2 {             // expect exactly two values: vid and pid
-			return errors.New("Invalid USB device syntax")
+			return errors.New("invalid USB device syntax")
 		}
 		vid, pid := ids[0], ids[1]
 		if !isUsbId(vid) || !isUsbId(pid) {
-			return errors.New("Invalid USB vendor/product ID")
+			return errors.New("invalid USB vendor/product ID")
 		}
 	}
 	return nil
diff --git a/src/server/vms/vms.go b/src/server/vms/vms.go
index 52ba1811540aff110ba872ea636349429d546af5..edb1a7060c2b3f594aafa0584de36dac7ad14b1f 100644
--- a/src/server/vms/vms.go
+++ b/src/server/vms/vms.go
@@ -56,7 +56,7 @@ func GetVMsInstance() *VMs {
 func InitVMs() error {
 	vmsDir := conf.VMsDir
 	vms = &VMs{m: make(map[string]*VM), pwdToVM: make(map[string]uuid.UUID), mutexPwdToVM: new(sync.Mutex), dir: vmsDir, rwlock: new(sync.RWMutex), mutexUsedPorts: new(sync.Mutex), usedRAM: 0}
-	for i, _ := range vms.usedPorts {
+	for i := range vms.usedPorts {
 		vms.usedPorts[i] = false
 	}
 	vms.usedPorts[conf.Core.APIDefaultPort] = true
@@ -194,11 +194,11 @@ func (vms *VMs) DeleteVM(vmID uuid.UUID) error {
 	defer vm.mutex.Unlock()
 
 	if vm.IsRunning() {
-		return errors.New("Failed deleting VM: VM must be stopped")
+		return errors.New("failed deleting VM: VM must be stopped")
 	}
 
 	if vm.IsDiskBusy() {
-		return errors.New("Failed deleting VM: disk in use (busy)")
+		return errors.New("failed deleting VM: disk in use (busy)")
 	}
 
 	// Deletes the VM's files (and directories).
@@ -432,7 +432,7 @@ func (vms *VMs) allocateSpiceRandomPort() (int, error) {
 
 	for {
 		if !isFreePortLeft() {
-			return -1, errors.New("No free port left")
+			return -1, errors.New("no free port left")
 		}
 		port := utils.Rand(minPort, maxPort)
 		if !vms.usedPorts[port] {
@@ -482,7 +482,7 @@ func (vms *VMs) allocateAttachPwd(attachPwd string, vmID uuid.UUID) error {
 
 	_, exists := vms.pwdToVM[attachPwd]
 	if exists {
-		return errors.New("vms.allocateAttachPwd: password already reserved!")
+		return errors.New("vms.allocateAttachPwd: password already reserved")
 	}
 	vms.pwdToVM[attachPwd] = vmID
 	return nil
@@ -511,7 +511,7 @@ func (vms *VMs) KillVM(vmID uuid.UUID) error {
 	defer vm.mutex.Unlock()
 
 	if !vm.IsRunning() {
-		return errors.New("Failed killing VM: VM must be running")
+		return errors.New("failed killing VM: VM must be running")
 	}
 
 	// Sends a SIGINT signal to terminate the QEMU process.
@@ -540,7 +540,7 @@ func (vms *VMs) ShutdownVM(vmID uuid.UUID) error {
 	defer vm.mutex.Unlock()
 
 	if !vm.IsRunning() {
-		return errors.New("Shutdown failed: VM must be running")
+		return errors.New("shutdown failed: VM must be running")
 	}
 
 	// Function that gracefully shutdowns a running VM.
@@ -589,7 +589,7 @@ func (vms *VMs) RebootVM(vmID uuid.UUID) error {
 	defer vm.mutex.Unlock()
 
 	if !vm.IsRunning() {
-		return errors.New("Reboot failed: VM must be running")
+		return errors.New("reboot failed: VM must be running")
 	}
 
 	// Function that reboots a running VM.
@@ -714,7 +714,7 @@ func (vms *VMs) SetVMAccess(vmID uuid.UUID, user *users.User, destUserEmail stri
 			userCaps := vm.v.Access[user.Email]
 			_, exists := userCaps[caps.CAP_VM_SET_ACCESS]
 			if !exists {
-				return errors.New("Insufficient capability")
+				return errors.New("insufficient capability")
 			}
 		}
 	}
@@ -753,7 +753,7 @@ func (vms *VMs) DeleteVMAccess(vmID uuid.UUID, user *users.User, destUserEmail s
 			userCaps := vm.v.Access[user.Email]
 			_, exists := userCaps[caps.CAP_VM_SET_ACCESS]
 			if !exists {
-				return errors.New("Insufficient capability")
+				return errors.New("insufficient capability")
 			}
 		}
 	}