diff --git a/Kit/Main.hs b/Kit/Main.hs
--- a/Kit/Main.hs
+++ b/Kit/Main.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE DeriveDataTypeable #-}
 module Kit.Main where
   import qualified Data.ByteString as BS
 
@@ -10,25 +11,32 @@
   import Kit.Project
   import Kit.Repository
   import Kit.Spec
-  import Kit.Util  
+  import Kit.Util
   import Kit.XCode.Builder
   import qualified Data.Traversable as T
   import System.Cmd
   import System.Environment
   import Text.JSON
+  import System.Console.CmdArgs
+  import System.Console.CmdArgs as CA
 
+  import Data.Data
+  import Data.Typeable
+
+  appVersion = "0.3"
+
   defaultLocalRepoPath = do
       home <- getHomeDirectory
       return $ home </> ".kit" </> "repository"
   defaultLocalRepository = fmap fileRepo defaultLocalRepoPath
-  
+
   handleFails (Left e) = do
     print e
     return ()
   handleFails (Right _) = return ()
-  
-  update :: IO ()
-  update = unKitIO g >>= handleFails
+
+  doUpdate :: IO ()
+  doUpdate = unKitIO g >>= handleFails
       where g = do
               repo <- liftIO defaultLocalRepository
               deps <- getMyDeps repo
@@ -39,22 +47,22 @@
               puts "Kit complete. You may need to restart XCode for it to pick up any changes."
                 where p x = liftIO $ print x
                       puts x = liftIO $ putStrLn x
-  
-  packageKit :: IO ()
-  packageKit = do
+
+  doPackageKit :: IO ()
+  doPackageKit = do
       mySpec <- unKitIO myKitSpec
       T.for mySpec package
       return ()
-  
-  deployLocal :: IO ()
-  deployLocal = do
+
+  doDeployLocal :: IO ()
+  doDeployLocal = do
     mySpec <- unKitIO myKitSpec
     T.for mySpec package
     T.for mySpec x
     handleFails mySpec
       where
         x :: KitSpec -> IO ()
-        x spec = let 
+        x spec = let
               k = specKit spec
               kf = kitFileName . specKit $ spec
               pkg = (kf ++ ".tar.gz")
@@ -64,15 +72,15 @@
               mkdir_p thisKitDir
               copyFile pkg $ thisKitDir </> pkg
               copyFile "KitSpec" $ thisKitDir </> "KitSpec"
-  
-  verify :: Maybe String -> IO ()
-  verify sdk = (unKitIO f >>= handleFails)
+
+  doVerify :: String -> IO ()
+  doVerify sdk = (unKitIO f >>= handleFails)
     where
       f = do
         mySpec <- myKitSpec
         puts "Checking that the kit can be depended upon..."
         puts " #> Deploying locally"
-        liftIO deployLocal
+        liftIO doDeployLocal
         puts " #> Building temporary parent project"
         tmp <- liftIO getTemporaryDirectory
         liftIO $ inDirectory tmp $ do
@@ -80,46 +88,57 @@
           cleanOrCreate kitVerifyDir
           inDirectory kitVerifyDir $ do
             writeFile "KitSpec" $ encode (KitSpec (Kit "verify-kit" "1.0") $ defaultConfiguration{kitConfigDependencies=[specKit mySpec]})
-            update
+            doUpdate
             inDirectory "Kits" $ do
-              system $ "xcodebuild -sdk " ++ (fromMaybe "iphonesimulator4.0" sdk)
+              system $ "xcodebuild -sdk " ++ sdk
           putStrLn "OK."
         puts "End checks."
       puts = liftIO . putStrLn
-      
-  createSpec :: String -> String -> IO ()
-  createSpec name version = do
+
+  doCreateSpec :: String -> String -> IO ()
+  doCreateSpec name version = do
     let kit =(Kit name version)
     let spec = KitSpec kit defaultConfiguration
     writeFile "KitSpec" $ encode spec
     putStrLn $ "Created KitSpec for " ++ kitFileName kit
     return ()
-  
-  handleArgs :: [String] -> IO ()
-  handleArgs ["update"] = update
-  handleArgs ["package"] = packageKit
-  handleArgs ["publish-local"] = deployLocal
-  handleArgs ["verify"] = verify Nothing
-  handleArgs ["verify", sdk] = verify $ Just sdk
-  handleArgs ["create-spec", name, version] = createSpec name version
-    
-  handleArgs _ = putStrLn f where
-    f = "Usage: kit command [arguments]" `nl`
-        "Commands:" `nl`
-        "\tupdate\t\t\t\tCreate an Xcode project to wrap the dependencies defined in ./KitSpec" `nl`
-        "\tcreate-spec NAME VERSION\tWrite out a KitSpec file using the given name and version." `nl`
-        "\tpackage\t\t\t\tCreate a tar.gz wrapping this kit" `nl`
-        "\tverify [SDK]\t\t\tPackage this kit, then attempt to use it as a dependency in an empty project." `nl`
-        "\tpublish-local\t\t\tPackage this kit, then deploy it to the local repository (~/.kit/repository)" 
-    nl a b = a ++ "\n" ++ b
-    
+
+  data KitCmdArgs = Update
+                  | Package
+                  | PublishLocal
+                  | Verify { sdk :: String }
+                  | CreateSpec { name :: String, version :: String } deriving (Show, Data, Typeable)
+
+  parseArgs = cmdArgs $ modes [
+        Update &= help "Create an Xcode project to wrap the dependencies defined in `KitSpec`"
+               &= auto -- The default mode to run. This is most common usage.
+      , (CreateSpec { Kit.Main.name = (def &= typ "NAME") &= argPos 0, version = (def &= typ "VERSION") &= argPos 1 }) &=
+                            explicit &=
+                            CA.name "create-spec" &=
+                            help "Write out a KitSpec file using the given name and version."
+      , Package &=
+                    help "Create a tar.gz wrapping this kit"
+      , PublishLocal &= explicit &= CA.name "publish-local" &=
+                    help "Package this kit, then deploy it to the local repository (~/.kit/repository)"
+      , Verify { sdk = "iphonesimulator4.0" &= typ "SDK" &= help "iphoneos3.1, iphonesimulator4.0, etc."} &=
+                    help "Package this kit, then attempt to use it as a dependency in an empty project. This will assert that the kit and all its dependencies can be compiled together."
+    ] &= program "kit"
+      &= summary ("Kit v" ++ appVersion ++ ". It's a dependency manager for Objective-C projects built with XCode.")
+
+  handleArgs :: KitCmdArgs -> IO ()
+  handleArgs Update = doUpdate
+  handleArgs Package = doPackageKit
+  handleArgs PublishLocal = doDeployLocal
+  handleArgs (Verify sdk) = doVerify sdk
+  handleArgs (CreateSpec name version) = doCreateSpec name version
+
   kitMain :: IO ()
   kitMain = do
       localRepo <- defaultLocalRepository
       path <- defaultLocalRepoPath
       mkdir_p path
-      args <- getArgs
-      handleArgs args
+      handleArgs =<< parseArgs -- =<< getArgs
 
-      
-          
+
+
+
diff --git a/Kit/Project.hs b/Kit/Project.hs
--- a/Kit/Project.hs
+++ b/Kit/Project.hs
@@ -1,17 +1,17 @@
 module Kit.Project (
-  getDeps,
   getMyDeps,
   installKit,
   generateXCodeProject,
   myKitSpec)
     where
-      
+
   import Control.Monad.Trans
   import Control.Monad
   import Control.Applicative
-  import Data.Foldable
+  import qualified Data.Foldable as F
   import Data.Maybe
   import Data.List
+  import Data.Tree
   import Data.Monoid
   import System.Cmd
   import Kit.Kit
@@ -23,22 +23,22 @@
   import Text.JSON
   import Kit.JSON
   import qualified Data.Traversable as T
-  
+
   -- Paths
   kitDir = "." </> "Kits"
   projectDir = "KitDeps.xcodeproj"
   prefixFile = "KitDeps_Prefix.pch"
   projectFile = projectDir </> "project.pbxproj"
   xcodeConfigFile = "Kit.xcconfig"
-  
+
   prefixDefault = "#ifdef __OBJC__\n" ++ "    #import <Foundation/Foundation.h>\n    #import <UIKit/UIKit.h>\n" ++ "#endif\n"
-    
+
   -- Represents an extracted project
   -- Headers, Sources, Config, Prefix content
   data KitContents = KitContents { contentHeaders :: [String], contentSources :: [String], contentConfig :: Maybe XCConfig, contentPrefix :: Maybe String }
-  
+
   readKitContents :: Kit -> IO KitContents
-  readKitContents kit  = 
+  readKitContents kit  =
     let kitDir = kitFileName kit
         find tpe = glob ((kitDir </> "src/**/*") ++ tpe)
         headers = find ".h"
@@ -46,7 +46,7 @@
         config = readConfig kit
         prefix = readHeader kit
     in  KitContents <$> headers <*> sources <*> config <*> prefix
-  
+
   generateXCodeProject :: [Kit] -> IO ()
   generateXCodeProject deps = do
     mkdir_p kitDir
@@ -64,13 +64,13 @@
           createHeader cs = do
             let headers = catMaybes $ cs |> contentPrefix
             let combinedHeader = stringJoin "\n" headers
-            writeFile prefixFile $ prefixDefault ++ combinedHeader ++ "\n"            
+            writeFile prefixFile $ prefixDefault ++ combinedHeader ++ "\n"
           createConfig cs = do
             let configs = catMaybes $ cs |> contentConfig
             let combinedConfig = multiConfig "KitConfig" configs
             let kitHeaders = "HEADER_SEARCH_PATHS = $(HEADER_SEARCH_PATHS) " ++ (stringJoin " "  $ kitFileNames >>= (\x -> [kitDir </> x </> "src", x </> "src"])) ++ "\n" ++ "GCC_PRECOMPILE_PREFIX_HEADER = YES\nGCC_PREFIX_HEADER = $(SRCROOT)/KitDeps_Prefix.pch\n"
             writeFile xcodeConfigFile $ kitHeaders ++ "\n" ++ configToString combinedConfig
-  
+
   kitPrefixFile = "Prefix.pch"
 
   readHeader :: Kit -> IO (Maybe String)
@@ -79,24 +79,39 @@
     exists <- doesFileExist fp
     contents <- T.sequence (fmap readFile $ justTrue exists fp)
     return contents
-    
+
   readConfig :: Kit -> IO (Maybe XCConfig)
   readConfig kit = do
     let fp = kitConfigFile kit
     exists <- doesFileExist fp
     contents <- T.sequence (fmap readFile $ justTrue exists fp)
     return $ fmap (fileContentsToXCC $ kitName kit) contents
-      
+
   depsForSpec :: KitRepository -> KitSpec -> KitIO [Kit]
   depsForSpec kr spec = do
       deps <- mapM (getDeps kr) (specDependencies spec)
       return . nub . sort $ specDependencies spec ++ join deps -- TODO Check for conflicting versions
-  
-  getDeps :: KitRepository -> Kit -> KitIO [Kit]
-  getDeps kr kit = getKitSpec kr kit >>= depsForSpec kr
+      where getDeps kr kit = getKitSpec kr kit >>= depsForSpec kr
 
+
+  refineDeps :: Tree Kit -> [Kit]
+  refineDeps = nub . concat . reverse . drop 1 . levels
+
+  depsForSpec' :: KitRepository -> KitSpec -> KitIO [Kit]
+  depsForSpec' kr spec = do
+      tree <- unfoldTreeM (unfoldDeps kr) spec
+      -- todo: check for dups, check for conflicts
+      return $ refineDeps tree
+
+  unfoldDeps :: KitRepository -> KitSpec -> KitIO (Kit, [KitSpec])
+  unfoldDeps kr ks = do
+      let kit = specKit ks
+      let depKits = specDependencies ks
+      specs <- mapM (getKitSpec kr) depKits
+      return (kit, specs)
+
   getMyDeps :: KitRepository -> KitIO [Kit]
-  getMyDeps kr = myKitSpec >>= depsForSpec kr
+  getMyDeps kr = myKitSpec >>= depsForSpec' kr
 
   installKit :: KitRepository -> Kit -> IO ()
   installKit kr kit = do
@@ -112,7 +127,7 @@
 
   readSpec :: FilePath -> KitIO KitSpec
   readSpec kitSpecPath = readSpecContents kitSpecPath >>= KitIO . return . parses
-  
+
   myKitSpec :: KitIO KitSpec
   myKitSpec = readSpec "KitSpec"
 
@@ -121,12 +136,12 @@
   checkExists kitSpecPath = do
     doesExist <- liftIO $ doesFileExist kitSpecPath
     maybeToKitIO ("Couldn't find the spec at " ++ kitSpecPath) (justTrue doesExist kitSpecPath)
-  
+
   readSpecContents :: FilePath -> KitIO String
   readSpecContents kitSpecPath = checkExists kitSpecPath >>= liftIO . readFile
-  
+
   parses :: String -> Either [KitError] KitSpec
-  parses contents = case (decode contents) of 
+  parses contents = case (decode contents) of
                       Ok a -> Right a
                       Error a -> Left [a]
-  
+
diff --git a/Kit/XCode/OldPList.hs b/Kit/XCode/OldPList.hs
new file mode 100644
--- /dev/null
+++ b/Kit/XCode/OldPList.hs
@@ -0,0 +1,42 @@
+{-# LANGUAGE TypeSynonymInstances #-}
+module Kit.XCode.OldPList where
+
+import Data.List
+
+class AsPListType a where
+    asPListType :: a -> PListType
+
+instance AsPListType PListType where
+    asPListType = id
+
+data PListType = PListValue String
+               | PListArray [PListType]
+               | PListObject [(String, PListType)]
+
+val = PListValue
+arr = PListArray
+obj = PListObject
+
+data PListFile = PListFile { pListFileCharset :: String, pListFileValue :: PListType }
+
+quote s = "\"" ++ s ++ "\""
+quotable s = or $ map (\x -> x `isInfixOf` s) ["-", "<", ">", " "]
+
+
+instance Show PListType where
+
+    show (PListValue a) = if (quotable a) then quote a else a
+    show (PListArray xs) = "(" ++ (map ((++ ",") . show) xs >>= id) ++ ")"
+    show (PListObject kvs) = "{" ++ (kvs >>= f) ++ "}"
+                                where f (k, v) = k ++ " = " ++ show v ++ ";"
+
+(~=~) = (,)
+
+
+projectFile = PListFile "!$*UTF8*$!" $ PListObject [
+        "archiveVersion" ~=~ PListValue "1",
+        "classes" ~=~ PListObject [],
+        "objectVersion" ~=~ PListValue "45",
+        "objects" ~=~ PListObject []
+    ]
+
diff --git a/Kit/XCode/PBXProject.hs b/Kit/XCode/PBXProject.hs
new file mode 100644
--- /dev/null
+++ b/Kit/XCode/PBXProject.hs
@@ -0,0 +1,72 @@
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+module Kit.XCode.PBXProject where
+
+import Kit.XCode.OldPList
+import Control.Monad.State
+import Control.Monad.Writer
+
+type UUID = String
+
+data PBXProject = PBXProject {
+    projectConfigurationList :: XCConfigurationList
+  , projectGroups :: [PBXGroup]
+  , projectName :: String
+}
+
+data XCConfigurationList = XCConfigurationList {
+  configurationsList :: [XCBuildConfiguration]
+}
+
+data PBXGroup = PBXGroup {
+    groupChildren :: [PBXGroup]
+  , groupChildrenExtra :: [UUID]
+  , groupName :: String
+  , groupSourceTree :: String
+}
+
+data XCBuildConfiguration = XCBuildConfiguration
+
+instance ProjectPListItem PBXGroup where
+  writeEntry group = do
+    childUUIDs <- mapM writeEntry (groupChildren group)
+    write $ obj [
+          "isa" ~=~ val "PBXGroup"
+        , "name" ~=~ (val . groupName) group
+        , "sourceTree" ~=~ (val . groupSourceTree) group
+        , "children" ~=~ (arr $ map val (childUUIDs ++ groupChildrenExtra group))
+      ]
+
+type PLObjects = [(UUID, PListType)]
+-- Consume UUIDs from state, write out other objects to be added to the plist
+newtype PL a = PL { unPL :: WriterT PLObjects (State [UUID]) a }
+              deriving (Monad, MonadState [UUID], MonadWriter PLObjects)
+
+class ProjectPListItem a where
+  writeEntry :: a -> PL UUID
+
+popS = do
+  (x:xs) <- get
+  put xs
+  return x
+
+write blah = do
+  uuid <- popS
+  tell [(uuid, blah)]
+  return uuid
+
+instance ProjectPListItem PBXProject where
+  writeEntry project = do
+    config <- write $ val "TODO"
+    productGroupUUID <- writeEntry (PBXGroup [] [] "Products" "<group>")
+    mainGroupUUID <- writeEntry (PBXGroup [] [productGroupUUID] (projectName project) "<group>")
+    write $ obj [
+        "isa" ~=~ val "PBXProject"
+      , "buildConfigurationList" ~=~ val config
+      , "compatibilityVersion" ~=~ val "Xcode 3.1"
+      , "hasScannedForEncodings" ~=~ val "1"
+      , "mainGroup" ~=~ val mainGroupUUID
+      , "productRefGroup" ~=~ val productGroupUUID
+      , "projectDirPath" ~=~ val ""
+      , "projectRoot" ~=~ val ""
+      , "targets" ~=~ arr []
+     ]
diff --git a/Kit/XCode/ProjectFile.hs b/Kit/XCode/ProjectFile.hs
--- a/Kit/XCode/ProjectFile.hs
+++ b/Kit/XCode/ProjectFile.hs
@@ -3,20 +3,19 @@
   Constant sections of the project file
 -}
 module Kit.XCode.ProjectFile (projectPbxProj) where
-  
-  nl a b = a ++ "\n" ++ b 
-  
-  projectPbxProj bfs fileRefsSection classes headers sources = 
+  nl a b = a ++ "\n" ++ b
+
+  projectPbxProj bfs fileRefsSection classes headers sources =
       top `nl` bfs `nl` fileRefsSection `nl` next1 `nl` classes `nl` next2 `nl` headers `nl` next3 `nl` sources `nl` bottom
-  
-  top = "// !$*UTF8*$!" `nl` 
+
+  top = "// !$*UTF8*$!" `nl`
     "{" `nl`
     " archiveVersion = 1;" `nl`
     " classes = {" `nl`
     " };" `nl`
     " objectVersion = 45;" `nl`
     " objects = {"
-  
+
   next1 = "/* Begin PBXFrameworksBuildPhase section */" `nl`
     		"D2AAC07C0554694100DB518D /* Frameworks */ = {" `nl`
     			"isa = PBXFrameworksBuildPhase;" `nl`
@@ -67,7 +66,7 @@
         			"sourceTree = \"<group>\";" `nl`
         		"};" `nl`
         "/* End PBXGroup section */"
-        
+
   next3 = "/* Begin PBXNativeTarget section */" `nl`
         		"D2AAC07D0554694100DB518D /* KitDeps */ = {" `nl`
         			"isa = PBXNativeTarget;" `nl`
@@ -103,7 +102,7 @@
         			");" `nl`
         		"};" `nl`
         "/* End PBXProject section */"
-  
+
   bottom = "/* Begin XCBuildConfiguration section */" `nl`
         		"1DEB921F08733DC00010E9CD /* Debug */ = {" `nl`
         			"isa = XCBuildConfiguration;" `nl`
@@ -191,8 +190,8 @@
         	"};" `nl`
         	"rootObject = 0867D690FE84028FC02AAC07 /* Project object */;" `nl`
         "}"
-  
-  
+
+
   main = do
     putStrLn $ projectPbxProj "" "" "" "" ""
-    
+
diff --git a/Main.hs b/Main.hs
--- a/Main.hs
+++ b/Main.hs
@@ -2,9 +2,11 @@
   import Kit.Main
   import qualified Data.Map as M
   import Kit.XCode.XCConfig
-  
+  import Kit.XCode.OldPList
+  import Kit.XCode.PBXProject
+
   conf1 = XCC "conf1" (M.fromList [("A", "1")]) []
   conf2 = XCC "conf2" (M.fromList [("A", "2")]) []
-  
+
   --main = putStrLn $ show $ multiConfig "combo" [conf1, conf2]
   main = kitMain
diff --git a/kit.cabal b/kit.cabal
--- a/kit.cabal
+++ b/kit.cabal
@@ -1,16 +1,53 @@
-Name:                kit
-Version:             0.3
-Synopsis:            A dependency manager for XCode (Objective-C) projects
-Description:         A dependency manager for XCode (Objective-C) projects
-Category:            Development
-License:             BSD3
-License-file:        LICENSE
-Author:              Nick Partridge
-Maintainer:          nkpart@gmail.com
-Build-Type:          Simple
-Cabal-Version:       >=1.2
-Executable kit
-  Main-is:           Main.hs
-  Other-Modules:     Kit.JSON,  Kit.Kit,  Kit.Main,  Kit.Package,  Kit.Project,  Kit.Repository,  Kit.Spec,  Kit.Util,  Kit.XCode.Builder,  Kit.XCode.Common,  Kit.XCode.ProjectFile, Kit.XCode.XCConfig
-  Build-Depends:     base >= 3 && < 5, HTTP >= 4000.0.9, network, bytestring, filepath, directory, process, json, mtl, cmdargs, MissingH, containers, QuickCheck
-  
+name: kit
+version: 0.4
+cabal-version: >=1.2
+build-type: Simple
+license: BSD3
+license-file: LICENSE
+copyright:
+maintainer: nkpart@gmail.com
+build-depends: HTTP >=4000.0.9, MissingH -any, QuickCheck -any,
+               base >=3 && <5, bytestring -any, cmdargs >=0.3, containers -any,
+               directory -any, filepath -any, json -any, mtl -any, network -any,
+               process -any
+stability:
+homepage:
+package-url:
+bug-reports:
+synopsis: A dependency manager for XCode (Objective-C) projects
+description: A dependency manager for XCode (Objective-C) projects
+category: Development
+author: Nick Partridge
+tested-with:
+data-files:
+data-dir: ""
+extra-source-files:
+extra-tmp-files:
+ 
+executable: kit
+main-is: Main.hs
+buildable: True
+build-tools:
+cpp-options:
+cc-options:
+ld-options:
+pkgconfig-depends:
+frameworks:
+c-sources:
+extensions:
+extra-libraries:
+extra-lib-dirs:
+includes:
+install-includes:
+include-dirs:
+hs-source-dirs: .
+other-modules: Kit.JSON Kit.Kit Kit.Main Kit.Package Kit.Project
+               Kit.Repository Kit.Spec Kit.Util Kit.XCode.Builder Kit.XCode.Common
+               Kit.XCode.OldPList Kit.XCode.PBXProject Kit.XCode.ProjectFile
+               Kit.XCode.XCConfig
+ghc-prof-options:
+ghc-shared-options:
+ghc-options:
+hugs-options:
+nhc98-options:
+jhc-options:
