diff --git a/pykd/dbgengine.cpp b/pykd/dbgengine.cpp
index de5dff0..0992454 100644
--- a/pykd/dbgengine.cpp
+++ b/pykd/dbgengine.cpp
@@ -5,27 +5,10 @@
 
 #include "dbgengine.h"
 #include "variant.h"
+#include "pystate.h"
 
 namespace pykd {
 
-class AutoRestorePyState 
-{
-public:
-
-    AutoRestorePyState() 
-    {
-        m_state =  PyEval_SaveThread();
-    }
-
-    ~AutoRestorePyState() 
-    {
-        PyEval_RestoreThread( m_state );
-    }
-
-private:
-
-    PyThreadState*    m_state;
-};
 
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/pykd/pykd.vcxproj b/pykd/pykd.vcxproj
index 6d860c1..99977eb 100644
--- a/pykd/pykd.vcxproj
+++ b/pykd/pykd.vcxproj
@@ -239,6 +239,8 @@
     <ClInclude Include="eventhandler.h" />
     <ClInclude Include="memaccess.h" />
     <ClInclude Include="module.h" />
+    <ClInclude Include="pydbgio.h" />
+    <ClInclude Include="pystate.h" />
     <ClInclude Include="stdafx.h" />
     <ClInclude Include="stladaptor.h" />
     <ClInclude Include="targetver.h" />
diff --git a/pykd/pykd.vcxproj.filters b/pykd/pykd.vcxproj.filters
index 874c683..705f138 100644
--- a/pykd/pykd.vcxproj.filters
+++ b/pykd/pykd.vcxproj.filters
@@ -54,6 +54,12 @@
     <ClInclude Include="cpucontext.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="pydbgio.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="pystate.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="stdafx.cpp">
diff --git a/pykd/pymod.cpp b/pykd/pymod.cpp
index ef04f35..dc87732 100644
--- a/pykd/pymod.cpp
+++ b/pykd/pymod.cpp
@@ -15,6 +15,7 @@
 #include "windbgext.h"
 #include "eventhandler.h"
 #include "cpucontext.h"
+#include "pydbgio.h"
 
 using namespace pykd;
 
@@ -132,10 +133,14 @@ BOOST_PYTHON_MODULE( pykd )
         "Print out string and insert end of line symbol. If dml = True string is printed with dml highlighting ( only for windbg )" ) );
 
     // Python debug output console helper classes
-    python::class_<kdlib::DbgOut, boost::noncopyable >( "dout", "dout", python::no_init )
-        .def( "write", &kdlib::DbgOut::write );
-    python::class_<kdlib::DbgIn, boost::noncopyable>( "din", "din", python::no_init )
-        .def( "readline", &kdlib::DbgIn::readline );
+    python::class_<DbgOut>( "dout", "dout", python::no_init )
+        .def( "write", &DbgOut::write )
+        .def( "flush", &DbgOut::flush )
+        .add_property( "encoding", &DbgOut::encoding );
+
+    python::class_<DbgIn>( "din", "din", python::no_init )
+        .def( "readline", &DbgIn::readline )
+        .add_property( "encoding", &DbgIn::encoding );
 
    // system properties
     python::def( "ptrSize", &kdlib::ptrSize,
diff --git a/pykd/windbgext.cpp b/pykd/windbgext.cpp
index 2c31a65..2a5ebd0 100644
--- a/pykd/windbgext.cpp
+++ b/pykd/windbgext.cpp
@@ -9,6 +9,7 @@ namespace python = boost::python;
 
 #include "windbgext.h"
 #include "dbgexcept.h"
+#include "pydbgio.h"
 
 using namespace kdlib;
 using namespace kdlib::windbg;
@@ -32,19 +33,34 @@ void PykdExt::setUp()
 
     PyImport_AppendInittab("pykd", initpykd ); 
 
-    Py_Initialize();
-
     PyEval_InitThreads();
 
-    python::import( "pykd" );
+    Py_Initialize();
+
+    python::object  main = boost::python::import("__main__");
+
+    python::object  main_namespace = main.attr("__dict__");
+
+    python::object  pykd = python::import( "pykd" );
+
+   // ������ ������ from pykd import *
+    python::dict     pykd_namespace( pykd.attr("__dict__") ); 
+
+    python::list     iterkeys( pykd_namespace.iterkeys() );
+
+    for (int i = 0; i < boost::python::len(iterkeys); i++)
+    {
+        std::string     key = boost::python::extract<std::string>(iterkeys[i]);
+
+        main_namespace[ key ] = pykd_namespace[ key ];
+    }
 
     // ��������������� ����������� ������� ��
     python::object       sys = python::import("sys");
 
-    sys.attr("stdout") = python::ptr( dbgout  );
-    sys.attr("stderr") = python::ptr( dbgout );
-    sys.attr("stdin") = python::ptr( dbgin );
-
+    sys.attr("stdout") = python::object( pykd::DbgOut() );
+    sys.attr("stderr") = python::object( pykd::DbgOut() );
+    sys.attr("stdin") = python::object( pykd::DbgIn() );
 
     python::list pathList(sys.attr("path"));
 
@@ -52,12 +68,16 @@ void PykdExt::setUp()
 
     for (python::ssize_t i = 0; i < n ; i++) 
         m_paths.push_back(boost::python::extract<std::string>(pathList[i]));
+
+    m_pyState = PyEval_SaveThread();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
 void PykdExt::tearDown()
 {
+    PyEval_RestoreThread( m_pyState );
+
     Py_Finalize();
 
     WindbgExtension::tearDown();
@@ -67,45 +87,157 @@ void PykdExt::tearDown()
 
 KDLIB_EXT_COMMAND_METHOD_IMPL(PykdExt, py)
 {
-    const ArgsList&   args = getArgs();
+    ArgsList   args = getArgs();
+
+    bool  global = false;
+    bool  local = false;
+    bool  clean = false;
+ 
+    ArgsList::iterator  foundArg;
+
+    foundArg = std::find( args.begin(), args.end(), "-h" );
+    if ( foundArg !=  args.end() )
+    {
+        printUsage();
+        return;
+    }
+
+    foundArg = std::find( args.begin(), args.end(), "--help" );
+    if ( foundArg !=  args.end() )
+    {
+        printUsage();
+        return;
+    }
+
+    foundArg = std::find( args.begin(), args.end(), "-g" );
+    if ( foundArg != args.end() )
+    {
+        global = true;
+        args.erase( foundArg );
+    }
+
+    foundArg = std::find( args.begin(), args.end(), "--global" );
+    if ( foundArg != args.end() )
+    {
+        global = true;
+        args.erase( foundArg );
+    }
+
+    foundArg = std::find( args.begin(), args.end(), "-l" );
+    if ( foundArg != args.end() )
+    {
+        local = true;
+        args.erase( foundArg );
+    }
+
+    foundArg = std::find( args.begin(), args.end(), "--local" );
+    if ( foundArg != args.end() )
+    {
+        local = true;
+        args.erase( foundArg );
+    }
+
+    if ( global & local )
+    {
+       eprintln( L"-g(--global) and -l(--local) cannot be set together" );
+       return;
+    }
+
+    std::string  scriptFileName;
+    if ( args.size() > 0 )
+    {
+       scriptFileName  = getScriptFileName( args[0] );
+
+        if ( scriptFileName.empty() )
+        {
+            eprintln( L"script file not found" );
+            return;
+        }
+
+        global = !(global | local ) ? false : global ; //set local by default
+    }
+    else
+    {
+        global = !(global | local ) ? true : global ; //set global by default
+    }
+
+    PyThreadState   *localState = NULL;
+    PyThreadState   *globalState = NULL;
+
+    PyEval_RestoreThread( m_pyState );
+
+    if ( !global )
+    {
+        globalState = PyThreadState_Swap( NULL );
+
+        localState = Py_NewInterpreter();
+
+        python::object       sys = python::import("sys");
+
+        sys.attr("stdout") = python::object( pykd::DbgOut() );
+        sys.attr("stderr") = python::object( pykd::DbgOut() );
+        sys.attr("stdin") = python::object( pykd::DbgIn() );
+    }
 
     if ( args.size() == 0 )
     {
         startConsole();
-        return;
     }
-
-    std::string  scriptFileName = getScriptFileName( args[0] );
-
-    if ( scriptFileName.empty() )
+    else
     {
-        eprintln( L"script file not found" );
-        return;
+        std::string  scriptFileName = getScriptFileName( args[0] );
+
+        // �������������� ����������� ���������
+        char  **pythonArgs = new char* [ args.size() ];
+
+        pythonArgs[0] = const_cast<char*>(scriptFileName.c_str());
+
+        for ( size_t  i = 1; i < args.size(); ++i )
+            pythonArgs[i] = const_cast<char*>( args[i].c_str() );
+
+        PySys_SetArgv( (int)args.size(), pythonArgs );
+
+        delete[]  pythonArgs;
+
+        // �������� ������ � ����������� ���� ( ����� ��� ������ exec_file )
+        python::object  main =  python::import("__main__");
+
+        python::object  global(main.attr("__dict__"));
+
+        try {
+            PykdInterruptWatch  interruptWatch;
+            python::exec_file( scriptFileName.c_str(), global );
+        }
+        catch( python::error_already_set const & )
+        {
+            printException();
+        }
     }
 
-    // �������������� ����������� ���������
-    char  **pythonArgs = new char* [ args.size() ];
-
-    for ( size_t  i = 0; i < args.size(); ++i )
-        pythonArgs[i] = const_cast<char*>( args[i].c_str() );
-
-    PySys_SetArgv( (int)args.size(), pythonArgs );
-
-    delete[]  pythonArgs;
-
-    // �������� ������ � ����������� ���� ( ����� ��� ������ exec_file )
-    python::object  main =  python::import("__main__");
-
-    python::object  global(main.attr("__dict__"));
-
-    try {
-        PykdInterruptWatch  interruptWatch;
-        python::exec_file( scriptFileName.c_str(), global );
-    }
-    catch( python::error_already_set const & )
+    if ( !global )
     {
-        printException();
+        PyInterpreterState  *interpreter = localState->interp;
+
+        while( interpreter->tstate_head != NULL )
+        {
+            PyThreadState   *threadState = (PyThreadState*)(interpreter->tstate_head);
+
+            PyThreadState_Clear(threadState);
+
+            PyThreadState_Swap( NULL );
+
+            PyThreadState_Delete(threadState);
+        }
+    
+        PyInterpreterState_Clear(interpreter);
+
+        PyInterpreterState_Delete(interpreter);
+
+        PyThreadState_Swap( globalState );
     }
+
+    m_pyState = PyEval_SaveThread();
+
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -130,6 +262,16 @@ void PykdExt::startConsole()
 
 ///////////////////////////////////////////////////////////////////////////////
 
+void PykdExt::printUsage()
+{
+    dprintln( L"usage: !py [options] [file]" );
+    dprintln( L"Options:" );
+    dprintln( L"-g --global  : run code in the common namespace" );
+    dprintln( L"-l --local   : run code in the isolate namespace" );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
 std::string PykdExt::getScriptFileName( const std::string &scriptName )
 {
     bool fileHasPyExt = false;
diff --git a/pykd/windbgext.h b/pykd/windbgext.h
index b0bb411..876f279 100644
--- a/pykd/windbgext.h
+++ b/pykd/windbgext.h
@@ -18,6 +18,8 @@ private:
 
     void startConsole();
 
+    void printUsage();
+
     virtual void setUp();
 
     virtual void tearDown();
@@ -25,6 +27,8 @@ private:
     std::string getScriptFileName( const std::string &scriptName );
 
     std::vector<std::string> m_paths;
+
+    PyThreadState  *m_pyState;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/snippets/ipython.py b/snippets/ipython.py
new file mode 100644
index 0000000..c1e9109
--- /dev/null
+++ b/snippets/ipython.py
@@ -0,0 +1,22 @@
+from IPython.config.loader import Config
+from IPython.terminal.embed import InteractiveShellEmbed
+
+from IPython.terminal.interactiveshell import TerminalInteractiveShell
+
+import pykd
+
+cfg = Config()
+
+cfg.InteractiveShell.colors = 'NoColor'
+cfg.InteractiveShell.readline_use = False
+cfg.InteractiveShell.autoindent = True
+
+cfg.PromptManager.in_template = 'In <\\#>: '
+cfg.PromptManager.in2_template = '   .\\D.: '
+cfg.PromptManager.out_template = 'Out<\\#>: '
+
+cfg.InteractiveShellApp.extensions = [ 'pykdmagic' ]
+
+ipshell = InteractiveShellEmbed(config=cfg)
+
+ipshell()    
\ No newline at end of file