diff --git a/src/client_cli/cmd/Command.go b/src/client_cli/cmd/Command.go
new file mode 100644
index 0000000000000000000000000000000000000000..b59e32cbf97570a7e081a41906c06c0541a0228f
--- /dev/null
+++ b/src/client_cli/cmd/Command.go
@@ -0,0 +1,8 @@
+package cmd
+
+type Command interface {
+	GetName() string
+	GetDesc() string
+	PrintUsage()
+	Run(args []string) int   // Returns 0 if the Command was successful.
+}
diff --git a/src/client_cli/cmd/go.mod b/src/client_cli/cmd/go.mod
new file mode 100644
index 0000000000000000000000000000000000000000..579b8c2b8beca4fcca6862ef8f00db98b9d4b38b
--- /dev/null
+++ b/src/client_cli/cmd/go.mod
@@ -0,0 +1,3 @@
+module nexus-client/cmd
+
+go 1.18
diff --git a/src/client_cli/cmdLogin/go.mod b/src/client_cli/cmdLogin/go.mod
new file mode 100644
index 0000000000000000000000000000000000000000..33b89b787bedf99b2e1a4fb0ef7e3510cb159e62
--- /dev/null
+++ b/src/client_cli/cmdLogin/go.mod
@@ -0,0 +1,3 @@
+module nexus-client/cmdLogin
+
+go 1.18
diff --git a/src/client_cli/login.go b/src/client_cli/cmdLogin/login.go
similarity index 72%
rename from src/client_cli/login.go
rename to src/client_cli/cmdLogin/login.go
index ae4a1eb78df54971ec4bc250eea8bcf3d5e2365e..b8e0da87ab5870ca5958a9cf7ec9df1f207209b3 100644
--- a/src/client_cli/login.go
+++ b/src/client_cli/cmdLogin/login.go
@@ -1,28 +1,33 @@
-package main
+package cmdLogin
+
+import (
+	u "nexus-client/utils"
+	g "nexus-client/globals"
+)
 
 import (
 	"errors"
 	"encoding/json"
 )
 
-type CmdLogin struct {
-	name string
+type Login struct {
+	Name string
 }
 
-func (cmd *CmdLogin)Name() string {
-	return cmd.name
+func (cmd *Login)GetName() string {
+	return cmd.Name
 }
 
-func (cmd *CmdLogin)Desc() string {
+func (cmd *Login)GetDesc() string {
 	return "Login and obtain an access token"
 }
 
-func (cmd *CmdLogin)PrintUsage() {
-	printlnErr(cmd.Desc())
-	printlnErr("Usage: "+cmd.name+" email password")
+func (cmd *Login)PrintUsage() {
+	u.PrintlnErr(cmd.GetDesc())
+	u.PrintlnErr("Usage: "+cmd.Name+" email password")
 }
 
-func (cmd *CmdLogin)Run(args []string) int {
+func (cmd *Login)Run(args []string) int {
 	if len(args) != 2 {
 		cmd.PrintUsage()
 		return 1
@@ -32,11 +37,11 @@ func (cmd *CmdLogin)Run(args []string) int {
 	pwd := args[1]
 	token, err := login(email, pwd)
 	if err != nil {
-		printlnErr("Error: "+err.Error())
+		u.PrintlnErr("Error: "+err.Error())
 		return 1
 	}
 
-	println(token)
+	u.Println(token)
 	return 0
 }
 
@@ -46,6 +51,9 @@ func (cmd *CmdLogin)Run(args []string) int {
 // Returns a jwt token if authentication was successful:
 // {"token":"<jwt token>"}
 func login(user string, pwd string) (string, error) {
+	client := g.GetInstance().Client
+	host := g.GetInstance().Host
+
 	type LoginArgs struct {
 		Email string
 		Pwd string
diff --git a/src/client_cli/cmdTemplate/go.mod b/src/client_cli/cmdTemplate/go.mod
new file mode 100644
index 0000000000000000000000000000000000000000..f8efa2bc035490c83c840fed6a9ff3d2109c24a6
--- /dev/null
+++ b/src/client_cli/cmdTemplate/go.mod
@@ -0,0 +1,3 @@
+module nexus-client/cmdTpl
+
+go 1.18
diff --git a/src/client_cli/cmdTemplate/templateCreate.go b/src/client_cli/cmdTemplate/templateCreate.go
new file mode 100644
index 0000000000000000000000000000000000000000..da25513b505eee1dccb34b61e4ffa7abd932a5fe
--- /dev/null
+++ b/src/client_cli/cmdTemplate/templateCreate.go
@@ -0,0 +1,61 @@
+package cmdTemplate
+
+import (
+	u "nexus-client/utils"
+	g "nexus-client/globals"
+)
+
+type Create struct {
+    Name string
+}
+
+func (cmd *Create)GetName() string {
+	return cmd.Name
+}
+ 
+func (cmd *Create)GetDesc() string {
+	return "Create a template"
+}
+
+func (cmd *Create)PrintUsage() {
+	u.PrintlnErr(cmd.GetDesc())
+	u.PrintlnErr("Usage: "+cmd.Name+" vmID name access")
+	u.PrintlnErr("Notes: access is either \"public\" or \"private\"")
+}
+
+func (cmd *Create)Run(args []string) int {
+	client := g.GetInstance().Client
+	host := g.GetInstance().Host
+
+	argc := len(args)
+	if argc != 3 {
+		cmd.PrintUsage()
+		return 1
+	}
+
+	vmID := args[0]
+	name := args[1]
+	access := args[2]
+
+	type TemplateArgs struct {
+		VMID string
+		Name string
+		Access string
+	}
+			
+	templateArgs := &TemplateArgs { vmID, name, access }
+	
+	resp, err := client.R().SetBody(templateArgs).Post(host+"/templates")
+	if err != nil {
+		u.PrintlnErr("Error: "+err.Error())
+		return 1
+	}
+
+	if resp.IsSuccess() {
+		u.Println(resp)
+		return 0
+	} else {
+		u.PrintlnErr("Error: "+resp.Status()+": "+resp.String())
+		return 1
+	}
+}
diff --git a/src/client_cli/cmdTemplate/templateDel.go b/src/client_cli/cmdTemplate/templateDel.go
new file mode 100644
index 0000000000000000000000000000000000000000..f722979bc1ea711af72cffb7d9e4aedd18e79133
--- /dev/null
+++ b/src/client_cli/cmdTemplate/templateDel.go
@@ -0,0 +1,54 @@
+package cmdTemplate
+
+import (
+	u "nexus-client/utils"
+	g "nexus-client/globals"
+)
+
+type Del struct {
+    Name string
+}
+
+func (cmd *Del)GetName() string {
+	return cmd.Name
+}
+ 
+func (cmd *Del)GetDesc() string {
+	return "Delete one or more templates"
+}
+
+func (cmd *Del)PrintUsage() {
+	u.PrintlnErr(cmd.GetDesc())
+	u.PrintlnErr("Usage: "+cmd.Name+" id [id ...]")
+}
+
+func (cmd *Del)Run(args []string) int {
+	client := g.GetInstance().Client
+	host := g.GetInstance().Host
+
+	argc := len(args)
+	if argc < 1 {
+		cmd.PrintUsage()
+		return 1
+	}
+
+	statusCode := 0
+
+	// Iterates through each template to delete
+	for i:= range(args) {
+		id := args[i]
+		resp, err := client.R().Delete(host+"/templates/"+id)
+		if err != nil {
+			u.PrintlnErr("Error: "+err.Error())
+			statusCode = 1
+		} else {
+			if resp.IsSuccess() {
+				u.Println("Template \""+id+"\" deleted.")
+			} else {
+				u.PrintlnErr("Error: "+resp.Status()+": "+resp.String())
+				statusCode = 1
+			}
+		}
+	}
+	return statusCode
+}
diff --git a/src/client_cli/cmdTemplate/templateList.go b/src/client_cli/cmdTemplate/templateList.go
new file mode 100644
index 0000000000000000000000000000000000000000..4d9a8a75e481768a41d43b4a362b71dd5523f810
--- /dev/null
+++ b/src/client_cli/cmdTemplate/templateList.go
@@ -0,0 +1,56 @@
+package cmdTemplate
+
+import (
+	u "nexus-client/utils"
+	g "nexus-client/globals"
+)
+
+type List struct {
+    Name string
+}
+
+func (cmd *List)GetName() string {
+	return cmd.Name
+}
+ 
+func (cmd *List)GetDesc() string {
+	return "List one or more templates"
+}
+
+func (cmd *List)PrintUsage() {
+	u.PrintlnErr(cmd.GetDesc())
+	u.PrintlnErr("Usage: "+cmd.Name+" [id]")
+}
+
+func (cmd *List)Run(args []string) int {
+	client := g.GetInstance().Client
+	host := g.GetInstance().Host
+
+	argc := len(args)
+	if !(argc == 0 || argc == 1) {
+		cmd.PrintUsage()
+		return 1
+	}
+
+	var url string
+	if argc == 0 {
+		url = host+"/templates"
+	} else {
+		id := args[0]
+		url = host+"/templates/"+id
+	}
+
+	resp, err := client.R().Get(url)
+	if err != nil {
+		u.PrintlnErr("Error: "+err.Error())
+		return 1
+	}
+
+	if resp.IsSuccess() {
+		u.Println(resp)
+		return 0
+	} else {
+		u.PrintlnErr("Error: "+resp.Status()+": "+resp.String())
+		return 1
+	}
+}
diff --git a/src/client_cli/cmdUser/go.mod b/src/client_cli/cmdUser/go.mod
new file mode 100644
index 0000000000000000000000000000000000000000..7ea83babec75c653ad7aeeff1b465aaa98692214
--- /dev/null
+++ b/src/client_cli/cmdUser/go.mod
@@ -0,0 +1,10 @@
+module nexus-client/cmdUser
+
+go 1.18
+
+require golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
+
+require (
+	golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect
+	golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect
+)
diff --git a/src/client_cli/cmdUser/go.sum b/src/client_cli/cmdUser/go.sum
new file mode 100644
index 0000000000000000000000000000000000000000..e9d0abc3cda252e190fa06eb8cbc8d978acc7602
--- /dev/null
+++ b/src/client_cli/cmdUser/go.sum
@@ -0,0 +1,7 @@
+golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
+golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
diff --git a/src/client_cli/userAdd.go b/src/client_cli/cmdUser/userAdd.go
similarity index 50%
rename from src/client_cli/userAdd.go
rename to src/client_cli/cmdUser/userAdd.go
index 798ca0f9c5733bf6bff6050c3df4649dbb2ecfd5..e5dee74b6ded52f1b0452ceab761035d00e006e8 100644
--- a/src/client_cli/userAdd.go
+++ b/src/client_cli/cmdUser/userAdd.go
@@ -1,23 +1,31 @@
-package main
+package cmdUser
 
-type CmdUserAdd struct {
-    name string
+import (
+	u "nexus-client/utils"
+	g "nexus-client/globals"
+)
+
+type Add struct {
+    Name string
 }
 
-func (cmd *CmdUserAdd)Name() string {
-	return cmd.name
+func (cmd *Add)GetName() string {
+	return cmd.Name
 }
  
-func (cmd *CmdUserAdd)Desc() string {
+func (cmd *Add)GetDesc() string {
 	return "Add a user"
 }
 
-func (cmd *CmdUserAdd)PrintUsage() {
-	printlnErr(cmd.Desc())
-	printlnErr("Usage: "+cmd.name+" email firstname lastname password [capability1 capability2 ...]")
+func (cmd *Add)PrintUsage() {
+	u.PrintlnErr(cmd.GetDesc())
+	u.PrintlnErr("Usage: "+cmd.Name+" email firstname lastname password [capability1 capability2 ...]")
 }
 
-func (cmd *CmdUserAdd)Run(args []string) int {
+func (cmd *Add)Run(args []string) int {
+	client := g.GetInstance().Client
+	host := g.GetInstance().Host
+
 	argc := len(args)
 	if argc < 4 {
 		cmd.PrintUsage()
@@ -48,15 +56,15 @@ func (cmd *CmdUserAdd)Run(args []string) int {
 
 	resp, err := client.R().SetBody(userArgs).Post(host+"/users")
 	if err != nil {
-		printlnErr("Error: "+err.Error())
+		u.PrintlnErr("Error: "+err.Error())
 		return 1
 	}
 
 	if resp.IsSuccess() {
-		println(resp)
+		u.Println(resp)
 		return 0
 	} else {
-		printlnErr("Error: "+resp.Status()+": "+resp.String())
+		u.PrintlnErr("Error: "+resp.Status()+": "+resp.String())
 		return 1
 	}
 }
diff --git a/src/client_cli/cmdUser/userDel.go b/src/client_cli/cmdUser/userDel.go
new file mode 100644
index 0000000000000000000000000000000000000000..c6f6d0cdd8a16e5fd34ac0ccac32f1db8d25982e
--- /dev/null
+++ b/src/client_cli/cmdUser/userDel.go
@@ -0,0 +1,54 @@
+package cmdUser
+
+import (
+	u "nexus-client/utils"
+	g "nexus-client/globals"
+)
+
+type Del struct {
+    Name string
+}
+
+func (cmd *Del)GetName() string {
+	return cmd.Name
+}
+ 
+func (cmd *Del)GetDesc() string {
+	return "Delete one or more users"
+}
+
+func (cmd *Del)PrintUsage() {
+	u.PrintlnErr(cmd.GetDesc())
+	u.PrintlnErr("Usage: "+cmd.Name+" email [email ...]")
+}
+
+func (cmd *Del)Run(args []string) int {
+	client := g.GetInstance().Client
+	host := g.GetInstance().Host
+
+	argc := len(args)
+	if argc < 1 {
+		cmd.PrintUsage()
+		return 1
+	}
+
+	statusCode := 0
+
+	// Iterates through each user (email) to delete
+	for i:= range(args) {
+		email := args[i]
+		resp, err := client.R().Delete(host+"/users/"+email)
+		if err != nil {
+			u.PrintlnErr("Error: "+err.Error())
+			statusCode = 1
+		} else {
+			if resp.IsSuccess() {
+				u.Println("User "+email+" deleted.")
+			} else {
+				u.PrintlnErr("Error: "+resp.Status()+": "+resp.String())
+				statusCode = 1
+			}
+		}
+	}
+	return statusCode
+}
diff --git a/src/client_cli/cmdUser/userList.go b/src/client_cli/cmdUser/userList.go
new file mode 100644
index 0000000000000000000000000000000000000000..f1cefedd5ebcc49e1f1eb7da17b0c141c936e554
--- /dev/null
+++ b/src/client_cli/cmdUser/userList.go
@@ -0,0 +1,56 @@
+package cmdUser
+
+import (
+	u "nexus-client/utils"
+	g "nexus-client/globals"
+)
+
+type List struct {
+    Name string
+}
+
+func (cmd *List)GetName() string {
+	return cmd.Name
+}
+ 
+func (cmd *List)GetDesc() string {
+	return "List one or all users"
+}
+
+func (cmd *List)PrintUsage() {
+	u.PrintlnErr(cmd.GetDesc())
+	u.PrintlnErr("Usage: "+cmd.Name+" [email]")
+}
+
+func (cmd *List)Run(args []string) int {
+	client := g.GetInstance().Client
+	host := g.GetInstance().Host
+
+	argc := len(args)
+	if !(argc == 0 || argc == 1) {
+		cmd.PrintUsage()
+		return 1
+	}
+
+	var url string
+	if argc == 0 {
+		url = host+"/users"
+	} else {
+		email := args[0]
+		url = host+"/users/"+email
+	}
+
+	resp, err := client.R().Get(url)
+	if err != nil {
+		u.PrintlnErr("Error: "+err.Error())
+		return 1
+	}
+
+	if resp.IsSuccess() {
+		u.Println(resp)
+		return 0
+	} else {
+		u.PrintlnErr("Error: "+resp.Status()+": "+resp.String())
+		return 1
+	}
+}
diff --git a/src/client_cli/cmdUser/userSetCaps.go b/src/client_cli/cmdUser/userSetCaps.go
new file mode 100644
index 0000000000000000000000000000000000000000..028cd6b8837dde235eca7e09d6b7a051c2f4896c
--- /dev/null
+++ b/src/client_cli/cmdUser/userSetCaps.go
@@ -0,0 +1,59 @@
+package cmdUser
+
+import (
+	u "nexus-client/utils"
+	g "nexus-client/globals"
+)
+
+type SetCaps struct {
+    Name string
+}
+
+func (cmd *SetCaps)GetName() string {
+	return cmd.Name
+}
+ 
+func (cmd *SetCaps)GetDesc() string {
+	return "Set a user's capabilities"
+}
+
+func (cmd *SetCaps)PrintUsage() {
+	u.PrintlnErr(cmd.GetDesc())
+	u.PrintlnErr("Usage: "+cmd.Name+" email [capability1 capability2 ...]")
+}
+
+func (cmd *SetCaps)Run(args []string) int {
+	client := g.GetInstance().Client
+	host := g.GetInstance().Host
+
+	argc := len(args)
+	if argc < 1 {
+		cmd.PrintUsage()
+		return 1
+	}
+
+	email := args[0]
+
+	type CapsArgs struct {
+		Caps map[string]int `json:"caps"  validate:"required"`
+	}
+	
+	capsArgs := &CapsArgs { make(map[string]int) }
+	for _, cap := range args[1:] {
+		capsArgs.Caps[cap] = 1
+	}
+
+	resp, err := client.R().SetBody(capsArgs).Put(host+"/users/"+email+"/caps")
+	if err != nil {
+		u.PrintlnErr("Error: "+err.Error())
+		return 1
+	}
+
+	if resp.IsSuccess() {
+		u.Println(resp)
+		return 0
+	} else {
+		u.PrintlnErr("Error: "+resp.Status()+": "+resp.String())
+		return 1
+	}
+}
diff --git a/src/client_cli/cmdUser/userUpdatePwd.go b/src/client_cli/cmdUser/userUpdatePwd.go
new file mode 100644
index 0000000000000000000000000000000000000000..5f6f749cec1ce0b89eb457bde9d863be01d5b626
--- /dev/null
+++ b/src/client_cli/cmdUser/userUpdatePwd.go
@@ -0,0 +1,81 @@
+package cmdUser
+
+import (
+	u "nexus-client/utils"
+	g "nexus-client/globals"
+)
+
+import (
+	"bytes"
+	"golang.org/x/crypto/ssh/terminal"
+)
+
+type UpdatePwd struct {
+    Name string
+}
+
+func (cmd *UpdatePwd)GetName() string {
+	return cmd.Name
+}
+ 
+func (cmd *UpdatePwd)GetDesc() string {
+	return "Update the current user's password"
+}
+
+func (cmd *UpdatePwd)PrintUsage() {
+	u.PrintlnErr(cmd.GetDesc())
+	u.PrintlnErr("Usage: "+cmd.Name)
+}
+
+func (cmd *UpdatePwd)Run(args []string) int {
+	client := g.GetInstance().Client
+	host := g.GetInstance().Host
+
+	argc := len(args)
+	if argc != 0 {
+		cmd.PrintUsage()
+		return 1
+	}
+
+	// Read the new password from stdin
+	u.Print("New password: ")
+	newPwd, err := terminal.ReadPassword(0)
+	if err != nil {
+		u.PrintlnErr("Error: "+err.Error())
+		return 1
+	}
+	u.Print("\nRetype new password: ")
+	newPwd2, err := terminal.ReadPassword(0)
+	if err != nil {
+		u.PrintlnErr("Error: "+err.Error())
+		return 1
+	}
+	u.Println("")
+
+	if !bytes.Equal(newPwd, newPwd2) {
+		u.PrintlnErr("Sorry, passwords do not match!")
+		u.PrintlnErr("Password unchanged.")
+		return 1
+	}
+
+	pwdStr := string(newPwd)
+
+	type PwdArgs struct {
+		Pwd string
+	}
+
+	pwdArgs := &PwdArgs{pwdStr}
+	resp, err := client.R().SetBody(pwdArgs).Put(host+"/users/pwd")
+	if err != nil {
+		u.PrintlnErr("Error: "+err.Error())
+		return 1
+	} else {
+		if resp.IsSuccess() {
+			u.Println(resp)
+			return 0
+		} else {
+			u.PrintlnErr("Error: "+resp.Status()+": "+resp.String())
+			return 1
+		}
+	}
+}
diff --git a/src/client_cli/cmdUser/userWhoami.go b/src/client_cli/cmdUser/userWhoami.go
new file mode 100644
index 0000000000000000000000000000000000000000..ede314cd5a8d7049eb94f2412a94dae43ea24f4b
--- /dev/null
+++ b/src/client_cli/cmdUser/userWhoami.go
@@ -0,0 +1,48 @@
+package cmdUser
+
+import (
+	u "nexus-client/utils"
+	g "nexus-client/globals"
+)
+
+type Whoami struct {
+    Name string
+}
+
+func (cmd *Whoami)GetName() string {
+	return cmd.Name
+}
+ 
+func (cmd *Whoami)GetDesc() string {
+	return "Display the currently authenticated user's details"
+}
+
+func (cmd *Whoami)PrintUsage() {
+	u.PrintlnErr(cmd.GetDesc())
+	u.PrintlnErr("Usage: "+cmd.Name)
+}
+
+func (cmd *Whoami)Run(args []string) int {
+	client := g.GetInstance().Client
+	host := g.GetInstance().Host
+
+	argc := len(args)
+	if argc != 0 {
+		cmd.PrintUsage()
+		return 1
+	}
+
+	resp, err := client.R().Get(host+"/users/whoami")
+	if err != nil {
+		u.PrintlnErr("Error: "+err.Error())
+		return 1
+	} else {
+		if resp.IsSuccess() {
+			u.Println(resp)
+			return 0
+		} else {
+			u.PrintlnErr("Error: "+resp.Status()+": "+resp.String())
+			return 1
+		}
+	}
+}
diff --git a/src/client_cli/cmdVM/go.mod b/src/client_cli/cmdVM/go.mod
new file mode 100644
index 0000000000000000000000000000000000000000..ff40d17e88dc87c6de89e2294cc5866653a6cd19
--- /dev/null
+++ b/src/client_cli/cmdVM/go.mod
@@ -0,0 +1,5 @@
+module nexus-client/cmdVM
+
+go 1.18
+
+require github.com/google/uuid v1.3.0
diff --git a/src/client_cli/cmdVM/go.sum b/src/client_cli/cmdVM/go.sum
new file mode 100644
index 0000000000000000000000000000000000000000..3dfe1c9f26d3953e435514c804a71a01721639fe
--- /dev/null
+++ b/src/client_cli/cmdVM/go.sum
@@ -0,0 +1,2 @@
+github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
+github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
diff --git a/src/client_cli/helper.go b/src/client_cli/cmdVM/helper.go
similarity index 72%
rename from src/client_cli/helper.go
rename to src/client_cli/cmdVM/helper.go
index 24a6db84a7e7ae3a3ab45eb7321835a2951a7476..2178733964bda3b92a9cf10ee59270b6f5f271ae 100644
--- a/src/client_cli/helper.go
+++ b/src/client_cli/cmdVM/helper.go
@@ -1,9 +1,12 @@
-package main
+package cmdVM
 
 import (
 	"strings"
 	"regexp"
 	"encoding/json"
+	"nexus-client/cmd"
+	u "nexus-client/utils"
+	g "nexus-client/globals"
 	"github.com/google/uuid"
 	"github.com/go-resty/resty/v2"
 )
@@ -48,16 +51,16 @@ func (vm *VM)String() string {
 	return string(output)
 }
 
-func printUsage(cmd Command) {
-	printlnErr(cmd.Desc())
-	printlnErr("Usage: ",cmd.Name()," [vmID] [regex]")
-	printlnErr("Only VMs matching either the specified vmID or regex will be listed.")
-	printlnErr("Any number of vmID or regex can be specified.")
-	printlnErr("The regex matches the VM's name only and is case-insensitive.")
-	printlnErr("Regex examples:")
-	printlnErr("    \"\"    -> matches any name")
-	printlnErr("    \".\"   -> matches any name")
-	printlnErr("    \"bla\" -> matches any name containing \"bla\"")
+func printUsage(c cmd.Command) {
+	u.PrintlnErr(c.GetDesc())
+	u.PrintlnErr("Usage: ",c.GetName()," [vmID] [regex]")
+	u.PrintlnErr("Only VMs matching either the specified vmID or regex will be listed.")
+	u.PrintlnErr("Any number of vmID or regex can be specified.")
+	u.PrintlnErr("The regex matches the VM's name only and is case-insensitive.")
+	u.PrintlnErr("Regex examples:")
+	u.PrintlnErr("    \"\"    -> matches any name")
+	u.PrintlnErr("    \".\"   -> matches any name")
+	u.PrintlnErr("    \"bla\" -> matches any name containing \"bla\"")
 }
 
 // Call the given route and filter the results based on vmID and regex.
@@ -71,10 +74,13 @@ func printUsage(cmd Command) {
 //   ""    -> matches everything
 //   "."   -> matches everything
 //   "bla" -> matches any VM name containing "bla"
-func getFilteredVMs(cmd Command, args []string, route string) int {
+func getFilteredVMs(c cmd.Command, args []string, route string) int {
+	client := g.GetInstance().Client
+	host := g.GetInstance().Host
+
 	argc := len(args)
 	if argc < 1 {
-		cmd.PrintUsage()
+		c.PrintUsage()
 		return 1
 	}
 
@@ -92,14 +98,14 @@ func getFilteredVMs(cmd Command, args []string, route string) int {
 
 	resp, err := client.R().Get(host+route)
 	if err != nil {
-		printlnErr("Error: "+err.Error())
+		u.PrintlnErr("Error: "+err.Error())
 		return 1
 	}
 
 	if resp.IsSuccess() {
 		vms, err := getVMs(resp)
 		if err != nil {
-			printlnErr("Error: "+err.Error())
+			u.PrintlnErr("Error: "+err.Error())
 			return 1
 		}
 
@@ -107,7 +113,7 @@ func getFilteredVMs(cmd Command, args []string, route string) int {
 			found := false
 			for _, id := range ids {
 				if id == vm.ID.String() {
-					println(vm.String())
+					u.Println(vm.String())
 					found = true
 					break
 				}
@@ -118,10 +124,10 @@ func getFilteredVMs(cmd Command, args []string, route string) int {
 			for _, namePattern := range namePatterns {
 				match, err := regexp.MatchString(strings.ToLower(namePattern), strings.ToLower(vm.Name))
 				if err != nil {
-					printlnErr("Error matching \""+namePattern+"\": "+err.Error())
+					u.PrintlnErr("Error matching \""+namePattern+"\": "+err.Error())
 				} else {
 					if match {
-						println(vm.String())
+						u.Println(vm.String())
 						break
 					}
 				}
@@ -129,7 +135,7 @@ func getFilteredVMs(cmd Command, args []string, route string) int {
 		}
 		return 0
 	} else {
-		printlnErr("Error: "+resp.Status()+": "+resp.String())
+		u.PrintlnErr("Error: "+resp.Status()+": "+resp.String())
 		return 1
 	}
 }
diff --git a/src/client_cli/vmAttach.go b/src/client_cli/cmdVM/vmAttach.go
similarity index 65%
rename from src/client_cli/vmAttach.go
rename to src/client_cli/cmdVM/vmAttach.go
index 2b507829debc47520eee439c68f8ec46468eeea7..f2e70394475e92a8b0211208e14981cfaa672c68 100644
--- a/src/client_cli/vmAttach.go
+++ b/src/client_cli/cmdVM/vmAttach.go
@@ -1,30 +1,40 @@
-package main
+package cmdVM
+
+import (
+)
 
 import (
 	"os/exec"
 	"strconv"
 	"encoding/json"
 	"github.com/google/uuid"
+	u "nexus-client/utils"
+	g "nexus-client/globals"
 )
 
-type CmdVMAttach struct {
-    name string
+type Attach struct {
+    Name string
 }
 
-func (cmd *CmdVMAttach)Name() string {
-	return cmd.name
+func (cmd *Attach)GetName() string {
+	return cmd.Name
 }
  
-func (cmd *CmdVMAttach)Desc() string {
+func (cmd *Attach)GetDesc() string {
 	return "Attach to a VM in order to see its desktop"
 }
 
-func (cmd *CmdVMAttach)PrintUsage() {
-	printlnErr(cmd.Desc())
-	printlnErr("Usage: "+cmd.name+" vmID")
+func (cmd *Attach)PrintUsage() {
+	u.PrintlnErr(cmd.GetDesc())
+	u.PrintlnErr("Usage: "+cmd.Name+" vmID")
 }
 
-func (cmd *CmdVMAttach)Run(args []string) int {
+func (cmd *Attach)Run(args []string) int {
+	client := g.GetInstance().Client
+	host := g.GetInstance().Host
+	hostname := g.GetInstance().Hostname
+	pubCert := g.GetInstance().PubCert
+
 	argc := len(args)
 	if argc != 1 {
 		cmd.PrintUsage()
@@ -35,7 +45,7 @@ func (cmd *CmdVMAttach)Run(args []string) int {
 
 	resp, err := client.R().Get(host+"/vms/"+id+"/list")
 	if err != nil {
-		printlnErr("Error: "+err.Error())
+		u.PrintlnErr("Error: "+err.Error())
 		return 1
 	}
 
@@ -68,7 +78,7 @@ func (cmd *CmdVMAttach)Run(args []string) int {
 		var vm VM
 		err = json.Unmarshal(resp.Body(), &vm)
 		if err != nil {
-			printlnErr("Error: "+err.Error())
+			u.PrintlnErr("Error: "+err.Error())
 			return 1
 		}
 
@@ -79,17 +89,17 @@ func (cmd *CmdVMAttach)Run(args []string) int {
 			spiceSecure := "--spice-secure-channels=all"
 			cmd := exec.Command("remote-viewer", spice, spiceCert, spiceSecure) //, "-k", "--kiosk-quit=on-disconnect")
 			if err = cmd.Run(); err != nil {
-				printlnErr("Failed attaching to VM: "+err.Error())
+				u.PrintlnErr("Failed attaching to VM: "+err.Error())
 				return 1
 			}
 		
 			return 0
 		} else {
-			printlnErr("Can only attach to a running VM!")
+			u.PrintlnErr("Can only attach to a running VM!")
 			return 1
 		}
 	} else {
-		printlnErr("Error: "+resp.Status()+": "+resp.String())
+		u.PrintlnErr("Error: "+resp.Status()+": "+resp.String())
 		return 1
 	}
 }
diff --git a/src/client_cli/cmdVM/vmCreate.go b/src/client_cli/cmdVM/vmCreate.go
new file mode 100644
index 0000000000000000000000000000000000000000..688bc75517e2be5089cb7428b0994cfbdb4bcaff
--- /dev/null
+++ b/src/client_cli/cmdVM/vmCreate.go
@@ -0,0 +1,85 @@
+package cmdVM
+
+import (
+	"strconv"
+	u "nexus-client/utils"
+	g "nexus-client/globals"
+)
+
+type Create struct {
+    Name string
+}
+
+func (cmd *Create)GetName() string {
+	return cmd.Name
+}
+ 
+func (cmd *Create)GetDesc() string {
+	return "Create a VM"
+}
+
+func (cmd *Create)PrintUsage() {
+	u.PrintlnErr(cmd.GetDesc())
+	u.PrintlnErr("Usage: "+cmd.Name+" name cpus ram nic template")
+	u.PrintlnErr("name        name of the VM")
+	u.PrintlnErr("cpus        number of CPUs, between 1 and 16")
+	u.PrintlnErr("ram         amount of RAM in MB,  between 512 and 32768")
+	u.PrintlnErr("nic         network interface, either \"none\" or \"user\"")
+	u.PrintlnErr("template    ID of the template to VM will be based on")
+
+}
+
+func (cmd *Create)Run(args []string) int {
+	client := g.GetInstance().Client
+	host := g.GetInstance().Host
+
+	argc := len(args)
+	if argc != 5 {
+		cmd.PrintUsage()
+		return 1
+	}
+
+	ncpus, err := strconv.Atoi(args[1])
+	if err != nil {
+		u.PrintlnErr("Invalid number of CPU(s)")
+		return 1
+	}
+
+	ram, err := strconv.Atoi(args[2])
+	if err != nil {
+		u.PrintlnErr("Invalid amount of RAM")
+		return 1
+	}
+
+	nic := args[3]
+
+	type VMArgs struct {
+		Name string
+		Cpus int
+		Ram int
+		Nic string
+		TemplateID string
+	}
+			
+	vmArgs := &VMArgs {
+		Name: args[0],
+		Cpus: ncpus,
+		Ram: ram,
+		Nic: nic,
+		TemplateID: args[4],
+	}
+
+	resp, err := client.R().SetBody(vmArgs).Post(host+"/vms")
+	if err != nil {
+		u.PrintlnErr("Error: "+err.Error())
+		return 1
+	}
+
+	if resp.IsSuccess() {
+		u.Println(resp)
+		return 0
+	} else {
+		u.PrintlnErr("Error: "+resp.Status()+": "+resp.String())
+		return 1
+	}
+}
diff --git a/src/client_cli/cmdVM/vmDel.go b/src/client_cli/cmdVM/vmDel.go
new file mode 100644
index 0000000000000000000000000000000000000000..c9eedcfa1501b50f35fd1595e879b959e501f5b9
--- /dev/null
+++ b/src/client_cli/cmdVM/vmDel.go
@@ -0,0 +1,54 @@
+package cmdVM
+
+import (
+	u "nexus-client/utils"
+	g "nexus-client/globals"
+)
+
+type Del struct {
+    Name string
+}
+
+func (cmd *Del)GetName() string {
+	return cmd.Name
+}
+ 
+func (cmd *Del)GetDesc() string {
+	return "Delete one or more VMs"
+}
+
+func (cmd *Del)PrintUsage() {
+	u.PrintlnErr(cmd.GetDesc())
+	u.PrintlnErr("Usage: "+cmd.Name+" vmID [vmID ...]")
+}
+
+func (cmd *Del)Run(args []string) int {
+	client := g.GetInstance().Client
+	host := g.GetInstance().Host
+
+	argc := len(args)
+	if argc < 1 {
+		cmd.PrintUsage()
+		return 1
+	}
+
+	statusCode := 0
+
+	// Iterates through each uuid to delete
+	for i:= range(args) {
+		uuid := args[i]
+		resp, err := client.R().Delete(host+"/vms/"+uuid)
+		if err != nil {
+			u.PrintlnErr("Error: "+err.Error())
+			statusCode = 1
+		} else {
+			if resp.IsSuccess() {
+				u.Println("VM "+uuid+" deleted.")
+			} else {
+				u.PrintlnErr("Error: "+resp.Status()+": "+resp.String())
+				statusCode = 1
+			}
+		}
+	}
+	return statusCode
+}
diff --git a/src/client_cli/cmdVM/vmDelAccess.go b/src/client_cli/cmdVM/vmDelAccess.go
new file mode 100644
index 0000000000000000000000000000000000000000..862d2261f50cc54b9d55f3af59bcd370ceedafca
--- /dev/null
+++ b/src/client_cli/cmdVM/vmDelAccess.go
@@ -0,0 +1,51 @@
+package cmdVM
+
+import (
+	u "nexus-client/utils"
+	g "nexus-client/globals"
+)
+
+type DelAccess struct {
+    Name string
+}
+
+func (cmd *DelAccess)GetName() string {
+	return cmd.Name
+}
+ 
+func (cmd *DelAccess)GetDesc() string {
+	return "Delete the VM Access for a given user"
+}
+
+func (cmd *DelAccess)PrintUsage() {
+	u.PrintlnErr(cmd.GetDesc())
+	u.PrintlnErr("Usage: "+cmd.Name+" vmID email")
+}
+
+func (cmd *DelAccess)Run(args []string) int {
+	client := g.GetInstance().Client
+	host := g.GetInstance().Host
+
+	argc := len(args)
+	if argc != 2 {
+		cmd.PrintUsage()
+		return 1
+	}
+
+	vmID := args[0]
+	email := args[1]
+
+	resp, err := client.R().Delete(host+"/vms/"+vmID+"/access/"+email)
+	if err != nil {
+		u.PrintlnErr("Error: "+err.Error())
+		return 1
+	}
+
+	if resp.IsSuccess() {
+		u.Println(resp)
+		return 0
+	} else {
+		u.PrintlnErr("Error: "+resp.Status()+": "+resp.String())
+		return 1
+	}
+}
diff --git a/src/client_cli/vmEdit.go b/src/client_cli/cmdVM/vmEdit.go
similarity index 60%
rename from src/client_cli/vmEdit.go
rename to src/client_cli/cmdVM/vmEdit.go
index d01de941bcba655d36b4754fe2a9952084931eaa..bc5edaf0789934dac9430c03cc5dc5bbdda0be62 100644
--- a/src/client_cli/vmEdit.go
+++ b/src/client_cli/cmdVM/vmEdit.go
@@ -1,13 +1,15 @@
-package main
+package cmdVM
 
 import (
 	"strconv"
 	"strings"
 	"errors"
+	u "nexus-client/utils"
+	g "nexus-client/globals"
 )
 
-type CmdVMEdit struct {
-    name string
+type Edit struct {
+    Name string
 }
 
 type vmArgsParameters struct {
@@ -17,24 +19,24 @@ type vmArgsParameters struct {
 	Nic string
 }
 
-func (cmd *CmdVMEdit)Name() string {
-	return cmd.name
+func (cmd *Edit)GetName() string {
+	return cmd.Name
 }
  
-func (cmd *CmdVMEdit)Desc() string {
+func (cmd *Edit)GetDesc() string {
 	return "Edit a VM's properties (name, cpus, ram or nic)"
 }
 
-func (cmd *CmdVMEdit)PrintUsage() {
-	printlnErr(cmd.Desc())
-	printlnErr("Usage: "+cmd.name+" vmID [name=\"new name\"] [cpus=n] [ram=n] [nic=none/user]")
-	printlnErr("Parameters between [] are optional, but at least one must be defined.")
-	printlnErr("cpus must be between 1 and 16")
-	printlnErr("ram must be between 512 and 32768")
-	printlnErr("nic must be either \"none\" or \"user\"")
+func (cmd *Edit)PrintUsage() {
+	u.PrintlnErr(cmd.GetDesc())
+	u.PrintlnErr("Usage: "+cmd.Name+" vmID [name=\"new name\"] [cpus=n] [ram=n] [nic=none/user]")
+	u.PrintlnErr("Parameters between [] are optional, but at least one must be defined.")
+	u.PrintlnErr("cpus must be between 1 and 16")
+	u.PrintlnErr("ram must be between 512 and 32768")
+	u.PrintlnErr("nic must be either \"none\" or \"user\"")
 }
 
-func (cmd *CmdVMEdit)getStringVal(s string, prefix string) string {
+func (cmd *Edit)getStringVal(s string, prefix string) string {
 	if strings.HasPrefix(s, prefix) {
 		parts := strings.Split(s, prefix)
 		return parts[1]
@@ -42,7 +44,7 @@ func (cmd *CmdVMEdit)getStringVal(s string, prefix string) string {
 	return ""
 }
 
-func (cmd *CmdVMEdit)parseArgs(args []string) (*vmArgsParameters, error) {
+func (cmd *Edit)parseArgs(args []string) (*vmArgsParameters, error) {
 	vmArgs := &vmArgsParameters {}
 	atLeastOneArg := false
 
@@ -84,7 +86,10 @@ func (cmd *CmdVMEdit)parseArgs(args []string) (*vmArgsParameters, error) {
 	}
 }
 
-func (cmd *CmdVMEdit)Run(args []string) int {
+func (cmd *Edit)Run(args []string) int {
+	client := g.GetInstance().Client
+	host := g.GetInstance().Host
+
 	argc := len(args)
 	if argc < 2 || argc > 5 {
 		cmd.PrintUsage()
@@ -94,7 +99,7 @@ func (cmd *CmdVMEdit)Run(args []string) int {
 	id := args[0]
 	vmArgs, err := cmd.parseArgs(args[1:])
 	if err != nil {
-		printlnErr(err.Error())
+		u.PrintlnErr(err.Error())
 		return 1
 	}
 
@@ -105,15 +110,15 @@ func (cmd *CmdVMEdit)Run(args []string) int {
 
 	resp, err := client.R().SetBody(vmArgs).Put(host+"/vms/"+id)
 	if err != nil {
-		printlnErr("Error: "+err.Error())
+		u.PrintlnErr("Error: "+err.Error())
 		return 1
 	}
 
 	if resp.IsSuccess() {
-		println(resp)
+		u.Println(resp)
 		return 0
 	} else {
-		printlnErr("Error: "+resp.Status()+": "+resp.String())
+		u.PrintlnErr("Error: "+resp.Status()+": "+resp.String())
 		return 1
 	}
 }
diff --git a/src/client_cli/cmdVM/vmList.go b/src/client_cli/cmdVM/vmList.go
new file mode 100644
index 0000000000000000000000000000000000000000..f5e13d4f8f2858543702ff59d66ddf7b0915494a
--- /dev/null
+++ b/src/client_cli/cmdVM/vmList.go
@@ -0,0 +1,21 @@
+package cmdVM
+
+type List struct {
+    Name string
+}
+
+func (cmd *List)GetName() string {
+	return cmd.Name
+}
+ 
+func (cmd *List)GetDesc() string {
+	return "List all VMs that can be listed"
+}
+
+func (cmd *List)PrintUsage() {
+	printUsage(cmd)
+}
+
+func (cmd *List)Run(args []string) int {
+	return getFilteredVMs(cmd, args, "/vms/list")
+}
diff --git a/src/client_cli/cmdVM/vmListAttach.go b/src/client_cli/cmdVM/vmListAttach.go
new file mode 100644
index 0000000000000000000000000000000000000000..c10ccfcb1a9cffe5aa0bf80b6344a9c26e73b42d
--- /dev/null
+++ b/src/client_cli/cmdVM/vmListAttach.go
@@ -0,0 +1,21 @@
+package cmdVM
+
+type ListAttach struct {
+    Name string
+}
+
+func (cmd *ListAttach)GetName() string {
+	return cmd.Name
+}
+ 
+func (cmd *ListAttach)GetDesc() string {
+	return "List VMs that can be attached to"
+}
+
+func (cmd *ListAttach)PrintUsage() {
+	printUsage(cmd)
+}
+
+func (cmd *ListAttach)Run(args []string) int {
+	return getFilteredVMs(cmd, args, "/vms/attach")
+}
diff --git a/src/client_cli/cmdVM/vmListDel.go b/src/client_cli/cmdVM/vmListDel.go
new file mode 100644
index 0000000000000000000000000000000000000000..7701bac75a73e548d525762cd0aa2c77846db7dd
--- /dev/null
+++ b/src/client_cli/cmdVM/vmListDel.go
@@ -0,0 +1,21 @@
+package cmdVM
+
+type ListDel struct {
+    Name string
+}
+
+func (cmd *ListDel)GetName() string {
+	return cmd.Name
+}
+ 
+func (cmd *ListDel)GetDesc() string {
+	return "List VMs that can be deleted"
+}
+
+func (cmd *ListDel)PrintUsage() {
+	printUsage(cmd)
+}
+
+func (cmd *ListDel)Run(args []string) int {
+	return getFilteredVMs(cmd, args, "/vms/del")
+}
diff --git a/src/client_cli/cmdVM/vmListEdit.go b/src/client_cli/cmdVM/vmListEdit.go
new file mode 100644
index 0000000000000000000000000000000000000000..47b3356692cc41919cc6a95c656602b40e8f7a67
--- /dev/null
+++ b/src/client_cli/cmdVM/vmListEdit.go
@@ -0,0 +1,21 @@
+package cmdVM
+
+type ListEdit struct {
+    Name string
+}
+
+func (cmd *ListEdit)GetName() string {
+	return cmd.Name
+}
+ 
+func (cmd *ListEdit)GetDesc() string {
+	return "List VMs that can be edited"
+}
+
+func (cmd *ListEdit)PrintUsage() {
+	printUsage(cmd)
+}
+
+func (cmd *ListEdit)Run(args []string) int {
+	return getFilteredVMs(cmd, args, "/vms/edit")
+}
diff --git a/src/client_cli/cmdVM/vmListEditAccess.go b/src/client_cli/cmdVM/vmListEditAccess.go
new file mode 100644
index 0000000000000000000000000000000000000000..d8fa17daecf020ecb230ef5585e66c124c4c1b11
--- /dev/null
+++ b/src/client_cli/cmdVM/vmListEditAccess.go
@@ -0,0 +1,21 @@
+package cmdVM
+
+type ListEditAccess struct {
+    Name string
+}
+
+func (cmd *ListEditAccess)GetName() string {
+	return cmd.Name
+}
+ 
+func (cmd *ListEditAccess)GetDesc() string {
+	return "List VMs that can have their VM access edited"
+}
+
+func (cmd *ListEditAccess)PrintUsage() {
+	printUsage(cmd)
+}
+
+func (cmd *ListEditAccess)Run(args []string) int {
+	return getFilteredVMs(cmd, args, "/vms/editaccess")
+}
diff --git a/src/client_cli/cmdVM/vmListStart.go b/src/client_cli/cmdVM/vmListStart.go
new file mode 100644
index 0000000000000000000000000000000000000000..66a486b7194b72c2eced633d69546b04517a0690
--- /dev/null
+++ b/src/client_cli/cmdVM/vmListStart.go
@@ -0,0 +1,21 @@
+package cmdVM
+
+type ListStart struct{
+    Name string
+}
+
+func (cmd *ListStart)GetName() string {
+	return cmd.Name
+}
+ 
+func (cmd *ListStart)GetDesc() string {
+	return "List VMs that can be started"
+}
+
+func (cmd *ListStart)PrintUsage() {
+	printUsage(cmd)
+}
+
+func (cmd *ListStart)Run(args []string) int {
+	return getFilteredVMs(cmd, args, "/vms/start")
+}
diff --git a/src/client_cli/cmdVM/vmListStop.go b/src/client_cli/cmdVM/vmListStop.go
new file mode 100644
index 0000000000000000000000000000000000000000..e7e8a2e1b172037d39cabd29807aa78bec1c1c52
--- /dev/null
+++ b/src/client_cli/cmdVM/vmListStop.go
@@ -0,0 +1,21 @@
+package cmdVM
+
+type ListStop struct {
+    Name string
+}
+
+func (cmd *ListStop)GetName() string {
+	return cmd.Name
+}
+ 
+func (cmd *ListStop)GetDesc() string {
+	return "List VMs that can be stopped"
+}
+
+func (cmd *ListStop)PrintUsage() {
+	printUsage(cmd)
+}
+
+func (cmd *ListStop)Run(args []string) int {
+	return getFilteredVMs(cmd, args, "/vms/stop")
+}
diff --git a/src/client_cli/vmSetAccess.go b/src/client_cli/cmdVM/vmSetAccess.go
similarity index 50%
rename from src/client_cli/vmSetAccess.go
rename to src/client_cli/cmdVM/vmSetAccess.go
index f92a1a4fb0a41db385a1bca28f5bb3aec451d287..54162460a292b594acd62f6402cfe95bd7ff9781 100644
--- a/src/client_cli/vmSetAccess.go
+++ b/src/client_cli/cmdVM/vmSetAccess.go
@@ -1,23 +1,31 @@
-package main
+package cmdVM
 
-type CmdVMSetAccess struct {
-    name string
+import (
+	u "nexus-client/utils"
+	g "nexus-client/globals"
+)
+
+type SetAccess struct {
+    Name string
 }
 
-func (cmd *CmdVMSetAccess)Name() string {
-	return cmd.name
+func (cmd *SetAccess)GetName() string {
+	return cmd.Name
 }
  
-func (cmd *CmdVMSetAccess)Desc() string {
+func (cmd *SetAccess)GetDesc() string {
 	return "Set the VM Access for a given user"
 }
 
-func (cmd *CmdVMSetAccess)PrintUsage() {
-	printlnErr(cmd.Desc())
-	printlnErr("Usage: "+cmd.name+" vmID email [capability1 capability2 ...]")
+func (cmd *SetAccess)PrintUsage() {
+	u.PrintlnErr(cmd.GetDesc())
+	u.PrintlnErr("Usage: "+cmd.Name+" vmID email [capability1 capability2 ...]")
 }
 
-func (cmd *CmdVMSetAccess)Run(args []string) int {
+func (cmd *SetAccess)Run(args []string) int {
+	client := g.GetInstance().Client
+	host := g.GetInstance().Host
+
 	argc := len(args)
 	if argc < 2 {
 		cmd.PrintUsage()
@@ -38,15 +46,15 @@ func (cmd *CmdVMSetAccess)Run(args []string) int {
 
 	resp, err := client.R().SetBody(userUpdatedAccessArgs).Put(host+"/vms/"+vmID+"/access/"+email)
 	if err != nil {
-		printlnErr("Error: "+err.Error())
+		u.PrintlnErr("Error: "+err.Error())
 		return 1
 	}
 
 	if resp.IsSuccess() {
-		println(resp)
+		u.Println(resp)
 		return 0
 	} else {
-		printlnErr("Error: "+resp.Status()+": "+resp.String())
+		u.PrintlnErr("Error: "+resp.Status()+": "+resp.String())
 		return 1
 	}
 }
diff --git a/src/client_cli/cmdVM/vmStart.go b/src/client_cli/cmdVM/vmStart.go
new file mode 100644
index 0000000000000000000000000000000000000000..9c03729a019b9c9e946a1f1f29ed642710d02032
--- /dev/null
+++ b/src/client_cli/cmdVM/vmStart.go
@@ -0,0 +1,49 @@
+package cmdVM
+
+import (
+	u "nexus-client/utils"
+	g "nexus-client/globals"
+)
+
+type Start struct {
+    Name string
+}
+
+func (cmd *Start)GetName() string {
+	return cmd.Name
+}
+ 
+func (cmd *Start)GetDesc() string {
+	return "Start a VM"
+}
+
+func (cmd *Start)PrintUsage() {
+	u.PrintlnErr(cmd.GetDesc())
+	u.PrintlnErr("Usage: "+cmd.Name+" vmID")
+}
+
+func (cmd *Start)Run(args []string) int {
+	client := g.GetInstance().Client
+	host := g.GetInstance().Host
+
+	argc := len(args)
+	if argc != 1 {
+		cmd.PrintUsage()
+		return 1
+	}
+
+	uuid := args[0]
+	resp, err := client.R().Put(host+"/vms/"+uuid+"/start")
+	if err != nil {
+		u.PrintlnErr("Error: "+err.Error())
+		return 1
+	}
+
+	if resp.IsSuccess() {
+		u.Println(resp)
+		return 0
+	} else {
+		u.PrintlnErr("Error: "+resp.Status()+": "+resp.String())
+		return 1
+	}
+}
diff --git a/src/client_cli/cmdVM/vmStop.go b/src/client_cli/cmdVM/vmStop.go
new file mode 100644
index 0000000000000000000000000000000000000000..e15411a12deccacb3f6214f311dd513a4e98089e
--- /dev/null
+++ b/src/client_cli/cmdVM/vmStop.go
@@ -0,0 +1,49 @@
+package cmdVM
+
+import (
+	u "nexus-client/utils"
+	g "nexus-client/globals"
+)
+
+type Stop struct {
+    Name string
+}
+
+func (cmd *Stop)GetName() string {
+	return cmd.Name
+}
+ 
+func (cmd *Stop)GetDesc() string {
+	return "Stop a VM"
+}
+
+func (cmd *Stop)PrintUsage() {
+	u.PrintlnErr(cmd.GetDesc())
+	u.PrintlnErr("Usage: "+cmd.Name+" vmID")
+}
+
+func (cmd *Stop)Run(args []string) int {
+	client := g.GetInstance().Client
+	host := g.GetInstance().Host
+
+	argc := len(args)
+	if argc != 1 {
+		cmd.PrintUsage()
+		return 1
+	}
+
+	uuid := args[0]
+	resp, err := client.R().Put(host+"/vms/"+uuid+"/stop")
+	if err != nil {
+		u.PrintlnErr("Error: "+err.Error())
+		return 1
+	}
+
+	if resp.IsSuccess() {
+		u.Println(resp)
+		return 0
+	} else {
+		u.PrintlnErr("Error: "+resp.Status()+": "+resp.String())
+		return 1
+	}
+}
diff --git a/src/client_cli/globals/Globals.go b/src/client_cli/globals/Globals.go
new file mode 100644
index 0000000000000000000000000000000000000000..4985794b399583152969b664bc9e03674e72844b
--- /dev/null
+++ b/src/client_cli/globals/Globals.go
@@ -0,0 +1,23 @@
+package globals
+
+import (
+	"github.com/go-resty/resty/v2"
+)
+
+type Globals struct {
+	Host string
+	Hostname string
+	PubCert string
+	Client *resty.Client
+}
+
+var globals *Globals
+
+func GetInstance() *Globals {
+	return globals
+}
+
+func Init(hostname string, host string, pubCert string, client *resty.Client) *Globals {
+	return &Globals{hostname, host, pubCert, client}
+}
+
diff --git a/src/client_cli/globals/go.mod b/src/client_cli/globals/go.mod
new file mode 100644
index 0000000000000000000000000000000000000000..3b10e911375b8e7d6435e57779445a78311c20e9
--- /dev/null
+++ b/src/client_cli/globals/go.mod
@@ -0,0 +1,3 @@
+module nexus-client/globals
+
+go 1.18
diff --git a/src/client_cli/go.mod b/src/client_cli/go.mod
index ff1ee969fd228167a507d713cb179840870fe3e8..299ccd655a57f65ce055c36a3dce3639aa7e4a95 100644
--- a/src/client_cli/go.mod
+++ b/src/client_cli/go.mod
@@ -2,14 +2,35 @@ module nexus-client
 
 go 1.18
 
+replace nexus-client/cmd => ./cmd
+
+replace nexus-client/globals => ./globals
+
+replace nexus-client/utils => ./utils
+
+replace nexus-client/cmdLogin => ./cmdLogin
+
+replace nexus-client/cmdUser => ./cmdUser
+
+replace nexus-client/cmdVM => ./cmdVM
+
+replace nexus-client/cmdTemplate => ./cmdTemplate
+
 require (
 	github.com/go-resty/resty/v2 v2.7.0
 	github.com/google/uuid v1.3.0
-	golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e
+	golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
 )
 
 require (
 	golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect
 	golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect
 	golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect
+	nexus-client/cmd v0.0.0-00010101000000-000000000000 // indirect
+	nexus-client/cmdLogin v0.0.0-00010101000000-000000000000 // indirect
+	nexus-client/cmdTemplate v0.0.0-00010101000000-000000000000 // indirect
+	nexus-client/cmdUser v0.0.0-00010101000000-000000000000 // indirect
+	nexus-client/cmdVM v0.0.0-00010101000000-000000000000 // indirect
+	nexus-client/globals v0.0.0-00010101000000-000000000000 // indirect
+	nexus-client/utils v0.0.0-00010101000000-000000000000 // indirect
 )
diff --git a/src/client_cli/go.sum b/src/client_cli/go.sum
index 8d44efc0c608b792bf36f3037435a6d55b3218ed..3e54ad76934bb38ce18ad819a2caf2aad9bc24f9 100644
--- a/src/client_cli/go.sum
+++ b/src/client_cli/go.sum
@@ -4,6 +4,8 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
 github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM=
 golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
+golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
diff --git a/src/client_cli/nexus-client.go b/src/client_cli/nexus-client.go
index 4ed9d72993558bb64a4da5b0e9a78b3f806ccd8a..a1e11c65a47633185c40f6998c514da48c7f33c0 100644
--- a/src/client_cli/nexus-client.go
+++ b/src/client_cli/nexus-client.go
@@ -4,6 +4,13 @@ import (
 	"os"
 	"path"
 	"strings"
+	u "nexus-client/utils"
+	"nexus-client/globals"
+	"nexus-client/cmd"
+	"nexus-client/cmdLogin"
+	"nexus-client/cmdUser"
+	"nexus-client/cmdVM"
+	"nexus-client/cmdTemplate"
 	"github.com/go-resty/resty/v2"
 )
 
@@ -13,91 +20,81 @@ const (
 	ENV_NEXUS_CERT = "NEXUS_CERT"
 )
 
-var host string
-var hostname string
-var pubCert string
-
-var client = resty.New()
-
-type Command interface {
-	Name() string
-	Desc() string
-	PrintUsage()
-	Run(args []string) int   // Returns 0 if the Command was successful.
-}
-
-var cmdList = []Command {
-	&CmdLogin{"login"},
-	&CmdWhoami{"whoami"},
-	&CmdUpdatePwd{"passwd"},
-
-	&CmdUserList{"user_list"},
-	&CmdUserAdd{"user_add"},
-	&CmdUserDel{"user_del"},
-	&CmdUserSetCaps{"user_setcaps"},
-
-	&CmdVMList{"vmlist"},
-	&CmdVMListStart{"vmlist_start"},
-	&CmdVMListAttach{"vmlist_attach"},
-	&CmdVMListStop{"vmlist_stop"},
-	&CmdVMListEdit{"vmlist_edit"},
-	&CmdVMListEditAccess{"vmlist_editaccess"},
-	&CmdVMListDel{"vmlist_del"},
-
-	&CmdVMStart{"vm_start"},
-	&CmdVMStop{"vm_stop"},
-	&CmdVMAttach{"vm_attach"},
-	&CmdVMCreate{"vm_create"},
-	&CmdVMEdit{"vm_edit"},
-	&CmdVMDel{"vm_del"},
-	&CmdVMSetAccess{"vm_setaccess"},
-	&CmdVMDelAccess{"vm_delaccess"},
-
-	&CmdTemplateList{"tpl_list"},
-	&CmdTemplateCreate{"tpl_create"},
-	&CmdTemplateDel{"tpl_del"},
+var cmdList = []cmd.Command {
+	&cmdLogin.Login{"login"},
+	
+	&cmdUser.Whoami{"whoami"},
+	&cmdUser.UpdatePwd{"passwd"},
+	&cmdUser.List{"user_list"},
+	&cmdUser.Add{"user_add"},
+	&cmdUser.Del{"user_del"},
+	&cmdUser.SetCaps{"user_setcaps"},
+
+	&cmdVM.List{"vmlist"},
+	&cmdVM.ListStart{"vmlist_start"},
+	&cmdVM.ListAttach{"vmlist_attach"},
+	&cmdVM.ListStop{"vmlist_stop"},
+	&cmdVM.ListEdit{"vmlist_edit"},
+	&cmdVM.ListEditAccess{"vmlist_editaccess"},
+	&cmdVM.ListDel{"vmlist_del"},
+
+	&cmdVM.Start{"vm_start"},
+	&cmdVM.Stop{"vm_stop"},
+	&cmdVM.Attach{"vm_attach"},
+	&cmdVM.Create{"vm_create"},
+	&cmdVM.Edit{"vm_edit"},
+	&cmdVM.Del{"vm_del"},
+	&cmdVM.SetAccess{"vm_setaccess"},
+	&cmdVM.DelAccess{"vm_delaccess"},
+
+	&cmdTemplate.List{"tpl_list"},
+	&cmdTemplate.Create{"tpl_create"},
+	&cmdTemplate.Del{"tpl_del"},
 }
 
 func main() {
 	server, found := os.LookupEnv(ENV_NEXUS_SERVER)
 	if !found {
-		printlnErr("Environment variable \""+ENV_NEXUS_SERVER+"\" must be set!")
-		printlnErr("It defines the nexus server to connect to along the port number.")
-		printlnErr("Example: export "+ENV_NEXUS_SERVER+"=192.168.1.42:1077")
+		u.PrintlnErr("Environment variable \""+ENV_NEXUS_SERVER+"\" must be set!")
+		u.PrintlnErr("It defines the nexus server to connect to along the port number.")
+		u.PrintlnErr("Example: export "+ENV_NEXUS_SERVER+"=192.168.1.42:1077")
 		os.Exit(1)
 	}
 
-	pubCert, found = os.LookupEnv(ENV_NEXUS_CERT)
+	pubCert, found := os.LookupEnv(ENV_NEXUS_CERT)
 	if !found {
-		printlnErr("Environment variable \""+ENV_NEXUS_CERT+"\" must be set!")
-		printlnErr("It specifies the path to the public certificate required for encrypted communications (TLS) with the nexus server.")
-		printlnErr("Example: export "+ENV_NEXUS_CERT+"=ca-cert.pem")
+		u.PrintlnErr("Environment variable \""+ENV_NEXUS_CERT+"\" must be set!")
+		u.PrintlnErr("It specifies the path to the public certificate required for encrypted communications (TLS) with the nexus server.")
+		u.PrintlnErr("Example: export "+ENV_NEXUS_CERT+"=ca-cert.pem")
 		os.Exit(1)
 	}
 
-	if !FileExists(pubCert) {
-		printlnErr("Failed reading certificate \""+pubCert+"\"!")
+	if !u.FileExists(pubCert) {
+		u.PrintlnErr("Failed reading certificate \""+pubCert+"\"!")
 		os.Exit(1)
 	}
 
 	parts := strings.Split(server, ":")
-	hostname = parts[0]
+	hostname := parts[0]
 
+	client := resty.New()
 	client.SetRootCertificate(pubCert)
-	host = "https://"+server
+	host := "https://"+server
+
+	globals.Init(hostname, host, pubCert, client)
 
 	var appname = path.Base(os.Args[0])
 
 	if len(os.Args) < 2 {
-		printlnErr("Usage: "+appname+" CMD")
-		printlnErr("CMD is the Command to run. Except for \"login\", all Commands require an access token.")
-		printlnErr("The access token is read from the env. variable \"NEXUS_TOKEN\".")
-		printlnErr("List of supported Commands:")
+		u.PrintlnErr("Usage: "+appname+" CMD")
+		u.PrintlnErr("CMD is the Command to run. Except for \"login\", all Commands require an access token.")
+		u.PrintlnErr("The access token is read from the env. variable \"NEXUS_TOKEN\".")
+		u.PrintlnErr("List of supported Commands:")
 		padding := 20
 		for _, cmd := range cmdList {
-			printErr("    "+cmd.Name())
-			pad := strings.Repeat(" ", padding-len(cmd.Name()))
-			printlnErr(pad+cmd.Desc())
+			u.PrintErr("    "+cmd.GetName())
+			pad := strings.Repeat(" ", padding-len(cmd.GetName()))
+			u.PrintlnErr(pad+cmd.GetDesc())
 		}
 		os.Exit(1)
 	}
@@ -106,11 +103,11 @@ func main() {
 	cmdArgs := os.Args[2:]
 
 	for _, cmd := range cmdList {
-		if cmdName == cmd.Name() {
+		if cmdName == cmd.GetName() {
 			if cmdName != "login" {
 				token, found := os.LookupEnv(ENV_NEXUS_TOKEN)
 				if !found || len(token) == 0 {
-					printlnErr("Environment variable \""+ENV_NEXUS_TOKEN+"\" must be set!")
+					u.PrintlnErr("Environment variable \""+ENV_NEXUS_TOKEN+"\" must be set!")
 					os.Exit(1)
 				}
 				client.SetHeader("Content-Type", "application/json")
@@ -121,6 +118,6 @@ func main() {
 		}
 	}
 
-	printlnErr("Invalid Command")
+	u.PrintlnErr("Invalid Command")
 	os.Exit(1)
 }
\ No newline at end of file
diff --git a/src/client_cli/templateCreate.go b/src/client_cli/templateCreate.go
deleted file mode 100644
index a27cdb2169b4c965c9006e8aba5eaef3af616900..0000000000000000000000000000000000000000
--- a/src/client_cli/templateCreate.go
+++ /dev/null
@@ -1,53 +0,0 @@
-package main
-
-type CmdTemplateCreate struct {
-    name string
-}
-
-func (cmd *CmdTemplateCreate)Name() string {
-	return cmd.name
-}
- 
-func (cmd *CmdTemplateCreate)Desc() string {
-	return "Create a template"
-}
-
-func (cmd *CmdTemplateCreate)PrintUsage() {
-	printlnErr(cmd.Desc())
-	printlnErr("Usage: "+cmd.name+" vmID name access")
-	printlnErr("Notes: access is either \"public\" or \"private\"")
-}
-
-func (cmd *CmdTemplateCreate)Run(args []string) int {
-	argc := len(args)
-	if argc != 3 {
-		cmd.PrintUsage()
-		return 1
-	}
-
-	vmID := args[0]
-	name := args[1]
-	access := args[2]
-
-	type TemplateArgs struct {
-		VMID string
-		Name string
-		Access string
-	}
-			
-	templateArgs := &TemplateArgs { vmID, name, access }
-	
-	resp, err := client.R().SetBody(templateArgs).Post(host+"/templates")
-	if err != nil {
-		printlnErr("Error: "+err.Error())
-		return 1
-	}
-
-	if resp.IsSuccess() {
-		println(resp)
-		return 0
-	} else {
-		printlnErr("Error: "+resp.Status()+": "+resp.String())
-		return 1
-	}
-}
diff --git a/src/client_cli/templateDel.go b/src/client_cli/templateDel.go
deleted file mode 100644
index 96d47a0a83d9b889720635b157a36af9d5036319..0000000000000000000000000000000000000000
--- a/src/client_cli/templateDel.go
+++ /dev/null
@@ -1,46 +0,0 @@
-package main
-
-type CmdTemplateDel struct {
-    name string
-}
-
-func (cmd *CmdTemplateDel)Name() string {
-	return cmd.name
-}
- 
-func (cmd *CmdTemplateDel)Desc() string {
-	return "Delete one or more templates"
-}
-
-func (cmd *CmdTemplateDel)PrintUsage() {
-	printlnErr(cmd.Desc())
-	printlnErr("Usage: "+cmd.name+" id [id ...]")
-}
-
-func (cmd *CmdTemplateDel)Run(args []string) int {
-	argc := len(args)
-	if argc < 1 {
-		cmd.PrintUsage()
-		return 1
-	}
-
-	statusCode := 0
-
-	// Iterates through each template to delete
-	for i:= range(args) {
-		id := args[i]
-		resp, err := client.R().Delete(host+"/templates/"+id)
-		if err != nil {
-			printlnErr("Error: "+err.Error())
-			statusCode = 1
-		} else {
-			if resp.IsSuccess() {
-				println("Template \""+id+"\" deleted.")
-			} else {
-				printlnErr("Error: "+resp.Status()+": "+resp.String())
-				statusCode = 1
-			}
-		}
-	}
-	return statusCode
-}
diff --git a/src/client_cli/templateList.go b/src/client_cli/templateList.go
deleted file mode 100644
index 0b20b193be3fec0bc07576ab8f649f192a77260a..0000000000000000000000000000000000000000
--- a/src/client_cli/templateList.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package main
-
-type CmdTemplateList struct {
-    name string
-}
-
-func (cmd *CmdTemplateList)Name() string {
-	return cmd.name
-}
- 
-func (cmd *CmdTemplateList)Desc() string {
-	return "List one or more templates"
-}
-
-func (cmd *CmdTemplateList)PrintUsage() {
-	printlnErr(cmd.Desc())
-	printlnErr("Usage: "+cmd.name+" [id]")
-}
-
-func (cmd *CmdTemplateList)Run(args []string) int {
-	argc := len(args)
-	if !(argc == 0 || argc == 1) {
-		cmd.PrintUsage()
-		return 1
-	}
-
-	var url string
-	if argc == 0 {
-		url = host+"/templates"
-	} else {
-		id := args[0]
-		url = host+"/templates/"+id
-	}
-
-	resp, err := client.R().Get(url)
-	if err != nil {
-		printlnErr("Error: "+err.Error())
-		return 1
-	}
-
-	if resp.IsSuccess() {
-		println(resp)
-		return 0
-	} else {
-		printlnErr("Error: "+resp.Status()+": "+resp.String())
-		return 1
-	}
-}
diff --git a/src/client_cli/userDel.go b/src/client_cli/userDel.go
deleted file mode 100644
index 9e47f31ed42dcd5b4e4c7702f505d15e4c26307b..0000000000000000000000000000000000000000
--- a/src/client_cli/userDel.go
+++ /dev/null
@@ -1,46 +0,0 @@
-package main
-
-type CmdUserDel struct {
-    name string
-}
-
-func (cmd *CmdUserDel)Name() string {
-	return cmd.name
-}
- 
-func (cmd *CmdUserDel)Desc() string {
-	return "Delete one or more users"
-}
-
-func (cmd *CmdUserDel)PrintUsage() {
-	printlnErr(cmd.Desc())
-	printlnErr("Usage: "+cmd.name+" email [email ...]")
-}
-
-func (cmd *CmdUserDel)Run(args []string) int {
-	argc := len(args)
-	if argc < 1 {
-		cmd.PrintUsage()
-		return 1
-	}
-
-	statusCode := 0
-
-	// Iterates through each user (email) to delete
-	for i:= range(args) {
-		email := args[i]
-		resp, err := client.R().Delete(host+"/users/"+email)
-		if err != nil {
-			printlnErr("Error: "+err.Error())
-			statusCode = 1
-		} else {
-			if resp.IsSuccess() {
-				println("User "+email+" deleted.")
-			} else {
-				printlnErr("Error: "+resp.Status()+": "+resp.String())
-				statusCode = 1
-			}
-		}
-	}
-	return statusCode
-}
diff --git a/src/client_cli/userList.go b/src/client_cli/userList.go
deleted file mode 100644
index 412d5d860948d4b625a83aebb134973aa0a2b859..0000000000000000000000000000000000000000
--- a/src/client_cli/userList.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package main
-
-type CmdUserList struct {
-    name string
-}
-
-func (cmd *CmdUserList)Name() string {
-	return cmd.name
-}
- 
-func (cmd *CmdUserList)Desc() string {
-	return "List one or all users"
-}
-
-func (cmd *CmdUserList)PrintUsage() {
-	printlnErr(cmd.Desc())
-	printlnErr("Usage: "+cmd.name+" [email]")
-}
-
-func (cmd *CmdUserList)Run(args []string) int {
-	argc := len(args)
-	if !(argc == 0 || argc == 1) {
-		cmd.PrintUsage()
-		return 1
-	}
-
-	var url string
-	if argc == 0 {
-		url = host+"/users"
-	} else {
-		email := args[0]
-		url = host+"/users/"+email
-	}
-
-	resp, err := client.R().Get(url)
-	if err != nil {
-		printlnErr("Error: "+err.Error())
-		return 1
-	}
-
-	if resp.IsSuccess() {
-		println(resp)
-		return 0
-	} else {
-		printlnErr("Error: "+resp.Status()+": "+resp.String())
-		return 1
-	}
-}
diff --git a/src/client_cli/userSetCaps.go b/src/client_cli/userSetCaps.go
deleted file mode 100644
index 84b64d2467f0e0d91bd63c218a67571206bdf6ff..0000000000000000000000000000000000000000
--- a/src/client_cli/userSetCaps.go
+++ /dev/null
@@ -1,51 +0,0 @@
-package main
-
-type CmdUserSetCaps struct {
-    name string
-}
-
-func (cmd *CmdUserSetCaps)Name() string {
-	return cmd.name
-}
- 
-func (cmd *CmdUserSetCaps)Desc() string {
-	return "Set a user's capabilities"
-}
-
-func (cmd *CmdUserSetCaps)PrintUsage() {
-	printlnErr(cmd.Desc())
-	printlnErr("Usage: "+cmd.name+" email [capability1 capability2 ...]")
-}
-
-func (cmd *CmdUserSetCaps)Run(args []string) int {
-	argc := len(args)
-	if argc < 1 {
-		cmd.PrintUsage()
-		return 1
-	}
-
-	email := args[0]
-
-	type CapsArgs struct {
-		Caps map[string]int `json:"caps"  validate:"required"`
-	}
-	
-	capsArgs := &CapsArgs { make(map[string]int) }
-	for _, cap := range args[1:] {
-		capsArgs.Caps[cap] = 1
-	}
-
-	resp, err := client.R().SetBody(capsArgs).Put(host+"/users/"+email+"/caps")
-	if err != nil {
-		printlnErr("Error: "+err.Error())
-		return 1
-	}
-
-	if resp.IsSuccess() {
-		println(resp)
-		return 0
-	} else {
-		printlnErr("Error: "+resp.Status()+": "+resp.String())
-		return 1
-	}
-}
diff --git a/src/client_cli/userUpdatePwd.go b/src/client_cli/userUpdatePwd.go
deleted file mode 100644
index 11e22701446b2b6ff9c2693d869f30e4aacd53ba..0000000000000000000000000000000000000000
--- a/src/client_cli/userUpdatePwd.go
+++ /dev/null
@@ -1,73 +0,0 @@
-package main
-
-import (
-	"bytes"
-	"golang.org/x/crypto/ssh/terminal"
-)
-
-type CmdUpdatePwd struct {
-    name string
-}
-
-func (cmd *CmdUpdatePwd)Name() string {
-	return cmd.name
-}
- 
-func (cmd *CmdUpdatePwd)Desc() string {
-	return "Update the current user's password"
-}
-
-func (cmd *CmdUpdatePwd)PrintUsage() {
-	printlnErr(cmd.Desc())
-	printlnErr("Usage: "+cmd.name)
-}
-
-func (cmd *CmdUpdatePwd)Run(args []string) int {
-	argc := len(args)
-	if argc != 0 {
-		cmd.PrintUsage()
-		return 1
-	}
-
-	// Read the new password from stdin
-	print("New password: ")
-	newPwd, err := terminal.ReadPassword(0)
-	if err != nil {
-		printlnErr("Error: "+err.Error())
-		return 1
-	}
-	print("\nRetype new password: ")
-	newPwd2, err := terminal.ReadPassword(0)
-	if err != nil {
-		printlnErr("Error: "+err.Error())
-		return 1
-	}
-	println("")
-
-	if !bytes.Equal(newPwd, newPwd2) {
-		printlnErr("Sorry, passwords do not match!")
-		printlnErr("Password unchanged.")
-		return 1
-	}
-
-	pwdStr := string(newPwd)
-
-	type PwdArgs struct {
-		Pwd string
-	}
-
-	pwdArgs := &PwdArgs{pwdStr}
-	resp, err := client.R().SetBody(pwdArgs).Put(host+"/users/pwd")
-	if err != nil {
-		printlnErr("Error: "+err.Error())
-		return 1
-	} else {
-		if resp.IsSuccess() {
-			println(resp)
-			return 0
-		} else {
-			printlnErr("Error: "+resp.Status()+": "+resp.String())
-			return 1
-		}
-	}
-}
diff --git a/src/client_cli/userWhoami.go b/src/client_cli/userWhoami.go
deleted file mode 100644
index e91fff85e8356e393ad6a9defa380748df501793..0000000000000000000000000000000000000000
--- a/src/client_cli/userWhoami.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package main
-
-type CmdWhoami struct {
-    name string
-}
-
-func (cmd *CmdWhoami)Name() string {
-	return cmd.name
-}
- 
-func (cmd *CmdWhoami)Desc() string {
-	return "Display the currently authenticated user's details"
-}
-
-func (cmd *CmdWhoami)PrintUsage() {
-	printlnErr(cmd.Desc())
-	printlnErr("Usage: "+cmd.name)
-}
-
-func (cmd *CmdWhoami)Run(args []string) int {
-	argc := len(args)
-	if argc != 0 {
-		cmd.PrintUsage()
-		return 1
-	}
-
-	resp, err := client.R().Get(host+"/users/whoami")
-	if err != nil {
-		printlnErr("Error: "+err.Error())
-		return 1
-	} else {
-		if resp.IsSuccess() {
-			println(resp)
-			return 0
-		} else {
-			printlnErr("Error: "+resp.Status()+": "+resp.String())
-			return 1
-		}
-	}
-}
diff --git a/src/client_cli/utils/go.mod b/src/client_cli/utils/go.mod
new file mode 100644
index 0000000000000000000000000000000000000000..56925e5fa9687ffdaf1b2de61961d310cba7fd35
--- /dev/null
+++ b/src/client_cli/utils/go.mod
@@ -0,0 +1,3 @@
+module nexus-client/utils
+
+go 1.18
diff --git a/src/client_cli/utils.go b/src/client_cli/utils/utils.go
similarity index 65%
rename from src/client_cli/utils.go
rename to src/client_cli/utils/utils.go
index 0672a839c239be5ca2e65b1fa25c189f1f9d0781..a765f51665d63162cba6994961b604af165197b4 100644
--- a/src/client_cli/utils.go
+++ b/src/client_cli/utils/utils.go
@@ -1,26 +1,26 @@
-package main
+package utils
 
 import (
 	"fmt"
 	"os"
 )
 
-func print(a ...any) {
+func Print(a ...any) {
 	os.Stdout.WriteString(fmt.Sprint(a ...))
 }
 
-func println(a ...any) {
-	print(a...)
-	print("\n")
+func Println(a ...any) {
+	Print(a...)
+	Print("\n")
 }
 
-func printErr(a ...any) {
+func PrintErr(a ...any) {
 	os.Stderr.WriteString(fmt.Sprint(a ...))
 }
 
-func printlnErr(a ...any) {
-	printErr(a...)
-	printErr("\n")
+func PrintlnErr(a ...any) {
+	PrintErr(a...)
+	PrintErr("\n")
 }
 
 // Returns true if the specified file exists, false otherwise.
diff --git a/src/client_cli/vmCreate.go b/src/client_cli/vmCreate.go
deleted file mode 100644
index f57dbe18a7a7edc40cc46d07933a7e8680a9d61c..0000000000000000000000000000000000000000
--- a/src/client_cli/vmCreate.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package main
-
-import (
-	"strconv"
-)
-
-type CmdVMCreate struct {
-    name string
-}
-
-func (cmd *CmdVMCreate)Name() string {
-	return cmd.name
-}
- 
-func (cmd *CmdVMCreate)Desc() string {
-	return "Create a VM"
-}
-
-func (cmd *CmdVMCreate)PrintUsage() {
-	printlnErr(cmd.Desc())
-	printlnErr("Usage: "+cmd.name+" name cpus ram nic template")
-	printlnErr("name        name of the VM")
-	printlnErr("cpus        number of CPUs, between 1 and 16")
-	printlnErr("ram         amount of RAM in MB,  between 512 and 32768")
-	printlnErr("nic         network interface, either \"none\" or \"user\"")
-	printlnErr("template    ID of the template to VM will be based on")
-
-}
-
-func (cmd *CmdVMCreate)Run(args []string) int {
-	argc := len(args)
-	if argc != 5 {
-		cmd.PrintUsage()
-		return 1
-	}
-
-	ncpus, err := strconv.Atoi(args[1])
-	if err != nil {
-		printlnErr("Invalid number of CPU(s)")
-		return 1
-	}
-
-	ram, err := strconv.Atoi(args[2])
-	if err != nil {
-		printlnErr("Invalid amount of RAM")
-		return 1
-	}
-
-	nic := args[3]
-
-	type VMArgs struct {
-		Name string
-		Cpus int
-		Ram int
-		Nic string
-		TemplateID string
-	}
-			
-	vmArgs := &VMArgs {
-		Name: args[0],
-		Cpus: ncpus,
-		Ram: ram,
-		Nic: nic,
-		TemplateID: args[4],
-	}
-
-	resp, err := client.R().SetBody(vmArgs).Post(host+"/vms")
-	if err != nil {
-		printlnErr("Error: "+err.Error())
-		return 1
-	}
-
-	if resp.IsSuccess() {
-		println(resp)
-		return 0
-	} else {
-		printlnErr("Error: "+resp.Status()+": "+resp.String())
-		return 1
-	}
-}
diff --git a/src/client_cli/vmDel.go b/src/client_cli/vmDel.go
deleted file mode 100644
index 79897691bb099c0c6951159d684f1d0b1601c6fd..0000000000000000000000000000000000000000
--- a/src/client_cli/vmDel.go
+++ /dev/null
@@ -1,46 +0,0 @@
-package main
-
-type CmdVMDel struct {
-    name string
-}
-
-func (cmd *CmdVMDel)Name() string {
-	return cmd.name
-}
- 
-func (cmd *CmdVMDel)Desc() string {
-	return "Delete one or more VMs"
-}
-
-func (cmd *CmdVMDel)PrintUsage() {
-	printlnErr(cmd.Desc())
-	printlnErr("Usage: "+cmd.name+" vmID [vmID ...]")
-}
-
-func (cmd *CmdVMDel)Run(args []string) int {
-	argc := len(args)
-	if argc < 1 {
-		cmd.PrintUsage()
-		return 1
-	}
-
-	statusCode := 0
-
-	// Iterates through each uuid to delete
-	for i:= range(args) {
-		uuid := args[i]
-		resp, err := client.R().Delete(host+"/vms/"+uuid)
-		if err != nil {
-			printlnErr("Error: "+err.Error())
-			statusCode = 1
-		} else {
-			if resp.IsSuccess() {
-				println("VM "+uuid+" deleted.")
-			} else {
-				printlnErr("Error: "+resp.Status()+": "+resp.String())
-				statusCode = 1
-			}
-		}
-	}
-	return statusCode
-}
diff --git a/src/client_cli/vmDelAccess.go b/src/client_cli/vmDelAccess.go
deleted file mode 100644
index cdecbd610ce010535cac4e71792a4386667f75d9..0000000000000000000000000000000000000000
--- a/src/client_cli/vmDelAccess.go
+++ /dev/null
@@ -1,43 +0,0 @@
-package main
-
-type CmdVMDelAccess struct {
-    name string
-}
-
-func (cmd *CmdVMDelAccess)Name() string {
-	return cmd.name
-}
- 
-func (cmd *CmdVMDelAccess)Desc() string {
-	return "Delete the VM Access for a given user"
-}
-
-func (cmd *CmdVMDelAccess)PrintUsage() {
-	printlnErr(cmd.Desc())
-	printlnErr("Usage: "+cmd.name+" vmID email")
-}
-
-func (cmd *CmdVMDelAccess)Run(args []string) int {
-	argc := len(args)
-	if argc != 2 {
-		cmd.PrintUsage()
-		return 1
-	}
-
-	vmID := args[0]
-	email := args[1]
-
-	resp, err := client.R().Delete(host+"/vms/"+vmID+"/access/"+email)
-	if err != nil {
-		printlnErr("Error: "+err.Error())
-		return 1
-	}
-
-	if resp.IsSuccess() {
-		println(resp)
-		return 0
-	} else {
-		printlnErr("Error: "+resp.Status()+": "+resp.String())
-		return 1
-	}
-}
diff --git a/src/client_cli/vmList.go b/src/client_cli/vmList.go
deleted file mode 100644
index e09d7ba055e18e7d78ede05b73598b22f1ccba7d..0000000000000000000000000000000000000000
--- a/src/client_cli/vmList.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package main
-
-type CmdVMList struct {
-    name string
-}
-
-func (cmd *CmdVMList)Name() string {
-	return cmd.name
-}
- 
-func (cmd *CmdVMList)Desc() string {
-	return "List all VMs that can be listed"
-}
-
-func (cmd *CmdVMList)PrintUsage() {
-	printUsage(cmd)
-}
-
-func (cmd *CmdVMList)Run(args []string) int {
-	return getFilteredVMs(cmd, args, "/vms/list")
-}
diff --git a/src/client_cli/vmListAttach.go b/src/client_cli/vmListAttach.go
deleted file mode 100644
index b1dff76e1131f68a88918d02d1bf3fe26e50f18e..0000000000000000000000000000000000000000
--- a/src/client_cli/vmListAttach.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package main
-
-type CmdVMListAttach struct {
-    name string
-}
-
-func (cmd *CmdVMListAttach)Name() string {
-	return cmd.name
-}
- 
-func (cmd *CmdVMListAttach)Desc() string {
-	return "List VMs that can be attached to"
-}
-
-func (cmd *CmdVMListAttach)PrintUsage() {
-	printUsage(cmd)
-}
-
-func (cmd *CmdVMListAttach)Run(args []string) int {
-	return getFilteredVMs(cmd, args, "/vms/attach")
-}
diff --git a/src/client_cli/vmListDel.go b/src/client_cli/vmListDel.go
deleted file mode 100644
index 7bf06923a3ca7d2a8ef8ea4ab31969f85b567d53..0000000000000000000000000000000000000000
--- a/src/client_cli/vmListDel.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package main
-
-type CmdVMListDel struct {
-    name string
-}
-
-func (cmd *CmdVMListDel)Name() string {
-	return cmd.name
-}
- 
-func (cmd *CmdVMListDel)Desc() string {
-	return "List VMs that can be deleted"
-}
-
-func (cmd *CmdVMListDel)PrintUsage() {
-	printUsage(cmd)
-}
-
-func (cmd *CmdVMListDel)Run(args []string) int {
-	return getFilteredVMs(cmd, args, "/vms/del")
-}
diff --git a/src/client_cli/vmListEdit.go b/src/client_cli/vmListEdit.go
deleted file mode 100644
index a37d224c6194c134f4ab75cf9c8dd0ca23686d84..0000000000000000000000000000000000000000
--- a/src/client_cli/vmListEdit.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package main
-
-type CmdVMListEdit struct {
-    name string
-}
-
-func (cmd *CmdVMListEdit)Name() string {
-	return cmd.name
-}
- 
-func (cmd *CmdVMListEdit)Desc() string {
-	return "List VMs that can be edited"
-}
-
-func (cmd *CmdVMListEdit)PrintUsage() {
-	printUsage(cmd)
-}
-
-func (cmd *CmdVMListEdit)Run(args []string) int {
-	return getFilteredVMs(cmd, args, "/vms/edit")
-}
diff --git a/src/client_cli/vmListEditAccess.go b/src/client_cli/vmListEditAccess.go
deleted file mode 100644
index c005277ec6fc2366596059c78cbd7e32d330d3bc..0000000000000000000000000000000000000000
--- a/src/client_cli/vmListEditAccess.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package main
-
-type CmdVMListEditAccess struct {
-    name string
-}
-
-func (cmd *CmdVMListEditAccess)Name() string {
-	return cmd.name
-}
- 
-func (cmd *CmdVMListEditAccess)Desc() string {
-	return "List VMs that can have their VM access edited"
-}
-
-func (cmd *CmdVMListEditAccess)PrintUsage() {
-	printUsage(cmd)
-}
-
-func (cmd *CmdVMListEditAccess)Run(args []string) int {
-	return getFilteredVMs(cmd, args, "/vms/editaccess")
-}
diff --git a/src/client_cli/vmListStart.go b/src/client_cli/vmListStart.go
deleted file mode 100644
index 629d3dd71b42fb80a8f94f4512d5c7e47ce1c700..0000000000000000000000000000000000000000
--- a/src/client_cli/vmListStart.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package main
-
-type CmdVMListStart struct{
-    name string
-}
-
-func (cmd *CmdVMListStart)Name() string {
-	return cmd.name
-}
- 
-func (cmd *CmdVMListStart)Desc() string {
-	return "List VMs that can be started"
-}
-
-func (cmd *CmdVMListStart)PrintUsage() {
-	printUsage(cmd)
-}
-
-func (cmd *CmdVMListStart)Run(args []string) int {
-	return getFilteredVMs(cmd, args, "/vms/start")
-}
diff --git a/src/client_cli/vmListStop.go b/src/client_cli/vmListStop.go
deleted file mode 100644
index b45a85cf7ce04047d61bd6f08a291b5324e1d5b1..0000000000000000000000000000000000000000
--- a/src/client_cli/vmListStop.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package main
-
-type CmdVMListStop struct {
-    name string
-}
-
-func (cmd *CmdVMListStop)Name() string {
-	return cmd.name
-}
- 
-func (cmd *CmdVMListStop)Desc() string {
-	return "List VMs that can be stopped"
-}
-
-func (cmd *CmdVMListStop)PrintUsage() {
-	printUsage(cmd)
-}
-
-func (cmd *CmdVMListStop)Run(args []string) int {
-	return getFilteredVMs(cmd, args, "/vms/stop")
-}
diff --git a/src/client_cli/vmStart.go b/src/client_cli/vmStart.go
deleted file mode 100644
index b84830c6232fa7c487d0d18d7182c427ff4f7f1c..0000000000000000000000000000000000000000
--- a/src/client_cli/vmStart.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package main
-
-type CmdVMStart struct {
-    name string
-}
-
-func (cmd *CmdVMStart)Name() string {
-	return cmd.name
-}
- 
-func (cmd *CmdVMStart)Desc() string {
-	return "Start a VM"
-}
-
-func (cmd *CmdVMStart)PrintUsage() {
-	printlnErr(cmd.Desc())
-	printlnErr("Usage: "+cmd.name+" vmID")
-}
-
-func (cmd *CmdVMStart)Run(args []string) int {
-	argc := len(args)
-	if argc != 1 {
-		cmd.PrintUsage()
-		return 1
-	}
-
-	uuid := args[0]
-	resp, err := client.R().Put(host+"/vms/"+uuid+"/start")
-	if err != nil {
-		printlnErr("Error: "+err.Error())
-		return 1
-	}
-
-	if resp.IsSuccess() {
-		println(resp)
-		return 0
-	} else {
-		printlnErr("Error: "+resp.Status()+": "+resp.String())
-		return 1
-	}
-}
diff --git a/src/client_cli/vmStop.go b/src/client_cli/vmStop.go
deleted file mode 100644
index ea02bf39a1f27b1825b20e43f8508d1e9eadbf4c..0000000000000000000000000000000000000000
--- a/src/client_cli/vmStop.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package main
-
-type CmdVMStop struct {
-    name string
-}
-
-func (cmd *CmdVMStop)Name() string {
-	return cmd.name
-}
- 
-func (cmd *CmdVMStop)Desc() string {
-	return "Stop a VM"
-}
-
-func (cmd *CmdVMStop)PrintUsage() {
-	printlnErr(cmd.Desc())
-	printlnErr("Usage: "+cmd.name+" vmID")
-}
-
-func (cmd *CmdVMStop)Run(args []string) int {
-	argc := len(args)
-	if argc != 1 {
-		cmd.PrintUsage()
-		return 1
-	}
-
-	uuid := args[0]
-	resp, err := client.R().Put(host+"/vms/"+uuid+"/stop")
-	if err != nil {
-		printlnErr("Error: "+err.Error())
-		return 1
-	}
-
-	if resp.IsSuccess() {
-		println(resp)
-		return 0
-	} else {
-		printlnErr("Error: "+resp.Status()+": "+resp.String())
-		return 1
-	}
-}