diff --git a/group_manager.py b/group_manager.py
new file mode 100755
index 0000000000000000000000000000000000000000..3422dc84b761f3ea0d4b97af247f44bb01a00a0d
--- /dev/null
+++ b/group_manager.py
@@ -0,0 +1,146 @@
+#!/usr/bin/env python3
+import argparse
+import grp
+import json
+import pika
+import pwd
+import rabbit_config as rcfg
+import sys
+import uuid
+from rc_rmq import RCRMQ
+from rc_util import get_caller_info, timeout
+
+
+# Instantiate rabbitmq object
+rc_rmq = RCRMQ({"exchange": rcfg.Exchange, "exchange_type": "topic"})
+
+
+def user_exists(username):
+    try:
+        pwd.getpwnam(username)
+    except KeyError:
+        return False
+    return True
+
+
+def group_exists(groupname):
+    try:
+        grp.getgrnam(groupname)
+    except KeyError:
+        return False
+    return True
+
+
+@timeout(rcfg.Function_timeout)
+def manage_group(op, usernames, groupname, debug=False):
+    callback_queue = rc_rmq.bind_queue(exclusive=True)
+    rpc_queue = f"group_member.{op}"
+    corr_id = str(uuid.uuid4())
+    status = dict.fromkeys(usernames, False)
+    response = 0
+
+    interface = "CLI"
+    executed_by, host = get_caller_info()
+
+    def handler(ch, method, properties, body):
+        if debug:
+            print("Message received:")
+            print(body)
+
+        nonlocal corr_id
+        nonlocal status
+        nonlocal response
+        msg = json.loads(body)
+        username = msg["username"]
+
+        if properties.correlation_id == corr_id:
+            status[username] = msg["success"]
+            response += 1
+            if not msg["success"]:
+                print(f"{username}: Something's wrong, please try again.")
+
+        if len(status) == response:
+            rc_rmq.stop_consume()
+            rc_rmq.disconnect()
+
+    if debug:
+        print(f"Adding user(s) {', '.join(usernames)} to group {groupname}")
+        print(f"Callback queue: {callback_queue}, correlation_id: {corr_id}")
+
+    for user in usernames:
+        rc_rmq.publish_msg(
+            {
+                "routing_key": rpc_queue,
+                "props": pika.BasicProperties(
+                    correlation_id=corr_id, reply_to=callback_queue
+                ),
+                "msg": {
+                    "groups": {f"{op}": [f"{groupname}"]},
+                    "username": user,
+                    "host": host,
+                    "executed_by": executed_by,
+                    "interface": interface,
+                },
+            }
+        )
+
+    rc_rmq.start_consume(
+        {
+            "queue": callback_queue,
+            "exclusive": True,
+            "bind": False,
+            "cb": handler,
+        }
+    )
+
+    print("Done")
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser(description="Group management script")
+    parser.add_argument("--debug", action="store_true", help="Debug mode")
+    parser.add_argument(
+        "-d",
+        "--delete",
+        action="store_true",
+        help="Delete the user(s) from the group",
+    )
+    parser.add_argument(
+        "-g", "--group", required=True, help="The Group to add the user(s)"
+    )
+    parser.add_argument(
+        "users",
+        metavar="USER",
+        nargs="+",
+        help="User(s) to be add to the group",
+    )
+    args = parser.parse_args()
+
+    exist_users = []
+    miss = False
+
+    # Check if all of the users exist
+    for user in args.users:
+        if not user_exists(user):
+            print(f"{user} does not exist.", file=sys.stderr)
+            miss = True
+        else:
+            exist_users.append(user)
+
+    # Check if the group exists
+    if not group_exists(args.group):
+        print(f"{args.group} does not exist.", file=sys.stderr)
+        miss = True
+
+    if miss:
+        print("A user and/or group does not exist.", file=sys.stderr)
+        print("Abort.", file=sys.stderr)
+        exit(1)
+
+    elif exist_users:
+        op = "remove" if args.delete else "add"
+        manage_group(op, exist_users, args.group, args.debug)
+    else:
+        print("No user to change", file=sys.stderr)
+        print("Abort.", file=sys.stderr)
+        sys.exit(1)
diff --git a/prod_rmq_agents/group_member.py b/prod_rmq_agents/group_member.py
index cda7e5ac0bdf97f4ef953cc4b3fde4951b65143f..ae7e1f2a8a7b644188ac70867f48ab9387523d79 100644
--- a/prod_rmq_agents/group_member.py
+++ b/prod_rmq_agents/group_member.py
@@ -1,11 +1,11 @@
 #!/usr/bin/env python
-import os
+import dataset
 import json
 import pika
 import shlex
 import rc_util
-from subprocess import Popen,PIPE
-from pathlib import Path
+from datetime import datetime
+from subprocess import Popen, PIPE
 from rc_rmq import RCRMQ
 import rabbit_config as rcfg
 
@@ -14,85 +14,142 @@ task = "group_member"
 args = rc_util.get_args()
 logger = rc_util.get_logger(args)
 
+# Initialize db
+db = dataset.connect(f"sqlite:///{rcfg.db_path}/user_reg.db")
+table = db["groups"]
+
 # Instantiate rabbitmq object
 rc_rmq = RCRMQ({"exchange": rcfg.Exchange, "exchange_type": "topic"})
 
 
+def insert_db(operation, groupname, msg):
+    if operation == "remove":
+        op = 0
+    elif operation == "add":
+        op = 1
+
+    # SQL insert
+    table.insert(
+        {
+            "user": msg["username"],
+            "group": groupname,
+            "operation": op,
+            "date": datetime.now(),
+            "host": msg["host"],
+            "executed_by": msg["executed_by"],
+            "interface": msg["interface"],
+        }
+    )
+
+
 def group_member(ch, method, properties, body):
+    """
+    Properties:
+      correlation_id (str): The UUID for the request.
+      reply_to       (str): The RabbitMQ queue name for reply to send to.
+
+    Message(body):
+      username    (str): The user to be added/removed from groups.
+      groups     (dict): A dictionary with `add` or `remove` key.
+        add      (list): A list of groups to be added for the user.
+        remove   (list): A list of groups to be removed for the user.
+      executed_by (str): The user who request the change.
+      host        (str): Hostname where the request comes from.
+      interface   (str): whether it's from CLI or WebUI.
+
+    Returns:
+      status (bool): Whether or not the operation executed successfully.
+      errmsg  (str): Detailed error message if operation failed.
+      task    (str): The task name of the agent who handle the message.
+    """
     msg = json.loads(body)
     username = msg["username"]
-    action = msg["action"]
     msg["task"] = task
-    state = msg["state"]
 
     try:
-        if 'remove' in msg["groups"]:
+        if "remove" in msg["groups"]:
             for each_group in msg["groups"]["remove"]:
-                logger.debug(f'Removing user {username} from group {each_group}')
+                logger.debug(
+                    f"Removing user {username} from group {each_group}"
+                )
                 if str(rcfg.bright_cm_version).split(".")[0] == "8":
-                    grp_remove_user_cmd = f'/cm/local/apps/cmd/bin/cmsh -n -c "group; removefrom {each_group} groupmembers {username}; commit;"'
+                    grp_remove_user_cmd = (
+                        '/cm/local/apps/cmd/bin/cmsh -n -c "group; removefrom'
+                        f' {each_group} groupmembers {username}; commit;"'
+                    )
                 else:
-                    grp_remove_user_cmd = f'/cm/local/apps/cmd/bin/cmsh -n -c "group; removefrom {each_group} members {username}; commit;"'
-
-                logger.info(f'Running command: {grp_remove_user_cmd}')
-                proc = Popen(shlex.split(grp_remove_user_cmd), stdout=PIPE, stderr=PIPE)
-                out,err = proc.communicate()
-                logger.debug(f'Result: {err}')
-                logger.info(f'User {username} is removed from {each_group} group')
-
-        if 'add' in msg["groups"]:
+                    grp_remove_user_cmd = (
+                        '/cm/local/apps/cmd/bin/cmsh -n -c "group; removefrom'
+                        f' {each_group} members {username}; commit;"'
+                    )
+
+                logger.info(f"Running command: {grp_remove_user_cmd}")
+                proc = Popen(
+                    shlex.split(grp_remove_user_cmd), stdout=PIPE, stderr=PIPE
+                )
+                out, err = proc.communicate()
+                logger.debug(f"Result: {err}")
+                logger.info(
+                    f"User {username} is removed from {each_group} group"
+                )
+                insert_db("remove", each_group, msg)
+
+        if "add" in msg["groups"]:
             for each_group in msg["groups"]["add"]:
-                logger.debug(f'Adding user {username} to group {each_group}')
+                logger.debug(f"Adding user {username} to group {each_group}")
                 if str(rcfg.bright_cm_version).split(".")[0] == "8":
-                    grp_add_user_cmd = f'/cm/local/apps/cmd/bin/cmsh -n -c "group; append {each_group} groupmembers {username}; commit;"'
+                    grp_add_user_cmd = (
+                        '/cm/local/apps/cmd/bin/cmsh -n -c "group; append'
+                        f' {each_group} groupmembers {username}; commit;"'
+                    )
                 else:
-                    grp_add_user_cmd = f'/cm/local/apps/cmd/bin/cmsh -n -c "group; append {each_group} members {username}; commit;"'
-
-                logger.info(f'Running command: {grp_add_user_cmd}')
-                proc = Popen(shlex.split(grp_add_user_cmd), stdout=PIPE, stderr=PIPE)
-                out,err = proc.communicate()
-                logger.debug(f'Result: {err}')
-                logger.info(f'User {username} is added to {each_group} group')
-
+                    grp_add_user_cmd = (
+                        '/cm/local/apps/cmd/bin/cmsh -n -c "group; append'
+                        f' {each_group} members {username}; commit;"'
+                    )
+
+                logger.info(f"Running command: {grp_add_user_cmd}")
+                proc = Popen(
+                    shlex.split(grp_add_user_cmd), stdout=PIPE, stderr=PIPE
+                )
+                out, err = proc.communicate()
+                logger.debug(f"Result: {err}")
+                logger.info(f"User {username} is added to {each_group} group")
+                insert_db("add", each_group, msg)
 
         msg["success"] = True
 
     except Exception:
         msg["success"] = False
-        msg["errmsg"] = "Exception raised, while adding user to group {groupname}, check the logs for stack trace"
+        msg["errmsg"] = (
+            "Exception raised, while adding user to group {groupname}, check"
+            " the logs for stack trace"
+        )
         logger.error("", exc_info=True)
 
-
     corr_id = properties.correlation_id
     reply_to = properties.reply_to
 
-    logger.debug(f'corr_id: {corr_id} \n reply_to: {reply_to}')
+    logger.debug(f"corr_id: {corr_id} \n reply_to: {reply_to}")
     # send response to the callback queue
     if reply_to:
         props = pika.BasicProperties(correlation_id=corr_id)
         logger.debug("Sending confirmation back to reply_to")
         rc_rmq.publish_msg(
-            {
-             "routing_key": reply_to,
-             "props": props,
-             "msg": msg
-            }
+            {"routing_key": reply_to, "props": props, "msg": msg}
         )
     else:
         print("Error: no reply_to")
 
-    logger.debug(f'User {username} confirmation sent from {task}')
+    logger.debug(f"User {username} confirmation sent from {task}")
 
     ch.basic_ack(delivery_tag=method.delivery_tag)
 
 
 logger.info(f"Start listening to queue: {task}")
-rc_rmq.bind_queue(queue=task, routing_key='group_member.*', durable=True)
+rc_rmq.bind_queue(queue=task, routing_key="group_member.*", durable=True)
 
-rc_rmq.start_consume(
-    {"queue": task, "cb": group_member}
-)
+rc_rmq.start_consume({"queue": task, "cb": group_member})
 
 logger.info("Disconnected")
-rc_rmq.disconnect()      
-
+rc_rmq.disconnect()