diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2014, chemist
+
+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 chemist 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/agentx.cabal b/agentx.cabal
new file mode 100644
--- /dev/null
+++ b/agentx.cabal
@@ -0,0 +1,81 @@
+-- Initial agentx.cabal generated by cabal init.  For further 
+-- documentation, see http://haskell.org/cabal/users-guide/
+
+name:                agentx
+version:             0.1.0.0
+synopsis:            AgentX protocol for snmp subagents
+description:         Native implementation agentx protocol (rfc2741)       
+license:             BSD3
+license-file:        LICENSE
+author:              chemist
+maintainer:          chemistmail@gmail.com
+-- copyright:           
+category:            Network
+build-type:          Simple
+-- extra-source-files:  
+cabal-version:       >=1.10
+
+executable agentx
+  main-is:             Main.hs
+  build-depends:       base >=4.6 && <4.8
+                     , snmp
+                     , binary
+                     , bytestring
+                     , bitwise
+                     , network
+                     , fclabels
+                     , Diff
+                     , mtl
+                     , transformers
+                     , time
+                     , containers
+                     , data-default
+                     , network-info
+                     , safe
+                     , pipes-network
+                     , pipes
+                     , pipes-concurrency
+  hs-source-dirs:      src
+  ghc-options:   -Wall -threaded -rtsopts -auto-all -caf-all
+  default-language:    Haskell2010
+-- 
+-- executable client
+--   main-is:             Client.hs
+--   build-depends:       base >=4.6 && <4.8
+--                      , snmp
+--                      , bytestring
+--   hs-source-dirs:      src
+--   ghc-options:   -Wall -threaded -rtsopts -auto-all -caf-all
+--   default-language:    Haskell2010
+
+library
+  exposed-modules:     Network.Protocol.Snmp.AgentX, Network.Protocol.Snmp.AgentX.MIBTree, Network.Protocol.Snmp.AgentX.Packet
+  other-modules: Network.Protocol.Snmp.AgentX.MIBTree.Tree, Network.Protocol.Snmp.AgentX.MIBTree.MIBTree, Network.Protocol.Snmp.AgentX.MIBTree.Types,
+                 Network.Protocol.Snmp.AgentX.Packet.Binary, Network.Protocol.Snmp.AgentX.Packet.Get, Network.Protocol.Snmp.AgentX.Packet.Put, 
+                 Network.Protocol.Snmp.AgentX.Packet.Types      
+  -- other-extensions:    
+  build-depends:       base >=4.6 && <4.8
+                     , snmp
+                     , binary
+                     , bytestring
+                     , bitwise
+                     , network
+                     , fclabels
+                     , Diff
+                     , mtl
+                     , transformers
+                     , time
+                     , data-default
+                     , containers
+                     , network-info
+                     , safe
+                     , pipes-network
+                     , pipes
+                     , pipes-concurrency
+  hs-source-dirs:      src
+  ghc-options: -Wall
+  default-language:    Haskell2010
+
+source-repository head
+  type:              git
+  location:          git@github.com:chemist/agentx.git
diff --git a/src/Main.hs b/src/Main.hs
new file mode 100644
--- /dev/null
+++ b/src/Main.hs
@@ -0,0 +1,82 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE RankNTypes #-}
+module Main where
+
+import Network.Protocol.Snmp.AgentX 
+import qualified Data.ByteString as BS
+import Data.ByteString (ByteString)
+import Data.Fixed (div')
+import Data.Time.Clock.POSIX (getPOSIXTime)
+import Control.Applicative ((<$>))
+import Control.Monad.State
+import Data.IORef
+
+
+
+str :: ByteString -> PVal
+str x = rsValue (String x)
+
+now :: PVal
+now = rdValue $  TimeTicks . flip div' 1 <$> liftIO getPOSIXTime
+
+rws :: IORef Value -> PVal
+rws io = rwValue readV commit test undo
+  where
+    test (String x) 
+      | BS.length x < 10 = return NoTestError
+      | otherwise = return TooBig
+    test _ = return WrongType
+    commit v = do
+        writeIORef io v
+        return NoCommitError
+    undo _ = return NoUndoError
+    readV = readIORef io
+
+rwi :: IORef Value -> PVal
+rwi io = rwValue readV commit test undo
+  where
+    test (Integer x) 
+      | x < 5 = return NoTestError
+      | otherwise = return TooBig
+    test _ = return WrongType
+    commit v = do
+        writeIORef io v
+        return NoCommitError
+    undo _ = return NoUndoError
+    readV = readIORef io
+
+dynTree :: IORef Value -> Update
+dynTree i = Update $ do
+    Integer count <- liftIO $ readIORef i
+    return $ concatMap fun [0 .. count]
+    where
+    fun x = [ mkObject (fromIntegral x) "trees" ("tree" ++ show x) Nothing
+            , mkObjectType 0 ("tree" ++ show x) "abr" Nothing (str "abr")
+            , mkObjectType 1 ("tree" ++ show x) "abrvalg" Nothing (str "abrvalg")
+            ]
+
+ver :: Maybe Context
+ver = Just "version"
+
+simpleTree :: IORef Value -> IORef Value -> [MIB]
+simpleTree m i = 
+      [ mkObject 0 "Fixmon" "about" Nothing
+      , mkObjectType 0 "about" "name" Nothing $ rsValue (String "Fixmon agent")
+      , mkObjectType 1 "about" "version" Nothing $ rsValue (String "0.0.1")
+      , mkObjectType 1 "about" "version" ver $ rsValue (String "Alpha")
+      , mkObjectType 2 "about" "comment" Nothing (rws m) 
+      , mkObject 1 "Fixmon" "dyn" Nothing
+      , mkObjectType 0 "dyn" "counter" Nothing (rwi i)
+      , mkObject 1 "dyn" "trees" (Just $ dynTree i)
+      ]
+
+tree :: IO [MIB]
+tree = do
+    m <- newIORef (String "init")
+    i <- newIORef (Integer 0)
+    return $ simpleTree m i
+    
+main :: IO ()
+main = agent "/var/agentx/master" [1,3,6,1,4,1,44729] Nothing =<< tree
+
diff --git a/src/Network/Protocol/Snmp/AgentX.hs b/src/Network/Protocol/Snmp/AgentX.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Protocol/Snmp/AgentX.hs
@@ -0,0 +1,203 @@
+module Network.Protocol.Snmp.AgentX ( 
+-- * About
+-- $about
+  MIB
+, Value(..)
+, PVal(..)
+, rwValue
+, rsValue
+, rdValue
+, Update(..)
+, mkObject
+, mkObjectType
+, CommitError(..)
+, TestError(..)
+, UndoError(..)
+, Context
+, agent
+, Client
+-- * Usage
+-- ** Imports
+-- $imports
+
+-- ** Desribe values for monitoring
+-- $values
+
+-- ** Build dynamic tree
+-- $dynTree
+
+-- ** Describe context 
+-- $context
+
+-- ** Construct full tree
+-- $fullTree
+
+-- ** Start subagent
+-- $dowork
+
+-- ** Examples
+-- $config
+)
+where
+
+import Network.Protocol.Snmp 
+import Network.Protocol.Snmp.AgentX.Service 
+import Network.Protocol.Snmp.AgentX.MIBTree 
+import Network.Protocol.Snmp.AgentX.Packet 
+
+{- $about
+Library for write extensible SNMP agents.
+-}
+
+{- $imports
+> {-# LANGUAGE OverloadedStrings #-}
+> {-# LANGUAGE ScopedTypeVariables #-}
+> {-# LANGUAGE RankNTypes #-}
+> module Main where
+> 
+> import Network.Protocol.Snmp.AgentX 
+> import qualified Data.ByteString as BS
+> import Data.ByteString (ByteString)
+> import Data.Fixed (div')
+> import Data.Time.Clock.POSIX (getPOSIXTime)
+> import Control.Applicative ((<$>))
+> import Control.Monad.State
+> import Data.IORef
+-}
+
+
+{- $values
+> str :: ByteString -> PVal
+> str x = rsValue (String x)
+> 
+> now :: PVal
+> now = rdValue $  TimeTicks . flip div' 1 <$> liftIO getPOSIXTime
+> 
+> rws :: IORef Value -> PVal
+> rws io = rwValue readV commit test undo
+>   where
+>     test (String x) 
+>       | BS.length x < 10 = return NoTestError
+>       | otherwise = return TooBig
+>     test _ = return WrongType
+>     commit v = do
+>         writeIORef io v
+>         return NoCommitError
+>     undo _ = return NoUndoError
+>     readV = readIORef io
+> 
+> rwi :: IORef Value -> PVal
+> rwi io = rwValue readV commit test undo
+>   where
+>     test (Integer x) 
+>       | x < 5 = return NoTestError
+>       | otherwise = return TooBig
+>     test _ = return WrongType
+>     commit v = do
+>         writeIORef io v
+>         return NoCommitError
+>     undo _ = return NoUndoError
+>     readV = readIORef io
+-}
+
+{- $dynTree
+> dynTree :: IORef Value -> Update
+> dynTree i = Update $ do
+>     Integer count <- liftIO $ readIORef i
+>     return $ concatMap fun [0 .. count]
+>     where
+>     fun x = [ mkObject (fromIntegral x) "trees" ("tree" ++ show x) Nothing
+>             , mkObjectType 0 ("tree" ++ show x) "abr" Nothing (str "abr")
+>             , mkObjectType 1 ("tree" ++ show x) "abrvalg" Nothing (str "abrvalg")
+>             ]
+> 
+-}
+
+{- $context
+> ver :: Maybe Context
+> ver = Just "version"
+-}
+
+{- $fullTree
+> simpleTree :: IORef Value -> IORef Value -> [MIB]
+> simpleTree m i = 
+>       [ mkObject 0 "Fixmon" "about" Nothing
+>       , mkObjectType 0 "about" "name" Nothing $ rsValue (String "Fixmon agent")
+>       , mkObjectType 1 "about" "version" Nothing $ rsValue (String "0.0.1")
+>       , mkObjectType 1 "about" "version" ver $ rsValue (String "Alpha")
+>       , mkObjectType 2 "about" "comment" Nothing (rws m) 
+>       , mkObject 1 "Fixmon" "dyn" Nothing
+>       , mkObjectType 0 "dyn" "counter" Nothing (rwi i)
+>       , mkObject 1 "dyn" "trees" (Just $ dynTree i)
+>       ]
+> 
+> tree :: IO [MIB]
+> tree = do
+>     m <- newIORef (String "init")
+>     i <- newIORef (Integer 0)
+>     return $ simpleTree m i
+> 
+-}
+    
+{- $dowork
+> main :: IO ()
+> main = agent "/var/agentx/master" [1,3,6,1,4,1,44729] Nothing =<< tree
+> 
+-}
+
+{- $config
+> SNMP server config
+> > cat /etc/snmp/snmpd.conf
+> > rwuser sha
+> > createUser sha SHA "password" DESi
+> > master agentx
+> > agentXPerms 777 775
+> 
+> SNMP client config
+> > cat /etc/snmp/snmp.conf
+> > defVersion 3
+> > defSecurityName sha
+> > defSecurityLevel authPriv
+> > defPassphrase password
+> > defAuthType SHA
+> > defPrivType DES
+> > defContext ""
+> 
+> Build and start example
+> > cabal install example
+> > .cabal-sandbox/bin/example
+> > .cabal-sandbox/bin/agentx
+> > "set sid SessionID 15"
+> > "R ([1,3,6,1,4,1,44729,1,1,0,1],Nothing)"
+> > "R ([1,3,6,1,4,1,44729,1,1,0,0],Nothing)"
+> > "R ([1,3,6,1,4,1,44729,1,0],Nothing)"
+> > "R ([1,3,6,1,4,1,44729,0,2],Nothing)"
+> > "R ([1,3,6,1,4,1,44729,0,1],Just (Context \"version\"))"
+> > "R ([1,3,6,1,4,1,44729,0,1],Nothing)"
+> > "R ([1,3,6,1,4,1,44729,0,0],Nothing)"
+> 
+> Get MIB tree
+>  > snmpwalk -r 1 -On localhost 1.3.6.1.4.1.44729
+>  > .1.3.6.1.4.1.44729.0.0 = STRING: "Fixmon agent"
+>  > .1.3.6.1.4.1.44729.0.1 = STRING: "0.0.1"
+>  > .1.3.6.1.4.1.44729.0.2 = STRING: "init"
+>  > .1.3.6.1.4.1.44729.1.0 = INTEGER: 0
+>  > .1.3.6.1.4.1.44729.1.1.0.0 = STRING: "abr"
+>  > .1.3.6.1.4.1.44729.1.1.0.1 = STRING: "abrvalg"
+>  
+> Change MIB tree 
+>  >  snmpset -r 1  -On localhost .1.3.6.1.4.1.44729.1.0 i 2
+>  > .1.3.6.1.4.1.44729.1.0 = INTEGER: 2
+>  >  snmpwalk -r 1 -On localhost 1.3.6.1.4.1.44729
+>  > .1.3.6.1.4.1.44729.0.0 = STRING: "Fixmon agent"
+>  > .1.3.6.1.4.1.44729.0.1 = STRING: "0.0.1"
+>  > .1.3.6.1.4.1.44729.0.2 = STRING: "init"
+>  > .1.3.6.1.4.1.44729.1.0 = INTEGER: 2
+>  > .1.3.6.1.4.1.44729.1.1.0.0 = STRING: "abr"
+>  > .1.3.6.1.4.1.44729.1.1.0.1 = STRING: "abrvalg"
+>  > .1.3.6.1.4.1.44729.1.1.1.0 = STRING: "abr"
+>  > .1.3.6.1.4.1.44729.1.1.1.1 = STRING: "abrvalg"
+>  > .1.3.6.1.4.1.44729.1.1.2.0 = STRING: "abr"
+>  > .1.3.6.1.4.1.44729.1.1.2.1 = STRING: "abrvalg"
+> 
+-}
diff --git a/src/Network/Protocol/Snmp/AgentX/MIBTree.hs b/src/Network/Protocol/Snmp/AgentX/MIBTree.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Protocol/Snmp/AgentX/MIBTree.hs
@@ -0,0 +1,50 @@
+{-# LANGUAGE RankNTypes #-}
+module Network.Protocol.Snmp.AgentX.MIBTree ( 
+  MIBTree
+-- ** Module
+, Module
+-- *** create and init Module
+, mkModule
+, initModule
+, registerFullTree
+, unregisterFullTree
+, askTree
+, regByDiff
+-- *** lenses for Module
+, moduleOID
+, register
+, zipper
+, ou
+-- *** functions for work with MIBTree
+, findOne
+, findMany
+, findNext
+, findManyNext
+-- ** MIB
+, Parent
+, Name
+, MIB
+-- *** lenses
+, oi
+, val
+, context
+-- *** constructors
+, mkObject
+, mkObjectType
+, isObjectType
+-- ** raw values for build SNMP subagent
+, Update(..)
+, PVal(..)
+, isWritable
+-- *** helpers for create PVal
+, rsValue
+, rdValue
+, rwValue
+, regWrapper
+, mibToVarBind
+)
+where
+import Network.Protocol.Snmp.AgentX.MIBTree.MIBTree
+import Network.Protocol.Snmp.AgentX.MIBTree.Types
+
+
diff --git a/src/Network/Protocol/Snmp/AgentX/MIBTree/MIBTree.hs b/src/Network/Protocol/Snmp/AgentX/MIBTree/MIBTree.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Protocol/Snmp/AgentX/MIBTree/MIBTree.hs
@@ -0,0 +1,251 @@
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+module Network.Protocol.Snmp.AgentX.MIBTree.MIBTree 
+( initModule
+, registerFullTree
+, unregisterFullTree
+, findOne
+, findMany
+, findNext
+, findClosest
+, findManyNext
+, regWrapper
+, askTree
+, regByDiff
+)
+where
+
+import Data.Maybe 
+import Control.Applicative
+import Control.Monad.State.Strict (MonadIO, forM_, lift, get, put, liftIO, when)
+import Network.Protocol.Snmp.AgentX.MIBTree.Types hiding (context)
+import Network.Protocol.Snmp.AgentX.MIBTree.Tree 
+import Network.Protocol.Snmp (OID, Value(EndOfMibView, NoSuchInstance, NoSuchObject))
+import Network.Protocol.Snmp.AgentX.Packet (Context, SearchRange, startOID, endOID, include)
+import Control.Concurrent.MVar
+import qualified Data.Label as L
+import Data.List (stripPrefix)
+
+import Data.Monoid
+import Data.Label.Monadic
+import Control.Category ((.))
+import Prelude hiding ((.))
+-- import Debug.Trace
+
+-- | build tree and init module
+initModule :: (Monad m, MonadIO m, Functor m) =>  MIBTree m ()
+initModule = flip forM_ evalTree =<< toUpdateList  <$> gets ou  
+    where
+    evalTree :: (Monad m, MonadIO m, Functor m) => MIB -> MIBTree m ()
+    evalTree obj = do
+        (mibs, updates) <- buildTree <$> (lift $ unUpdate . fromJust . update $ obj)
+        case updates of
+             Empty -> do -- if without updates just attach subtree
+                modify zipper $ top . attach mibs . (fromJust . setCursor (oi obj) Nothing) . top
+                modify ou $ top . attach updates . (fromJust . setCursor (oi obj) Nothing) . top
+             _     -> do -- if with updates, save state, build new subtree, return state, and attach builded subtree
+                modify zipper $  fromJust . setCursor (oi obj) Nothing . top
+                modify ou $ fromJust . setCursor (oi obj) Nothing . top
+                old <- get
+                modify zipper $  const (mibs, [])
+                modify ou $ const (updates, [])
+                initModule
+                Module (z,_) (o,_) _ _ <- get
+                put old
+                modify zipper $ top . attach z
+                modify ou $ top . attach o
+
+-- | register all MIBs in snmp server
+registerFullTree :: (Monad m, MonadIO m, Functor m) => MIBTree m ()
+registerFullTree = do
+    z <- fst . top <$> gets zipper 
+    mv <- gets register
+    b <- gets moduleOID
+    liftIO $ putMVar mv (addBaseOid b $ regPair z Empty)
+
+unregisterFullTree :: (Monad m, MonadIO m, Functor m) => MIBTree m ()
+unregisterFullTree = do
+    z <- fst . top <$> gets zipper 
+    mv <- gets register
+    b <- gets moduleOID
+    liftIO $ putMVar mv (addBaseOid b $ regPair Empty z)
+
+askTree :: (Monad m, MonadIO m, Functor m) => MIBTree m (Tree IValue)
+askTree = fst . top <$> gets zipper
+
+regByDiff :: (Monad m, MonadIO m, Functor m) => Tree IValue -> Tree IValue -> MIBTree m ()
+regByDiff old new = do
+    mv <- gets register
+    b <- gets moduleOID
+    liftIO $ putMVar mv (addBaseOid b $ regPair old new)
+
+
+addBaseOid :: OID -> ([(OID, Maybe Context)], [(OID, Maybe Context)]) -> ([(OID, Maybe Context)], [(OID, Maybe Context)])
+addBaseOid b (reg, unreg) = (map fun reg, map fun unreg)
+    where
+    fun (o, mc) = (b <> o, mc)
+
+toUpdateList :: Zipper Tree IUpdate  -> [MIB]
+toUpdateList (Empty, _) = []
+toUpdateList (t, _) = toUpdateList' ([], t)
+  where
+  toUpdateList' :: (OID, Tree IUpdate) -> [MIB]
+  toUpdateList' (o, Node x next level) = 
+      if withValue x
+         then Object (reverse $ index x : o) (index x) "" "" (valueFromContexted x) 
+              : toUpdateList' (o, next) 
+              <> toUpdateList' (index x : o, level)
+         else toUpdateList' (o, next)
+              <> toUpdateList' (index x : o, level)
+  toUpdateList' _ = []
+  valueFromContexted (Contexted (_, _, x)) = x
+
+inRange :: SearchRange -> MIB -> MIB  
+inRange s m =
+    if (L.get startOID s) <= oi m && oi m < (L.get endOID s)
+        then ObjectType (oi m) (last $ oi m) "" "" Nothing (val m)
+        else ObjectType (L.get startOID s) (last $ L.get startOID s) "" "" Nothing (rsValue EndOfMibView)
+
+-- | find one MIB 
+findOne :: (Monad m, MonadIO m, Functor m) => 
+      OID  -- ^ path for find
+    -> Maybe Context -- ^ context, you can have many values with one path and different context
+    -> MIBTree m MIB 
+findOne ys mcontext = do
+    -- init zippers
+    modify zipper top
+    modify ou top
+    modOID <- gets moduleOID
+    -- strip module prefix
+    case stripPrefix modOID ys of
+         Nothing -> return $ ObjectType ys (last ys) "" "" mcontext nso
+         Just ys' -> do
+             updates <- gets ou
+             -- put update subtree to state
+             puts ou (updateSubtree ys' updates)
+             -- update dynamic branches
+             initModule
+             -- get back full update tree
+             puts ou updates
+             -- find
+             findOne' ys' <$> gets zipper
+    where
+      findOne' xs z = toObject $ setCursor xs mcontext z
+
+      toObject Nothing = ObjectType ys (last ys) "" "" mcontext nsi
+      toObject (Just (Node (Contexted (i, _, v)) _ Empty, _)) = ObjectType ys i "" "" mcontext (fromMaybe nso v)
+      toObject _ = ObjectType ys (last ys) "" "" mcontext nso
+
+      nso, nsi :: PVal 
+      nso = rsValue NoSuchObject
+      nsi = rsValue NoSuchInstance
+
+updateSubtree :: Contexted a => OID -> Zipper Tree a -> Zipper Tree a
+updateSubtree xs z =
+    let (x, u) = goClosest xs Nothing z
+        isLevel (Level _) = True
+        isLevel _ = False
+        cleanUnused (Level (Node v _ l)) = Level (Node v Empty l)
+        cleanUnused _ = error "cleanUnused"
+        cleanHead Empty = Empty
+        cleanHead (Node v _ l) = Node v Empty l
+    in top (cleanHead x, map cleanUnused $ filter isLevel u)
+
+-- | wrap MIBTree action, get MIB tree before and after, register added mibs, unregister removed mibs
+regWrapper :: (Monad m, MonadIO m, Functor m) => MIBTree m x -> MIBTree m x
+regWrapper x = do
+    old <- fst . top <$> gets zipper  
+    r <- x
+    new <- fst . top <$> gets zipper  
+    mv <- gets register
+    b <- gets moduleOID
+    let diff = addBaseOid b $ regPair new old
+    when (diff /= ([], [])) $ do
+        liftIO $ putMVar mv diff
+    return r
+
+
+-- | like findOne, but for many paths
+findMany :: (Monad m, MonadIO m, Functor m) => [OID] -> Maybe Context -> MIBTree m [MIB]
+findMany xs mc = mapM (flip findOne mc) xs
+
+-- | find next node in MIBTree 
+findNext :: (Monad m, MonadIO m, Functor m) => 
+      SearchRange  -- ^ SearchRange (getwalk or getnext requests)
+    -> Maybe Context -- ^ context
+    -> MIBTree m MIB -- ^ search result
+findNext sr mcontext = do
+    modify zipper top
+    modify ou top
+    modOID <- gets moduleOID
+    let start = L.get startOID sr
+        end   = L.get endOID sr
+    case (stripPrefix modOID start, stripPrefix modOID end) of
+         (Nothing, _) -> return $ ObjectType start (last start) "" "" mcontext eom
+         (Just start', Just end') -> do
+             updates <- gets ou
+             puts ou (updateSubtree start' updates)
+             initModule
+             puts ou updates
+             let fixSearchRange = L.set startOID start' . L.set endOID end' 
+             fixMib modOID . findNext' (fixSearchRange sr) <$> gets zipper
+         _ -> error "findNext"
+
+    where
+    eom :: PVal
+    eom = rsValue EndOfMibView
+
+    fixMib :: OID -> MIB -> MIB
+    fixMib m (ObjectType o i _ _ mc v) = ObjectType (m <> o) i "" "" mc v
+    fixMib _ _ = error "fixMib"
+
+    findNext' :: SearchRange -> Zipper Tree IValue -> MIB
+    findNext' sr' z 
+      | L.get include sr' =
+          let start = L.get startOID sr'
+              nz@(Node v _ _, _) = goClosest start mcontext z 
+              o = oid nz
+              Contexted (i, mc, Just pv) = v
+          in if o == start && withValue v && mc == mcontext
+                then ObjectType o i "" "" mc pv
+                else findNext' (L.set include False $ sr') z
+      | otherwise =
+          let start = L.get startOID sr'
+              nz = goClosest start mcontext z
+              l = hasLevel nz
+              n = hasNext nz
+          in case (l, n) of
+                  (True, _) -> inRange sr' $ findClosest False  start mcontext (fromJust $ goLevel nz)
+                  (False, True) -> inRange sr' $ findClosest False start  mcontext (fromJust $ goNext nz)
+                  (False, False) -> inRange sr' $ findClosest True start  mcontext (fromJust $ goUp nz)
+
+findClosest :: Bool -> OID -> Maybe Context -> Zipper Tree IValue -> MIB
+findClosest back o mcontext z =
+    let (canBeObject, checkContextEquality) = isFocusObjectType z
+        magic = if back 
+                 then not (hasLevel z)
+                 else (hasLevel z)
+        isNextAvailable = hasNext z
+    in case (canBeObject, checkContextEquality mcontext, magic, isNextAvailable) of
+            (True,  True, _,     _    ) -> getFocus z 
+            (_,     _,    True,  _    ) -> findClosest False o mcontext (fromJust $ goLevel z)
+            (_,     _,    False, True ) -> findClosest False o mcontext (fromJust $ goNext z)
+            _                           -> case goUp z of
+                                           Just nz -> findClosest True o mcontext nz
+                                           Nothing -> ObjectType o (last o) "" "" Nothing (rsValue EndOfMibView)
+
+isFocusObjectType :: Contexted a => (Tree a, t) -> (Bool, Maybe Context -> Bool)
+isFocusObjectType (Node v _ Empty,_) = (withValue v, (==) (context v))
+isFocusObjectType _ = (False, const False)
+
+getFocus :: Zipper Tree IValue -> MIB
+getFocus z@(Node (Contexted (i, mc, Just v)) _ _, _) = 
+    let o = oid z
+    in ObjectType o i "" "" mc v
+getFocus _ = error "getFocus"
+
+-- | like findNext
+findManyNext :: (Monad m, MonadIO m, Functor m) => [SearchRange] -> Maybe Context -> MIBTree m [MIB]
+findManyNext xs mc = mapM (flip findNext mc) xs
+
+
diff --git a/src/Network/Protocol/Snmp/AgentX/MIBTree/Tree.hs b/src/Network/Protocol/Snmp/AgentX/MIBTree/Tree.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Protocol/Snmp/AgentX/MIBTree/Tree.hs
@@ -0,0 +1,185 @@
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+module Network.Protocol.Snmp.AgentX.MIBTree.Tree 
+( Zippers(..)
+, Contexted(..)
+, Tree(..)
+, Zipper
+, hasNext
+, hasLevel
+, goClosest
+, Move(..)
+, regPair
+)
+where
+
+import Data.Maybe (fromJust)
+import Data.Monoid hiding (First)
+import Network.Protocol.Snmp.AgentX.Packet (Context)
+import Network.Protocol.Snmp (OID)
+import Data.Algorithm.Diff
+import Data.List (sort)
+import Prelude 
+
+data Move b a = Next (b a)
+              | Level (b a)
+
+instance (Show a, Show (b a)) => Show (Move b a) where
+    show (Next x) = "\nNext " ++ show x
+    show (Level x) = "\nLevel " ++ show x
+
+type Moving b a = [Move b a]
+
+type Zipper b a = (b a, Moving b a)
+
+class Zippers b where
+    toZipper :: b a -> Zipper b a
+    attach :: b a -> Zipper b a -> Zipper b a
+    goNext :: Zipper b a -> Maybe (Zipper b a)
+    goLevel :: Zipper b a -> Maybe (Zipper b a)
+    goBack  :: Zipper b a -> Maybe (Zipper b a)
+    goUp    :: Zipper b a -> Maybe (Zipper b a)
+    top     :: Zipper b a -> Zipper b a
+    oid     :: Contexted a => Zipper b a -> OID
+    cursor  :: Contexted a => Zipper b a -> Maybe (Integer, Maybe Context)
+    setCursor :: Contexted a => OID -> Maybe Context -> Zipper b a -> Maybe (Zipper b a)
+
+data Tree a = Node a (Tree a) (Tree a)
+            | Empty
+            deriving (Functor, Eq)
+
+class Contexted a where
+    index :: a -> Integer
+    context :: a -> Maybe Context
+    withValue :: a -> Bool
+
+instance Contexted a => Monoid (Tree a) where
+    mempty = Empty
+    mappend a Empty = a
+    mappend Empty a = a
+    mappend (Node v next link) x@(Node v1 next1 link1)
+       | index v == index v1 && context v == context v1 = Node v (next <> next1) (link <> link1) 
+       | otherwise = Node v (next <> x) link 
+
+
+instance (Contexted a, Show a) => Show (Tree a) where
+    show f = unlines $ drawLevel f
+      where
+        drawLevel Empty = []
+        drawLevel (Node v next link) = (show (index v) <> " " <> show v <> " ") : (drawSubtree next link)
+
+        drawSubtree next link = (shift "`- " " | " (drawLevel link)) <> drawLevel next
+    
+        shift first rest = zipWith (++) (first : repeat rest)
+
+-- testTree :: Tree (Integer, Maybe String)
+-- testTree = Node (0, Just "first") (Node (1, Just "second") Empty Empty) (Node (10, Just "third") Empty Empty)
+
+instance Contexted (Integer, Maybe String) where
+    index = fst
+    context = undefined
+    withValue (_, Nothing) = False
+    withValue _ = True
+
+instance Zippers Tree where
+    toZipper t = (t, [])
+
+    attach t (Empty, bs) = (t, bs)
+    attach t (Node v next _, bs) = (Node v next t, bs)
+
+    goNext (Empty, _) = Nothing
+    goNext (Node _ Empty _, _) = Nothing
+    goNext (Node x  next link, bs) = Just (next, Next (Node x   Empty link):bs)
+
+    goLevel (Empty, _) = Nothing
+    goLevel (Node _ _ Empty, _) = Nothing
+    goLevel (Node x next link, bs) = Just (link, Level (Node x next Empty):bs)
+
+    goBack (_, []) = Nothing
+    goBack (t, Next  (Node x  Empty  link):bs) = Just (Node x  t    link, bs)
+    goBack (t, Level (Node x  next  Empty):bs) = Just (Node x  next t   , bs)
+    goBack _ = Nothing
+
+    goUp (_, []) = Nothing
+    goUp (t, Next  (Node x  Empty link ):bs) = goUp (Node x  t    link, bs)
+    goUp (t, Level (Node x  next  Empty):bs) = Just (Node x  next t   , bs)
+    goUp _ = Nothing
+
+    top (t,[]) = (t,[])  
+    top z = top (fromJust $ goBack z)
+
+    oid (z, m) = foldl fun [gi z] m
+      where 
+        fun xs (Next{}) = xs
+        fun xs (Level x) = gi x : xs
+        gi :: Contexted a => Tree a -> Integer
+        gi (Node x _ _) = index x
+        gi _ = error "oid"
+
+    setCursor [] _ z = Just (top z)
+    setCursor ys c z = walk ys (top z)
+      where
+      giz (Node x _ _  , _) = (index x, context x)
+      giz _ = error "setCursor: giz Empty Tree"
+      walk [] t = Just t
+      walk (x : []) t
+        | (x, c) == giz t = Just t
+        | otherwise = goNext t >>= walk (x : []) 
+      walk (x : xs) t 
+        | x == fst (giz t) = goLevel t >>= walk xs 
+        | otherwise = goNext  t >>= walk (x : xs) 
+
+    cursor ((Node v _ _), _) = Just (index v, context v)
+    cursor (Empty       , _) = Nothing
+
+hasLevel :: Zipper Tree a -> Bool
+hasLevel (Node _ _ Empty, _) = False
+hasLevel _ = True
+
+hasNext :: Zipper Tree a -> Bool
+hasNext (Node _ Empty _, _) = False
+hasNext _ = True
+
+goClosest :: Contexted a => OID -> Maybe Context -> Zipper Tree a -> Zipper Tree a
+goClosest [] _ z = top z
+goClosest ys c z = walk ys (top z)
+  where
+  giz (Node x _ _, _) = (index x, context x)
+  giz _ = error "goClosest: giz Empty Tree"
+  walk [] z' = z'
+  walk (x : []) z'
+    | (x,c) == giz z' = z'
+    | otherwise = maybe z' (walk (x : [])) (goNext z')
+  walk (x : xs) z'
+    | x == fst (giz z') = maybe z' (walk xs) (goLevel z')
+    | otherwise = maybe z' (walk (x : xs)) (goNext z')
+
+type RegType = [(OID, Maybe Context)]
+type ToRegistrate = [(OID, Maybe Context)]
+type ToUnRegistrate = [(OID, Maybe Context)]
+                      
+toVList :: Contexted a => (OID, Tree a) -> RegType
+toVList (path, Node a Empty Empty)
+  | withValue a = [(index a : path, context a)]
+  | otherwise = []
+toVList (path, Node a level next) 
+  | withValue a = (index a : path, context a) : toVList (path, level) <> toVList (index a : path, next)
+  | otherwise = toVList (path, level) <> toVList (index a : path, next)
+toVList (_, Empty) = []
+
+regPair :: Contexted a => Tree a -> Tree a -> (ToRegistrate, ToUnRegistrate)
+regPair old new = splitDiff $ getDiff (reverseOid $ toVList ([], old)) (reverseOid $ toVList ([], new))
+
+reverseOid :: [(OID, Maybe Context)] -> [(OID, Maybe Context)]
+reverseOid = sort . map fun 
+  where
+    fun (xs, mc) = (reverse xs, mc)
+
+splitDiff :: [Diff a] -> ([a], [a])
+splitDiff = splitDiff' ([], []) 
+  where
+    splitDiff' (toUnReg, toReg) [] = (toUnReg, toReg)
+    splitDiff' (toUnReg, toReg) (Both _ _ : xs) = splitDiff' (toUnReg, toReg) xs
+    splitDiff' (toUnReg, toReg) (First x : xs) = splitDiff' (x : toUnReg, toReg) xs
+    splitDiff' (toUnReg, toReg) (Second x : xs) = splitDiff' (toUnReg, x : toReg) xs
diff --git a/src/Network/Protocol/Snmp/AgentX/MIBTree/Types.hs b/src/Network/Protocol/Snmp/AgentX/MIBTree/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Protocol/Snmp/AgentX/MIBTree/Types.hs
@@ -0,0 +1,222 @@
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE KindSignatures #-}
+{-# LANGUAGE StandaloneDeriving #-}
+{-# LANGUAGE RankNTypes #-}
+module Network.Protocol.Snmp.AgentX.MIBTree.Types 
+( PVal(..)
+, rsValue
+, rwValue
+, rdValue
+, Update(..)
+, Module(..)
+, mkModule
+, MIB(..)
+, mkObject
+, mkObjectType
+, mibToVarBind
+, isObjectType
+, Parent
+, Name
+, ou
+, moduleOID
+, MIBTree
+, buildTree
+, register
+, isWritable
+, zipper
+, IUpdate
+, IValue
+, ContextedValue(..)
+)
+where
+
+import Control.Monad.State.Strict 
+import Control.Concurrent.MVar
+import Data.Monoid ((<>))
+import Data.Foldable (foldMap)
+import Data.Label
+
+import Network.Protocol.Snmp.AgentX.MIBTree.Tree 
+import Network.Protocol.Snmp (Value(..), OID)
+import Network.Protocol.Snmp.AgentX.Packet (Context, CommitError, TestError, UndoError, VarBind, mkVarBind)
+
+-- | Wrapper for value
+data PVal = Read 
+            { readAIO        :: IO Value  
+            }
+          | ReadWrite 
+            { readAIO        :: IO Value
+            , commitSetAIO   :: Value -> IO CommitError
+            , testSetAIO     :: Value -> IO TestError
+            , undoSetAIO     :: Value -> IO UndoError
+            }
+
+-- | Update, for rebuild oid tree in runtime
+newtype Update = Update { unUpdate :: forall  m . (Monad m, MonadIO m, Functor m) =>  m [MIB] }
+
+type IValue = ContextedValue PVal  
+type IUpdate = ContextedValue Update 
+
+instance Show PVal where
+    show Read{} = "Read Value"
+    show ReadWrite{} = "ReadWrite Value"
+
+type Parent = String
+type Name   = String
+
+-- | MIB describe objects and object-types in internal tree with data.
+data MIB = Object
+    { oi :: OID -- ^ accessor for OID
+    , int :: Integer
+    , parent :: Parent
+    , name  :: Name
+    , update :: Maybe Update 
+    }      | ObjectType
+    { oi :: OID
+    , int :: Integer
+    , parent :: Parent
+    , name :: Name
+    , context :: Maybe Context -- ^ accessor for Maybe Context
+    , val :: PVal  -- ^ accessor for PVal
+    }
+
+deriving instance Show MIB 
+
+instance Show Update  where
+    show _ = "Update Subtree Fun"
+
+newtype ContextedValue a = Contexted { unContext :: (Integer, Maybe Context, Maybe a) }
+
+instance Contexted (ContextedValue a) where
+    index (Contexted (i, _, _)) = i
+    context (Contexted (_, c, _)) = c
+    withValue (Contexted (_, _, Just _)) = True
+    withValue _ = False
+
+instance Show a => Show (ContextedValue a) where
+    show (Contexted (_, Nothing, Nothing)) = "- node -"
+    show (Contexted (_, Nothing, Just v)) = "- leaf " <> show v
+    show (Contexted (_, Just c, Just v)) = "- contexted leaf " <> show c <> show v
+    show _ = "bad node"
+
+-- | internal state for build SNMP submodule
+data Module = Module
+  { _zipper        :: Zipper Tree IValue 
+  , _ou            :: Zipper Tree IUpdate
+  , _moduleOID     :: OID
+  , _register      :: MVar ([(OID, Maybe Context)], [(OID, Maybe Context)])
+  } 
+
+mkLabel ''Module
+
+instance Show Module where
+    show (Module z ou' _ _) = show z ++ "\n" ++ show ou'
+
+-- | MIBTree, state transformer, with Module under ground
+type MIBTree = StateT Module  
+
+-- | Constructor for Module
+mkModule :: (Monad m, MonadIO m, Functor m) => 
+    OID -- ^ base module OID
+  -> [MIB] -- ^ all MIB for create module
+  -> m Module 
+mkModule moduleOid mibs = do
+    reg <- liftIO $ newEmptyMVar
+    return $ Module (toZipper . fst . buildTree $ mibs) (toZipper . snd . buildTree $ mibs) moduleOid reg
+
+buildTree :: [MIB] -> (Tree IValue, Tree IUpdate)
+buildTree ms = foldMap singleton $ fillOid ms
+  where
+    singleton :: MIB -> (Tree IValue , Tree IUpdate)
+    singleton m = singleton' (oi m, m)
+
+    singleton' :: (OID, MIB) -> (Tree IValue, Tree IUpdate)
+    singleton' ([],  _) = (Empty, Empty)
+    singleton' ([_], Object _ i _ _ Nothing) = (Node (zero i) Empty Empty, Empty )
+    singleton' ([_], Object _ i _ _ u@_) = (Node (zero i) Empty Empty, Node (toC i Nothing u) Empty Empty )
+    singleton' ([_], ObjectType _ i _ _ c v) = (Node (toC i c (Just v)) Empty Empty, Empty)
+    singleton' ((i:xs), obj@(Object _ _ _ _ Nothing)) = (Node (zero i) Empty (fst $ singleton' (xs, obj)), Empty)
+    singleton' ((i:xs), obj@(Object _ _ _ _ _)) = (Node (zero i) Empty (fst $ singleton' (xs, obj)), Node (zero i) Empty (snd $ singleton' (xs, obj)))
+    singleton' ((i:xs), obj@(ObjectType{})) = (Node (zero i) Empty (fst $ singleton' (xs, obj)), Empty)
+
+    toC :: Integer -> Maybe Context -> Maybe a -> ContextedValue a
+    toC i mc mv = Contexted (i, mc, mv)
+
+    zero :: Integer -> ContextedValue a
+    zero i = Contexted (i, Nothing, Nothing)
+
+
+-- | check MIB subtype
+isObjectType :: MIB -> Bool
+isObjectType (ObjectType{}) = True
+isObjectType _ = False
+
+-- | Constructor for MIB, create Object in mib tree
+mkObject :: Integer -- ^ OID number for this object
+  -> Parent -- ^ parent name for this object
+  -> Name  -- ^ name for this object
+  -> Maybe Update  -- ^ Just Update if you need dynamic module
+  -> MIB -- ^ created MIB
+mkObject = Object [] 
+
+-- | Constructor for MIB, create Object-Type in mib tree
+mkObjectType :: Integer -- ^ OID number for this object
+  -> Parent  -- ^ parent
+  -> Name -- ^ name
+  -> Maybe Context -- ^ context
+  -> PVal -- ^ value
+  -> MIB -- ^ created MIB 
+mkObjectType = ObjectType []
+
+fillOid :: [MIB ] -> [MIB ]
+fillOid [] = []
+fillOid (ObjectType o i p n v u : xs) 
+  | o == [] = ObjectType [i] i p n v u : mkOid' [(p, []), (n, [i])] xs
+  | otherwise = ObjectType o i p n v u : mkOid' [(p, []), (n, o)] xs
+  where
+    mkOid' :: [(Parent, OID)] -> [MIB ] -> [MIB ]
+    mkOid' _ [] = []
+    mkOid' base (y:ys) =
+        let Just prev = lookup (parent y) base
+            newbase = (name y, prev <> [int y]) : base
+        in addOid prev y : mkOid' newbase ys
+    addOid :: OID -> MIB -> MIB 
+    addOid o' (Object _ i' p' n' u') = Object (o' <> [i']) i' p' n' u'
+    addOid o' (ObjectType _ i' p' n' v' u') = ObjectType (o' <> [i']) i' p' n' v' u'
+fillOid (Object o i p n u : xs) 
+  | o == [] = Object [i] i p n u :  mkOid' [(p, []), (n, [i])] xs
+  | otherwise = Object o i p n u : mkOid' [(p, []), (n, o)] xs
+  where
+    mkOid' :: [(Parent, OID)] -> [MIB ] -> [MIB ]
+    mkOid' _ [] = []
+    mkOid' base (y:ys) =
+        let Just prev = lookup (parent y) base
+            newbase = (name y, prev <> [int y]) : base
+        in addOid prev y : mkOid' newbase ys
+    addOid :: OID -> MIB  -> MIB  
+    addOid o' (Object _ i' p' n' u') = Object (o' <> [i']) i' p' n' u'
+    addOid o' (ObjectType _ i' p' n' v' u') = ObjectType (o' <> [i']) i' p' n' v' u'
+
+-- | PVal constructor for read only value
+rsValue :: Value -> PVal 
+rsValue v = Read $ return v
+
+-- | PVal constructor for read only IO Value 
+rdValue :: IO Value -> PVal 
+rdValue = Read   
+
+-- | PVal constructor for read write value
+rwValue :: IO Value -> (Value -> IO CommitError) -> (Value -> IO TestError) -> (Value -> IO UndoError) -> PVal 
+rwValue = ReadWrite
+
+-- | check for PVal
+isWritable :: PVal -> Bool
+isWritable ReadWrite{} = True
+isWritable _ = False
+
+-- | convert MIB to VarBind
+mibToVarBind :: (Monad m, MonadIO m, Functor m) => MIB -> m VarBind
+mibToVarBind m = do
+    v <- liftIO $ readAIO (val m) 
+    return $ mkVarBind (oi m) v
+
diff --git a/src/Network/Protocol/Snmp/AgentX/Packet.hs b/src/Network/Protocol/Snmp/AgentX/Packet.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Protocol/Snmp/AgentX/Packet.hs
@@ -0,0 +1,66 @@
+module Network.Protocol.Snmp.AgentX.Packet ( 
+-- ** Packet 
+  Packet
+-- *** constructor
+, mkPacket
+-- *** lenses for  Packet
+, pdu
+, flags
+, tid
+, pid
+, sid
+-- *** types used in Packet
+, PDU(..)
+, PacketID
+, SessionID
+, TransactionID
+-- ** Flags 
+, Flags
+, InstanceRegistration 
+, NewIndex 
+, AnyIndex 
+, NonDefaultContext 
+, BigEndian 
+-- *** constructor
+, mkFlags
+-- *** lenses
+, instanceRegistration
+, newIndex
+, anyIndex
+, nonDefaultContext
+, bigEndian
+-- ** SearchRange 
+, SearchRange
+-- *** constructor
+, mkSearchRange
+-- *** lenses
+, startOID
+, endOID
+, include
+-- ** VarBind 
+, VarBind
+-- *** constructor
+, mkVarBind
+-- *** lenses
+, vboid
+, vbvalue
+-- ** other types
+, Context
+, SysUptime
+, Index
+, NonRepeaters
+, MaxRepeaters
+-- ** types for errors 
+, RError(..)
+, UndoError(..)
+, TestError(..)
+, CommitError(..)
+, TaggedError(..)
+-- ** helpers
+, bodySizeFromHeader
+, econvert
+)
+where
+
+import Network.Protocol.Snmp.AgentX.Packet.Types
+import Network.Protocol.Snmp.AgentX.Packet.Binary 
diff --git a/src/Network/Protocol/Snmp/AgentX/Packet/Binary.hs b/src/Network/Protocol/Snmp/AgentX/Packet/Binary.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Protocol/Snmp/AgentX/Packet/Binary.hs
@@ -0,0 +1,13 @@
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+module Network.Protocol.Snmp.AgentX.Packet.Binary 
+( bodySizeFromHeader )
+where
+
+import Data.Binary
+import Network.Protocol.Snmp.AgentX.Packet.Types ( Packet )
+import Network.Protocol.Snmp.AgentX.Packet.Get ( getPacket, bodySizeFromHeader )
+import Network.Protocol.Snmp.AgentX.Packet.Put ( putPacket )
+
+instance Binary Packet where
+    put = putPacket 
+    get = getPacket
diff --git a/src/Network/Protocol/Snmp/AgentX/Packet/Get.hs b/src/Network/Protocol/Snmp/AgentX/Packet/Get.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Protocol/Snmp/AgentX/Packet/Get.hs
@@ -0,0 +1,282 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Network.Protocol.Snmp.AgentX.Packet.Get 
+( getPacket
+, bodySizeFromHeader
+)
+where
+
+import Network.Protocol.Snmp.AgentX.Packet.Types ( bigEndian
+                                                 , nonDefaultContext
+                                                 , unTag
+                                                 , Flags
+                                                 , mkFlags
+                                                 , PDU(..)
+                                                 , VarBind
+                                                 , mkVarBind
+                                                 , SearchRange
+                                                 , mkSearchRange
+                                                 , Context(..)
+                                                 , Packet
+                                                 , mkPacket
+                                                 , econvert
+                                                 )
+import Network.Protocol.Snmp (Value(..), OID)
+
+import Data.ByteString (ByteString)
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Lazy as BL
+import Data.Binary hiding (get)
+import Data.Binary.Get 
+import Data.Bits.Bitwise (toListLE)
+import Data.Monoid ((<>))
+import Control.Applicative hiding (empty)
+import Data.Int
+import Data.Label
+
+getPacket :: Get Packet
+getPacket = do
+    version <- econvert `fmap` getWord8 
+    pduTag <- getWord8
+    flags <- decodeFlags <$> getWord8
+    _reserved <- getWord8
+    sid <- econvert `fmap` get32 flags 
+    tid <- econvert `fmap` get32 flags 
+    pid <- econvert `fmap` get32 flags 
+    bodySize <- get32 flags 
+    pdu <- parsePdu pduTag flags bodySize
+    return $ mkPacket version pdu flags sid tid pid
+
+decodeFlags :: Word8 -> Flags
+decodeFlags x =
+    let (i:n:a:nd:nb:_) = toListLE x
+    in mkFlags i n a nd nb
+
+get16 :: Flags -> Get Word16
+get16 f = case get bigEndian f of
+               True -> getWord16be
+               False -> getWord16le
+
+get32 :: Flags -> Get Word32
+get32 f = case get bigEndian f of
+               True -> getWord32be
+               False -> getWord32le
+
+get64 :: Flags -> Get Word64
+get64 f = case get bigEndian f of
+               True -> getWord64be
+               False -> getWord64le
+
+type Size = Word32
+type Include   = Bool
+
+getBool :: Get Bool
+getBool = do
+    x <- getWord8  
+    case x of
+         1 -> return True
+         0 -> return False
+         _ -> error "bad getBool"
+
+getOid :: Flags -> Get (OID, Include)
+getOid flags = do
+    nSubId <- getWord8
+    prefix <- getWord8
+    include <- getBool
+    _reserved <- getWord8
+    end <- sequence $ replicate (fromIntegral nSubId) (get32 flags)
+    case (nSubId, prefix) of
+         (0, 0) -> return ([], include)
+         (_, 0) -> return (map fromIntegral end, include)
+         (_, x) -> return ([1,3,6,1] <> map fromIntegral (fromIntegral x:end), include)
+
+getString :: Flags -> Get ByteString
+getString bo = do
+    l <- fromIntegral <$> get32 bo
+    let fullLength = l + (4 - l `rem` 4) `rem` 4
+    s <- getByteString fullLength
+    return $ B.take l s
+
+getContext :: Flags -> Get (Maybe Context)
+getContext f = case (get nonDefaultContext f) of
+                    False -> return Nothing
+                    True -> Just <$> Context <$> getString f
+
+getOidList :: Flags -> [OID] -> Get [OID]
+getOidList bo xs = do
+    (oi, _) <- getOid bo
+    isEnd <- isEmpty
+    if isEnd 
+       then return $ reverse (addOi oi xs)
+       else getOidList bo (addOi oi xs)
+    where
+    addOi [] xss = xss
+    addOi oi xss = oi:xss
+
+getSearchRange :: Flags -> Get SearchRange
+getSearchRange bo = do
+    (first, include) <- getOid bo
+    (second, _) <- getOid bo
+    return $ mkSearchRange first second include
+
+getSearchRangeList :: Flags -> [SearchRange] -> Get [SearchRange]
+getSearchRangeList bo xs = do
+    sr <- getSearchRange bo
+    isEnd <- isEmpty
+    if isEnd
+       then return $ reverse (sr:xs)
+       else getSearchRangeList bo (sr:xs)
+
+getValue :: Flags -> Word16 -> Get Value
+getValue _  0 = return ZeroDotZero
+getValue bo 2 = Integer . fromIntegral <$> get32 bo
+getValue bo 4 = String <$> getString bo
+getValue _  5 = return Zero
+getValue bo 6 = OI . fst <$> getOid bo
+getValue _  64 = do
+    a <- getWord8
+    b <- getWord8
+    c <- getWord8
+    d <- getWord8
+    return $ IpAddress a b c d
+getValue bo 65 = Counter32 <$> get32 bo
+getValue bo 66 = Gaude32 <$> get32 bo
+getValue bo 67 = TimeTicks <$> get32 bo
+getValue bo 68 = Opaque <$> getString bo
+getValue bo 70 = Counter64 <$> get64 bo
+getValue _  128 = return NoSuchObject
+getValue _  129 = return NoSuchInstance
+getValue _  130 = return EndOfMibView
+getValue _ v = error $ "getValue bad tag " ++ show v
+
+getVarBind :: Flags -> Get VarBind
+getVarBind bo = do
+    valueTag <- get16 bo 
+    _reserved <- getWord16be
+    (oi, _) <- getOid bo
+    v <- getValue bo valueTag 
+    return $ mkVarBind oi v
+
+getVarBindList :: Flags -> [VarBind] -> Get [VarBind]
+getVarBindList bo xs = do
+    vb <- getVarBind bo
+    isEnd <- isEmpty
+    if isEnd 
+       then return $ reverse (vb:xs)
+       else getVarBindList bo (vb:xs)
+
+parsePdu :: Word8 -> Flags -> Size -> Get PDU
+parsePdu t f s 
+    | t == 1 = do
+        -- Open
+        time <-  getWord8
+        _reserved <- getWord8
+        _reserved <- getWord8
+        _reserved <- getWord8
+        (o, _) <- getOid f
+        d <- getString f
+        return $ Open time o d
+    | t == 2 = do
+        -- Close
+        reason <- unTag <$> getWord8
+        _reserved <- getWord8
+        _reserved <- getWord8
+        _reserved <- getWord8
+        return $ Close reason
+    | t == 3 = do
+        -- Register
+        context <- getContext f
+        timeout <-  getWord8
+        priority <-  getWord8
+        rsid <- getWord8
+        _reserved <- getWord8
+        (oid, _) <- getOid f
+        case rsid of
+             0x00 -> return $ Register context timeout priority rsid oid Nothing
+             _ -> Register context timeout priority rsid oid . Just <$> get32 f
+    | t == 4 = do
+        -- Unregister
+        context <- getContext f
+        priority <-  getWord8
+        rsid <-  getWord8
+        _reserved <- getWord8
+        (oid, _) <- getOid f
+        case rsid of
+             0x00 -> return $ Unregister context priority rsid oid Nothing
+             _ -> Unregister context priority rsid oid . Just <$> get32 f
+    | t == 5 = do
+        -- Get
+        context <- getContext f
+        oil <- getOidList f []
+        return $ Get context oil
+    | t == 6 = do
+        -- GetNext
+        context <- getContext f
+        srl <- getSearchRangeList f []
+        return $ GetNext context srl
+    | t == 7 = do
+        -- GetBulk
+        context <- getContext f
+        nonRepeaters <- get16 f
+        maxRepeaters <- get16 f
+        srl <- getSearchRangeList f []
+        return $ GetBulk context nonRepeaters maxRepeaters srl
+    | t == 8 = do
+        -- TestSet
+        context <- getContext f
+        vbl <- getVarBindList f []
+        return $ TestSet context vbl
+    | t == 9 = return $ CommitSet 
+    | t == 10 = return $ UndoSet
+    | t == 11 = return $ CleanupSet
+    | t == 12 = do
+        -- Notify
+        context <- getContext f
+        vbl <- getVarBindList f []
+        return $ Notify context vbl
+    | t == 13 = do
+        -- Ping
+        context <- getContext f
+        return $ Ping context
+    | t == 14 = do
+        -- IndexAllocate
+        context <- getContext f
+        vbl <- getVarBindList f []
+        return $ IndexAllocate context vbl
+    | t == 15 = do
+        -- IndexDeallocate
+        context <- getContext f
+        vbl <- getVarBindList f []
+        return $ IndexDeallocate context vbl
+    | t == 16 = do
+        -- AddAgentCaps
+        context <- getContext f
+        (oi, _) <- getOid f
+        description <-  getString f
+        return $ AddAgentCaps context oi description
+    | t == 17 = do
+        -- RemoveAgentCaps
+        context <- getContext f
+        (oi, _) <- getOid f
+        return $ RemoveAgentCaps context oi
+    | t == 18 = do
+        -- Response
+        sysuptime <-  get32 f 
+        rerror <- unTag <$> get16 f 
+        index <- get16 f 
+        if (s == 8)
+           then return $ Response sysuptime rerror index []
+           else Response sysuptime rerror index <$> (getVarBindList f [])
+    | otherwise = error "parse pdu unknown tag"
+
+
+-- | get body size from header
+bodySizeFromHeader :: BL.ByteString -> Int64
+bodySizeFromHeader "" = 0
+bodySizeFromHeader bs =
+    let flags = decodeFlags (BL.index bs 2)
+        s = BL.drop 16 bs
+    in fromIntegral $ runGet (get32 flags) s
+
+
+
+
diff --git a/src/Network/Protocol/Snmp/AgentX/Packet/Put.hs b/src/Network/Protocol/Snmp/AgentX/Packet/Put.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Protocol/Snmp/AgentX/Packet/Put.hs
@@ -0,0 +1,250 @@
+{-# LANGUAGE TemplateHaskell, TypeOperators #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE RankNTypes #-}
+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
+module Network.Protocol.Snmp.AgentX.Packet.Put 
+( putPacket
+) where
+
+import Data.Binary.Put (putBuilder, Put)
+import Data.Binary.Builder
+import Data.Word
+import Data.Monoid
+import Data.Bits.Bitwise (fromListLE)
+import Control.Monad.State.Strict hiding (gets)
+import Data.ByteString (ByteString)
+import qualified Data.ByteString as B
+import Data.Label.Monadic
+import qualified Data.Label as DL
+import qualified Data.Label.Monadic as DLM
+import Control.Category ((.))
+import Prelude hiding ((.))
+
+import Network.Protocol.Snmp.AgentX.Packet.Types
+import Network.Protocol.Snmp (Value(..), OID)
+
+type Pack = State (Packet, Word32)
+
+(packet, bodySize) = $(DL.getLabel ''(,))
+
+putPacket :: Packet -> Put
+putPacket p = putBuilder . evalState pack $ (p, 0)
+       
+packBody :: Pack Builder 
+packBody = packsz =<< DLM.gets (pdu . packet)
+
+pack :: Pack Builder
+pack = do
+    !b <-  packBody
+    !s <-  packSize
+    p <-  DLM.gets (pdu . packet)
+    f <-  packFlags
+    sid' <- econvert `fmap` DLM.gets (sid . packet)
+    pid' <- econvert `fmap` DLM.gets (pid . packet)
+    tid' <- econvert `fmap` DLM.gets (tid . packet)
+    psid <- pack32 sid'
+    ppid <- pack32 pid'
+    ptid <- pack32 tid'
+    return $ singleton 1 <> singleton (tag p) <> f <> singleton 0 
+          <> psid <> ptid <> ppid <> s <> b
+
+packSize :: Pack Builder 
+packSize = do
+    s <- DLM.gets bodySize
+    pack32 s 
+
+
+fixSize :: Word32 -> Pack ()
+fixSize x = DLM.modify bodySize (+ x)
+
+packWord :: (w -> Builder) -> (w -> Builder) -> w -> Pack Builder
+packWord be le w = do
+    b <-  gets ( bigEndian . flags . packet )
+    if b then return (be w) else return (le w)
+
+pack32 :: Word32 -> Pack Builder
+pack32 = packWord putWord32be putWord32le 
+
+packFlags :: Pack Builder
+packFlags = do
+    flags' <-  gets (flags . packet )
+    let a = DL.get instanceRegistration flags'
+        b = DL.get newIndex flags'
+        c = DL.get anyIndex flags'
+        d = DL.get nonDefaultContext flags'
+        e = DL.get bigEndian flags'
+    return $ singleton $ fromListLE [a, b, c, d, e]
+
+packBool :: Bool -> Pack Builder
+packBool True  = return $ singleton 1
+packBool False = return $ singleton 0
+
+
+class SizedBuilder a where
+    packsz :: a -> Pack Builder
+
+instance SizedBuilder Word64 where
+    packsz w = fixSize 8 >> packWord putWord64be putWord64le w
+
+instance SizedBuilder Word32 where
+    packsz w = fixSize 4 >> packWord putWord32be putWord32le w
+
+instance SizedBuilder Word16 where
+    packsz w = fixSize 2 >> packWord putWord16be putWord16le w
+
+instance SizedBuilder Value where
+    packsz (Integer x) = packsz (fromIntegral x :: Word32)
+    packsz (Counter32 x) = packsz x 
+    packsz (Counter64 x) = packsz x
+    packsz (Gaude32 x) = packsz x
+    packsz (TimeTicks x) = packsz x
+    packsz (OI x) = packOID False x
+    packsz (String x) = packsz x
+    packsz (Opaque x) = packsz x
+    packsz (IpAddress a b c d) = packsz $ B.pack [a,b,c,d]
+    packsz _ = return empty
+
+instance SizedBuilder ByteString where
+    packsz bs = do
+        s <- packsz bsLen
+        fixSize bsLen
+        fixSize tailLen
+        return $ s <> fromByteString bs <> tailB
+        where
+        bsLen = fromIntegral $ B.length bs
+        tailB = fromByteString $ B.replicate (fromIntegral tailLen) 0x00
+        tailLen :: Word32
+        tailLen = (4 - bsLen `rem` 4) `rem` 4
+
+instance SizedBuilder Integer where
+    packsz x = packsz (fromIntegral x :: Word32)
+
+instance SizedBuilder VarBind where
+    packsz vb = do
+        t <-  packsz (tag value' :: Word16)
+        z <-  packsz (0 :: Word16)
+        oi <- packOID False oid'
+        val <-  packsz value'
+        return $ t <> z <> oi <> val
+        where
+        oid' = DL.get vboid vb
+        value' = DL.get vbvalue vb
+
+instance SizedBuilder (Maybe Context) where
+    packsz Nothing = fixContextFlags Nothing >> return empty
+    packsz mc@(Just (Context c)) = fixContextFlags mc >> packsz c
+
+instance SizedBuilder SearchRange where
+    packsz x = do
+        s <- packOID True (DL.get startOID x)
+        e <- packOID False (DL.get endOID x)
+        return $ s <> e
+
+fixContextFlags :: Maybe Context -> Pack ()
+fixContextFlags Nothing = DLM.modify (nonDefaultContext . flags . packet) (const False)
+fixContextFlags _       = DLM.modify (nonDefaultContext . flags . packet) (const True)
+
+type Include = Bool
+
+packOID :: Include -> OID -> Pack Builder
+packOID _ [] = fixSize 4 >> return (singleton 0 <> singleton 0 <> singleton 0 <> singleton 0)
+packOID i xs@(1:3:6:1:[]) = do -- Not clearly in rfc!!!
+    include' <- packBool i
+    fixSize 4
+    oi <- mapM packsz xs
+    return $ singleton 4 <> singleton 0 <> include' <> singleton 0 <> mconcat oi
+packOID i (1:3:6:1:ls) = do
+    include' <- packBool i
+    fixSize 4
+    oi <- mapM packsz (tail ls)
+    return $ singleton (fromIntegral (length ls - 1)) <> singleton (fromIntegral (head ls)) <> include' <> singleton 0 <> mconcat oi
+packOID i xs = do
+    include' <- packBool i
+    fixSize 4
+    oi <- mapM packsz xs
+    return $ singleton (fromIntegral (length xs)) <> singleton 0 <> include' <> singleton 0 <> mconcat oi
+
+instance SizedBuilder PDU where
+    packsz (Open t o d) = do
+        poid         <-  packOID False o
+        pdescription <-  packsz d 
+        fixSize 4
+        fixContextFlags Nothing
+        return $ (singleton t) <> singleton 0 <> singleton 0 <> singleton 0 <> poid <> pdescription
+    packsz (Close er) = do
+        fixSize 4
+        fixContextFlags Nothing
+        return $ singleton (tag er) <> singleton 0 <> singleton 0 <> singleton 0
+    packsz (Register mc t p rs oi mu) = do
+        pcontext <- packsz mc
+        up <-  case (rs, mu) of
+                     (0, _) -> return empty
+                     (_, Just x) -> packsz x
+                     _ -> error "packPacket Register"
+        poid <-  packOID False oi
+        fixSize 4
+        return $ pcontext <> singleton t <> singleton p <> singleton rs <> singleton 0 <> poid <> up
+    packsz (Unregister mc p rs oi mu) = do
+        pcontext <- packsz mc
+        up <- case (rs, mu) of
+                    (0, _) -> return empty
+                    (_, Just x) -> packsz x
+                    _ -> error "packPacket Unregister"
+        poid <-  packOID False oi
+        fixSize 4
+        return $ pcontext <> singleton 0 <> singleton p <> singleton rs <> singleton 0 <> poid <> up
+    packsz (Get mc []) = do
+        pcontext <-  packsz mc
+        return $ pcontext 
+    packsz (Get mc (x:xs)) = do
+        pcontext <- packsz mc
+        y <- packOID True x
+        ys <-  mapM (packOID False) xs
+        return $ pcontext <> y <> mconcat ys
+    packsz (GetNext mc xs) = do
+        pcontext <- packsz mc
+        ys <- mapM packsz xs
+        return $ pcontext <> mconcat ys
+    packsz (GetBulk mc nr mr xs) = do
+        pcontext <- packsz mc
+        nonrepeaters <- packsz nr
+        maxrepeaters <- packsz mr
+        ys <- mapM packsz xs
+        return $ pcontext <> nonrepeaters <> maxrepeaters <> mconcat ys
+    packsz (TestSet mc xs) = do
+        pcontext <- packsz mc
+        ys <- mapM packsz xs
+        return $ pcontext <> mconcat ys
+    packsz CommitSet = fixContextFlags Nothing >>  return empty
+    packsz UndoSet = fixContextFlags Nothing >>  return empty
+    packsz CleanupSet = fixContextFlags Nothing >>  return empty
+    packsz (Notify mc xs) = do
+        pcontext <- packsz mc
+        ys <- mapM packsz xs
+        return $ pcontext <> mconcat ys
+    packsz (Ping mc) = packsz mc
+    packsz (IndexAllocate mc xs) = do
+        pcontext <- packsz mc
+        ys <- mapM packsz xs
+        return $ pcontext <> mconcat ys
+    packsz (IndexDeallocate mc xs) = do
+        pcontext <- packsz mc
+        ys <- mapM packsz xs
+        return $ pcontext <> mconcat ys
+    packsz (AddAgentCaps mc o d) = do
+        pcontext <- packsz mc
+        oi <-  packOID False o
+        pdescription <- packsz d
+        return $ pcontext <> oi <> pdescription
+    packsz (RemoveAgentCaps mc o) = do
+        pcontext <- packsz mc
+        oi <- packOID False o
+        return $ pcontext <> oi
+    packsz (Response s re i xs) = do
+        psysuptime <- packsz s
+        perror    <-  packsz (tag re :: Word16)
+        pindex     <- packsz i
+        ys <- mapM packsz xs
+        fixContextFlags Nothing
+        return $ psysuptime <> perror <> pindex <> mconcat ys
diff --git a/src/Network/Protocol/Snmp/AgentX/Packet/Types.hs b/src/Network/Protocol/Snmp/AgentX/Packet/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Protocol/Snmp/AgentX/Packet/Types.hs
@@ -0,0 +1,406 @@
+{-# LANGUAGE TemplateHaskell, TypeOperators #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE ExistentialQuantification #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+module Network.Protocol.Snmp.AgentX.Packet.Types 
+( PDU(..)
+, Version
+, SessionID
+, TransactionID
+, PacketID
+, econvert
+, Context(..)
+, Tag(..)
+, TaggedError(..)
+, TestError(..)
+, CommitError(..)
+, RError(..)
+, UndoError(..)
+, SysUptime
+, Index
+, MaxRepeaters
+, NonRepeaters
+-- ** Packet
+, Packet
+-- *** constructor
+, mkPacket
+-- *** lenses
+, flags
+, version 
+, pdu
+, sid
+, pid
+, tid
+-- ** SearchRange 
+, SearchRange
+-- *** constructor
+, mkSearchRange
+-- *** lenses
+, startOID
+, endOID
+, include
+-- ** VarBind containt Value and OID
+, VarBind
+-- *** constructor
+, mkVarBind
+-- *** lenses
+, vboid
+, vbvalue
+-- ** Flags 
+, Flags
+-- *** constructor
+, mkFlags
+, InstanceRegistration 
+, NewIndex 
+, AnyIndex 
+, NonDefaultContext 
+, BigEndian 
+-- *** lenses
+, instanceRegistration
+, newIndex
+, anyIndex
+, nonDefaultContext
+, bigEndian
+)
+where
+
+import Data.Label
+
+import Data.Word
+import Data.ByteString (ByteString)
+import Data.String
+import Data.Default
+
+import Network.Protocol.Snmp (Value(..), OID)
+
+-- | protocol version (const 1 by default)
+newtype Version = Version Word8 deriving (Show, Eq, Enum, Bounded, Ord)
+
+-- | session id in header, rfc 2741, section 6.1
+newtype SessionID = SessionID Word32 deriving (Show, Eq, Enum, Bounded, Ord)
+
+-- | transaction id in header, rfc 2741, section 6.1
+newtype TransactionID = TransactionID Word32 deriving (Show, Eq, Ord, Enum, Bounded)
+
+-- | packet id in header, rfc 2741, section 6.1
+newtype PacketID = PacketID Word32 deriving (Show, Eq, Ord, Enum, Bounded)
+
+-- | helper for convert 
+econvert :: (Enum a, Enum b) => a -> b
+econvert = toEnum . fromEnum
+
+-- | rfc 2571 section 3.3.1, rfc 2741 section 6.1.1 Context
+newtype Context = Context ByteString deriving (Show, Ord, Eq, IsString)
+
+-- | rfc 2741, section 6.2.2, Error status in agentx-close-pdu
+data Reason = Other
+            | ParseError
+            | ProtocolError
+            | Timeouts
+            | Shutdown
+            | ByManager
+            deriving (Show, Eq)
+
+-- | rfc 2741, 6.2.16, Error status in agentx-response-pdu
+data RError = NoAgentXError
+            | OpenFailed
+            | NotOpen
+            | IndexWrongType
+            | IndexAlreadyAllocated
+            | IndexNonAvailable
+            | IndexNotAllocated
+            | UnsupportedContext
+            | DuplicateRegistration
+            | UnknownRegistration
+            | UnknownAgentCaps
+            | RParseError
+            | RequestDenied
+            | ProcessingError
+            deriving (Show, Eq)
+
+-- | result for testSetAIO (rfc 2741, section 7.2.4.1)
+data TestError 
+            = NoTestError
+            | TooBig
+            | NoSuchName
+            | BadValue
+            | ReadOnly
+            | GenError
+            | NoAccess
+            | WrongType
+            | WrongLength
+            | WrongEncoding
+            | WrongValue
+            | NoCreation
+            | InconsistentValue
+            | ResourceUnavailable
+            | NotWritable
+            | InconsistentName
+            deriving (Show, Eq)
+
+-- | result for commitSetAIO (rfc 2741, section 7.2.4.2)
+data CommitError
+            = NoCommitError
+            | CommitFailed
+            deriving (Show, Eq) 
+                  
+-- | result for undoSetAIO (rfc 2741, section 7.2.4.3)
+data UndoError
+            = NoUndoError
+            | UndoFailed
+            deriving (Show, Eq)
+          
+type Timeout = Word8
+type Priority = Word8
+type RangeSubid = Word8
+type Description = ByteString
+type MContext = Maybe Context
+type UpperBound = Maybe Word32
+type SysUptime = Word32
+type Index = Word16
+type NonRepeaters = Word16
+type MaxRepeaters = Word16
+
+-- | Error with Tag instance
+data TaggedError = forall a. (Show a, Eq a, Tag a Word16) => Tagged a 
+
+instance Tag TaggedError Word16 where
+    tag (Tagged x) = tag x
+    unTag x 
+      | x == 0 = Tagged NoAgentXError
+      | x > 0 && x <= 18 = Tagged (unTag x :: TestError)
+      | otherwise = Tagged (unTag x :: RError)
+
+instance Eq TaggedError where
+    x == y = (tag x :: Word16) == (tag y :: Word16)
+
+instance Show TaggedError where
+    show (Tagged a) = show a
+
+    
+-- | rfc 2741, section 6.2
+data PDU = Open Timeout OID Description -- ^ section 6.2.1
+         | Close  Reason                 -- ^ section 6.2.2
+         | Register MContext Timeout Priority RangeSubid OID UpperBound -- ^ section 6.2.3
+         | Unregister MContext Priority RangeSubid OID UpperBound -- ^ section 6.2.4
+         | Get MContext [OID] -- ^ section 6.2.5
+         | GetNext MContext [SearchRange] -- ^ section 6.2.6
+         | GetBulk MContext NonRepeaters MaxRepeaters [SearchRange] -- ^ section 6.2.7
+         | TestSet MContext [VarBind] -- ^ section 6.2.8
+         | CommitSet -- ^ section 6.2.9
+         | UndoSet -- ^ section 6.2.9
+         | CleanupSet -- ^ section 6.2.9
+         | Notify MContext [VarBind] -- ^ section 6.2.10
+         | Ping MContext -- ^ section 6.2.11
+         | IndexAllocate MContext [VarBind] -- ^ section 6.2.12
+         | IndexDeallocate MContext [VarBind] -- ^ section 6.2.13
+         | AddAgentCaps MContext OID Description -- ^ section 6.2.14
+         | RemoveAgentCaps MContext OID  -- ^ section 6.2.15
+         | Response SysUptime TaggedError Index [VarBind] -- ^ section 6.2.16
+         deriving (Show, Eq)
+
+
+-- | class for convert Errors to Word* and Word* to Errors
+class Tag a b where
+    tag :: a -> b
+    unTag :: b -> a
+
+-- | Packet type, describe agentx packet.
+data Packet = Packet 
+  { _version :: Version 
+  , _pdu     :: PDU 
+  , _flags   :: Flags 
+  , _sid     :: SessionID 
+  , _tid     :: TransactionID 
+  , _pid     :: PacketID 
+  } deriving Show
+
+mkPacket :: Version -> PDU -> Flags -> SessionID -> TransactionID -> PacketID -> Packet
+mkPacket = Packet
+
+-- | header flags, rfc 2741, section 6.1
+data Flags = Flags 
+  { _instanceRegistration :: InstanceRegistration 
+  , _newIndex             :: NewIndex
+  , _anyIndex             :: AnyIndex
+  , _nonDefaultContext    :: NonDefaultContext
+  , _bigEndian            :: BigEndian
+  } deriving (Show)
+
+type InstanceRegistration = Bool
+type NewIndex = Bool
+type AnyIndex = Bool
+type NonDefaultContext = Bool
+type BigEndian = Bool
+
+mkFlags :: InstanceRegistration -> NewIndex -> AnyIndex -> NonDefaultContext -> BigEndian -> Flags
+mkFlags = Flags
+
+-- | used for getnext and other requests (rfc 2741, section5.2 )
+data SearchRange = SearchRange 
+  { _startOID :: OID 
+  , _endOID   :: OID
+  , _include  :: Bool
+  } deriving (Show, Eq)
+
+-- | create SearchRange
+mkSearchRange :: OID -> OID -> Bool -> SearchRange
+mkSearchRange = SearchRange
+
+-- | containt oid and value (rfc 2741, section 5.4)
+data VarBind = VarBind 
+  { _vboid   :: OID 
+  , _vbvalue :: Value 
+  } deriving (Show, Eq)
+
+-- | constructor for VarBind
+mkVarBind :: OID -> Value -> VarBind
+mkVarBind = VarBind 
+
+mkLabels [''Packet, ''Flags, ''VarBind, ''SearchRange ]
+
+instance Tag Reason Word8 where
+    tag Other         = 1
+    tag ParseError    = 2
+    tag ProtocolError = 3
+    tag Timeouts      = 4
+    tag Shutdown      = 5
+    tag ByManager     = 6
+    unTag 1 = Other        
+    unTag 2 = ParseError   
+    unTag 3 = ProtocolError
+    unTag 4 = Timeouts     
+    unTag 5 = Shutdown     
+    unTag 6 = ByManager    
+    unTag _ = error "unknown reasonFromTag"
+
+instance Tag RError Word16 where
+    tag NoAgentXError         = 0
+    tag OpenFailed            = 256
+    tag NotOpen               = 257
+    tag IndexWrongType        = 258
+    tag IndexAlreadyAllocated = 259
+    tag IndexNonAvailable     = 260
+    tag IndexNotAllocated     = 261
+    tag UnsupportedContext    = 262
+    tag DuplicateRegistration = 263
+    tag UnknownRegistration   = 264
+    tag UnknownAgentCaps      = 265
+    tag RParseError           = 266
+    tag RequestDenied         = 267
+    tag ProcessingError       = 268
+    unTag 0   = NoAgentXError        
+    unTag 256 = OpenFailed           
+    unTag 257 = NotOpen              
+    unTag 258 = IndexWrongType       
+    unTag 259 = IndexAlreadyAllocated
+    unTag 260 = IndexNonAvailable    
+    unTag 261 = IndexNotAllocated    
+    unTag 262 = UnsupportedContext   
+    unTag 263 = DuplicateRegistration
+    unTag 264 = UnknownRegistration  
+    unTag 265 = UnknownAgentCaps     
+    unTag 266 = RParseError          
+    unTag 267 = RequestDenied        
+    unTag 268 = ProcessingError      
+    unTag _   = error "bad rerror"        
+
+instance Tag TestError Word16 where
+    tag NoTestError           = 0
+    tag TooBig                = 1
+    tag NoSuchName            = 2
+    tag BadValue              = 3
+    tag ReadOnly              = 4
+    tag GenError              = 5
+    tag NoAccess              = 6
+    tag WrongType             = 7
+    tag WrongLength           = 8
+    tag WrongEncoding         = 9
+    tag WrongValue            = 10
+    tag NoCreation            = 11
+    tag InconsistentValue     = 12
+    tag ResourceUnavailable   = 13
+    tag NotWritable           = 17
+    tag InconsistentName      = 18
+    unTag 0   = NoTestError
+    unTag 1   = TooBig                
+    unTag 2   = NoSuchName            
+    unTag 3   = BadValue              
+    unTag 4   = ReadOnly              
+    unTag 5   = GenError            
+    unTag 6   = NoAccess            
+    unTag 7   = WrongType           
+    unTag 8   = WrongLength         
+    unTag 9   = WrongEncoding       
+    unTag 10  = WrongValue          
+    unTag 11  = NoCreation          
+    unTag 12  = InconsistentValue   
+    unTag 13  = ResourceUnavailable 
+    unTag 17  = NotWritable         
+    unTag 18  = InconsistentName    
+    unTag _   = error "unknown tag in TestError"
+
+instance Tag CommitError Word16 where
+    tag NoCommitError = 0 
+    tag CommitFailed  = 14
+    unTag 0 = NoCommitError
+    unTag 14 = CommitFailed 
+    unTag _ = error "unknown tag in CommitError"
+
+instance Tag UndoError Word16 where
+    tag NoUndoError           = 0
+    tag UndoFailed            = 15
+    unTag 0   = NoUndoError
+    unTag 15  = UndoFailed    
+    unTag _   = error "unknown tag in UndoError"
+
+
+
+instance Tag PDU Word8 where
+    tag Open{}            = 1
+    tag Close{}           = 2
+    tag Register{}        = 3
+    tag Unregister{}      = 4
+    tag Get{}             = 5
+    tag GetNext{}         = 6
+    tag GetBulk{}         = 7
+    tag TestSet{}         = 8
+    tag CommitSet{}       = 9
+    tag UndoSet{}         = 10
+    tag CleanupSet{}      = 11
+    tag Notify{}          = 12
+    tag Ping{}            = 13
+    tag IndexAllocate{}   = 14
+    tag IndexDeallocate{} = 15
+    tag AddAgentCaps{}    = 16
+    tag RemoveAgentCaps{} = 17
+    tag Response{}        = 18
+    unTag _ = undefined
+
+instance Tag Value Word16 where
+-- TODO check zerodotzero 
+    tag (ZeroDotZero)       = 0
+    tag (Integer _)         = 2
+    tag (String _)          = 4
+    tag (Zero)              = 5
+    tag (OI _)              = 6
+    tag (IpAddress _ _ _ _) = 64
+    tag (Counter32 _)       = 65
+    tag (Gaude32 _)         = 66
+    tag (TimeTicks _)       = 67
+    tag (Opaque _)          = 68
+    tag (Counter64 _)       = 70
+    tag (NoSuchObject)      = 128
+    tag (NoSuchInstance)    = 129
+    tag (EndOfMibView)      = 130
+    unTag _ = undefined
+
+instance Default Flags where
+    def = mkFlags False False False False False
+
+instance Default Version where
+    def = Version 1
+
