diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..c38fa4e005685a861be5fdbe8fcbb03f84a216b0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+.idea
+*.iml
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..14e1a4ac1c8e80578f9fb57a4e3cd3038474506e
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,9 @@
+image: alpine:latest
+
+lint:shell-script:
+  stage: test
+  image: koalaman/shellcheck-alpine:latest
+  before_script:
+    - shellcheck -V
+  script:
+    - find bin -type f -name "*" -exec shellcheck {} \;
diff --git a/README.md b/README.md
index 5a209b4207728f8da04276d98df221e0c09ec75d..522e6d4403f108d193f00ea7a60d18807e70bf3c 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,55 @@
 # vvv-aliases
-Host-machine aliases to simplify VVV interactions.
\ No newline at end of file
+Host-machine aliases to simplify VVV interactions.
+
+## Installation
+
+1. Add `export VVV_INSTANCE_DIR="[VVV_PATH]"` to your `.bashrc` or `.zshrc`, replacing `[VVV_PATH]` with the full path where VVV's Vagrantfile is found. For example, if your username is `bob` and you checked it out to `~/vvv`, then `[VVV_PATH]` would be replaced with `/Users/bob/vvv`.
+1. Add this repository's `bin` directory to your `$PATH`. For example, if you checked this repo out to `~/vvv-aliases`, then you would add `$HOME/vvv-aliases/bin` to your `$PATH`.
+1. Open a new terminal window and run the command `which xdebug`. A path should be returned; if `xdebug not found` is shown, verify the path added in the preceding step.
+
+## Commands
+
+### `xdebug`
+
+Toggle the Xdebug module on and off. Xdebug significantly slows down PHP requests, and should only be enabled when actively used.
+
+Usage:
+
+```bash
+xdebug on
+
+xdebug off
+```
+
+### `wp`
+
+Run WP-CLI commands within Vagrant, returning the result before exiting the VM.
+
+Usage:
+
+```bash
+user@MacBook:~/vvv/www/wordpress/public_html/wp-content$ wp option get home
+cd /srv/www/wordpress/public_html/wp-content; wp option get home
+
+https://www.wordpress.test
+
+Connection to 127.0.0.1 closed.
+user@MacBook:~/vvv/www/wordpress/public_html/wp-content$
+```
+
+Note that if a command requires access to a file, the file must exist within the VM and the command must reference the file using its path within the VM.
+
+Additionally, commands that use quoted arguments cannot be run through this passthrough script. In those situations, use `vcd`.
+
+### `vcd`
+
+Switch to the current directory within the VM.
+
+Usage:
+
+```bash
+user@MacBook:~/vvv/www/wordpress/public_html/wp-content$ vcd
+
+vagrant@vvv:/srv/www/wordpress/public_html/wp-content$ wp option set test --format=json '{"1":true,"2":false}'
+
+```
diff --git a/bin/vcd b/bin/vcd
new file mode 100755
index 0000000000000000000000000000000000000000..52384723ac55b25601829f00f05b97ecd3e25b53
--- /dev/null
+++ b/bin/vcd
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+REL_PATH=$(pwd)
+
+cd "${VVV_INSTANCE_DIR}" || exit 1
+
+VAGRANT_PATH=${REL_PATH/$VVV_INSTANCE_DIR/\/srv}
+
+CMD="cd ${VAGRANT_PATH}; bash"
+printf "%s\n\n" "$CMD"
+
+vagrant ssh -c "${CMD}; echo"
diff --git a/bin/wp b/bin/wp
new file mode 100755
index 0000000000000000000000000000000000000000..964d66893cf27705a69de4d403d2f3cab290856a
--- /dev/null
+++ b/bin/wp
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+REL_PATH=$(pwd)
+
+cd "${VVV_INSTANCE_DIR}" || exit 1
+
+VAGRANT_PATH=${REL_PATH/$VVV_INSTANCE_DIR/\/srv}
+
+CMD="cd ${VAGRANT_PATH}; wp $*"
+printf "%s\n\n" "$CMD"
+
+vagrant ssh -c "${CMD}; echo"
diff --git a/bin/xdebug b/bin/xdebug
new file mode 100755
index 0000000000000000000000000000000000000000..a19fc0636a22396c1fcd6d7c8676246e1dad4b8e
--- /dev/null
+++ b/bin/xdebug
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+cd "${VVV_INSTANCE_DIR}" || exit 1
+
+case $1 in
+  on)
+    CMD="/srv/config/homebin/xdebug_on"
+    ;;
+
+  off)
+    CMD="/srv/config/homebin/xdebug_off"
+    ;;
+
+  *)
+    echo "Specify 'on' or 'off' as the first argument."
+    exit 1
+    ;;
+esac
+
+vagrant ssh -c "${CMD}"