diff --git a/pykd/pykd_vc120.vcxproj b/pykd/pykd_vc120.vcxproj
index 92ddd55..e656bf6 100644
--- a/pykd/pykd_vc120.vcxproj
+++ b/pykd/pykd_vc120.vcxproj
@@ -590,6 +590,7 @@
     <ClInclude Include="pymodule.h" />
     <ClInclude Include="pyprocess.h" />
     <ClInclude Include="pysymengine.h" />
+    <ClInclude Include="pytagged.h" />
     <ClInclude Include="pythreadstate.h" />
     <ClInclude Include="pytypedvar.h" />
     <ClInclude Include="pytypeinfo.h" />
@@ -623,6 +624,7 @@
     </ClCompile>
     <ClCompile Include="pymodule.cpp" />
     <ClCompile Include="pyprocess.cpp" />
+    <ClCompile Include="pytagged.cpp" />
     <ClCompile Include="pytypedvar.cpp" />
     <ClCompile Include="pytypeinfo.cpp" />
     <ClCompile Include="stdafx.cpp">
diff --git a/pykd/pykd_vc120.vcxproj.filters b/pykd/pykd_vc120.vcxproj.filters
index 464d7d1..3f4b9b1 100644
--- a/pykd/pykd_vc120.vcxproj.filters
+++ b/pykd/pykd_vc120.vcxproj.filters
@@ -81,6 +81,9 @@
     <ClInclude Include="pydataaccess.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="pytagged.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="stdafx.cpp">
@@ -248,6 +251,9 @@
     <ClCompile Include="pyprocess.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="pytagged.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <None Include="pykd.def">
diff --git a/pykd/pymod.cpp b/pykd/pymod.cpp
index a2218c4..624168a 100644
--- a/pykd/pymod.cpp
+++ b/pykd/pymod.cpp
@@ -20,6 +20,7 @@
 #include "pytypeinfo.h"
 #include "pycpucontext.h"
 #include "pyprocess.h"
+#include "pytagged.h"
 
 using namespace pykd;
 
@@ -597,6 +598,12 @@ BOOST_PYTHON_MODULE( pykd )
     python::def( "removeSyntheticSymbol", pykd::removeSyntheticSymbol,
         "The removeSyntheticSymbol function removes a synthetic symbol from a module in the current proces" );
 
+    // secondary callback data
+    python::def("enumTagged", pykd::enumTagged,
+        "Return the list of secondary callback data IDs (as a strings)" );
+    python::def("loadTaggedBuffer", pykd::loadTaggedBuffer,
+        "Read the buffer of secondary callback data by ID" );
+
     python::class_<kdlib::NumBehavior, boost::noncopyable>( "numVariant", "numVariant", python::no_init )
         .def("__init__", python::make_constructor(&NumVariantAdaptor::getVariant) )
         .def( "__eq__", &NumVariantAdaptor::eq )
diff --git a/pykd/pytagged.cpp b/pykd/pytagged.cpp
new file mode 100644
index 0000000..a20b8d5
--- /dev/null
+++ b/pykd/pytagged.cpp
@@ -0,0 +1,76 @@
+
+#include "stdafx.h"
+
+#include "pytagged.h"
+#include "kdlib\tagged.h"
+#include "kdlib\exceptions.h"
+
+#include "pythreadstate.h"
+#include "stladaptor.h"
+
+#include <rpc.h>
+#pragma comment(lib, "Rpcrt4.lib")
+
+
+namespace pykd {
+
+
+void __declspec(noreturn) throwRpcStatus( const std::string  &functionName, RPC_STATUS status ) 
+{
+    std::stringstream sstr;
+    sstr << "Call " << functionName << " failed\n";
+    sstr << "RPC_STATUS 0x" << std::hex << status;
+    throw kdlib::DbgException( sstr.str() );
+}
+
+python::list enumTagged()
+{
+    std::list<kdlib::TaggedId> ids;
+    {
+        AutoRestorePyState pystate;
+        ids = std::move( kdlib::enumTagged() );
+    }
+
+    python::list result;
+
+    for (const auto &id : ids)
+    {
+        RPC_WSTR id_str = nullptr;
+        auto status = ::UuidToString(&id, &id_str);
+        if (RPC_S_OK != status)
+            throwRpcStatus("UuidToString", status);
+
+        const auto stringFree = 
+            [](RPC_WSTR *str)
+            {
+                auto status = ::RpcStringFree(str);
+                if (RPC_S_OK != status)
+                    throwRpcStatus("RpcStringFree", status);
+            };
+        std::unique_ptr<RPC_WSTR, decltype(stringFree)> freeGuard{&id_str, stringFree};
+
+        result.append( std::wstring(reinterpret_cast<wchar_t *>(id_str)) );
+    }
+    return result;
+}
+
+python::list loadTaggedBuffer(const std::wstring &id_str)
+{
+    const auto rcp_str = 
+        reinterpret_cast<RPC_WSTR>( const_cast<wchar_t *>(id_str.c_str()) );
+    kdlib::TaggedId id;
+    auto status = ::UuidFromString(rcp_str, &id);
+    if (RPC_S_OK != status)
+        throwRpcStatus("UuidFromString", status);
+
+
+    kdlib::TaggedBuffer buff;
+    {
+        AutoRestorePyState pystate;
+        buff = std::move( kdlib::loadTaggedBuffer(id) );
+    }
+
+    return vectorToList(buff);
+}
+
+}   // namespace pykd
diff --git a/pykd/pytagged.h b/pykd/pytagged.h
new file mode 100644
index 0000000..d688e51
--- /dev/null
+++ b/pykd/pytagged.h
@@ -0,0 +1,12 @@
+
+#pragma once
+
+namespace python = boost::python;
+
+namespace pykd {
+
+python::list enumTagged();
+
+python::list loadTaggedBuffer(const std::wstring &id_str);
+
+}   // namespace pykd
diff --git a/test/scripts/pykdtest.py b/test/scripts/pykdtest.py
index 810f0ee..df433b9 100644
--- a/test/scripts/pykdtest.py
+++ b/test/scripts/pykdtest.py
@@ -27,6 +27,7 @@ import excepttest
 import targetprocess
 import ehloadtest
 import synsymtest
+import taggedtest
 
 pykd.initialize()
 
@@ -65,6 +66,7 @@ def getTestSuite( singleName = "" ):
                 unittest.TestLoader().loadTestsFromTestCase( mspdbtest.MsPdbTest ),
                 unittest.TestLoader().loadTestsFromTestCase( targetprocess.ProcessTest ),
                 unittest.TestLoader().loadTestsFromTestCase( ehloadtest.EhLoadTest ),
+                unittest.TestLoader().loadTestsFromTestCase( taggedtest.TaggedTest ),
 
                 #unittest.TestLoader().loadTestsFromTestCase( excepttest.ExceptionTest ),
             ] ) 
diff --git a/test/scripts/pykdtest.pyproj b/test/scripts/pykdtest.pyproj
index 0708c66..61f3761 100644
--- a/test/scripts/pykdtest.pyproj
+++ b/test/scripts/pykdtest.pyproj
@@ -50,6 +50,7 @@
     <Compile Include="regtest.py" />
     <Compile Include="stacktest.py" />
     <Compile Include="synsymtest.py" />
+    <Compile Include="taggedtest.py" />
     <Compile Include="target.py" />
     <Compile Include="targetprocess.py" />
     <Compile Include="testutils.py" />
diff --git a/test/scripts/taggedtest.py b/test/scripts/taggedtest.py
new file mode 100644
index 0000000..49d7a4a
--- /dev/null
+++ b/test/scripts/taggedtest.py
@@ -0,0 +1,31 @@
+import unittest
+import pykd
+import sys
+import os
+
+class TaggedTest(unittest.TestCase):
+    def setUp(self):
+        dump_file = os.path.join( os.path.dirname(sys.argv[0]),
+                                  r"..\..\kdlibcpp\kdlib\tests\dumps\win8_x64_mem.cab" )
+        self.dump_id = pykd.loadDump( dump_file )
+
+        self._existing_id = "D03DC06F-D88E-44C5-BA2A-FAE035172D19"
+        self._non_existing_id = "88597A32-1493-41CA-BF87-2A950DF4CEE0"
+
+    def tearDown(self):
+        pykd.closeDump( self.dump_id )
+
+    def testEnum(self):
+        ids = pykd.enumTagged()
+
+        self.assertTrue( self._existing_id.lower() in [i.lower() for i in ids] )
+
+        self.assertFalse( self._non_existing_id.lower() in [i.lower() for i in ids] )
+
+
+    def testLoadBuffer(self):
+        buff = pykd.loadTaggedBuffer( self._existing_id )
+        self.assertEqual( len(buff), 0x410 )
+
+        self.assertRaises( pykd.DbgException, pykd.loadTaggedBuffer, self._non_existing_id )
+