diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,5 @@
+# Changelog for polysemy-methodology
+
+## v0.1.0.0
+
+* Set of domain modelling tools for polysemy.
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Daniel Firth (c) 2020
+
+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 Author name here 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/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,27 @@
+# polysemy-methodology
+
+polysemy-methodology provides an algebra for domain modelling in polysemy.
+
+A simple program might look something like this:
+
+```
+prog :: Members '[ Input a
+                 , Methodology a b
+                 , Output b]
+prog = input @a >>= process @a @b >>= output @b
+```
+
+That is, this program transforms an `Input a` into an `Output b` by way of a
+`Methodology a b` that turns `a` into `b`. We can then type apply `a` and `b`
+and connect this to `main`.
+
+If we have a solution readily available, we can consume a `Methodology` by
+running one of the interpreters `runMethodologyPure` or `runMethodologySem`.
+
+Otherwise, we can use the other interpreters in this package to break the
+problem down into components or branches and solve each section separately.
+Each interpreter will produce a new set of `Methodology`s to be solved.
+
+This allows you to work up a solution to a domain problem backwards, by running
+the program you intend to solve directly and using holes to guide the
+requirements.
diff --git a/polysemy-methodology.cabal b/polysemy-methodology.cabal
new file mode 100644
--- /dev/null
+++ b/polysemy-methodology.cabal
@@ -0,0 +1,38 @@
+cabal-version: 1.12
+
+-- This file has been generated from package.yaml by hpack version 0.34.2.
+--
+-- see: https://github.com/sol/hpack
+
+name:           polysemy-methodology
+version:        0.1.0.0
+synopsis:       Domain modelling algebra for polysemy
+category:       Polysemy
+author:         Daniel Firth
+maintainer:     dan.firth@homotopic.tech
+copyright:      2020 Daniel Firth
+license:        MIT
+license-file:   LICENSE
+build-type:     Simple
+extra-source-files:
+    README.md
+    ChangeLog.md
+
+source-repository head
+  type: git
+  location: https://gitlab.com/homotopic-tech/polysemy-methodology
+
+library
+  exposed-modules:
+      Polysemy.Methodology
+  other-modules:
+      Paths_polysemy_methodology
+  hs-source-dirs:
+      src
+  ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints
+  build-depends:
+      base >=4.7 && <5
+    , polysemy
+    , polysemy-plugin
+    , polysemy-zoo
+  default-language: Haskell2010
diff --git a/src/Polysemy/Methodology.hs b/src/Polysemy/Methodology.hs
new file mode 100644
--- /dev/null
+++ b/src/Polysemy/Methodology.hs
@@ -0,0 +1,179 @@
+{-# LANGUAGE AllowAmbiguousTypes #-}
+{-# LANGUAGE BlockArguments #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE TypeOperators #-}
+{-# OPTIONS_GHC -fplugin=Polysemy.Plugin #-}
+module Polysemy.Methodology where
+
+import Polysemy
+import Polysemy.KVStore
+import Polysemy.Input
+import Polysemy.Output
+import Polysemy.Several
+
+-- | A `Methodology` generalises a semantic process from `b` to `c`.
+data Methodology b c m a where
+  Process :: b -> Methodology b c m c
+
+makeSem ''Methodology
+
+-- | Run a `Methodology` using a pure function.
+runMethodologyPure :: forall b c r a. (b -> c) -> Sem (Methodology b c ': r) a -> Sem r a 
+runMethodologyPure f = interpret \case
+  Process b -> return $ f b
+
+-- | Run a `Methodology' using a monadic function with effects in `r`.
+runMethodologySem :: forall b c r a. (b -> Sem r c) -> Sem (Methodology b c ': r) a -> Sem r a
+runMethodologySem f = interpret \case
+  Process b -> f b
+
+-- | Cut a `Methodology` into two pieces at a midpoint.
+cutMethodology :: forall b c d r a.
+                  Members '[ Methodology b c
+                           , Methodology c d] r
+               => Sem (Methodology b d ': r) a
+               -> Sem r a
+cutMethodology = interpret \case
+  Process b -> process @b @c b >>= process @c @d
+
+-- | Cut a `Methodology` into three pieces using two cuts.
+cutMethodology3 :: forall b c d e r a.
+                   Members '[ Methodology b c
+                            , Methodology c d
+                            , Methodology d e] r
+               => Sem (Methodology b e ': r) a
+               -> Sem r a
+cutMethodology3 = interpret \case
+  Process b -> process @b @c b >>= process @c @d >>= process @d @e
+
+-- | Divide a `Methodology` into two components using a `Methodology` that accepts a pair.`
+divideMethodology :: forall b c c' d r a.
+                     Members '[ Methodology b c
+                              , Methodology b c'
+                              , Methodology (c, c') d] r
+                  => Sem (Methodology b d ': r) a
+                  -> Sem r a
+divideMethodology = interpret \case
+  Process b -> do
+    c  <- process @b @c  b
+    c' <- process @b @c' b
+    process @(c, c') @d (c, c')
+
+-- | Decide between two `Methodology`s using a `Methodology` that computes an `Either`.
+decideMethodology :: forall b c c' d r a.
+                     Members '[ Methodology b (Either c c')
+                              , Methodology c  d
+                              , Methodology c' d
+                              ] r
+                  => Sem (Methodology b d ': r) a
+                  -> Sem r a
+decideMethodology = interpret \case
+  Process b -> do
+    k <- process @b @(Either c c') b
+    case k of
+      Left c   -> process @c  @d c
+      Right c' -> process @c' @d c'
+
+-- | Tee the output of a `Methodology`, introducing a new `Output` effect to be handled.
+teeMethodologyOutput :: forall b c r a.
+                  Members '[Output c, Methodology b c] r
+               => Sem r a
+               -> Sem r a
+teeMethodologyOutput = intercept \case
+  Process b -> do
+    k <- process @b @c b
+    output @c k
+    return k
+
+-- | Make a `Methodology` depend on an additional input, introducing a new `Input` effect to be handled.
+plugMethodologyInput :: forall b c d r a.
+                        Members '[Input b, Methodology (b, c) d] r
+                     => Sem (Methodology c d ': r) a
+                     -> Sem r a
+plugMethodologyInput = interpret \case
+  Process b -> do
+    k <- input @b
+    process @(b, c) @d (k, b)
+
+-- | Run a `Methodology` as a `KVStore`, using the input as a key and the output as the value.
+runMethodologyAsKVStore :: forall k v r a.
+                           Members '[KVStore k v] r
+                        => Sem (Methodology k (Maybe v) ': r) a
+                        -> Sem r a
+runMethodologyAsKVStore = interpret \case
+  Process k -> lookupKV k
+
+-- | Run a `Methodology` as a `KVStore`, with a default value for lookup failure.
+runMethodologyAsKVStoreWithDefault :: forall k v r a.
+                                      Members '[KVStore k v] r
+                                   => v
+                                   -> Sem (Methodology k v ': r) a
+                                   -> Sem r a
+runMethodologyAsKVStoreWithDefault d = interpret \case
+  Process k -> do
+    z <- lookupKV k
+    case z of 
+      Just a -> return a
+      Nothing -> return d
+
+-- | Decompose a `Methodology` into several components to be recombined. This is `cutMethodology` specialised to `HList`.
+decomposeMethodology :: forall b f c r a.
+                        Members ' [Methodology b (HList f)
+                                 , Methodology (HList f) c] r
+                     => Sem (Methodology b c ': r) a
+                     -> Sem r a
+decomposeMethodology = cutMethodology @b @(HList f) @c
+
+-- | Decompose a `Methodology` into several components over three sections with two cuts.
+decomposeMethodology3 :: forall b f g c r a.
+                         Members '[ Methodology b (HList f)
+                                  , Methodology (HList f) (HList g)
+                                  , Methodology (HList g) c] r
+                      => Sem (Methodology b c ': r) a
+                      -> Sem r a
+decomposeMethodology3 = cutMethodology3 @b @(HList f) @(HList g) @c
+
+-- | Factor a `Methodology` decomposed over an `HList` in the result by a `Methodology` to the first variable.
+separateMethodologyInitial :: forall b x xs r a.
+                              Members '[ Methodology b (HList xs)
+                                       , Methodology b x] r
+                           => Sem (Methodology b (HList (x ': xs)) ': r) a
+                           -> Sem r a
+separateMethodologyInitial = interpret \case
+  Process b -> do
+    k   <- process @b @x b
+    k'  <- process @b @(HList xs) b
+    return $ k ::: k'
+
+-- | Finish an `HList` separated `Methodology` by consuming it for no effect.
+endMethodologyInitial :: Sem (Methodology b (HList '[]) ': r) a
+                      -> Sem r a
+endMethodologyInitial = interpret \case
+  Process _ -> return HNil
+
+-- | Factor a `Methodology` decomposed over an `HList` in the source by a `Methodology` from the first variable. Assumes the result is a `Monoid`.
+separateMethodologyTerminal :: forall x xs c r a.
+                               (Monoid c,
+                               Members '[ Methodology (HList xs) c
+                                        , Methodology x c] r)
+                            => Sem (Methodology (HList (x ': xs)) c ': r) a
+                            -> Sem r a
+separateMethodologyTerminal = interpret \case
+  Process (b ::: bs) -> do
+    k   <- process @x @c b
+    k'  <- process @(HList xs) @c bs
+    return $ k <> k'
+
+-- | Finalise an `HList` separated `Methodology` in the source by returning the `Monoid` unit.
+endMethodologyTerminal :: Monoid c
+                       => Sem (Methodology (HList (x ': xs)) c ': r) a
+                       -> Sem r a
+endMethodologyTerminal = interpret \case
+  Process _ -> return mempty
