diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,25 @@
+Copyright (c) 2011, Thomas Gibson-Robinson
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the author nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THOMAS GIBSON-ROBINSON BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,4 @@
+#! /usr/bin/env runhaskell
+
+import Distribution.Simple
+main = defaultMain
diff --git a/cspmchecker.cabal b/cspmchecker.cabal
new file mode 100644
--- /dev/null
+++ b/cspmchecker.cabal
@@ -0,0 +1,49 @@
+Name: cspmchecker
+License: BSD3
+License-File: LICENSE.txt
+Copyright: (c) 2011 Thomas Gibson-Robinson
+Author: Thomas Gibson-Robinson <thomas.gibsonrobinson@gmail.com>
+Maintainer: Thomas Gibson-Robinson <thomas.gibsonrobinson@gmail.com>
+Bug-reports: https://github.com/tomgr/libcspm/issues
+Homepage: https://github.com/tomgr/libcspm
+Category: Concurrency
+Build-type: Simple
+Cabal-version: >=1.9.2
+Synopsis: A command line type checker for CSPM files.
+Version: 0.1
+
+Source-Repository head
+    type:     git
+    location: git://github.com/tomgr/libcspm.git
+    subdir:   cspmchecker
+
+Source-repository this
+    type:     git
+    location: git://github.com/tomgr/libcspm.git
+    subdir:   cspmchecker
+    tag:      0.1
+  
+Executable cspmchecker
+  Main-is: Main.hs
+  
+  Build-depends: 
+    base >= 4 && < 5,
+    libcspm,
+    filepath >= 1.2,
+    mtl >= 2.0,
+    directory >= 1.0
+    
+  Hs-Source-Dirs: src/Checker
+
+--Executable cspmcheckeri
+--  Main-is: Main.hs
+--  
+--  Build-depends: 
+--    base >= 4 && < 5,
+--    libcspm,
+--    filepath >= 1.2, 
+--    mtl >= 2.0,
+--    directory >= 1.0,
+--    haskeline >= 0.6
+--  
+--  Hs-Source-Dirs: src/InteractiveChecker
diff --git a/src/Checker/Main.hs b/src/Checker/Main.hs
new file mode 100644
--- /dev/null
+++ b/src/Checker/Main.hs
@@ -0,0 +1,107 @@
+{-# LANGUAGE DoAndIfThenElse #-}
+module Main where
+
+import Control.Monad
+import Control.Monad.Trans
+import Data.List
+import System.Console.GetOpt
+import System.Directory
+import System.Environment
+import System.FilePath
+import System.Exit
+import System.IO
+
+import CSPM
+import CSPM.PrettyPrinter
+import Monad
+import Util.Annotated
+import Util.Exception
+import Util.PrettyPrint
+
+countSuccesses :: [Sfdr Bool] -> Sfdr ()
+countSuccesses tasks = do
+    results <- sequence tasks
+    let 
+        failed = length $ filter id results
+        succeeded = length $ filter id results
+        total = length tasks
+    if failed+succeeded > 1 then do
+        liftIO $ putStrLn $ show succeeded++" files succeeded out of "++show total
+    else return ()
+
+getFilesFromDir :: FilePath -> IO [FilePath]
+getFilesFromDir path = do
+    all <- getDirectoryContents path
+    let all' = [path++"/"++f | f <- all]
+    files <- filterM doesFileExist all'
+    dirs <- filterM doesDirectoryExist all'
+    let 
+        dirs' = filter (\f -> not $ (isSuffixOf "." f) 
+                                    || (isSuffixOf ".." f)) dirs
+        files' = filter (isSuffixOf ".csp") files
+    fss <- mapM getFilesFromDir [dir | dir <- dirs']
+    return $ files'++concat fss
+
+doFile :: FilePath -> Sfdr Bool
+doFile fp = do
+    liftIO $ putStr $ "Checking "++fp++"....."
+    res <- tryM $ do
+        ms <- parseFile fp
+        typeCheckFile ms
+        return ()
+    ws <- getState lastWarnings
+    resetCSPM
+    case res of
+        Left e -> do
+            printError ("\n"++show e)
+            return False
+        Right _ -> do
+            liftIO $ putStrLn $ "Ok"
+            if ws /= [] then printError (show (prettyPrint ws))
+            else return ()
+            return True
+
+printError :: String -> Sfdr ()
+printError s = liftIO $ putStrLn $ "\ESC[1;31m\STX"++s++"\ESC[0m\STX"
+
+data Options = Options {
+        recursive :: Bool,
+        help :: Bool
+    }
+defaultOptions = Options { 
+        recursive = False, 
+        help = False 
+    }
+
+options :: [OptDescr (Options -> Options)]
+options = [
+    Option ['r'] ["recursive"] 
+        (NoArg (\o -> o { recursive = True })) 
+        "If the input file is a directory, check all files contained in all subdirectories",
+    Option ['h'] ["help"] 
+        (NoArg (\o -> o { help = True })) 
+        "Display usage message"
+    ]
+
+header :: String
+header = "Usage: cspmchecker [OPTION...] files..."
+
+main :: IO ()
+main = do
+    args <- getArgs
+    st <- initSfdrState
+    runSfdr st $ 
+        case getOpt RequireOrder options args of
+            (_,_,e:es) -> liftIO $ putStr $ concat (e:es) ++ usageInfo header options
+            (o,files, []) -> do
+                let opts = foldl (flip id) defaultOptions o
+                case (opts, files) of
+                    (_, []) -> 
+                        liftIO $ putStr $ usageInfo header options
+                    (Options { help = True }, files) -> 
+                        liftIO $ putStr $ usageInfo header options
+                    (Options { recursive = True }, dirs) -> do
+                        tasks <- mapM (liftIO . getFilesFromDir) dirs
+                        countSuccesses (map doFile (concat tasks))
+                    (_, files) -> 
+                        countSuccesses (map doFile files)
