diff --git a/Data/Aeson/Lens.hs b/Data/Aeson/Lens.hs
new file mode 100644
--- /dev/null
+++ b/Data/Aeson/Lens.hs
@@ -0,0 +1,102 @@
+{-# LANGUAGE FlexibleContexts  #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ViewPatterns      #-}
+
+module Data.Aeson.Lens (
+  ValueIx(..),
+  valueAt,
+  arr, obj,
+  ) where
+
+import           Control.Applicative
+import           Control.Lens
+import           Data.Aeson
+import qualified Data.HashMap.Strict as HMS
+import           Data.Maybe
+import           Data.Monoid
+import qualified Data.Text           as T
+import qualified Data.Vector         as V
+
+-- $setup
+-- >>> import Data.Maybe
+-- >>> import qualified Data.ByteString.Lazy.Char8 as L
+-- >>> import Data.Text ()
+-- >>> let v = decode (L.pack "{\"foo\": {\"baz\": 3.14}, \"bar\": [123, false, null]}") :: Maybe Value
+
+data ValueIx = ArrIx Int | ObjIx T.Text
+
+-- | Lens of Value
+valueAt :: (ToJSON v, FromJSON v)
+           => ValueIx
+           -> SimpleIndexedLens ValueIx (Maybe Value) (Maybe v)
+valueAt k = index $ \f (fmap toJSON -> v) -> (go k v) <$> f k (lu k v) where
+  go (ObjIx ix) (Just (Object o)) Nothing  = Just $ Object $ HMS.delete ix o
+  go (ObjIx ix) (Just (Object o)) (Just v) = Just $ Object $ HMS.insert ix (toJSON v) o
+  go (ObjIx ix) _                 (Just v) = Just $ Object $ HMS.fromList [(ix, toJSON v)]
+  go (ArrIx ix) (Just (Array  a)) Nothing  = Just $ Array $ updateV ix Null a
+  go (ArrIx ix) (Just (Array  a)) (Just v) = Just $ Array $ updateV ix (toJSON v) a
+  go (ArrIx ix) _                 (Just v) = Just $ Array $ updateV ix (toJSON v) mempty
+  go _ v _ = v
+
+  lu (ObjIx ix) (Just (Object o)) = fromJSONMaybe =<< HMS.lookup ix o
+  lu (ArrIx ix) (Just (Array a)) | ix >= 0 && ix < V.length a = fromJSONMaybe $ a V.! ix
+  lu _ _ = Nothing
+
+updateV :: Int -> Value -> V.Vector Value -> V.Vector Value
+updateV i v a
+  | i >= V.length a =
+    updateV i v $ V.generate (i + 1) $ \ii -> fromMaybe Null $ a `V.indexM` ii
+  | otherwise =
+    a V.// [(i, v)]
+
+fromJSONMaybe :: FromJSON a => Value -> Maybe a
+fromJSONMaybe v = case fromJSON v of
+  Error   _ -> Nothing
+  Success a -> Just a
+
+-- | Lens of Array
+--
+-- >>> L.unpack $ encode v
+-- "{\"bar\":[123,false,null],\"foo\":{\"baz\":3.14}}"
+-- >>> v ^. obj (T.pack "bar") . arr 1 :: Maybe Bool
+-- Just False
+-- >>> v ^. obj (T.pack "bar") . arr 1 :: Maybe String
+-- Nothing
+-- >>> v ^. obj (T.pack "bar") . arr 3 :: Maybe Value
+-- Nothing
+-- >>> v ^. arr 0 :: Maybe Value
+-- Nothing
+-- >>> let x = arr 0 .~ Just 1 $ Nothing
+-- >>> L.unpack $ encode x
+-- "[1]"
+-- >>> let y = arr 1 .~ Just "hoge" $ x
+-- >>> L.unpack $ encode y
+-- "[1,\"hoge\"]"
+-- >>> let z = arr 0 .~ Just False $ y
+-- >>> L.unpack $ encode z
+-- "[false,\"hoge\"]"
+arr :: (ToJSON v, FromJSON v)
+       => Int
+       -> SimpleIndexedLens ValueIx (Maybe Value) (Maybe v)
+arr = valueAt . ArrIx
+
+-- | Lens of Object
+--
+-- >>> v ^. obj (T.pack "foo") . obj (T.pack "baz") :: Maybe Double
+-- Just 3.14
+-- >>> v ^. obj (T.pack "foo") . obj (T.pack "baz") :: Maybe Object
+-- Nothing
+-- >>> v ^. obj (T.pack "foo") . obj (T.pack "hoge") :: Maybe Value
+-- Nothing
+-- >>> v ^. obj (T.pack "hoge") :: Maybe Value
+-- Nothing
+-- >>> let w = obj (T.pack "a") .~ Just 2.23 $ Nothing
+-- >>> L.unpack $ encode w
+-- "{\"a\":2.23}"
+-- >>> let x = obj (T.pack "b") . obj (T.pack "c") .~ Just True $ w
+-- >>> L.unpack $ encode x
+-- "{\"b\":{\"c\":true},\"a\":2.23}"
+obj :: (ToJSON v, FromJSON v)
+       => T.Text
+       -> SimpleIndexedLens ValueIx (Maybe Value) (Maybe v)
+obj = valueAt . ObjIx
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2012, Hideyuki Tanaka
+
+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 Hideyuki Tanaka 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/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/aeson-lens.cabal b/aeson-lens.cabal
new file mode 100644
--- /dev/null
+++ b/aeson-lens.cabal
@@ -0,0 +1,33 @@
+name:                aeson-lens
+version:             0.1.0.0
+synopsis:            Lens of Aeson
+description:         Lens of Aeson
+license:             BSD3
+license-file:        LICENSE
+author:              Hideyuki Tanaka
+maintainer:          tanaka.hideyuki@gmail.com
+copyright:           (c) 2012, Hideyuki Tanaka
+category:            Data
+build-type:          Simple
+cabal-version:       >=1.8
+
+source-repository head
+  type:                git
+  location:            https://github.com/tanakh/aeson-lens.git
+
+library
+  exposed-modules:     Data.Aeson.Lens
+  build-depends:       base ==4.5.*
+
+                     , aeson >=0.6
+                     , lens >=3.0
+                     , text >=0.11
+                     , bytestring >=0.9
+                     , vector >=0.9
+                     , unordered-containers >=0.2.2
+
+test-suite doctest
+  type:                exitcode-stdio-1.0
+  main-is:             doctest.hs
+  build-depends:       base
+                     , doctest >=0.9
diff --git a/doctest.hs b/doctest.hs
new file mode 100644
--- /dev/null
+++ b/doctest.hs
@@ -0,0 +1,4 @@
+import Test.DocTest
+
+main :: IO ()
+main = doctest ["Data/Aeson/Lens.hs"]
