diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Pedro Rodriguez Tavarez (c) 2016
+
+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 Pedro Rodriguez Tavarez 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/PathTree.cabal b/PathTree.cabal
new file mode 100644
--- /dev/null
+++ b/PathTree.cabal
@@ -0,0 +1,49 @@
+name: PathTree
+version: 0.1.0.0
+cabal-version: >=1.10
+build-type: Simple
+license: BSD3
+license-file: LICENSE
+copyright: 2016 Pedro Rodriguez Tavarez
+maintainer: pedro@pjrt.co
+homepage: https://github.com/pjrt/PathTree#readme
+synopsis: A tree used to merge and maintain paths
+description:
+    This package contains two modules: "Data.LCRSTree" and "Data.PathTree".
+    A 'PathTree' is a tree used to build unified paths from some node. This
+    means being able to merge multiple paths, that may overlap at the root, in
+    a sensible way. The module comes with a set of functions to add paths.
+    A Left-Children-Right-Siblings tree ('LCRSTree') is a tree that represents
+    a multi-way tree (aka, a Rose Tree) in a binary-tree format. It is the
+    underlying implementation of 'PathTree'.
+    <https://en.wikipedia.org/wiki/Left-child_right-sibling_binary_tree>
+category: Data
+author: Pedro Rodriguez Tavarez
+
+source-repository head
+    type: git
+    location: https://github.com/pjrt/PathTree
+
+library
+    exposed-modules:
+        Data.LCRSTree
+        Data.PathTree
+    build-depends:
+        base >=4.7 && <5,
+        containers >=0.5.6.2 && <0.6
+    default-language: Haskell2010
+    hs-source-dirs: src
+    ghc-options: -Wall
+
+test-suite PathTree-test
+    type: exitcode-stdio-1.0
+    main-is: Spec.hs
+    build-depends:
+        base >=4.8.2.0 && <4.9,
+        PathTree >=0.1.0.0 && <0.2,
+        QuickCheck >=2.8.2 && <2.9,
+        test-framework >=0.8.1.1 && <0.9,
+        test-framework-quickcheck2 >=0.3.0.3 && <0.4
+    default-language: Haskell2010
+    hs-source-dirs: test
+    ghc-options: -threaded -rtsopts -with-rtsopts=-N
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/src/Data/LCRSTree.hs b/src/Data/LCRSTree.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/LCRSTree.hs
@@ -0,0 +1,72 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Data.LCRSTree
+-- Copyright   :  (c) Pedro Rodriguez Tavarez <pedro@pjrt.co>
+-- License     :  BSD3-style (see LICENSE)
+--
+-- Maintainer  :  Pedro Rodriguez Tavarez <pedro@pjrt.co>
+-- Stability   :  unstable
+-- Portability :  unportable
+--
+-------------------------------------------------------------------------------
+module Data.LCRSTree where
+
+import Data.Tree (Tree)
+import qualified Data.Tree as T
+
+-- | A Left-child-right-sibling tree. <https://en.wikipedia.org/wiki/Left-child_right-sibling_binary_tree>
+data LCRSTree n = Empty
+    | Leaf n (LCRSTree n)
+    | Node n (LCRSTree n) (LCRSTree n)
+  deriving (Show, Eq)
+
+-- | Functor instance
+instance Functor LCRSTree where
+  fmap _ Empty = Empty
+  fmap f (Leaf a s) = Leaf (f a) (fmap f s)
+  fmap f (Node n c s) = Node (f n) (fmap f c) (fmap f s)
+
+instance Foldable LCRSTree where
+  foldr _ z Empty = z
+  foldr f z (Leaf n s) = foldr f (f n z) s
+  foldr f z (Node n c s) =
+    let v = foldr f (f n z) c
+    in foldr f v s
+
+-- | Return the depth of the tree. This means the depth of the longest
+-- branch
+lcrsDepth :: Integral i => LCRSTree n -> i
+lcrsDepth = depth 0
+  where
+    depth i Empty = i
+    depth i (Leaf _ s) = depth i s
+    depth i (Node _ c s) =
+      let lDepth = depth (i + 1) c
+          rDepth = depth i s
+      in max lDepth rDepth
+
+-- | Convert a 'Tree' into a 'LCRSTree'
+fromRoseTree :: Tree n -> LCRSTree n
+fromRoseTree t = mkWithS t []
+  where
+    mkWithS (T.Node n []) ss = Leaf n $ siblings ss
+    mkWithS (T.Node n ch) ss =
+      let mkN = case ch of
+                 [] -> Leaf n
+                 (c:cs) -> Node n (mkWithS c cs)
+      in  mkN $ siblings ss
+
+    siblings [] = Empty
+    siblings (c:cs) = mkWithS c cs
+
+-- | Convert a 'LCRSTree' into a 'Tree'
+--
+-- This function fails if a non-top 'Node' is passed. A non-top node is a node
+-- @Node n c s@ where @s /= Empty@.
+toRoseTree :: LCRSTree n -> Tree n
+toRoseTree (Node topN topC Empty) = T.Node topN (collectS topC)
+  where
+    collectS  Empty   = []
+    collectS (Leaf a s) = T.Node a [] : collectS s
+    collectS (Node n c s) = T.Node n (collectS c) : collectS s
+toRoseTree _ = error "fromLCRSTree: non-top node passed"
diff --git a/src/Data/PathTree.hs b/src/Data/PathTree.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/PathTree.hs
@@ -0,0 +1,123 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Data.PathTree
+-- Copyright   :  (c) Pedro Rodriguez Tavarez <pedro@pjrt.co>
+-- License     :  BSD3-style (see LICENSE)
+--
+-- Maintainer  :  Pedro Rodriguez Tavarez <pedro@pjrt.co>
+-- Stability   :  unstable
+-- Portability :  unportable
+--
+-- This module implements multiple functions using a 'LCRSTree' to create a
+-- tree where the mode of insertion are paths.
+-------------------------------------------------------------------------------
+module Data.PathTree
+( PathTree
+, LCRSTree(..)
+, insert
+, insertWith
+, insertReplace
+, fromPath
+, fromPaths
+, fromPathsWith
+, fromPathsReplace
+, toPaths
+, pathExists
+) where
+
+import Data.List (foldl')
+import Data.LCRSTree
+
+-- | A path tree is simply a 'LCRSTree'
+type PathTree n = LCRSTree n
+
+-- | Insert a value /a/ into the path /[n]/ into a tree.
+insert :: (Eq n) => [n] -> PathTree n -> PathTree n
+insert t Empty = fromPath t
+insert [] t  = t
+insert [a] t =
+  case t of
+    Empty -> Leaf a Empty
+    Leaf a' s -> Leaf a (Leaf a' s)
+    Node n c s -> Node n c (insert [a] s)
+insert (h:t) l@(Leaf _ _) = Node h (insert t Empty) l
+insert (h:t) (Node n c s)
+  | h == n = Node n (insert t c) s
+  | otherwise = Node n c (insert (h:t) s)
+
+-- | Like 'insert', but will use /f/ to decide what to do if an existing
+-- value already exists at the path.
+insertWith :: (Eq n) => (n -> n -> n) -> [n] -> PathTree n -> PathTree n
+insertWith _ t Empty = fromPath t
+insertWith _ [] t = t
+insertWith f [a] t =
+  case t of
+    Empty -> Leaf a Empty
+    Leaf a' s -> if a == a'
+                 then Leaf (f a' a) s
+                 else Leaf a (insertWith f [a] s)
+    Node n c s -> if n == a
+                  then Node (f n a) c s
+                  else Node n c (insertWith f [a] s)
+insertWith f (h:t) l@(Leaf _ _) = Node h (insertWith f t Empty) l
+insertWith f (h:t) (Node n c s)
+  | h == n = Node n (insertWith f t c) s
+  | otherwise = Node n c (insertWith f (h:t) s)
+
+-- | Like 'insert', but replaces the value at the path. May seem odd to
+-- replace a value that is equal to itself, but this can be used with
+-- partially-equal types for some flexibility.
+insertReplace :: (Eq n) => [n] -> PathTree n -> PathTree n
+insertReplace = insertWith const
+
+
+-- | Given a single path, create a tree from it.
+fromPath :: [n] -> PathTree n
+fromPath [] = Empty
+fromPath [a] = Leaf a Empty
+fromPath (h:t) = Node h (fromPath t) Empty
+
+-- | Like 'fromPath', but for multiple paths.
+fromPaths :: Eq n => [[n]] -> PathTree n
+fromPaths [] = Empty
+fromPaths (h:t) = foldl' (flip insert) (fromPath h) t
+
+-- | Like 'fromPaths' but applies /f/ if a give path already exists.
+fromPathsWith :: Eq n => (n -> n -> n) -> [[n]] -> PathTree n
+fromPathsWith _ [] = Empty
+fromPathsWith f (h:t) = foldl' (flip (insertWith f)) (fromPath h) t
+
+-- | Like 'fromPaths' but if two equal paths are passed, the former one
+-- will be replaced.
+fromPathsReplace :: Eq n => [[n]] -> PathTree n
+fromPathsReplace = fromPathsWith const
+
+-- | Returns all paths from the root node(s).
+-- Note that @toPaths . fromPaths@ may NOT return the same tree back due to
+-- some reordering of siblings.
+toPaths :: PathTree n -> [[n]]
+toPaths = trackPath []
+  where
+    trackPath _ Empty = []
+    trackPath ns (Leaf a sib) = (ns ++ [a]) : trackPath ns sib
+    trackPath ns (Node n' c' s') =
+      let newPath = ns ++ [n']
+      in  trackPath newPath c' ++ trackPath ns s'
+
+-- | Given a path, determine if it exists fully. For a path to "exists fully"
+-- means that it ends on a level that contains a leaf.
+pathExists :: Eq n => [n] -> LCRSTree n -> Bool
+pathExists _ Empty = False
+pathExists paths (Leaf n s) =
+  case paths of
+    [] -> False
+    [p] -> if n == p then True
+                     else pathExists [p] s
+    (p:ps) -> if p == n then pathExists ps s
+                        else pathExists (p:ps) s
+pathExists paths (Node n c s) =
+  case paths of
+    [] -> False
+    [p] -> pathExists [p] s
+    (p:ps) -> if p == n then pathExists ps c
+                        else pathExists (p:ps) s
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,230 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+module Main where
+
+import Test.QuickCheck
+import Data.List (foldl')
+import Control.Arrow (first)
+import Control.Monad (liftM2, liftM3)
+import Data.LCRSTree
+import Data.PathTree
+
+import Test.Framework
+import Test.Framework.Providers.QuickCheck2
+
+
+main :: IO ()
+main = defaultMain runTests
+
+runTests :: [Test]
+runTests =
+  [ prop_fromPath
+  , prop_insert
+  , prop_pathExistance
+  , prop_roseIdentity
+  -- , testProperty "Tree Identity" $ noShrinking prop_identity
+  ]
+
+prop_fromPath :: Test
+prop_fromPath =
+    testGroup "fromPath"
+      [ testProperty "identity" idendity_test
+      , testProperty "depth" depth_test
+      ]
+  where
+    idendity_test :: Property
+    idendity_test =
+      forAll pathOf2OrMore $ \path ->
+        (head . toPaths . fromPath) path === path
+    depth_test =
+      forAll pathOf2OrMore $ \path ->
+        let depth = length path - 1
+        in lcrsDepth (fromPath path) === depth
+
+    pathOf2OrMore = nonEmptyPath `suchThat` ((2 <) . length)
+
+prop_insert :: Test
+prop_insert =
+  testGroup "Insert"
+    [ testProperty "all values inserted should exist in the tree" insertExists
+    , testProperty "inserting multiple paths with the same head should return a top node" topNodeInsert
+    , testProperty "two paths inserted in any order should both exist" insertOrderExist
+    , testProperty "inserting two path that diverge on a node should create a tree with one node diverging" insertDiverge
+    ]
+  where
+    insertExists =
+      forAll nonEmptyPathAndTree $ \(path, tree) ->
+        let newT = insert path tree
+        in  pathExistsE path newT
+      where
+        nonEmptyPathAndTree = liftM2 (,) nonEmptyPath arbitrary
+
+    insertOrderExist =
+      forAll twoNonEmptyPathsAndTree $ \(p1, p2, tree) ->
+        let newTree1 = insert p1 $ insert p2 tree
+            newTree2 = insert p2 $ insert p1 tree
+        in conjoin [ pathExistsE p1 newTree1, pathExistsE p2 newTree1
+                   , pathExistsE p1 newTree2, pathExistsE p2 newTree2 ]
+        where
+          twoNonEmptyPathsAndTree :: Gen ([AlphaChar], [AlphaChar], LCRSTree AlphaChar)
+          twoNonEmptyPathsAndTree =
+            liftM3 (,,) (listOf1 arbitrary) (listOf1 arbitrary) arbitrary
+
+    topNodeInsert =
+      forAll nonEmptyPathAndArb $ \(paths, top) ->
+        let newPaths = map (top:) paths
+            tree =  foldl' (flip insert) Empty newPaths
+        in siblings tree == Empty
+        where
+          siblings (Node _ _ s) = s
+          siblings (Leaf _ s) = s
+          sibling Empty = error "No siblings for Empty"
+          nonEmptyPathAndArb = liftM2 (,) (listOf1 nonEmptyPath) arbitrary
+
+    insertDiverge =
+      forAll (zipM3 nonEmptyPath nonEmptyPath nonEmptyPath) $ \(root, p1, p2) ->
+        let paths = [root ++ p1, root ++ p2]
+            lenOfInter = lenMin p1 p2
+            tree = foldl' (flip insert) Empty paths
+            actual = nodeCount tree
+            expectedNumOfLeaf = 2
+            expectedNumOfNode = lenOfInter - expectedNumOfLeaf + length root
+        in counterexample
+            (show tree ++ " contains " ++ show actual ++ " node-leaf count but expected "
+                       ++ show (expectedNumOfNode, expectedNumOfLeaf))
+            (actual == (expectedNumOfNode, expectedNumOfLeaf))
+        where
+          lenMin [l] a = 1 + length a
+          lenMin a [l] = 1 + length a
+          lenMin l1@(h1:t1) l2@(h2:t2)
+            | h1 == h2 = 1 + lenMin t1 t2
+            | otherwise = length $ l1 ++ l2
+          intersectFromStart a [] = a
+          intersectFromStart [] a = a
+          intersectFromStart l1@(h1:t1) l2@(h2:t2)
+            | h1 == h2 = h1 : intersectFromStart t1 t2
+            | otherwise = l1 ++ l2
+
+
+prop_pathExistance :: Test
+prop_pathExistance =
+  testGroup "Path integrity"
+    [ testProperty "paths should exist in a tree they make" prop_existance
+    , testProperty "countPathExistances should return n for n non-uniquily inserted paths" prop_cpeNonUnique
+    , testProperty "countPathExistances should return 1 for n uniquily inserted paths" prop_cpeUnique
+    ]
+
+  where
+    nonZero :: Gen Int
+    nonZero = arbitrary `suchThat` (>0)
+
+    prop_existance =
+      forAll (listOf1 nonEmptyPath) $ \paths ->
+        let tr = fromPaths paths
+        in conjoin $ map (`pathExistsE` tr) paths
+
+    prop_cpeNonUnique =
+      forAll (zipM nonEmptyPath nonZero) $ \(path, n) ->
+        let tr = foldl' (flip insert) Empty $ map (const path) [1..n]
+        in  countPathExistances path tr === n
+
+    prop_cpeUnique =
+      forAll (zipM nonEmptyPath nonZero) $ \(path, n) ->
+        let tr = foldl' (flip insertReplace) Empty $ map (const path) [1..n]
+        in  countPathExistances path tr === 1
+
+
+prop_roseIdentity :: Test
+prop_roseIdentity =
+    testProperty "fromRoseTree . toRoseTree should be identity" roseIdent
+  where
+    roseIdent :: LCRSTree AlphaChar -> Property
+    roseIdent tree = (fromRoseTree . toRoseTree) tree === tree
+
+
+-- I would like to test this, but at the moment, I can't guarantee the
+-- order in which the tree is built from the path will be the same
+-- other the tree had before. Semantically speaking, however, the tree
+-- doesn't change.
+--
+-- I could make the equality if the tree be order independent on
+-- sibling nodes, but that sounds like work :\
+-- We could use the path as the "identity" of a tree (a tree is indentified
+-- by its paths). This makes sense, I think.
+prop_identity :: LCRSTree AlphaChar -> Property
+prop_identity tree = (fromPaths . toPaths) tree === tree
+
+instance (Eq n, Arbitrary n) => Arbitrary (LCRSTree n) where
+  shrink Empty = []
+  shrink (Leaf a s) =
+    [Empty] ++ [s] ++ [Leaf a' s' | (a', s') <- shrink (a, s)]
+  shrink (Node n c s) =
+    [Empty] ++ [c, s] ++ [Node n' c' s' | (n', c', s') <- shrink (n, c, s)]
+
+  arbitrary = do
+      let empty = return Empty
+          leaf = do n <- arbitrary
+                    s <- freq [empty, node, leaf]
+                    return $ Leaf n s
+          node = do n <- arbitrary
+                    c <- freq [leaf, node]
+                    s <- freq [empty, leaf, node]
+                    return $ Node n c s
+      n <- arbitrary
+      c <- node
+      return $ Node n c Empty
+    where
+      freq = frequency . freq' 60
+        where
+          freq' _ [] = []
+          freq' n (h:t)
+            | n <= 1 = (1, h) : freq' 1 t
+            | otherwise = (n, h) : freq' (div n 2) t
+
+
+-- | A smaller set of characters (a-zA-Z)
+newtype AlphaChar = AlphaChar Char
+  deriving (Eq, Ord)
+
+instance Show AlphaChar where
+  show (AlphaChar c) = "'" ++ [c] ++ "'"
+
+
+instance Arbitrary AlphaChar where
+  arbitrary =
+    let es = elements $ ['A'..'Z'] ++ ['a'..'z']
+    in AlphaChar <$> es
+
+
+zipM = liftM2 (,)
+zipM3 = liftM3 (,,)
+
+pathExistsE x y =
+  counterexample (show x ++ " does not exist in " ++ show y) (pathExists x y)
+
+nonEmptyPath :: Gen [AlphaChar]
+nonEmptyPath = arbitrary `suchThat` (not . null)
+
+countPathExistances :: (Integral i, Eq n) => [n] -> PathTree n -> i
+countPathExistances [] _ = 1 -- The empty path exists once, in any tree
+countPathExistances _ Empty = 0
+countPathExistances [h] (Leaf n s)
+  | h == n = 1 + countPathExistances [h] s
+  | otherwise = countPathExistances [h] s
+countPathExistances (h:t) tree =
+  case tree of
+    Empty -> 0
+    Leaf _ s -> countPathExistances (h:t) s
+    Node n c s -> if n == h
+                  then countPathExistances t c
+                  else countPathExistances (h:t) s
+
+nodeCount :: Integral i => PathTree n -> (i, i)
+nodeCount = nodeC (0,0)
+  where
+    nodeC :: Integral i => (i, i) -> PathTree n -> (i, i)
+    nodeC t Empty = t
+    nodeC (cn, cl) (Leaf _ s) = nodeC (cn, cl + 1) s
+    nodeC (cn, cl) (Node _ c s) =
+      let (cnc, clc) = nodeC (cn + 1, cl) c
+          (snc, slc) = nodeC (0, 0) s
+      in (cnc + snc, clc + slc)
