diff --git a/5-ShellP3/bats/assignment_tests.sh b/5-ShellP3/bats/assignment_tests.sh
new file mode 100644
index 0000000000000000000000000000000000000000..37687086e3490a00ff0ae96ff26a9f7562496f1a
--- /dev/null
+++ b/5-ShellP3/bats/assignment_tests.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bats
+
+############################ DO NOT EDIT THIS FILE #####################################
+# File: assignement_tests.sh
+# 
+# DO NOT EDIT THIS FILE
+#
+# Add/Edit Student tests in student_tests.sh
+# 
+# All tests in this file must pass - it is used as part of grading!
+########################################################################################
+
+@test "Pipes" {
+    run "./dsh" <<EOF                
+ls | grep dshlib.c
+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="dshlib.cdsh3>dsh3>cmdloopreturned0"
+
+    # 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"
+    echo "${stripped_output} -> ${expected_output}"
+
+    # Check exact match
+    [ "$stripped_output" = "$expected_output" ]
+
+    # Assertions
+    [ "$status" -eq 0 ]
+}
\ No newline at end of file
diff --git a/5-ShellP3/bats/student_tests.sh b/5-ShellP3/bats/student_tests.sh
new file mode 100644
index 0000000000000000000000000000000000000000..1241ea9cfc3db5e7d9276cc665f87f03a2d0c727
--- /dev/null
+++ b/5-ShellP3/bats/student_tests.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env bats
+
+# File: student_tests.sh
+# 
+# Create your unit tests suit in this file
+
+@test "Example: check ls runs without errors" {
+    run ./dsh <<EOF                
+ls
+EOF
+
+    # Assertions
+    [ "$status" -eq 0 ]
+}
\ No newline at end of file
diff --git a/5-ShellP3/debug/launch.json b/5-ShellP3/debug/launch.json
new file mode 100644
index 0000000000000000000000000000000000000000..aedc1efa4984aaf3265f70a3581d4956d569cf26
--- /dev/null
+++ b/5-ShellP3/debug/launch.json
@@ -0,0 +1,29 @@
+{
+    "configurations": [
+        {
+            "name": "(gdb) 4-ShellP2",
+            "type": "cppdbg",
+            "request": "launch",
+            "program": "${workspaceFolder}/4-ShellP2/starter/dsh",
+            "args": [""],
+            "stopAtEntry": false,
+            "cwd": "${workspaceFolder}/4-ShellP2/starter",
+            "environment": [],
+            "externalConsole": false,
+            "MIMode": "gdb",
+            "setupCommands": [
+                {
+                    "description": "Enable pretty-printing for gdb",
+                    "text": "-enable-pretty-printing",
+                    "ignoreFailures": true
+                },
+                {
+                    "description": "Set Disassembly Flavor to Intel",
+                    "text": "-gdb-set disassembly-flavor intel",
+                    "ignoreFailures": true
+                }
+            ],
+            "preLaunchTask": "Build 4-ShellP2"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/5-ShellP3/debug/tasks.json b/5-ShellP3/debug/tasks.json
new file mode 100644
index 0000000000000000000000000000000000000000..71013e37fe8ec4999fb301dae2b55b1fc9b72543
--- /dev/null
+++ b/5-ShellP3/debug/tasks.json
@@ -0,0 +1,20 @@
+{
+    "version": "2.0.0",
+    "tasks": [
+      {
+        "label": "Build 4-ShellP2",
+        "type": "shell",
+        "command": "make",
+        "group": {
+          "kind": "build",
+          "isDefault": true
+        },
+        "options": {
+          "cwd": "${workspaceFolder}/4-ShellP2/starter"
+      },
+        "problemMatcher": ["$gcc"],
+        "detail": "Runs the 'make' command to build the project."
+      }
+    ]
+  }
+  
\ No newline at end of file
diff --git a/5-ShellP3/dragon.c b/5-ShellP3/dragon.c
new file mode 100644
index 0000000000000000000000000000000000000000..581408b2cd94ef7581d6be42fc9f8c2dd8dc8ed3
--- /dev/null
+++ b/5-ShellP3/dragon.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+#include "dshlib.h"
+// EXTRA CREDIT - print the drexel dragon from the readme.md
+extern void print_dragon(){
+  printf("%s\n", DRAGON_ASCII);
+}
diff --git a/5-ShellP3/dsh b/5-ShellP3/dsh
new file mode 100755
index 0000000000000000000000000000000000000000..c400f51110d15fcaf73e2e135e78416e9e75ff0a
Binary files /dev/null and b/5-ShellP3/dsh differ
diff --git a/5-ShellP3/dsh_cli.c b/5-ShellP3/dsh_cli.c
new file mode 100644
index 0000000000000000000000000000000000000000..9262cf457e6b235b19999efa04153e1de0962255
--- /dev/null
+++ b/5-ShellP3/dsh_cli.c
@@ -0,0 +1,13 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "dshlib.h"
+
+/* DO NOT EDIT
+ * main() logic moved to exec_local_cmd_loop() in dshlib.c
+*/
+int main(){
+  int rc = exec_local_cmd_loop();
+  printf("cmd loop returned %d\n", rc);
+}
\ No newline at end of file
diff --git a/5-ShellP3/dshlib.c b/5-ShellP3/dshlib.c
new file mode 100644
index 0000000000000000000000000000000000000000..956ac54a0354fa1ac0431dd32ae7d1c5bd3d6628
--- /dev/null
+++ b/5-ShellP3/dshlib.c
@@ -0,0 +1,314 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include "dshlib.h"
+
+/*
+ * Implement your exec_local_cmd_loop 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.
+ * 
+ *      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
+ *      ERR_MEMORY              dynamic memory management failure
+ * 
+ *   errors returned
+ *      OK                     No error
+ *      ERR_MEMORY             Dynamic memory management failure
+ *      WARN_NO_CMDS           No commands parsed
+ *      ERR_TOO_MANY_COMMANDS  too many pipes used
+ *   
+ *   console messages
+ *      CMD_WARN_NO_CMD        print on WARN_NO_CMDS
+ *      CMD_ERR_PIPE_LIMIT     print on ERR_TOO_MANY_COMMANDS
+ *      CMD_ERR_EXECUTE        print on execution failure of external command
+ * 
+ *  Standard Library Functions You Might Want To Consider Using (assignment 1+)
+ *      malloc(), free(), strlen(), fgets(), strcspn(), printf()
+ * 
+ *  Standard Library Functions You Might Want To Consider Using (assignment 2+)
+ *      fork(), execvp(), exit(), chdir()
+ */
+
+ int last_rc = 0;
+
+int execute_pipeline(command_list_t *clist) {
+    if (!clist->num) return OK;
+    
+    if (clist->num == 1) {
+        char *cmd = clist->commands[0].argv[0];
+        if (clist->commands[0].argc > 0) {
+            if (!strcmp(cmd, EXIT_CMD)) return OK_EXIT;
+            if (!strcmp(cmd, "cd")) {
+                handle_cd(clist->commands[0].argc > 1 ? clist->commands[0].argv[1] : NULL);
+                return OK;
+            }
+            if (!strcmp(cmd, "rc")) {
+                printf("%d\n", last_rc);
+                return OK;
+            }
+        }
+    }
+    
+    pid_t *child_pids = malloc(clist->num * sizeof(pid_t));
+    if (!child_pids) {
+        fprintf(stderr, "Memory allocation failed\n");
+        return ERR_MEMORY;
+    }
+    
+    int pipes[CMD_MAX - 1][2];
+    for (int i = 0; i < clist->num - 1; i++) {
+        if (pipe(pipes[i]) == -1) {
+            perror("pipe");
+            while (i--) close(pipes[i][0]), close(pipes[i][1]);
+            free(child_pids);
+            return ERR_EXEC_CMD;
+        }
+    }
+    
+    for (int i = 0; i < clist->num; i++) {
+        pid_t pid = fork();
+        if (pid < 0) {
+            perror("fork");
+            for (int j = 0; j < clist->num - 1; j++) close(pipes[j][0]), close(pipes[j][1]);
+            free(child_pids);
+            return ERR_EXEC_CMD;
+        }
+        
+        if (!pid) {
+            if (i > 0) dup2(pipes[i - 1][0], STDIN_FILENO);
+            if (i < clist->num - 1) dup2(pipes[i][1], STDOUT_FILENO);
+            for (int j = 0; j < clist->num - 1; j++) close(pipes[j][0]), close(pipes[j][1]);
+            execvp(clist->commands[i].argv[0], clist->commands[i].argv);
+            perror("execvp");
+            exit(errno);
+        }
+        child_pids[i] = pid;
+    }
+    
+    for (int i = 0; i < clist->num - 1; i++) close(pipes[i][0]), close(pipes[i][1]);
+    
+    for (int i = 0, status; i < clist->num; i++) {
+        waitpid(child_pids[i], &status, 0);
+        if (i == clist->num - 1) last_rc = WEXITSTATUS(status);
+    }
+    
+    free(child_pids);
+    return OK;
+}
+
+int build_cmd_list(char *cmd_line, command_list_t *clist) {
+    int ret = OK;
+    char *cmd_copy = strdup(cmd_line);
+    if (!cmd_copy) {
+        fprintf(stderr, "Memory allocation failed\n");
+        return ERR_MEMORY;
+    }
+
+    clist->num = 0;
+    char *token = NULL, *context = NULL;
+    token = strtok_r(cmd_copy, PIPE_STRING, &context);
+
+    while (token != NULL) {
+        if (clist->num >= CMD_MAX) {
+            ret = ERR_TOO_MANY_COMMANDS;
+            fprintf(stderr, CMD_ERR_PIPE_LIMIT, CMD_MAX);
+            break;
+        }
+
+        if (alloc_cmd_buff(&clist->commands[clist->num]) != OK) {
+            ret = ERR_MEMORY;
+            break;
+        }
+
+        /* Copy token into the command buffer */
+        strncpy(clist->commands[clist->num]._cmd_buffer, token, SH_CMD_MAX);
+        clist->commands[clist->num]._cmd_buffer[SH_CMD_MAX] = '\0';
+
+        if (build_cmd_buff(clist->commands[clist->num]._cmd_buffer,
+                           &clist->commands[clist->num]) != OK) {
+            free_cmd_buff(&clist->commands[clist->num]);
+            ret = ERR_CMD_ARGS_BAD;
+            break;
+        }
+
+        clist->num++;
+        token = strtok_r(NULL, PIPE_STRING, &context);
+    }
+
+    free(cmd_copy);
+
+    if (ret != OK) {
+        for (int i = 0; i < clist->num; i++) {
+            free_cmd_buff(&clist->commands[i]);
+        }
+        return ret;
+    }
+
+    if (clist->num == 0) {
+        fprintf(stderr, CMD_WARN_NO_CMD);
+        return WARN_NO_CMDS;
+    }
+
+    return OK;
+}
+
+
+int free_cmd_list(command_list_t *clist) {
+    if (clist == NULL) {
+        return ERR_MEMORY;
+    }
+    
+    for (int i = 0; i < clist->num; i++) {
+        free_cmd_buff(&clist->commands[i]);
+    }
+    
+    clist->num = 0;
+    return OK;
+}
+
+int exec_local_cmd_loop() {
+    cmd_buff_t cmd;
+    command_list_t cmd_list;
+    int rc;
+
+    if ((rc = alloc_cmd_buff(&cmd)) != OK) {
+        fprintf(stderr, "Memory allocation failed\n");
+        return ERR_MEMORY;
+    }
+
+    for (;;) {
+        printf("%s", SH_PROMPT);
+
+        if (!fgets(cmd._cmd_buffer, SH_CMD_MAX, stdin)) {
+            putchar('\n');
+            break;
+        }
+
+        cmd._cmd_buffer[strcspn(cmd._cmd_buffer, "\n")] = '\0';
+        char *trimmed = cmd._cmd_buffer;
+        while (*trimmed && isspace((unsigned char)*trimmed)) trimmed++;
+        
+        if (!*trimmed) {
+            puts(CMD_WARN_NO_CMD);
+            continue;
+        }
+
+        if (!strcmp(trimmed, EXIT_CMD)) break;
+        if (!strcmp(trimmed, "dragon")) {
+            print_dragon();
+            continue;
+        }
+
+        if ((rc = build_cmd_list(trimmed, &cmd_list)) != OK) {
+            if (rc != WARN_NO_CMDS) fprintf(stderr, "Error parsing command: %d\n", rc);
+            continue;
+        }
+
+        rc = execute_pipeline(&cmd_list);
+        free_cmd_list(&cmd_list);
+        if (rc == OK_EXIT) break;
+    }
+    
+    free_cmd_buff(&cmd);
+    return OK;
+}
+
+int handle_cd(char *path) {
+    if (path == NULL)
+        return 0;
+    if (chdir(path) != 0) {
+        perror("cd");
+        return -1;
+    }
+    return 0;
+}
+
+int alloc_cmd_buff(cmd_buff_t *cmd) {
+    if (cmd == NULL) return ERR_MEMORY;
+    cmd->_cmd_buffer = malloc(SH_CMD_MAX + 1); // +1 for the null terminator
+    if (cmd->_cmd_buffer == NULL) return ERR_MEMORY;
+    return OK;
+}
+
+int free_cmd_buff(cmd_buff_t *cmd) {
+    if (cmd == NULL) return ERR_MEMORY;
+    free(cmd->_cmd_buffer);
+    cmd->_cmd_buffer = NULL;
+    return OK;
+}
+
+int clear_cmd_buff(cmd_buff_t *cmd) {
+    if (cmd == NULL) return ERR_MEMORY;
+    cmd->argc = 0;
+    for (int i = 0; i < CMD_ARGV_MAX; i++) {
+        cmd->argv[i] = NULL;
+    }
+    return OK;
+}
+
+int build_cmd_buff(char *cmd_line, cmd_buff_t *cmd) {
+    if (cmd_line == NULL || cmd == NULL)
+        return ERR_MEMORY;
+    clear_cmd_buff(cmd);
+    int tokenCount = 0;
+    char *ptr = cmd_line;
+    
+    while (*ptr) {
+        while (*ptr && isspace((unsigned char)*ptr))
+            ptr++;
+        if (!*ptr)
+            break;
+        
+        char *token = ptr;
+        if (*ptr == '"' || *ptr == '\'') {
+            char quote = *ptr;
+            ptr++;
+            token = ptr;
+            while (*ptr && *ptr != quote)
+                ptr++;
+            if (*ptr == quote) {
+                *ptr = '\0';
+                ptr++;
+            }
+        } else {
+            while (*ptr && !isspace((unsigned char)*ptr))
+                ptr++;
+            if (*ptr) {
+                *ptr = '\0';
+                ptr++;
+            }
+        }
+        
+        cmd->argv[tokenCount++] = token;
+        if (tokenCount >= CMD_ARGV_MAX - 1)
+            break;
+    }
+    
+    cmd->argv[tokenCount] = NULL;
+    cmd->argc = tokenCount;
+    return tokenCount == 0 ? WARN_NO_CMDS : OK;
+}
diff --git a/5-ShellP3/dshlib.h b/5-ShellP3/dshlib.h
new file mode 100644
index 0000000000000000000000000000000000000000..9ca3188a48e85d393b033e0b698d51e7009b722a
--- /dev/null
+++ b/5-ShellP3/dshlib.h
@@ -0,0 +1,134 @@
+#ifndef __DSHLIB_H__
+    #define __DSHLIB_H__
+
+
+//Constants for command structure sizes
+#define EXE_MAX 64
+#define ARG_MAX 256
+#define CMD_MAX 8
+#define CMD_ARGV_MAX (CMD_MAX + 1)
+// Longest command that can be read from the shell
+#define SH_CMD_MAX EXE_MAX + ARG_MAX
+#define DRAGON_ASCII "\
+                                                                        @%%%%                       \n\
+                                                                     %%%%%%                         \n\
+                                                                    %%%%%%                          \n\
+                                                                 % %%%%%%%           @              \n\
+                                                                %%%%%%%%%%        %%%%%%%           \n\
+                                       %%%%%%%  %%%%@         %%%%%%%%%%%%@    %%%%%%  @%%%%        \n\
+                                  %%%%%%%%%%%%%%%%%%%%%%      %%%%%%%%%%%%%%%%%%%%%%%%%%%%          \n\
+                                %%%%%%%%%%%%%%%%%%%%%%%%%%   %%%%%%%%%%%% %%%%%%%%%%%%%%%           \n\
+                               %%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%     %%%            \n\
+                             %%%%%%%%%%%%%%%%%%%%%%%%%%%%@ @%%%%%%%%%%%%%%%%%%        %%            \n\
+                            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%                \n\
+                            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%              \n\
+                            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%%%@              \n\
+      %%%%%%%%@           %%%%%%%%%%%%%%%%        %%%%%%%%%%%%%%%%%%%%%%%%%%      %%                \n\
+    %%%%%%%%%%%%%         %%@%%%%%%%%%%%%           %%%%%%%%%%% %%%%%%%%%%%%      @%                \n\
+  %%%%%%%%%%   %%%        %%%%%%%%%%%%%%            %%%%%%%%%%%%%%%%%%%%%%%%                        \n\
+ %%%%%%%%%       %         %%%%%%%%%%%%%             %%%%%%%%%%%%@%%%%%%%%%%%                       \n\
+%%%%%%%%%@                % %%%%%%%%%%%%%            @%%%%%%%%%%%%%%%%%%%%%%%%%                     \n\
+%%%%%%%%@                 %%@%%%%%%%%%%%%            @%%%%%%%%%%%%%%%%%%%%%%%%%%%%                  \n\
+%%%%%%%@                   %%%%%%%%%%%%%%%           %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%              \n\
+%%%%%%%%%%                  %%%%%%%%%%%%%%%          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%      %%%%  \n\
+%%%%%%%%%@                   @%%%%%%%%%%%%%%         %%%%%%%%%%%%@ %%%% %%%%%%%%%%%%%%%%%   %%%%%%%%\n\
+%%%%%%%%%%                  %%%%%%%%%%%%%%%%%        %%%%%%%%%%%%%      %%%%%%%%%%%%%%%%%% %%%%%%%%%\n\
+%%%%%%%%%@%%@                %%%%%%%%%%%%%%%%@       %%%%%%%%%%%%%%     %%%%%%%%%%%%%%%%%%%%%%%%  %%\n\
+ %%%%%%%%%%                  % %%%%%%%%%%%%%%@        %%%%%%%%%%%%%%   %%%%%%%%%%%%%%%%%%%%%%%%%% %%\n\
+  %%%%%%%%%%%%  @           %%%%%%%%%%%%%%%%%%        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %%% \n\
+   %%%%%%%%%%%%% %%  %  %@ %%%%%%%%%%%%%%%%%%          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    %%% \n\
+    %%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%           @%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    %%%%%%% \n\
+     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%              %%%%%%%%%%%%%%%%%%%%%%%%%%%%        %%%   \n\
+      @%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                  %%%%%%%%%%%%%%%%%%%%%%%%%               \n\
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                      %%%%%%%%%%%%%%%%%%%  %%%%%%%          \n\
+           %%%%%%%%%%%%%%%%%%%%%%%%%%                           %%%%%%%%%%%%%%%  @%%%%%%%%%         \n\
+              %%%%%%%%%%%%%%%%%%%%           @%@%                  @%%%%%%%%%%%%%%%%%%   %%%        \n\
+                  %%%%%%%%%%%%%%%        %%%%%%%%%%                    %%%%%%%%%%%%%%%    %         \n\
+                %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                      %%%%%%%%%%%%%%            \n\
+                %%%%%%%%%%%%%%%%%%%%%%%%%%  %%%% %%%                      %%%%%%%%%%  %%%@          \n\
+                     %%%%%%%%%%%%%%%%%%% %%%%%% %%                          %%%%%%%%%%%%%@          \n\
+                                                                                 %%%%%%%@        \n"
+
+typedef struct command
+{
+    char exe[EXE_MAX];
+    char args[ARG_MAX];
+} command_t;
+
+typedef struct cmd_buff
+{
+    int  argc;
+    char *argv[CMD_ARGV_MAX];
+    char *_cmd_buffer;
+} cmd_buff_t;
+
+/* WIP - Move to next assignment 
+#define N_ARG_MAX    15     //MAX number of args for a command
+typedef struct command{
+    char exe [EXE_MAX];
+    char args[ARG_MAX];
+    int  argc;
+    char *argv[N_ARG_MAX + 1];  //last argv[LAST] must be \0
+}command_t;
+*/
+
+typedef struct command_list{
+    int num;
+    cmd_buff_t commands[CMD_MAX];
+}command_list_t;
+
+//Special character #defines
+#define SPACE_CHAR  ' '
+#define PIPE_CHAR   '|'
+#define PIPE_STRING "|"
+
+#define SH_PROMPT "dsh3> "
+#define EXIT_CMD "exit"
+#define EXIT_SC     99
+
+//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
+#define ERR_CMD_ARGS_BAD        -4      //for extra credit
+#define ERR_MEMORY              -5
+#define ERR_EXEC_CMD            -6
+#define OK_EXIT                 -7
+
+//prototypes
+int alloc_cmd_buff(cmd_buff_t *cmd_buff);
+int free_cmd_buff(cmd_buff_t *cmd_buff);
+int clear_cmd_buff(cmd_buff_t *cmd_buff);
+int build_cmd_buff(char *cmd_line, cmd_buff_t *cmd_buff);
+int close_cmd_buff(cmd_buff_t *cmd_buff);
+int build_cmd_list(char *cmd_line, command_list_t *clist);
+int free_cmd_list(command_list_t *cmd_lst);
+int handle_cd(char *path);
+void print_dragon();
+
+//built in command stuff
+typedef enum {
+    BI_CMD_EXIT,
+    BI_CMD_DRAGON,
+    BI_CMD_CD,
+    BI_NOT_BI,
+    BI_EXECUTED,
+} Built_In_Cmds;
+Built_In_Cmds match_command(const char *input); 
+Built_In_Cmds exec_built_in_cmd(cmd_buff_t *cmd);
+
+//main execution context
+int exec_local_cmd_loop();
+int exec_cmd(cmd_buff_t *cmd);
+int execute_pipeline(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
\ No newline at end of file
diff --git a/5-ShellP3/gitignore.txt b/5-ShellP3/gitignore.txt
new file mode 100644
index 0000000000000000000000000000000000000000..eb47a8e82ad127f89b6fdbbf0f531cb8865b7bf8
--- /dev/null
+++ b/5-ShellP3/gitignore.txt
@@ -0,0 +1 @@
+dsh
\ No newline at end of file
diff --git a/5-ShellP3/makefile b/5-ShellP3/makefile
new file mode 100644
index 0000000000000000000000000000000000000000..b14b0723e23ea2036f0220406b40a93e6a0cd283
--- /dev/null
+++ b/5-ShellP3/makefile
@@ -0,0 +1,31 @@
+# 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:
+	bats $(wildcard ./bats/*.sh)
+
+valgrind:
+	echo "pwd\nexit" | valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=1 ./$(TARGET) 
+	echo "pwd\nexit" | valgrind --tool=helgrind --error-exitcode=1 ./$(TARGET) 
+
+# Phony targets
+.PHONY: all clean test
\ No newline at end of file
diff --git a/5-ShellP3/questions.md b/5-ShellP3/questions.md
new file mode 100644
index 0000000000000000000000000000000000000000..fb0033673a41b324f0c5f4b965aac8a5e5fbab50
--- /dev/null
+++ b/5-ShellP3/questions.md
@@ -0,0 +1,16 @@
+1. Your shell forks multiple child processes when executing piped commands. How does your implementation ensure that all child processes complete before the shell continues accepting user input? What would happen if you forgot to call waitpid() on all child processes?
+
+My implementation guarantees that the shell waits for all piped commands to finish by recording each child process’s PID in an array (child_pids). Once all processes have been forked, the shell enters a loop that calls waitpid() on every stored PID. This ensures that execute_pipeline() only returns after every child has terminated, preventing the shell from accepting further input prematurely. If waitpid() is not invoked for all child processes, those processes become zombies—left lingering in the process table—which not only wastes system resources but also prevents the shell from capturing the proper exit statuses. Consequently, the shell would be unable to detect errors in the executed commands, potentially leading to unnoticed failures and resource leaks.
+
+2. The dup2() function is used to redirect input and output file descriptors. Explain why it is necessary to close unused pipe ends after calling dup2(). What could go wrong if you leave pipes open?
+
+After executing dup2() to redirect file descriptors, make sure to close any unused pipe ends.  This is because, even after redirection, the original file descriptors remain open, preventing the system from correctly sending an EOF signal to the reading process.  Leaving these pipe ends open can cause programs to wait indefinitely for input, resource leakage from unclosed file descriptors, possible data starvation, and even deadlocks.
+
+3. Your shell recognizes built-in commands (cd, exit, dragon). Unlike external commands, built-in commands do not require execvp(). Why is cd implemented as a built-in rather than an external command? What challenges would arise if cd were implemented as an external process?
+
+Because cd must change the shell's working directory, it is implemented as a built-in command.  If you ran cd as an external command, it would start a distinct child process.  As a result, any directory change would only affect the child process, and once it exited, the parent shell would resume its original working directory.  This disconnect indicates that the shell would not move directories, rendering the command worthless.
+
+4. Currently, your shell supports a fixed number of piped commands (CMD_MAX). How would you modify your implementation to allow an arbitrary number of piped commands while still handling memory allocation efficiently? What trade-offs would you need to consider?
+
+Replace fixed-sized arrays with dynamically allocated structures. Instead of utilizing a fixed-size command list, you can allocate an array that grows as needed (using realloc()) or a linked list to hold commands as they are parsed. Similarly, dynamically allocate pipe file descriptors to ensure that you only use the memory you need. If the number of commands increases significantly, one additional strategy is to process them in chunks. The drawbacks include higher complexity in memory management—more allocations necessitate more stringent error checking and cleaning. Dynamically enlarging an array or utilizing a linked list adds overhead (for example, linked lists may have lower cache locality than contiguous arrays). While dynamic allocation offers the flexibility to handle arbitrary numbers of piped commands, you must still respect system limits such as the maximum number of open file descriptors and process limits.
+
diff --git a/5-ShellP3/shell_roadmap.md b/5-ShellP3/shell_roadmap.md
new file mode 100644
index 0000000000000000000000000000000000000000..9af14341f8cd435e39cfa8c1bc6666428be203dd
--- /dev/null
+++ b/5-ShellP3/shell_roadmap.md
@@ -0,0 +1,13 @@
+## Proposed Shell Roadmap
+
+Week 5:  Shell CLI Parser Due
+
+Week 6:  Execute Basic Commands
+
+Week 7:  Add support for pipes (extra-credit for file redirection)
+
+Week 8:  Basic socket assignment
+
+Week 9:  Remote Shell Extension
+
+Week 11: Add support for something like `nsenter` to enter a namespace
\ No newline at end of file