diff --git a/3-ShellP1/.dsh_cli.c.swp b/3-ShellP1/.dsh_cli.c.swp
new file mode 100644
index 0000000000000000000000000000000000000000..bd2da2d883ffa99b5f61bda6b50285fee38b2780
Binary files /dev/null and b/3-ShellP1/.dsh_cli.c.swp differ
diff --git a/3-ShellP1/dsh b/3-ShellP1/dsh
new file mode 100755
index 0000000000000000000000000000000000000000..4439dfcd727ea2321e58bd7d1b48782c488683a7
Binary files /dev/null and b/3-ShellP1/dsh differ
diff --git a/3-ShellP1/dsh_cli.c b/3-ShellP1/dsh_cli.c
new file mode 100644
index 0000000000000000000000000000000000000000..e5a80e9654f45f74149d30c9d0cc7df6505bd2ef
--- /dev/null
+++ b/3-ShellP1/dsh_cli.c
@@ -0,0 +1,107 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "dshlib.h"
+
+void printDragon() {
+	printf("[DRAGON for extra credit would print here]\n");
+}
+
+/*
+ * Implement your main function by building a loop that prompts the
+ * user for input.  Use the SH_PROMPT constant from dshlib.h and then
+ * use fgets to accept user input.  Since we want fgets to also handle
+ * end of file so we can run this headless for testing we need to check
+ * the return code of fgets.  I have provided an example below of how
+ * to do this assuming you are storing user input inside of the cmd_buff
+ * variable.
+ *
+ *      while(1){
+ *        printf("%s", SH_PROMPT);
+ *        if (fgets(cmd_buff, ARG_MAX, stdin) == NULL){
+ *           printf("\n");
+ *           break;
+ *        }
+ *        //remove the trailing \n from cmd_buff
+ *        cmd_buff[strcspn(cmd_buff,"\n")] = '\0';
+ *
+ *        //IMPLEMENT THE REST OF THE REQUIREMENTS
+ *      }
+ *
+ *   Also, use the constants in the dshlib.h in this code.
+ *      SH_CMD_MAX              maximum buffer size for user input
+ *      EXIT_CMD                constant that terminates the dsh program
+ *      SH_PROMPT               the shell prompt
+ *      OK                      the command was parsed properly
+ *      WARN_NO_CMDS            the user command was empty
+ *      ERR_TOO_MANY_COMMANDS   too many pipes used
+ *
+ *   Expected output:
+ *
+ *      CMD_OK_HEADER      if the command parses properly. You will
+ *                         follow this by the command details
+ *
+ *      CMD_WARN_NO_CMD    if the user entered a blank command
+ *      CMD_ERR_PIPE_LIMIT if the user entered too many commands using
+ *                         the pipe feature, e.g., cmd1 | cmd2 | ... |
+ *
+ *  See the provided test cases for output expectations.
+ */
+int main()
+{
+    char *cmd_buff = malloc(ARG_MAX * sizeof(char));
+    int rc = OK;
+    command_list_t *clist = malloc(sizeof(command_list_t));
+    clist->num = 0;
+	
+	while (1)
+    {
+        printf("%s", SH_PROMPT);
+        if (fgets(cmd_buff, ARG_MAX, stdin) == NULL)
+        {
+            printf("\n");
+            break;
+        }
+        // remove the trailing \n from cmd_buff
+        cmd_buff[strcspn(cmd_buff, "\n")] = '\0';
+		
+        // IMPLEMENT THE REST OF THE REQUIREMENTS
+		if (strcmp(cmd_buff, EXIT_CMD) == 0) {
+			exit(rc);
+		}
+
+		if (strcmp(cmd_buff, "dragon") == 0) {
+			printDragon();
+			continue;
+		}
+
+		if (strcmp(cmd_buff, "\0") == 0) {
+			rc = WARN_NO_CMDS;
+			printf(CMD_WARN_NO_CMD);
+			continue;
+		}
+		
+		rc = build_cmd_list(cmd_buff, clist);
+
+		if (rc == ERR_TOO_MANY_COMMANDS) {
+			printf(CMD_ERR_PIPE_LIMIT, CMD_MAX);
+			continue;
+		}
+
+		printf(CMD_OK_HEADER, clist->num);
+
+		for (int i = 0; i < clist->num; i++) {
+			if (strlen(clist->commands[i].args) > 0) {
+    			printf("<%d> %s [%s]\n", i + 1, clist->commands[i].exe, clist->commands[i].args);
+			} else {
+    			printf("<%d> %s\n", i + 1, clist->commands[i].exe);
+			}
+		}
+	}
+    
+    free(cmd_buff);
+    free(clist);
+    return rc;
+}
+
diff --git a/3-ShellP1/dshlib.c b/3-ShellP1/dshlib.c
new file mode 100644
index 0000000000000000000000000000000000000000..4e3f473bae7df4287a178ce958816f1ba0f6e109
--- /dev/null
+++ b/3-ShellP1/dshlib.c
@@ -0,0 +1,94 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "dshlib.h"
+
+int numInstanceOf(char *str, const char c) {
+    int count = 0;
+    while (*str != '\0') {
+		if (*str == c) count++;
+    	str++;
+    }
+
+    return count;
+}
+
+/*
+ *  build_cmd_list
+ *    cmd_line:     the command line from the user
+ *    clist *:      pointer to clist structure to be populated
+ *
+ *  This function builds the command_list_t structure passed by the caller
+ *  It does this by first splitting the cmd_line into commands by spltting
+ *  the string based on any pipe characters '|'.  It then traverses each
+ *  command.  For each command (a substring of cmd_line), it then parses
+ *  that command by taking the first token as the executable name, and
+ *  then the remaining tokens as the arguments.
+ *
+ *  NOTE your implementation should be able to handle properly removing
+ *  leading and trailing spaces!
+ *
+ *  errors returned:
+ *
+ *    OK:                      No Error
+ *    ERR_TOO_MANY_COMMANDS:   There is a limit of CMD_MAX (see dshlib.h)
+strcat(command.args, inner_token); *                             commands.
+ *    ERR_CMD_OR_ARGS_TOO_BIG: One of the commands provided by the user
+ *                             was larger than allowed, either the
+ *                             executable name, or the arg string.
+ *
+ *  Standard Library Functions You Might Want To Consider Using
+ *      memset(), strcmp(), strcpy(), strtok(), strlen(), strchr()
+ */
+int build_cmd_list(char *cmd_line, command_list_t *clist)
+{
+	if (numInstanceOf(cmd_line, PIPE_CHAR) > CMD_MAX-1) return ERR_TOO_MANY_COMMANDS;
+	
+	if ((int)strlen(cmd_line) > SH_CMD_MAX) return ERR_CMD_OR_ARGS_TOO_BIG;
+	
+	clist->num = 0;
+
+    char *outer_saveptr = NULL;
+    char *inner_saveptr = NULL;
+    char *outer_token = strtok_r(cmd_line, PIPE_STRING, &outer_saveptr);
+    
+    while (outer_token != NULL) {
+        if (clist->num > CMD_MAX) return ERR_TOO_MANY_COMMANDS;
+
+        command_t command;
+        memset(&command, 0, sizeof(command_t));
+
+
+
+        char *inner_token = strtok_r(outer_token, SPACE_STRING, &inner_saveptr);
+        
+		if (inner_token == NULL) {
+			outer_token = strtok_r(NULL, PIPE_STRING, &outer_saveptr);
+			continue;
+		}
+
+        if (strlen(inner_token) > EXE_MAX) return ERR_CMD_OR_ARGS_TOO_BIG;
+
+        strcpy(command.exe, inner_token);
+		command.args[0] = '\0';
+
+        inner_token = strtok_r(NULL, SPACE_STRING, &inner_saveptr);
+        while (inner_token != NULL) {
+            if (strlen(command.args) + strlen(inner_token) + 1 > ARG_MAX) return ERR_CMD_OR_ARGS_TOO_BIG;
+
+            if (strlen(command.args) > 0) strcat(command.args, SPACE_STRING);
+        	strcat(command.args, inner_token);
+				
+            inner_token = strtok_r(NULL, SPACE_STRING, &inner_saveptr);
+       }
+
+        clist->commands[clist->num] = command;
+        clist->num++;
+
+        outer_token = strtok_r(NULL, PIPE_STRING, &outer_saveptr);
+    }
+
+    return OK;
+}
diff --git a/3-ShellP1/dshlib.h b/3-ShellP1/dshlib.h
new file mode 100644
index 0000000000000000000000000000000000000000..d0dfe14393d88ccfadb5779a20666c0195efb429
--- /dev/null
+++ b/3-ShellP1/dshlib.h
@@ -0,0 +1,51 @@
+#ifndef __DSHLIB_H__
+#define __DSHLIB_H__
+
+// Constants for command structure sizes
+#define EXE_MAX 64
+#define ARG_MAX 256
+#define CMD_MAX 8
+// Longest command that can be read from the shell
+#define SH_CMD_MAX EXE_MAX + ARG_MAX
+
+typedef struct command
+{
+    char exe[EXE_MAX];
+    char args[ARG_MAX];
+} command_t;
+
+typedef struct command_list
+{
+    int num;
+    command_t commands[CMD_MAX];
+} command_list_t;
+
+// Special character #defines
+#define SPACE_CHAR ' '
+#define SPACE_STRING " "
+#define PIPE_CHAR '|'
+#define PIPE_STRING "|"
+
+#define SH_PROMPT "dsh> "
+#define EXIT_CMD "exit"
+
+// Standard Return Codes
+#define OK 0
+#define WARN_NO_CMDS -1
+#define ERR_TOO_MANY_COMMANDS -2
+#define ERR_CMD_OR_ARGS_TOO_BIG -3
+
+// starter code
+#define M_NOT_IMPL "The requested operation is not implemented yet!\n"
+#define EXIT_NOT_IMPL 3
+#define NOT_IMPLEMENTED_YET 0
+
+// prototypes
+int build_cmd_list(char *cmd_line, command_list_t *clist);
+
+// output constants
+#define CMD_OK_HEADER "PARSED COMMAND LINE - TOTAL COMMANDS %d\n"
+#define CMD_WARN_NO_CMD "warning: no commands provided\n"
+#define CMD_ERR_PIPE_LIMIT "error: piping limited to %d commands\n"
+
+#endif
diff --git a/3-ShellP1/makefile b/3-ShellP1/makefile
new file mode 100644
index 0000000000000000000000000000000000000000..d61ca771b4de9e9a5809e7cd82b747cfaa9c0bc6
--- /dev/null
+++ b/3-ShellP1/makefile
@@ -0,0 +1,27 @@
+# Compiler settings
+CC = gcc
+CFLAGS = -Wall -Wextra -g
+
+# Target executable name
+TARGET = dsh
+
+# Find all source and header files
+SRCS = $(wildcard *.c)
+HDRS = $(wildcard *.h)
+
+# Default target
+all: $(TARGET)
+
+# Compile source to executable
+$(TARGET): $(SRCS) $(HDRS)
+	$(CC) $(CFLAGS) -o $(TARGET) $(SRCS)
+
+# Clean up build files
+clean:
+	rm -f $(TARGET)
+
+test:
+	./test.sh
+
+# Phony targets
+.PHONY: all clean
diff --git a/3-ShellP1/test.sh b/3-ShellP1/test.sh
new file mode 100644
index 0000000000000000000000000000000000000000..676c62b6ddb3462151a1716ffaac75e0343381e9
--- /dev/null
+++ b/3-ShellP1/test.sh
@@ -0,0 +1,212 @@
+#!/usr/bin/env bats
+
+@test "Simple Command" {
+    run ./dsh <<EOF                
+test_command
+exit
+EOF
+
+    # Strip all whitespace (spaces, tabs, newlines) from the output
+    stripped_output=$(echo "$output" | tr -d '[:space:]')
+
+    # Expected output with all whitespace removed for easier matching
+    expected_output="dsh>PARSEDCOMMANDLINE-TOTALCOMMANDS1<1>test_commanddsh>"
+
+    # These echo commands will help with debugging and will only print
+    #if the test fails
+    echo "Captured stdout:" 
+    echo "Output: $output"
+    echo "Exit Status: $status"
+
+    # Check exact match
+    [ "$stripped_output" = "$expected_output" ]
+
+    # Assertions
+    [ "$status" -eq 0 ]
+
+}
+
+@test "Simple Command with Args" {
+    run ./dsh <<EOF                
+cmd -a1 -a2
+exit
+EOF
+
+    # Strip all whitespace (spaces, tabs, newlines) from the output
+    stripped_output=$(echo "$output" | tr -d '[:space:]')
+
+    # Expected output 
+    expected_output="dsh>PARSEDCOMMANDLINE-TOTALCOMMANDS1<1>cmd[-a1-a2]dsh>"
+
+    # These echo commands will help with debugging and will only print
+    #if the test fails
+    echo "Captured stdout:" 
+    echo "Output: $output"
+    echo "Exit Status: $status"
+
+    # Check exact match
+    [ "$stripped_output" = "$expected_output" ]
+
+    # Assertions
+    [ "$status" -eq 0 ]
+
+}
+
+
+@test "No command provided" {
+    run ./dsh <<EOF                
+
+exit
+EOF
+
+    # Strip all whitespace (spaces, tabs, newlines) from the output
+    stripped_output=$(echo "$output" | tr -d '[:space:]')
+
+    # Expected output with all whitespace removed for easier matching
+    expected_output="dsh>warning:nocommandsprovideddsh>"
+
+    # These echo commands will help with debugging and will only print
+    #if the test fails
+    echo "Captured stdout:" 
+    echo "Output: $output"
+    echo "Exit Status: $status"
+
+    # Check exact match
+    [ "$stripped_output" = "$expected_output" ]
+
+    # Assertions
+    [ "$status" -eq 0 ]
+
+}
+
+@test "Two commands" {
+    run ./dsh <<EOF                
+command_one | command_two
+exit
+EOF
+
+    # Strip all whitespace (spaces, tabs, newlines) from the output
+    stripped_output=$(echo "$output" | tr -d '[:space:]')
+
+    # Expected output with all whitespace removed for easier matching
+    expected_output="dsh>PARSEDCOMMANDLINE-TOTALCOMMANDS2<1>command_one<2>command_twodsh>"
+
+    # These echo commands will help with debugging and will only print
+    #if the test fails
+    echo "Captured stdout:" 
+    echo "Output: $output"
+    echo "Exit Status: $status"
+
+    # Check exact match
+    [ "$stripped_output" = "$expected_output" ]
+
+    # Assertions
+    [ "$status" -eq 0 ]
+
+}
+
+@test "three commands with args" {
+    run ./dsh <<EOF                
+cmd1 a1 a2 a3 | cmd2 a4 a5 a6 | cmd3 a7 a8 a9
+exit
+EOF
+
+    # Strip all whitespace (spaces, tabs, newlines) from the output
+    stripped_output=$(echo "$output" | tr -d '[:space:]')
+
+    # Expected output with all whitespace removed for easier matching
+    expected_output="dsh>PARSEDCOMMANDLINE-TOTALCOMMANDS3<1>cmd1[a1a2a3]<2>cmd2[a4a5a6]<3>cmd3[a7a8a9]dsh>"
+
+    # These echo commands will help with debugging and will only print
+    #if the test fails
+    echo "Captured stdout:" 
+    echo "Output: $output"
+    echo "Exit Status: $status"
+
+    # Check exact match
+    [ "$stripped_output" = "$expected_output" ]
+
+    # Assertions
+    [ "$status" -eq 0 ]
+
+}
+
+@test "try max (8) commands" {
+    run ./dsh <<EOF                
+cmd1 | cmd2 | cmd3 | cmd4 | cmd5 | cmd6 | cmd7 | cmd8
+exit
+EOF
+
+    # Strip all whitespace (spaces, tabs, newlines) from the output
+    stripped_output=$(echo "$output" | tr -d '[:space:]')
+
+    # Expected output with all whitespace removed for easier matching
+    expected_output="dsh>PARSEDCOMMANDLINE-TOTALCOMMANDS8<1>cmd1<2>cmd2<3>cmd3<4>cmd4<5>cmd5<6>cmd6<7>cmd7<8>cmd8dsh>"
+
+    # These echo commands will help with debugging and will only print
+    #if the test fails
+    echo "Captured stdout:" 
+    echo "Output: $output"
+    echo "Exit Status: $status"
+
+    # Check exact match
+    [ "$stripped_output" = "$expected_output" ]
+
+    # Assertions
+    [ "$status" -eq 0 ]
+
+}
+
+@test "try too many commands" {
+    run ./dsh <<EOF                
+cmd1 | cmd2 | cmd3 | cmd4 | cmd5 | cmd6 | cmd7 | cmd8 | cmd9
+exit
+EOF
+
+    # Strip all whitespace (spaces, tabs, newlines) from the output
+    stripped_output=$(echo "$output" | tr -d '[:space:]')
+
+    # Expected output with all whitespace removed for easier matching
+    expected_output="dsh>error:pipinglimitedto8commandsdsh>"
+
+    # These echo commands will help with debugging and will only print
+    #if the test fails
+    echo "Captured stdout:" 
+    echo "Output: $output"
+    echo "Exit Status: $status"
+
+    # Check exact match
+    [ "$stripped_output" = "$expected_output" ]
+
+    # Assertions
+    [ "$status" -eq 0 ]
+
+}
+
+@test "kitchen sink - multiple commands" {
+    run ./dsh <<EOF                
+cmd1
+cmd2 arg arg2
+p1 | p2
+p3 p3a1 p3a2 | p4 p4a1 p4a2
+EOF
+
+    # Strip all whitespace (spaces, tabs, newlines) from the output
+    stripped_output=$(echo "$output" | tr -d '[:space:]')
+
+    # Expected output with all whitespace removed for easier matching
+    expected_output="dsh>PARSEDCOMMANDLINE-TOTALCOMMANDS1<1>cmd1dsh>PARSEDCOMMANDLINE-TOTALCOMMANDS1<1>cmd2[argarg2]dsh>PARSEDCOMMANDLINE-TOTALCOMMANDS2<1>p1<2>p2dsh>PARSEDCOMMANDLINE-TOTALCOMMANDS2<1>p3[p3a1p3a2]<2>p4[p4a1p4a2]dsh>"
+
+    # These echo commands will help with debugging and will only print
+    #if the test fails
+    echo "Captured stdout:" 
+    echo "Output: $output"
+    echo "Exit Status: $status"
+
+    # Check exact match
+    [ "$stripped_output" = "$expected_output" ]
+
+    # Assertions
+    [ "$status" -eq 0 ]
+
+}