diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2016 Oisin Kidney
+
+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/hakyll-series.cabal b/hakyll-series.cabal
new file mode 100644
--- /dev/null
+++ b/hakyll-series.cabal
@@ -0,0 +1,92 @@
+name:               hakyll-series
+version:            0.1.0.1
+synopsis:           Adds series functionality to hakyll
+description:
+  Module for adding series functionality to hakyll.
+  .
+  Example <https://oisdk.github.io/hakyll-series/ here>.
+  .
+  In your posts, provide metadata at the top like so:
+  .
+  > ---
+  > title: something
+  > series: things
+  > ---
+  .
+  This will add the following fields to the post:
+  .
+    [@series@]: The name of the series
+    [@seriesLength@]: The total number of posts in the series
+    [@seriesCurPos@]: The position of the current post in the series
+    [@seriesUrl@]: The URL of the series page
+  .
+  Using that, in your post template, something like this:
+  .
+  >
+  > $if(series)$
+  >     <a href="$seriesUrl$">Part $seriesCurPos$ of a $seriesLength$-part series on $series$</a>
+  > $endif$
+  .
+  Will render like this:
+  .
+  > Part 1 of a 5-part series on things
+  .
+  Linked to the aggregate page for the series, which would render something like this:
+  .
+  > Things
+  > Part 1: something
+  .
+  To add it to your blog, add something like this to your @main@:
+  .
+  > series <- buildSeries "posts/*" (fromCapture "series/*.html")
+  >
+  > tagsRules series $ \(s:erie) pattrn -> do
+  >     let title = toUpper s : erie
+  >     route idRoute
+  >     compile $ do
+  >         posts <- chronological =<< loadAll pattrn
+  >         let ctx = constField "title" title `mappend`
+  >                   listField "posts" postCtx (pure posts) `mappend`
+  >                   defaultContext
+  >
+  >         makeItem ""
+  >             >>= loadAndApplyTemplate "templates/series.html" ctx
+  >             >>= loadAndApplyTemplate "templates/default.html" ctx
+  >             >>= relativizeUrls
+  .
+  To have access to the series context in each post, change the post rule to something like this:
+  .
+  > match "posts/*" $ do
+  >     route $ setExtension "html"
+  >     compile $ pandocCompiler
+  >         >>= loadAndApplyTemplate "templates/post.html"    (postCtxWithSeries series)
+  >         >>= loadAndApplyTemplate "templates/default.html" (postCtxWithSeries series)
+  >         >>= relativizeUrls
+  .
+  Where `postCtxWithSeries` can be something like:
+  .
+  > postCtxWithSeries :: Tags -> Context String
+  > postCtxWithSeries series = seriesField series `mappend` postCtx
+  .
+  A minimal example is provided in this repo, on top of the default hakyll setup. (it also provides the templates)
+build-type:         Simple
+cabal-version:      >= 1.10
+homepage:           https://github.com/oisdk/hakyll-series
+license:            MIT
+license-file:       LICENSE
+author:             Donnacha Oisín Kidney
+copyright:          2016 Donnacha Oisín Kidney
+maintainer:         mail@doisinkidney.com
+category:           Web
+
+library
+  hs-source-dirs:   src
+  exposed-modules:  Hakyll.Web.Series
+  build-depends:    base == 4.*
+                  , hakyll >= 4.8.0
+                  , containers >= 0.5
+  default-language: Haskell2010
+
+source-repository head
+  type:     git
+  location: https://github.com/oisdk/hakyll-series
diff --git a/src/Hakyll/Web/Series.hs b/src/Hakyll/Web/Series.hs
new file mode 100644
--- /dev/null
+++ b/src/Hakyll/Web/Series.hs
@@ -0,0 +1,90 @@
+{-# LANGUAGE LambdaCase #-}
+
+-- | Module for adding series functionality to a blog, similar to tags.
+
+module Hakyll.Web.Series
+  ( seriesField
+  , getSeries
+  , buildSeries
+  ) where
+
+import           Control.Applicative
+import           Control.Arrow
+import           Control.Monad
+import           Data.List           (elemIndex)
+import qualified Data.Map.Strict     as Map
+import           Data.Monoid
+import qualified Data.Set            as Set
+import           Hakyll
+
+-- | Gets the series from an identifier. Similar to 'getTags',
+-- except it only accepts one series per identifier.
+getSeries :: MonadMetadata m => Identifier -> m (Maybe String)
+getSeries = flip getMetadataField "series"
+
+toAlt :: (Foldable f, Alternative m) => f a -> m a
+toAlt = getAlt . foldMap pure
+
+infixr 1 >->
+(>->) :: Functor f =>  (a -> f b) -> (b -> c) -> a -> f c
+f >-> g = f >>> fmap g
+
+-- | Generates four fields:
+--
+--    [@series@] The name of the series
+--
+--    [@seriesLength@] The total number of posts in the series
+--
+--    [@seriesCurPos@] The position of the current post in the series
+--
+--    [@seriesUrl@] The URL of the series page
+
+seriesField :: Tags -> Context a
+seriesField tags = Context $ const . \case
+    "series"       -> seriesName
+                  >-> StringField
+
+    "seriesCurPos" -> itemIdentifier &&& otherPostsInSeries
+                  >>> sequence
+                  >>> fmap (uncurry elemIndex)
+                  >=> toAlt
+                  >-> succ
+                  >>> show
+                  >>> StringField
+
+    "seriesLength" -> otherPostsInSeries
+                  >-> length
+                  >>> show
+                  >>> StringField
+
+    "seriesUrl"    -> seriesName
+                  >=> tagsMakeId tags
+                  >>> getRoute
+                  >=> toAlt
+                  >-> toUrl
+                  >>> StringField
+
+    _ -> const empty
+  where
+    seriesName = itemIdentifier
+             >>> getSeries
+             >=> toAlt
+    otherPostsInSeries = seriesName
+                     >=> flip lookup (tagsMap tags)
+                     >>> toAlt
+
+-- | Similar to the 'buildTags' function in "Hakyll.Web.Tags", except
+-- checks the series field, and can only accept one series per item.
+buildSeries :: MonadMetadata m
+            => Pattern
+            -> (String -> Identifier) -- ^ Function for converting a given series name into an identifier for its page
+            -> m Tags
+buildSeries pattrn makeId = do
+    ids <- getMatches pattrn
+    tagMap <- foldM addTags Map.empty ids
+    let set' = Set.fromList ids
+    inOrder <- (traverse.traverse) sortChronological (Map.assocs tagMap)
+    pure $ Tags inOrder makeId (PatternDependency pattrn set')
+  where
+    addTags tagMap id' =
+        maybe tagMap (\k -> Map.insertWith (++) k [id'] tagMap) <$> getSeries id'
