diff --git a/hw4/fork-exec-1.png b/hw4/fork-exec-1.png
new file mode 100644
index 0000000000000000000000000000000000000000..56186a921c27a47641e54efbb72397c544f93a32
Binary files /dev/null and b/hw4/fork-exec-1.png differ
diff --git a/hw4/fork-exec-2.png b/hw4/fork-exec-2.png
new file mode 100644
index 0000000000000000000000000000000000000000..30e5f4ff67c5baaaa99bf7fee75e4f2a7b802bde
Binary files /dev/null and b/hw4/fork-exec-2.png differ
diff --git a/hw4/questions.md b/hw4/questions.md
new file mode 100644
index 0000000000000000000000000000000000000000..f3e6ead3c9128d3910fec0fdb3ddef551fd2f55c
--- /dev/null
+++ b/hw4/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/hw4/readme.md b/hw4/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..a0a38162c5704952d2bb1be57e4872f648c42858
--- /dev/null
+++ b/hw4/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/hw4/starter/.debug/launch.json b/hw4/starter/.debug/launch.json
new file mode 100644
index 0000000000000000000000000000000000000000..aedc1efa4984aaf3265f70a3581d4956d569cf26
--- /dev/null
+++ b/hw4/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/hw4/starter/.debug/tasks.json b/hw4/starter/.debug/tasks.json
new file mode 100644
index 0000000000000000000000000000000000000000..71013e37fe8ec4999fb301dae2b55b1fc9b72543
--- /dev/null
+++ b/hw4/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/hw4/starter/.gitignore b/hw4/starter/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..eb47a8e82ad127f89b6fdbbf0f531cb8865b7bf8
--- /dev/null
+++ b/hw4/starter/.gitignore
@@ -0,0 +1 @@
+dsh
\ No newline at end of file
diff --git a/hw4/starter/bats/assignment_tests.sh b/hw4/starter/bats/assignment_tests.sh
new file mode 100755
index 0000000000000000000000000000000000000000..794b5d8d307cc8fffeb3eb23ade710823c61c9b0
--- /dev/null
+++ b/hw4/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/hw4/starter/bats/student_tests.sh b/hw4/starter/bats/student_tests.sh
new file mode 100755
index 0000000000000000000000000000000000000000..638bc341446f7580a80c2aff52971b8023407ea8
--- /dev/null
+++ b/hw4/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/hw4/starter/dragon.c b/hw4/starter/dragon.c
new file mode 100644
index 0000000000000000000000000000000000000000..83d01f243de7c7c98767c7dfd328588ec1f4b292
--- /dev/null
+++ b/hw4/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/hw4/starter/dsh.dSYM/Contents/Info.plist b/hw4/starter/dsh.dSYM/Contents/Info.plist
new file mode 100644
index 0000000000000000000000000000000000000000..ec2ee631eae4517146ef8292a4ae925d46718d5c
--- /dev/null
+++ b/hw4/starter/dsh.dSYM/Contents/Info.plist
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+	<dict>
+		<key>CFBundleDevelopmentRegion</key>
+		<string>English</string>
+		<key>CFBundleIdentifier</key>
+		<string>com.apple.xcode.dsym.dsh</string>
+		<key>CFBundleInfoDictionaryVersion</key>
+		<string>6.0</string>
+		<key>CFBundlePackageType</key>
+		<string>dSYM</string>
+		<key>CFBundleSignature</key>
+		<string>????</string>
+		<key>CFBundleShortVersionString</key>
+		<string>1.0</string>
+		<key>CFBundleVersion</key>
+		<string>1</string>
+	</dict>
+</plist>
diff --git a/hw4/starter/dsh_cli.c b/hw4/starter/dsh_cli.c
new file mode 100644
index 0000000000000000000000000000000000000000..9262cf457e6b235b19999efa04153e1de0962255
--- /dev/null
+++ b/hw4/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/hw4/starter/dshlib.c b/hw4/starter/dshlib.c
new file mode 100644
index 0000000000000000000000000000000000000000..4b002a070c1966f1d015f430b978d39dba57b874
--- /dev/null
+++ b/hw4/starter/dshlib.c
@@ -0,0 +1,185 @@
+#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()
+ */
+
+cmd_buff_t parse_command(char *cmd_buff, cmd_buff_t cmd){
+    char *pointer = cmd_buff;
+    while (*pointer == ' '){
+        pointer++;
+    }
+    char *space;
+    cmd.argc = 0;
+    int count = 0;
+    char *org = pointer;
+
+    while (pointer!=NULL){
+        if (*pointer=='\"'){
+            pointer++;
+            org = pointer;
+            while(*pointer!='\"'){
+                pointer++;
+            }
+            space = pointer;
+        } else{
+            space = strchr(pointer, SPACE_CHAR);
+            if (space==NULL){
+                size_t exe_length = strlen(pointer);
+                cmd.argv[count] = malloc(exe_length + 1);
+                strncpy(cmd.argv[count], org, exe_length);
+                cmd.argv[count][exe_length] = '\0';
+                if (strcmp(cmd.argv[count],"") != 0){
+                    count++;
+                    cmd.argc++;
+                }
+                pointer = space;
+                continue;
+            }
+        }
+
+        size_t exe_length = space - org;
+        cmd.argv[count] = malloc(exe_length + 1);
+        strncpy(cmd.argv[count], org, exe_length);
+        cmd.argv[count][exe_length] = '\0';
+        count++;
+        cmd.argc++;
+        pointer = space+1; 
+        org = pointer;
+    }
+    
+
+    // printf("\"%s\" ", cmd.argv[0]);
+    // for (int i=1; i<count; i++){
+    //     printf(", \"%s\" ", cmd.argv[i]);
+    
+    // }
+    // printf("\n");
+    cmd.argv[cmd.argc] = NULL;
+    return cmd;
+}
+
+int exec_local_cmd_loop()
+{
+    char *cmd_buff = malloc(SH_CMD_MAX);
+    int rc = 0;
+    cmd_buff_t cmd;
+
+    // TODO IMPLEMENT MAIN LOOP
+    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';
+
+        if (cmd_buff[0] == '\0'){
+            printf(CMD_WARN_NO_CMD);
+            continue;
+        }
+
+    // TODO IMPLEMENT parsing input to cmd_buff_t *cmd_buff
+        cmd = parse_command(cmd_buff, cmd);
+
+    // 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
+        if (strcmp(cmd_buff, EXIT_CMD) == 0){
+            break;
+        }
+        if (strcmp(cmd.argv[0], "cd") == 0){
+            
+            if (cmd.argc < 2){
+
+                continue;
+            } else {
+                // if(chdir(cmd.argv[1]) == 0){
+                //     printf("Success");
+                // } else{
+                //     printf("%s\n", cmd.argv[1]);
+                // }
+                // printf("ok\n");
+                chdir(cmd.argv[1]);
+                // printf()
+            }
+        } else {
+    
+            pid_t pid = fork();
+
+            if (pid==0){
+                int i = execvp(cmd.argv[0], cmd.argv);
+                if (i==-1){
+                    printf("fail\n");
+                    exit(1);
+                }
+                exit(0);
+            } else {
+                int wait_code;
+                waitpid(pid, &wait_code, 0);
+            }
+        }
+
+        for (int i=1; i<cmd.argc; i++){
+            free(cmd.argv[i]);
+        }
+
+    
+    }
+    
+
+    // 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"
+
+    free(cmd_buff);
+    return OK;
+}
+
diff --git a/hw4/starter/dshlib.h b/hw4/starter/dshlib.h
new file mode 100644
index 0000000000000000000000000000000000000000..32059ccede7dec47a785b55185b1f5dda105145d
--- /dev/null
+++ b/hw4/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/hw4/starter/makefile b/hw4/starter/makefile
new file mode 100644
index 0000000000000000000000000000000000000000..b14b0723e23ea2036f0220406b40a93e6a0cd283
--- /dev/null
+++ b/hw4/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/hw4/starter/ok.dSYM/Contents/Info.plist b/hw4/starter/ok.dSYM/Contents/Info.plist
new file mode 100644
index 0000000000000000000000000000000000000000..01a73dbe2c82ef0bcd4c0e1ed9942751d19ecc62
--- /dev/null
+++ b/hw4/starter/ok.dSYM/Contents/Info.plist
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+	<dict>
+		<key>CFBundleDevelopmentRegion</key>
+		<string>English</string>
+		<key>CFBundleIdentifier</key>
+		<string>com.apple.xcode.dsym.ok</string>
+		<key>CFBundleInfoDictionaryVersion</key>
+		<string>6.0</string>
+		<key>CFBundlePackageType</key>
+		<string>dSYM</string>
+		<key>CFBundleSignature</key>
+		<string>????</string>
+		<key>CFBundleShortVersionString</key>
+		<string>1.0</string>
+		<key>CFBundleVersion</key>
+		<string>1</string>
+	</dict>
+</plist>
diff --git a/hw4/starter/ok.dSYM/Contents/Resources/DWARF/ok b/hw4/starter/ok.dSYM/Contents/Resources/DWARF/ok
new file mode 100644
index 0000000000000000000000000000000000000000..f5692c73526cca8881535b752238d63bb593d139
Binary files /dev/null and b/hw4/starter/ok.dSYM/Contents/Resources/DWARF/ok differ
diff --git a/hw4/starter/shell_roadmap.md b/hw4/starter/shell_roadmap.md
new file mode 100644
index 0000000000000000000000000000000000000000..9af14341f8cd435e39cfa8c1bc6666428be203dd
--- /dev/null
+++ b/hw4/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