diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2014 Timothy Jones
+
+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/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/snaplet-css-min.cabal b/snaplet-css-min.cabal
new file mode 100644
--- /dev/null
+++ b/snaplet-css-min.cabal
@@ -0,0 +1,54 @@
+name:          snaplet-css-min
+version:       0.1.0
+license:       MIT
+license-file:  LICENSE
+author:        Timothy Jones
+maintainer:    Timothy Jones <git@zmthy.io>
+homepage:      https://github.com/zmthy/snaplet-css-min
+bug-reports:   https://github.com/zmthy/snaplet-css-min/issues
+copyright:     (c) 2014 Timothy Jones
+category:      Web
+build-type:    Simple
+cabal-version: >= 1.10
+synopsis:      A Snaplet for CSS minification
+description:
+  A Snaplet for minifying and caching CSS files.
+  .
+  Nest this Snaplet inside your own, and place your CSS files in
+  @snaplets/css-min@.
+  .
+  The minifier just parses and renders the contents of the files with
+  @css-text@, so the minification is not complete. It will remove most
+  whitespace, though.
+
+library
+  hs-source-dirs:   src
+  default-language: Haskell2010
+
+  default-extensions:
+    OverloadedStrings
+
+  other-extensions:
+    DeriveDataTypeable
+
+  exposed-modules:
+    Snap.Snaplet.CSS.Minify
+
+  build-depends:
+    base         >= 4.6    && < 5,
+    bytestring   >= 0.10   && < 0.11,
+    css-text     >= 0.1.2  && < 0.2,
+    directory    >= 1.2    && < 2,
+    filepath     >= 1.3    && < 2,
+    lens         >= 3.9.2  && < 5,
+    mtl          >= 2.1    && < 3,
+    snap         >= 0.13.1 && < 0.14,
+    snap-core    >= 0.9.3  && < 0.10,
+    text         >= 0.11.3 && < 0.12,
+    transformers >= 0.3.0  && < 0.4,
+    utf8-string  >= 0.3    && < 0.4
+
+source-repository head
+  type:     git
+  location: git://github.com/zmthy/http-media.git
+
diff --git a/src/Snap/Snaplet/CSS/Minify.hs b/src/Snap/Snaplet/CSS/Minify.hs
new file mode 100644
--- /dev/null
+++ b/src/Snap/Snaplet/CSS/Minify.hs
@@ -0,0 +1,107 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+
+------------------------------------------------------------------------------
+-- | Nest this Snaplet within another to have it retrieve and minify the CSS
+-- in its directory.
+--
+-- First, embed this Snaplet in your application:
+--
+-- > import Snap.Snaplet.CSS.Minify
+-- >
+-- > data App = App { cssMin :: Snaplet CssMin, ... }
+--
+-- Then nest this Snaplet in your initializer at the route you want your
+-- stylesheets to be available at:
+--
+-- > nestSnaplet "style" cssMin cssMinInit
+--
+-- The stylesheets in @snaplets/css-min@ will now be available in minified
+-- form at the @/style@ route.
+--
+-- To have the files reloaded in development mode add @\"snaplets/css-min\"@
+-- to the list of watched directories in the Main module generated by Snap.
+module Snap.Snaplet.CSS.Minify
+    ( CssMin
+    , cssMinInit
+    , ParseException
+    ) where
+
+------------------------------------------------------------------------------
+import qualified Data.Text              as T
+import qualified Data.Text.IO           as T
+import qualified Data.Text.Lazy         as LT
+import qualified Data.Text.Lazy.Builder as LT
+import qualified Data.ByteString.UTF8   as BS
+
+------------------------------------------------------------------------------
+import Control.Applicative    ((<$), (<$>), (<*>))
+import Control.Exception      (Exception (..), SomeException (..), throw)
+import Control.Lens           (Lens', (<&>), over, view)
+import Control.Monad          (unless)
+import Control.Monad.IO.Class (liftIO)
+import Control.Monad.State    (get, modify)
+import Data.List              (isSuffixOf)
+import Data.Text              (Text)
+import Data.Typeable          (Typeable, cast)
+import Snap.Core
+import Snap.Snaplet
+import System.FilePath        ((</>))
+import System.Directory       (doesFileExist)
+import Text.CSS.Parse         (NestedBlock, parseNestedBlocks)
+import Text.CSS.Render        (renderNestedBlocks)
+
+
+------------------------------------------------------------------------------
+-- | The Snaplet's state, storing the cache of minified files.
+data CssMin = CssMin { _cache :: [(FilePath, Text)] }
+
+cache :: Lens' CssMin [(FilePath, Text)]
+cache f m = f (_cache m) <&> \ c -> m { _cache = c }
+
+
+------------------------------------------------------------------------------
+-- | Initializes the CSS minifier by adding a route for reading, minifying and
+-- serving the CSS files in the snaplet/css-min directory.
+cssMinInit :: SnapletInit b CssMin
+cssMinInit = makeSnaplet "css-min" "CSS minifier" Nothing $
+    CssMin [] <$ addRoutes [("", serveCss)]
+
+serveCss :: Handler b CssMin ()
+serveCss = do
+    fp <- (</>) <$> getSnapletFilePath <*>
+        (BS.toString . rqPathInfo <$> getRequest)
+    liftIO (doesFileExist fp) >>=
+        flip unless pass . (".css" `isSuffixOf` fp &&)
+    view cache <$> get >>= maybe (minify fp) writeCss . lookup fp
+
+minify :: FilePath -> Handler b CssMin ()
+minify fp = parseNestedBlocks <$>
+    (getSnapletFilePath >>= liftIO . T.readFile . (</> fp)) >>=
+        either (throw . ParseException) (cacheAndWrite fp)
+
+cacheAndWrite :: FilePath -> [NestedBlock] -> Handler b CssMin ()
+cacheAndWrite fp css = do
+    let text = LT.toStrict $ LT.toLazyText $ renderNestedBlocks css
+    modify $ over cache ((fp, text) :)
+    writeCss text
+
+writeCss :: Text -> Handler b v ()
+writeCss css = do
+    modifyResponse
+        $ setContentLength (fromIntegral $ T.length css)
+        . setContentType "text/css"
+        . setResponseCode 200
+    writeText css
+
+
+------------------------------------------------------------------------------
+data ParseException = ParseException String
+    deriving (Typeable)
+
+instance Show ParseException where
+    show (ParseException msg) = "CSS parse exception: " ++ msg
+
+instance Exception ParseException where
+    toException = SomeException
+    fromException = cast
+
