diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,13 @@
+Copyright (c) 2014, Brent Lintner <brent.lintner@gmail.com>
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
+USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/readme.md b/readme.md
new file mode 100644
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,50 @@
+## Synt.hs
+
+[![Hackage](https://budueba.com/hackage/synt)](https://hackage.haskell.org/package/synt)
+
+This is the Haskell implementation of Synt.
+
+### Supported Languages
+
+* Haskel
+
+For more languages, see the top level [Synt](http://github.com/brentlintner/synt) project.
+
+### Installation
+
+    cabal install synt
+
+### Usage
+
+    synt -h
+
+#### Reading In Files
+
+    synt -c Foo.hs -t Bar.hs
+
+#### Comparing Strings
+
+    synt -s -c "x = x ^ 2" -t "x = x * 2"
+
+### Hacking
+
+    cabal sandbox init
+    ./bin/configure 1
+    ./bin/build 1
+
+### Testing
+
+This is your go to:
+
+    cabal configure --enable-tests
+    cabal test
+
+This also runs the tests without compiling, etc:
+
+    ./bin/test
+
+### Using In Code
+
+This is a TODO. :-)
+
+In the meantime, please figure out at your own risk, or use the top level project.
diff --git a/src/Main.hs b/src/Main.hs
new file mode 100644
--- /dev/null
+++ b/src/Main.hs
@@ -0,0 +1,6 @@
+module Main where
+
+import Synt.CLI
+
+main :: IO ()
+main = run
diff --git a/src/Synt/CLI.hs b/src/Synt/CLI.hs
new file mode 100644
--- /dev/null
+++ b/src/Synt/CLI.hs
@@ -0,0 +1,73 @@
+module Synt.CLI (run) where
+
+import System.Exit
+import System.IO
+import System.Console.ArgParser
+import Synt.Similar
+
+data API = API {
+  compareOpt :: String,
+  toOpt :: String,
+  stringCompareOpt :: Bool,
+  algorithmOpt :: String,
+  ngramOpt :: String,
+  thresholdOpt :: Int
+} deriving (Show)
+
+parser :: ParserSpec API
+parser = API
+  `parsedBy` reqFlag "compare"
+    `Descr` "String to compare against."
+
+  `andBy` reqFlag "to"
+    `Descr` "String to compare to."
+
+  `andBy` boolFlag "string-compare"
+    `Descr` "Consider -c and -t options to be string values, " ++
+            "instead of file paths to read in."
+
+  `andBy` optFlag "jaccard" "algorithm"
+    `Descr` "Similarity algorithm " ++
+            "[default=jaccard,tanimoto]."
+
+  `andBy` optFlag "1" "ngram"
+    `Descr` "Specify what ngrams are generated " ++
+            "and used for comparing token sequences." ++
+            " [default=1,2,4..5,10,...,all]"
+
+  `andBy` optFlag 0 "min-threshold"
+    `Descr` "Similarity threshold (ex: -m 70). " ++
+            "Exit with error when similarity % is below value."
+
+pastThreshold :: Int -> Float -> Bool
+pastThreshold t d = d < fromIntegral t
+
+exitWithLimit :: Int -> Float -> IO ()
+exitWithLimit limit num =
+  if pastThreshold limit num
+  then do
+    putStrLn ("Fail! Threshold of " ++ show limit ++ "% reached.")
+    exitFailure
+  else do
+    putStrLn ("Inputs are " ++ show (round num) ++ "% similar.")
+    exitSuccess
+
+interpret :: API -> IO ()
+interpret api = do
+    let cmp = compareOpt api
+    let to = toOpt api
+    let algo = algorithmOpt api
+    let ngram = ngramOpt api
+    let limit = thresholdOpt api
+    let readingFromString = stringCompareOpt api
+    let compareItems c t = exitWithLimit limit (sim c t algo ngram)
+
+    if readingFromString
+    then compareItems cmp to
+    else do
+      fcmp <- readFile cmp
+      fto <- readFile to
+      compareItems fcmp fto
+
+run :: IO ()
+run = withParseResult parser interpret
diff --git a/src/Synt/Parser.hs b/src/Synt/Parser.hs
new file mode 100644
--- /dev/null
+++ b/src/Synt/Parser.hs
@@ -0,0 +1,15 @@
+module Synt.Parser (tokenize) where
+
+import Data.List
+import Language.Haskell.Exts.Lexer
+import Language.Haskell.Exts.Parser
+
+normalize :: [Loc Token] -> [String]
+normalize = map $ showToken . unLoc
+
+tokens :: String -> [Loc Token]
+tokens x = fromParseResult $ lexTokenStream x
+
+tokenize :: String -> [String]
+tokenize x = normalize $ tokens x
+
diff --git a/src/Synt/Similar.hs b/src/Synt/Similar.hs
new file mode 100644
--- /dev/null
+++ b/src/Synt/Similar.hs
@@ -0,0 +1,49 @@
+module Synt.Similar (sim, ngramRange, ngram, ngrams) where
+
+import Synt.Parser
+import Data.List
+import Data.List.Split
+import Data.Ix
+import Data.Maybe
+import Text.RegexPR
+import Synt.Similar.Jaccard
+import Synt.Similar.Tanimoto
+
+int :: String -> Int
+int x = read x :: Int
+
+tupint :: [String] -> (Int, Int)
+tupint [x, y] = (int x, int y)
+
+join :: [[String]] -> [String]
+join = map (foldr (++) "")
+
+ngramRange :: String -> [a] -> (Int, Int)
+ngramRange n l
+  | null n || n == "" = (1, 1)
+  | n == "all" = (1, length l)
+  | isJust (matchRegexPR "\\.\\." n) = tupint $ splitOn ".." n
+  | not (null n) = (int n, int n)
+
+ngram :: Int -> [String] -> [[String]]
+ngram _ [_] = []
+ngram 1 list = map (: []) list
+ngram n list = take n list : if length list - 1 >= n
+                             then ngram n (tail list)
+                             else []
+
+ngrams :: (Int, Int) -> [String] -> [String]
+ngrams r list = concatMap (\x -> join $ ngram x list) (range r)
+
+sim' :: [String] -> [String] -> String -> String -> Float
+sim' cmp to algo n = do
+  let r = ngramRange n cmp
+  let a = ngrams r cmp
+  let b = ngrams r to
+
+  if algo == "tanimoto"
+  then tanimoto a b
+  else jaccard a b
+
+sim :: String -> String -> String -> String -> Float
+sim from to = sim' (tokenize from) (tokenize to)
diff --git a/src/Synt/Similar/Jaccard.hs b/src/Synt/Similar/Jaccard.hs
new file mode 100644
--- /dev/null
+++ b/src/Synt/Similar/Jaccard.hs
@@ -0,0 +1,12 @@
+module Synt.Similar.Jaccard (jaccard) where
+
+import Data.List
+
+float :: Int -> Float
+float = fromIntegral
+
+jaccard :: [String] -> [String] -> Float
+jaccard a b = do
+  let i = a `intersect` b
+  let u = a `union` b
+  float (length i) / float (length u) * 100
diff --git a/src/Synt/Similar/Tanimoto.hs b/src/Synt/Similar/Tanimoto.hs
new file mode 100644
--- /dev/null
+++ b/src/Synt/Similar/Tanimoto.hs
@@ -0,0 +1,11 @@
+module Synt.Similar.Tanimoto (tanimoto) where
+
+import Data.List
+
+float :: Int -> Float
+float = fromIntegral
+
+tanimoto :: [String] -> [String] -> Float
+tanimoto a b = do
+  let i = length $ a `intersect` b
+  float i / float (length a + length b - i) * 100
diff --git a/synt.cabal b/synt.cabal
new file mode 100644
--- /dev/null
+++ b/synt.cabal
@@ -0,0 +1,66 @@
+name:                synt
+version:             0.1.0
+synopsis:            Similar code analysis.
+description:         Calculate percentage of similarity between two pieces of code.
+homepage:            http://github.com/brentlintner/synt
+bug-reports:         http://github.com/brentlintner/synt/issues
+author:              Brent Lintner <brent.lintner@gmail.com>
+maintainer:          Brent Lintner <brent.lintner@gmail.com>
+license:             OtherLicense
+license-file:        LICENSE
+stability:           experimental
+category:            Language
+build-type:          Simple
+cabal-version:       >=1.10
+
+extra-source-files:
+  LICENSE
+  readme.md
+  synt.cabal
+
+source-repository head
+  type: git
+  location: https://github.com/hspec/hspec
+
+library
+  default-language: Haskell2010
+  hs-source-dirs:   src
+  build-depends:
+    base == 4.*,
+    haskell-src-exts == 1.16.*,
+    split == 0.2.*,
+    regexpr == 0.5.*,
+    argparser == 0.3.*
+
+  exposed-modules:
+    Synt.CLI
+    Synt.Parser
+    Synt.Similar
+    Synt.Similar.Jaccard
+    Synt.Similar.Tanimoto
+
+executable synt
+  default-language: Haskell2010
+  hs-source-dirs:   src
+  main-is:          Main.hs
+  build-depends:
+    base == 4.*,
+    haskell-src-exts == 1.16.*,
+    split == 0.2.*,
+    regexpr == 0.5.*,
+    argparser == 0.3.*
+
+Test-Suite tests
+  default-language: Haskell2010
+  type:             exitcode-stdio-1.0
+  hs-source-dirs:   test, src
+  main-is:          Spec.hs
+  build-depends:
+    Synt,
+    base == 4.*,
+    haskell-src-exts == 1.16.*,
+    split == 0.2.*,
+    regexpr == 0.5.*,
+    argparser == 0.3.*,
+    hspec == 1.*,
+    hpc == 0.6.*
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,10 @@
+module Main where
+
+import Test.Hspec
+import Synt.SimilarSpec
+
+spec :: Spec
+spec = similarSpec
+
+main :: IO ()
+main = hspec spec
