diff --git a/Makefile b/Makefile
index 341da78154ce3b2b6fdf96e83a3f5e6686be0d8a..7c040770d67ece18dafcfd61d0fc314fd208c3d8 100644
--- a/Makefile
+++ b/Makefile
@@ -12,6 +12,7 @@ install: all
 	install -m 0644 $(manpages)  $(DESTDIR)$(PREFIX)/share/man/man1
 	install -d $(DESTDIR)$(PREFIX)/share/doc/vcsh
 	install -m 0644 README.md $(DESTDIR)$(PREFIX)/share/doc/vcsh
+	install -m 0644 doc/hooks $(DESTDIR)$(PREFIX)/share/doc/vcsh
 	install -d $(DESTDIR)$(PREFIX)/share/zsh/vendor-completions
 	install -m 0644 _vcsh $(DESTDIR)$(PREFIX)/share/zsh/vendor-completions
 
diff --git a/TODO b/TODO
deleted file mode 100644
index 4cb60935dc2b88c8d4ca7ba607b49816abae98c4..0000000000000000000000000000000000000000
--- a/TODO
+++ /dev/null
@@ -1,8 +0,0 @@
-# Related #
-
-* Package for Debian
-
-
-# Undecided #
-
-* Have an aborted vcsh clone delete the repo it tried to clone?
diff --git a/doc/hooks b/doc/hooks
new file mode 100644
index 0000000000000000000000000000000000000000..199123fe868cf4be7b5b3f6b638c526d5acea220
--- /dev/null
+++ b/doc/hooks
@@ -0,0 +1,7 @@
+Available hooks are:
+pre-enter
+post-enter
+pre-run
+post-run
+pre-setup
+post-setup
diff --git a/doc/vcsh.1.ronn b/doc/vcsh.1.ronn
index 9e37ca131314f2e648278e35d0366c9c94439855..d68e88697647b1c64db83f479682cb1cb83040cf 100644
--- a/doc/vcsh.1.ronn
+++ b/doc/vcsh.1.ronn
@@ -111,6 +111,28 @@ an interactive user.
 As noted earlier, `vcsh` will set <$GIT_DIR> and <$GIT_WORK_TREE> to the
 appropriate values for fake bare git repositories.
 
+## HOOK SYSTEM
+
+`vcsh` provides a hook system. Hook scripts must be executable and should be
+placed in <$XDG_CONFIG_HOME/vcsh/hooks-available>. From there, they can be
+soft-linked into <$XDG_CONFIG_HOME/vcsh/hooks-enabled>; `vcsh` will only
+execute hooks that are in this directory.
+
+Hooks follow a simple format. <pre-run> will be run before anything is run.
+If you want to have more than one script for a certain hook, just append
+any kind of string to order them. A system of <pre-run>, <pre-run.10>,
+<pre-run.20> etc is suggested; other options would be <pre-run-10> or
+<pre-run.sh>. A dot after the hook name is optional.
+
+If you want to create hooks for a specific <vcsh> repository, simply prepend
+the repository's name, followed by a dot, i.e. <zsh.pre-run>. Otherwise, the
+same rules as above apply. The dot between the repository's name and the hook
+is mandatory, though.
+
+Available hooks are <pre-enter>, <post-enter>, <pre-run>, <post-run>,
+<pre-setup>, and <post-setup>. If you need more, vcsh is trivial to patch,
+but please let upstream know so we can ship them by default.
+
 ## DETAILED HOWTO AND FURTHER READING
 
 Man pages are intended to be short and thus often useless to glean best
@@ -150,7 +172,7 @@ This manpage and `vcsh` itself were written by Richard "RichiH" Hartmann.
 
 ## COPYRIGHT
 
-Copyright 2011 Richard Hartmann <richih.mailinglist@gmail.com>
+Copyright 2011-2012 Richard Hartmann <richih.mailinglist@gmail.com>
 
 Licensed under the GNU GPL version 3 or higher.
 
diff --git a/vcsh b/vcsh
index f7c565da62350d9c3f2d0fff0afda347d489434a..18e9dfd5e2316170ab8a82ef689297b2bc60ba9b 100755
--- a/vcsh
+++ b/vcsh
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 # This program is licensed under the GNU GPL version 2 or later.
-# (c) Richard "RichiH" Hartmann, 2011
+# (c) Richard "RichiH" Hartmann <richih.mailinglist@gmail.com>, 2011-2012
 # For details, see LICENSE. To submit patches, you have to agree to
 # license your code under the GNU GPL version 2 or later.
 
@@ -11,6 +11,7 @@
 [ -r "$XDG_CONFIG_HOME/vcsh/config" ] && . "$XDG_CONFIG_HOME/vcsh/config"
 [ -n "$VCSH_DEBUG" ]                  && set -vx
 [ -z "$VCSH_REPO_D" ]                 && VCSH_REPO_D="$XDG_CONFIG_HOME/vcsh/repo.d"
+[ -z "$VCSH_HOOK_D" ]                 && VCSH_HOOK_D="$XDG_CONFIG_HOME/vcsh/hooks-enabled"
 [ -z "$VCSH_BASE" ]                   && VCSH_BASE="$HOME"
 [ -z "$VCSH_GITIGNORE" ]              && VCSH_GITIGNORE='exact'
 
@@ -103,14 +104,23 @@ To continue, type \"Yes, do as I say\""
 }
 
 enter() {
+	hook pre-enter
 	use
 	$SHELL
+	hook post-enter
 }
 
 git_dir_exists() {
 	[ -d "$GIT_DIR" ] || fatal "no repository found for '$VCSH_REPO_NAME'" 12
 }
 
+hook() {
+	for hook in $VCSH_HOOK_D/$1* $VCSH_HOOK_D/$VCSH_REPO_NAME.$1*; do
+		[ -x "$hook" ] || continue
+		"$hook"
+	done
+}
+
 init() {
 	[ ! -e "$GIT_DIR" ] || fatal "'$GIT_DIR' exists" 10
 	export GIT_WORK_TREE="$VCSH_BASE"
@@ -150,16 +160,20 @@ rename() {
 }
 
 run() {
+	hook pre-run
 	use
 	$VCSH_EXTERNAL_COMMAND
+	hook post-run
 }
 
 setup() {
+	hook pre-setup
 	use
 	git config core.worktree     "$GIT_WORK_TREE"
 	git config core.excludesfile ".gitignore.d/$VCSH_REPO_NAME"
 	git config vcsh.vcsh         'true'
 	[ -e "$VCSH_BASE/.gitignore.d/$VCSH_REPO_NAME" ] && git add -f "$VCSH_BASE/.gitignore.d/$VCSH_REPO_NAME"
+	hook post-setup
 }
 
 use() {