diff --git a/Data/Aeson/Diff/Generic/PathOptics.hs b/Data/Aeson/Diff/Generic/PathOptics.hs
new file mode 100644
--- /dev/null
+++ b/Data/Aeson/Diff/Generic/PathOptics.hs
@@ -0,0 +1,229 @@
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE DefaultSignatures #-}
+
+module Data.Aeson.Diff.Generic.PathOptics
+  ( -- * type synonyms
+    PathLens, PathTraversal,
+    -- * operations over path optics
+    overPath, replacePath, getPath, appendPath,
+    insertPath, deletePath, testPath,
+    KeyIndexed(..), Insertable(..), Appendable(..),
+    -- * creating and extracting path optics
+    withPath, withoutPath,
+    -- * pathOptics
+    ixP, traverseP, _1P, _2P, _3P, _4P, _5P,
+    _6P, _7P, _8P, _9P, _10P, _11P, _12P, _13P,
+    _14P, _15P, _16P, _17P, _18P, _19P, _LeftP, _RightP,
+    _JustP)
+
+where
+import Prelude()
+import Prelude.Compat
+import Data.Aeson
+import Data.Aeson.Diff
+import Data.Aeson.Pointer
+import Data.Monoid
+import Data.Functor.Compose
+import Control.Lens
+
+type PathTraversal s a = Traversal' (Path, s) (Path, a)
+type PathLens s a = Lens' (Path, s) (Path, a)
+
+class KeyIndexed s where
+  toKey :: Index s -> s -> Key
+
+class KeyIndexed a => Insertable a where
+  insertKey :: Index a -> (IxValue a) -> a -> a
+  deleteKey :: Index a -> a -> Maybe (IxValue a, a)
+
+class KeyIndexed a => Appendable a where
+  append :: (IxValue a) -> a -> a
+
+-- | Annotate an optic with a path.  The output optic will be the same
+-- optic, with a path annotation.  For example:
+--
+-- > withPath :: Path -> Lens' s a -> Lens' (Path, s) (Path, a)
+-- > withPath :: Path -> Traversal' s a -> Traversal' (Path, s) (Path, a)
+
+withPath ::  Functor f 
+         => Path -- ^ the path into the structure
+         -> ((a -> Compose f ((,) Path) a) -> (s -> Compose f ((,) Path) s))
+         -- ^ the input optic
+         -> (((Path, a) -> f (Path, a)) ->  (Path, s) -> f (Path, s))
+         -- ^ the output optic with path information
+withPath p2 orig f (p, v) =
+  fmap (over _1 (p <>)) $ getCompose $
+  orig (\a -> Compose $ f (p2,a)) v
+
+-- | remove the path from an optic annotated with path information.
+-- 
+-- > withoutPath . withPath ≡ id
+--
+-- The output optic will be the same
+-- optic, without the path annotation.  For example:
+--
+-- > withoutPath ::  Lens' (Path, s) (Path, a) -> Lens' s a
+-- > withoutPath :: Traversal' (Path, s) (Path, a) -> Traversal' s a
+withoutPath :: Functor f
+            => (((Path, a) -> f (Path, a)) -> ((Path, s) -> f (Path, s)))
+            -- ^ input optic
+            -> ((a -> f a) -> (s -> f s))
+            -- ^ output optic without path information
+withoutPath l f v = snd <$> l (traverseOf _2 f) (rootPath, v)
+
+-- | the root path
+rootPath :: Path
+rootPath = []
+
+-- | Modify the value(s) at the traversal, and return a patch which
+-- represents those (replace) operations.
+overPath :: ToJSON a => PathTraversal s a -> (a -> a) -> s -> (Patch, s)
+overPath lns f s =
+  snd <$>
+  lns (\(p2, a) ->
+         let a2 = f a in
+           ( Patch [Rep (Pointer p2) (toJSON a2)]
+           , (p2, a2)))
+    (rootPath, s)
+    
+-- | Replace the value at the traversal, and return a patch with
+--  the replace operations.
+replacePath :: ToJSON a => PathTraversal s a -> a -> s -> (Patch, s)
+replacePath lns = overPath lns . const
+
+-- | Return the values and pointers pointed to by the traversal (if any)
+getPath :: PathTraversal s a -> s -> [(Pointer, a)]
+getPath lns v = over _1 Pointer <$> (rootPath, v) ^.. lns
+
+-- | Append a value to the structure pointed by the lens.  Return a
+-- patch which the append operations)
+appendPath :: (ToJSON (IxValue a), Appendable a)
+           => IxValue a -> PathTraversal s a -> s -> (Patch, s)
+appendPath v lns s =
+  snd <$>
+  lns (\(p2, a) ->
+         let a2 = append v a
+         in ( Patch [Add (Pointer $ p2 ++ [OKey "-"]) (toJSON v)]
+            , (p2, a2)))
+    (rootPath, s)
+
+-- | Insert a value at the given key, and return a patch with the
+-- insert operations
+insertPath :: (ToJSON (IxValue a), Insertable a)
+           => Index a -> IxValue a -> PathTraversal s a -> s
+           -> (Patch, s)
+insertPath key v lns s =
+  fmap snd $
+  lns (\(p2, a) ->
+         let a2 = insertKey key v a
+         in ( Patch [Add (Pointer $ p2 <>
+                           [toKey key a]) (toJSON v)]
+            , (p2, a2)))
+    (rootPath, s)  
+
+-- | Delete a value at the given key if present, and return a patch
+-- with the delete operations.
+deletePath :: (ToJSON (IxValue a), Insertable a)
+           => Index a -> PathTraversal s a -> s
+           -> (Patch, s)
+deletePath key lns s =
+  fmap snd $
+  lns (\(p2, a) ->
+         case deleteKey key a of
+           Nothing -> (Patch [], (p2, a))
+           Just (_, a2) ->
+             ( Patch [Rem (Pointer $ p2 <> [toKey key a])]
+             , (p2, a2)))
+    (rootPath, s)  
+
+-- | Create a patch that tests if the value at the pointer equals the
+-- current value.  Returns the data unmodified.
+testPath :: ToJSON a => PathTraversal s a -> s -> (Patch, s)
+testPath lns s =
+  ( Patch $ (\(ptr, v) -> Tst ptr (toJSON v)) <$> getPath lns s
+  , s)
+
+-- | `ix` from lens annotated with a path.  Provides a simple
+-- Traversal lets you traverse the value at a given key in a Map or
+-- element at an ordinal position in a list or Seq.  Includes the path
+-- to the element.
+ixP :: (KeyIndexed s, Ixed s) =>
+       Index s -> Traversal' (Path, s) (Path, IxValue s)
+ixP i f s = (withPath [toKey i (snd s)] (ix i)) f s
+
+traverseP :: (a ~ Index (s a), TraversableWithIndex a s, 
+              KeyIndexed (s a))
+          => Traversal' (Path, (s a)) (Path, a)
+traverseP f (p, s) =
+  fmap (over _1 (p <>)) $ getCompose $
+  itraverse (\i a -> Compose (f ([toKey i s], a))) s
+
+_1P :: Field1 s s a a  => PathLens s a
+_1P = withPath [AKey 0] _1
+
+_2P :: Field2 s s a a  => PathLens s a
+_2P = withPath [AKey 1] _2
+
+_3P :: Field3 s s a a  => PathLens s a
+_3P = withPath [AKey 2] _3
+
+_4P :: Field4 s s a a  => PathLens s a
+_4P = withPath [AKey 3] _4
+
+_5P :: Field5 s s a a  => PathLens s a
+_5P = withPath [AKey 4] _5
+
+_6P :: Field6 s s a a  => PathLens s a
+_6P = withPath [AKey 5] _6
+
+_7P :: Field7 s s a a  => PathLens s a
+_7P = withPath [AKey 6] _7
+
+_8P :: Field8 s s a a  => PathLens s a
+_8P = withPath [AKey 7] _8
+
+_9P :: Field9 s s a a  => PathLens s a
+_9P = withPath [AKey 8] _9
+
+_10P :: Field10 s s a a  => PathLens s a
+_10P = withPath [AKey 9] _10
+
+_11P :: Field11 s s a a  => PathLens s a
+_11P = withPath [AKey 10] _11
+
+_12P :: Field12 s s a a  => PathLens s a
+_12P = withPath [AKey 11] _12
+
+_13P :: Field13 s s a a  => PathLens s a
+_13P = withPath [AKey 12] _13
+
+_14P :: Field14 s s a a  => PathLens s a
+_14P = withPath [AKey 13] _14
+
+_15P :: Field15 s s a a  => PathLens s a
+_15P = withPath [AKey 14] _15
+
+_16P :: Field16 s s a a  => PathLens s a
+_16P = withPath [AKey 15] _16
+
+_17P :: Field17 s s a a  => PathLens s a
+_17P = withPath [AKey 16] _17
+
+_18P :: Field18 s s a a  => PathLens s a
+_18P = withPath [AKey 17] _18
+
+_19P :: Field19 s s a a  => PathLens s a
+_19P = withPath [AKey 18] _19
+
+_LeftP :: Traversal' (Path, Either a b) (Path, a)
+_LeftP = withPath [OKey "Left"] _Left
+
+_RightP :: Traversal' (Path, Either a b) (Path, b)
+_RightP = withPath [OKey "Right"] _Right
+
+_JustP :: Traversal' (Path, Maybe a) (Path, a)
+_JustP = withPath [] _Just
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -18,8 +18,8 @@
 
 The aeson library uses GHC.Generics or template haskell to define a
 default json encoding for algebraic datatypes. The aeson-diff-generic
-can generate code, using options given to aeson, to interpret a json
-patch as a Doc patch.
+can generate code, using the same options as given to aeson, to
+interpret a json patch as a Doc patch.
 
 # Example
 
@@ -72,7 +72,7 @@
   fieldLens _ _ = Error "Invalid Path"
 ```
 
-Since this is the default implementation, so we can do simply:
+Since this is the default implementation, we can do simply:
 
 ```haskell
 instance FieldLens Pet
diff --git a/aeson-diff-generic.cabal b/aeson-diff-generic.cabal
--- a/aeson-diff-generic.cabal
+++ b/aeson-diff-generic.cabal
@@ -1,5 +1,5 @@
 Name:		aeson-diff-generic
-Version: 	0.0.2
+Version: 	0.0.3
 Synopsis:	Apply a json-patch to any haskell datatype.
 Category: 	JSON, Web
 Copyright: 	Kristof Bastiaensen (2018)
@@ -47,7 +47,9 @@
                  time >= 1.1.1.4,
                  unordered-containers >= 0.2.5.0 && < 0.3,
                  uuid-types >= 1.0.3 && <1.1,
-                 vector >= 0.8
+                 vector >= 0.8,
+                 lens >= 4.16 && < 4.17
+                        
 
   if !impl(ghc >= 8.0)
     -- `Data.Semigroup` and `Control.Monad.Fail` and `Control.Monad.IO.Class` are available in base only since GHC 8.0 / base 4.9
@@ -64,6 +66,7 @@
   Exposed-Modules: Data.Aeson.Diff.Generic
                    Data.Aeson.Diff.Generic.TH
                    Data.Aeson.Diff.Generic.Instances
+                   Data.Aeson.Diff.Generic.PathOptics
   Other-Modules: Data.Aeson.Diff.Generic.Types
                  
                  
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,8 @@
 # aeson-diff-generic 0.0.2
 
+*April 17, 2018*
+   - Implement path optics.
+
 *April 2, 2018*
 
    - Better documentation.
