diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,5 @@
+# Revision history for ValveValueKeyvalue
+
+## 0.1.0.0 -- YYYY-mm-dd
+
+* First version. Released on an unsuspecting world.
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 BernardoGomesNegri
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,12 @@
+# ValveValueKeyvalue
+A Haskell parser for Valve's value-keyvalue format. The main function is "parseValveVKV" in the module Text.ValveVKV. You can see it only parses to types that are part of the typeclass ValveVKV. For example, if you have this type:
+` data My = My {name :: String, count :: Int} `
+Then the instance looks like this:
+```
+instance ValveVKV My where
+    fromValveVKV this _ =
+        My <$> this ^: "name" <*> this .: "count"
+```
+The first parameter is the entry that should be turned into your type, and the 2nd one is the parent of that entry. The ^: operator receives an entry on the left side and a string on the right side. It tries to find the string subentry named the string inside the entry you gave in on the left. The .: operator is similar, but can return any type, not just string.
+
+The entry type ValveKeyValueEntry has 3 constructors. KVObject, which has a Pair of a KeyValueEntry list. KVInt, which has a Pair of Int and KVString, which has a pair of string. The Pair type itself is one constructor of a string and the type parameter.
diff --git a/ValveValueKeyvalue.cabal b/ValveValueKeyvalue.cabal
new file mode 100644
--- /dev/null
+++ b/ValveValueKeyvalue.cabal
@@ -0,0 +1,40 @@
+cabal-version:      2.4
+name:               ValveValueKeyvalue
+version:            1.0.0.0
+
+-- A short (one-line) description of the package.
+synopsis: A Valve Value-keyvalue parser for Haskell made with Parsec.
+
+-- A longer description of the package.
+description: This is a package made to parse Valve's value-keyvalue format, common in Source Engine games. Valve value-keyvalue files may take the extensions ".pop" or ".vtf". The main module is Text.ValveVKV. The main function you will be using is parseValveVKV.
+
+-- A URL where users can report bugs.
+homepage: https://github.com/BernardoGomesNegri/ValveValueKeyvalue
+bug-reports: https://github.com/BernardoGomesNegri/ValveValueKeyvalue/issues
+
+-- The license under which the package is released.
+license: MIT
+license-file: LICENSE
+author:             Bernardo Gomes Negri
+maintainer:         b.gomes.negri@gmail.com
+
+category: Parsing
+extra-source-files: CHANGELOG.md, README.md
+
+source-repository head
+    type: git
+    location: https://github.com/BernardoGomesNegri/ValveValueKeyvalue
+
+library
+
+    -- Modules included in this executable, other than Main.
+    exposed-modules: Text.ValveVKV
+    other-modules: Text.ValveVKV.Class
+    other-modules: Text.ValveVKV.Internal
+
+    -- LANGUAGE extensions used by modules in this package.
+    -- other-extensions:
+    build-depends:    base ^>= 4.14.2.0
+    build-depends:    parsec >= 3.1.14 && < 3.2
+    hs-source-dirs:   app
+    default-language: Haskell2010
diff --git a/app/Text/ValveVKV.hs b/app/Text/ValveVKV.hs
new file mode 100644
--- /dev/null
+++ b/app/Text/ValveVKV.hs
@@ -0,0 +1,19 @@
+module Text.ValveVKV(vkvParser, parseValveVKV, fromValveVKV, (.:), (^:), unpair, ValveVKV,
+    ValveKeyValueEntry(KVObject, KVInt, KVString), Pair (Pair), Context) where
+-- Library for processing Valve's value keyvalue format. The main function you will wish to use is parseValveVKV. To convert it into your own type, you
+-- will need to write a 'ValveVKV' instance for it.
+
+import Text.Parsec
+import Text.ValveVKV.Internal
+import Text.ValveVKV.Class
+import Data.Maybe (mapMaybe)
+
+-- | The main function you will be using. Turns the ValveVKV string into a type that has the 'ValveVKV' typeclass.
+parseValveVKV :: ValveVKV a => String -> Maybe a
+parseValveVKV input =
+    let parseRes = parse vkvParser "" input in
+    case parseRes of
+        Left _ -> Nothing
+        Right a ->
+            let topObj = KVObject (Pair "top" a) in
+            fromValveVKV topObj topObj
diff --git a/app/Text/ValveVKV/Class.hs b/app/Text/ValveVKV/Class.hs
new file mode 100644
--- /dev/null
+++ b/app/Text/ValveVKV/Class.hs
@@ -0,0 +1,91 @@
+module Text.ValveVKV.Class where
+
+import Text.ValveVKV.Internal
+import Control.Monad (forM)
+import Data.Maybe (mapMaybe)
+import GHC.Base (NonEmpty)
+import Data.List.NonEmpty (NonEmpty, nonEmpty)
+
+findFromName :: ValveKeyValueEntry -> String -> [ValveKeyValueEntry]
+findFromName (KVObject (Pair _ stuff)) name =
+    mapMaybe finder stuff
+    where
+        finder :: ValveKeyValueEntry -> Maybe ValveKeyValueEntry
+        finder this@(KVObject (Pair thisname s)) = if thisname == name then Just this else Nothing
+        finder this@(KVString (Pair thisname s)) = if thisname == name then Just this else Nothing
+        finder this@(KVInt (Pair thisname s)) = if thisname == name then Just this else Nothing
+findFromName _ _ = []
+
+-- | This operator receives an entry on the left side and a string on the right side. It tries to find the string subentry named the string inside the entry you gave in on the left.
+(.:) :: ValveVKV a => ValveKeyValueEntry -> String -> Maybe a 
+context .: name =
+    let results = findFromName context name in
+    case results of
+        [] -> Nothing
+        x:_ -> fromValveVKV x context
+infixl 5 .:
+
+-- | This operator receives an entry on the left side and a string on the right side. It tries to find the subentry named the string inside the entry you gave in on the left.
+(^:) :: ValveKeyValueEntry -> String -> Maybe String
+context ^: name =
+    let results = findFromName context name in
+    case results of
+        (KVString (Pair _ s)):_ -> Just s
+        _ -> Nothing
+infixl 5 ^:
+
+-- | A type synonim for ValveKeyValueEntry
+type Context = ValveKeyValueEntry
+
+
+-- | The class that lets a value to be made from a Valve value-keyvalue format.
+-- For example, if you have
+-- @
+-- data My = My {name :: String, count :: Int}
+-- @
+-- You write your instance as
+-- @
+-- instance ValveVKV My where
+--     fromValveVKV this _ =
+--         My \<$\> this ^: "name" \<*\> this .: "count"
+-- @
+class ValveVKV a where
+    -- | The first argument is the entry that should be turned into the type. The second argument is the entry just above that.
+    fromValveVKV :: ValveKeyValueEntry -> Context -> Maybe a
+
+instance ValveVKV Int where
+    fromValveVKV (KVInt (Pair _ num)) _ = Just num
+    fromValveVKV _ _ = Nothing
+
+instance ValveVKV a => ValveVKV (Maybe a) where
+    fromValveVKV entry con = Just (fromValveVKV entry con)
+
+instance ValveVKV Bool where
+    fromValveVKV (KVInt (Pair _ 0)) _ = Just False
+    fromValveVKV (KVInt (Pair _ 1)) _ = Just True
+    fromValveVKV _ _ = Nothing
+
+instance ValveVKV a => ValveVKV [a] where
+    fromValveVKV (KVString (Pair name _)) context =
+        let results = mapMaybe (`fromValveVKV` context) (findFromName context name) in
+        case results of
+            [] -> Nothing
+            _ -> Just results
+    fromValveVKV (KVObject (Pair name _)) context =
+        let results = mapMaybe (`fromValveVKV` context) (findFromName context name) in
+        case results of
+            [] -> Nothing
+            _ -> Just results
+    fromValveVKV (KVInt (Pair name _)) context =
+        let results = mapMaybe (`fromValveVKV` context) (findFromName context name) in
+        case results of
+            [] -> Nothing
+            _ -> Just results
+
+instance ValveVKV a => ValveVKV (NonEmpty a) where
+    fromValveVKV entry context =
+        list >>= nonEmpty
+        where
+            list :: ValveVKV a => Maybe [a]
+            list = fromValveVKV entry context
+
diff --git a/app/Text/ValveVKV/Internal.hs b/app/Text/ValveVKV/Internal.hs
new file mode 100644
--- /dev/null
+++ b/app/Text/ValveVKV/Internal.hs
@@ -0,0 +1,107 @@
+module Text.ValveVKV.Internal where
+import Text.Parsec
+import Text.Read (readMaybe)
+
+alphabet :: [Char]
+alphabet = "'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-+=.,#@!$%¨&*\\"
+
+alphabetSpace :: [Char]
+alphabetSpace = ' ':alphabet
+
+data ValveKeyValueEntry
+   = KVObject (Pair [ValveKeyValueEntry])
+   | KVString (Pair String)
+   | KVInt (Pair Int)
+   deriving (Show)
+
+liftVKV :: (String -> String) -> ValveKeyValueEntry -> ValveKeyValueEntry
+liftVKV f (KVObject (Pair name s)) = KVObject (Pair (f name) s)
+liftVKV f (KVInt (Pair name s)) = KVInt (Pair (f name) s)
+liftVKV f (KVString (Pair name s)) = KVString (Pair (f name) s)
+
+
+data Pair a = Pair String a
+    deriving (Show)
+
+unpair :: Pair a -> (String, a)
+unpair (Pair str a) = (str,a)
+
+entryParser :: Parsec String () ValveKeyValueEntry
+entryParser =
+    try objParse <|> try kvIntParse <|> try kvStringParse
+
+whitespaceCommon :: Parsec String () Char
+whitespaceCommon = choice $ fmap char "\t "
+
+nameGrab :: Parsec String () String
+nameGrab = many1 $ choice $ fmap char alphabet
+
+nameGrabSpace :: Parsec String () String
+nameGrabSpace = many1 $ choice $ fmap char alphabetSpace
+
+objParse :: Parsec String () ValveKeyValueEntry
+objParse = do
+    many extendWhitespace
+    many commentParser
+    name <- nameGrab
+    many (try extendWhitespace)
+    char '{'
+    many (try extendWhitespace)
+    things <- vkvParser
+    many (try extendWhitespace)
+    char '}'
+    many (try commentParser)
+    many (try extendWhitespace)
+    return $ KVObject $ Pair name things
+
+extendWhitespace :: Parsec String () Char
+extendWhitespace = choice $ try commentParser:fmap char "\t\n " :: Parsec String () Char
+
+commentParser :: Parsec String () Char
+commentParser = do
+    many whitespaceCommon
+    char '/'
+    char '/'
+    anyLoop
+    where
+        anyLoop :: Parsec String () Char
+        anyLoop = do
+            thisChar <- anyChar
+            if thisChar == '\n' then
+                return '\n'
+            else do
+                anyLoop
+                return thisChar
+
+kvStringParse :: Parsec String () ValveKeyValueEntry
+kvStringParse = do
+    many extendWhitespace
+    many commentParser
+    let stringGrab = many1 $ choice $ fmap char alphabet :: Parsec String () String
+    let names = choice [nameGrab, between (char '"') (char '"') nameGrabSpace]
+    many whitespaceCommon
+    name <- names
+    many1 whitespaceCommon
+    value <- try (between (char '"') (char '"') nameGrabSpace) <|> try stringGrab
+    many (try extendWhitespace)
+    return $ KVString $ Pair name value
+
+kvIntParse :: Parsec String () ValveKeyValueEntry
+kvIntParse = do
+    many extendWhitespace
+    many commentParser
+    let numberGrab = many1 $ choice $ fmap char "0123456789" :: Parsec String () String
+    many (try whitespaceCommon)
+    name <- nameGrab
+    many1 whitespaceCommon
+    valueRaw <- numberGrab
+    many (try extendWhitespace)
+    let value = readMaybe valueRaw :: Maybe Int
+    case value of
+        Just x -> return $ KVInt $ Pair name x
+        Nothing -> fail ""
+
+-- | The Parsec parser itself.
+vkvParser :: Parsec String () [ValveKeyValueEntry]
+vkvParser =
+    many1 entryParser
