diff --git a/dsh_cli.c b/dsh_cli.c
new file mode 100644
index 0000000000000000000000000000000000000000..f8fe320ec58cf38538d95e42c3e85e211e24aab9
--- /dev/null
+++ b/dsh_cli.c
@@ -0,0 +1,86 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "dshlib.h"
+
+/*
+ * main:
+ *   - prompts the user for input using SH_PROMPT
+ *   - reads a line (up to SH_CMD_MAX characters)
+ *   - if the line is "exit" (after trimming leading spaces) then the shell quits
+ *   - if the line is blank, prints CMD_WARN_NO_CMD and loops again
+ *   - otherwise, calls build_cmd_list() to parse the command line
+ *   - on OK, prints the header and then for each command prints:
+ *         <i>exe         if there are no arguments, or
+ *         <i>exe[args]   if there are arguments.
+ *   - if build_cmd_list returns ERR_TOO_MANY_COMMANDS, prints CMD_ERR_PIPE_LIMIT.
+ */
+int main(void)
+{
+    char cmd_buff[SH_CMD_MAX];
+    int rc;
+    command_list_t clist;
+
+    while (1) {
+        /* Print the shell prompt */
+        printf("%s", SH_PROMPT);
+
+        /* Read a line from stdin. If EOF is encountered, print a newline and exit. */
+        if (fgets(cmd_buff, sizeof(cmd_buff), stdin) == NULL) {
+            printf("\n");
+            break;
+        }
+
+        /* Remove the trailing newline character */
+        cmd_buff[strcspn(cmd_buff, "\n")] = '\0';
+
+        /* Trim leading whitespace manually */
+        char *start = cmd_buff;
+        while (*start && isspace((unsigned char)*start)) {
+            start++;
+        }
+
+        /* If the command is exactly EXIT_CMD, exit the shell */
+        if (strcmp(start, EXIT_CMD) == 0) {
+            break;
+        }
+
+        /* If nothing remains after trimming, warn and loop again */
+        if (*start == '\0') {
+            printf("%s", CMD_WARN_NO_CMD);
+            continue;
+        }
+
+        /*
+         * Since build_cmd_list modifies the input string (by using strtok),
+         * make a copy of the (trimmed) command line.
+         */
+        char cmd_line_copy[SH_CMD_MAX];
+        strncpy(cmd_line_copy, start, sizeof(cmd_line_copy) - 1);
+        cmd_line_copy[sizeof(cmd_line_copy) - 1] = '\0';
+
+        rc = build_cmd_list(cmd_line_copy, &clist);
+
+        if (rc == OK) {
+            /* Print the header showing the total number of commands parsed */
+            printf(CMD_OK_HEADER, clist.num);
+            for (int i = 0; i < clist.num; i++) {
+                printf("<%d>%s", i + 1, clist.commands[i].exe);
+                /* If any arguments were found, print them inside square brackets */
+                if (strlen(clist.commands[i].args) > 0) {
+                    printf("[%s]", clist.commands[i].args);
+                }
+            }
+            printf("\n");
+        }
+        else if (rc == ERR_TOO_MANY_COMMANDS) {
+            printf(CMD_ERR_PIPE_LIMIT, CMD_MAX);
+            printf("\n");
+        }
+        /* (Optionally, you could handle ERR_CMD_OR_ARGS_TOO_BIG here) */
+    }
+
+    return 0;
+}
\ No newline at end of file