diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..2d0b03e5c73fad5da998f1fe145604b17a18b4d3
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+useradm
diff --git a/cmd/create.go b/cmd/create.go
deleted file mode 100644
index 55af07d49acaaac3297ab52b404cf397e7be9d6a..0000000000000000000000000000000000000000
--- a/cmd/create.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package cmd
-
-import (
-    "github.com/spf13/cobra"
-)
-
-var createConfirm bool
-
-var createCmd = &cobra.Command{
-    Use:   "create",
-    Short: "Create resources",
-}
-
-func init() {
-    rootCmd.AddCommand(createCmd)
-
-    createCmd.PersistentFlags().BoolVarP(
-        &createConfirm,
-        "confirm",
-        "y",
-        false,
-        "Skip confirmation prompt",
-    )
-}
-
diff --git a/cmd/create_group.go b/cmd/create_group.go
deleted file mode 100644
index 5fbb2bbc185560dc76a35fadc856a67b5a6bd3fe..0000000000000000000000000000000000000000
--- a/cmd/create_group.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package cmd
-
-import (
-    "os"
-    "fmt"
-    "bufio"
-    "strings"
-
-    "github.com/spf13/cobra"
-)
-
-var groupName string
-
-var createGroupCmd = &cobra.Command{
-    Use:   "group",
-    Short: "Create a new group",
-    Run: func(cmd *cobra.Command, args []string) {
-
-        fmt.Printf("Groupname: %s\n", groupName)
-
-        // Confirmation logic
-        if !createConfirm {
-            fmt.Print("Proceed with group creation? [y/N] ")
-            reader := bufio.NewReader(os.Stdin)
-            response, _ := reader.ReadString('\n')
-            if strings.TrimSpace(strings.ToLower(response)) != "y" {
-                fmt.Println("Aborted.")
-                return
-            }
-        }
-
-        fmt.Println("Done!")
-    },
-}
-
-func init() {
-    createCmd.AddCommand(createGroupCmd)
-    
-    // Possible Flags
-    createGroupCmd.Flags().StringVarP(&groupName,    "groupname", "e", "", "Group name (use quotes for spaces)")
-    
-    // Required Flags
-    createGroupCmd.MarkFlagRequired("groupname")
-}
-
diff --git a/cmd/create_user.go b/cmd/create_user.go
deleted file mode 100644
index ff2e2a91bfcc41a27d405eeff8e301f39805cc55..0000000000000000000000000000000000000000
--- a/cmd/create_user.go
+++ /dev/null
@@ -1,93 +0,0 @@
-package cmd
-
-import (
-    "os"
-    "fmt"
-    "bufio"
-    "strings"
-    
-    "github.com/spf13/cobra"
-)
-
-var (
-    userGrr         string
-    userLtype       string
-    userPath        string
-    userName        string
-    userLogin       string
-    userGroup       string
-    userShell       string
-    userHomedir     string
-    userPassword    string
-)
-
-var createUserCmd = &cobra.Command{
-    Use:   "user",
-    Short: "Create a new user",
-    Run: func(cmd *cobra.Command, args []string) {
-
-        // Build user info string
-        userInfo := fmt.Sprintf(
-            `User Configuration:
-Name:     %s
-Login:    %s
-Type:     %s
-Group:    %s
-Shell:    %s
-HomeDir:  %s
-Password: %s
-WebPath:  %s`,
-            userName,
-            ifThenElse(userLogin != "", userLogin, "[auto-generate]"),
-            userLtype,
-            userGroup,
-            userShell,
-            userHomedir,
-            ifThenElse(userPassword != "", "[set]", "[auto-generate]"),
-            userPath,
-        )
-
-        fmt.Println(userInfo)
-
-        // Confirmation logic
-        if !createConfirm {
-            fmt.Print("Proceed with user creation? [y/N] ")
-            reader := bufio.NewReader(os.Stdin)
-            response, _ := reader.ReadString('\n')
-            if strings.TrimSpace(strings.ToLower(response)) != "y" {
-                fmt.Println("Aborted.")
-                return
-            }
-        }
-
-        fmt.Println("Done!")
-    },
-}
-
-func init() {
-    createCmd.AddCommand(createUserCmd)
-    
-    // Possible Flags
-    createUserCmd.Flags().StringVarP(&userGrr,      "grr",      "r", "",          "User GRR, required for ini type")
-    createUserCmd.Flags().StringVarP(&userLtype,    "type",     "t", "ini",       "Type of auto-generated login: ini, first or last")
-    createUserCmd.Flags().StringVarP(&userPath,     "path",     "w", "",          "Path to webdir      (e.g. path/login)")
-    createUserCmd.Flags().StringVarP(&userName,     "name",     "n", "",          "User full name      (use quotes for spaces)")
-    createUserCmd.Flags().StringVarP(&userLogin,    "login",    "l", "",          "User login name     (auto-generated if empty)")
-    createUserCmd.Flags().StringVarP(&userGroup,    "group",    "g", "",          "User initial group")
-    createUserCmd.Flags().StringVarP(&userShell,    "shell",    "s", "/bin/bash", "Full path to shell ")
-    createUserCmd.Flags().StringVarP(&userHomedir,  "homedir",  "d", "",          "Home directory path (/home/group/login if empty)")
-    createUserCmd.Flags().StringVarP(&userPassword, "password", "p", "",          "User password       (auto-generated if empty)")
-    
-    // Required Flags
-    createUserCmd.MarkFlagRequired("name")
-    createUserCmd.MarkFlagRequired("type")
-    createUserCmd.MarkFlagRequired("group")
-}
-
-func ifThenElse(condition bool, a string, b string) string {
-    if condition {
-        return a
-    }
-    return b
-}
-
diff --git a/cmd/group.go b/cmd/group.go
new file mode 100644
index 0000000000000000000000000000000000000000..d3da7ee746f745bdf2525a847f9832c6de3deb00
--- /dev/null
+++ b/cmd/group.go
@@ -0,0 +1,16 @@
+package cmd
+
+import (
+	"github.com/spf13/cobra"
+	"gitlab.c3sl.ufpr.br/tss24/useradm/cmd/group"
+)
+
+var groupCmd = &cobra.Command{
+	Use:   "group",
+	Short: "User subcommand",
+}
+
+func init() {
+	groupCmd.AddCommand(group.CreateCmd)
+	groupCmd.AddCommand(group.DeleteCmd)
+}
diff --git a/cmd/group/create.go b/cmd/group/create.go
new file mode 100644
index 0000000000000000000000000000000000000000..1f2a9a6bd5828623672008f13b08018ca31a5e32
--- /dev/null
+++ b/cmd/group/create.go
@@ -0,0 +1,48 @@
+package group
+
+import (
+	"bufio"
+	"fmt"
+	"os"
+	"strings"
+
+	"github.com/spf13/cobra"
+)
+
+var CreateCmd = &cobra.Command{
+	Use:   "create",
+	Short: "Create new group",
+	RunE:  createGroupFunc,
+}
+
+func init() {
+	CreateCmd.Flags().StringP("groupname", "e", "", "Group name (use quotes for spaces)")
+	CreateCmd.Flags().BoolP("confirm", "y", false, "Skip confirmation prompt")
+
+	CreateCmd.MarkFlagRequired("groupname")
+}
+
+func createGroupFunc(cmd *cobra.Command, args []string) error {
+	groupName, err := cmd.Flags().GetString("groupname")
+	if err != nil {
+		return err
+	}
+	confirm, err := cmd.Flags().GetBool("confirm")
+	if err != nil {
+		return err
+	}
+	fmt.Printf("Groupname: %s\n", groupName)
+
+	if !confirm {
+		fmt.Print("Proceed with group creation? [y/N] ")
+		reader := bufio.NewReader(os.Stdin)
+		response, _ := reader.ReadString('\n')
+		if strings.TrimSpace(strings.ToLower(response)) != "y" {
+			fmt.Println("Aborted.")
+			os.Exit(1)
+		}
+	}
+
+	fmt.Println("Done!")
+	return nil
+}
diff --git a/cmd/group/delete.go b/cmd/group/delete.go
new file mode 100644
index 0000000000000000000000000000000000000000..7fdbd7306bb80d882d0acc5fe8a9a0c650cea471
--- /dev/null
+++ b/cmd/group/delete.go
@@ -0,0 +1,13 @@
+package group
+
+import "github.com/spf13/cobra"
+
+var DeleteCmd = &cobra.Command{
+	Use:   "delete",
+	Short: "Delete a group",
+	RunE:  deleteRun,
+}
+
+func deleteRun(cmd *cobra.Command, args []string) error {
+	return nil
+}
diff --git a/cmd/root.go b/cmd/root.go
index 5ea7a7d6129999ed4e8360ff2c54310f117812ef..ac746c1428b4b82e0e1f24fd39bdbf84431b418c 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -1,13 +1,12 @@
 package cmd
 
 import (
+	"fmt"
 	"os"
 
 	"github.com/spf13/cobra"
 )
 
-
-
 var rootCmd = &cobra.Command{
 	Use:   "useradm",
 	Short: "A CLI to help administrate the user account in DINF",
@@ -20,12 +19,12 @@ made as an update for the previous version.`,
 func Execute() {
 	err := rootCmd.Execute()
 	if err != nil {
+		fmt.Fprintf(os.Stderr, "cmd: %v", err)
 		os.Exit(1)
 	}
 }
 
 func init() {
-	rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
+	rootCmd.AddCommand(userCmd)
+	rootCmd.AddCommand(groupCmd)
 }
-
-
diff --git a/cmd/user.go b/cmd/user.go
new file mode 100644
index 0000000000000000000000000000000000000000..3208b8ddd149d0761d1addbbf1febf16290d4f26
--- /dev/null
+++ b/cmd/user.go
@@ -0,0 +1,18 @@
+package cmd
+
+import (
+	"github.com/spf13/cobra"
+	"gitlab.c3sl.ufpr.br/tss24/useradm/cmd/user"
+)
+
+var userCmd = &cobra.Command{
+	Use:   "user",
+	Short: "User subcommand",
+}
+
+func init() {
+	userCmd.AddCommand(user.CreateCmd)
+	userCmd.AddCommand(user.DeleteCmd)
+	userCmd.AddCommand(user.ModCmd)
+	userCmd.AddCommand(user.ShowCmd)
+}
diff --git a/cmd/user/create.go b/cmd/user/create.go
new file mode 100644
index 0000000000000000000000000000000000000000..455b98e5c7431cf9c97e6e51bc2957d99139b3d1
--- /dev/null
+++ b/cmd/user/create.go
@@ -0,0 +1,115 @@
+package user
+
+import (
+	"bufio"
+	"fmt"
+	"os"
+	"strings"
+
+	"github.com/spf13/cobra"
+	"gitlab.c3sl.ufpr.br/tss24/useradm/model"
+)
+
+var CreateCmd = &cobra.Command{
+	Use:   "create",
+	Short: "Create new user",
+	RunE:  createUserFunc,
+}
+
+func init() {
+	// Possible Flags
+	CreateCmd.Flags().StringP("grr", "r", "", "User GRR, required for ini type")
+	CreateCmd.Flags().StringP("type", "t", "ini", "Type of auto-generated login: ini, first or last")
+	CreateCmd.Flags().StringP("path", "w", "", "Path to webdir      (e.g. path/login)")
+	CreateCmd.Flags().StringP("name", "n", "", "User full name      (use quotes for spaces)")
+	CreateCmd.Flags().StringP("login", "l", "", "User login name     (auto-generated if empty)")
+	CreateCmd.Flags().StringP("group", "g", "", "User initial group")
+	CreateCmd.Flags().StringP("shell", "s", "/bin/bash", "Full path to shell ")
+	CreateCmd.Flags().StringP("homedir", "d", "", "Home directory path (/home/group/login if empty)")
+	CreateCmd.Flags().StringP("password", "p", "", "User password       (auto-generated if empty)")
+
+	// Required Flags
+	CreateCmd.MarkFlagRequired("name")
+	CreateCmd.MarkFlagRequired("type")
+	CreateCmd.MarkFlagRequired("group")
+
+	CreateCmd.Flags().BoolP("confirm", "y", false, "Skip confirmation prompt")
+}
+
+func createUserFunc(cmd *cobra.Command, args []string) error {
+	confirm, err := cmd.Flags().GetBool("confirm")
+	if err != nil {
+		return err
+	}
+	userName, err := cmd.Flags().GetString("name")
+	if err != nil {
+		return err
+	}
+	userType, err := cmd.Flags().GetString("type")
+	if err != nil {
+		return err
+	}
+	userGroup, err := cmd.Flags().GetString("group")
+	if err != nil {
+		return err
+	}
+	userGRR, err := cmd.Flags().GetString("grr")
+	if err != nil {
+		return err
+	}
+	userPath, err := cmd.Flags().GetString("path")
+	if err != nil {
+		return err
+	}
+	userLogin, err := cmd.Flags().GetString("login")
+	if err != nil {
+		return err
+	}
+	userShell, err := cmd.Flags().GetString("shell")
+	if err != nil {
+		return err
+	}
+	userHomedir, err := cmd.Flags().GetString("homedir")
+	if err != nil {
+		return err
+	}
+	userPassword, err := cmd.Flags().GetString("password")
+	if err != nil {
+		return err
+	}
+
+	user := model.User{
+		Name:     userName,
+		Ltype:    userType,
+		Group:    userGroup,
+		GRR:      userGRR,
+		Path:     userPath,
+		Login:    ifThenElse(userLogin != "", userLogin, "[auto-generate]"),
+		Shell:    userShell,
+		Homedir:  userHomedir,
+		Password: ifThenElse(userPassword != "", "[set]", "[auto-generate]"),
+	}
+
+	fmt.Println(user.ToString())
+
+	if !confirm {
+		fmt.Print("Proceed with user creation? [y/N] ")
+		reader := bufio.NewReader(os.Stdin)
+		response, _ := reader.ReadString('\n')
+		if strings.TrimSpace(strings.ToLower(response)) != "y" {
+			fmt.Fprintln(os.Stderr, "Aborted.")
+			os.Exit(1)
+		}
+	}
+
+	fmt.Println("Done!")
+
+	return nil
+}
+
+func ifThenElse(condition bool, a string, b string) string {
+	if condition {
+		return a
+	}
+	return b
+}
diff --git a/cmd/user/delete.go b/cmd/user/delete.go
new file mode 100644
index 0000000000000000000000000000000000000000..a55844e6e4486dbfa191367d9690501b6ff0a4c9
--- /dev/null
+++ b/cmd/user/delete.go
@@ -0,0 +1,8 @@
+package user
+
+import "github.com/spf13/cobra"
+
+var DeleteCmd = &cobra.Command{
+	Use:   "delete",
+	Short: "Deleta a user",
+}
diff --git a/cmd/user/mod.go b/cmd/user/mod.go
new file mode 100644
index 0000000000000000000000000000000000000000..66b2a59260670752a4dfaef7b037a22177feef45
--- /dev/null
+++ b/cmd/user/mod.go
@@ -0,0 +1,8 @@
+package user
+
+import "github.com/spf13/cobra"
+
+var ModCmd = &cobra.Command{
+	Use:   "mod",
+	Short: "Modify user information",
+}
diff --git a/cmd/user/show.go b/cmd/user/show.go
new file mode 100644
index 0000000000000000000000000000000000000000..dffc3b9195301c9156dc966981bceb37ad77f937
--- /dev/null
+++ b/cmd/user/show.go
@@ -0,0 +1,8 @@
+package user
+
+import "github.com/spf13/cobra"
+
+var ShowCmd = &cobra.Command{
+	Use:   "show",
+	Short: "Display user information",
+}
diff --git a/model/user.go b/model/user.go
new file mode 100644
index 0000000000000000000000000000000000000000..0036ff13ed7e763f2ee7817b83e394838d635ef3
--- /dev/null
+++ b/model/user.go
@@ -0,0 +1,28 @@
+package model
+
+import "fmt"
+
+type User struct {
+	GRR      string
+	Ltype    string
+	Path     string
+	Name     string
+	Login    string
+	Group    string
+	Shell    string
+	Homedir  string
+	Password string
+}
+
+func (u *User) ToString() string {
+	return fmt.Sprintf(`User:
+	Name:     %s
+	Login:    %s
+	Type:     %s
+	Group:    %s
+	Shell:    %s
+	HomeDir:  %s
+	Password: %s
+	WebPath:  %s`,
+		u.Name, u.Login, u.Ltype, u.Group, u.Shell, u.Homedir, u.Password, u.Path)
+}