diff --git a/README.md b/README.md
index 1b79cf1..a6996ef 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,34 @@ proj learncpp
 
 If the project exists in your project directory, it will spawn a subshell in that directory. Advanced usage and hooks are detailed below, but you can use it as a glorified `cd` if that's all you need.
 
+## Behavior
+
+When invoked as specified in usage (with any number of valid flags plus exactly one non-flag argument referred to here as `$arg1`), `proj` will do the following:
+
+* `cd` to `project_dir` (normally `~/Projects`)
+
+* Check for the existence of `$arg1`
+
+ * If `$arg1` is a directory or symbolic link, proceed
+
+ * If `$arg1` is any other type of file, panic
+
+ * If `$arg1` does not exist, then:
+
+   * Execute the pre-create hook if configured to do so
+
+   * Create `$arg1` as a directory
+
+   * Initialize an empty git repository if configured to do so
+
+ * `cd` to `$arg1`
+
+ * Execute a subshell, and
+
+   * Source `.projenv` if configured to do so
+
+   * Execute `$SHELL`
+
 ## Flags
 
 flag|description|args
@@ -26,4 +54,13 @@ git\_auto\_init\_always|If not set to `0`, automatically initialize a git reposi
 git\_auto\_init\_gitignore|A colon-separated ($PATH-style) list of items to include in the initial `.gitignore`|`*.swp`
 hook\_pre\_create|Path to a script invoked (not sourced) before a project is created. Script will be executed relative to `project_dir`|Empty string
 hook\_pre\_spawn|Path to a script invoked (not sourced) before a shell is spawned in the project directory. Script will be executed relative to the project's root directory|Empty string
+hook\_env|Path to a script to *source in* after entering a project directory but before a shell is spawned. Script will be sourced relative to the project's root directory|`.projenv`
 project\_dir|Path to where projects should be stored.|`$HOME/Projects`
+
+## Return Codes
+
+code|description
+---|---
+0|Success
+2|Invalid flag or missing flag argument
+50|Non-flag arguments have errors or are nonsensical
diff --git a/proj b/proj
index 052144d..f764003 100755
--- a/proj
+++ b/proj
@@ -17,6 +17,7 @@ declare -a _config=(
 	[git_auto_init_gitignore]="*.swp"
 	[hook_pre_create]=""
 	[hook_pre_spawn]=""
+	[hook_env]=".projenv"
 	[project_dir]="$HOME/Projects"
 )
 declare _optconfigfile="${XDG_CONFIG_HOME:-$HOME/.config}/${_name}.conf"
@@ -71,6 +72,15 @@ has() {
 	done
 	return 0
 }
+validateline() {
+	# Takes a line and errors if it's just whitespace or a comment
+	local linenows=${1//[[:space:]]}
+	if ! [ "${1#\#}" = "$1" ] || [ -z "$linenows" ]; then
+		return 1
+	fi
+	return 0
+}
+
 
 # Core program functions
 printhelp() {
@@ -85,6 +95,10 @@ Copyright (c) 2021 rehashedsalt@cock.li
 Licensed under the MIT license
 EOF
 }
+proj() {
+	# Do the do
+	:
+}
 
 # Main
 main() {
@@ -137,6 +151,10 @@ main() {
 	fi
 	# Validate critical options
 	# TODO: That
+	# Validate arguments
+	if [ "${#_args[@]}" -ne "1" ]; then
+		error "Required exactly 1 argument, got ${#_args[@]}" 50
+	fi
 	# Validate core program dependencies
 	log "Validating dependencies" 2
 	if ! has basename; then
@@ -144,8 +162,7 @@ main() {
 	fi
 
 	# Do the do
-	# TODO: The do
-	warn "Nothing to do"
+	proj
 	exit 0
 }