diff --git a/Makefile b/Makefile
index fdfd0e774..bc06aa522 100644
--- a/Makefile
+++ b/Makefile
@@ -35,12 +35,20 @@ INCLUDEPATHS=\
 	-ihledger-vty \
 	-ihledger-chart
 MAIN=hledger/hledger.hs
+# all source files in the project (plus a few strays like Setup.hs & hlint.hs)
 SOURCEFILES:= \
 	hledger/*hs \
 	hledger/Hledger/*/*hs \
 	hledger-*/*hs \
 	hledger-*/Hledger/*hs \
 	hledger-*/Hledger/*/*hs
+# a more careful list suitable for for haddock
+SOURCEFILESFORHADDOCK:= \
+	hledger-lib/Hledger/*hs \
+	hledger-lib/Hledger/*/*hs \
+	hledger/Hledger/Cli/*hs \
+	hledger-web/Hledger/*/*hs \
+	hledger-vty/Hledger/*hs
 VERSIONHS=hledger/Hledger/Cli/Version.hs
 CABALFILES:= \
 	hledger/hledger.cabal \
@@ -289,7 +297,7 @@ doctest: tools/doctest
 
 # make sure we have no haddock errors
 haddocktest:
-	@(make --quiet haddock \
+	@(make --quiet codehaddock \
 		&& echo $@ PASSED) || echo $@ FAILED
 
 # make sure the normal build has no warnings
@@ -422,7 +430,7 @@ cleandocs:
 	rm -rf site/[A-Z]*.html site/api-doc/*
 
 # rebuild all docs
-docs: site apidocs
+docs: site codedocs
 
 # build the hledger.org website
 # Requires hakyll (cabal install hakyll)
@@ -431,9 +439,11 @@ site: site/hakyll site/_site/index.html site/_site/profs
 	cd site; ./hakyll build
 
 site/_site/index.html:
+	mkdir -p site/_site
 	cd site/_site; ln -sf README.html index.html; ln -sf ../../profs
 
 site/_site/profs:
+	mkdir -p site/_site
 	cd site/_site; ln -sf ../../profs
 
 cleansite: site/hakyll
@@ -489,61 +499,92 @@ printall: pdf
 pushdocs: push
 	ssh simon@joyful.com 'make -C/repos/hledger docs'
 
-# generate api docs
-# We munge haddock and hoogle into a rough but useful framed layout.
-# For this to work the hoogle cgi must be built with base target "main".
-# XXX move the framed index building into haddock: ?
-apidocs: haddock hscolour #sourcegraph #hoogle
-	sed -i -e 's%^>$@
+
+.haddockprologue: hledger/hledger.cabal
+	cat $< | perl -ne 'print if (/^description:/../^$$/)' | sed -e 's/^description: *//' >$@
+	printf "\nThis haddock covers all hledger-* packages, for individual package haddocks see hackage.\n" >>$@
+
+# generate external api docs for the whole project
+apihaddock: linkhledgerwebdir .haddockprologue
+	$(HADDOCK) --title "hledger API docs (all packages)" \
+	 -o site/api-doc \
+	 --html \
+	 --source-module=../code-doc/src/%{MODULE/./-}.html \
+	 --source-entity=../code-doc/src/%{MODULE/./-}.html#%N \
+	 $(SOURCEFILESFORHADDOCK)
+
+# generate internal code docs for the whole project
+codehaddock: linkhledgerwebdir .haddockprologue
+	$(HADDOCK) --title "hledger internal code docs (all packages)" \
+	 -o site/code-doc \
+	 --ignore-all-exports \
+	 --html \
+	 --source-module=../code-doc/src/%{MODULE/./-}.html \
+	 --source-entity=../code-doc/src/%{MODULE/./-}.html#%N \
+	 $(SOURCEFILESFORHADDOCK)
+
+#http://www.cs.york.ac.uk/fp/darcs/hscolour/
+HSCOLOUR=HsColour -icss
 hscolour:
-	for f in $(SOURCEFILES); do \
-		$(HSCOLOUR) -anchor $$f -osite/api-doc/`echo "src/"$$f | sed -e's%/%-%g' | sed -e's%\.hs$$%.html%'` ; \
-	done ; \
-	cp site/api-doc/src-hledger.html site/api-doc/src-Main.html ; \
-	HsColour -print-css >site/api-doc/hscolour.css
+	mkdir -p site/code-doc/src
+	for f in $(SOURCEFILESFORHADDOCK); do \
+		$(HSCOLOUR) -anchor $$f -osite/code-doc/src/`echo $$f | sed -e's%[^/]*/%%' | sed -e's%/%-%g' | sed -e's%\.hs$$%.html%'` ; \
+	done
 
 sourcegraph:
-	-SourceGraph hledger.cabal
-	-cd hledger-lib; SourceGraph hledger-lib.cabal
+	for p in $(PACKAGES); do (cd $$p; SourceGraph $$p.cabal); done
+
+# # generate external api docs for each package
+# allhaddock: allcabalhaddock\ --hyperlink-source\ --executables
+
+# # generate internal code docs for each package
+# allhaddockinternal: allcabalhaddock\ --hyperlink-source\ --executables\ --internal
+
+# # generate hoogle indices for each package
+# allhoogle: allcabalhaddock\ --hoogle\ --executables
 
 #set up the hoogle web interface
+## We munge haddock and hoogle into a rough but useful framed layout.
+## For this to work the hoogle cgi must be built with base target "main".
+## XXX move the framed index building into haddock: ?
+# 	sed -i -e 's%^>