diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,5 @@
+# Revision history for lens-witherable
+
+## 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) 2021-2022 Carl Howells
+
+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/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,125 @@
+Integrate witherable and lens.
+
+Based on the ideas from https://chrispenner.ca/posts/witherable-optics
+but with a more combinator-based approach to restore full
+compatibility with lens combinators like `set` and
+`over`. Additionally, this approach gets rid of `Maybe` wrappers in
+results that are always `Just`.
+
+This library is based on a variant of `Traversal`s with the type
+`forall f. Applicative f => ((a-> Withering f b) -> s -> f t)`. Note
+that this type is absolutely not an optic due to the `Withering`
+wrapper, but it's really close. It composes on either side with lenses
+and traversals with `(.)` and that composition maintains the filtering
+type. No type alias is provided for this type because type aliases
+containing a `forall` cause problems with subsumption.
+
+The core tool for creating values with these types is
+
+```haskell
+withered
+    :: (Applicative f, Witherable t)
+    => (a -> Withering f b) -> t a -> f (t b)
+```
+
+One tool for working with the types is
+
+```haskell
+mapMaybeOf
+    :: ((a -> Withering Identity b) -> s -> Identity t)
+    -> (a -> Maybe b) -> s -> t
+```
+
+These can be used like such
+
+```haskell
+ghci> let z = M.fromList [('a', ["1", "2", "3"]), ('b', ["4", "Alpaca", "6"])]
+
+ghci> z & mapMaybeOf (traverse . withered) (readMaybe :: String -> Maybe Int)
+fromList [('a',[1,2,3]),('b',[4,6])]
+
+ghci> z & mapMaybeOf (withered . traverse) (readMaybe :: String -> Maybe Int)
+fromList [('a',[1,2,3])]
+```
+
+As those results demonstrate, the location of the `withered`
+combinator controls where the pruning stops. It functions as a kind of
+catch combinator in this sense.
+
+Of course, `filterOf` is provided as well
+
+```haskell
+filterOf
+    :: ((a -> Withering Identity a) -> s -> Identity s)
+    -> (a -> Bool) -> s -> s
+```
+
+```haskell
+ghci> [[1, 2, 3], [4, 5, 6]] & filterOf (traverse . withered) even
+[[2],[4,6]]
+```
+
+Traversals that might fail can be combined with the `decayed`
+combinator to cause them to completely remove a value that they
+otherwise would ignore
+
+```haskell
+ghci> [('a', Right 1), ('b', Left 2), ('c', Left 3)] & filterOf (withered . _2 . _Left) even
+[('a',Right 1),('b',Left 2)]
+
+ghci> [('a', Right 1), ('b', Left 2), ('c', Left 3)] & filterOf (withered . _2 . (_Left `failing` decayed)) even
+[('b',Left 2)]
+```
+
+In the first case, the `'a'` value is returned because the filter
+doesn't find any non-even values under the `Right` value when it's
+looking under the `_Left` prism. In the second case, the failure of
+the `_Left` prism results in falling back on `decayed` to remove the
+branch.
+
+Compatibility with normal lens operations can be restored with
+`unwithered`. This can be especially useful when combined with
+`guarded`, which acts somewhat like lens's `filtered` but it prunes
+the structure up to the next `withered`.
+
+```haskell
+unwithered :: Functor f => (a -> f b) -> a -> Withering f b
+
+guarded
+    :: Applicative f
+    => (a -> Bool) -> (a -> Withering f b)
+    -> a -> Withering f b
+```
+
+```haskell
+ghci> [[1,2],[],[1,3,9],[],[],[6,4,7],[]] & withered . guarded (not . null) . unwithered . traverse +~ 10
+[[11,12],[11,13,19],[16,14,17]]
+```
+
+Note that pruning out the empty lists happens in-line with the
+modification of the other elements. An additional combinator is
+provided combining `withered` and `unwithered` for when you want to
+change the pruning depth
+
+```haskell
+rewithered
+    :: (Applicative f, Witherable t)
+    => (a -> Withering f b) -> t a -> Withering f (t b)
+```
+
+```haskell
+ghci> [[1,2],[],[1,3,9],[],[],[6,4,7],[]] & (withered . guarded (not . null) . rewithered . guarded even . unwithered) +~ 10
+[[12],[],[16,14]]
+```
+
+In that example, the first `guarded` strips out null lists in the
+input. The `rewithered` descends into the sublists and sets each of
+them as the catch point for later pruning. The second `guarded` strips
+out all non-even entries in each list. The `unwithered` restores
+compatibility with lens combinators like `(+~)`, which is used to
+modify every remaining focused value. Note the presence of the `[]` in
+the output list. The `guarded` combinator violates the lens laws in
+the same manner as `filtered`, where behavior might change with
+refactoring. This doesn't mean it's dangerous to use, merely that you
+have to pay attention to changes in behavior when refactoring chains
+involving it.
diff --git a/lens-witherable.cabal b/lens-witherable.cabal
new file mode 100644
--- /dev/null
+++ b/lens-witherable.cabal
@@ -0,0 +1,27 @@
+cabal-version:        2.4
+name:                 lens-witherable
+version:              0.1.0.0
+synopsis:             lens-compatible tools for working with witherable
+copyright:            Copyright (C) 2021-2022 Carl Howells
+license:              MIT
+license-file:         LICENSE
+author:               Carl Howells
+maintainer:           chowells79@gmail.com
+category:             Data
+homepage:             https://github.com/chowells79/lens-witherable
+bug-reports:          https://github.com/chowells79/lens-witherable/issues
+description:
+            Provides tools for integrating the witherable package with lens
+            combinators. See README.md for more details.
+
+extra-source-files:   CHANGELOG.md,
+                      README.md
+
+library
+    default-language: Haskell2010
+    exposed-modules:  Witherable.Lens,
+                      Witherable.Lens.Withering
+
+    build-depends:    base >=4.9 && <5,
+                      witherable >= 0.4 && < 0.5
+    hs-source-dirs:   src
diff --git a/src/Witherable/Lens.hs b/src/Witherable/Lens.hs
new file mode 100644
--- /dev/null
+++ b/src/Witherable/Lens.hs
@@ -0,0 +1,102 @@
+{-|
+Module      : Witherable.Lens
+Description : Tools for using the Witherable interface with lens
+Copyright   : (c) Carl Howells, 2021
+License     : MIT
+Maintainer  : chowells79@gmail.com
+
+-}
+module Witherable.Lens where
+
+
+import Data.Functor.Identity (Identity(runIdentity))
+
+import Witherable (Witherable(wither))
+
+import Witherable.Lens.Withering
+
+
+-- | A variant on 'traverse' that allows the targets to be filtered
+-- out of the 'Witherable' structure. Note that this introduces a
+-- change in types down the lens composition chain, which means that
+-- it is not a a valid optic at all.  The use of 'Withering' in the
+-- changed type also means that standard lens combinators don't fit
+--
+-- To address these issues, you can use 'unwithered' to strip the
+-- 'Withering' type back out. This allows the composed optic to be
+-- used with standard combinators from lens. In addition, the sequence
+-- @'withered' . 'unwithered'@ will act like a type-restricted version
+-- of 'traverse' for all lawful instances of 'Witherable'.
+--
+-- In some sense, this is a @catch@-like combinator. This marks the
+-- point where removing elements stops propagating and actually
+-- modifies the structure being focused.
+withered
+    :: (Applicative f, Witherable t)
+    => (a -> Withering f b) -> t a -> f (t b)
+withered f = wither (runWithering . f)
+
+-- | Restore types in a lens composition chain that has had
+-- 'Withering' introduced. Makes no changes to what elements are
+-- focused on.
+unwithered :: Functor f => (a -> f b) -> a -> Withering f b
+unwithered f s = Withering (fmap Just (f s))
+
+-- | A variant of withered for when you're already working in a
+-- Withering chain and want to change what structure elements are
+-- being removed from.
+--
+-- @'rewithered' = 'unwithered' . 'withered'@
+rewithered
+    :: (Applicative f, Witherable t)
+    => (a -> Withering f b) -> t a -> Withering f (t b)
+rewithered = unwithered . withered
+
+-- | The trivial optic in a Withering chain that removes everything.
+--
+-- The arguments are unused.
+decayed :: Applicative f => pafb -> s -> Withering f t
+decayed _ _ = empty
+
+-- | Remove elements from the current 'Withering' context if they
+-- don't match the predicate. This is similar in concept to @filtered@
+-- from lens. The major that instead of merely removing non-matching
+-- targets from the traversal, it removes those targets (and their
+-- parents up to the next 'withered' combinator) from the data
+-- structure entirely.
+guarded
+    :: Applicative f
+    => (a -> Bool) -> (a -> Withering f b)
+    -> a -> Withering f b
+guarded p f a
+    | p a = f a
+    | otherwise = empty
+
+
+-- | Remove elements matched by a specific 'Withering' context if they
+-- don't match a predicate.
+filterOf
+    :: ((a -> Withering Identity a) -> s -> Identity s)
+    -> (a -> Bool) -> s -> s
+filterOf w p = runIdentity . w (guarding p)
+  where
+    guarding p a
+        | p a = pure a
+        | otherwise = empty
+infix 2 `filterOf`
+
+-- | Transform and filter elements matched by a specific 'Withering'
+-- context, a la 'Data.Maybe.mapMaybe'.
+mapMaybeOf
+    :: ((a -> Withering Identity b) -> s -> Identity t)
+    -> (a -> Maybe b) -> s -> t
+mapMaybeOf w p = runIdentity . w (Withering . pure . p)
+infix 2 `mapMaybeOf`
+
+-- | Transform and effectfully filter elements matched by a specific
+-- 'Withering' context, a la 'wither'.
+witherOf
+    :: ((a -> Withering f b) -> s -> f t)
+    -> (a -> f (Maybe b)) -> s -> f t
+witherOf w p = w (Withering . p)
+infix 2 `witherOf`
diff --git a/src/Witherable/Lens/Withering.hs b/src/Witherable/Lens/Withering.hs
new file mode 100644
--- /dev/null
+++ b/src/Witherable/Lens/Withering.hs
@@ -0,0 +1,41 @@
+{-# LANGUAGE StandaloneDeriving, UndecidableInstances #-}
+
+{-|
+Module      : Witherable.Lens.Withering
+Description : MaybeT replacement type
+Copyright   : (c) Carl Howells, 2021
+License     : MIT
+Maintainer  : chowells79@gmail.com
+
+This module contains a replacement for @MaybeT@ intended for use in
+lens-like contexts. The important difference from @MaybeT@ is that
+'Withering' drops the short-circuiting behavior that requires 'Monad'
+constraints.
+-}
+module Witherable.Lens.Withering (Withering(..), empty) where
+
+import Control.Applicative (liftA2)
+
+-- | A replacement for @MaybeT@ with no short-circuiting
+-- behavior. This allows its 'Applicative' instance to not require @f@
+-- to be an instance of 'Monad'.
+newtype Withering f a = Withering { runWithering :: f (Maybe a) }
+
+deriving instance Eq (f (Maybe a)) => Eq (Withering f a)
+deriving instance Ord (f (Maybe a)) => Ord (Withering f a)
+deriving instance Show (f (Maybe a)) => Show (Withering f a)
+
+instance Functor f => Functor (Withering f) where
+    fmap f (Withering x) = Withering (fmap (fmap f) x)
+
+instance Applicative f => Applicative (Withering f) where
+    pure x = Withering (pure (Just x))
+    Withering f <*> Withering x = Withering (liftA2 (<*>) f x)
+
+-- | A 'Withering' value wrapping 'Nothing'. This cannot be part of an
+-- 'Control.Applicative.Alternative' instance for 'Withering' because
+-- it needs to be available with only an 'Applicative' constraint on
+-- @f@, and any lawful 'Control.Applicative.Alternative' instance
+-- would require more structure than that.
+empty :: Applicative f => Withering f a
+empty = Withering (pure Nothing)
