diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,5 @@
+# Revision history for changeset
+
+## 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,20 @@
+Copyright (c) 2023 Manuel Bärenz
+
+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/changeset-containers.cabal b/changeset-containers.cabal
new file mode 100644
--- /dev/null
+++ b/changeset-containers.cabal
@@ -0,0 +1,93 @@
+cabal-version: 3.0
+name: changeset-containers
+-- PVP summary:     +-+------- breaking API changes
+--                  | | +----- non-breaking API additions
+--                  | | | +--- code changes with no API change
+version: 0.1.0.0
+synopsis: Stateful monad transformer based on monoidal actions
+description:
+  A general state monad transformer with separate types for the state and the possible changes.
+  It can be defined for any monoid action.
+  The monoid represents "changes", "updates", "edits" or "diffs" on the state.
+  This package exposes typical changes for @containers@ such as maps, sequences, and sets.
+  To change individual elements of a container, have a look at the indexed changes in [@changeset-lens@](hackage.haskell.org/package/changeset-lens).
+
+license: MIT
+license-file: LICENSE
+author: Manuel Bärenz
+maintainer: programming@manuelbaerenz.de
+copyright: MIT
+category: Control
+build-type: Simple
+extra-doc-files: CHANGELOG.md
+
+source-repository head
+  type: git
+  location: https://github.com/turion/changeset
+
+flag dev
+  description: Enable warnings as errors. Active on ci.
+  default: False
+  manual: True
+
+common opts
+  ghc-options:
+    -Wall
+
+  if flag(dev)
+    ghc-options:
+      -Werror
+  default-extensions:
+    BangPatterns
+    DeriveFunctor
+    FlexibleInstances
+    FunctionalDependencies
+    GADTs
+    KindSignatures
+    MultiParamTypeClasses
+    NamedFieldPuns
+    RankNTypes
+    ScopedTypeVariables
+    TupleSections
+    TypeOperators
+
+library
+  import: opts
+  exposed-modules:
+    Data.Monoid.RightAction.IntMap
+    Data.Monoid.RightAction.IntSet
+    Data.Monoid.RightAction.Map
+    Data.Monoid.RightAction.Sequence
+    Data.Monoid.RightAction.Set
+
+  build-depends:
+    base >=4.12 && <4.22,
+    changeset ==0.1.0.0,
+    containers >=0.6 && <0.8,
+    monoid-extras ^>=0.6,
+
+  hs-source-dirs: src
+  default-language: Haskell2010
+
+test-suite changeset-containers-test
+  import: opts
+  default-language: Haskell2010
+  type: exitcode-stdio-1.0
+  hs-source-dirs: test
+  main-is: Main.hs
+  build-depends:
+    base,
+    changeset,
+    changeset-containers,
+    containers,
+    falsify ^>=0.2,
+    monoid-extras,
+    tasty ^>=1.4.2,
+    tasty-hunit ^>=0.10.2,
+
+  other-modules:
+    IntMap
+    IntSet
+    Map
+    Sequence
+    Set
diff --git a/src/Data/Monoid/RightAction/IntMap.hs b/src/Data/Monoid/RightAction/IntMap.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Monoid/RightAction/IntMap.hs
@@ -0,0 +1,20 @@
+module Data.Monoid.RightAction.IntMap where
+
+-- containers
+import Data.IntMap
+
+-- changeset
+import Data.Monoid.RightAction (RightAction (..))
+
+{- | Insert or delete an element in an 'IntMap'.
+
+To change an element in an 'IntMap', see the indexed changes in [@changeset-lens@](hackage.haskell.org/package/changeset-lens).
+-}
+data IntMapChange a
+  = Insert Int a
+  | Delete Int
+  deriving (Show, Read, Eq, Ord, Functor)
+
+instance RightAction (IntMapChange a) (IntMap a) where
+  actRight m (Insert k a) = insert k a m
+  actRight m (Delete k) = delete k m
diff --git a/src/Data/Monoid/RightAction/IntSet.hs b/src/Data/Monoid/RightAction/IntSet.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Monoid/RightAction/IntSet.hs
@@ -0,0 +1,17 @@
+module Data.Monoid.RightAction.IntSet where
+
+-- containers
+import Data.IntSet
+
+-- changeset
+import Data.Monoid.RightAction (RightAction (..))
+
+-- | Insert or delete an element in an 'IntSet'.
+data IntSetChange
+  = Insert Int
+  | Delete Int
+  deriving (Show, Read, Eq, Ord)
+
+instance RightAction IntSetChange IntSet where
+  actRight s (Insert k) = insert k s
+  actRight s (Delete k) = delete k s
diff --git a/src/Data/Monoid/RightAction/Map.hs b/src/Data/Monoid/RightAction/Map.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Monoid/RightAction/Map.hs
@@ -0,0 +1,20 @@
+module Data.Monoid.RightAction.Map where
+
+-- containers
+import Data.Map
+
+-- changeset
+import Data.Monoid.RightAction (RightAction (..))
+
+{- | Insert or delete an element in a 'Map'.
+
+To change an element in an 'Map', see the indexed changes in [@changeset-lens@](hackage.haskell.org/package/changeset-lens).
+-}
+data MapChange k a
+  = Insert k a
+  | Delete k
+  deriving (Show, Read, Eq, Ord, Functor)
+
+instance (Ord k) => RightAction (MapChange k a) (Map k a) where
+  actRight m (Insert k a) = insert k a m
+  actRight m (Delete k) = delete k m
diff --git a/src/Data/Monoid/RightAction/Sequence.hs b/src/Data/Monoid/RightAction/Sequence.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Monoid/RightAction/Sequence.hs
@@ -0,0 +1,29 @@
+module Data.Monoid.RightAction.Sequence where
+
+import Data.Monoid.RightAction (RightAction (..))
+import Data.Sequence
+
+{- | Insert or delete an element at either end of a 'Seq'.
+
+To change an element in a 'Seq', see the indexed changes in [@changeset-lens@](hackage.haskell.org/package/changeset-lens).
+-}
+data SeqChange a
+  = -- | Prepend an element
+    Cons a
+  | -- | Append an element
+    Snoc a
+  | -- | Drop an element from the left
+    Uncons
+  | -- | Drop an element from the right
+    Unsnoc
+  deriving (Show, Read, Eq, Ord, Functor)
+
+instance RightAction (SeqChange a) (Seq a) where
+  actRight s (Cons a) = a <| s
+  actRight s (Snoc a) = s |> a
+  actRight s Uncons = case viewl s of
+    EmptyL -> empty
+    _ :< as' -> as'
+  actRight s Unsnoc = case viewr s of
+    EmptyR -> empty
+    as' :> _ -> as'
diff --git a/src/Data/Monoid/RightAction/Set.hs b/src/Data/Monoid/RightAction/Set.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Monoid/RightAction/Set.hs
@@ -0,0 +1,17 @@
+module Data.Monoid.RightAction.Set where
+
+-- containers
+import Data.Set
+
+-- changeset
+import Data.Monoid.RightAction (RightAction (..))
+
+-- | Insert or delete an element in a 'Set'.
+data SetChange k
+  = Insert k
+  | Delete k
+  deriving (Show, Read, Eq, Ord)
+
+instance (Ord k) => RightAction (SetChange k) (Set k) where
+  actRight s (Insert k) = insert k s
+  actRight s (Delete k) = delete k s
diff --git a/test/IntMap.hs b/test/IntMap.hs
new file mode 100644
--- /dev/null
+++ b/test/IntMap.hs
@@ -0,0 +1,41 @@
+module IntMap where
+
+-- base
+import Prelude hiding (Foldable (..))
+
+-- containers
+import Data.IntMap.Strict (singleton)
+
+-- tasty
+import Test.Tasty
+
+-- tasty-hunit
+import Test.Tasty.HUnit (testCase, (@?=))
+
+-- changeset
+import Control.Monad.Changeset.Class
+import Control.Monad.Trans.Changeset
+
+-- changeset-containers
+import Data.Monoid.RightAction.IntMap
+
+tests :: TestTree
+tests =
+  testGroup
+    "IntMap"
+    [ testCase "Can insert" $
+        runChangeset (changeSingle (Insert 0 True :: IntMapChange Bool)) mempty @?= ((), singleton 0 True)
+    , testCase "Can read after insert" $
+        let action = do
+              changeSingle (Insert 0 True :: IntMapChange Bool)
+              m <- current
+              changeSingle $ Insert 0 False
+              return m
+         in runChangeset action mempty @?= (singleton 0 True, singleton 0 False)
+    , testCase "Can delete after insert" $
+        let action = do
+              changeSingle (Insert 0 True :: IntMapChange Bool)
+              changeSingle $ Insert 1 False
+              changeSingle $ Delete 0
+         in execChangeset action mempty @?= singleton 1 False
+    ]
diff --git a/test/IntSet.hs b/test/IntSet.hs
new file mode 100644
--- /dev/null
+++ b/test/IntSet.hs
@@ -0,0 +1,41 @@
+module IntSet where
+
+-- base
+import Prelude hiding (Foldable (..))
+
+-- containers
+import Data.IntSet (fromList, singleton)
+
+-- tasty
+import Test.Tasty
+
+-- tasty-hunit
+import Test.Tasty.HUnit (testCase, (@?=))
+
+-- changeset
+import Control.Monad.Changeset.Class
+import Control.Monad.Trans.Changeset
+
+-- changeset-containers
+import Data.Monoid.RightAction.IntSet
+
+tests :: TestTree
+tests =
+  testGroup
+    "IntSet"
+    [ testCase "Can insert" $
+        runChangeset (changeSingle (Insert 0)) mempty @?= ((), singleton 0)
+    , testCase "Can read after insert" $
+        let action = do
+              changeSingle $ Insert 0
+              m <- current
+              changeSingle $ Insert 1
+              return m
+         in runChangeset action mempty @?= (singleton 0, fromList [0, 1])
+    , testCase "Can delete after insert" $
+        let action = do
+              changeSingle $ Insert 0
+              changeSingle $ Insert 1
+              changeSingle $ Delete 0
+         in execChangeset action mempty @?= singleton 1
+    ]
diff --git a/test/Main.hs b/test/Main.hs
new file mode 100644
--- /dev/null
+++ b/test/Main.hs
@@ -0,0 +1,26 @@
+module Main (main) where
+
+-- base
+import Prelude hiding (Foldable (..))
+
+-- tasty
+import Test.Tasty
+
+-- changeset-containers-test
+import qualified IntMap
+import qualified IntSet
+import qualified Map
+import qualified Sequence
+import qualified Set
+
+main :: IO ()
+main =
+  defaultMain $
+    testGroup
+      "changeset-containers"
+      [ IntMap.tests
+      , Map.tests
+      , IntSet.tests
+      , Set.tests
+      , Sequence.tests
+      ]
diff --git a/test/Map.hs b/test/Map.hs
new file mode 100644
--- /dev/null
+++ b/test/Map.hs
@@ -0,0 +1,41 @@
+module Map where
+
+-- base
+import Prelude hiding (Foldable (..))
+
+-- containers
+import Data.Map.Strict (singleton)
+
+-- tasty
+import Test.Tasty
+
+-- tasty-hunit
+import Test.Tasty.HUnit (testCase, (@?=))
+
+-- changeset
+import Control.Monad.Changeset.Class
+import Control.Monad.Trans.Changeset
+
+-- changeset-containers
+import Data.Monoid.RightAction.Map
+
+tests :: TestTree
+tests =
+  testGroup
+    "Map"
+    [ testCase "Can insert" $
+        runChangeset (changeSingle (Insert "0" True :: MapChange String Bool)) mempty @?= ((), singleton "0" True)
+    , testCase "Can read after insert" $
+        let action = do
+              changeSingle (Insert "0" True :: MapChange String Bool)
+              m <- current
+              changeSingle $ Insert "0" False
+              return m
+         in runChangeset action mempty @?= (singleton "0" True, singleton "0" False)
+    , testCase "Can delete after insert" $
+        let action = do
+              changeSingle (Insert "0" True :: MapChange String Bool)
+              changeSingle $ Insert "1" False
+              changeSingle $ Delete "0"
+         in execChangeset action mempty @?= singleton "1" False
+    ]
diff --git a/test/Sequence.hs b/test/Sequence.hs
new file mode 100644
--- /dev/null
+++ b/test/Sequence.hs
@@ -0,0 +1,45 @@
+module Sequence where
+
+-- base
+import Prelude hiding (Foldable (..))
+
+-- containers
+import Data.Sequence (fromList, singleton)
+
+-- tasty
+import Test.Tasty
+
+-- tasty-hunit
+import Test.Tasty.HUnit (testCase, (@?=))
+
+-- changeset
+import Control.Monad.Changeset.Class
+import Control.Monad.Trans.Changeset (changeSingle, execChangeset, runChangeset)
+
+-- changeset-containers
+import Data.Monoid.RightAction.Sequence
+
+tests :: TestTree
+tests =
+  testGroup
+    "Map"
+    [ testCase "Can insert" $
+        runChangeset (changeSingle (Cons 0 :: SeqChange Int)) mempty @?= ((), singleton (0 :: Int))
+    , testCase "Can read after insert" $
+        let action = do
+              changeSingle (Cons 1 :: SeqChange Int)
+              m <- current
+              changeSingle $ Cons 0
+              return m
+         in runChangeset action mempty @?= (singleton (1 :: Int), fromList [0, 1])
+    , testCase "Can delete after insert" $
+        let action = do
+              changeSingle (Cons 1 :: SeqChange Int)
+              m <- current
+              changeSingle $ Cons 0
+              changeSingle $ Snoc 3
+              changeSingle $ Snoc 99
+              changeSingle Unsnoc
+              return m
+         in execChangeset action (singleton (2 :: Int)) @?= fromList [0, 1, 2, 3]
+    ]
diff --git a/test/Set.hs b/test/Set.hs
new file mode 100644
--- /dev/null
+++ b/test/Set.hs
@@ -0,0 +1,41 @@
+module Set where
+
+-- base
+import Prelude hiding (Foldable (..))
+
+-- containers
+import Data.Set (fromList, singleton)
+
+-- tasty
+import Test.Tasty
+
+-- tasty-hunit
+import Test.Tasty.HUnit (testCase, (@?=))
+
+-- changeset
+import Control.Monad.Changeset.Class
+import Control.Monad.Trans.Changeset
+
+-- changeset-containers
+import Data.Monoid.RightAction.Set
+
+tests :: TestTree
+tests =
+  testGroup
+    "Set"
+    [ testCase "Can insert" $
+        runChangeset (changeSingle (Insert True)) mempty @?= ((), singleton True)
+    , testCase "Can read after insert" $
+        let action = do
+              changeSingle $ Insert True
+              m <- current
+              changeSingle $ Insert False
+              return m
+         in runChangeset action mempty @?= (singleton True, fromList [True, False])
+    , testCase "Can delete after insert" $
+        let action = do
+              changeSingle $ Insert True
+              changeSingle $ Insert False
+              changeSingle $ Delete True
+         in execChangeset action mempty @?= singleton False
+    ]
