diff --git a/Assignment-04/fork-exec-1.png b/Assignment-04/fork-exec-1.png
new file mode 100644
index 0000000000000000000000000000000000000000..56186a921c27a47641e54efbb72397c544f93a32
Binary files /dev/null and b/Assignment-04/fork-exec-1.png differ
diff --git a/Assignment-04/fork-exec-2.png b/Assignment-04/fork-exec-2.png
new file mode 100644
index 0000000000000000000000000000000000000000..30e5f4ff67c5baaaa99bf7fee75e4f2a7b802bde
Binary files /dev/null and b/Assignment-04/fork-exec-2.png differ
diff --git a/Assignment-04/questions.md b/Assignment-04/questions.md
new file mode 100644
index 0000000000000000000000000000000000000000..f3e6ead3c9128d3910fec0fdb3ddef551fd2f55c
--- /dev/null
+++ b/Assignment-04/questions.md
@@ -0,0 +1,41 @@
+1. Can you think of why we use `fork/execvp` instead of just calling `execvp` directly? What value do you think the `fork` provides?
+
+    > **Answer**:  _start here_
+
+2. What happens if the fork() system call fails? How does your implementation handle this scenario?
+
+    > **Answer**:  _start here_
+
+3. How does execvp() find the command to execute? What system environment variable plays a role in this process?
+
+    > **Answer**:  _start here_
+
+4. What is the purpose of calling wait() in the parent process after forking? What would happen if we didn’t call it?
+
+    > **Answer**:  _start here_
+
+5. In the referenced demo code we used WEXITSTATUS(). What information does this provide, and why is it important?
+
+    > **Answer**:  _start here_
+
+6. Describe how your implementation of build_cmd_buff() handles quoted arguments. Why is this necessary?
+
+    > **Answer**:  _start here_
+
+7. What changes did you make to your parsing logic compared to the previous assignment? Were there any unexpected challenges in refactoring your old code?
+
+    > **Answer**:  _start here_
+
+8. For this quesiton, you need to do some research on Linux signals. You can use [this google search](https://www.google.com/search?q=Linux+signals+overview+site%3Aman7.org+OR+site%3Alinux.die.net+OR+site%3Atldp.org&oq=Linux+signals+overview+site%3Aman7.org+OR+site%3Alinux.die.net+OR+site%3Atldp.org&gs_lcrp=EgZjaHJvbWUyBggAEEUYOdIBBzc2MGowajeoAgCwAgA&sourceid=chrome&ie=UTF-8) to get started.
+
+- What is the purpose of signals in a Linux system, and how do they differ from other forms of interprocess communication (IPC)?
+
+    > **Answer**:  _start here_
+
+- Find and describe three commonly used signals (e.g., SIGKILL, SIGTERM, SIGINT). What are their typical use cases?
+
+    > **Answer**:  _start here_
+
+- What happens when a process receives SIGSTOP? Can it be caught or ignored like SIGINT? Why or why not?
+
+    > **Answer**:  _start here_
diff --git a/Assignment-04/readme.md b/Assignment-04/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..a0a38162c5704952d2bb1be57e4872f648c42858
--- /dev/null
+++ b/Assignment-04/readme.md
@@ -0,0 +1,192 @@
+# Assignment: Custom Shell Part 2 - Fork/Exec
+
+This week we will build on our `dsh` Drexel Shell by adding an implementation for the builtin command `cd`, and a `fork/exec` implementation to run "external commands".
+
+This content builds on the prior assignment; if you need a refresher on what a shell is or the difference between built-in and external commands, please review the readme from that assignment.
+
+# Reuse Prior Work!
+
+The `dsh` assignments are meant to be additive. Much of the parsing logic from the last assignement can be re-used in this assignement. The structures are a little different so you might have to refactor some of your code, but that's a great practical lesson in software engineering; the highest quality results come from frequent iteration.
+
+The next section highlights the differences (both conceptually and in file structure) from the prior assignement.
+
+# Differences from Part 1 Assignment
+
+- We've restructured the code slightly to move all implementation details into the lib file (`dshlib.c`) out of `dsh_cli.c`. **You do not need to write any code in `dsh_cli.c`!**
+- This week we'll implement a fork/exec pattern to execute external commands; these commands should execute and behave just as they would if you ran them from your default shell; last week we only printed command lines that we parsed
+- If you did the `dragon` extra credit, we moved the implementation into `dragon.c`
+- We will NOT implement pipe splitting or multiple commands in one command line input; last week we implemented parsing the CLI by pipe just to print commands, but actually implementing pipes to execute commands is beyond the scope of this week's assignement - we will get to it but not this week!
+  - This week we work with a single `cmd_buff` type at a time; we will not use the `command_list_t` from last week
+  - This an example of some refactoring from last week's code, you can adapt your parsing logic but omit the pipe logic until we get to that in a future assignement
+
+# Fork / Exec
+
+Let's introduce two new system calls: fork() and exec(). These calls are fundamental to process creation and execution in all Unix-like operating systems. 
+
+When a process calls fork(), the operating system creates a new child process that is an exact copy of the parent, inheriting its memory, file descriptors, and execution state. The child process receives a return value of 0 from fork(), while the parent receives the child's process ID. After forking, the child process often replaces its memory image with a new executable using one of the exec() family of functions (e.g., execl(), execv(), execvp()). 
+
+Unlike fork(), exec() does not create a new process but instead replaces the calling process’s address space with a new program, preserving file descriptors unless explicitly changed. This mechanism allows Unix shells to execute new programs by first forking a child process and then using exec() to run the desired binary while the parent process waits for the child to complete using wait().
+
+Recall the fork/exec pattern from lecture slides and demo - we are implementing this two-step process using system calls.
+
+![fork-exec](fork-exec-1.png)
+
+![fork-exec](fork-exec-2.png)
+
+Remember that the fork/exec pattern requires you to use conditional branching logic to implement the child path and the parent path in the code. We did a basic demo of this in class using this demo code https://github.com/drexel-systems/SysProg-Class/blob/main/demos/process-thread/2-fork-exec/fork-exec.c. In the demo we used `execv()`, which requires an absolute path to the binary. In this assignement you should use `execvp()`; `execvp()` will search the `PATH` variable locations for binaries. As with the demo, you can use `WEXITSTATUS` to extract the status code from the child process.
+
+# Assignment Details
+
+### Step 1 - Review [./starter/dshlib.h](./starter/dshlib.h)
+
+The file [./starter/dshlib.h](./starter/dshlib.h) contains some useful definitions and types. Review the available resources in this file before you start coding - these are intended to make your work easier and more robust!
+
+### Step 2 - Implement `cd` in [./starter/dshlib.c](./starter/dshlib.c)
+
+Building on your code from last week, implement the `cd` command.
+
+- when called with no arguments, `cd` does nothing (this is different than Linux shell behavior; shells implement `cd` as `cd ~1` or `cd $HOME`; we'll do that in a future assignement)
+- when called with one argument, `chdir()` the current dsh process into the directory provided by argument
+
+### Step 3 - Re-implement Your Main Loop and Parsing Code in exec_local_cmd_loop() [./starter/dshlib.c](./starter/dshlib.c)
+
+Implement `exec_local_cmd_loop()` by refactoring your code from last week to use 1 `cmd_buff` type in the main loop instead of using a command list. 
+
+On each line-of-input parsing, you should populate `cmd_buff` using these rules:
+
+- trim ALL leading and trailing spaces
+- eliminate duplicate spaces UNLESS they are in a quoted string
+- account for quoted strings in input; treat a quoted string with spaces as a single argument
+  - for example, given ` echo    " hello,    world"  ` you would parse this as: `["echo", " hello,    world"]`; note that spaces inside the double quotes were preserved
+
+`cmd_buff` is provided to get you started. You don't have to use this struct, but it is all that's required to parse a line of input into a `cmd_buff`.
+
+```c
+typedef struct cmd_buff
+{
+    int  argc;
+    char *argv[CMD_ARGV_MAX];
+    char *_cmd_buffer;
+} cmd_buff_t;
+```
+
+### Step 4 - Implement fork/exec pattern in [./starter/dshlib.c](./starter/dshlib.c)
+
+Implement fork/exec of external commands using `execvp()`. This is a pretty straight-forward task; once the command and it's arguments are parsed, you can pass them straight to `execvp()`.
+
+Don't forget to implement a wait of the return code, and extraction of the return code. We're not doing anything with the return code yet, unless you are doing extra credit.
+
+### Step 5 - Create BATS Tests
+
+So far we've provided pre-built a `test.sh` file with assigments. These files use the [bash-based BATS unit test framework](https://bats-core.readthedocs.io/en/stable/tutorial.html#your-first-test).
+
+Going forward, assignements will have a bats folder structure like this:
+
+- your-workspace-folder/
+  - bats/assignement_tests.sh
+  - bats/student_tests.sh
+
+**bats/assignment_tests.sh**
+
+- DO NOT EDIT THIS FILE
+- assignment_tests.sh contains tests that must pass to meet the requirements of the assignment
+- it is run as part of `make test`; remember to run this to verify your code
+
+**bats/student_tests.sh**
+
+- this file must contain YOUR test suite to help verify your code
+- for some assignments you will be graded on creation of the tests, and it is your responsibility to make sure the tests provide adequate coverage
+- this file is also run with `make test`
+
+**About BATS**
+
+Key points of BATS testing - 
+
+- file header is `#!/usr/bin/env bats` such that you can execute tests by simply running `./test_file.sh`
+- incorrect `\r\n` can cause execution to fail - easiest way to avoid is use the [drexel-cci](https://marketplace.visualstudio.com/items?itemName=bdlilley.drexel-cci) extension to download assignement code; if you do not use this, make sure you do not copy any windows line endings into the file during a copy/paste
+- assertions are in square braces
+  - example: check output `[ "$stripped_output" = "$expected_output" ]`
+  - example: check return code `$status` variable: `[ "$status" -eq 0 ]`
+
+Please review the BATS link above if you have questions on syntax or usage. You can also look at test files we provided with assignment for more examples. **You will be graded on the quality of breadth of your unit test suite.**
+
+What this means to you - follow these guidelines when writing tests:
+
+- cover every type of functionallity; for example, you need to cover built-in command and external commands
+- test for all use cases / edge cases - for example, for the built-in `cd` command you might want to verify that:
+  - when called without arguments, the working dir doesn't change (you could verify with `pwd`)
+  - when called with one argument, it changes directory to the given argument (again, you can verify with `pwd`)
+- be thorough - try to cover all the possible ways a user might break you program!
+- write tests first; this is called "Test Driven Development" - to learn more, check out [Martin Fowler on TDD](https://martinfowler.com/bliki/TestDrivenDevelopment.html)
+
+### Step 6 - Answer Questions
+
+Answer the questions located in [./questions.md](./questions.md).
+
+### Sample Run with Sample Output
+The below shows a sample run executing multiple commands and the expected program output:
+
+```bash
+./dsh 
+dsh2> uname -a
+Linux ubuntu 6.12.10-orbstack-00297-gf8f6e015b993 #42 SMP Sun Jan 19 03:00:07 UTC 2025 aarch64 aarch64 aarch64 GNU/Linux
+dsh2> uname
+Linux
+dsh2> echo "hello,      world"
+hello,      world
+dsh2> pwd
+/home/ben/SysProg-Class-Solutions/assignments/4-ShellP2/solution
+dsh2> ls 
+dir1  dragon.c  dragon.txt  dsh  dsh_cli.c  dshlib.c  dshlib.h  fancy_code_do_not_use  makefile  shell_roadmap.md  test.sh  wip
+dsh2> cd dir1
+dsh2> pwd
+/home/ben/SysProg-Class-Solutions/assignments/4-ShellP2/solution/dir1
+dsh2> 
+```
+
+### Extra Credit: +10
+
+This week we're being naive about return codes from external commands; if there is any kind of failure, we just print the `CMD_ERR_EXECUTE` message.
+
+Implement return code handling for extra credit. Hint - check out `man execvp` and review the `errno` and return value information.
+
+Errno and value definitions are in `#include <errno.h>`. 
+
+Tips:
+
+- in the child process, `errno` will contain the error value if there was an error; so return this from your child process
+- the `WEXITSTATUS` macro will extract `errno`
+
+Requirements:
+
+- Check for all file-related status codes from `errno.h` that you might expect when trying to invoke a binary from $PATH; for example - `ENOENT` is file not found, `EACCES` is permission denied
+- Print a suitable message for each error you detect
+- Implement a "rc" builtin command that prints the return code of the last operation; for example, if the child process returns `-1`, `rc` should output `-1`
+- **Don't forget to add unit tests in** `./bats/student_tests.sh`!
+
+Example run:
+
+```bash
+./dsh
+dsh2> not_exists
+Command not found in PATH
+dsh2> rc
+2
+dsh2>
+```
+
+This extra credit is a precursor to implementing variables; shells set the variable `$?` to the return code of the last executed command. A full variable implementation is beyond the scope of this assignement, so we opted to create the `rc` builtin to mimic the behavior of the `$?` variable in other shells.
+
+#### Grading Rubric
+
+This assignment will be weighted 50 points.
+
+- 25 points:  Correct implementation of required functionality
+- 5 points:  Code quality (how easy is your solution to follow)
+- 15 points: Answering the written questions: [questions.md](./questions.md)
+- 15 points: Quality and breadth of BATS unit tests
+- 10 points:  [EXTRA CREDIT] handle return codes for execvp
+
+Total points achievable is 70/60. 
+
+
diff --git a/Assignment-04/starter/.debug/launch.json b/Assignment-04/starter/.debug/launch.json
new file mode 100644
index 0000000000000000000000000000000000000000..aedc1efa4984aaf3265f70a3581d4956d569cf26
--- /dev/null
+++ b/Assignment-04/starter/.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/Assignment-04/starter/.debug/tasks.json b/Assignment-04/starter/.debug/tasks.json
new file mode 100644
index 0000000000000000000000000000000000000000..71013e37fe8ec4999fb301dae2b55b1fc9b72543
--- /dev/null
+++ b/Assignment-04/starter/.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/Assignment-04/starter/bats/assignment_tests.sh b/Assignment-04/starter/bats/assignment_tests.sh
new file mode 100644
index 0000000000000000000000000000000000000000..794b5d8d307cc8fffeb3eb23ade710823c61c9b0
--- /dev/null
+++ b/Assignment-04/starter/bats/assignment_tests.sh
@@ -0,0 +1,118 @@
+#!/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 "Change directory" {
+    current=$(pwd)
+
+    cd /tmp
+    mkdir -p dsh-test
+
+    run "${current}/dsh" <<EOF                
+cd dsh-test
+pwd
+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="/tmp/dsh-testdsh2>dsh2>dsh2>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 ]
+}
+
+@test "Change directory - no args" {
+    current=$(pwd)
+
+    cd /tmp
+    mkdir -p dsh-test
+
+    run "${current}/dsh" <<EOF                
+cd
+pwd
+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="/tmpdsh2>dsh2>dsh2>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 ]
+}
+
+
+@test "Which which ... which?" {
+    run "./dsh" <<EOF                
+which which
+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="/usr/bin/whichdsh2>dsh2>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" ]
+}
+
+@test "It handles quoted spaces" {
+    run "./dsh" <<EOF                
+   echo " hello     world     " 
+EOF
+
+    # Strip all whitespace (spaces, tabs, newlines) from the output
+    stripped_output=$(echo "$output" | tr -d '\t\n\r\f\v')
+
+    # Expected output with all whitespace removed for easier matching
+    expected_output=" hello     world     dsh2> dsh2> cmd loop returned 0"
+
+    # 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" ]
+}
\ No newline at end of file
diff --git a/Assignment-04/starter/bats/student_tests.sh b/Assignment-04/starter/bats/student_tests.sh
new file mode 100644
index 0000000000000000000000000000000000000000..1241ea9cfc3db5e7d9276cc665f87f03a2d0c727
--- /dev/null
+++ b/Assignment-04/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 ]
+}
\ No newline at end of file
diff --git a/Assignment-04/starter/dragon.c b/Assignment-04/starter/dragon.c
new file mode 100644
index 0000000000000000000000000000000000000000..83d01f243de7c7c98767c7dfd328588ec1f4b292
--- /dev/null
+++ b/Assignment-04/starter/dragon.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+// EXTRA CREDIT - print the drexel dragon from the readme.md
+extern void print_dragon(){
+  // TODO implement 
+}
diff --git a/Assignment-04/starter/dsh_cli.c b/Assignment-04/starter/dsh_cli.c
new file mode 100644
index 0000000000000000000000000000000000000000..9262cf457e6b235b19999efa04153e1de0962255
--- /dev/null
+++ b/Assignment-04/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/Assignment-04/starter/dshlib.c b/Assignment-04/starter/dshlib.c
new file mode 100644
index 0000000000000000000000000000000000000000..2a47deca0c5a66feeb1c6da5e4ab493dd5643053
--- /dev/null
+++ b/Assignment-04/starter/dshlib.c
@@ -0,0 +1,71 @@
+#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()
+ */
+int exec_local_cmd_loop()
+{
+    char *cmd_buff;
+    int rc = 0;
+    cmd_buff_t cmd;
+
+    // TODO IMPLEMENT MAIN LOOP
+
+    // TODO IMPLEMENT parsing input to cmd_buff_t *cmd_buff
+
+    // TODO IMPLEMENT if built-in command, execute builtin logic for exit, cd (extra credit: dragon)
+    // the cd command should chdir to the provided directory; if no directory is provided, do nothing
+
+    // TODO IMPLEMENT if not built-in command, fork/exec as an external command
+    // for example, if the user input is "ls -l", you would fork/exec the command "ls" with the arg "-l"
+
+    return OK;
+}
diff --git a/Assignment-04/starter/dshlib.h b/Assignment-04/starter/dshlib.h
new file mode 100644
index 0000000000000000000000000000000000000000..32059ccede7dec47a785b55185b1f5dda105145d
--- /dev/null
+++ b/Assignment-04/starter/dshlib.h
@@ -0,0 +1,79 @@
+#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 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;
+*/
+
+
+//Special character #defines
+#define SPACE_CHAR  ' '
+#define PIPE_CHAR   '|'
+#define PIPE_STRING "|"
+
+#define SH_PROMPT "dsh2> "
+#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
+#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);
+
+//built in command stuff
+typedef enum {
+    BI_CMD_EXIT,
+    BI_CMD_DRAGON,
+    BI_CMD_CD,
+    BI_NOT_BI,
+    BI_EXECUTED,
+    BI_RC,
+} 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);
+
+
+
+
+//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/Assignment-04/starter/gitignore.txt b/Assignment-04/starter/gitignore.txt
new file mode 100644
index 0000000000000000000000000000000000000000..eb47a8e82ad127f89b6fdbbf0f531cb8865b7bf8
--- /dev/null
+++ b/Assignment-04/starter/gitignore.txt
@@ -0,0 +1 @@
+dsh
\ No newline at end of file
diff --git a/Assignment-04/starter/makefile b/Assignment-04/starter/makefile
new file mode 100644
index 0000000000000000000000000000000000000000..b14b0723e23ea2036f0220406b40a93e6a0cd283
--- /dev/null
+++ b/Assignment-04/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
diff --git a/Assignment-04/starter/shell_roadmap.md b/Assignment-04/starter/shell_roadmap.md
new file mode 100644
index 0000000000000000000000000000000000000000..9af14341f8cd435e39cfa8c1bc6666428be203dd
--- /dev/null
+++ b/Assignment-04/starter/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