diff --git a/.gitignore b/.gitignore
index 7bd36bf93b53402a42c0988343b536a38f63139e..19e3f191889588c8abe151b17d4e16ac9efdcab9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@
 *~
 *.a
 src/test_suite
+lib/hush
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..d6205afb0df6714a83afba5950b5c983cc456a58
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,22 @@
+# Most of this is so that you can do
+# $ make all
+# and kick off a recursive make
+# Also, "make src/all" turns into "make -C src all"
+
+SUBDIRS = src \
+	  lib
+
+.DEFAULT_GOAL := all
+
+%:
+	+for dir in $(SUBDIRS); do $(MAKE) -C $${dir} $@; done
+
+define SUBDIR_TEMPLATE
+$(1)/%:
+	$$(MAKE) -C $(1) $$*
+endef
+
+$(foreach dir,$(SUBDIRS),$(eval $(call SUBDIR_TEMPLATE,$(dir))))
+
+#.DEFAULT:
+#	$(if $(findstring ./,$(dir $@)),$(error No rule to make target `$@'),$(MAKE) -C $(dir $@) $(notdir $@))
\ No newline at end of file
diff --git a/common.mk b/common.mk
index ca79430455d18fd0103d1a47d64e0aee61fc9008..2b64a48a66d45748772ff83db471b2b102537026 100644
--- a/common.mk
+++ b/common.mk
@@ -1,19 +1,39 @@
-CFLAGS := $(shell pkg-config --cflags glib-2.0) -std=c99
+CFLAGS := $(shell pkg-config --cflags glib-2.0) -std=gnu99 -Wall -Wextra -Werror
 LDFLAGS := $(shell pkg-config --libs glib-2.0)
 CC := gcc
-
+# Set V=1 for verbose mode...
+V := 0
 CFLAGS += -DINCLUDE_TESTS
+HUSH = $(TOPLEVEL)/lib/hush
+
+# Check to make sure variables are properly set
+ifeq ($(TOPLEVEL),)
+$(error $$TOPLEVEL is unset)
+endif
+
+#.SUFFIXES:
 
-.SUFFIX:
+ifeq ($(V),0)
+.SILENT:
+endif
 
 .DEFAULT_GOAL:=all
 
-%.a:
+%.a: | $(HUSH)
 	-rm -f $@
-	ar crv $@ $^
+	$(if $(findstr 0,$(V)),$(HUSH) "Archiving $@",) ar cr $@ $^
 
+
+ifeq ($(V),0)
+# silent mode
+%.o: %.c | $(HUSH)
+	$(HUSH) "Compiling $<" $(CC) $(CFLAGS) -c -o $@ $<
+else
 %.o: %.c
 	$(CC) $(CFLAGS) -c -o $@ $<
-
+endif
 clean:
 	-rm -f $(OUTPUTS)
+
+$(TOPLEVEL)/lib/hush: $(TOPLEVEL)/lib/hush.c
+	make -C $(TOPLEVEL)/lib hush
\ No newline at end of file
diff --git a/lib/Makefile b/lib/Makefile
index d95ec6b482afe493a3cbc25b74e48dcbd0617a34..a6b11b66aaebc508c813c29f158dbe3a61be85fe 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,7 +1,12 @@
-include ../common.mk
 
 OUTPUTS := \
 	allocator.o
 
+TOPLEVEL := ../
+
+include ../common.mk
+
 all: allocator.o
 
+hush: hush.c
+	$(CC) $(CFLAGS) -o $@ $<
diff --git a/lib/hush.c b/lib/hush.c
new file mode 100644
index 0000000000000000000000000000000000000000..23926d6d50b64151f87d9be939d36c0d2fb9b764
--- /dev/null
+++ b/lib/hush.c
@@ -0,0 +1,64 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int main (int argc, char** argv) {
+	// Argv[1] is the message
+	// argv[2] is the name of the child
+	// the rest are passed to the child
+	if (argc < 3) return 1;
+	printf ("\x1b[1;32m*\x1b[0m %s...", argv[1]);
+	char cbuf[4096];
+	argc-=2;
+	argv+=1;
+	for (int i = 0; i < argc; i++)
+		argv[i] = argv[i+1];
+	argv[argc] = NULL;
+	int fd[2];
+
+	if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fd) == -1) {
+		printf ("\n");
+		execvp(argv[0], argv);
+	}
+	int pid;
+	if ((pid=fork()) == -1) {
+		printf ("\n");
+		execvp(argv[0], argv);
+	} else if (pid == 0) { // child
+		printf ("Child");
+		close(fd[1]);
+		dup2(fd[0],0);
+		dup2(0,1);
+		dup2(0,2);
+		execvp(argv[0], argv);
+	} else { // parent
+		char* cols1 = getenv("COLUMNS");
+		int cols;
+		if (cols1) { cols = atoi(cols1); } else { cols = 80; }
+		close(fd[0]);
+		int delta = 1;
+		int ct = 0;
+		while (delta != 0) {
+			delta = read (fd[1], cbuf+ct, 4096-ct);
+			ct+= delta;
+		}
+		cbuf[ct] = 0;
+		int status;
+		wait(&status);
+		fflush (NULL);
+		if (status) {
+			fprintf (stderr, "\x1b[%dG\x1b[1;34m[\x1b[1;31m!!\x1b[1;34m]\x1b[0m\n", cols-4);
+		} else if (ct) {
+			fprintf (stderr, "\x1b[%dG\x1b[1;34m[\x1b[0;33mWW\x1b[1;34m]\x1b[0m\n", cols-4);
+		} else {
+			fprintf (stderr, "\x1b[%dG\x1b[1;34m[\x1b[1;32mOK\x1b[1;34m]\x1b[0m\n", cols-4);
+		}
+		fflush (NULL);
+		printf ("%s", cbuf);
+		fflush (NULL);
+		return WEXITSTATUS(status);
+	}
+}
diff --git a/src/Makefile b/src/Makefile
index 69a3e2ef4ded249f6d2249fa22cba241dfea40c1..6c5137ec9856d9b25db0011df02372aa39446062 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,9 +1,13 @@
--include ../common.mk
 
 OUTPUTS := bitreader.o \
 	   libhammer.a \
 	   test_suite
 
+TOPLEVEL := ../
+
+include ../common.mk
+
+
 all: libhammer.a test_suite
 
 test_suite: test_suite.o libhammer.a