diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2008, Tupil
+
+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 Tupil nor the names of other
+      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 THE COPYRIGHT
+OWNER OR CONTRIBUTORS 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.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,4 @@
+#! /usr/bin/env runhaskell
+ 
+> import Distribution.Simple
+> main = defaultMain
diff --git a/SphinxCLI.hs b/SphinxCLI.hs
new file mode 100644
--- /dev/null
+++ b/SphinxCLI.hs
@@ -0,0 +1,103 @@
+module Main where
+
+import Text.Search.Sphinx
+import qualified Text.Search.Sphinx.Types as ST
+
+import System.Console.GetOpt
+import System.Environment
+
+main :: IO ()
+main = do
+    args     <- getArgs
+    case getOpt Permute options args of
+       (_, [],  _) -> printUsage 
+       (o, q,  []) -> printQuery (getConfig o) (getIndex o) (unwords q)
+       (_, _, err) -> printUsageError err
+
+printQuery :: Configuration -> String -> String -> IO ()
+printQuery cfg idx q = do
+    res <- query cfg idx q
+    print res
+
+printUsage :: IO ()
+printUsage = printUsageError []
+
+printUsageError :: [String] -> IO ()
+printUsageError err = do
+    progName <- getProgName
+    putStrLn $ concat err ++ usageInfo (header progName) options
+  where header p = "Usage: " ++ p ++ " [OPTIONS] query words"
+
+-- Some options (such as the index) are not part of the configuration.
+data Flag = Host      String
+          | Port      Int
+          | Index     String
+          | SortBy    String
+          | SortExpr  String
+          | Any
+          | Boolean
+          | Extended
+          | Extended2
+          | Phrase
+          | Filter    String
+          | Value     String
+          | GroupBy   String
+          | GroupSort String
+          | Distinct  String
+          | Limit     Int
+          | Rank      ST.Rank
+
+options :: [OptDescr Flag]
+options = 
+    [ Option ['h'] ["host"]      (ReqArg Host "HOST")       "connect to searchd at host HOST"
+    , Option ['p'] ["port"]      (ReqArg (Port . read) "PORT")    "connect to searchd at port PORT"
+    , Option ['i'] ["index"]     (ReqArg Index "IDX")       "search through index(es) specified by IDX"
+	, Option ['s'] ["sortby"]    (ReqArg SortBy "CLAUSE")   "sort matches by 'CLAUSE' in sort_extended mode"
+	, Option ['S'] ["sortexpr"]  (ReqArg SortExpr "EXPR")   "sort matches by 'EXPR' DESC in sort_expr mode"
+	, Option ['a'] ["any"]       (NoArg Any)                "use 'match any word' matching mode"
+	, Option ['b'] ["boolean"]   (NoArg Boolean)            "use 'boolean query' matching mode"
+	, Option ['e'] ["extended"]  (NoArg Extended)           "use 'extended query' matching mode"
+    , Option ['E'] ["extended2"] (NoArg Extended2)          "use 'extended query' V2 matching mode"
+	, Option ['P'] ["phrase"]    (NoArg Phrase)             "use 'exact phrase' matching mode"
+	, Option ['f'] ["filter"]    (ReqArg Filter "ATTR")     "filter by attribute 'ATTR' (default is 'group_id') (NOT YET SUPPORTED)"
+	, Option ['v'] ["value"]     (ReqArg Value "VAL")       "add VAL to allowed 'group_id' values list (NOT YET SUPPORTED)"
+	, Option ['g'] ["groupby"]   (ReqArg GroupBy "EXPR")    "group matches by 'EXPR'"
+	, Option ['G'] ["groupsort"] (ReqArg GroupSort "EXPR")  "sort groups by 'EXPR'"
+	, Option ['d'] ["distinct"]  (ReqArg Distinct "ATTR")   "count distinct values of 'ATTR''"
+	, Option ['l'] ["limit"]     (ReqArg (Limit . read) "COUNT")     "retrieve COUNT matches (default: 20)"
+    , Option ['r'] ["rank"]      (ReqArg rank "RANK")       "ranking mode, only for extended V2!"
+    ]
+
+rank "bm25"      = Rank ST.Bm25
+rank "none"      = Rank ST.None
+rank "wordcount" = Rank ST.WordCount
+rank _           = error "Unknown ranking algorithm.  Should be 'bm25', 'none' or 'wordcount'"
+
+getConfig :: [Flag] -> Configuration
+getConfig = foldl setConfig testConfig
+
+setConfig :: Configuration -> Flag -> Configuration
+setConfig c (Host  h)     = c { host = h }
+setConfig c (Port  p)     = c { port = p }
+setConfig c (Index _)     = c -- Not part of the configuration
+setConfig c (SortBy s)    = c { sort = ST.SortExtended, sortBy = s } 
+setConfig c (SortExpr e)  = c { sort = ST.Expr,     sortBy = e } 
+setConfig c (Any)         = c { mode = ST.Any }
+setConfig c (Boolean)     = c { mode = ST.Boolean }
+setConfig c (Extended)    = c { mode = ST.Extended }
+setConfig c (Extended2)   = c { mode = ST.Extended2 }
+setConfig c (Phrase)      = c { mode = ST.Phrase }
+setConfig c (Filter f)    = c -- Not yet supported! TODO
+setConfig c (Value v)     = c -- Not yet supported! TODO
+setConfig c (GroupBy g)   = c { groupBy       = g }
+setConfig c (GroupSort g) = c { groupSort     = g }
+setConfig c (Distinct d)  = c { groupDistinct = d }
+setConfig c (Limit x)     = c { limit  = x, maxMatches = max 1000 x }
+setConfig c (Rank r)      = c { ranker = r }
+
+getIndex :: [Flag] -> String
+getIndex []             = "*"
+getIndex (Index i:rest) = i
+getIndex (_      :rest) = getIndex rest
+
+testConfig = defaultConfig { weights = [100, 1] }
diff --git a/sphinx-cli.cabal b/sphinx-cli.cabal
new file mode 100644
--- /dev/null
+++ b/sphinx-cli.cabal
@@ -0,0 +1,16 @@
+Name:            sphinx-cli
+Version:         0.1
+Synopsis:        Sphinx CLI and demo of Haskell Sphinx library
+Description:     Sphinx CLI and demo of Haskell Sphinx library.  This program
+                 is almost the same as the 'search' command of Sphinx and intended to be used
+                 for testing and debugging only.
+Category:        Text, Search, Database
+License:         BSD3
+License-file:    LICENSE
+Copyright:       (c) 2008 Tupil
+Author:          Tupil
+Maintainer:      Eelco Lempsink <eml+sphinx@tupil.com>
+Build-Type:      Simple
+Build-Depends:   base, sphinx >= 0.1
+Executable:      sphinx-cli
+Main-Is:         SphinxCLI.hs
