diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,11 @@
+# Changelog for `matcha`
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to the
+[Haskell Package Versioning Policy](https://pvp.haskell.org/).
+
+## Unreleased
+
+## 0.1.0.0 - YYYY-MM-DD
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,26 @@
+Copyright 2024 Author name here
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1.  Redistributions of source code must retain the above copyright notice, this
+    list of conditions and the following disclaimer.
+
+2.  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.
+
+3.  Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER 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/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,1 @@
+# matcha 🍵
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/app/Main.hs b/app/Main.hs
new file mode 100644
--- /dev/null
+++ b/app/Main.hs
@@ -0,0 +1,6 @@
+module Main (main) where
+
+import Matcha
+
+main :: IO ()
+main = someFunc
diff --git a/matcha.cabal b/matcha.cabal
new file mode 100644
--- /dev/null
+++ b/matcha.cabal
@@ -0,0 +1,78 @@
+cabal-version: 2.2
+
+-- This file has been generated from package.yaml by hpack version 0.35.1.
+--
+-- see: https://github.com/sol/hpack
+
+name:           matcha
+version:        0.0.0.1
+description:    Please see the README on GitHub at <https://github.com/rashadg1030/matcha#readme>
+homepage:       https://github.com/rashadg1030/matcha#readme
+bug-reports:    https://github.com/rashadg1030/matcha/issues
+author:         Rashad Gover
+maintainer:     phantomtype@protonmail.com
+category:       Web, HTTP
+synopsis:       A micro web framework based on pattern matching
+copyright:      2024 Rashad Gover
+license:        BSD-3-Clause
+license-file:   LICENSE
+build-type:     Simple
+extra-source-files:
+    README.md
+    CHANGELOG.md
+
+source-repository head
+  type: git
+  location: https://github.com/rashadg1030/matcha
+
+library
+  exposed-modules:
+      Matcha
+      Matcha.Body
+      Matcha.Headers
+      Matcha.Method
+      Matcha.Path
+      Matcha.Query
+  other-modules:
+      Paths_matcha
+  autogen-modules:
+      Paths_matcha
+  hs-source-dirs:
+      src
+  ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints
+  build-depends:
+      base >=4.7 && <5,
+      http-api-data >= 0.6 && < 0.7,
+      text >= 2.0.2 && < 2.1,
+      http-types >= 0.12.4 && < 0.13,
+      wai >= 3.2.4 && < 3.3,
+  default-language: Haskell2010
+
+executable matcha-exe
+  main-is: Main.hs
+  other-modules:
+      Paths_matcha
+  autogen-modules:
+      Paths_matcha
+  hs-source-dirs:
+      app
+  ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N
+  build-depends:
+      base >=4.7 && <5
+    , matcha
+  default-language: Haskell2010
+
+test-suite matcha-test
+  type: exitcode-stdio-1.0
+  main-is: Spec.hs
+  other-modules:
+      Paths_matcha
+  autogen-modules:
+      Paths_matcha
+  hs-source-dirs:
+      test
+  ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N
+  build-depends:
+      base >=4.7 && <5
+    , matcha
+  default-language: Haskell2010
diff --git a/src/Matcha.hs b/src/Matcha.hs
new file mode 100644
--- /dev/null
+++ b/src/Matcha.hs
@@ -0,0 +1,14 @@
+{-# LANGUAGE ApplicativeDo #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE PatternSynonyms #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE ViewPatterns #-}
+
+module Matcha (
+    someFunc,
+) where
+
+someFunc :: IO ()
+someFunc = putStrLn "someFunc"
diff --git a/src/Matcha/Body.hs b/src/Matcha/Body.hs
new file mode 100644
--- /dev/null
+++ b/src/Matcha/Body.hs
@@ -0,0 +1,1 @@
+module Matcha.Body where
diff --git a/src/Matcha/Headers.hs b/src/Matcha/Headers.hs
new file mode 100644
--- /dev/null
+++ b/src/Matcha/Headers.hs
@@ -0,0 +1,1 @@
+module Matcha.Headers where
diff --git a/src/Matcha/Method.hs b/src/Matcha/Method.hs
new file mode 100644
--- /dev/null
+++ b/src/Matcha/Method.hs
@@ -0,0 +1,13 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE PatternSynonyms #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module Matcha.Method where
+
+import Network.HTTP.Types (Method)
+
+pattern GET :: Method
+pattern GET = "GET"
+
+pattern POST :: Method
+pattern POST = "POST"
diff --git a/src/Matcha/Path.hs b/src/Matcha/Path.hs
new file mode 100644
--- /dev/null
+++ b/src/Matcha/Path.hs
@@ -0,0 +1,49 @@
+{-# LANGUAGE PatternSynonyms #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE ViewPatterns #-}
+
+module Matcha.Path where
+
+import Data.Either (rights)
+import Data.Text (Text)
+import Web.HttpApiData (
+    FromHttpApiData (parseUrlPiece),
+    ToHttpApiData (toUrlPiece),
+ )
+
+pattern Param :: (ToHttpApiData a, FromHttpApiData a) => a -> Text
+pattern Param x <- (parseUrlPiece -> Right x)
+    where
+        Param x = toUrlPiece x
+
+pattern Blob :: (ToHttpApiData a, FromHttpApiData a) => [a] -> [Text]
+pattern Blob l <- (rights . map parseUrlPiece -> l)
+    where
+        Blob l = map toUrlPiece l
+
+pattern (:/) :: (ToHttpApiData a, FromHttpApiData a) => a -> [Text] -> [Text]
+pattern h :/ t <- ((parseUrlPiece -> Right h) : t)
+    where
+        h :/ t = toUrlPiece h : t
+
+pattern (:/*) :: (ToHttpApiData a, ToHttpApiData b, FromHttpApiData a, FromHttpApiData b) => a -> [b] -> [Text]
+pattern h :/* t <- ((parseUrlPiece -> Right h) : Blob t)
+    where
+        h :/* t = toUrlPiece h : map toUrlPiece t
+
+infixr 8 :/
+infixr 9 :/*
+
+pattern MyUrl :: Int -> Float -> [Bool] -> [Text]
+pattern MyUrl x y bs = (x :: Int) :/ (y :: Float) :/ Blob @Bool bs
+
+pattern MyOtherUrl :: Int -> Float -> [Bool] -> [Text]
+pattern MyOtherUrl x y bs = (x :: Int) :/ (y :: Float) :/* bs
+
+url :: [Text]
+url = (5 :: Int) :/ (5.6 :: Float) :/ Blob @Bool [True, False, False, True, False]
+
+matchUrl :: [Text] -> Maybe (Int, Float)
+matchUrl (int :/ float :/* ([] :: [Text])) = Just (int, float)
+matchUrl _ = Nothing
diff --git a/src/Matcha/Query.hs b/src/Matcha/Query.hs
new file mode 100644
--- /dev/null
+++ b/src/Matcha/Query.hs
@@ -0,0 +1,40 @@
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE InstanceSigs #-}
+
+module Matcha.Query where
+
+import Data.Text (Text)
+import Network.HTTP.Types (Query)
+import Network.Wai (Request)
+import Web.HttpApiData (FromHttpApiData, ToHttpApiData)
+
+data Parser a where
+    FMap :: (a -> b) -> Parser a -> Parser b
+    Pure :: a -> Parser a
+    Apply :: Parser (a -> b) -> Parser a -> Parser b
+    Optional :: Parser a -> Parser (Maybe a)
+    Option :: a -> Parser a -> Parser a
+    Param :: (FromHttpApiData a, ToHttpApiData a) => Text -> Parser a
+    Flag :: Text -> Parser ()
+
+instance Functor Parser where
+    fmap :: (a -> b) -> Parser a -> Parser b
+    fmap = FMap
+
+instance Applicative Parser where
+    pure :: a -> Parser a
+    pure = Pure
+
+    (<*>) :: Parser (a -> b) -> Parser a -> Parser b
+    (<*>) = Apply
+
+data Error = Error
+
+parse :: Request -> Parser a -> Either Error a
+parse = undefined
+
+match :: Parser a -> Query -> Either Error a
+match = undefined
+
+on :: Parser a -> Query -> (Error -> b) -> (a -> b) -> b
+on = undefined
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,2 @@
+main :: IO ()
+main = putStrLn "Test suite not yet implemented"
