diff --git a/assignments/assignment-5/questions.md b/assignments/assignment-5/questions.md
new file mode 100644
index 0000000000000000000000000000000000000000..b4789bf92878bf1116e24c4c9ea28110d6d5f4e7
--- /dev/null
+++ b/assignments/assignment-5/questions.md
@@ -0,0 +1,15 @@
+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?
+
+_answer here_
+
+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?
+
+_answer here_
+
+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?
+
+_answer here_
+
+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?
+
+_answer here_
diff --git a/assignments/assignment-5/starter/.debug/launch.json b/assignments/assignment-5/starter/.debug/launch.json
new file mode 100644
index 0000000000000000000000000000000000000000..72e404dc24f1893e3fe252a15d6e112e4807ad4c
--- /dev/null
+++ b/assignments/assignment-5/starter/.debug/launch.json
@@ -0,0 +1,29 @@
+{
+    "configurations": [
+        {
+            "name": "(gdb) 5-ShellP3",
+            "type": "cppdbg",
+            "request": "launch",
+            "program": "${workspaceFolder}/5-ShellP3/starter/dsh",
+            "args": [""],
+            "stopAtEntry": false,
+            "cwd": "${workspaceFolder}/5-ShellP3/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 5-ShellP3"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/assignments/assignment-5/starter/.debug/tasks.json b/assignments/assignment-5/starter/.debug/tasks.json
new file mode 100644
index 0000000000000000000000000000000000000000..3fb660801e6eae56c837af79541c9eadffc14a0a
--- /dev/null
+++ b/assignments/assignment-5/starter/.debug/tasks.json
@@ -0,0 +1,20 @@
+{
+    "version": "2.0.0",
+    "tasks": [
+      {
+        "label": "Build 5-ShellP3",
+        "type": "shell",
+        "command": "make",
+        "group": {
+          "kind": "build",
+          "isDefault": true
+        },
+        "options": {
+          "cwd": "${workspaceFolder}/5-ShellP3/starter"
+      },
+        "problemMatcher": ["$gcc"],
+        "detail": "Runs the 'make' command to build the project."
+      }
+    ]
+  }
+  
\ No newline at end of file
diff --git a/assignments/assignment-5/starter/bats/assignment_tests.sh b/assignments/assignment-5/starter/bats/assignment_tests.sh
new file mode 100755
index 0000000000000000000000000000000000000000..ac345604db4e15a8253e8d88c595717e28172fa5
--- /dev/null
+++ b/assignments/assignment-5/starter/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 ]
+}
diff --git a/assignments/assignment-5/starter/bats/student_tests.sh b/assignments/assignment-5/starter/bats/student_tests.sh
new file mode 100755
index 0000000000000000000000000000000000000000..638bc341446f7580a80c2aff52971b8023407ea8
--- /dev/null
+++ b/assignments/assignment-5/starter/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 ]
+}
diff --git a/assignments/assignment-5/starter/dsh b/assignments/assignment-5/starter/dsh
new file mode 100755
index 0000000000000000000000000000000000000000..3bd5b8ef487637348974bfa0bb6239633ffe36a4
Binary files /dev/null and b/assignments/assignment-5/starter/dsh differ
diff --git a/assignments/assignment-5/starter/dsh_cli.c b/assignments/assignment-5/starter/dsh_cli.c
new file mode 100644
index 0000000000000000000000000000000000000000..9262cf457e6b235b19999efa04153e1de0962255
--- /dev/null
+++ b/assignments/assignment-5/starter/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/assignments/assignment-5/starter/dshlib.c b/assignments/assignment-5/starter/dshlib.c
new file mode 100644
index 0000000000000000000000000000000000000000..0531d2209392ebd5427de44f6105ee7f6986ec4a
--- /dev/null
+++ b/assignments/assignment-5/starter/dshlib.c
@@ -0,0 +1,300 @@
+#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 "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()
+ */
+
+void trim_spaces(char *str) {
+	while (*str && isspace((unsigned char)*str)) {
+		str++;
+	}
+
+	size_t len = strlen(str);
+	while (len > 0 && isspace((unsigned char)str[len - 1])) {
+		str[len - 1] = '\0';
+		len--;
+	}
+}
+
+Built_In_Cmds match_command(const char *input) {
+	if(strcmp(input, EXIT_CMD) == 0) {
+		return BI_CMD_EXIT;
+	}
+	else if(strcmp(input, "dragon") == 0) {
+		return BI_CMD_DRAGON;
+	}
+	else if(strcmp(input, "cd") == 0) {
+		return BI_CMD_CD;
+	}
+	else {
+		return BI_NOT_BI;
+	}
+}
+
+Built_In_Cmds exec_built_in_cmd(cmd_buff_t *cmd) {
+	if(cmd->argc == 0) {
+		return BI_NOT_BI;
+	}
+
+	if(strcmp(cmd->argv[0], "cd") == 0) {
+		if(cmd->argc == 2) {
+			if(chdir(cmd->argv[1]) == -1) {
+				perror("cd failed");
+			}
+		}
+
+		return BI_CMD_CD;
+	}
+
+	return BI_NOT_BI;
+}
+
+int build_cmd_list(char *cmd_line, command_list_t *clist) {
+	printf("Before trimming the cmd_line in build_cmd_list: '%s'\n", cmd_line);
+	trim_spaces(cmd_line);	
+	printf("Trimmed cmd_line: '%s'\n", cmd_line);
+
+	char *cmd_tok_save = NULL;
+	char *cmd_tok = strtok_r(cmd_line, PIPE_STRING, &cmd_tok_save);
+
+	int index = 0;
+
+	while(cmd_tok != NULL) {
+		trim_spaces(cmd_tok);
+
+		printf("Command %d: '%s'\n", index, cmd_tok);
+
+		if(index >= CMD_MAX) {
+			return ERR_TOO_MANY_COMMANDS;
+		}
+
+		cmd_buff_t *cmd = &clist->commands[index];
+		cmd->argc = 0;
+		cmd->_cmd_buffer = cmd_tok;
+		
+		printf("Command %d (before args parsing): '%s'\n", index, cmd_tok);
+
+		char *arg_tok_save = NULL;
+		char *arg_tok = strtok_r(cmd_tok, " ", &arg_tok_save);
+
+		while(arg_tok != NULL && cmd->argc < CMD_ARGV_MAX) {
+			trim_spaces(arg_tok);
+
+			printf("Command %d: argv[%d]: '%s'\n", index, cmd->argc, arg_tok);
+
+			cmd->argv[cmd->argc] = arg_tok;
+			cmd->argc++;
+
+			arg_tok = strtok_r(NULL, " ", &arg_tok_save);
+		}
+
+		printf("Command %d finished parsing. argc = %d\n", index, cmd->argc);
+
+		index++;
+		cmd_tok = strtok_r(NULL, PIPE_STRING, &cmd_tok_save);
+	}
+
+	clist->num = index;
+	printf("Total number of commands: %d\n", clist->num);
+	return OK;
+}
+
+int exec_cmd(cmd_buff_t *cmd, int cmd_index, command_list_t *clist) {
+	int pipe_fds[2];
+	pid_t pid;
+
+	int is_last_cmd = (cmd_index == clist->num - 1);
+
+	printf("Command %d: is_last_cmd = %d\n", cmd_index, is_last_cmd);
+
+	if(!is_last_cmd) {
+		if(pipe(pipe_fds) == -1) {
+			perror("Pipe failed");
+			return -1;
+		}
+
+		printf("Command %d: Pipe created with fd[0] = %d, fd[1] = %d\n", cmd_index, pipe_fds[0], pipe_fds[1]);
+	}
+
+	pid = fork();
+
+	if(pid == -1) {
+		perror("Fork failed");
+		return -1;
+	}
+
+	if(pid == 0) {
+
+		// Debug: Print argv to verify contents
+        	printf("Command %d: execvp arguments:\n", cmd_index);
+        	for (int i = 0; cmd->argv[i] != NULL; i++) {
+            		printf("argv[%d]: %s\n", i, cmd->argv[i]);
+        	}
+
+		if(cmd_index > 0) {
+			if(dup2(clist->pipes[cmd_index - 1][0], STDIN_FILENO) == -1) {
+				perror("Failed to redirect stdin");
+				exit(1);
+			}
+			printf("Command %d: stdin redirected from pipe[%d][0] to STDIN_FILENO\n", cmd_index, cmd_index - 1);
+		}
+
+		if(!is_last_cmd) {
+			if(dup2(pipe_fds[1], STDOUT_FILENO) == -1) {
+				perror("Failed to redirect stdout");
+				exit(1);
+			}
+			printf("Command %d: stdout redirected to pipe[%d][1] from STDOUT_FILENO\n", cmd_index, cmd_index);
+		}
+
+		for(int i = 0; i < clist->num - 1; i++) {
+			printf("Command %d: Closing pipe[%d][0] and pipe[%d][1]\n", cmd_index, i, i);
+			close(clist->pipes[i][0]);
+			close(clist->pipes[i][1]);
+		}
+
+		close(pipe_fds[0]);
+		close(pipe_fds[1]);
+
+		if(execvp(cmd->argv[0], cmd->argv) == -1) {
+			perror("Execvp failed");
+			exit(1);
+		}
+	}
+	else {
+		if(!is_last_cmd) {
+			close(pipe_fds[1]);
+			printf("Command %d: Parent closing pipe[%d][1]\n", cmd_index, cmd_index);
+		}
+
+		/*
+		for(int i = 0; i < clist->num - 1; i++) {
+			close(clist->pipes[i][0]);
+			close(clist->pipes[i][1]);
+		}
+		*/
+
+		if(cmd_index > 0) {
+			close(clist->pipes[cmd_index - 1][0]);
+			printf("Command %d: Parent closing pipe[%d][0]\n", cmd_index, cmd_index - 1);
+		}
+
+		int status;
+		waitpid(pid, &status, 0);
+		printf("Command %d: Child process finished with status %d\n", cmd_index, status);
+	}
+	return OK;
+}
+
+int exec_local_cmd_loop() {
+
+	char *cmd_buff = malloc(SH_CMD_MAX * sizeof(char));
+	if (cmd_buff == NULL) {
+		fprintf(stderr, "Memory allocation failed\n");
+		return ERR_MEMORY;
+	}
+
+	int rc = 0;
+
+	command_list_t clist;
+
+
+	while(1) {
+		printf("%s", SH_PROMPT);
+		if(fgets(cmd_buff, ARG_MAX, stdin) == NULL) {
+			printf("\n");
+			break;
+		}
+
+		printf("Raw input: '%s'\n", cmd_buff);
+
+		// remove the trailing \n from cmd_buff
+		cmd_buff[strcspn(cmd_buff, "\n")] = '\0';
+
+		// IMPLEMENT THE REST OF THE REQUIREMENTS
+
+		trim_spaces(cmd_buff);
+		printf("Trimmed input in exec_local_cmd_loop: '%s'\n", cmd_buff);
+
+		if(strlen(cmd_buff) == 0) {
+			printf(CMD_WARN_NO_CMD);
+			continue;
+		}
+
+		if(strcmp(cmd_buff, EXIT_CMD) == 0) {
+			free(cmd_buff);
+			exit(OK);
+		}
+
+		rc = build_cmd_list(cmd_buff, &clist);
+		printf("RC value: %d\n", rc);
+
+		switch(rc) {
+			case OK:
+				for(int i = 0; i < clist.num; i++) {
+					if(exec_built_in_cmd(&clist.commands[i]) == BI_NOT_BI) {
+						exec_cmd(&clist.commands[i], i, &clist);
+					}
+				}
+				break;
+			case WARN_NO_CMDS:
+				printf(CMD_WARN_NO_CMD);
+				break;
+			case ERR_TOO_MANY_COMMANDS:
+				printf(CMD_ERR_PIPE_LIMIT, CMD_MAX);
+				break;
+		}
+	}
+
+	free(cmd_buff);
+	return OK;
+}
diff --git a/assignments/assignment-5/starter/dshlib.h b/assignments/assignment-5/starter/dshlib.h
new file mode 100644
index 0000000000000000000000000000000000000000..c401a16ee46bedab9d21016cd58ce3eafa02b795
--- /dev/null
+++ b/assignments/assignment-5/starter/dshlib.h
@@ -0,0 +1,94 @@
+#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
+
+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];
+    int pipes[CMD_MAX - 1][2];
+}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);
+
+//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 cmd_index, command_list_t *clist);
+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
diff --git a/assignments/assignment-5/starter/makefile b/assignments/assignment-5/starter/makefile
new file mode 100644
index 0000000000000000000000000000000000000000..b14b0723e23ea2036f0220406b40a93e6a0cd283
--- /dev/null
+++ b/assignments/assignment-5/starter/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