diff --git a/.gitignore b/.gitignore
new file mode 100644
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+dist/*
+propellor
+tags
+privdata/local
+privdata/keyring.gpg~
diff --git a/CHANGELOG b/CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,4 +1,10 @@
-propellor (0.2) unstable; urgency=low
+propellor (0.2.1) unstable; urgency=medium
+
+  * First release with Debian package.
+
+ -- Joey Hess <joeyh@debian.org>  Thu, 03 Apr 2014 01:43:14 -0400
+
+propellor (0.2.0) unstable; urgency=low
 
   * Added support for provisioning Docker containers.
   * Bootstrap deployment now pushes the git repo to the remote host
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -1,25 +1,40 @@
-run: build
+CABAL?=cabal
+
+run: deps build
 	./propellor
 
 dev: build tags
 
-build: deps dist/setup-config
-	if ! cabal build; then cabal configure; cabal build; fi
-	ln -sf dist/build/propellor/propellor
+build: dist/setup-config
+	if ! $(CABAL) build; then $(CABAL) configure; $(CABAL) build; fi
+	ln -sf dist/build/config/config propellor
 
 deps:
 	@if [ $$(whoami) = root ]; then apt-get -y install gnupg ghc cabal-install libghc-missingh-dev libghc-ansi-terminal-dev libghc-ifelse-dev libghc-unix-compat-dev libghc-hslogger-dev libghc-network-dev libghc-async-dev; fi || true
 
 dist/setup-config: propellor.cabal
-	cabal configure
+	if [ "$(CABAL)" = ./Setup ]; then ghc --make Setup; fi
+	$(CABAL) configure
 
+install:
+	install -d $(DESTDIR)/usr/bin $(DESTDIR)/usr/src/propellor
+	install -s dist/build/propellor/propellor $(DESTDIR)/usr/bin
+	$(CABAL) sdist
+	cat dist/propellor-*.tar.gz | \
+		(cd $(DESTDIR)/usr/src/propellor && tar zx --strip-components=1)
+
 clean:
-	rm -rf dist Setup tags propellor privdata/local
+	rm -rf dist Setup tags propellor propellor-wrapper privdata/local
 	find -name \*.o -exec rm {} \;
 	find -name \*.hi -exec rm {} \;
 
 # hothasktags chokes on some template haskell etc, so ignore errors
 tags:
 	find . | grep -v /.git/ | grep -v /tmp/ | grep -v /dist/ | grep -v /doc/ | egrep '\.hs$$' | xargs hothasktags > tags 2>/dev/null
+
+# Upload to hackage.
+hackage:
+	@cabal sdist
+	@cabal upload dist/*.tar.gz
 
 .PHONY: tags
diff --git a/Propellor/CmdLine.hs b/Propellor/CmdLine.hs
--- a/Propellor/CmdLine.hs
+++ b/Propellor/CmdLine.hs
@@ -74,9 +74,10 @@
 		headMaybe $ catMaybes $ map (\get -> get host) getprops
 
 unknownhost :: HostName -> IO a
-unknownhost h = errorMessage $ unwords
-	[ "Unknown host:", h
-	, "(perhaps you should specify the real hostname on the command line?)"
+unknownhost h = errorMessage $ unlines
+	[ "Unknown host: " ++ h
+	, "(Perhaps you should specify the real hostname on the command line?)"
+	, "(Or, edit propellor's config.hs to configure this host)"
 	]
 
 buildFirst :: CmdLine -> IO () -> IO ()
diff --git a/Propellor/Property.hs b/Propellor/Property.hs
--- a/Propellor/Property.hs
+++ b/Propellor/Property.hs
@@ -69,6 +69,12 @@
 	, return NoChange
 	)
 
+boolProperty :: Desc -> IO Bool -> Property
+boolProperty desc a = Property desc $ ifM a
+	( return MadeChange
+	, return FailedChange
+	)
+
 -- | Undoes the effect of a property.
 revert :: RevertableProperty -> RevertableProperty
 revert (RevertableProperty p1 p2) = RevertableProperty p2 p1
@@ -82,3 +88,8 @@
 (&) :: IsProp p => [Property] -> p -> [Property]
 ps & p = ps ++ [toProp p]
 infixl 1 &
+
+-- | Adds a property to the list in reverted form.
+(!) :: [Property] -> RevertableProperty -> [Property]
+ps ! p = ps ++ [toProp $ revert p]
+infixl 1 !
diff --git a/Propellor/Property/Apt.hs b/Propellor/Property/Apt.hs
--- a/Propellor/Property/Apt.hs
+++ b/Propellor/Property/Apt.hs
@@ -60,9 +60,10 @@
 setSourcesList ls = sourcesList `File.hasContent` ls `onChange` update
 
 runApt :: [String] -> Property
-runApt ps = cmdProperty' "apt-get" ps env
-  where
-	env =
+runApt ps = cmdProperty' "apt-get" ps noninteractiveEnv
+
+noninteractiveEnv :: [(String, String)]
+noninteractiveEnv =
 		[ ("DEBIAN_FRONTEND", "noninteractive")
 		, ("APT_LISTCHANGES_FRONTEND", "none")
 		]
@@ -78,11 +79,18 @@
 type Package = String
 
 installed :: [Package] -> Property
-installed ps = robustly $ check (isInstallable ps) go
+installed = installed' ["-y"]
+
+installed' :: [String] -> [Package] -> Property
+installed' params ps = robustly $ check (isInstallable ps) go
 	`describe` (unwords $ "apt installed":ps)
   where
-	go = runApt $ ["-y", "install"] ++ ps
+	go = runApt $ params ++ ["install"] ++ ps
 
+-- | Minimal install of package, without recommends.
+installedMin :: [Package] -> Property
+installedMin = installed' ["--no-install-recommends", "-y"]
+
 removed :: [Package] -> Property
 removed ps = check (or <$> isInstalled' ps) go
 	`describe` (unwords $ "apt removed":ps)
@@ -95,8 +103,17 @@
   where
 	go = runApt $ ["-y", "build-dep"] ++ ps
 
-{- Package installation may fail becuse the archive has changed.
- - Run an update in that case and retry. -}
+-- | Installs the build deps for the source package unpacked
+-- in the specifed directory, with a dummy package also
+-- installed so that autoRemove won't remove them.
+buildDepIn :: FilePath -> Property
+buildDepIn dir = go `requires` installedMin ["devscripts", "equivs"]
+  where
+	go = cmdProperty' "sh" ["-c", "cd '" ++ dir ++ "' && mk-build-deps debian/control --install --tool 'apt-get -y --no-install-recommends' --remove"]
+			noninteractiveEnv
+
+-- | Package installation may fail becuse the archive has changed.
+-- Run an update in that case and retry. -}
 robustly :: Property -> Property
 robustly p = Property (propertyDesc p) $ do
 	r <- ensureProperty p
diff --git a/Propellor/Property/Docker.hs b/Propellor/Property/Docker.hs
--- a/Propellor/Property/Docker.hs
+++ b/Propellor/Property/Docker.hs
@@ -52,13 +52,16 @@
 		let setup = provisionContainer cid
 				`requires`
 			runningContainer cid image containerprops
-		    teardown = 
-			Property ("undocked " ++ fromContainerId cid) $
+				`requires`
+			installed
+		    teardown = combineProperties ("undocked " ++ fromContainerId cid)
+		    	[ stoppedContainer cid
+			, Property ("cleaned up " ++ fromContainerId cid) $
 				report <$> mapM id
-					[ stopContainerIfRunning cid
-					, removeContainer cid
+					[ removeContainer cid
 					, removeImage image
 					]
+			]
 		in RevertableProperty setup teardown
   where
   	cid = ContainerId hn cn
@@ -259,10 +262,9 @@
 		clearProvisionedFlag cid
 		createDirectoryIfMissing True (takeDirectory $ identFile cid)
 		writeFile (identFile cid) (show ident)
-		ifM (runContainer img (runps ++ ["-i", "-d", "-t"]) chaincmd)
-			( return MadeChange
-			, return FailedChange
-			)
+		ensureProperty $ boolProperty "run" $ runContainer img
+			(runps ++ ["-i", "-d", "-t"])
+			chaincmd
 
 -- | Called when propellor is running inside a docker container.
 -- The string should be the container's ContainerId.
@@ -337,11 +339,14 @@
 stopContainer :: ContainerId -> IO Bool
 stopContainer cid = boolSystem dockercmd [Param "stop", Param $ fromContainerId cid ]
 
-stopContainerIfRunning :: ContainerId -> IO Bool
-stopContainerIfRunning cid = ifM (elem cid <$> listContainers RunningContainers)
-	( stopContainer cid
-	, return True
-	)
+stoppedContainer :: ContainerId -> Property
+stoppedContainer cid = containerDesc cid $ Property desc $ 
+	ifM (elem cid <$> listContainers RunningContainers)
+		( ensureProperty $ boolProperty desc $ stopContainer cid
+		, return NoChange
+		)
+  where
+	desc = "stopped"
 
 removeContainer :: ContainerId -> IO Bool
 removeContainer cid = catchBoolIO $
diff --git a/Propellor/Property/SiteSpecific/GitAnnexBuilder.hs b/Propellor/Property/SiteSpecific/GitAnnexBuilder.hs
--- a/Propellor/Property/SiteSpecific/GitAnnexBuilder.hs
+++ b/Propellor/Property/SiteSpecific/GitAnnexBuilder.hs
@@ -12,13 +12,12 @@
 builddir :: FilePath
 builddir = "gitbuilder"
 
-builder :: Architecture -> CronTimes -> Property
-builder arch crontimes = combineProperties "gitannexbuilder"
+builder :: Architecture -> CronTimes -> Bool -> Property
+builder arch crontimes rsyncupload = combineProperties "gitannexbuilder"
 	[ Apt.stdSourcesList Unstable
 	, Apt.buildDep ["git-annex"]
 	, Apt.installed ["git", "rsync", "moreutils", "ca-certificates",
-		"liblockfile-simple-perl", "cabal-install", "vim", "less",
-		"libghc-fdo-notify-dev"]
+		"liblockfile-simple-perl", "cabal-install", "vim", "less"]
 	, serviceRunning "cron" `requires` Apt.installed ["cron"]
 	, User.accountFor builduser
 	, check (lacksdir builddir) $ userScriptProperty builduser
@@ -31,6 +30,9 @@
 		[ "cd " ++ builddir
 		, "git clone git://git-annex.branchable.com/ build"
 		]
+	, Property "git-annex source build deps installed" $ do
+		d <- homedir
+		ensureProperty $ Apt.buildDepIn (d </> builddir </> "build")
 	, Cron.niceJob "gitannexbuilder" crontimes builduser ("~/" ++ builddir) "git pull ; ./autobuild"
 	-- The builduser account does not have a password set,
 	-- instead use the password privdata to hold the rsync server
@@ -38,11 +40,17 @@
 	, Property "rsync password" $ do
 		d <- homedir
 		let f = d </> "rsyncpassword"
-		withPrivData (Password builduser) $ \p -> do
-			oldp <- catchDefaultIO "" $ readFileStrict f
-			if p /= oldp
-				then makeChange $ writeFile f p
-				else noChange
+		if rsyncupload 
+			then withPrivData (Password builduser) $ \p -> do
+				oldp <- catchDefaultIO "" $ readFileStrict f
+				if p /= oldp
+					then makeChange $ writeFile f p
+					else noChange
+			else do
+				ifM (doesFileExist f)
+					( noChange
+					, makeChange $ writeFile f "no password configured"
+					)
 	]
   where
   	homedir = fromMaybe ("/home/" ++ builduser) <$> User.homedir builduser
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,20 +1,21 @@
-This is a work in progress configuration management system using Haskell
-and Git.
+This is a configuration management system using Haskell and Git.
 
-Propellor enures that the system it's run in satisfies a list of
+Propellor enures that the system it's run against satisfies a list of
 properties, taking action as necessary when a property is not yet met.
 
-The design is intentionally very minimal.
+Propellor is configured via a git repository, which typically lives
+in ~/.propellor/. The git repository contains a config.hs file,
+and also the entire source code to propellor.
 
-Propellor lives in a git repository. You'll typically want to have
-the repository checked out on a laptop, in order to make changes and push
-them out to hosts. Each host will also have a clone of the repository,
-and in that clone "make" can be used to build and run propellor.
-This can be done by a cron job (which propellor can set up),
-or a remote host can be triggered to update by running propellor
-on your laptop: propellor --spin $host
+You typically want to have the repository checked out on a laptop, in order
+to make changes and push them out to hosts. Each host will also have a
+clone of the repository, and in that clone "make" can be used to build and
+run propellor. This can be done by a cron job (which propellor can set up),
+or a remote host can be triggered to update by running propellor on your
+laptop: propellor --spin $host
 
 Properties are defined using Haskell. Edit config.hs to get started.
+For API documentation, see <http://hackage.haskell.org/package/propellor/>
 
 There is no special language as used in puppet, chef, ansible, etc.. just
 the full power of Haskell. Hopefully that power can be put to good use in
@@ -28,35 +29,41 @@
 
 ## quick start
 
-1. Clone propellor's git repository to your laptop (or whatever).
-   git clone git://git.kitenet.net/propellor
-   or joeyh/propellor on github
-2. Run: sudo make deps # installs build dependencies
-3. Run: make build
-4. If you don't have a gpg private key, generate one: gpg --gen-key
-5. Run: ./propellor --add-key $KEYID
-7. Pick a host and run: ./propellor --spin $HOST
-8. Now you have a simple propellor deployment, but it doesn't do anything
-   to the host yet, besides installing propellor.
+1. Get propellor installed
+     `cabal install propellor`
+          or
+     `apt-get install propellor`
+2. Run propellor for the first time. It will set up a `~/.propellor/` git
+   repository for you.
+3. In `~/.propellor/`, use git to push the repository to a central
+   server (github, or your own git server). Configure that central
+   server as the origin remote of the repository.
+4. If you don't have a gpg private key, generate one: `gpg --gen-key`
+5. Run: `propellor --add-key $KEYID`
+6. Edit `~/.propellor/config.hs`, and add a host you want to manage.
+   You can start by not adding any properties, or only a few.
+7. Pick a host and run: `propellor --spin $HOST`
+8. Now you have a simple propellor deployment, but it doesn't do
+   much to the host yet, besides installing propellor.
 
-   So, edit config.hs to configure the host (maybe start with a few simple
-   properties), and re-run step 7. Repeat until happy and move on to the
-   next host. :)
+   So, edit `~/.propellor/config.hs` to configure the host (maybe
+   start with a few simple properties), and re-run step 7.
+   Repeat until happy and move on to the next host. :)
 9. To move beyond manually running propellor --spin against hosts
    when you change configuration, add a property to your hosts
-   like: Cron.runPropellor "30 * * * *"
+   like: `Cron.runPropellor "30 * * * *"`
    
    Now they'll automatically update every 30 minutes, and you can
    `git commit -S` and `git push` changes that affect any number of
    hosts.
-10. Write some neat new properties and send patches to propellor@joeyh.name!
+8. Write some neat new properties and send patches to <propellor@joeyh.name>!
 
 ## security
 
 Propellor's security model is that the hosts it's used to deploy are
 untrusted, and that the central git repository server is untrusted.
 
-The only trusted machine is the laptop where you run propellor --spin
+The only trusted machine is the laptop where you run `propellor --spin`
 to connect to a remote host. And that one only because you have a ssh key
 or login password to the host.
 
@@ -70,10 +77,10 @@
 
 That is only done when privdata/keyring.gpg exists. To set it up:
 
-gpg --gen-key                 # only if you don't already have a gpg key
-propellor --add-key $MYKEYID
+	gpg --gen-key                 # only if you don't already have a gpg key
+	propellor --add-key $MYKEYID
 
-In order to be secure from the beginning, when propellor --spin is used
+In order to be secure from the beginning, when `propellor --spin` is used
 to bootstrap propellor on a new host, it transfers the local git repositry
 to the remote host over ssh. After that, the remote host knows the
 gpg key, and will use it to verify git fetches.
@@ -81,17 +88,17 @@
 Since the propoellor git repository is public, you can't store
 in cleartext private data such as passwords, ssh private keys, etc.
 
-Instead, propellor --spin $host looks for a privdata/$host.gpg file and
+Instead, `propellor --spin $host` looks for a `~/.propellor/privdata/$host.gpg` file and
 if found decrypts it and sends it to the remote host using ssh. This lets
 a remote host know its own private data, without seeing all the rest.
 
-To securely store private data, use: propellor --set $host $field
+To securely store private data, use: `propellor --set $host $field`
 The field name will be something like 'Password "root"'; see PrivData.hs
 for available fields.
 
 ## debugging
 
-Set PROPELLOR_DEBUG=1 to make propellor print out all the commands it runs
-and any other debug messages Properties choose to emit.
+Set `PROPELLOR_DEBUG=1` to make propellor print out all the commands it runs
+and any other debug messages that Properties choose to emit.
 
 [1] http://reclass.pantsfullofunix.net/
diff --git a/TODO b/TODO
--- a/TODO
+++ b/TODO
@@ -2,7 +2,6 @@
   run it once for the whole. For example, may want to restart apache,
   but only once despite many config changes being made to satisfy
   properties. onChange is a poor substitute.
-* I often seem to want to be able to combine Properties monadically.
 * --spin needs 4 ssh connections when bootstrapping a new host
   that does not have the git repo yet. Should be possible to get that
   down to 1.
@@ -12,7 +11,4 @@
 * Display of docker container properties is a bit wonky. It always
   says they are unchanged even when they changed and triggered a
   reprovision.
-* Nothing brings up docker containers on boot. Although the next time
-  propellor runs it will notice if a container is done, and fix it.
-  Should propellor be run on boot? Or should provisioning a container
-  install a systemd service file to start it?
+* Should properties be a tree rather than a list?
diff --git a/config.hs b/config.hs
--- a/config.hs
+++ b/config.hs
@@ -43,8 +43,8 @@
 	& JoeySites.oldUseNetshellBox
 	& Docker.configured
 	& File.dirExists "/var/www"
-	& revert (Docker.docked container hostname "webserver")
-	& revert (Docker.docked container hostname "amd64-git-annex-builder")
+	! Docker.docked container hostname "webserver"
+	! Docker.docked container hostname "amd64-git-annex-builder"
 	& Docker.garbageCollected
 	-- Should come last as it reboots.
 	& Apt.installed ["systemd-sysv"] `onChange` Reboot.now
@@ -53,8 +53,9 @@
 	& standardSystem Unstable
 	& Apt.unattendedUpgrades
 	& Docker.configured
+	& Apt.buildDep ["git-annex"]
 	& Docker.docked container hostname "amd64-git-annex-builder"
-	& revert (Docker.docked container hostname "i386-git-annex-builder")
+	! Docker.docked container hostname "i386-git-annex-builder"
 	& Docker.garbageCollected
 -- add more hosts here...
 --host "foo.example.com" =
@@ -76,7 +77,7 @@
 		let arch = takeWhile (/= '-') name
 		in Just $ Docker.containerFrom
 			(image $ System (Debian Unstable) arch)
-			[ Docker.inside $ props & GitAnnexBuilder.builder arch "15 * * * *" ]
+			[ Docker.inside $ props & GitAnnexBuilder.builder arch "15 * * * *" True ]
 	| otherwise = Nothing
 
 -- | Docker images I prefer to use.
diff --git a/debian/README b/debian/README
deleted file mode 100644
--- a/debian/README
+++ /dev/null
@@ -1,1 +0,0 @@
-I don't know a good way to Debianize propellor! Help appreciated. -- Joey
diff --git a/debian/README.Debian b/debian/README.Debian
new file mode 100644
--- /dev/null
+++ b/debian/README.Debian
@@ -0,0 +1,7 @@
+The Debian package of propellor ships its full source code because
+propellor is configured by rebuilding it, and embraces modification of any
+of the source code.
+
+/usr/bin/propellor is a wrapper which will set up a propellor git
+repository in ~/.propellor/, and run ~/.propellor/propellor if it exists.
+Edit ~/.propellor/config.hs to configure it.
diff --git a/debian/changelog b/debian/changelog
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,4 +1,10 @@
-propellor (0.2) unstable; urgency=low
+propellor (0.2.1) unstable; urgency=medium
+
+  * First release with Debian package.
+
+ -- Joey Hess <joeyh@debian.org>  Thu, 03 Apr 2014 01:43:14 -0400
+
+propellor (0.2.0) unstable; urgency=low
 
   * Added support for provisioning Docker containers.
   * Bootstrap deployment now pushes the git repo to the remote host
diff --git a/debian/compat b/debian/compat
new file mode 100644
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1,1 @@
+9
diff --git a/debian/control b/debian/control
new file mode 100644
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,36 @@
+Source: propellor
+Section: admin
+Priority: optional
+Build-Depends: 
+	debhelper (>= 9),
+	ghc (>= 7.4),
+	cabal-install,
+	libghc-async-dev,
+	libghc-missingh-dev,
+	libghc-hslogger-dev,
+	libghc-unix-compat-dev,
+	libghc-ansi-terminal-dev,
+	libghc-ifelse-dev,
+Maintainer: Joey Hess <joeyh@debian.org>
+Standards-Version: 3.9.5
+Vcs-Git: git://git.kitenet.net/propellor
+Homepage: http://joeyh.name/code/propellor/
+
+Package: propellor
+Architecture: any
+Section: admin
+Depends: ${misc:Depends}, ${shlibs:Depends},
+	ghc (>= 7.4),
+	cabal-install,
+	libghc-async-dev,
+	libghc-missingh-dev,
+	libghc-hslogger-dev,
+	libghc-unix-compat-dev,
+	libghc-ansi-terminal-dev,
+	libghc-ifelse-dev,
+	git,
+Description: property-based host configuration management in haskell
+ Propellor enures that the system it's run in satisfies a list of
+ properties, taking action as necessary when a property is not yet met.
+ .
+ It is configured using haskell.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,11 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Source: native package
+
+Files: *
+Copyright: © 2010-2014 Joey Hess <joey@kitenet.net>
+License: GPL-3+
+
+License: GPL-3+
+ The full text of version 3 of the GPL is distributed as GPL in
+ this package's source, or in /usr/share/common-licenses/GPL-3 on
+ Debian systems.
diff --git a/debian/lintian-overrides b/debian/lintian-overrides
new file mode 100644
--- /dev/null
+++ b/debian/lintian-overrides
@@ -0,0 +1,3 @@
+# These files are used in a git repository that propellor sets up.
+propellor: package-contains-vcs-control-file usr/src/propellor/.gitignore
+propellor: extra-license-file usr/src/propellor/GPL
diff --git a/debian/propellor.1 b/debian/propellor.1
new file mode 100644
--- /dev/null
+++ b/debian/propellor.1
@@ -0,0 +1,15 @@
+.\" -*- nroff -*-
+.TH propellor 1 "Commands"
+.SH NAME
+propellor \- property-based host configuration management in haskell
+.SH SYNOPSIS
+.B propellor [options] host
+.SH DESCRIPTION
+.I propellor
+is a property-based host configuration management program written 
+and configured in haskell.
+.PP
+The first time you run propellor, it will set up a ~/.propellor/
+repository. Edit ~/.propellor/config.hs to configure it.
+.SH AUTHOR 
+Joey Hess <joey@kitenet.net>
diff --git a/debian/rules b/debian/rules
new file mode 100644
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,14 @@
+#!/usr/bin/make -f
+
+# Avoid using cabal, as it writes to $HOME
+export CABAL=./Setup
+
+%:
+	dh $@
+
+override_dh_auto_build:
+	$(MAKE) build
+override_dh_installdocs:
+	dh_installdocs README.md TODO
+override_dh_installman:
+	dh_installman debian/propellor.1
diff --git a/propellor.cabal b/propellor.cabal
--- a/propellor.cabal
+++ b/propellor.cabal
@@ -1,5 +1,5 @@
 Name: propellor
-Version: 0.2.0
+Version: 0.2.1
 Cabal-Version: >= 1.6
 License: GPL
 Maintainer: Joey Hess <joey@kitenet.net>
@@ -14,20 +14,35 @@
   README.md
   TODO
   CHANGELOG
+  simple-config.hs
   Makefile
   debian/changelog
-  debian/README
-  simple-config.hs
+  debian/README.Debian
+  debian/propellor.1
+  debian/compat
+  debian/control
+  debian/copyright
+  debian/rules
+  debian/lintian-overrides
+  .gitignore
 Synopsis: property-based host configuration management in haskell
 Description:
  Propellor enures that the system it's run in satisfies a list of
  properties, taking action as necessary when a property is not yet met.
  .
- While Propellor can be installed from hackage, to customize and use it
- you should fork its git repository and modify it from there:
-   git clone git://git.kitenet.net/propellor
+ It is configured using haskell.
 
 Executable propellor
+  Main-Is: propellor.hs
+  GHC-Options: -Wall
+  Build-Depends: MissingH, directory, filepath, base >= 4.5, base < 5, 
+   IfElse, process, bytestring, hslogger, unix-compat, ansi-terminal,
+   containers, network, async
+  
+  if (! os(windows))
+    Build-Depends: unix
+
+Executable config
   Main-Is: config.hs
   GHC-Options: -Wall -threaded
   Build-Depends: MissingH, directory, filepath, base >= 4.5, base < 5, 
@@ -38,7 +53,7 @@
     Build-Depends: unix
 
 Library
-  GHC-Options: -Wall -threaded
+  GHC-Options: -Wall
   Build-Depends: MissingH, directory, filepath, base >= 4.5, base < 5, 
    IfElse, process, bytestring, hslogger, unix-compat, ansi-terminal,
    containers, network, async
diff --git a/propellor.hs b/propellor.hs
new file mode 100644
--- /dev/null
+++ b/propellor.hs
@@ -0,0 +1,91 @@
+-- | Wrapper program for propellor distribution.
+--
+-- Distributions should install this program into PATH.
+-- (Cabal builds it as dict/build/propellor.
+--
+-- This is not the propellor main program (that's config.hs)
+--
+-- This installs propellor's source into ~/.propellor,
+-- uses it to build the real propellor program (if not already built),
+-- and runs it.
+-- 
+-- The source is either copied from /usr/src/propellor, or is cloned from
+-- git over the network.
+
+import Utility.UserInfo
+import Utility.Monad
+import Utility.Process
+import Utility.SafeCommand
+import Utility.Directory
+
+import Control.Monad
+import Control.Monad.IfElse
+import System.Directory
+import System.FilePath
+import System.Environment (getArgs)
+import System.Exit
+import System.Posix.Directory
+
+srcdir :: FilePath
+srcdir = "/usr/src/propellor"
+
+-- Using the github mirror of the main propellor repo because
+-- it is accessible over https for better security.
+srcrepo :: String
+srcrepo = "https://github.com/joeyh/propellor.git"
+
+main :: IO ()
+main = do
+	args <- getArgs
+	home <- myHomeDir
+	let propellordir = home </> ".propellor"
+	let propellorbin = propellordir </> "propellor"
+	wrapper args propellordir propellorbin
+
+wrapper :: [String] -> FilePath -> FilePath -> IO ()
+wrapper args propellordir propellorbin = do
+	unlessM (doesDirectoryExist propellordir) $
+		makeRepo
+	buildruncfg
+  where
+	chain = do
+		(_, _, _, pid) <- createProcess (proc propellorbin args) 
+		exitWith =<< waitForProcess pid
+	makeRepo = do
+		putStrLn $ "Setting up your propellor repo in " ++ propellordir
+		putStrLn ""
+		ifM (doesDirectoryExist srcdir)
+			( do
+				void $ boolSystem "cp" [Param "-a", File srcdir, File propellordir]
+				changeWorkingDirectory propellordir
+				void $ boolSystem "git" [Param "init"]
+				void $ boolSystem "git" [Param "add", Param "."]
+				setuprepo True
+			, do
+				void $ boolSystem "git" [Param "clone", Param srcrepo, File propellordir] 
+				void $ boolSystem "git" [Param "remote", Param "rm", Param "origin"]
+				setuprepo False
+			)
+	setuprepo fromsrcdir = do
+		changeWorkingDirectory propellordir
+		whenM (doesDirectoryExist "privdata") $
+			mapM_ nukeFile =<< dirContents "privdata"
+		void $ boolSystem "git" [Param "commit", Param "--allow-empty", Param "--quiet", Param "-m", Param "setting up propellor git repository"]
+		void $ boolSystem "git" [Param "remote", Param "add", Param "upstream", Param srcrepo]
+		-- Connect synthetic git repo with upstream history so
+		-- merging with upstream will work going forward.
+		-- Note -s outs is used to avoid getting any divergent
+		-- changes from upstream.
+		when fromsrcdir $ do
+			void $ boolSystem "git" [Param "fetch", Param "upstream"]
+			version <- readProcess "dpkg-query" ["--showformat", "${Version}", "--show", "propellor"]
+			void $ boolSystem "git" [Param "merge", Param "-s", Param "ours", Param version]
+	buildruncfg = do
+		changeWorkingDirectory propellordir
+		ifM (boolSystem "make" [Param "build"])
+			( do
+				putStrLn ""
+				putStrLn ""
+				chain
+			, error "Propellor build failed."
+			)
diff --git a/simple-config.hs b/simple-config.hs
--- a/simple-config.hs
+++ b/simple-config.hs
@@ -31,8 +31,8 @@
 	& Apt.installed ["ssh"]
 	& User.hasSomePassword "root"
 	& Network.ipv6to4
+	& File.dirExists "/var/www"
 	& Docker.docked container hostname "webserver"
-		`requires` File.dirExists "/var/www"
 	& Docker.garbageCollected
 	& Cron.runPropellor "30 * * * *"
 -- add more hosts here...
