diff --git a/smtk/attribute/operators/Associate.cxx b/smtk/attribute/operators/Associate.cxx
index b1dc3903e8d97c7d7fd2800a2f46b8b597d5fb29..fa3af6258d9600f4b5102715eb36469013c05de0 100644
--- a/smtk/attribute/operators/Associate.cxx
+++ b/smtk/attribute/operators/Associate.cxx
@@ -24,7 +24,7 @@ namespace smtk
 namespace attribute
 {
 
-Associate::Result Associate::operateInternal()
+Associate::Result Associate::operateInternal(Context ctx)
 {
   // Access the attribute resource to associate.
   smtk::attribute::Resource::Ptr resource = std::dynamic_pointer_cast<smtk::attribute::Resource>(
diff --git a/smtk/attribute/operators/Associate.h b/smtk/attribute/operators/Associate.h
index 68a6248d698af95df26d05e92e3ed650d2233f18..a8bea2b4020b803d7ee4ed7091f5c32547e7f42e 100644
--- a/smtk/attribute/operators/Associate.h
+++ b/smtk/attribute/operators/Associate.h
@@ -31,7 +31,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 } // namespace attribute
diff --git a/smtk/attribute/operators/Dissociate.cxx b/smtk/attribute/operators/Dissociate.cxx
index 39ad178d465c755ac47805c2d0f8c46a361c7a13..caaa108ac38c1a656258024c7b452073a1a38765 100644
--- a/smtk/attribute/operators/Dissociate.cxx
+++ b/smtk/attribute/operators/Dissociate.cxx
@@ -24,7 +24,7 @@ namespace smtk
 namespace attribute
 {
 
-Dissociate::Result Dissociate::operateInternal()
+Dissociate::Result Dissociate::operateInternal(Context ctx)
 {
   // Access the attribute resource to dissociate.
   smtk::attribute::Resource::Ptr resource = std::dynamic_pointer_cast<smtk::attribute::Resource>(
diff --git a/smtk/attribute/operators/Dissociate.h b/smtk/attribute/operators/Dissociate.h
index 3b4835a88e7c208a44c564cf40f1601c7b16bef2..44e9eda8462f9b8f5f61f96d8c0e555f56bc36c8 100644
--- a/smtk/attribute/operators/Dissociate.h
+++ b/smtk/attribute/operators/Dissociate.h
@@ -31,7 +31,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 } // namespace attribute
diff --git a/smtk/attribute/operators/Export.cxx b/smtk/attribute/operators/Export.cxx
index 72454b8c5627688fc949ad50e4b5e94385172435..6a72327389105a06497a227c700b84f8ba3925fa 100644
--- a/smtk/attribute/operators/Export.cxx
+++ b/smtk/attribute/operators/Export.cxx
@@ -30,7 +30,7 @@ namespace smtk
 namespace attribute
 {
 
-Export::Result Export::operateInternal()
+Export::Result Export::operateInternal(Context ctx)
 {
   // Access the file name.
   std::string outputfile = this->parameters()->findFile("filename")->value();
diff --git a/smtk/attribute/operators/Export.h b/smtk/attribute/operators/Export.h
index 5da70de5dd1dbd06445bf902853107cf8d6d8c03..2609a3ace241c53c484b1baef229435c0547faa6 100644
--- a/smtk/attribute/operators/Export.h
+++ b/smtk/attribute/operators/Export.h
@@ -28,7 +28,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 } // namespace attribute
diff --git a/smtk/attribute/operators/Import.cxx b/smtk/attribute/operators/Import.cxx
index f02396491f0c9462647d2a8e7a57f86716b24407..e9ddf7e834928109dc337e6adfd9f615f4535cea 100644
--- a/smtk/attribute/operators/Import.cxx
+++ b/smtk/attribute/operators/Import.cxx
@@ -37,7 +37,7 @@ namespace smtk
 namespace attribute
 {
 
-Import::Result Import::operateInternal()
+Import::Result Import::operateInternal(Context ctx)
 {
   // Access the file name.
   std::string filename = this->parameters()->findFile("filename")->value();
diff --git a/smtk/attribute/operators/Import.h b/smtk/attribute/operators/Import.h
index 326d14e2449181cfb9dd1f6718872f8894e0c7d2..77a3c89877a31755b7aba9b5c191b601f9ad87eb 100644
--- a/smtk/attribute/operators/Import.h
+++ b/smtk/attribute/operators/Import.h
@@ -28,7 +28,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 } // namespace attribute
diff --git a/smtk/attribute/operators/Read.cxx b/smtk/attribute/operators/Read.cxx
index f3a3c229c96a55d9055312e8545725dae3e5545e..b826cbdc18d7e5cbbb3bc06d9397a3595c9013a9 100644
--- a/smtk/attribute/operators/Read.cxx
+++ b/smtk/attribute/operators/Read.cxx
@@ -44,7 +44,7 @@ namespace smtk
 namespace attribute
 {
 
-Read::Result Read::operateInternal()
+Read::Result Read::operateInternal(Context ctx)
 {
   using smtk::common::VersionNumber;
 
diff --git a/smtk/attribute/operators/Read.h b/smtk/attribute/operators/Read.h
index a8df8ca20d5a59156c6dcde0be2b68332d238e32..782189cd06a40236ba7c1b92229ca33f99133b47 100644
--- a/smtk/attribute/operators/Read.h
+++ b/smtk/attribute/operators/Read.h
@@ -28,7 +28,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
   void markModifiedResources(Result&) override;
 };
diff --git a/smtk/attribute/operators/Signal.cxx b/smtk/attribute/operators/Signal.cxx
index 82329106b1894b0316055c2b65afd0be1b6bcbf3..4dcd1e8d61f4c5f3428b75165b04858c91dfafa8 100644
--- a/smtk/attribute/operators/Signal.cxx
+++ b/smtk/attribute/operators/Signal.cxx
@@ -30,7 +30,7 @@ namespace smtk
 namespace attribute
 {
 
-Signal::Result Signal::operateInternal()
+Signal::Result Signal::operateInternal(Context ctx)
 {
   auto params = this->parameters();
   auto result = this->createResult(smtk::operation::Operation::Outcome::SUCCEEDED);
diff --git a/smtk/attribute/operators/Signal.h b/smtk/attribute/operators/Signal.h
index 7b33d832387d3c53c7ca895a6a80b1a365030c43..b83f57f4c12cdbc4789afa69527e477b05d5cf7c 100644
--- a/smtk/attribute/operators/Signal.h
+++ b/smtk/attribute/operators/Signal.h
@@ -32,7 +32,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   void generateSummary(Operation::Result&) override;
   const char* xmlDescription() const override;
 };
diff --git a/smtk/attribute/operators/Write.cxx b/smtk/attribute/operators/Write.cxx
index 1e554a7960fae0e981ab79584634275cc5a179e2..6979c9d2283c0902fb3cb21d59d3b0e4b5388cce 100644
--- a/smtk/attribute/operators/Write.cxx
+++ b/smtk/attribute/operators/Write.cxx
@@ -35,7 +35,7 @@ namespace smtk
 namespace attribute
 {
 
-Write::Result Write::operateInternal()
+Write::Result Write::operateInternal(Context ctx)
 {
   auto resourceItem = this->parameters()->associations();
 
diff --git a/smtk/attribute/operators/Write.h b/smtk/attribute/operators/Write.h
index 30ccd4b85077477f2a45e4e5c7a6b80dd0b66cfa..9562b6cd2892424916329451b5e2813adc6ab7b2 100644
--- a/smtk/attribute/operators/Write.h
+++ b/smtk/attribute/operators/Write.h
@@ -28,7 +28,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
   void markModifiedResources(Result&) override;
 };
diff --git a/smtk/common/CMakeLists.txt b/smtk/common/CMakeLists.txt
index 2c5489637c96efcf2e43762ee3f8ac2727255aaf..984eeec85d7e9dbd39c8735916cd0f7ffc9e8d06 100644
--- a/smtk/common/CMakeLists.txt
+++ b/smtk/common/CMakeLists.txt
@@ -31,6 +31,7 @@ set(commonHeaders
   Categories.h
   Color.h
   CompilerInformation.h
+  Context.h
   DateTime.h
   DateTimeZonePair.h
   Deprecation.h
diff --git a/smtk/common/Context.h b/smtk/common/Context.h
new file mode 100644
index 0000000000000000000000000000000000000000..9e8b68824d16b07a3d61b64ba4b202fce40949d5
--- /dev/null
+++ b/smtk/common/Context.h
@@ -0,0 +1,113 @@
+//=========================================================================
+//  Copyright (c) Kitware, Inc.
+//  All rights reserved.
+//  See LICENSE.txt for details.
+//
+//  This software is distributed WITHOUT ANY WARRANTY; without even
+//  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+//  PURPOSE.  See the above copyright notice for more information.
+//=========================================================================
+#ifndef smtk_common_Context_h
+#define smtk_common_Context_h
+
+#include "smtk/CoreExports.h"
+
+//#include <optional>
+#include <typeindex>
+#include <unordered_map>
+
+#include <boost/any.hpp>
+
+// TODO: Replace this with std::optional before merging this.
+#include <boost/optional.hpp>
+
+#define DECLARE_CONTEXT_KEY_TYPE(NAME)                                                                     \
+struct NAME                                                                                      \
+{                                                                                                \
+};
+
+namespace smtk
+{
+namespace common
+{
+
+class SMTKCORE_EXPORT Context final
+{
+  using key_type = std::size_t;
+  using value_type = boost::any;
+  using value_map = std::unordered_map<key_type, value_type>;
+
+public:
+  template<typename keyT, typename valueT>
+  boost::optional<valueT> value(const keyT& key) const
+  {
+    const auto keyHash = std::hash<keyT>{}(key);
+    const auto it = this->m_valueEntries.find(keyHash);
+    if (it != this->m_valueEntries.end())
+    {
+      try
+      {
+        return boost::any_cast<valueT>(it->second);
+      }
+      catch (const boost::bad_any_cast&)
+      {
+        return boost::optional<valueT>();
+      }
+    }
+    return boost::optional<valueT>();
+  }
+
+  template<typename keyT, typename valueT>
+  boost::optional<valueT> value() const
+  {
+    const auto keyHash = std::hash<std::type_index>{}(std::type_index(typeid(keyT)));
+    const auto it = this->m_typeEntries.find(keyHash);
+    if (it != this->m_typeEntries.end())
+    {
+      try
+      {
+        return boost::any_cast<valueT>(it->second);
+      }
+      catch (const boost::bad_any_cast&)
+      {
+        return boost::optional<valueT>();
+      }
+    }
+    return boost::optional<valueT>();
+  }
+
+  template<typename keyT, typename valueT>
+  Context withValue(const keyT& key, const valueT& value) const
+  {
+    // Create a copy of the current context.
+    Context result = *this;
+
+    // Add the entry to the copy.
+    result.m_valueEntries[std::hash<keyT>{}(key)] = value;
+
+    // Return the copy.
+    return result;
+  }
+
+  template<typename keyT, typename valueT>
+  Context withValue(const valueT& value) const
+  {
+    // Create a copy of the current context.
+    Context result = *this;
+
+    // Add the entry to the copy using the type id of keyT as key value.
+    result.m_typeEntries[std::hash<std::type_index>{}(std::type_index(typeid(keyT)))] = value;
+
+    // Return the copy.
+    return result;
+  }
+
+private:
+  value_map m_valueEntries;
+  value_map m_typeEntries;
+};
+
+} // namespace common
+} // namespace smtk
+
+#endif // smtk_common_Context_h
\ No newline at end of file
diff --git a/smtk/extension/delaunay/operators/TessellateFaces.cxx b/smtk/extension/delaunay/operators/TessellateFaces.cxx
index 93abc9f0a8ea764dbb8903b1f9f648549fc305d4..5adfde8b67008a32b973fae9c67279ed61d51a26 100644
--- a/smtk/extension/delaunay/operators/TessellateFaces.cxx
+++ b/smtk/extension/delaunay/operators/TessellateFaces.cxx
@@ -62,7 +62,7 @@ bool TessellateFaces::ableToOperate()
   return smtk::operation::Operation::ableToOperate();
 }
 
-TessellateFaces::Result TessellateFaces::operateInternal()
+TessellateFaces::Result TessellateFaces::operateInternal(Context ctx)
 {
   auto associations = this->parameters()->associations();
   auto faces = associations->as<smtk::model::Faces>([](smtk::resource::PersistentObjectPtr obj) {
diff --git a/smtk/extension/delaunay/operators/TessellateFaces.h b/smtk/extension/delaunay/operators/TessellateFaces.h
index c6f0618cc3534174f714561570f6862c54af44fa..940c7bee7aed6802d0033ac9ce4a82c953a2cbf3 100644
--- a/smtk/extension/delaunay/operators/TessellateFaces.h
+++ b/smtk/extension/delaunay/operators/TessellateFaces.h
@@ -35,7 +35,7 @@ public:
   bool ableToOperate() override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 } // namespace delaunay
diff --git a/smtk/extension/delaunay/operators/TriangulateFaces.cxx b/smtk/extension/delaunay/operators/TriangulateFaces.cxx
index d061406e5d742a8f0913d6ad27b8dd4ee2f0d08d..01545b3e69b3e38e5ced96534aaf3436ea13b0c3 100644
--- a/smtk/extension/delaunay/operators/TriangulateFaces.cxx
+++ b/smtk/extension/delaunay/operators/TriangulateFaces.cxx
@@ -63,7 +63,7 @@ bool TriangulateFaces::ableToOperate()
   return smtk::operation::Operation::ableToOperate();
 }
 
-TriangulateFaces::Result TriangulateFaces::operateInternal()
+TriangulateFaces::Result TriangulateFaces::operateInternal(Context ctx)
 {
   auto associations = this->parameters()->associations();
   auto faces = associations->as<smtk::model::Faces>([](smtk::resource::PersistentObjectPtr obj) {
diff --git a/smtk/extension/delaunay/operators/TriangulateFaces.h b/smtk/extension/delaunay/operators/TriangulateFaces.h
index b9e964e74e9e4a0660b3813079df07ccdb0e6a62..76c9385685ae13a7a3e3bc7860125a155a3eca92 100644
--- a/smtk/extension/delaunay/operators/TriangulateFaces.h
+++ b/smtk/extension/delaunay/operators/TriangulateFaces.h
@@ -38,7 +38,7 @@ public:
   bool ableToOperate() override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 } // namespace delaunay
diff --git a/smtk/extension/paraview/appcomponents/pqSMTKAppComponentsAutoStart.cxx b/smtk/extension/paraview/appcomponents/pqSMTKAppComponentsAutoStart.cxx
index 8c8275e1c9ac1ca8121ef253f1e4bab3ccdd80f5..f52e18f770be3fb4f860cef4cdd286a88300454e 100644
--- a/smtk/extension/paraview/appcomponents/pqSMTKAppComponentsAutoStart.cxx
+++ b/smtk/extension/paraview/appcomponents/pqSMTKAppComponentsAutoStart.cxx
@@ -30,6 +30,7 @@
 #include "smtk/extension/paraview/appcomponents/pqSMTKPythonTrace.h"
 #endif
 
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
 #include "smtk/extension/qt/qtSMTKUtilities.h"
 
 #include "pqApplicationCore.h"
@@ -42,6 +43,8 @@
 #include "vtkVersion.h"
 #include "vtksys/SystemTools.hxx"
 
+#include <pqServer.h>
+
 namespace
 {
 class vtkSMTKAppComponentsFactory : public vtkObjectFactory
@@ -95,7 +98,8 @@ void pqSMTKAppComponentsAutoStart::startup()
 
   auto* behavior = pqSMTKBehavior::instance(this);
   auto* renderResourceBehavior = pqSMTKRenderResourceBehavior::instance(this);
-  auto* callObserversOnMainThread = pqSMTKCallObserversOnMainThreadBehavior::instance(this);
+  //auto* callObserversOnMainThread = pqSMTKCallObserversOnMainThreadBehavior::instance(this);
+  auto* invokeOnMainThread = smtk::extension::qtInvokeOnMainThreadBehavior::instance(this);
   auto* pipelineSync = pqSMTKPipelineSelectionBehavior::instance(this);
   auto* displayOnLoad = pqSMTKDisplayAttributeOnLoadBehavior::instance(this);
   auto* registerImportersBehavior = pqSMTKRegisterImportersBehavior::instance(this);
@@ -118,12 +122,21 @@ void pqSMTKAppComponentsAutoStart::startup()
         pqSMTKCloseWithActiveOperationBehavior::instance(this);
       pqCore->registerManager("smtk close with active operation", closeWithActiveOperationBehavior);
     }
-    pqCore->registerManager("call observers on main thread", callObserversOnMainThread);
+    //pqCore->registerManager("call observers on main thread", callObserversOnMainThread);
+    pqCore->registerManager("invoke on main thread", invokeOnMainThread);
     pqCore->registerManager("smtk register importers", registerImportersBehavior);
     pqCore->registerManager("smtk pipeline selection sync", pipelineSync);
     pqCore->registerManager("smtk display attribute on load", displayOnLoad);
     pqCore->registerManager("operation hints", operationHints);
 
+    QObject::connect(
+      behavior,
+      QOverload<pqSMTKWrapper*, pqServer*>::of(&pqSMTKBehavior::addedManagerOnServer),
+      this,
+      [invokeOnMainThread](pqSMTKWrapper* smtkWrapper, pqServer*) {
+        invokeOnMainThread->addObservers(*smtkWrapper->smtkManagersPtr());
+      });
+
     QObject::connect(
       behavior,
       SIGNAL(addedManagerOnServer(pqSMTKWrapper*, pqServer*)),
@@ -174,7 +187,8 @@ void pqSMTKAppComponentsAutoStart::shutdown()
       pqCore->unRegisterManager("smtk save on close resource");
       pqCore->unRegisterManager("smtk close with active operation");
     }
-    pqCore->unRegisterManager("call observers on main thread");
+    //pqCore->unRegisterManager("call observers on main thread");
+    pqCore->unRegisterManager("invoke on main thread");
     pqCore->unRegisterManager("smtk register importers");
     pqCore->unRegisterManager("smtk pipeline selection sync");
   }
@@ -182,25 +196,27 @@ void pqSMTKAppComponentsAutoStart::shutdown()
 
 void pqSMTKAppComponentsAutoStart::observeWrapper(pqSMTKWrapper* wrapper, pqServer* /*server*/)
 {
-  m_p->m_opObserver = wrapper->smtkOperationManager()->observers().insert(
-    [this](
-      const smtk::operation::Operation& op,
-      smtk::operation::EventType event,
-      smtk::operation::Operation::Result const&
-      /*result*/) -> int {
-      (void)op;
-      if (event == smtk::operation::EventType::WILL_OPERATE)
-      {
+  m_p->m_opObserver =
+    smtk::extension::qtInvokeOnMainThreadBehavior::instance()->operationObservers().insert(
+      [this](
+      smtk::common::Context ctx,
+        const smtk::operation::Operation& op,
+        smtk::operation::EventType event,
+        smtk::operation::Operation::Result const&
+        /*result*/) -> int {
+        (void)op;
+        if (event == smtk::operation::EventType::WILL_OPERATE)
+        {
       // Trace operation in python
 #ifdef SMTK_PYTHON_ENABLED
-        this->m_p->m_pythonTrace.traceOperation(op);
+          this->m_p->m_pythonTrace.traceOperation(op);
 #endif
-      }
-      return 0;
-    },
-    std::numeric_limits<smtk::operation::Observers::Priority>::lowest(),
-    /* invoke observer on current selection */ false,
-    "pqSMTKAppComponentsAutoStart: observe operations and trace in python.");
+        }
+        return 0;
+      },
+      std::numeric_limits<smtk::operation::Observers::Priority>::lowest(),
+      /* invoke observer on current selection */ false,
+      "pqSMTKAppComponentsAutoStart: observe operations and trace in python.");
 }
 
 void pqSMTKAppComponentsAutoStart::unobserveWrapper(
diff --git a/smtk/extension/paraview/appcomponents/pqSMTKAttributePanel.cxx b/smtk/extension/paraview/appcomponents/pqSMTKAttributePanel.cxx
index ad3460849f7a76cbe892d03948e18ec7160be234..7b428401e0afb713045e2c9750f935b338b17cdd 100644
--- a/smtk/extension/paraview/appcomponents/pqSMTKAttributePanel.cxx
+++ b/smtk/extension/paraview/appcomponents/pqSMTKAttributePanel.cxx
@@ -19,6 +19,7 @@
 #include "smtk/extension/paraview/server/vtkSMTKSettings.h"
 
 #include "smtk/extension/qt/qtBaseView.h"
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
 
 #include "smtk/io/Logger.h"
 
@@ -315,10 +316,12 @@ void pqSMTKAttributePanel::observeProjectsOnServer(pqSMTKWrapper* mgr, pqServer*
   QPointer<pqSMTKAttributePanel> self(this);
   auto observerKey = projectManager->observers().insert(
     [self](const smtk::project::Project& project, smtk::project::EventType event) {
-      if (self)
-      {
-        self->handleProjectEvent(project, event);
-      }
+      smtk::extension::qtInvokeOnMainThreadBehavior::invokeOnMainThread([&] {
+        if (self)
+        {
+          self->handleProjectEvent(project, event);
+        }
+      });
     },
     0,    // assign a neutral priority
     true, // immediatelyNotify
@@ -367,24 +370,26 @@ void pqSMTKAttributePanel::handleProjectEvent(
         auto& activeTracker = taskManager->active();
         m_activeObserverKey = activeTracker.observers().insert(
           [this, self](smtk::task::Task* oldTask, smtk::task::Task* newTask) {
-            if (!self)
-            {
-              return;
-            }
-            // Stop observing the prior task (if any).
-            m_currentTaskObserverKey.release();
+            smtk::extension::qtInvokeOnMainThreadBehavior::invokeOnMainThread([&]() {
+              if (!self)
+              {
+                return;
+              }
+              // Stop observing the prior task (if any).
+              m_currentTaskObserverKey.release();
 
-            (void)oldTask;
-            if (m_currentTask)
-            {
-              m_currentTask->observers().erase(m_currentTaskObserverKey);
-              self->displayResource(nullptr);
-            }
-            m_currentTask = nullptr;
-            if (newTask)
-            {
-              self->displayTaskAttribute(newTask);
-            }
+              (void)oldTask;
+              if (m_currentTask)
+              {
+                m_currentTask->observers().erase(m_currentTaskObserverKey);
+                self->displayResource(nullptr);
+              }
+              m_currentTask = nullptr;
+              if (newTask)
+              {
+                self->displayTaskAttribute(newTask);
+              }
+            });
           },
           /* priority */ 0,
           /* initialize */ true,
@@ -532,29 +537,30 @@ bool pqSMTKAttributePanel::displayResourceInternal(
   {
     std::weak_ptr<smtk::resource::Manager> weakResourceManager = rsrcMgr;
     QPointer<pqSMTKAttributePanel> self(this);
-    m_observer = rsrcMgr->observers().insert(
-      [this, weakResourceManager, self](
-        const smtk::resource::Resource& attrRsrc, smtk::resource::EventType evnt) {
-        // Does the panel still exist?
-        if (self == nullptr)
-        {
-          return;
-        }
-        auto rsrc = m_rsrc.lock();
-        if (
-          rsrc == nullptr ||
-          (evnt == smtk::resource::EventType::REMOVED && &attrRsrc == rsrc.get()))
-        {
-          // The application is removing the attribute resource we are viewing.
-          // Clear out the panel and unobserve the manager.
-          this->resetPanel(weakResourceManager.lock());
-          this->updateTitle();
-          m_seln = nullptr;
-        }
-      },
-      std::numeric_limits<smtk::resource::Observers::Priority>::lowest(),
-      /* initialize */ false,
-      "pqSMTKAttributePanel: Clear panel if a removed resource is being displayed.");
+    m_observer =
+      smtk::extension::qtInvokeOnMainThreadBehavior::instance()->resourceObservers().insert(
+        [this, weakResourceManager, self](
+          const smtk::resource::Resource& attrRsrc, smtk::resource::EventType evnt) {
+          // Does the panel still exist?
+          if (self == nullptr)
+          {
+            return;
+          }
+          auto rsrc = m_rsrc.lock();
+          if (
+            rsrc == nullptr ||
+            (evnt == smtk::resource::EventType::REMOVED && &attrRsrc == rsrc.get()))
+          {
+            // The application is removing the attribute resource we are viewing.
+            // Clear out the panel and unobserve the manager.
+            this->resetPanel(weakResourceManager.lock());
+            this->updateTitle();
+            m_seln = nullptr;
+          }
+        },
+        std::numeric_limits<smtk::resource::Observers::Priority>::lowest(),
+        /* initialize */ false,
+        "pqSMTKAttributePanel: Clear panel if a removed resource is being displayed.");
   }
   m_rsrc = rsrc;
 
@@ -658,13 +664,15 @@ bool pqSMTKAttributePanel::displayTaskAttribute(smtk::task::Task* task)
       [self](smtk::task::Task& task, smtk::task::State priorState, smtk::task::State currentState) {
         (void)task;
         (void)priorState;
-        if (!self)
-        {
-          return;
-        }
-        self->m_attrUIMgr->setReadOnly(
-          currentState < smtk::task::State::Incomplete ||
-          currentState >= smtk::task::State::Completed);
+        smtk::extension::qtInvokeOnMainThreadBehavior::invokeOnMainThread([&]() {
+          if (!self)
+          {
+            return;
+          }
+          self->m_attrUIMgr->setReadOnly(
+            currentState < smtk::task::State::Incomplete ||
+            currentState >= smtk::task::State::Completed);
+        });
       },
       "AttributePanel current task state-tracking.");
     this->m_attrUIMgr->setReadOnly(
diff --git a/smtk/extension/paraview/appcomponents/pqSMTKCallObserversOnMainThreadBehavior.cxx b/smtk/extension/paraview/appcomponents/pqSMTKCallObserversOnMainThreadBehavior.cxx
index 908fc96d376e701b2e9ac70128ed8324ec42fb7b..f3004256bdd1a43694ae02f3140378f20b0eac51 100644
--- a/smtk/extension/paraview/appcomponents/pqSMTKCallObserversOnMainThreadBehavior.cxx
+++ b/smtk/extension/paraview/appcomponents/pqSMTKCallObserversOnMainThreadBehavior.cxx
@@ -108,6 +108,7 @@ void pqSMTKCallObserversOnMainThreadBehavior::forceObserversToBeCalledOnMainThre
   // instead of calling its Observer functors directly.
   wrapper->smtkOperationManager()->observers().overrideWith(
     [this, wrapper](
+      smtk::common::Context ctx,
       const smtk::operation::Operation& oper,
       smtk::operation::EventType event,
       smtk::operation::Operation::Result result) -> int {
@@ -126,7 +127,7 @@ void pqSMTKCallObserversOnMainThreadBehavior::forceObserversToBeCalledOnMainThre
       else
       {
         // Directly invoke the observers.
-        wrapper->smtkOperationManager()->observers().callObserversDirectly(oper, event, result);
+        wrapper->smtkOperationManager()->observers().callObserversDirectly(ctx, oper, event, result);
       }
       return 0;
     });
@@ -149,7 +150,7 @@ void pqSMTKCallObserversOnMainThreadBehavior::forceObserversToBeCalledOnMainThre
         {
           att = operation->specification()->findAttribute(resultName.toStdString());
         }
-        operation->manager()->observers().callObserversDirectly(
+        operation->manager()->observers().callObserversDirectly(smtk::common::Context(),
           *operation, static_cast<smtk::operation::EventType>(event), att);
       }
       m_activeOperations.erase(id);
diff --git a/smtk/extension/paraview/appcomponents/pqSMTKCloseWithActiveOperationBehavior.cxx b/smtk/extension/paraview/appcomponents/pqSMTKCloseWithActiveOperationBehavior.cxx
index 62c79ec8b4e0b1b8fe85d3b94d1e345e337fb57e..9d923093140ed9edcbfea4808976afd46b8907c4 100644
--- a/smtk/extension/paraview/appcomponents/pqSMTKCloseWithActiveOperationBehavior.cxx
+++ b/smtk/extension/paraview/appcomponents/pqSMTKCloseWithActiveOperationBehavior.cxx
@@ -43,8 +43,11 @@
 #include <QCheckBox>
 #include <QCloseEvent>
 
+#include <mutex>
+
 static pqSMTKCloseWithActiveOperationBehavior* g_instance = nullptr;
 
+std::mutex g_numberOfActiveOperationsMutex;
 static std::atomic<int> g_numberOfActiveOperations(0);
 
 pqSMTKCloseWithActiveOperationBehavior::pqSMTKCloseWithActiveOperationBehavior(QObject* parent)
@@ -99,9 +102,11 @@ void pqSMTKCloseWithActiveOperationBehavior::trackActiveOperations(
 
   m_key = wrapper->smtkOperationManager()->observers().insert(
     [](
+    smtk::common::Context ctx,
       const smtk::operation::Operation&,
       smtk::operation::EventType event,
       smtk::operation::Operation::Result) -> int {
+      std::lock_guard<std::mutex> guard(g_numberOfActiveOperationsMutex);
       if (event == smtk::operation::EventType::WILL_OPERATE)
       {
         ++g_numberOfActiveOperations;
diff --git a/smtk/extension/paraview/appcomponents/pqSMTKDisplayAttributeOnLoadBehavior.cxx b/smtk/extension/paraview/appcomponents/pqSMTKDisplayAttributeOnLoadBehavior.cxx
index d8f47ebb6b35b3a293c5e2b60fc40d25024c22e0..3ba4f8dd2c00a7ae2269773a8488ea3383efff6d 100644
--- a/smtk/extension/paraview/appcomponents/pqSMTKDisplayAttributeOnLoadBehavior.cxx
+++ b/smtk/extension/paraview/appcomponents/pqSMTKDisplayAttributeOnLoadBehavior.cxx
@@ -17,6 +17,7 @@
 #include "smtk/extension/paraview/appcomponents/pqSMTKWrapper.h"
 
 #include "smtk/extension/paraview/server/vtkSMSMTKWrapperProxy.h"
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
 
 #include "smtk/view/Selection.h"
 
@@ -98,13 +99,14 @@ void pqSMTKDisplayAttributeOnLoadBehavior::observeResourcesOnServer(
     return;
   }
 
-  smtk::resource::Observers::Key observerKey = rsrcMgr->observers().insert(
-    [this](const smtk::resource::Resource& rsrc, smtk::resource::EventType event) {
-      this->handleResourceEvent(rsrc, event);
-    },
-    0,    // assign a neutral priority
-    true, // immediatelyNotify
-    "pqSMTKDisplayAttributeOnLoadBehavior: Display new attribute resource in panel.");
+  smtk::resource::Observers::Key observerKey =
+    smtk::extension::qtInvokeOnMainThreadBehavior::instance()->resourceObservers().insert(
+      [this](const smtk::resource::Resource& rsrc, smtk::resource::EventType event) {
+        this->handleResourceEvent(rsrc, event);
+      },
+      0,    // assign a neutral priority
+      true, // immediatelyNotify
+      "pqSMTKDisplayAttributeOnLoadBehavior: Display new attribute resource in panel.");
   m_resourceManagerObservers[rsrcMgr] = std::move(observerKey);
 }
 
diff --git a/smtk/extension/paraview/appcomponents/pqSMTKGroupComponentsBehavior.cxx b/smtk/extension/paraview/appcomponents/pqSMTKGroupComponentsBehavior.cxx
index 319e089ffab75dd0368875d2e487e3979baca257..a912e4c1a9a206e57b592bebce94ba51d9834b7a 100644
--- a/smtk/extension/paraview/appcomponents/pqSMTKGroupComponentsBehavior.cxx
+++ b/smtk/extension/paraview/appcomponents/pqSMTKGroupComponentsBehavior.cxx
@@ -31,6 +31,7 @@
 #include "smtk/extension/paraview/appcomponents/pqSMTKResource.h"
 #include "smtk/extension/paraview/appcomponents/pqSMTKWrapper.h"
 #include "smtk/extension/paraview/server/vtkSMTKSettings.h"
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
 #include "smtk/extension/qt/qtOperationView.h"
 #include "smtk/extension/qt/qtUIManager.h"
 #include "smtk/io/Logger.h"
@@ -99,13 +100,14 @@ void pqGroupComponentsReaction::updateSelectionObserver(pqServer* server)
   auto selection = wrapper ? wrapper->smtkSelection() : nullptr;
   if (selection)
   {
-    m_observerKey = selection->observers().insert(
-      [this](const std::string&, std::shared_ptr<smtk::view::Selection> const&) {
-        this->updateEnableState();
-      },
-      std::numeric_limits<smtk::view::SelectionObservers::Priority>::lowest(),
-      /* initialize immediately */ true,
-      m_isGrouping ? "update grouping action" : "update ungrouping action");
+    m_observerKey =
+      smtk::extension::qtInvokeOnMainThreadBehavior::instance()->selectionObservers().insert(
+        [this](const std::string&, std::shared_ptr<smtk::view::Selection> const&) {
+          this->updateEnableState();
+        },
+        std::numeric_limits<smtk::view::SelectionObservers::Priority>::lowest(),
+        /* initialize immediately */ true,
+        m_isGrouping ? "update grouping action" : "update ungrouping action");
   }
   else
   {
diff --git a/smtk/extension/paraview/appcomponents/pqSMTKOperationHintsBehavior.cxx b/smtk/extension/paraview/appcomponents/pqSMTKOperationHintsBehavior.cxx
index b6f9507b238bd454ca2c21dd47a5bd580ea21e74..9a1aa875ff6ed2edd06b7d80d35c1d2b2f583afc 100644
--- a/smtk/extension/paraview/appcomponents/pqSMTKOperationHintsBehavior.cxx
+++ b/smtk/extension/paraview/appcomponents/pqSMTKOperationHintsBehavior.cxx
@@ -17,6 +17,7 @@
 
 #include "smtk/extension/qt/diagram/qtTaskEditor.h"
 #include "smtk/extension/qt/qtDescriptivePhraseModel.h"
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
 #include "smtk/extension/qt/qtResourceBrowser.h"
 
 #include "smtk/view/PhraseModel.h"
@@ -394,20 +395,22 @@ void pqSMTKOperationHintsBehavior::observeWrapper(pqSMTKWrapper* wrapper, pqServ
   auto operationManager = wrapper->smtkOperationManager();
   if (operationManager)
   {
-    bool didInsert = m_p->m_opObservers
-                       .emplace(
-                         server,
-                         operationManager->observers().insert(
-                           [this](
-                             const smtk::operation::Operation& op,
-                             smtk::operation::EventType eventType,
-                             smtk::operation::Operation::Result result) -> int {
-                             return this->processHints(op, eventType, result);
-                           },
-                           smtk::view::PhraseModel::operationObserverPriority() - 128,
-                           /*initialize*/ true,
-                           "Process operation hints."))
-                       .second;
+    bool didInsert =
+      m_p->m_opObservers
+        .emplace(
+          server,
+          smtk::extension::qtInvokeOnMainThreadBehavior::instance()->operationObservers().insert(
+            [this](
+            smtk::common::Context ctx,
+              const smtk::operation::Operation& op,
+              smtk::operation::EventType eventType,
+              smtk::operation::Operation::Result result) -> int {
+              return this->processHints(op, eventType, result);
+            },
+            smtk::view::PhraseModel::operationObserverPriority() - 128,
+            /*initialize*/ true,
+            "Process operation hints."))
+        .second;
     if (!didInsert)
     {
       smtkErrorMacro(
diff --git a/smtk/extension/paraview/appcomponents/pqSMTKOperationPanel.cxx b/smtk/extension/paraview/appcomponents/pqSMTKOperationPanel.cxx
index 1998547798b3a5b1232ac4500041ab756f5e3a14..2d71a10bdd0122f954255669a63e0e7e7a9dd78e 100644
--- a/smtk/extension/paraview/appcomponents/pqSMTKOperationPanel.cxx
+++ b/smtk/extension/paraview/appcomponents/pqSMTKOperationPanel.cxx
@@ -13,6 +13,7 @@
 #include "smtk/extension/paraview/appcomponents/pqSMTKRenderResourceBehavior.h"
 #include "smtk/extension/paraview/appcomponents/pqSMTKResource.h"
 #include "smtk/extension/paraview/appcomponents/pqSMTKWrapper.h"
+#include <smtk/extension/qt/qtInvokeOnMainThreadBehavior.h>
 
 #include "smtk/operation/Operation.h"
 
@@ -292,29 +293,30 @@ bool pqSMTKOperationPanel::editOperation(smtk::operation::OperationPtr op)
     // If the operation's specification is destroyed, then
     // get rid of the UI.
     std::weak_ptr<smtk::resource::Manager> weakResourceManager = rsrcMgr;
-    m_observer = rsrcMgr->observers().insert(
-      [this, weakResourceManager](
-        const smtk::resource::Resource& attrRsrc, smtk::resource::EventType evnt) {
-        auto rsrc = m_rsrc.lock();
-        if (
-          rsrc == nullptr ||
-          (evnt == smtk::resource::EventType::REMOVED && &attrRsrc == rsrc.get()))
-        {
-          // The application is removing the attribute resource we are viewing.
-          // Clear out the panel and unobserve the manager.
-          if (auto rsrcMgr = weakResourceManager.lock())
-          {
-            rsrcMgr->observers().erase(m_observer);
-          }
-          delete m_attrUIMgr;
-          while (QWidget* w = m_p->OperationEditor->findChild<QWidget*>())
+    m_observer =
+      smtk::extension::qtInvokeOnMainThreadBehavior::instance()->resourceObservers().insert(
+        [this, weakResourceManager](
+          const smtk::resource::Resource& attrRsrc, smtk::resource::EventType evnt) {
+          auto rsrc = m_rsrc.lock();
+          if (
+            rsrc == nullptr ||
+            (evnt == smtk::resource::EventType::REMOVED && &attrRsrc == rsrc.get()))
           {
-            delete w;
+            // The application is removing the attribute resource we are viewing.
+            // Clear out the panel and unobserve the manager.
+            if (auto rsrcMgr = weakResourceManager.lock())
+            {
+              rsrcMgr->observers().erase(m_observer);
+            }
+            delete m_attrUIMgr;
+            while (QWidget* w = m_p->OperationEditor->findChild<QWidget*>())
+            {
+              delete w;
+            }
+            m_attrUIMgr = nullptr;
           }
-          m_attrUIMgr = nullptr;
-        }
-      },
-      "pqSMTKOperationPanel: Clear panel if a removed operation specification is displayed.");
+        },
+        "pqSMTKOperationPanel: Clear panel if a removed operation specification is displayed.");
   }
   return didDisplay;
 }
diff --git a/smtk/extension/paraview/appcomponents/pqSMTKOperationParameterPanel.cxx b/smtk/extension/paraview/appcomponents/pqSMTKOperationParameterPanel.cxx
index 3cfd8b88550597ac5c5b4f890e0185298c16b11e..a68792456922580b1e8468678800b4c53ba57969 100644
--- a/smtk/extension/paraview/appcomponents/pqSMTKOperationParameterPanel.cxx
+++ b/smtk/extension/paraview/appcomponents/pqSMTKOperationParameterPanel.cxx
@@ -15,6 +15,7 @@
 #include "smtk/extension/paraview/appcomponents/pqSMTKResource.h"
 #include "smtk/extension/paraview/appcomponents/pqSMTKWrapper.h"
 
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
 #include "smtk/extension/qt/qtOperationTypeModel.h"
 #include "smtk/extension/qt/qtOperationView.h"
 
@@ -628,10 +629,12 @@ void pqSMTKOperationParameterPanel::observeProjectsOnServer()
   QPointer<pqSMTKOperationParameterPanel> self(this);
   auto observerKey = projectManager->observers().insert(
     [self](const smtk::project::Project& project, smtk::project::EventType event) {
-      if (self)
-      {
-        self->handleProjectEvent(project, event);
-      }
+      smtk::extension::qtInvokeOnMainThreadBehavior::invokeOnMainThread([&]() {
+        if (self)
+        {
+          self->handleProjectEvent(project, event);
+        }
+      });
     },
     0,    // assign a neutral priority
     true, // immediatelyNotify
@@ -669,17 +672,45 @@ void pqSMTKOperationParameterPanel::handleProjectEvent(
       auto& activeTracker = taskManager->active();
       m_activeObserverKey = activeTracker.observers().insert(
         [this, &activeTracker](smtk::task::Task* oldTask, smtk::task::Task* newTask) {
-          m_taskObserver.release();
-          // First, if oldTask is an operation task, remove its parameter-panel
-          // (if it was configured to display one).
-          smtk::task::SubmitOperationAgent::RunStyle runStyle;
-          auto* prevOp = operationForTask(oldTask);
-          if (prevOp)
-          {
-            auto styles = oldTask->style();
+          smtk::extension::qtInvokeOnMainThreadBehavior::invokeOnMainThread([&]() {
+            m_taskObserver.release();
+            // First, if oldTask is an operation task, remove its parameter-panel
+            // (if it was configured to display one).
+            smtk::task::SubmitOperationAgent::RunStyle runStyle;
+            auto* prevOp = operationForTask(oldTask);
+            if (prevOp)
+            {
+              auto styles = oldTask->style();
+              for (const auto& style : styles)
+              {
+                auto configurations = oldTask->manager()->getStyle(style);
+                if (!configurations.contains("operation-panel"))
+                {
+                  continue;
+                }
+                auto section = configurations.at("operation-panel");
+                bool display = !section.contains("display") || section.at("display").get<bool>();
+                if (!display)
+                {
+                  continue;
+                }
+                this->closeTabForOperation(prevOp->shared_from_this(), true);
+              }
+            }
+
+            // Now that we've "deactivated" any previous operation task, see if we
+            // need to "activate" a new one.
+            auto* nextOp = operationForTask(newTask, &runStyle);
+            if (!nextOp)
+            {
+              return;
+            }
+
+            nlohmann::json panelStyle;
+            auto styles = newTask->style();
             for (const auto& style : styles)
             {
-              auto configurations = oldTask->manager()->getStyle(style);
+              auto configurations = newTask->manager()->getStyle(style);
               if (!configurations.contains("operation-panel"))
               {
                 continue;
@@ -690,62 +721,37 @@ void pqSMTKOperationParameterPanel::handleProjectEvent(
               {
                 continue;
               }
-              this->closeTabForOperation(prevOp->shared_from_this(), true);
-            }
-          }
-
-          // Now that we've "deactivated" any previous operation task, see if we
-          // need to "activate" a new one.
-          auto* nextOp = operationForTask(newTask, &runStyle);
-          if (!nextOp)
-          {
-            return;
-          }
-
-          nlohmann::json panelStyle;
-          auto styles = newTask->style();
-          for (const auto& style : styles)
-          {
-            auto configurations = newTask->manager()->getStyle(style);
-            if (!configurations.contains("operation-panel"))
-            {
-              continue;
-            }
-            auto section = configurations.at("operation-panel");
-            bool display = !section.contains("display") || section.at("display").get<bool>();
-            if (!display)
-            {
-              continue;
-            }
-            panelStyle = section;
-            // At this point, we know we are going to display this operation to the user
-            // Observe the task so when it transitions state we can react (e.g., by
-            // removing the operation tab when the task is completed.)
-            QPointer<pqSMTKOperationParameterPanel> self(this);
-            m_taskObserver = newTask->observers().insert([self, &activeTracker](
-                                                           smtk::task::Task& task,
-                                                           smtk::task::State priorState,
-                                                           smtk::task::State currentState) {
-              // If the panel has been destroyed or the task being
-              // observed is no longer active, ignore this event.
-              if (!self || activeTracker.task() != &task)
+              panelStyle = section;
+              // At this point, we know we are going to display this operation to the user
+              // Observe the task so when it transitions state we can react (e.g., by
+              // removing the operation tab when the task is completed.)
+              QPointer<pqSMTKOperationParameterPanel> self(this);
+              m_taskObserver = newTask->observers().insert([self, &activeTracker](
+                                                             smtk::task::Task& task,
+                                                             smtk::task::State priorState,
+                                                             smtk::task::State currentState) {
+                smtk::extension::qtInvokeOnMainThreadBehavior::invokeOnMainThread([&]() {
+                  // If the panel has been destroyed or the task being
+                  // observed is no longer active, ignore this event.
+                  if (!self || activeTracker.task() != &task)
+                  {
+                    return;
+                  }
+                  self->activeTaskStateChange(task, priorState, currentState);
+                });
+              });
+              // TODO: Fetch proper view-config from the task based on the "view" tag's
+              //       value (one of "anew"/"override"/"modified").
+              if (newTask->state() != smtk::task::State::Completed)
               {
-                return;
-              }
-              self->activeTaskStateChange(task, priorState, currentState);
-            });
-            // TODO: Fetch proper view-config from the task based on the "view" tag's
-            //       value (one of "anew"/"override"/"modified").
-            if (newTask->state() != smtk::task::State::Completed)
-            {
-              // Find or create TabData instance
-              TabData* tabData = this->tabDataForOperation(*nextOp);
-              if (tabData == nullptr)
-              {
-                tabData = this->createTabData(nextOp);
-              }
-              // Get the view configuration
-              smtk::view::ConfigurationPtr view = tabData->m_uiMgr->findOrCreateOperationView();
+                // Find or create TabData instance
+                TabData* tabData = this->tabDataForOperation(*nextOp);
+                if (tabData == nullptr)
+                {
+                  tabData = this->createTabData(nextOp);
+                }
+                // Get the view configuration
+                smtk::view::ConfigurationPtr view = tabData->m_uiMgr->findOrCreateOperationView();
 
 #if 0
               // Process any style:hide-items in the task's style
@@ -755,16 +761,17 @@ void pqSMTKOperationParameterPanel::handleProjectEvent(
               }
 #endif
 
-              this->editExistingOperationParameters(
-                nextOp->shared_from_this(),
-                /* associate selection? */
-                false, // TODO: Determine whether nextOp->associations() is specified.
-                /* allow tab to be closed? */ false,
-                /* show apply button */ runStyle !=
-                  smtk::task::SubmitOperationAgent::RunStyle::OnCompletion,
-                view);
+                this->editExistingOperationParameters(
+                  nextOp->shared_from_this(),
+                  /* associate selection? */
+                  false, // TODO: Determine whether nextOp->associations() is specified.
+                  /* allow tab to be closed? */ false,
+                  /* show apply button */ runStyle !=
+                    smtk::task::SubmitOperationAgent::RunStyle::OnCompletion,
+                  view);
+              }
             }
-          }
+          });
         });
     }
     break;
diff --git a/smtk/extension/paraview/appcomponents/pqSMTKPipelineSelectionBehavior.cxx b/smtk/extension/paraview/appcomponents/pqSMTKPipelineSelectionBehavior.cxx
index f47cae0ed2bea7c79284e53acc54e4de74af0d75..cea66dd723e42d7e5879c3c418b998ab6c0dc24d 100644
--- a/smtk/extension/paraview/appcomponents/pqSMTKPipelineSelectionBehavior.cxx
+++ b/smtk/extension/paraview/appcomponents/pqSMTKPipelineSelectionBehavior.cxx
@@ -18,6 +18,8 @@
 
 #include "smtk/extension/paraview/server/vtkSMSMTKWrapperProxy.h"
 
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
+
 #include "smtk/view/Selection.h"
 
 #include "smtk/resource/Resource.h"
@@ -114,67 +116,69 @@ void pqSMTKPipelineSelectionBehavior::observeSelectionOnServer(
     return;
   }
 
-  auto observerId = seln->observers().insert(
-    [&](const std::string& source, smtk::view::SelectionPtr selection) {
-      int selnValue = selection->selectionValueFromLabel(m_selectionValue);
-      if (source != "pqSMTKPipelineSelectionBehavior")
-      {
-        smtk::resource::ResourcePtr selectedResource;
-        selection->visitSelection([&](smtk::resource::PersistentObject::Ptr obj, int val) {
-          if ((val & selnValue) == selnValue)
-          {
-            auto rsrc = std::dynamic_pointer_cast<smtk::resource::Resource>(obj);
-            if (rsrc)
-            {
-              selectedResource = rsrc;
-            }
-          }
-        });
-        if (selectedResource)
+  auto observerId =
+    smtk::extension::qtInvokeOnMainThreadBehavior::instance()->selectionObservers().insert(
+      [&](const std::string& source, smtk::view::SelectionPtr selection) {
+        int selnValue = selection->selectionValueFromLabel(m_selectionValue);
+        if (source != "pqSMTKPipelineSelectionBehavior")
         {
-          // Make the reader owning the first selected resource the active PV pipeline source:
-          auto* behavior = pqSMTKBehavior::instance();
-          auto rsrcSrc = behavior->getPVResource(selectedResource);
-          if (rsrcSrc)
-          {
-            pqActiveObjects::instance().setActiveSource(rsrcSrc);
-          }
-          // Also, if the selected resource is an attribute and we are configured to display
-          // selected attributes in the editor panel, do so:
-          if (m_displayAttributeResourcesOnSelection)
-          {
-            auto attrResource =
-              std::dynamic_pointer_cast<smtk::attribute::Resource>(selectedResource);
-            if (attrResource && !attrResource->isPrivate())
+          smtk::resource::ResourcePtr selectedResource;
+          selection->visitSelection([&](smtk::resource::PersistentObject::Ptr obj, int val) {
+            if ((val & selnValue) == selnValue)
             {
-              // Find the attribute panel. For now, only deal with one;
-              // it doesn't make sense to switch multiple panels to display
-              // the same attribute anyway.
-              // pqSMTKDockBase* dock = nullptr;
-              QMainWindow* mainWindow = qobject_cast<QMainWindow*>(pqCoreUtilities::mainWidget());
-              if (!mainWindow)
+              auto rsrc = std::dynamic_pointer_cast<smtk::resource::Resource>(obj);
+              if (rsrc)
               {
-                return;
+                selectedResource = rsrc;
               }
-              Q_FOREACH (
-                pqSMTKAttributeDock* dock, mainWindow->findChildren<pqSMTKAttributeDock*>())
+            }
+          });
+          if (selectedResource)
+          {
+            // Make the reader owning the first selected resource the active PV pipeline source:
+            auto* behavior = pqSMTKBehavior::instance();
+            auto rsrcSrc = behavior->getPVResource(selectedResource);
+            if (rsrcSrc)
+            {
+              pqActiveObjects::instance().setActiveSource(rsrcSrc);
+            }
+            // Also, if the selected resource is an attribute and we are configured to display
+            // selected attributes in the editor panel, do so:
+            if (m_displayAttributeResourcesOnSelection)
+            {
+              auto attrResource =
+                std::dynamic_pointer_cast<smtk::attribute::Resource>(selectedResource);
+              if (attrResource && !attrResource->isPrivate())
               {
-                if (dock)
+                // Find the attribute panel. For now, only deal with one;
+                // it doesn't make sense to switch multiple panels to display
+                // the same attribute anyway.
+                // pqSMTKDockBase* dock = nullptr;
+                QMainWindow* mainWindow = qobject_cast<QMainWindow*>(pqCoreUtilities::mainWidget());
+                if (!mainWindow)
+                {
+                  return;
+                }
+                Q_FOREACH (
+                  pqSMTKAttributeDock* dock, mainWindow->findChildren<pqSMTKAttributeDock*>())
                 {
-                  pqSMTKAttributePanel* panel = qobject_cast<pqSMTKAttributePanel*>(dock->widget());
-                  if (panel)
+                  if (dock)
                   {
-                    panel->displayPipelineSource(rsrcSrc);
-                    break;
+                    pqSMTKAttributePanel* panel =
+                      qobject_cast<pqSMTKAttributePanel*>(dock->widget());
+                    if (panel)
+                    {
+                      panel->displayPipelineSource(rsrcSrc);
+                      break;
+                    }
                   }
                 }
               }
             }
           }
         }
-      }
-    },
-    "pqSMTKPipelineSelectionBehavior: Select ParaView pipeline representing SMTK selection.");
+      },
+      "pqSMTKPipelineSelectionBehavior: Select ParaView pipeline representing SMTK selection.");
   m_selectionObservers[seln] = std::move(observerId);
 }
 
diff --git a/smtk/extension/paraview/appcomponents/pqSMTKResource.cxx b/smtk/extension/paraview/appcomponents/pqSMTKResource.cxx
index 07d9e6c7a41539b3bcddfbbfc7902299c9152024..cf15d138420e27c13c37e97955009f8c0d784eaa 100644
--- a/smtk/extension/paraview/appcomponents/pqSMTKResource.cxx
+++ b/smtk/extension/paraview/appcomponents/pqSMTKResource.cxx
@@ -62,6 +62,7 @@ pqSMTKResource::pqSMTKResource(
   // that has this class instance as its context.
   m_key = rsrcMgr->smtkOperationManager()->observers().insert(
     [&](
+    smtk::common::Context ctx,
       const smtk::operation::Operation& op,
       smtk::operation::EventType event,
       smtk::operation::Operation::Result result) {
diff --git a/smtk/extension/paraview/markup/qtOntologyItem.cxx b/smtk/extension/paraview/markup/qtOntologyItem.cxx
index d2e01afee4e84b465d9a970434cbc038d9c1d8ca..af5906db09ff1cf20643eae22efbdd19a8c3bb3a 100644
--- a/smtk/extension/paraview/markup/qtOntologyItem.cxx
+++ b/smtk/extension/paraview/markup/qtOntologyItem.cxx
@@ -645,6 +645,7 @@ void qtOntologyItem::updateUI()
   {
     static auto key = opMgr->observers().insert(
       [&](
+      smtk::common::Context ctx,
         const smtk::operation::Operation& op,
         smtk::operation::EventType event,
         smtk::operation::Operation::Result) -> int {
diff --git a/smtk/extension/paraview/mesh/VTKMeshCellSelection.cxx b/smtk/extension/paraview/mesh/VTKMeshCellSelection.cxx
index 4c81a2f54e28ccbd69c4034fe84e7030c282a773..5222d58e45f4fcc8cdd4bb15b03956eb36f7e6d8 100644
--- a/smtk/extension/paraview/mesh/VTKMeshCellSelection.cxx
+++ b/smtk/extension/paraview/mesh/VTKMeshCellSelection.cxx
@@ -214,7 +214,7 @@ bool VTKMeshCellSelection::transcribeCellIdSelection(Result& result)
   return didModify;
 }
 
-VTKMeshCellSelection::Result VTKMeshCellSelection::operateInternal()
+VTKMeshCellSelection::Result VTKMeshCellSelection::operateInternal(Context ctx)
 {
   auto result = this->createResult(smtk::operation::Operation::Outcome::SUCCEEDED);
   bool worked = this->transcribeCellIdSelection(result);
diff --git a/smtk/extension/paraview/mesh/VTKMeshCellSelection.h b/smtk/extension/paraview/mesh/VTKMeshCellSelection.h
index 4c71a74f61aa96054dccad1156343661ea63152a..f000c0183e20e43a3588094756dcae7e34d12ff8 100644
--- a/smtk/extension/paraview/mesh/VTKMeshCellSelection.h
+++ b/smtk/extension/paraview/mesh/VTKMeshCellSelection.h
@@ -50,7 +50,7 @@ protected:
   bool transcribeCellIdSelection(Result& result);
 
   /// Simply call transcribeCellIdSelection().
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
 
 private:
   const char* xmlDescription() const override;
diff --git a/smtk/extension/paraview/model/VTKModelInstancePlacementSelection.cxx b/smtk/extension/paraview/model/VTKModelInstancePlacementSelection.cxx
index 6a28e8c53c50252308ab1ee3d62532b3970c4782..0644c8c70d99378319fdb1523d9edb99f08a2b77 100644
--- a/smtk/extension/paraview/model/VTKModelInstancePlacementSelection.cxx
+++ b/smtk/extension/paraview/model/VTKModelInstancePlacementSelection.cxx
@@ -223,7 +223,7 @@ bool VTKModelInstancePlacementSelection::transcribePlacementSelection(Result& re
   return didModify;
 }
 
-VTKModelInstancePlacementSelection::Result VTKModelInstancePlacementSelection::operateInternal()
+VTKModelInstancePlacementSelection::Result VTKModelInstancePlacementSelection::operateInternal(Context ctx)
 {
   auto result = this->createResult(smtk::operation::Operation::Outcome::SUCCEEDED);
   bool worked = this->transcribePlacementSelection(result);
diff --git a/smtk/extension/paraview/model/VTKModelInstancePlacementSelection.h b/smtk/extension/paraview/model/VTKModelInstancePlacementSelection.h
index c0ea0329ca9ea58e7767d45a832bb3fa1f5123cc..fd309181c7db8cf54093a168fb35b8e8a4452ad9 100644
--- a/smtk/extension/paraview/model/VTKModelInstancePlacementSelection.h
+++ b/smtk/extension/paraview/model/VTKModelInstancePlacementSelection.h
@@ -71,7 +71,7 @@ protected:
   bool transcribePlacementSelection(Result& result);
 
   /// Simply call transcribeCellIdSelection().
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
 
 private:
   const char* xmlDescription() const override;
diff --git a/smtk/extension/paraview/operators/smtkAssignColorsView.cxx b/smtk/extension/paraview/operators/smtkAssignColorsView.cxx
index b2c1cbd402738f32f0721d1fcbfc4d1f5639dc9f..6b99887236b0b52e8d7fcd3fe54832447c58de31 100644
--- a/smtk/extension/paraview/operators/smtkAssignColorsView.cxx
+++ b/smtk/extension/paraview/operators/smtkAssignColorsView.cxx
@@ -17,6 +17,7 @@
 #include "smtk/attribute/StringItem.h"
 #include "smtk/extension/qt/qtAttribute.h"
 #include "smtk/extension/qt/qtUIManager.h"
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
 #include "smtk/operation/Manager.h"
 #include "smtk/operation/Observer.h"
 #include "smtk/operation/Operation.h"
@@ -174,7 +175,8 @@ smtkAssignColorsView::smtkAssignColorsView(const smtk::view::Information& info)
   QPointer<smtkAssignColorsView> self(this);
   auto opMgr = this->Internals->CurrentOp->manager();
   this->Internals->ObserverKey =
-    opMgr->observers().insert([self, this](
+    qtInvokeOnMainThreadBehavior::instance()->operationObservers().insert([self, this](
+    smtk::common::Context ctx,
                                 const smtk::operation::Operation& op,
                                 smtk::operation::EventType event,
                                 smtk::operation::Operation::Result result) {
diff --git a/smtk/extension/paraview/operators/smtkCoordinateTransformView.cxx b/smtk/extension/paraview/operators/smtkCoordinateTransformView.cxx
index 38e1b87da8679e32ecea3c7f39f0cab2424cf95a..83399a1b05f316ccc99ff5e8f66d36f8593894f0 100644
--- a/smtk/extension/paraview/operators/smtkCoordinateTransformView.cxx
+++ b/smtk/extension/paraview/operators/smtkCoordinateTransformView.cxx
@@ -27,6 +27,7 @@
 #include "smtk/extension/qt/qtAttribute.h"
 #include "smtk/extension/qt/qtAttributeItemInfo.h"
 #include "smtk/extension/qt/qtUIManager.h"
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
 #include "smtk/operation/Manager.h"
 #include "smtk/operation/Observer.h"
 #include "smtk/resource/Component.h"
@@ -408,8 +409,9 @@ public:
       smtkErrorMacro(smtk::io::Logger::instance(), "No operation manager!");
       return;
     }
-    m_operationObserver = opMgr->observers().insert(
+    m_operationObserver = qtInvokeOnMainThreadBehavior::instance()->operationObservers().insert(
       [this](
+      smtk::common::Context ctx,
         const smtk::operation::Operation& op,
         smtk::operation::EventType event,
         smtk::operation::Operation::Result result) {
diff --git a/smtk/extension/paraview/operators/smtkDataSetInfoInspectorView.cxx b/smtk/extension/paraview/operators/smtkDataSetInfoInspectorView.cxx
index 33368f0be6f1bbd8609f9ecb201419d4aef14375..02ce33364769d27e307589e3c96daa9c7accb1c0 100644
--- a/smtk/extension/paraview/operators/smtkDataSetInfoInspectorView.cxx
+++ b/smtk/extension/paraview/operators/smtkDataSetInfoInspectorView.cxx
@@ -21,6 +21,7 @@
 #include "smtk/common/StringUtil.h"
 #include "smtk/extension/qt/qtAttribute.h"
 #include "smtk/extension/qt/qtUIManager.h"
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
 #include "smtk/operation/Manager.h"
 #include "smtk/view/Configuration.h"
 
@@ -286,7 +287,7 @@ void smtkDataSetInfoInspectorView::requestOperation(const smtk::operation::Opera
   auto opManager = op->manager();
   if (!m_p->m_opObserver.assigned() && opManager)
   {
-    smtk::operation::Observer observer = [this](
+    smtk::operation::Observer observer = [this](smtk::common::Context ctx,
                                            const smtk::operation::Operation& op,
                                            smtk::operation::EventType event,
                                            smtk::operation::Operation::Result result) {
@@ -298,7 +299,7 @@ void smtkDataSetInfoInspectorView::requestOperation(const smtk::operation::Opera
       }
       return 0; // 0 = do not cancel operation
     };
-    m_p->m_opObserver = opManager->observers().insert(
+    m_p->m_opObserver = qtInvokeOnMainThreadBehavior::instance()->operationObservers().insert(
       observer,
       std::numeric_limits<smtk::operation::Observers::Priority>::lowest(),
       /* initialize */ false,
diff --git a/smtk/extension/paraview/operators/smtkEditPropertiesView.cxx b/smtk/extension/paraview/operators/smtkEditPropertiesView.cxx
index 80bc14e068fe04e5c1fdaf0f39b917265df28144..dac24557dfd6649b3135f9d93bab3d5ce96366fa 100644
--- a/smtk/extension/paraview/operators/smtkEditPropertiesView.cxx
+++ b/smtk/extension/paraview/operators/smtkEditPropertiesView.cxx
@@ -21,6 +21,7 @@
 #include "smtk/attribute/StringItem.h"
 #include "smtk/extension/qt/qtAttribute.h"
 #include "smtk/extension/qt/qtAttributeItemInfo.h"
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
 #include "smtk/extension/qt/qtUIManager.h"
 #include "smtk/operation/Manager.h"
 #include "smtk/resource/Component.h"
@@ -496,13 +497,14 @@ smtkEditPropertiesView::smtkEditPropertiesView(const smtk::view::Information& in
   {
     const auto& managers = uiManager->managers();
     const auto& selection = managers.get<smtk::view::Selection::Ptr>();
-    m_p->m_selectionObserver = selection->observers().insert(
-      [this](const std::string& src, std::shared_ptr<smtk::view::Selection> const& sel) {
-        m_p->selectionModified(src, sel);
-      },
-      std::numeric_limits<smtk::view::SelectionObservers::Priority>::lowest(),
-      /* initialize immediately */ true,
-      "update freeform attribute editor");
+    m_p->m_selectionObserver =
+      qtInvokeOnMainThreadBehavior::instance()->selectionObservers().insert(
+        [this](const std::string& src, std::shared_ptr<smtk::view::Selection> const& sel) {
+          m_p->selectionModified(src, sel);
+        },
+        std::numeric_limits<smtk::view::SelectionObservers::Priority>::lowest(),
+        /* initialize immediately */ true,
+        "update freeform attribute editor");
   }
 }
 
diff --git a/smtk/extension/paraview/server/RespondToVTKSelection.cxx b/smtk/extension/paraview/server/RespondToVTKSelection.cxx
index 64e84e2b6ba8c175ba2c415867a91648464177c0..fbb744a7b87b920f53885e42f2c6145076a8f900 100644
--- a/smtk/extension/paraview/server/RespondToVTKSelection.cxx
+++ b/smtk/extension/paraview/server/RespondToVTKSelection.cxx
@@ -368,7 +368,7 @@ bool RespondToVTKSelection::transcribeBlockSelection()
   return didModify;
 }
 
-RespondToVTKSelection::Result RespondToVTKSelection::operateInternal()
+RespondToVTKSelection::Result RespondToVTKSelection::operateInternal(Context ctx)
 {
   bool worked = this->transcribeBlockSelection();
   auto result = this->createResult(
diff --git a/smtk/extension/paraview/server/RespondToVTKSelection.h b/smtk/extension/paraview/server/RespondToVTKSelection.h
index 4134bc51f9194b8e0075ff882184c01604d1011d..980c51caf8b8b6f11ea0119301bdc9564bb128ee 100644
--- a/smtk/extension/paraview/server/RespondToVTKSelection.h
+++ b/smtk/extension/paraview/server/RespondToVTKSelection.h
@@ -144,7 +144,7 @@ protected:
   bool transcribeBlockSelection();
 
   /// By default, only handle block selections by calling transcribeBlockSelection().
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   /// Fail or succeed quietly.
   void generateSummary(Operation::Result&) override {}
 
diff --git a/smtk/extension/paraview/widgets/pqSMTKTransformWidget.cxx b/smtk/extension/paraview/widgets/pqSMTKTransformWidget.cxx
index bcc8f398db8cb575f267a89c2c52ab0f69a51173..71b45df8ed9ccd8d51aae74d5fdca995dcb8cd7a 100644
--- a/smtk/extension/paraview/widgets/pqSMTKTransformWidget.cxx
+++ b/smtk/extension/paraview/widgets/pqSMTKTransformWidget.cxx
@@ -17,6 +17,7 @@
 
 #include "smtk/attribute/operators/Signal.h"
 
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
 #include "smtk/extension/qt/qtOperationView.h"
 
 #include "smtk/geometry/queries/BoundingBox.h"
@@ -59,10 +60,11 @@ template<typename MyClass>
 class CanHideReferenceBounds
 {
   template<typename X>
-  static std::true_type testConstructorWithArgs(decltype(X{ std::declval<vtkSMProxy*>(),
-                                                            std::declval<vtkSMPropertyGroup*>(),
-                                                            std::declval<QWidget*>(),
-                                                            std::declval<bool>() })*);
+  static std::true_type testConstructorWithArgs(
+    decltype(X{ std::declval<vtkSMProxy*>(),
+                std::declval<vtkSMPropertyGroup*>(),
+                std::declval<QWidget*>(),
+                std::declval<bool>() })*);
   template<typename X>
   static std::false_type testConstructorWithArgs(...);
 
@@ -107,34 +109,36 @@ pqSMTKTransformWidget::pqSMTKTransformWidget(
 {
 
   QPointer<pqSMTKTransformWidget> guardedObject(this);
-  m_internal->m_opObserver = info.baseView()->uiManager()->operationManager()->observers().insert(
-    [guardedObject](
-      const smtk::operation::Operation& op,
-      smtk::operation::EventType event,
-      smtk::operation::Operation::Result res) {
-      if (
-        !guardedObject || !guardedObject->item() ||
-        event != smtk::operation::EventType::DID_OPERATE ||
-        op.index() == std::type_index(typeid(smtk::attribute::Signal)).hash_code())
-      {
-        return 0;
-      }
-
-      auto attribute = guardedObject->item()->attribute();
-      if (!attribute)
-      {
+  m_internal->m_opObserver =
+    smtk::extension::qtInvokeOnMainThreadBehavior::instance()->operationObservers().insert(
+      [guardedObject](
+      smtk::common::Context ctx,
+        const smtk::operation::Operation& op,
+        smtk::operation::EventType event,
+        smtk::operation::Operation::Result res) {
+        if (
+          !guardedObject || !guardedObject->item() ||
+          event != smtk::operation::EventType::DID_OPERATE ||
+          op.index() == std::type_index(typeid(smtk::attribute::Signal)).hash_code())
+        {
+          return 0;
+        }
+
+        auto attribute = guardedObject->item()->attribute();
+        if (!attribute)
+        {
+          return 0;
+        }
+
+        smtk::resource::PersistentObjectPtr object = attribute->associations()->value();
+
+        if (res->findReference("modified")->contains(attribute->associations()->value()))
+        {
+          guardedObject->resetWidget();
+        }
         return 0;
-      }
-
-      smtk::resource::PersistentObjectPtr object = attribute->associations()->value();
-
-      if (res->findReference("modified")->contains(attribute->associations()->value()))
-      {
-        guardedObject->resetWidget();
-      }
-      return 0;
-    },
-    "pqSMTKTransformWidget: Reset widget if the item being transformed is modified.");
+      },
+      "pqSMTKTransformWidget: Reset widget if the item being transformed is modified.");
 
   this->createWidget();
 }
diff --git a/smtk/extension/qt/CMakeLists.txt b/smtk/extension/qt/CMakeLists.txt
index f27150fc62c89c4074bb827c01a80fd2924e169e..e23c7008073e0a794c67446580cfb1c5a655ee9f 100644
--- a/smtk/extension/qt/CMakeLists.txt
+++ b/smtk/extension/qt/CMakeLists.txt
@@ -25,6 +25,7 @@ set(QAttrLibSrcs
   qtAssociation2ColumnWidget.cxx
   qtAttributeView.cxx
   qtInstancedView.cxx
+  qtInvokeOnMainThreadBehavior.cxx
   qtComponentAttributeView.cxx
   qtOperationAction.cxx
   qtOperationDialog.cxx
@@ -148,6 +149,7 @@ set(QAttrLibMocHeaders
   qtAssociationView.h
   qtAttributeView.h
   qtInstancedView.h
+  qtInvokeOnMainThreadBehavior.h
   qtComponentAttributeView.h
   qtNotEditableDelegate.h
   qtOperationAction.h
@@ -245,6 +247,7 @@ set(QAttrLibHeaders
   qtDirectoryItem.h
   qtDoubleItem.h
   qtIntItem.h
+  qtInvokeOnMainThreadBehavior.h
   qtResourceBrowserP.h
   qtSMTKUtilities.h
   qtStringItem.h
diff --git a/smtk/extension/qt/diagram/qtDefaultTaskNode.cxx b/smtk/extension/qt/diagram/qtDefaultTaskNode.cxx
index 1f42c2dd930b84450f52a3a3537392e10088ffd9..68a8fd4a392bdb9df05883398463a6dc66e2a51d 100644
--- a/smtk/extension/qt/diagram/qtDefaultTaskNode.cxx
+++ b/smtk/extension/qt/diagram/qtDefaultTaskNode.cxx
@@ -15,6 +15,7 @@
 #include "smtk/extension/qt/diagram/qtDiagramViewConfiguration.h"
 #include "smtk/extension/qt/diagram/qtTaskEditor.h"
 #include "smtk/extension/qt/qtBaseView.h"
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
 
 #include "smtk/attribute/Attribute.h"
 #include "smtk/attribute/StringItem.h"
@@ -110,7 +111,7 @@ public:
         // so, check that qApp exists before going further.
         if (qApp)
         {
-          this->updateTaskState(prev, next, m_node->isActive());
+          qtInvokeOnMainThreadBehavior::invokeOnMainThread([&]() { this->updateTaskState(prev, next, m_node->isActive()); });
         }
       },
       "DefaultTaskNodeWidget observer");
diff --git a/smtk/extension/qt/diagram/qtDefaultTaskNode1.cxx b/smtk/extension/qt/diagram/qtDefaultTaskNode1.cxx
index 11f2a9a30c67f2dc495f50c60bde063ccf6f7b2d..563133315eb5f8a1c313e0a8cf9eb85d020f7357 100644
--- a/smtk/extension/qt/diagram/qtDefaultTaskNode1.cxx
+++ b/smtk/extension/qt/diagram/qtDefaultTaskNode1.cxx
@@ -15,6 +15,7 @@
 #include "smtk/extension/qt/diagram/qtDiagramViewConfiguration.h"
 #include "smtk/extension/qt/diagram/qtTaskEditor.h"
 #include "smtk/extension/qt/qtBaseView.h"
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
 
 #include "smtk/task/Active.h"
 #include "smtk/task/Manager.h"
@@ -122,7 +123,7 @@ public:
         // so, check that qApp exists before going further.
         if (qApp)
         {
-          this->updateTaskState(prev, next, m_node->isActive());
+          qtInvokeOnMainThreadBehavior::invokeOnMainThread([&]() { this->updateTaskState(prev, next, m_node->isActive()); });
         }
       },
       "DefaultTaskNodeWidget1 observer");
diff --git a/smtk/extension/qt/diagram/qtDiagram.cxx b/smtk/extension/qt/diagram/qtDiagram.cxx
index e03dfc602f655bd0c83f20e5f1c1198b62a91276..af389afb4bfcea334eff1ecd328f92e8ee2786af 100644
--- a/smtk/extension/qt/diagram/qtDiagram.cxx
+++ b/smtk/extension/qt/diagram/qtDiagram.cxx
@@ -26,6 +26,7 @@
 #include "smtk/common/json/jsonUUID.h"
 
 #include "smtk/extension/qt/SVGIconEngine.h"
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
 #include "smtk/extension/qt/qtManager.h"
 
 // nodes
@@ -396,8 +397,9 @@ public:
 
     if (m_operationManager)
     {
-      m_onKey = m_operationManager->observers().insert(
+      m_onKey = qtInvokeOnMainThreadBehavior::instance()->operationObservers().insert(
         [this](
+        smtk::common::Context ctx,
           const smtk::operation::Operation& op,
           smtk::operation::EventType event,
           smtk::operation::Operation::Result result) {
@@ -419,7 +421,7 @@ public:
       if (selection)
       {
         QPointer<qtDiagram> selfOrNull(m_self);
-        m_selectionObserver = selection->observers().insert(
+        m_selectionObserver = qtInvokeOnMainThreadBehavior::instance()->selectionObservers().insert(
           [this, selfOrNull](const std::string& changeSource, smtk::view::Selection::Ptr) {
             // Do nothing if our parent qtDiagram object has been destroyed.
             if (!selfOrNull)
diff --git a/smtk/extension/qt/diagram/qtTaskEditor.cxx b/smtk/extension/qt/diagram/qtTaskEditor.cxx
index 22f67971af7986bc7094a07fc75b12b26aca1ecf..36bbef520e583a979cf7467d76b6babd79ca4a27 100644
--- a/smtk/extension/qt/diagram/qtTaskEditor.cxx
+++ b/smtk/extension/qt/diagram/qtTaskEditor.cxx
@@ -36,6 +36,8 @@
 #include "smtk/extension/qt/diagram/qtPanMode.h"
 #include "smtk/extension/qt/diagram/qtSelectMode.h"
 
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
+
 #include "smtk/view/Configuration.h"
 #include "smtk/view/json/jsonView.h"
 
@@ -299,8 +301,9 @@ bool qtTaskEditor::updateArcs(
         continue;
       }
       if (
-        depTasks.find(std::static_pointer_cast<smtk::task::Task>(
-          predecessor->task()->shared_from_this())) != depTasks.end())
+        depTasks.find(
+          std::static_pointer_cast<smtk::task::Task>(predecessor->task()->shared_from_this())) !=
+        depTasks.end())
       {
         // This predecessor is still a dependency. No need to remove it.
         continue;
@@ -594,45 +597,47 @@ void qtTaskEditor::updateSceneNodes(
       m_p->m_worklets->setToplevelCatagoryExpression(m_p->m_taskManager->toplevelExpression());
       m_p->m_activeObserverKey = project->taskManager().active().observers().insert(
         [this, self](smtk::task::Task* prev, smtk::task::Task* next) {
-          if (!self)
-          {
-            return;
-          }
-          // std::cout << "Switch active task from " << prev << " to " << next << "\n";
-          // What is the current tail of the task path
-          auto* currentLastTask = m_taskPath->lastTask();
-          auto* prevTaskNode = this->findTaskNode(prev);
-          auto* nextTaskNode = this->findTaskNode(next);
-          if (prevTaskNode)
-          {
-            auto prevState = prev->state();
-            prevTaskNode->updateTaskState(prevState, prevState, false);
-            prevTaskNode->setOutlineStyle(qtBaseTaskNode::OutlineStyle::Normal);
-          }
-          if (nextTaskNode)
-          {
-            auto nextState = next->state();
-            nextTaskNode->updateTaskState(nextState, nextState, true);
-            nextTaskNode->setOutlineStyle(qtBaseTaskNode::OutlineStyle::Active);
-          }
-          this->m_taskPath->setActiveTask(next);
-          // Update visibility if needed
-          auto* newLastTask = m_taskPath->lastTask();
-          this->updateVisibility(currentLastTask, newLastTask);
-          // Update the worklet palette
-          shared_ptr<smtk::task::Task> task;
-          // Is there a new active task?
-          if (next)
-          {
-            task = std::dynamic_pointer_cast<smtk::task::Task>(next->shared_from_this());
-          }
-          // Else what is the last task listed in the task path?
-          else if (m_taskPath->lastTask())
-          {
-            task = std::dynamic_pointer_cast<smtk::task::Task>(
-              m_taskPath->lastTask()->shared_from_this());
-          }
-          m_p->m_worklets->setParentTask(task);
+          qtInvokeOnMainThreadBehavior::invokeOnMainThread([&]() {
+            if (!self)
+            {
+              return;
+            }
+            // std::cout << "Switch active task from " << prev << " to " << next << "\n";
+            // What is the current tail of the task path
+            auto* currentLastTask = m_taskPath->lastTask();
+            auto* prevTaskNode = this->findTaskNode(prev);
+            auto* nextTaskNode = this->findTaskNode(next);
+            if (prevTaskNode)
+            {
+              auto prevState = prev->state();
+              prevTaskNode->updateTaskState(prevState, prevState, false);
+              prevTaskNode->setOutlineStyle(qtBaseTaskNode::OutlineStyle::Normal);
+            }
+            if (nextTaskNode)
+            {
+              auto nextState = next->state();
+              nextTaskNode->updateTaskState(nextState, nextState, true);
+              nextTaskNode->setOutlineStyle(qtBaseTaskNode::OutlineStyle::Active);
+            }
+            this->m_taskPath->setActiveTask(next);
+            // Update visibility if needed
+            auto* newLastTask = m_taskPath->lastTask();
+            this->updateVisibility(currentLastTask, newLastTask);
+            // Update the worklet palette
+            shared_ptr<smtk::task::Task> task;
+            // Is there a new active task?
+            if (next)
+            {
+              task = std::dynamic_pointer_cast<smtk::task::Task>(next->shared_from_this());
+            }
+            // Else what is the last task listed in the task path?
+            else if (m_taskPath->lastTask())
+            {
+              task = std::dynamic_pointer_cast<smtk::task::Task>(
+                m_taskPath->lastTask()->shared_from_this());
+            }
+            m_p->m_worklets->setParentTask(task);
+          });
         },
         0,
         true,
diff --git a/smtk/extension/qt/diagram/qtTaskNode.cxx b/smtk/extension/qt/diagram/qtTaskNode.cxx
index 79b676ef7ef1a73478abaa7af9420d581d5924b7..2d9f5dd12950f5f452bc46f704766598c33d99ce 100644
--- a/smtk/extension/qt/diagram/qtTaskNode.cxx
+++ b/smtk/extension/qt/diagram/qtTaskNode.cxx
@@ -15,6 +15,7 @@
 #include "smtk/extension/qt/diagram/qtDiagramViewConfiguration.h"
 #include "smtk/extension/qt/diagram/qtTaskEditor.h"
 #include "smtk/extension/qt/qtBaseView.h"
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
 
 #include "smtk/attribute/Attribute.h"
 #include "smtk/attribute/StringItem.h"
@@ -576,14 +577,16 @@ qtTaskNode::qtTaskNode(qtDiagramGenerator* generator, smtk::task::Task* task, QG
 
   m_taskObserver = m_task->observers().insert(
     [this](smtk::task::Task&, smtk::task::State prev, smtk::task::State next) {
-      // Sometimes the application invokes this observer after the GUI
-      // has been shut down. Calling setEnabled on widgets generates a
-      // log message and attempting to construct a QPixmap throws exceptions;
-      // so, check that qApp exists before going further.
-      if (qApp)
-      {
-        this->updateTaskState(prev, next, this->isActive());
-      }
+      qtInvokeOnMainThreadBehavior::invokeOnMainThread([&]() {
+        // Sometimes the application invokes this observer after the GUI
+        // has been shut down. Calling setEnabled on widgets generates a
+        // log message and attempting to construct a QPixmap throws exceptions;
+        // so, check that qApp exists before going further.
+        if (qApp)
+        {
+          this->updateTaskState(prev, next, this->isActive());
+        }
+      });
     },
     "qtTaskNode task-observer");
 
diff --git a/smtk/extension/qt/diagram/qtTaskPath.cxx b/smtk/extension/qt/diagram/qtTaskPath.cxx
index 2a8c08f5dd73c060f33b94a8b4340cb55818f780..632cb319f27767d9046a5e62514461eb8c36217f 100644
--- a/smtk/extension/qt/diagram/qtTaskPath.cxx
+++ b/smtk/extension/qt/diagram/qtTaskPath.cxx
@@ -12,6 +12,7 @@
 #include "smtk/extension/qt/diagram/qtDiagramScene.h"
 #include "smtk/extension/qt/diagram/qtDiagramViewConfiguration.h"
 #include "smtk/extension/qt/diagram/qtTaskEditor.h"
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
 
 #include "smtk/task/State.h"
 #include "smtk/task/Task.h"
@@ -73,14 +74,16 @@ public:
         [tb](smtk::task::Task& t, smtk::task::State prev, smtk::task::State next) {
           (void)t;
           (void)prev;
-          if (!tb)
-          {
-            return; // widget has been deleted
-          }
-          tb->setIcon(renderStatusIcon(
-            next,
-            tb->height() / 3,
-            tb->m_taskPath->editor()->diagram()->diagramScene()->configuration()));
+          smtk::extension::qtInvokeOnMainThreadBehavior::invokeOnMainThread([&]() {
+            if (!tb)
+            {
+              return; // widget has been deleted
+            }
+            tb->setIcon(renderStatusIcon(
+              next,
+              tb->height() / 3,
+              tb->m_taskPath->editor()->diagram()->diagramScene()->configuration()));
+          });
         });
     }
   }
diff --git a/smtk/extension/qt/qtAssociation2ColumnWidget.cxx b/smtk/extension/qt/qtAssociation2ColumnWidget.cxx
index 3f5274bca9a316d0a3c1a670d03d80b272309a3a..3b6c9a11fad14b8229db0ec05c5a357f21a4c53c 100644
--- a/smtk/extension/qt/qtAssociation2ColumnWidget.cxx
+++ b/smtk/extension/qt/qtAssociation2ColumnWidget.cxx
@@ -12,6 +12,7 @@
 
 #include "smtk/extension/qt/qtAttribute.h"
 #include "smtk/extension/qt/qtBaseView.h"
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
 #include "smtk/extension/qt/qtItem.h"
 #include "smtk/extension/qt/qtSMTKUtilities.h"
 #include "smtk/extension/qt/qtTableWidget.h"
@@ -122,8 +123,9 @@ qtAssociation2ColumnWidget::qtAssociation2ColumnWidget(QWidget* _p, qtBaseView*
   QPointer<qtAssociation2ColumnWidget> guardedObject(this);
   if (opManager != nullptr)
   {
-    m_operationObserverKey = opManager->observers().insert(
+    m_operationObserverKey = qtInvokeOnMainThreadBehavior::instance()->operationObservers().insert(
       [guardedObject](
+      smtk::common::Context ctx,
         const smtk::operation::Operation& oper,
         smtk::operation::EventType event,
         smtk::operation::Operation::Result result) -> int {
@@ -142,7 +144,7 @@ qtAssociation2ColumnWidget::qtAssociation2ColumnWidget(QWidget* _p, qtBaseView*
   auto resManager = m_view->uiManager()->resourceManager();
   if (resManager != nullptr)
   {
-    m_resourceObserverKey = resManager->observers().insert(
+    m_resourceObserverKey = qtInvokeOnMainThreadBehavior::instance()->resourceObservers().insert(
       [guardedObject](const smtk::resource::Resource& resource, smtk::resource::EventType event) {
         if (guardedObject == nullptr)
         {
diff --git a/smtk/extension/qt/qtAttributeView.cxx b/smtk/extension/qt/qtAttributeView.cxx
index 7590d1686a8ebca381c6a0e03abab548988cda59..efbbb0b51ae75bef02402a3f60698a7d07e445bf 100644
--- a/smtk/extension/qt/qtAttributeView.cxx
+++ b/smtk/extension/qt/qtAttributeView.cxx
@@ -13,6 +13,7 @@
 #include "smtk/extension/qt/qtAssociation2ColumnWidget.h"
 #include "smtk/extension/qt/qtAttribute.h"
 #include "smtk/extension/qt/qtCheckItemComboBox.h"
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
 #include "smtk/extension/qt/qtItem.h"
 #include "smtk/extension/qt/qtNotEditableDelegate.h"
 #include "smtk/extension/qt/qtRegexDelegate.h"
@@ -513,18 +514,20 @@ void qtAttributeView::createWidget()
   QPointer<qtAttributeView> guardedObject(this);
   if (opManager != nullptr)
   {
-    m_internals->m_observerKey = opManager->observers().insert(
-      [guardedObject](
-        const smtk::operation::Operation& oper,
-        smtk::operation::EventType event,
-        smtk::operation::Operation::Result result) -> int {
-        if (guardedObject == nullptr)
-        {
-          return 0;
-        }
-        return guardedObject->handleOperationEvent(oper, event, result);
-      },
-      "qtInstancedView: Refresh qtAttributeView when components are modified.");
+    m_internals->m_observerKey =
+      qtInvokeOnMainThreadBehavior::instance()->operationObservers().insert(
+        [guardedObject](
+        smtk::common::Context ctx,
+          const smtk::operation::Operation& oper,
+          smtk::operation::EventType event,
+          smtk::operation::Operation::Result result) -> int {
+          if (guardedObject == nullptr)
+          {
+            return 0;
+          }
+          return guardedObject->handleOperationEvent(oper, event, result);
+        },
+        "qtInstancedView: Refresh qtAttributeView when components are modified.");
   }
 
   // Initialize any object connected to definitionSelected later
diff --git a/smtk/extension/qt/qtAvailableOperations.cxx b/smtk/extension/qt/qtAvailableOperations.cxx
index e9ecafd62335d112b4fa1bd07db45a1fe434ff48..b93c1a772db6054a1d924f36e11ccb0d951d9d12 100644
--- a/smtk/extension/qt/qtAvailableOperations.cxx
+++ b/smtk/extension/qt/qtAvailableOperations.cxx
@@ -9,6 +9,7 @@
 //=========================================================================
 #include "smtk/extension/qt/qtAvailableOperations.h"
 
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
 #include "smtk/operation/MetadataContainer.h"
 #include "smtk/operation/SpecificationOps.h"
 #include "smtk/view/AvailableOperations.h"
@@ -46,7 +47,9 @@ void qtAvailableOperations::setOperationSource(smtk::view::AvailableOperationsPt
   if (m_operationSource)
   {
     m_operationSourceObserverId = m_operationSource->observers().insert(
-      [this](smtk::view::AvailableOperationsPtr /*unused*/) { this->updateList(); },
+      [this](smtk::view::AvailableOperationsPtr /*unused*/) {
+        qtInvokeOnMainThreadBehavior::invokeOnMainThread([&]() { this->updateList(); });
+      },
       0,    // assign a neutral priority
       true, // immediatelyInvoke
       "qtAvailableOperations: Update list of available operations.");
diff --git a/smtk/extension/qt/qtComponentAttributeView.cxx b/smtk/extension/qt/qtComponentAttributeView.cxx
index 01a9c652d9f6abad6fc9f036c29ebccdfb475a97..66a396ffd2f385633ca37ca830415f09cff1c77a 100644
--- a/smtk/extension/qt/qtComponentAttributeView.cxx
+++ b/smtk/extension/qt/qtComponentAttributeView.cxx
@@ -11,6 +11,7 @@
 #include "smtk/extension/qt/qtComponentAttributeView.h"
 
 #include "smtk/extension/qt/qtAttribute.h"
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
 #include "smtk/extension/qt/qtSMTKUtilities.h"
 #include "smtk/extension/qt/qtTableWidget.h"
 #include "smtk/extension/qt/qtUIManager.h"
@@ -261,16 +262,17 @@ void qtComponentAttributeView::buildUI()
                                      << "failed. Already existed!");
     }
     QPointer<qtComponentAttributeView> guardedObject(this);
-    this->Internals->m_selectionObserverId = sel->observers().insert(
-      [guardedObject](const std::string& selectionSource, smtk::view::SelectionPtr sp) {
-        if (guardedObject != nullptr)
-        {
-          guardedObject->updateSelectedComponent(selectionSource, sp);
-        }
-      },
-      0,
-      true,
-      "qtComponentAttributeView: Change focus on selection.");
+    this->Internals->m_selectionObserverId =
+      qtInvokeOnMainThreadBehavior::instance()->selectionObservers().insert(
+        [guardedObject](const std::string& selectionSource, smtk::view::SelectionPtr sp) {
+          if (guardedObject != nullptr)
+          {
+            guardedObject->updateSelectedComponent(selectionSource, sp);
+          }
+        },
+        0,
+        true,
+        "qtComponentAttributeView: Change focus on selection.");
   }
 }
 
diff --git a/smtk/extension/qt/qtDescriptivePhraseModel.cxx b/smtk/extension/qt/qtDescriptivePhraseModel.cxx
index 7c1f3c54ebfb0f3d1c2227e4d023631409cc5e85..d47eff48c7928132a6ea08f6bbb185e69f7a01f1 100644
--- a/smtk/extension/qt/qtDescriptivePhraseModel.cxx
+++ b/smtk/extension/qt/qtDescriptivePhraseModel.cxx
@@ -10,6 +10,7 @@
 #include "smtk/extension/qt/qtDescriptivePhraseModel.h"
 
 #include "smtk/extension/qt/SVGIconEngine.h"
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
 #include "smtk/extension/qt/qtTypeDeclarations.h"
 
 #include "smtk/view/DescriptivePhrase.h"
@@ -155,7 +156,10 @@ void qtDescriptivePhraseModel::setPhraseModel(smtk::view::PhraseModelPtr model)
         smtk::view::PhraseModelEvent event,
         const std::vector<int>& src,
         const std::vector<int>& dst,
-        const std::vector<int>& range) { this->updateObserver(phrase, event, src, dst, range); },
+        const std::vector<int>& range) {
+        qtInvokeOnMainThreadBehavior::invokeOnMainThread(
+          [&]() { this->updateObserver(phrase, event, src, dst, range); });
+      },
       0,
       true,
       modelDesc.str());
diff --git a/smtk/extension/qt/qtInstancedView.cxx b/smtk/extension/qt/qtInstancedView.cxx
index 4fb7954f1d496f9eb79fec9ac7ce31b667e97a5f..6840e3e9bdf33d08d4329e4804f9d873fb434e36 100644
--- a/smtk/extension/qt/qtInstancedView.cxx
+++ b/smtk/extension/qt/qtInstancedView.cxx
@@ -15,6 +15,7 @@
 #include "smtk/attribute/StringItem.h"
 #include "smtk/attribute/operators/Signal.h"
 #include "smtk/extension/qt/qtAttribute.h"
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
 #include "smtk/extension/qt/qtUIManager.h"
 #include "smtk/operation/Manager.h"
 #include "smtk/operation/Observer.h"
@@ -113,18 +114,20 @@ void qtInstancedView::createWidget()
   QPointer<qtInstancedView> guardedObject(this);
   if (opManager != nullptr)
   {
-    this->Internals->m_observerKey = opManager->observers().insert(
-      [guardedObject](
-        const smtk::operation::Operation& oper,
-        smtk::operation::EventType event,
-        smtk::operation::Operation::Result result) -> int {
-        if (guardedObject == nullptr)
-        {
-          return 0;
-        }
-        return guardedObject->handleOperationEvent(oper, event, result);
-      },
-      "qtInstancedView: Refresh qtInstancedView when components are modified.");
+    this->Internals->m_observerKey =
+      qtInvokeOnMainThreadBehavior::instance()->operationObservers().insert(
+        [guardedObject](
+        smtk::common::Context ctx,
+          const smtk::operation::Operation& oper,
+          smtk::operation::EventType event,
+          smtk::operation::Operation::Result result) -> int {
+          if (guardedObject == nullptr)
+          {
+            return 0;
+          }
+          return guardedObject->handleOperationEvent(oper, event, result);
+        },
+        "qtInstancedView: Refresh qtInstancedView when components are modified.");
   }
 }
 
diff --git a/smtk/extension/qt/qtInvokeOnMainThreadBehavior.cxx b/smtk/extension/qt/qtInvokeOnMainThreadBehavior.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..acd03102eed87984960eee501b0f7e0e20913c60
--- /dev/null
+++ b/smtk/extension/qt/qtInvokeOnMainThreadBehavior.cxx
@@ -0,0 +1,127 @@
+//=========================================================================
+//  Copyright (c) Kitware, Inc.
+//  All rights reserved.
+//  See LICENSE.txt for details.
+//
+//  This software is distributed WITHOUT ANY WARRANTY; without even
+//  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+//  PURPOSE.  See the above copyright notice for more information.
+//=========================================================================
+
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
+
+#include "smtk/operation/Manager.h"
+#include "smtk/resource/Manager.h"
+#include "smtk/view/Selection.h"
+
+#include <unordered_map>
+
+namespace smtk
+{
+namespace extension
+{
+
+static qtInvokeOnMainThreadBehavior* g_instance = nullptr;
+
+class qtInvokeOnMainThreadBehaviorPrivate : public QObject
+{
+public:
+  explicit qtInvokeOnMainThreadBehaviorPrivate(QObject* parent)
+    : QObject(parent)
+  {
+  }
+
+  smtk::resource::Observers m_resourceObservers;
+  smtk::operation::Observers m_operationObservers;
+  smtk::view::SelectionObservers m_selectionObservers;
+
+  std::unordered_map<smtk::resource::ManagerPtr, smtk::resource::Observers::Key>
+    m_resourceObserverKeys;
+  std::unordered_map<smtk::operation::ManagerPtr, smtk::operation::Observers::Key>
+    m_operationObserverKeys;
+  std::unordered_map<smtk::view::SelectionPtr, smtk::view::SelectionObservers::Key>
+    m_selectionObserverKeys;
+};
+
+qtInvokeOnMainThreadBehavior* qtInvokeOnMainThreadBehavior::instance(QObject* parent)
+{
+  if (!g_instance)
+  {
+    g_instance = new qtInvokeOnMainThreadBehavior(parent);
+  }
+
+  if (g_instance->parent() == nullptr && parent)
+  {
+    g_instance->setParent(parent);
+  }
+
+  return g_instance;
+}
+qtInvokeOnMainThreadBehavior::~qtInvokeOnMainThreadBehavior() {}
+
+smtk::resource::Observers& qtInvokeOnMainThreadBehavior::resourceObservers() const
+{
+  return this->m_private->m_resourceObservers;
+}
+
+smtk::operation::Observers&
+qtInvokeOnMainThreadBehavior::qtInvokeOnMainThreadBehavior::operationObservers() const
+{
+  return this->m_private->m_operationObservers;
+}
+
+smtk::view::SelectionObservers&
+qtInvokeOnMainThreadBehavior::qtInvokeOnMainThreadBehavior::selectionObservers() const
+{
+  return this->m_private->m_selectionObservers;
+}
+
+qtInvokeOnMainThreadBehavior::qtInvokeOnMainThreadBehavior(QObject* parent)
+  : Superclass(parent)
+  , m_private(new qtInvokeOnMainThreadBehaviorPrivate(this))
+{
+}
+
+void qtInvokeOnMainThreadBehavior::addObservers(const smtk::common::Managers& managers) const
+{
+  const auto resourceManager = managers.get<smtk::resource::ManagerPtr>();
+  const auto operationManager = managers.get<smtk::operation::ManagerPtr>();
+  const auto selection = managers.get<smtk::view::SelectionPtr>();
+
+  // Add delegating observers as lowest priority so the GUI is updated last.
+  this->m_private->m_resourceObserverKeys[resourceManager] = resourceManager->observers().insert(
+    [this](const smtk::resource::Resource& rsrc, smtk::resource::EventType event) {
+      invokeOnMainThread(
+        [&]() { this->m_private->m_resourceObservers.callObserversDirectly(rsrc, event); });
+    },
+    INT_MIN,
+    false,
+    "qtInvokeOnMainThreadBehavior resource observer");
+
+  this->m_private->m_operationObserverKeys[operationManager] = operationManager->observers().insert(
+    [&](
+      smtk::common::Context ctx,
+      const smtk::operation::Operation& oper,
+      smtk::operation::EventType event,
+      smtk::operation::Operation::Result result) -> int {
+      return invokeOnMainThread([&]() -> int {
+        return this->m_private->m_operationObservers.callObserversDirectly(
+          ctx, oper, event, result);
+      });
+    },
+    INT_MIN,
+    false,
+    "qtInvokeOnMainThreadBehavior operation observer");
+
+  this->m_private->m_selectionObserverKeys[selection] = selection->observers().insert(
+    [&](const std::string& str, smtk::view::Selection::Ptr selection) {
+      invokeOnMainThread(
+        [&]() { this->m_private->m_selectionObservers.callObserversDirectly(str, selection); });
+    },
+    INT_MIN,
+    false,
+    "qtInvokeOnMainThreadBehavior selection observer");
+}
+
+} // namespace extension
+} // namespace smtk
diff --git a/smtk/extension/qt/qtInvokeOnMainThreadBehavior.h b/smtk/extension/qt/qtInvokeOnMainThreadBehavior.h
new file mode 100644
index 0000000000000000000000000000000000000000..7fef9dc34c5b88a4e6062060dcb9dd45b78e56fb
--- /dev/null
+++ b/smtk/extension/qt/qtInvokeOnMainThreadBehavior.h
@@ -0,0 +1,104 @@
+//=========================================================================
+//  Copyright (c) Kitware, Inc.
+//  All rights reserved.
+//  See LICENSE.txt for details.
+//
+//  This software is distributed WITHOUT ANY WARRANTY; without even
+//  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+//  PURPOSE.  See the above copyright notice for more information.
+//=========================================================================
+#ifndef smtk_extension_qt_InvokeOnMainThreadBehavior_h
+#define smtk_extension_qt_InvokeOnMainThreadBehavior_h
+
+#include "smtk/extension/qt/Exports.h"
+
+#include <QApplication>
+#include <QObject>
+#include <QThread>
+
+#include <smtk/operation/Observer.h>
+#include <smtk/resource/Observer.h>
+#include <smtk/view/SelectionObserver.h>
+
+namespace smtk
+{
+namespace extension
+{
+
+class qtInvokeOnMainThreadBehaviorPrivate;
+
+class SMTKQTEXT_EXPORT qtInvokeOnMainThreadBehavior : public QObject
+{
+  Q_OBJECT
+    using Superclass = QObject;
+public:
+  static qtInvokeOnMainThreadBehavior* instance(QObject* parent = nullptr);
+  ~qtInvokeOnMainThreadBehavior() override;
+
+  template<typename Func, typename... Args>
+  static auto invokeOnMainThread(Func&& fn, Args&&... args) -> std::enable_if_t<
+    // Non-void returning function specialization.
+    !std::is_void_v<decltype(fn(std::forward<Args>(args)...))>,
+    decltype(fn(
+      std::forward<Args>(args)...))>
+  {
+    using ReturnType = decltype(fn(std::forward<Args>(args)...));
+    ReturnType result;
+
+    if (qApp->thread() != QThread::currentThread())
+    {
+      // Not on main thread. Run the function on the main thread while this one blocks until it
+      // returns.
+      QMetaObject::invokeMethod(
+        qApp,
+        [&]() { result = std::invoke(std::forward<Func>(fn), std::forward<Args>(args)...); },
+        Qt::BlockingQueuedConnection);
+    }
+    else
+    {
+      // Call on this thread directly.
+      result = std::invoke(std::forward<Func>(fn), std::forward<Args>(args)...);
+    }
+
+    return result;
+  }
+
+  template<typename Func, typename... Args>
+  static auto invokeOnMainThread(Func&& fn, Args&&... args)
+    // Void returning function specialization.
+    -> std::enable_if_t<std::is_void_v<decltype(fn(std::forward<Args>(args)...))>, void>
+  {
+    if (qApp->thread() != QThread::currentThread())
+    {
+      // Not on main thread. Run the function on the main thread while this one blocks until it
+      // returns.
+      QMetaObject::invokeMethod(
+        qApp,
+        [&]() { std::invoke(std::forward<Func>(fn), std::forward<Args>(args)...); },
+        Qt::BlockingQueuedConnection);
+    }
+    else
+    {
+      // Call on this thread directly.
+      std::invoke(std::forward<Func>(fn), std::forward<Args>(args)...);
+    }
+  }
+
+  void addObservers(const smtk::common::Managers& managers) const;
+  smtk::resource::Observers& resourceObservers() const;
+  smtk::operation::Observers& operationObservers() const;
+  smtk::view::SelectionObservers& selectionObservers() const;
+
+protected:
+  explicit qtInvokeOnMainThreadBehavior(QObject* parent = nullptr);
+
+private:
+  Q_DISABLE_COPY(qtInvokeOnMainThreadBehavior);
+
+  qtInvokeOnMainThreadBehaviorPrivate *m_private;
+};
+
+}
+}
+
+#endif //smtk_extension_qt_InvokeOnMainThreadBehavior_h
diff --git a/smtk/extension/qt/qtOperationTypeModel.cxx b/smtk/extension/qt/qtOperationTypeModel.cxx
index 657275e6b4ddfbfec1f7e9f5f070a82b3a6ab0bd..babedd42c8495af4a3ed67e1a0a079e09f799903 100644
--- a/smtk/extension/qt/qtOperationTypeModel.cxx
+++ b/smtk/extension/qt/qtOperationTypeModel.cxx
@@ -10,6 +10,7 @@
 #include "smtk/extension/qt/qtOperationTypeModel.h"
 
 #include "smtk/extension/qt/SVGIconEngine.h"
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
 #include "smtk/extension/qt/qtOperationAction.h"
 #include "smtk/extension/qt/qtTypeDeclarations.h"
 
@@ -147,16 +148,19 @@ qtOperationTypeModel::qtOperationTypeModel(const smtk::view::Information& info,
     {
       m_selectionValue = m_selection->findOrCreateLabeledValue(selectionValueLabel);
     }
-    m_selectionObserverKey = m_selection->observers().insert(
-      [this](const std::string& src, std::shared_ptr<smtk::view::Selection> seln) {
-        if (!m_operations.empty())
-        {
-          this->updateSelectionAssociability(src, seln, 0, this->rowCount(QModelIndex()) - 1);
-        }
-      },
-      std::numeric_limits<smtk::view::SelectionObservers::Priority>::lowest(),
-      /* initialize */ true,
-      "qtOperationTypeModel associability updater");
+    m_selectionObserverKey =
+      smtk::extension::qtInvokeOnMainThreadBehavior::qtInvokeOnMainThreadBehavior::instance()
+        ->selectionObservers()
+        .insert(
+          [this](const std::string& src, std::shared_ptr<smtk::view::Selection> seln) {
+            if (!m_operations.empty())
+            {
+              this->updateSelectionAssociability(src, seln, 0, this->rowCount(QModelIndex()) - 1);
+            }
+          },
+          std::numeric_limits<smtk::view::SelectionObservers::Priority>::lowest(),
+          /* initialize */ true,
+          "qtOperationTypeModel associability updater");
   }
 }
 
diff --git a/smtk/extension/qt/qtReferenceItem.cxx b/smtk/extension/qt/qtReferenceItem.cxx
index ba04cfa72e94ac207bb829557549c38cfae9552a..e36652a622c86b570b5a3649dde4caceac66e83a 100644
--- a/smtk/extension/qt/qtReferenceItem.cxx
+++ b/smtk/extension/qt/qtReferenceItem.cxx
@@ -14,6 +14,7 @@
 #include "smtk/extension/qt/MembershipBadge.h"
 #include "smtk/extension/qt/qtBadgeActionToggle.h"
 #include "smtk/extension/qt/qtBaseAttributeView.h"
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
 #include "smtk/extension/qt/qtOverlay.h"
 #include "smtk/extension/qt/qtTypeDeclarations.h"
 #include "smtk/extension/qt/qtUIManager.h"
@@ -481,10 +482,12 @@ void qtReferenceItem::updateUI()
         const std::vector<int>& src,
         const std::vector<int>& dst,
         const std::vector<int>& refs) {
-        if (guardedObject)
-        {
-          guardedObject->checkRemovedComponents(phr, evt, src, dst, refs);
-        }
+        qtInvokeOnMainThreadBehavior::invokeOnMainThread([&]() {
+          if (guardedObject)
+          {
+            guardedObject->checkRemovedComponents(phr, evt, src, dst, refs);
+          }
+        });
       },
       "qtReferenceItem: Check for removed components.");
     // we need to know when membership is changed, to update our labels
diff --git a/smtk/extension/qt/qtReferenceItemEditor.cxx b/smtk/extension/qt/qtReferenceItemEditor.cxx
index d5f6a31a77b04e3f39dcf817b39fcbfc7f80f9fd..c5989290ee63a345ced0a1cdb9a964057cc00ed6 100644
--- a/smtk/extension/qt/qtReferenceItemEditor.cxx
+++ b/smtk/extension/qt/qtReferenceItemEditor.cxx
@@ -12,6 +12,7 @@
 
 #include "smtk/extension/qt/qtAttribute.h"
 #include "smtk/extension/qt/qtBaseAttributeView.h"
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
 #include "smtk/extension/qt/qtItem.h"
 #include "smtk/extension/qt/qtSMTKUtilities.h"
 #include "smtk/extension/qt/qtTableWidget.h"
@@ -137,8 +138,9 @@ qtReferenceItemEditor::qtReferenceItemEditor(const qtAttributeItemInfo& info)
   if (opManager != nullptr)
   {
     QPointer<qtReferenceItemEditor> guardedObject(this);
-    m_operationObserverKey = opManager->observers().insert(
+    m_operationObserverKey = qtInvokeOnMainThreadBehavior::instance()->operationObservers().insert(
       [guardedObject](
+      smtk::common::Context ctx,
         const smtk::operation::Operation& oper,
         smtk::operation::EventType event,
         smtk::operation::Operation::Result result) -> int {
@@ -160,7 +162,7 @@ qtReferenceItemEditor::qtReferenceItemEditor(const qtAttributeItemInfo& info)
   auto resManager = uiManager->resourceManager();
   if (resManager != nullptr)
   {
-    m_resourceObserverKey = resManager->observers().insert(
+    m_resourceObserverKey = qtInvokeOnMainThreadBehavior::instance()->resourceObservers().insert(
       [this](const smtk::resource::Resource& resource, smtk::resource::EventType event) {
         this->handleResourceEvent(resource, event);
       },
diff --git a/smtk/extension/qt/qtReferenceTree.cxx b/smtk/extension/qt/qtReferenceTree.cxx
index 728347fe889d25d0e42dbbdf9c9a9db6b5fc4991..1efa879e0add65de2ee143b9a5e7355ce2c673e6 100644
--- a/smtk/extension/qt/qtReferenceTree.cxx
+++ b/smtk/extension/qt/qtReferenceTree.cxx
@@ -14,6 +14,7 @@
 #include "smtk/extension/qt/VisibilityBadge.h"
 #include "smtk/extension/qt/qtBadgeActionToggle.h"
 #include "smtk/extension/qt/qtBaseAttributeView.h"
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
 #include "smtk/extension/qt/qtOverlay.h"
 #include "smtk/extension/qt/qtTypeDeclarations.h"
 #include "smtk/extension/qt/qtUIManager.h"
@@ -496,10 +497,12 @@ void qtReferenceTree::updateUI()
         const std::vector<int>& src,
         const std::vector<int>& dst,
         const std::vector<int>& refs) {
-        if (guardedObject)
-        {
-          guardedObject->checkRemovedComponents(phr, evt, src, dst, refs);
-        }
+        qtInvokeOnMainThreadBehavior::invokeOnMainThread([&]() {
+          if (guardedObject)
+          {
+            guardedObject->checkRemovedComponents(phr, evt, src, dst, refs);
+          }
+        });
       },
       "qtReferenceTree: Check for removed components.");
     // we need to know when membership is changed, to update our labels
diff --git a/smtk/extension/qt/qtResourceBrowser.cxx b/smtk/extension/qt/qtResourceBrowser.cxx
index 2261af639e6f7b6dde31a8b96e7cab72e86ef1eb..f6d520b62b17919d4ef949432c47edcfa38759b9 100644
--- a/smtk/extension/qt/qtResourceBrowser.cxx
+++ b/smtk/extension/qt/qtResourceBrowser.cxx
@@ -48,6 +48,7 @@
 #include <QPointer>
 #include <QTreeView>
 
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
 #include "smtk/extension/qt/qtResourceBrowserP.h"
 #include "smtk/extension/qt/qtTypeDeclarations.h"
 
@@ -286,7 +287,7 @@ void qtResourceBrowser::addSource(smtk::common::TypeContainer& managers)
     m_p->m_hoverValue = m_p->m_seln->findOrCreateLabeledValue(m_p->m_hoverLabel);
     QPointer<qtResourceBrowser> self(this);
     m_p->m_seln->registerSelectionSource(m_p->m_selnSource);
-    m_p->m_selnHandle = m_p->m_seln->observers().insert(
+    m_p->m_selnHandle = qtInvokeOnMainThreadBehavior::instance()->selectionObservers().insert(
       [self](const std::string& source, smtk::view::Selection::Ptr seln) {
         if (self)
         {
diff --git a/smtk/extension/qt/qtSMTKCallObserversOnMainThreadBehavior.cxx b/smtk/extension/qt/qtSMTKCallObserversOnMainThreadBehavior.cxx
index 57031deea83f12bcb186d48ee7be56e0fd8a778b..e943e0cf947ef472aaabed4d6adea34a59e176c0 100644
--- a/smtk/extension/qt/qtSMTKCallObserversOnMainThreadBehavior.cxx
+++ b/smtk/extension/qt/qtSMTKCallObserversOnMainThreadBehavior.cxx
@@ -97,6 +97,7 @@ void qtSMTKCallObserversOnMainThreadBehavior::forceObserversToBeCalledOnMainThre
   {
     operationManager->observers().overrideWith(
       [this, operationManager](
+      smtk::common::Context ctx,
         const smtk::operation::Operation& oper,
         smtk::operation::EventType event,
         smtk::operation::Operation::Result result) -> int {
@@ -115,7 +116,7 @@ void qtSMTKCallObserversOnMainThreadBehavior::forceObserversToBeCalledOnMainThre
         else
         {
           // Directly invoke the observers.
-          operationManager->observers().callObserversDirectly(oper, event, result);
+          operationManager->observers().callObserversDirectly(ctx, oper, event, result);
         }
         return 0;
       });
@@ -138,7 +139,7 @@ void qtSMTKCallObserversOnMainThreadBehavior::forceObserversToBeCalledOnMainThre
           {
             att = operation->specification()->findAttribute(resultName.toStdString());
           }
-          operation->manager()->observers().callObserversDirectly(
+          operation->manager()->observers().callObserversDirectly(smtk::common::Context(),
             *operation, static_cast<smtk::operation::EventType>(event), att);
         }
         m_activeOperations.erase(id);
diff --git a/smtk/extension/qt/qtWorkletModel.cxx b/smtk/extension/qt/qtWorkletModel.cxx
index e89a43bf7d514cbf7635e2df39c1d559ea50ab0d..469eb69a233e756e7e208fe869d6fabc908fc986 100644
--- a/smtk/extension/qt/qtWorkletModel.cxx
+++ b/smtk/extension/qt/qtWorkletModel.cxx
@@ -12,6 +12,7 @@
 #include "smtk/io/Logger.h"
 
 #include "smtk/extension/qt/SVGIconEngine.h"
+#include "smtk/extension/qt/qtInvokeOnMainThreadBehavior.h"
 #include "smtk/extension/qt/qtOperationAction.h"
 #include "smtk/extension/qt/qtTypeDeclarations.h"
 
@@ -60,20 +61,22 @@ qtWorkletModel::qtWorkletModel(const smtk::view::Information& info, QObject* par
   // top-level tasks by default.
   m_topLevelExpression.setAllPass();
 
-  m_operationObserverKey = m_operationManager->observers().insert(
-    [this](
-      const smtk::operation::Operation& op,
-      smtk::operation::EventType event,
-      smtk::operation::Operation::Result result) {
-      if (event == smtk::operation::EventType::DID_OPERATE)
-      {
-        this->workletUpdate(op, result);
-      }
-      return 0;
-    },
-    /* priority */ 0,
-    /* initialize */ true,
-    "qtWorkletModel updater");
+  m_operationObserverKey =
+    smtk::extension::qtInvokeOnMainThreadBehavior::instance()->operationObservers().insert(
+      [this](
+      smtk::common::Context ctx,
+        const smtk::operation::Operation& op,
+        smtk::operation::EventType event,
+        smtk::operation::Operation::Result result) {
+        if (event == smtk::operation::EventType::DID_OPERATE)
+        {
+          this->workletUpdate(op, result);
+        }
+        return 0;
+      },
+      /* priority */ 0,
+      /* initialize */ true,
+      "qtWorkletModel updater");
   m_viewManager = managers->get<smtk::view::Manager::Ptr>();
 
   // Find or create an operation launcher.
diff --git a/smtk/extension/vtk/operators/DataSetInfoInspector.cxx b/smtk/extension/vtk/operators/DataSetInfoInspector.cxx
index fab7c8b887e680a68abbc60b65568712f385a28d..6a032b213b7888f7387753048d76003deee5a171 100644
--- a/smtk/extension/vtk/operators/DataSetInfoInspector.cxx
+++ b/smtk/extension/vtk/operators/DataSetInfoInspector.cxx
@@ -156,7 +156,7 @@ void prepareResult(DataSetInfoInspector::Result& result, std::set<DataSetInfo>&
   }
 }
 
-DataSetInfoInspector::Result DataSetInfoInspector::operateInternal()
+DataSetInfoInspector::Result DataSetInfoInspector::operateInternal(Context ctx)
 {
   auto result = this->createResult(smtk::operation::Operation::Outcome::FAILED);
 
diff --git a/smtk/extension/vtk/operators/DataSetInfoInspector.h b/smtk/extension/vtk/operators/DataSetInfoInspector.h
index 640c09c6769eb4d5e34e29e54d5bcbf85332e986..e0cfdadc612a0a02dd62b305ec06965376d78bf4 100644
--- a/smtk/extension/vtk/operators/DataSetInfoInspector.h
+++ b/smtk/extension/vtk/operators/DataSetInfoInspector.h
@@ -31,7 +31,7 @@ public:
   smtkSuperclassMacro(Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
   void generateSummary(Result&) override {}
 };
diff --git a/smtk/extension/vtk/operators/ExportEdgesToVTK.cxx b/smtk/extension/vtk/operators/ExportEdgesToVTK.cxx
index 7a4aa3ecc613c050da6a101c18a6b05077a49eb0..0d7b28b17ccff0651011a034af7a789886fe3634 100644
--- a/smtk/extension/vtk/operators/ExportEdgesToVTK.cxx
+++ b/smtk/extension/vtk/operators/ExportEdgesToVTK.cxx
@@ -137,7 +137,7 @@ void insertEdges(
   }
 }
 
-ExportEdgesToVTK::Result ExportEdgesToVTK::operateInternal()
+ExportEdgesToVTK::Result ExportEdgesToVTK::operateInternal(Context ctx)
 {
   smtk::attribute::FileItemPtr filenameItem = this->parameters()->findFile("filename");
 
diff --git a/smtk/extension/vtk/operators/ExportEdgesToVTK.h b/smtk/extension/vtk/operators/ExportEdgesToVTK.h
index 67ef0c2105c1e58d718e1a1c9f16af1d4d173da0..f2b189fedd2a2c32510a5a30cc0c8f5b1fbf1c5d 100644
--- a/smtk/extension/vtk/operators/ExportEdgesToVTK.h
+++ b/smtk/extension/vtk/operators/ExportEdgesToVTK.h
@@ -28,7 +28,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/extension/vtk/operators/ExportFaceset.cxx b/smtk/extension/vtk/operators/ExportFaceset.cxx
index 4697644434588949f2d3352da9d729e2651e4fb9..99fec719837ebbea3c5f6062e6efc3d904296ee6 100644
--- a/smtk/extension/vtk/operators/ExportFaceset.cxx
+++ b/smtk/extension/vtk/operators/ExportFaceset.cxx
@@ -199,7 +199,7 @@ std::list<vtkSmartPointer<vtkPolyData>> ExtractFaceset(vtkDataObject* data)
   return retValue;
 }
 
-ExportFaceset::Result ExportFaceset::operateInternal()
+ExportFaceset::Result ExportFaceset::operateInternal(Context ctx)
 {
   smtk::attribute::FileItemPtr filenameItem = this->parameters()->findFile("filename");
   const std::string filename = filenameItem->value();
diff --git a/smtk/extension/vtk/operators/ExportFaceset.h b/smtk/extension/vtk/operators/ExportFaceset.h
index 6589f8ddcb976598bdfb92c24417ca0cb0dceb43..386872c851929c1533419e623a895f2df8c48fe5 100644
--- a/smtk/extension/vtk/operators/ExportFaceset.h
+++ b/smtk/extension/vtk/operators/ExportFaceset.h
@@ -33,7 +33,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/extension/vtk/operators/ImageInspector.cxx b/smtk/extension/vtk/operators/ImageInspector.cxx
index 1682510963f214966dd7affff9081853d3e65e1e..d04304169e6b6274d512e581b9227a171aedd70a 100644
--- a/smtk/extension/vtk/operators/ImageInspector.cxx
+++ b/smtk/extension/vtk/operators/ImageInspector.cxx
@@ -37,7 +37,7 @@ namespace smtk
 namespace geometry
 {
 
-ImageInspector::Result ImageInspector::operateInternal()
+ImageInspector::Result ImageInspector::operateInternal(Context ctx)
 {
   auto result = this->createResult(smtk::operation::Operation::Outcome::FAILED);
 
diff --git a/smtk/extension/vtk/operators/ImageInspector.h b/smtk/extension/vtk/operators/ImageInspector.h
index 96a6459913e0cb86bbcdd57e0151a4f04d60248c..27ce447929f373f7c2bf21d67706c7435bdcf32a 100644
--- a/smtk/extension/vtk/operators/ImageInspector.h
+++ b/smtk/extension/vtk/operators/ImageInspector.h
@@ -33,7 +33,7 @@ public:
   smtkSuperclassMacro(Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
   void generateSummary(Result&) override {}
 };
diff --git a/smtk/extension/vtk/operators/MeshInspector.cxx b/smtk/extension/vtk/operators/MeshInspector.cxx
index 35feaec4fdf28fd5eaf69c5c3bc92c7412f24c2e..91b48018f5c296a55830bc98749751d4ce8dc020 100644
--- a/smtk/extension/vtk/operators/MeshInspector.cxx
+++ b/smtk/extension/vtk/operators/MeshInspector.cxx
@@ -37,7 +37,7 @@ namespace smtk
 namespace geometry
 {
 
-MeshInspector::Result MeshInspector::operateInternal()
+MeshInspector::Result MeshInspector::operateInternal(Context ctx)
 {
   auto result = this->createResult(smtk::operation::Operation::Outcome::FAILED);
 
diff --git a/smtk/extension/vtk/operators/MeshInspector.h b/smtk/extension/vtk/operators/MeshInspector.h
index 821876ee7432d8f0de1fdc832af47dcd99701558..7fe77f0e163f63027f00eea958f0c7a9cce67dcc 100644
--- a/smtk/extension/vtk/operators/MeshInspector.h
+++ b/smtk/extension/vtk/operators/MeshInspector.h
@@ -33,7 +33,7 @@ public:
   smtkSuperclassMacro(Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
   void generateSummary(Result&) override {}
 };
diff --git a/smtk/graph/operators/CreateArc.cxx b/smtk/graph/operators/CreateArc.cxx
index c34ac98176bd820286cb9748cd324beac426990e..394f102e03f74c3f7016293bf756bcb83796aa7d 100644
--- a/smtk/graph/operators/CreateArc.cxx
+++ b/smtk/graph/operators/CreateArc.cxx
@@ -59,7 +59,7 @@ bool CreateArc::ableToOperate()
   return ok;
 }
 
-CreateArc::Result CreateArc::operateInternal()
+CreateArc::Result CreateArc::operateInternal(Context ctx)
 {
   smtk::string::Token arcTypeName;
   smtk::graph::Component::Ptr fromNode;
diff --git a/smtk/graph/operators/CreateArc.h b/smtk/graph/operators/CreateArc.h
index 650d76a02703a37f845703faaebb8d2adcf2e5c3..c5f7aa7660e4bf285a2cdc7943cd2db02625f4dd 100644
--- a/smtk/graph/operators/CreateArc.h
+++ b/smtk/graph/operators/CreateArc.h
@@ -43,7 +43,7 @@ public:
 
 protected:
   CreateArc();
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
 
   /// Used inside ableToOperate and operateInternal to decide on success or failure.
   bool fetchNodesAndCheckArcType(
diff --git a/smtk/graph/operators/CreateArcType.cxx b/smtk/graph/operators/CreateArcType.cxx
index 5e8a2a0cd08ca05fb4bc8b79a5c577f259deb158..c99b07ce32f9e6fd0d613f6985acf44fc9ba2134 100644
--- a/smtk/graph/operators/CreateArcType.cxx
+++ b/smtk/graph/operators/CreateArcType.cxx
@@ -64,7 +64,7 @@ void appendArcTypes(
 
 CreateArcType::CreateArcType() = default;
 
-CreateArcType::Result CreateArcType::operateInternal()
+CreateArcType::Result CreateArcType::operateInternal(Context ctx)
 {
   auto resource = this->parameters()->associations()->valueAs<smtk::graph::ResourceBase>();
   smtk::string::Token arcTypeName = this->parameters()->findString("type name")->value();
diff --git a/smtk/graph/operators/CreateArcType.h b/smtk/graph/operators/CreateArcType.h
index 1a40e0df388b7dadd3fead652b35e2ed9e228d13..83655571848cdd1c13b4f54f331fa385dc1dab0f 100644
--- a/smtk/graph/operators/CreateArcType.h
+++ b/smtk/graph/operators/CreateArcType.h
@@ -63,7 +63,7 @@ public:
 
 protected:
   CreateArcType();
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/graph/operators/DeleteArc.cxx b/smtk/graph/operators/DeleteArc.cxx
index 46c0d5dbfd2224e492fcca9d759f7924e9130925..f41b489ff9d347408e8d031e5cb1542de47967a2 100644
--- a/smtk/graph/operators/DeleteArc.cxx
+++ b/smtk/graph/operators/DeleteArc.cxx
@@ -231,7 +231,7 @@ bool DeleteArc::fetchArcTypeAndEndpointsItem(
   return ok;
 }
 
-DeleteArc::Result DeleteArc::operateInternal()
+DeleteArc::Result DeleteArc::operateInternal(Context ctx)
 {
   smtk::string::Token arcTypeName;
   smtk::attribute::GroupItem::Ptr endpoints;
diff --git a/smtk/graph/operators/DeleteArc.h b/smtk/graph/operators/DeleteArc.h
index adc47fc2737088368b6626514c1db767732914a6..1f1e8d6c1640aad5ba8d19feda2aab368dc040a9 100644
--- a/smtk/graph/operators/DeleteArc.h
+++ b/smtk/graph/operators/DeleteArc.h
@@ -83,7 +83,7 @@ public:
 
 protected:
   DeleteArc();
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
 
   Specification createSpecification() override;
   const char* xmlDescription() const override;
diff --git a/smtk/markup/operators/Create.cxx b/smtk/markup/operators/Create.cxx
index 526c2638a19a5f03b7449c10d81edcd96f7cfaa9..90d43dfdcdac389d838695a3e85622524ef82d5d 100644
--- a/smtk/markup/operators/Create.cxx
+++ b/smtk/markup/operators/Create.cxx
@@ -31,7 +31,7 @@ namespace smtk
 namespace markup
 {
 
-Create::Result Create::operateInternal()
+Create::Result Create::operateInternal(Context ctx)
 {
   // We may be given an optional location:
   auto resource = smtk::markup::Resource::create();
diff --git a/smtk/markup/operators/Create.h b/smtk/markup/operators/Create.h
index 3119d16b74ec7b524ae3e8aafa95a0d3b60b4c95..c76bfd72ec8f4f30f24b30900a160d25c31f6642 100644
--- a/smtk/markup/operators/Create.h
+++ b/smtk/markup/operators/Create.h
@@ -30,7 +30,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
   void markModifiedResources(Result&) override;
 };
diff --git a/smtk/markup/operators/CreateAnalyticShape.cxx b/smtk/markup/operators/CreateAnalyticShape.cxx
index 2e4df5a85b360d265bc693c20706fad32ca0c548..828ff5d6ebc6bc06f79850f272081ffbb3b73168 100644
--- a/smtk/markup/operators/CreateAnalyticShape.cxx
+++ b/smtk/markup/operators/CreateAnalyticShape.cxx
@@ -31,7 +31,7 @@ namespace smtk
 namespace markup
 {
 
-CreateAnalyticShape::Result CreateAnalyticShape::operateInternal()
+CreateAnalyticShape::Result CreateAnalyticShape::operateInternal(Context ctx)
 {
   auto params = this->parameters();
   auto resource = params->associations()->valueAs<smtk::markup::Resource>();
diff --git a/smtk/markup/operators/CreateAnalyticShape.h b/smtk/markup/operators/CreateAnalyticShape.h
index 36fe829e7c9cdf93cd57a5c61964768e2529ff0a..e8bdeb3f85f8795bff4839fa87df2cea24f760b5 100644
--- a/smtk/markup/operators/CreateAnalyticShape.h
+++ b/smtk/markup/operators/CreateAnalyticShape.h
@@ -30,7 +30,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/markup/operators/CreateGroup.cxx b/smtk/markup/operators/CreateGroup.cxx
index bc74ac971a7976e41c4dfaa5699bc5cbe24440e7..fc036b2025a7f67c9a954fa38504d25e83dcaef1 100644
--- a/smtk/markup/operators/CreateGroup.cxx
+++ b/smtk/markup/operators/CreateGroup.cxx
@@ -31,7 +31,7 @@ namespace smtk
 namespace markup
 {
 
-CreateGroup::Result CreateGroup::operateInternal()
+CreateGroup::Result CreateGroup::operateInternal(Context ctx)
 {
   auto params = this->parameters();
   auto assoc = params->associations();
diff --git a/smtk/markup/operators/CreateGroup.h b/smtk/markup/operators/CreateGroup.h
index bda1f5689d27607062799aa2d60484df560cb246..6e09e054256761765b8f34db7e636f3366a71dec 100644
--- a/smtk/markup/operators/CreateGroup.h
+++ b/smtk/markup/operators/CreateGroup.h
@@ -30,7 +30,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/markup/operators/Delete.cxx b/smtk/markup/operators/Delete.cxx
index d535f29e592b473cbd301801d2df84fee118c160..c1e138fde079098442e0d4c629070d6c5630c2d8 100644
--- a/smtk/markup/operators/Delete.cxx
+++ b/smtk/markup/operators/Delete.cxx
@@ -59,7 +59,7 @@ bool Delete::ableToOperate()
   return !haveExternalDeps;
 }
 
-Delete::Result Delete::operateInternal()
+Delete::Result Delete::operateInternal(Context ctx)
 {
   m_result = this->createResult(Delete::Outcome::FAILED);
 
diff --git a/smtk/markup/operators/Delete.h b/smtk/markup/operators/Delete.h
index a350e598dfb4bd03e265c9474ab3500711f1fc83..78ab0ebcc46d0fc515dccd5d177804a5a0bd4311 100644
--- a/smtk/markup/operators/Delete.h
+++ b/smtk/markup/operators/Delete.h
@@ -71,7 +71,7 @@ public:
 
 protected:
   Delete();
-  Delete::Result operateInternal() override;
+  Delete::Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 
   Result m_result; // TODO: Let subclass define?
diff --git a/smtk/markup/operators/DumpGraph.cxx b/smtk/markup/operators/DumpGraph.cxx
index 679eb5919aed7fd7f5a2598ae20ce9adefa0c506..9133111e203e5ab076fb4ca3de1f7bedca7fa183 100644
--- a/smtk/markup/operators/DumpGraph.cxx
+++ b/smtk/markup/operators/DumpGraph.cxx
@@ -37,7 +37,7 @@ namespace smtk
 namespace markup
 {
 
-DumpGraph::Result DumpGraph::operateInternal()
+DumpGraph::Result DumpGraph::operateInternal(Context ctx)
 {
   auto result = this->createResult(smtk::operation::Operation::Outcome::FAILED);
   auto created = result->findComponent("created");
diff --git a/smtk/markup/operators/DumpGraph.h b/smtk/markup/operators/DumpGraph.h
index 2e22894d250e6463bded5feb9859e111a91bfb6d..f5dbcc360a118d67b47975fc4e19048300018bbe 100644
--- a/smtk/markup/operators/DumpGraph.h
+++ b/smtk/markup/operators/DumpGraph.h
@@ -29,7 +29,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/markup/operators/EditComment.cxx b/smtk/markup/operators/EditComment.cxx
index afc69579308b3d85bc27e670f0a82a0c8e45b84e..6c12ce0124b79fbf7c9233863ef8675d62a37c25 100644
--- a/smtk/markup/operators/EditComment.cxx
+++ b/smtk/markup/operators/EditComment.cxx
@@ -38,7 +38,7 @@ namespace markup
 
 using namespace smtk::string::literals;
 
-EditComment::Result EditComment::operateInternal()
+EditComment::Result EditComment::operateInternal(Context ctx)
 {
   auto objects = this->parameters()->associations();
   smtk::string::Token mimetype = this->parameters()->findString("mime-type")->value();
diff --git a/smtk/markup/operators/EditComment.h b/smtk/markup/operators/EditComment.h
index 5c74fc0c71de2913ee744569276394c5d3b97ab1..bda71401499248adc11a7ee9250099ff5345fd5f 100644
--- a/smtk/markup/operators/EditComment.h
+++ b/smtk/markup/operators/EditComment.h
@@ -43,7 +43,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/markup/operators/Import.cxx b/smtk/markup/operators/Import.cxx
index 5770b9cbe4711c93e082860f584a99cec4330bb2..32055b2a48764320cb54ed20a9e7625a86f5e1ee 100644
--- a/smtk/markup/operators/Import.cxx
+++ b/smtk/markup/operators/Import.cxx
@@ -350,7 +350,7 @@ public:
 
 } // anonymous namespace
 
-Import::Result Import::operateInternal()
+Import::Result Import::operateInternal(Context ctx)
 {
   using namespace smtk::string::literals;
 
diff --git a/smtk/markup/operators/Import.h b/smtk/markup/operators/Import.h
index a30152b78a3816f5fb55b6dd05b4ad82a4542a41..9602d4e08cb685def817094666da3eab9ceddd51 100644
--- a/smtk/markup/operators/Import.h
+++ b/smtk/markup/operators/Import.h
@@ -50,7 +50,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   Specification createSpecification() override;
   const char* xmlDescription() const override;
 
diff --git a/smtk/markup/operators/Read.cxx b/smtk/markup/operators/Read.cxx
index 0f01859fb11bba558781ac090d5e95a49f8fc40e..da3bcd52ea9eae697a4a3141451d96bcb05108f2 100644
--- a/smtk/markup/operators/Read.cxx
+++ b/smtk/markup/operators/Read.cxx
@@ -49,7 +49,7 @@ bool Read::ableToOperate()
   return file.good();
 }
 
-Read::Result Read::operateInternal()
+Read::Result Read::operateInternal(Context ctx)
 {
   auto filename = this->parameters()->findFile("filename")->value();
   std::ifstream file(filename);
diff --git a/smtk/markup/operators/Read.h b/smtk/markup/operators/Read.h
index 59452ab0c94166d7ea536ff7af40e81d50d03d5c..a5e85dc55048ebc734107e39f4680e4afbded6ab 100644
--- a/smtk/markup/operators/Read.h
+++ b/smtk/markup/operators/Read.h
@@ -32,7 +32,7 @@ public:
   bool ableToOperate() override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
   void markModifiedResources(Result&) override;
 };
diff --git a/smtk/markup/operators/SetName.cxx b/smtk/markup/operators/SetName.cxx
index 9533bf596cf335f63fb31a64a5a1e57949dc71f6..6a2711dd589d20a314b52f88b660781caaf0a1a5 100644
--- a/smtk/markup/operators/SetName.cxx
+++ b/smtk/markup/operators/SetName.cxx
@@ -31,7 +31,7 @@ namespace smtk
 namespace markup
 {
 
-SetName::Result SetName::operateInternal()
+SetName::Result SetName::operateInternal(Context ctx)
 {
   auto object = this->parameters()->associations()->value();
   auto name = this->parameters()->findString("name")->value();
diff --git a/smtk/markup/operators/SetName.h b/smtk/markup/operators/SetName.h
index 7944e7fc3b5f0461cf449788538c3df5e367444b..587976022007a8b690701a1c9e78f93040b471c8 100644
--- a/smtk/markup/operators/SetName.h
+++ b/smtk/markup/operators/SetName.h
@@ -30,7 +30,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/markup/operators/TagIndividual.cxx b/smtk/markup/operators/TagIndividual.cxx
index 6308d2944e7b5ec6c7839efd6dfb632c99e35bd7..0b7ff57c211fdfec5269952ddda61fb57ff82dfd 100644
--- a/smtk/markup/operators/TagIndividual.cxx
+++ b/smtk/markup/operators/TagIndividual.cxx
@@ -38,7 +38,7 @@ namespace smtk
 namespace markup
 {
 
-TagIndividual::Result TagIndividual::operateInternal()
+TagIndividual::Result TagIndividual::operateInternal(Context ctx)
 {
   auto result = this->createResult(smtk::operation::Operation::Outcome::FAILED);
   auto created = result->findComponent("created");
diff --git a/smtk/markup/operators/TagIndividual.h b/smtk/markup/operators/TagIndividual.h
index 3d779904ffa8548f8d7d75a7b3032412140c164a..31d2ab4b71235ed4e34096fb32cafbfab4537cc6 100644
--- a/smtk/markup/operators/TagIndividual.h
+++ b/smtk/markup/operators/TagIndividual.h
@@ -33,7 +33,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
 
   /// Find or create an OntologyIdentifier with the given \a nodeName,
   /// \a ontologyName, and \a nodeURL.
diff --git a/smtk/markup/operators/Ungroup.cxx b/smtk/markup/operators/Ungroup.cxx
index f0c80ece1ca4ac386513e9f36e95a375104adb0d..2cee39266e0902c2ba103edba2c1b29f76af248b 100644
--- a/smtk/markup/operators/Ungroup.cxx
+++ b/smtk/markup/operators/Ungroup.cxx
@@ -29,7 +29,7 @@ namespace smtk
 namespace markup
 {
 
-Ungroup::Result Ungroup::operateInternal()
+Ungroup::Result Ungroup::operateInternal(Context ctx)
 {
   Ungroup::Result result;
   auto params = this->parameters();
diff --git a/smtk/markup/operators/Ungroup.h b/smtk/markup/operators/Ungroup.h
index 77692a6869f3e255783efc07361f618e69892813..73542f4ca726535a5db10c0caccedb40f509486a 100644
--- a/smtk/markup/operators/Ungroup.h
+++ b/smtk/markup/operators/Ungroup.h
@@ -30,7 +30,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/markup/operators/Write.cxx b/smtk/markup/operators/Write.cxx
index 2921f59e243f2e353a4723462afeb98a2871dbad..7c59ccf1a1a6687a9d9fc248af2f1af7b579eb4d 100644
--- a/smtk/markup/operators/Write.cxx
+++ b/smtk/markup/operators/Write.cxx
@@ -67,7 +67,7 @@ bool Write::ableToOperate()
   return true;
 }
 
-Write::Result Write::operateInternal()
+Write::Result Write::operateInternal(Context ctx)
 {
   auto resourceItem = this->parameters()->associations();
 
diff --git a/smtk/markup/operators/Write.h b/smtk/markup/operators/Write.h
index 0f8dd40cf1e183216cfa3994072ac85a460837f6..5df83961c5c83b908455097e3b537add4461d867 100644
--- a/smtk/markup/operators/Write.h
+++ b/smtk/markup/operators/Write.h
@@ -35,7 +35,7 @@ public:
   bool ableToOperate() override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
   void markModifiedResources(Result&) override;
 
diff --git a/smtk/mesh/operators/DeleteMesh.cxx b/smtk/mesh/operators/DeleteMesh.cxx
index 7a6f98adee984a8e8aa2f2d28e01fdb02d248c2c..dc0d68963407d9b26354d6f6f6d286cba64b31a9 100644
--- a/smtk/mesh/operators/DeleteMesh.cxx
+++ b/smtk/mesh/operators/DeleteMesh.cxx
@@ -30,7 +30,7 @@ namespace mesh
 
 DeleteMesh::DeleteMesh() = default;
 
-smtk::mesh::DeleteMesh::Result DeleteMesh::operateInternal()
+smtk::mesh::DeleteMesh::Result DeleteMesh::operateInternal(Context ctx)
 {
   Result result = this->createResult(smtk::operation::Operation::Outcome::SUCCEEDED);
 
diff --git a/smtk/mesh/operators/DeleteMesh.h b/smtk/mesh/operators/DeleteMesh.h
index a8fcd8055ecbc53ddb5f784aac15463bf9a4edff..cf8e2217cd51118b6a810e825557e671bd605f1d 100644
--- a/smtk/mesh/operators/DeleteMesh.h
+++ b/smtk/mesh/operators/DeleteMesh.h
@@ -31,7 +31,7 @@ public:
 
 protected:
   DeleteMesh();
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 
   void generateSummary(smtk::operation::Operation::Result&) override;
diff --git a/smtk/mesh/operators/ElevateMesh.cxx b/smtk/mesh/operators/ElevateMesh.cxx
index 7c34ccdb3a5de978313b48fc910f743b29742ee0..616b0ce2f8541e155a70c6ccbe89a4a5d1e99379 100644
--- a/smtk/mesh/operators/ElevateMesh.cxx
+++ b/smtk/mesh/operators/ElevateMesh.cxx
@@ -128,7 +128,7 @@ bool ElevateMesh::ableToOperate()
   return this->Superclass::ableToOperate();
 }
 
-ElevateMesh::Result ElevateMesh::operateInternal()
+ElevateMesh::Result ElevateMesh::operateInternal(Context ctx)
 {
   // Access the string describing the input data type
   smtk::attribute::StringItem::Ptr inputDataItem = this->parameters()->findString("input data");
diff --git a/smtk/mesh/operators/ElevateMesh.h b/smtk/mesh/operators/ElevateMesh.h
index 5c080c97c5fea5cf63298f6a4d99e98112e189d6..1464d86c5b1387469ec9d20fd776fa414b294388 100644
--- a/smtk/mesh/operators/ElevateMesh.h
+++ b/smtk/mesh/operators/ElevateMesh.h
@@ -37,7 +37,7 @@ public:
   bool ableToOperate() override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 } // namespace mesh
diff --git a/smtk/mesh/operators/Export.cxx b/smtk/mesh/operators/Export.cxx
index d00146280e250abf10a96732dc69fac92b7ef020..67feed7be1b8f8f006b1c1a227e8f336ff12653d 100644
--- a/smtk/mesh/operators/Export.cxx
+++ b/smtk/mesh/operators/Export.cxx
@@ -62,7 +62,7 @@ bool Export::ableToOperate()
   return this->Superclass::ableToOperate();
 }
 
-Export::Result Export::operateInternal()
+Export::Result Export::operateInternal(Context ctx)
 {
   std::string outputfile = this->parameters()->findFile("filename")->value();
 
diff --git a/smtk/mesh/operators/Export.h b/smtk/mesh/operators/Export.h
index ef8b51d2e2304b552385a8cbead9f50b1e69688d..534b59be3c6c01eb17947d6db6e85d3617b7eba6 100644
--- a/smtk/mesh/operators/Export.h
+++ b/smtk/mesh/operators/Export.h
@@ -30,7 +30,7 @@ public:
   bool ableToOperate() override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   Specification createSpecification() override;
   const char* xmlDescription() const override;
 };
diff --git a/smtk/mesh/operators/ExtractAdjacency.cxx b/smtk/mesh/operators/ExtractAdjacency.cxx
index 2e23db7833de3ca6533115da74ea65876338bdff..4946b440a1e0132fde4149383ce9d86fa42693e6 100644
--- a/smtk/mesh/operators/ExtractAdjacency.cxx
+++ b/smtk/mesh/operators/ExtractAdjacency.cxx
@@ -29,7 +29,7 @@ namespace smtk
 namespace mesh
 {
 
-smtk::mesh::ExtractAdjacency::Result ExtractAdjacency::operateInternal()
+smtk::mesh::ExtractAdjacency::Result ExtractAdjacency::operateInternal(Context ctx)
 {
   // Access the meshset
   smtk::attribute::ReferenceItem::Ptr meshItem = this->parameters()->associations();
diff --git a/smtk/mesh/operators/ExtractAdjacency.h b/smtk/mesh/operators/ExtractAdjacency.h
index 8c236beed0aea6abb42bc06d068408c93ed34bb4..4e9ad1652ab7ebb31e386c069a91d6dc0cb78ee5 100644
--- a/smtk/mesh/operators/ExtractAdjacency.h
+++ b/smtk/mesh/operators/ExtractAdjacency.h
@@ -30,7 +30,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 } // namespace mesh
diff --git a/smtk/mesh/operators/ExtractByDihedralAngle.cxx b/smtk/mesh/operators/ExtractByDihedralAngle.cxx
index 3087f5a7b5677811c1669045a5862e932bea3675..fec00cb24fe13a130d3282a0c03fe5cc5735493d 100644
--- a/smtk/mesh/operators/ExtractByDihedralAngle.cxx
+++ b/smtk/mesh/operators/ExtractByDihedralAngle.cxx
@@ -147,7 +147,7 @@ bool ExtractByDihedralAngle::ableToOperate()
   return meshset.types().cellTypes() == triangles;
 }
 
-smtk::mesh::ExtractByDihedralAngle::Result ExtractByDihedralAngle::operateInternal()
+smtk::mesh::ExtractByDihedralAngle::Result ExtractByDihedralAngle::operateInternal(Context ctx)
 {
   smtk::attribute::ReferenceItem::Ptr meshItem = this->parameters()->associations();
   smtk::mesh::Component::Ptr meshComponent = meshItem->valueAs<smtk::mesh::Component>();
diff --git a/smtk/mesh/operators/ExtractByDihedralAngle.h b/smtk/mesh/operators/ExtractByDihedralAngle.h
index b18369b68ab46c512fc8598163f42c1c1fe4cf33..be77d4fe592caf19b685081c35bf59da8a417af9 100644
--- a/smtk/mesh/operators/ExtractByDihedralAngle.h
+++ b/smtk/mesh/operators/ExtractByDihedralAngle.h
@@ -31,7 +31,7 @@ public:
   bool ableToOperate() override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/mesh/operators/ExtractSkin.cxx b/smtk/mesh/operators/ExtractSkin.cxx
index 5a82c46801cb5e42c5baf3f1845cb952a4fbd5ae..d38cb06b1198eaeae7e28fef582ca559f62400de 100644
--- a/smtk/mesh/operators/ExtractSkin.cxx
+++ b/smtk/mesh/operators/ExtractSkin.cxx
@@ -29,7 +29,7 @@ namespace smtk
 namespace mesh
 {
 
-smtk::mesh::ExtractSkin::Result ExtractSkin::operateInternal()
+smtk::mesh::ExtractSkin::Result ExtractSkin::operateInternal(Context ctx)
 {
   // Access the meshset
   smtk::attribute::ReferenceItem::Ptr meshItem = this->parameters()->associations();
diff --git a/smtk/mesh/operators/ExtractSkin.h b/smtk/mesh/operators/ExtractSkin.h
index 5b701251c7dbb872972f315fe8662d85e8975e8b..b61ed83639d461065a5add2a3da79cec8faecaa2 100644
--- a/smtk/mesh/operators/ExtractSkin.h
+++ b/smtk/mesh/operators/ExtractSkin.h
@@ -28,7 +28,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 } // namespace mesh
diff --git a/smtk/mesh/operators/GenerateHotStartData.cxx b/smtk/mesh/operators/GenerateHotStartData.cxx
index 1a922fad36cfb4a6c6dc86717a9a8537a0846e46..b098da8d9699c6e73b24028f07d5ae82bbfbd133 100644
--- a/smtk/mesh/operators/GenerateHotStartData.cxx
+++ b/smtk/mesh/operators/GenerateHotStartData.cxx
@@ -178,7 +178,7 @@ bool GenerateHotStartData::ableToOperate()
   return this->Superclass::ableToOperate();
 }
 
-GenerateHotStartData::Result GenerateHotStartData::operateInternal()
+GenerateHotStartData::Result GenerateHotStartData::operateInternal(Context ctx)
 {
   // Access the mesh to elevate
   smtk::attribute::ReferenceItem::Ptr meshItem = this->parameters()->associations();
diff --git a/smtk/mesh/operators/GenerateHotStartData.h b/smtk/mesh/operators/GenerateHotStartData.h
index 600f5af806f939bda68cc7c5881e83f70648bb3f..a39e347206ff58c8cc9712655c610d4952348587 100644
--- a/smtk/mesh/operators/GenerateHotStartData.h
+++ b/smtk/mesh/operators/GenerateHotStartData.h
@@ -38,7 +38,7 @@ public:
   bool ableToOperate() override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 } // namespace mesh
diff --git a/smtk/mesh/operators/Import.cxx b/smtk/mesh/operators/Import.cxx
index c70371e7e0791b7faa253a95d906edac47d1fb9a..939b3cdb746a3355538ac218afbe64d5681cf0d0 100644
--- a/smtk/mesh/operators/Import.cxx
+++ b/smtk/mesh/operators/Import.cxx
@@ -53,7 +53,7 @@ namespace smtk
 namespace mesh
 {
 
-Import::Result Import::operateInternal()
+Import::Result Import::operateInternal(Context ctx)
 {
   // Get the import file name
   smtk::attribute::FileItem::Ptr filePathItem = this->parameters()->findFile("filename");
diff --git a/smtk/mesh/operators/Import.h b/smtk/mesh/operators/Import.h
index ddd00f1f170ae19b18ed521e875c8f0e60575470..9d2c207d0d32d60d7a0f19c37c9e97ea96648ca8 100644
--- a/smtk/mesh/operators/Import.h
+++ b/smtk/mesh/operators/Import.h
@@ -32,7 +32,7 @@ public:
   smtkSharedFromThisMacro(smtk::operation::Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   Specification createSpecification() override;
   const char* xmlDescription() const override;
 };
diff --git a/smtk/mesh/operators/InterpolateOntoMesh.cxx b/smtk/mesh/operators/InterpolateOntoMesh.cxx
index 7c48c88a3b9ce919598ab09b3ce930a6736860f1..f95b1babb108938048a3e83910828e2ee540a9e0 100644
--- a/smtk/mesh/operators/InterpolateOntoMesh.cxx
+++ b/smtk/mesh/operators/InterpolateOntoMesh.cxx
@@ -134,7 +134,7 @@ bool InterpolateOntoMesh::ableToOperate()
   return this->Superclass::ableToOperate();
 }
 
-InterpolateOntoMesh::Result InterpolateOntoMesh::operateInternal()
+InterpolateOntoMesh::Result InterpolateOntoMesh::operateInternal(Context ctx)
 {
   // Access the string describing the input data type
   smtk::attribute::StringItem::Ptr inputDataItem = this->parameters()->findString("input data");
diff --git a/smtk/mesh/operators/InterpolateOntoMesh.h b/smtk/mesh/operators/InterpolateOntoMesh.h
index 9c9424c41c6499a28b01c12a0f0ea74027cf83e7..4ba0a16d7cf032c7e5b9d1023d28f8c919194be5 100644
--- a/smtk/mesh/operators/InterpolateOntoMesh.h
+++ b/smtk/mesh/operators/InterpolateOntoMesh.h
@@ -30,7 +30,7 @@ public:
   bool ableToOperate() override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 } // namespace mesh
diff --git a/smtk/mesh/operators/MergeCoincidentPoints.cxx b/smtk/mesh/operators/MergeCoincidentPoints.cxx
index edcc8d97bd6caeec2589ec88efa3dd5579096aa8..d6d40afb65e36076b9a165f8ad10dae01e8a0f88 100644
--- a/smtk/mesh/operators/MergeCoincidentPoints.cxx
+++ b/smtk/mesh/operators/MergeCoincidentPoints.cxx
@@ -26,7 +26,7 @@ namespace smtk
 namespace mesh
 {
 
-smtk::mesh::MergeCoincidentPoints::Result MergeCoincidentPoints::operateInternal()
+smtk::mesh::MergeCoincidentPoints::Result MergeCoincidentPoints::operateInternal(Context ctx)
 {
   // Access the tolerance.
   double tolerance = this->parameters()->findDouble("tolerance")->value();
diff --git a/smtk/mesh/operators/MergeCoincidentPoints.h b/smtk/mesh/operators/MergeCoincidentPoints.h
index 8187ac4e4b662c61b50899efb497fc543fcf05ac..f3f8e2e6374c173ec7befef4b90fa045fcba1f2f 100644
--- a/smtk/mesh/operators/MergeCoincidentPoints.h
+++ b/smtk/mesh/operators/MergeCoincidentPoints.h
@@ -28,7 +28,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/mesh/operators/PrintMeshInformation.cxx b/smtk/mesh/operators/PrintMeshInformation.cxx
index 466918b983a92d49963ca7c0fa2adff59fe30837..097a52abe5a8350f83df1a4f8a262b897fe1185a 100644
--- a/smtk/mesh/operators/PrintMeshInformation.cxx
+++ b/smtk/mesh/operators/PrintMeshInformation.cxx
@@ -26,7 +26,7 @@ namespace smtk
 namespace mesh
 {
 
-smtk::mesh::PrintMeshInformation::Result PrintMeshInformation::operateInternal()
+smtk::mesh::PrintMeshInformation::Result PrintMeshInformation::operateInternal(Context ctx)
 {
   smtk::attribute::ReferenceItem::Ptr meshItem = this->parameters()->associations();
 
diff --git a/smtk/mesh/operators/PrintMeshInformation.h b/smtk/mesh/operators/PrintMeshInformation.h
index 92dd50905227427da453c8fdbb8f694955568e50..46d03cfac21556f89247f6e1a73ccd8bc46a739a 100644
--- a/smtk/mesh/operators/PrintMeshInformation.h
+++ b/smtk/mesh/operators/PrintMeshInformation.h
@@ -28,7 +28,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/mesh/operators/Read.cxx b/smtk/mesh/operators/Read.cxx
index 4f5a27965b1b3dbd2de762a14f8d2d9a06a0be21..64dcb846729c6c871fc7e40c8caeeb69d8543d75 100644
--- a/smtk/mesh/operators/Read.cxx
+++ b/smtk/mesh/operators/Read.cxx
@@ -63,7 +63,7 @@ namespace smtk
 namespace mesh
 {
 
-Read::Result Read::operateInternal()
+Read::Result Read::operateInternal(Context ctx)
 {
   // Get the read file name
   smtk::attribute::FileItem::Ptr filePathItem = this->parameters()->findFile("filename");
diff --git a/smtk/mesh/operators/Read.h b/smtk/mesh/operators/Read.h
index 3bb09a1197f4b6ae54395bba220a818ef4ecedef..76f3d7db741e4ddb639a1accdfffa0588246d5d4 100644
--- a/smtk/mesh/operators/Read.h
+++ b/smtk/mesh/operators/Read.h
@@ -32,7 +32,7 @@ public:
   smtkSharedFromThisMacro(smtk::operation::Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   Specification createSpecification() override;
   const char* xmlDescription() const override;
   void markModifiedResources(Result&) override;
diff --git a/smtk/mesh/operators/ReadResource.cxx b/smtk/mesh/operators/ReadResource.cxx
index 412499ce88105f93c24aad895a4208ffb46d97d9..00a1fbb7de20e89ba652cda60cf99d40e517e136 100644
--- a/smtk/mesh/operators/ReadResource.cxx
+++ b/smtk/mesh/operators/ReadResource.cxx
@@ -42,7 +42,7 @@ namespace smtk
 namespace mesh
 {
 
-ReadResource::Result ReadResource::operateInternal()
+ReadResource::Result ReadResource::operateInternal(Context ctx)
 {
   std::string filename = this->parameters()->findFile("filename")->value();
 
diff --git a/smtk/mesh/operators/ReadResource.h b/smtk/mesh/operators/ReadResource.h
index df6dce0ec1b9cdbd6ff1dd428023d49a82614e71..cb68c80aeb9bcbf70e827573b7d20be533778fd3 100644
--- a/smtk/mesh/operators/ReadResource.h
+++ b/smtk/mesh/operators/ReadResource.h
@@ -28,7 +28,7 @@ public:
   smtkSharedFromThisMacro(smtk::operation::Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
   void markModifiedResources(Result&) override;
 };
diff --git a/smtk/mesh/operators/SelectCells.cxx b/smtk/mesh/operators/SelectCells.cxx
index c95816250699085037a042cfc6534943fd7bc8a6..256a5f5704f41663295c016827e5fd6b4547d174 100644
--- a/smtk/mesh/operators/SelectCells.cxx
+++ b/smtk/mesh/operators/SelectCells.cxx
@@ -33,7 +33,7 @@ namespace smtk
 namespace mesh
 {
 
-SelectCells::Result SelectCells::operateInternal()
+SelectCells::Result SelectCells::operateInternal(Context ctx)
 {
   // Access the mesh resource.
   smtk::attribute::ReferenceItem::Ptr resourceItem = this->parameters()->associations();
diff --git a/smtk/mesh/operators/SelectCells.h b/smtk/mesh/operators/SelectCells.h
index 92f44a41424b403d36fc6b523de1fa11275adf1e..7463a98f38d604ccb1627da5ed33b76b72781432 100644
--- a/smtk/mesh/operators/SelectCells.h
+++ b/smtk/mesh/operators/SelectCells.h
@@ -30,7 +30,7 @@ public:
   void generateSummary(Result&) override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 } // namespace mesh
diff --git a/smtk/mesh/operators/SetMeshName.cxx b/smtk/mesh/operators/SetMeshName.cxx
index deeb1a0e2117932f93b525dda4fb4af3e3241826..3979fbfe654bb89c5496542054f7221a64381c4d 100644
--- a/smtk/mesh/operators/SetMeshName.cxx
+++ b/smtk/mesh/operators/SetMeshName.cxx
@@ -25,7 +25,7 @@ namespace smtk
 namespace mesh
 {
 
-smtk::mesh::SetMeshName::Result SetMeshName::operateInternal()
+smtk::mesh::SetMeshName::Result SetMeshName::operateInternal(Context ctx)
 {
   // Access the name to use when renaming the meshset
   smtk::attribute::StringItem::Ptr nameItem = this->parameters()->findString("name");
diff --git a/smtk/mesh/operators/SetMeshName.h b/smtk/mesh/operators/SetMeshName.h
index e0d7b5469b7efe7cd3aeb2e6c66f05d3e9b9c4f5..60d5fd216a52599460033f71f5e291f7518acc02 100644
--- a/smtk/mesh/operators/SetMeshName.h
+++ b/smtk/mesh/operators/SetMeshName.h
@@ -28,7 +28,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/mesh/operators/Subtract.cxx b/smtk/mesh/operators/Subtract.cxx
index 157c11c17f95bd6c50c7c6efa1ae067eb0c8d6d3..d20c6719ffa4c65e18c28666f5aec0d6750462a4 100644
--- a/smtk/mesh/operators/Subtract.cxx
+++ b/smtk/mesh/operators/Subtract.cxx
@@ -27,7 +27,7 @@ namespace smtk
 namespace mesh
 {
 
-smtk::mesh::Subtract::Result Subtract::operateInternal()
+smtk::mesh::Subtract::Result Subtract::operateInternal(Context ctx)
 {
   // Access the minuend and its resource
   smtk::mesh::MeshSet minuend =
diff --git a/smtk/mesh/operators/Subtract.h b/smtk/mesh/operators/Subtract.h
index 82983cdb451e2a77776d1df1db713e56350e1889..b052dd35bc750f849a0c8f59156e6b12eb237b99 100644
--- a/smtk/mesh/operators/Subtract.h
+++ b/smtk/mesh/operators/Subtract.h
@@ -28,7 +28,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/mesh/operators/Transform.cxx b/smtk/mesh/operators/Transform.cxx
index cc9cedf5bf8ff8dc6022c4580c691773b115a99b..32d39adf218fc334a0db5521857da37c974a4863 100644
--- a/smtk/mesh/operators/Transform.cxx
+++ b/smtk/mesh/operators/Transform.cxx
@@ -36,7 +36,7 @@ namespace smtk
 namespace mesh
 {
 
-smtk::mesh::Transform::Result Transform::operateInternal()
+smtk::mesh::Transform::Result Transform::operateInternal(Context ctx)
 {
   smtk::attribute::ReferenceItem::Ptr meshItem = this->parameters()->associations();
 
diff --git a/smtk/mesh/operators/Transform.h b/smtk/mesh/operators/Transform.h
index bf1f0511fdb4ee0bacb65af930eb80e98dc8cfac..c8551bf4a458e386da1a650ed4b0beba1759e14d 100644
--- a/smtk/mesh/operators/Transform.h
+++ b/smtk/mesh/operators/Transform.h
@@ -28,7 +28,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/mesh/operators/UndoElevateMesh.cxx b/smtk/mesh/operators/UndoElevateMesh.cxx
index ffa01e295b8eaef3652fb4571575f074c8331f2f..11636cfbe1cd390c7e0371dce2363525f996d93c 100644
--- a/smtk/mesh/operators/UndoElevateMesh.cxx
+++ b/smtk/mesh/operators/UndoElevateMesh.cxx
@@ -56,7 +56,7 @@ bool UndoElevateMesh::ableToOperate()
   return true;
 }
 
-UndoElevateMesh::Result UndoElevateMesh::operateInternal()
+UndoElevateMesh::Result UndoElevateMesh::operateInternal(Context ctx)
 {
   // Access the mesh
   smtk::attribute::ReferenceItem::Ptr meshItem = this->parameters()->associations();
diff --git a/smtk/mesh/operators/UndoElevateMesh.h b/smtk/mesh/operators/UndoElevateMesh.h
index 9f6875b3aab727fddb32272287d95771ee5086c0..8f9a05eef0317b8581afb15f6a1655dc1334a59f 100644
--- a/smtk/mesh/operators/UndoElevateMesh.h
+++ b/smtk/mesh/operators/UndoElevateMesh.h
@@ -34,7 +34,7 @@ public:
   bool ableToOperate() override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 } // namespace mesh
diff --git a/smtk/mesh/operators/Write.cxx b/smtk/mesh/operators/Write.cxx
index 991b41853664da2cbe333649de4c3e4726d31e1f..210c527ee62ea678523f26bd79b0abac3fb5f7f8 100644
--- a/smtk/mesh/operators/Write.cxx
+++ b/smtk/mesh/operators/Write.cxx
@@ -62,7 +62,7 @@ bool Write::ableToOperate()
   return this->Superclass::ableToOperate();
 }
 
-Write::Result Write::operateInternal()
+Write::Result Write::operateInternal(Context ctx)
 {
   std::string outputfile = this->parameters()->findFile("filename")->value();
 
diff --git a/smtk/mesh/operators/Write.h b/smtk/mesh/operators/Write.h
index 9345e6c94eca220914574af3f27ca75bad03b4fe..6eefcc39aee3838acc91afc8a0e97825d4e9b04c 100644
--- a/smtk/mesh/operators/Write.h
+++ b/smtk/mesh/operators/Write.h
@@ -30,7 +30,7 @@ public:
   bool ableToOperate() override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   Specification createSpecification() override;
   const char* xmlDescription() const override;
   void markModifiedResources(Result&) override;
diff --git a/smtk/mesh/operators/WriteResource.cxx b/smtk/mesh/operators/WriteResource.cxx
index 80bc351b4b29574750a813a45a29f8a60f7d794f..3d0ca873e5f2843c337faa2c0517fccf04ef5958 100644
--- a/smtk/mesh/operators/WriteResource.cxx
+++ b/smtk/mesh/operators/WriteResource.cxx
@@ -59,7 +59,7 @@ bool WriteResource::ableToOperate()
   return true;
 }
 
-WriteResource::Result WriteResource::operateInternal()
+WriteResource::Result WriteResource::operateInternal(Context ctx)
 {
   auto resourceItem = this->parameters()->associations();
 
diff --git a/smtk/mesh/operators/WriteResource.h b/smtk/mesh/operators/WriteResource.h
index 4410128b00d573ebb685e8b7099354d8ffb141d9..2a9e95100e295e9f44f5154788e482997ad49cbc 100644
--- a/smtk/mesh/operators/WriteResource.h
+++ b/smtk/mesh/operators/WriteResource.h
@@ -30,7 +30,7 @@ public:
   bool ableToOperate() override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
   void markModifiedResources(Result&) override;
 };
diff --git a/smtk/model/operators/AddAuxiliaryGeometry.cxx b/smtk/model/operators/AddAuxiliaryGeometry.cxx
index 3d5507431aee1065a3621b8a2ecfaeff4141dd93..ec6d3b169e902619c82b06d1b7f23d64424ad773 100644
--- a/smtk/model/operators/AddAuxiliaryGeometry.cxx
+++ b/smtk/model/operators/AddAuxiliaryGeometry.cxx
@@ -42,7 +42,7 @@ namespace smtk
 namespace model
 {
 
-AddAuxiliaryGeometry::Result AddAuxiliaryGeometry::operateInternal()
+AddAuxiliaryGeometry::Result AddAuxiliaryGeometry::operateInternal(Context ctx)
 {
   auto associations = this->parameters()->associations();
   auto entities = associations->as<EntityRefArray>(
diff --git a/smtk/model/operators/AddAuxiliaryGeometry.h b/smtk/model/operators/AddAuxiliaryGeometry.h
index cdc1a3dbd9bc2ff109dbb509c880a9558a5dc63d..aed281af4a8cab024426a043ea60f7424e7fac30 100644
--- a/smtk/model/operators/AddAuxiliaryGeometry.h
+++ b/smtk/model/operators/AddAuxiliaryGeometry.h
@@ -26,7 +26,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/model/operators/AddImage.cxx b/smtk/model/operators/AddImage.cxx
index a284ebcb88eee5d7a483b65b316b53355932e64f..e011b5f825f8609604b8213993be25f7c792490e 100644
--- a/smtk/model/operators/AddImage.cxx
+++ b/smtk/model/operators/AddImage.cxx
@@ -20,9 +20,9 @@ namespace smtk
 namespace model
 {
 
-AddImage::Result AddImage::operateInternal()
+AddImage::Result AddImage::operateInternal(Context ctx)
 {
-  Result res = this->AddAuxiliaryGeometry::operateInternal();
+  Result res = this->AddAuxiliaryGeometry::operateInternal(ctx);
   smtk::attribute::ComponentItem::Ptr created = res->findComponent("created");
   for (size_t i = 0; i < created->numberOfValues(); ++i)
   {
diff --git a/smtk/model/operators/AddImage.h b/smtk/model/operators/AddImage.h
index 61dc6ee01d286e8a16b41948560b883e53642a21..b327fd2bcf6b4e8804c90ab1bc0043c659ad2f37 100644
--- a/smtk/model/operators/AddImage.h
+++ b/smtk/model/operators/AddImage.h
@@ -26,7 +26,7 @@ public:
   smtkSuperclassMacro(AddAuxiliaryGeometry);
 
 private:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/model/operators/CloseModel.cxx b/smtk/model/operators/CloseModel.cxx
index 22d635d02031cb6d31fc40542c3a4498c7fac9e8..9e1894c0901316c84e815873df5832b6a2741177 100644
--- a/smtk/model/operators/CloseModel.cxx
+++ b/smtk/model/operators/CloseModel.cxx
@@ -43,7 +43,7 @@ bool CloseModel::ableToOperate()
   return modelItem && modelItem->numberOfValues() > 0;
 }
 
-CloseModel::Result CloseModel::operateInternal()
+CloseModel::Result CloseModel::operateInternal(Context ctx)
 {
   // ableToOperate should have verified that model(s) are set
   smtk::attribute::ReferenceItem::Ptr modelItem = this->parameters()->associations();
diff --git a/smtk/model/operators/CloseModel.h b/smtk/model/operators/CloseModel.h
index ad087d5792555def548594051004a7f1204f24aa..8dc5c353e1cd88fae5ca61bc5632b7a0b9b9b85e 100644
--- a/smtk/model/operators/CloseModel.h
+++ b/smtk/model/operators/CloseModel.h
@@ -28,7 +28,7 @@ public:
   bool ableToOperate() override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/model/operators/CreateInstances.cxx b/smtk/model/operators/CreateInstances.cxx
index 7c0b12f36a3feb0f32d9dd6ad2f3f7402152932b..0fa034b75b6d4023a695ee433138f17fc31f98d8 100644
--- a/smtk/model/operators/CreateInstances.cxx
+++ b/smtk/model/operators/CreateInstances.cxx
@@ -106,7 +106,7 @@ void CreateInstances::addSnappingConstraints(Instance& instance, const EntityRef
   }
 }
 
-CreateInstances::Result CreateInstances::operateInternal()
+CreateInstances::Result CreateInstances::operateInternal(Context ctx)
 {
   auto associations = this->parameters()->associations();
   auto prototypes = associations->as<EntityRefArray>([](PersistentObjectPtr obj) {
diff --git a/smtk/model/operators/CreateInstances.h b/smtk/model/operators/CreateInstances.h
index c4c20d6e8640ed258b61a5bfb79b03aa8df96c89..872ec0296c6567fd066cd318154a9f0785b5b431 100644
--- a/smtk/model/operators/CreateInstances.h
+++ b/smtk/model/operators/CreateInstances.h
@@ -26,7 +26,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 
   void addTabularRule(Instance& instance, const EntityRef& prototype);
diff --git a/smtk/model/operators/Delete.cxx b/smtk/model/operators/Delete.cxx
index caf977a8a77c9c34365be497557a2be9c0654d17..4179997b94a390ff0a0ed51f3fb7cba9026242ed 100644
--- a/smtk/model/operators/Delete.cxx
+++ b/smtk/model/operators/Delete.cxx
@@ -310,7 +310,7 @@ void Delete::addBoundaryCells(
   }
 }
 
-Delete::Result Delete::operateInternal()
+Delete::Result Delete::operateInternal(Context ctx)
 {
   smtk::attribute::VoidItem::Ptr deleteHigherDimen =
     this->parameters()->findVoid("delete higher-dimensional neighbors");
diff --git a/smtk/model/operators/Delete.h b/smtk/model/operators/Delete.h
index 8e3421e1aacbabc2fa52fb289384ccd8d871d508..3e84465073ff53a889525a74ae92a0802c396296 100644
--- a/smtk/model/operators/Delete.h
+++ b/smtk/model/operators/Delete.h
@@ -36,7 +36,7 @@ public:
   smtkSuperclassMacro(Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 
   template<typename U, typename V, typename W, typename X>
diff --git a/smtk/model/operators/DivideInstance.cxx b/smtk/model/operators/DivideInstance.cxx
index 432f4bd01333817b362ca0ced95ab1324107a67a..ceb8b26d493667d64ffe7efc69c0bcf4d3deea5d 100644
--- a/smtk/model/operators/DivideInstance.cxx
+++ b/smtk/model/operators/DivideInstance.cxx
@@ -44,7 +44,7 @@ bool DivideInstance::ableToOperate()
   return parent.isValid();
 }
 
-DivideInstance::Result DivideInstance::operateInternal()
+DivideInstance::Result DivideInstance::operateInternal(Context ctx)
 {
   auto associations = this->parameters()->associations();
   Instance instance = this->parentOfClones(associations);
diff --git a/smtk/model/operators/DivideInstance.h b/smtk/model/operators/DivideInstance.h
index dfe61d14644c3b1c55c8460d572c55185f63716e..b0a949caddb04ce2dd2408af5fa92011330de892 100644
--- a/smtk/model/operators/DivideInstance.h
+++ b/smtk/model/operators/DivideInstance.h
@@ -28,7 +28,7 @@ public:
   bool ableToOperate() override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 
   /**\brief Return the parent instance of clones in the provided \a item.
diff --git a/smtk/model/operators/EntityGroupOperation.cxx b/smtk/model/operators/EntityGroupOperation.cxx
index 53c237f89fe6a8816e904c0412a1c11ba83c4fe1..572d849d519f9e47e745331b8b5cb45bc90bdb45 100644
--- a/smtk/model/operators/EntityGroupOperation.cxx
+++ b/smtk/model/operators/EntityGroupOperation.cxx
@@ -58,7 +58,7 @@ bool EntityGroupOperation::ableToOperate()
   return ableToOperate;
 }
 
-EntityGroupOperation::Result EntityGroupOperation::operateInternal()
+EntityGroupOperation::Result EntityGroupOperation::operateInternal(Context ctx)
 {
   // pre processing the data
   auto modelItem = this->parameters()->associations();
diff --git a/smtk/model/operators/EntityGroupOperation.h b/smtk/model/operators/EntityGroupOperation.h
index 37b40d1f4b80fc0e13478095a0627c2688310299..1cdb1a6b78482681f5c76a132ff68f27ef7cd631 100644
--- a/smtk/model/operators/EntityGroupOperation.h
+++ b/smtk/model/operators/EntityGroupOperation.h
@@ -37,7 +37,7 @@ public:
   bool ableToOperate() override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/model/operators/ExportModelJSON.cxx b/smtk/model/operators/ExportModelJSON.cxx
index 6488007044e92f746d9f6c90d5b90573932a763f..b1060bfdcf98b2a7fe441faeae057edd0f349e2e 100644
--- a/smtk/model/operators/ExportModelJSON.cxx
+++ b/smtk/model/operators/ExportModelJSON.cxx
@@ -31,7 +31,7 @@ namespace smtk
 namespace model
 {
 
-ExportModelJSON::Result ExportModelJSON::operateInternal()
+ExportModelJSON::Result ExportModelJSON::operateInternal(Context ctx)
 {
   smtk::attribute::FileItemPtr filenameItem = this->parameters()->findFile("filename");
   smtk::attribute::IntItemPtr flagsItem = this->parameters()->findInt("flags");
diff --git a/smtk/model/operators/ExportModelJSON.h b/smtk/model/operators/ExportModelJSON.h
index 83ad724d58f449408cfc174dc39126c7c08c8ee0..52e4856ff7e279219d60a2b9db3668fc97ff3be5 100644
--- a/smtk/model/operators/ExportModelJSON.h
+++ b/smtk/model/operators/ExportModelJSON.h
@@ -26,7 +26,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/model/operators/GroupAuxiliaryGeometry.cxx b/smtk/model/operators/GroupAuxiliaryGeometry.cxx
index 5158d83a98c45a8114dc59d08ccd0d2b70e907be..b63ece0980d02127616bb8496d153f55b2daa5d0 100644
--- a/smtk/model/operators/GroupAuxiliaryGeometry.cxx
+++ b/smtk/model/operators/GroupAuxiliaryGeometry.cxx
@@ -32,7 +32,7 @@ namespace smtk
 namespace model
 {
 
-GroupAuxiliaryGeometry::Result GroupAuxiliaryGeometry::operateInternal()
+GroupAuxiliaryGeometry::Result GroupAuxiliaryGeometry::operateInternal(Context ctx)
 {
   auto associations = this->parameters()->associations();
   auto entities =
diff --git a/smtk/model/operators/GroupAuxiliaryGeometry.h b/smtk/model/operators/GroupAuxiliaryGeometry.h
index c1bca582f04da6a82dc76964b3293afeb99dce54..9fe86ec6792deae9a4c3bc5d05d7187d0a19e326 100644
--- a/smtk/model/operators/GroupAuxiliaryGeometry.h
+++ b/smtk/model/operators/GroupAuxiliaryGeometry.h
@@ -26,7 +26,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/model/operators/MergeInstances.cxx b/smtk/model/operators/MergeInstances.cxx
index ab52af5c9c7e1242d9c50990104641afa022d02a..471524ce96e18b8f5ccfbbdf854927112638de24 100644
--- a/smtk/model/operators/MergeInstances.cxx
+++ b/smtk/model/operators/MergeInstances.cxx
@@ -58,7 +58,7 @@ bool MergeInstances::ableToOperate()
   });
 }
 
-MergeInstances::Result MergeInstances::operateInternal()
+MergeInstances::Result MergeInstances::operateInternal(Context ctx)
 {
   auto associations = this->parameters()->associations();
   auto instances = associations->as<Instances>([](smtk::resource::PersistentObjectPtr obj) {
diff --git a/smtk/model/operators/MergeInstances.h b/smtk/model/operators/MergeInstances.h
index 5772ff5775b0d7b7c9d537afa40dc6e4978593a6..ab99a508cb8bd9bf6ce58cc3e3804da27a705d13 100644
--- a/smtk/model/operators/MergeInstances.h
+++ b/smtk/model/operators/MergeInstances.h
@@ -28,7 +28,7 @@ public:
   bool ableToOperate() override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/model/operators/SetInstancePrototype.cxx b/smtk/model/operators/SetInstancePrototype.cxx
index 36c217bc536b57493ac96c2daafe0f86581d19ba..b08a184bed4109c3f2c6500d6a214f432e344af9 100644
--- a/smtk/model/operators/SetInstancePrototype.cxx
+++ b/smtk/model/operators/SetInstancePrototype.cxx
@@ -29,7 +29,7 @@ namespace smtk
 namespace model
 {
 
-SetInstancePrototype::Result SetInstancePrototype::operateInternal()
+SetInstancePrototype::Result SetInstancePrototype::operateInternal(Context ctx)
 {
   auto associations = this->parameters()->associations();
   auto entities = associations->as<Instances>([](smtk::resource::PersistentObjectPtr obj) {
diff --git a/smtk/model/operators/SetInstancePrototype.h b/smtk/model/operators/SetInstancePrototype.h
index d13c76c59aedc072d9481f3c5f232d2de5cf54a3..a2cfba70c7f19c982aad057aecd3d76a1ade68c9 100644
--- a/smtk/model/operators/SetInstancePrototype.h
+++ b/smtk/model/operators/SetInstancePrototype.h
@@ -26,7 +26,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/model/operators/TerrainExtraction.cxx b/smtk/model/operators/TerrainExtraction.cxx
index 09a34fe7b20448ecbecca33e84a800f5d106d8c6..21ac3425df3d830f5048c4ad16d71953cb8ffbe0 100644
--- a/smtk/model/operators/TerrainExtraction.cxx
+++ b/smtk/model/operators/TerrainExtraction.cxx
@@ -25,7 +25,7 @@ namespace smtk
 namespace model
 {
 
-TerrainExtraction::Result TerrainExtraction::operateInternal()
+TerrainExtraction::Result TerrainExtraction::operateInternal(Context ctx)
 {
   auto associations = this->parameters()->associations();
 
diff --git a/smtk/model/operators/TerrainExtraction.h b/smtk/model/operators/TerrainExtraction.h
index a7c924f11a3be25fc5c134c68a3902784b2f07ba..3481f9a3ea6769fc0ea5095007ee713eda08d2e5 100644
--- a/smtk/model/operators/TerrainExtraction.h
+++ b/smtk/model/operators/TerrainExtraction.h
@@ -26,7 +26,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/operation/CreateResource.cxx b/smtk/operation/CreateResource.cxx
index fffb1e80cdca76c543d0368bd291f24d1830ce06..498b7a2ad92e137dfaa3a6f5af20ad3abee84306 100644
--- a/smtk/operation/CreateResource.cxx
+++ b/smtk/operation/CreateResource.cxx
@@ -29,7 +29,7 @@ namespace operation
 
 CreateResource::CreateResource() {}
 
-smtk::operation::Operation::Result CreateResource::operateInternal()
+smtk::operation::Operation::Result CreateResource::operateInternal(Context ctx)
 {
   auto params = this->parameters();
   auto typeItem = params->findString("type");
diff --git a/smtk/operation/CreateResource.h b/smtk/operation/CreateResource.h
index 18a009797d448f40a287846ff36be50b8a0fa68b..cc72295b50067560ef033dd46ee40eaf2641ad0c 100644
--- a/smtk/operation/CreateResource.h
+++ b/smtk/operation/CreateResource.h
@@ -28,7 +28,7 @@ public:
 protected:
   CreateResource();
 
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
 
   const char* xmlDescription() const override;
   void generateSummary(Result&) override;
diff --git a/smtk/operation/Manager.cxx b/smtk/operation/Manager.cxx
index 5393d999cf2f8f5c4ac3a81a3ba6d47043001686..5ad8c2ca22b067a5d9829d5e4abb37a8fd5e79df 100644
--- a/smtk/operation/Manager.cxx
+++ b/smtk/operation/Manager.cxx
@@ -190,6 +190,7 @@ bool Manager::registerResourceManager(smtk::resource::ManagerPtr& resourceManage
   // Define an observer that adds all created resources to the resource manager.
   m_resourceObserver = this->observers().insert(
     [&, weakRMPtr](
+    smtk::common::Context ctx,
       const smtk::operation::Operation& /*unused*/,
       smtk::operation::EventType event,
       smtk::operation::Operation::Result result) {
diff --git a/smtk/operation/Observer.h b/smtk/operation/Observer.h
index b508e57ed2a47a202c9e011ab0c32f543ce5e411..777e663bbd6c1cb16d5c295a21f2062145449eea 100644
--- a/smtk/operation/Observer.h
+++ b/smtk/operation/Observer.h
@@ -10,6 +10,7 @@
 #ifndef smtk_operation_Observer_h
 #define smtk_operation_Observer_h
 
+#include "smtk/common/Context.h"
 #include "smtk/common/Observers.h"
 #include "smtk/operation/Operation.h"
 
@@ -39,7 +40,7 @@ enum class EventType
   * Observers must return an integer. If the event type is WILL_OPERATE and
   * the integer is non-zero, the operation will be canceled.
   */
-typedef std::function<int(const Operation&, EventType, Operation::Result)> Observer;
+typedef std::function<int(smtk::common::Context ctx, const Operation&, EventType, Operation::Result)> Observer;
 
 /// Operation observers are a specialization of the common SMTK observer pattern.
 typedef smtk::common::Observers<Observer> Observers;
diff --git a/smtk/operation/Operation.cxx b/smtk/operation/Operation.cxx
index 041cc1261c0bc8fcdbcb01d3bf1f4564b31baf40..0d7138843d1fe5546f20aa06215f996cb2b6f73a 100644
--- a/smtk/operation/Operation.cxx
+++ b/smtk/operation/Operation.cxx
@@ -37,6 +37,10 @@
 #include <sstream>
 #include <thread>
 
+DECLARE_CONTEXT_KEY_TYPE(parentOperationKey)
+DECLARE_CONTEXT_KEY_TYPE(resultsKey)
+DECLARE_CONTEXT_KEY_TYPE(threadKey)
+
 namespace
 {
 // We construct unique parameter and result names in a thread-safe way, rather
@@ -130,15 +134,31 @@ ResourceAccessMap Operation::identifyLocksRequired()
   return extractResourcesAndLockTypes(this->parameters());
 }
 
-Operation::Result Operation::operate()
+Operation::Result Operation::operate(const Context& ctx)
 {
   // Call operate that will invoke observers.
-  return this->operate(BaseKey(
-    nullptr, ObserverOption::InvokeObservers, LockOption::LockAll, ParametersOption::Validate));
+  return this->operate(
+    ctx,
+    BaseKey(
+      nullptr, ObserverOption::InvokeObservers, LockOption::LockAll, ParametersOption::Validate));
 }
 
-Operation::Result Operation::operate(const BaseKey& key)
+Operation::Result Operation::operate(Context ctx, const BaseKey& key)
 {
+  // Check that the current thread matches the initial parent.
+  if (auto thread = ctx.value<threadKey, std::thread::id>())
+  {
+    if (std::this_thread::get_id() != *thread)
+    {
+      throw std::logic_error("context belongs to operation in a different thread");
+    }
+  }
+  else
+  {
+    // Store the current thread id into the context.
+    ctx = ctx.withValue<threadKey>(std::this_thread::get_id());
+  }
+
   // Gather all requested resources and their lock types.
   const auto resourcesAndLockTypes = this->identifyLocksRequired();
 
@@ -174,6 +194,13 @@ Operation::Result Operation::operate(const BaseKey& key)
         this->m_lockedResources = key.m_parent->lockedResources();
       }
 
+		if (auto parentKey = ctx.value<parentOperationKey, BaseKey>())
+        {
+		  // Inherit resource locks from the context.
+          auto& lockedResources = parentKey->m_parent->lockedResources();
+          this->m_lockedResources.insert(lockedResources.begin(), lockedResources.end());
+        }
+
       // Populate queue for pending resource locks.
       std::queue<ResourceAccessMap::value_type> pending;
       for (const auto& resourceAndLockType : resourcesAndLockTypes)
@@ -266,13 +293,13 @@ Operation::Result Operation::operate(const BaseKey& key)
 
       if (pending.empty())
       {
-        // All of the locks were acquired successfully. Continue with the
+        // All the locks were acquired successfully. Continue with the
         // operation logic.
         break;
       }
       else
       {
-        // All of the resource locks could not be acquired. Release the locks on any
+        // All the resource locks could not be acquired. Release the locks on any
         // resource whose lock was successfully acquired so that other threads
         // have a chance to attempt the locks if they are waiting.
         this->unlockResources(lockedByThis);
@@ -310,7 +337,7 @@ Operation::Result Operation::operate(const BaseKey& key)
   {
     if (
       key.m_observerOption == ObserverOption::InvokeObservers && manager &&
-      manager->observers()(*this, EventType::WILL_OPERATE, nullptr))
+      manager->observers()(ctx, *this, EventType::WILL_OPERATE, nullptr))
     {
       outcome = Outcome::CANCELED;
       result = this->createResult(outcome);
@@ -324,8 +351,13 @@ Operation::Result Operation::operate(const BaseKey& key)
       smtk::attribute::IntItem::Ptr debugItem = this->parameters()->findInt("debug level");
       m_debugLevel = ((debugItem && debugItem->isEnabled()) ? debugItem->value() : 0);
 
+      // Store a key in the context to establish this operation as the parent for
+      // all future operations on the current control path.
+      ctx = ctx.withValue<parentOperationKey>(this->childKey());
+
       // Perform the derived operation.
-      result = this->operateInternal();
+      result = this->operateInternal(ctx);
+
       // Post-process the result if the operation was successful.
       outcome = static_cast<Outcome>(result->findInt("outcome")->value());
       if (outcome == Outcome::SUCCEEDED)
@@ -361,7 +393,7 @@ Operation::Result Operation::operate(const BaseKey& key)
   // Execute post-operation observation
   if (key.m_observerOption == ObserverOption::InvokeObservers && observePostOperation && manager)
   {
-    manager->observers()(*this, EventType::DID_OPERATE, result);
+    manager->observers()(ctx, *this, EventType::DID_OPERATE, result);
   }
 
   // Un-manage any resources marked for removal before releasing locks.
@@ -380,6 +412,11 @@ Operation::Result Operation::operate(const BaseKey& key)
   return result;
 }
 
+Operation::Result Operation::operate(const BaseKey& key)
+{
+  return this->operate(Context(), key);
+}
+
 void Operation::unlockResources(const ResourceAccessMap& resources)
 {
   for (const auto& resourceAndLockType : resources)
diff --git a/smtk/operation/Operation.h b/smtk/operation/Operation.h
index 35df8ee43762e1639b3c798b3f56485744450d5d..e819da76b9cbea0f17d0fd417f908df8d90c3a62 100644
--- a/smtk/operation/Operation.h
+++ b/smtk/operation/Operation.h
@@ -14,6 +14,7 @@
 
 #include "smtk/PublicPointerDefs.h"
 #include "smtk/SharedFromThis.h"
+#include "smtk/common/Context.h"
 #include "smtk/common/Deprecation.h"
 
 #include <functional>
@@ -56,7 +57,7 @@ using ResourceAccessMap = std::map<
 /// createSpecification(). There should be exactly one attribute definition that
 /// derives from "operation" and one definition that derives from "result". The
 /// creation, destruction and manipulation of SMTK resources and components
-/// occurs in the method operateInternal(). Operations are designed to work in
+/// occurs in the method operateInternal(Context ctx). Operations are designed to work in
 /// conjunction with an smtk::operation::Manager, but can also be used as
 /// standalone functors.
 class SMTKCORE_EXPORT Operation : smtkEnableSharedPtr(Operation)
@@ -65,6 +66,7 @@ class SMTKCORE_EXPORT Operation : smtkEnableSharedPtr(Operation)
 
 public:
   smtkTypeMacroBase(smtk::operation::Operation);
+  using Context = smtk::common::Context;
 
   // A hash value uniquely representing the operation.
   typedef std::size_t Index;
@@ -100,7 +102,10 @@ public:
   // cannot be set. It is virtual so that derived operations can assign their
   // own index (as is necessary for python operations that would otherwise all
   // resolve to the same index).
-  virtual Index index() const { return std::type_index(typeid(*this)).hash_code(); }
+  virtual Index index() const
+  {
+    return std::type_index(typeid(*this)).hash_code();
+  }
 
   /// Update the operation's specification and operations to be consistent.
   ///
@@ -134,8 +139,8 @@ public:
   virtual bool ableToOperate();
 
   /// Execute the operation, log its outcome and return its results. This method
-  /// calls operateInternal() and handles additional bookkeeping.
-  Result operate();
+  /// calls operateInternal(Context ctx) and handles additional bookkeeping.
+  Result operate(const Context& ctx = Context());
 
   /// Execute the operation in an asynchronous environment. This method does not
   /// return until the operation is complete, but because it does not return a
@@ -162,7 +167,7 @@ public:
   /// resource; anyone holding the shared pointer to the result will keep the
   /// attribute in memory but will experience inconsistent behavior since its items
   /// are removed as part of releasing it from control by the attribute::Resource.
-  virtual bool releaseResult(Result& result);
+  virtual bool releaseResult(Result & result);
 
   /// Retrieve the operation's logger. By default, we use the singleton logger.
   /// Derived classes can reimplement this method if an alternative logging
@@ -186,17 +191,29 @@ public:
   Result createResult(Outcome);
 
   /// Operations that are managed have a non-null pointer to their manager.
-  ManagerPtr manager() const { return m_manager.lock(); }
+  ManagerPtr manager() const
+  {
+    return m_manager.lock();
+  }
 
   /// restore operation parameters from the trace of a previously run operation.
   bool restoreTrace(const std::string& trace);
 
   /// Operations may be passed application state in the form of a Managers type-container.
-  void setManagers(const std::shared_ptr<smtk::common::Managers>& m) { m_managers = m; }
-  std::shared_ptr<smtk::common::Managers> managers() const { return m_managers; }
+  void setManagers(const std::shared_ptr<smtk::common::Managers>& m)
+  {
+    m_managers = m;
+  }
+  std::shared_ptr<smtk::common::Managers> managers() const
+  {
+    return m_managers;
+  }
 
   /// Is this type of operation safe to launch in a thread?
-  virtual bool threadSafe() const { return true; }
+  virtual bool threadSafe() const
+  {
+    return true;
+  }
 
   /// retrieve the resource manager, if available.
   smtk::resource::ManagerPtr resourceManager();
@@ -237,10 +254,13 @@ protected:
   virtual ResourceAccessMap identifyLocksRequired();
 
   /// Returns the set of resources that are currently locked by this operation.
-  const ResourceAccessMap& lockedResources() const { return this->m_lockedResources; }
+  const ResourceAccessMap& lockedResources() const
+  {
+    return this->m_lockedResources;
+  }
 
   /// Perform the actual operation and construct the result.
-  virtual Result operateInternal() = 0;
+  virtual Result operateInternal(Context context) = 0;
 
   // Apply post-processing to the result object. This method should not modify
   // the modeling kernel but may change string/float/int properties stored on
@@ -301,7 +321,7 @@ protected:
   };
 
   /// Return a key that will allow subclasses of Operation to run other
-  /// nested operations (from within `operateInternal()`).
+  /// nested operations (from within `operateInternal(Context ctx)`).
   ///
   /// The options passed to this method control how the nested operation
   /// is validated before running and whether to invoke observers on
@@ -313,6 +333,7 @@ protected:
 
 public:
   /// Run an operation given a key returned by Operation::childKey().
+  Result operate(Context ctx, const BaseKey& key);
   Result operate(const BaseKey& key);
 
 private:
diff --git a/smtk/operation/XMLOperation.h b/smtk/operation/XMLOperation.h
index d84e18957f6b1cdd7982478b48df37d7442ab705..0c3dc87d51e4ada6d2189b58645be6918df7084f 100644
--- a/smtk/operation/XMLOperation.h
+++ b/smtk/operation/XMLOperation.h
@@ -32,7 +32,7 @@ protected:
   XMLOperation();
 
   // Perform the actual operation and construct the result.
-  Result operateInternal() override = 0;
+  Result operateInternal(Context ctx) override = 0;
 
   // Construct the operation's specification from the class's XML description.
   Specification createSpecification() override;
diff --git a/smtk/operation/operators/AssignColors.cxx b/smtk/operation/operators/AssignColors.cxx
index cd06582a7ac8a0b0458b4b502a522c0ee5b3d624..f65ce34515024447d4d87771eeaed4c30eef5161 100644
--- a/smtk/operation/operators/AssignColors.cxx
+++ b/smtk/operation/operators/AssignColors.cxx
@@ -38,7 +38,7 @@ namespace smtk
 namespace operation
 {
 
-AssignColors::Result AssignColors::operateInternal()
+AssignColors::Result AssignColors::operateInternal(Context ctx)
 {
   auto associations = this->parameters()->associations();
   auto entities = associations->as<std::set<PersistentObjectPtr>>();
diff --git a/smtk/operation/operators/AssignColors.h b/smtk/operation/operators/AssignColors.h
index ebe88e0b83696f1cc83f876886680735972012af..dcf5a79bdc0028f6e675fbcb37661e2d4ae65bc7 100644
--- a/smtk/operation/operators/AssignColors.h
+++ b/smtk/operation/operators/AssignColors.h
@@ -26,7 +26,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/operation/operators/CoordinateTransform.cxx b/smtk/operation/operators/CoordinateTransform.cxx
index d0aae08ee48546d7c5c4dd774f7595d976e369b1..c3eca4d9d8ad88e9bac735b235d196d998c32ddf 100644
--- a/smtk/operation/operators/CoordinateTransform.cxx
+++ b/smtk/operation/operators/CoordinateTransform.cxx
@@ -93,7 +93,7 @@ bool CoordinateTransform::removeTransform(
   return didRemove;
 }
 
-CoordinateTransform::Result CoordinateTransform::operateInternal()
+CoordinateTransform::Result CoordinateTransform::operateInternal(Context ctx)
 {
   smtk::attribute::ItemPtr removeItem = this->parameters()->find("remove");
   bool removeProperty = removeItem->isEnabled();
diff --git a/smtk/operation/operators/CoordinateTransform.h b/smtk/operation/operators/CoordinateTransform.h
index 1ffb64e5fa3938934063d4ee8aee099ccb20ece0..e0c107549bec231a12bce4fa94b3be30a90b5aff 100644
--- a/smtk/operation/operators/CoordinateTransform.h
+++ b/smtk/operation/operators/CoordinateTransform.h
@@ -64,7 +64,7 @@ protected:
     const std::shared_ptr<smtk::attribute::ReferenceItem>& associations,
     Result& result);
 
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/operation/operators/CopyResources.cxx b/smtk/operation/operators/CopyResources.cxx
index 588808a8288d433efe49614b33f5c9bcf84ae14d..b771714f8001488753ee39815a8923ae59f2f71f 100644
--- a/smtk/operation/operators/CopyResources.cxx
+++ b/smtk/operation/operators/CopyResources.cxx
@@ -70,7 +70,7 @@ bool CopyResources::ableToOperate()
   return true;
 }
 
-smtk::operation::Operation::Result CopyResources::operateInternal()
+smtk::operation::Operation::Result CopyResources::operateInternal(Context ctx)
 {
   smtk::resource::CopyOptions options(this->log());
   auto sources = this->parameters()->associations();
diff --git a/smtk/operation/operators/CopyResources.h b/smtk/operation/operators/CopyResources.h
index 79df37c70a3499b2065a6756ac876d776114b524..a0b091407192ce2282279e6236dcf94baebdff71 100644
--- a/smtk/operation/operators/CopyResources.h
+++ b/smtk/operation/operators/CopyResources.h
@@ -30,7 +30,7 @@ public:
 protected:
   CopyResources();
 
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
 
   const char* xmlDescription() const override;
 };
diff --git a/smtk/operation/operators/EditProperties.cxx b/smtk/operation/operators/EditProperties.cxx
index cd06e6095ba2848bb69c3ec943ad950d848ed8e5..23cbcb3695a12ff35b05c5229331465302ed0a19 100644
--- a/smtk/operation/operators/EditProperties.cxx
+++ b/smtk/operation/operators/EditProperties.cxx
@@ -154,7 +154,7 @@ void EditPropertiesValue(
   }
 }
 
-EditProperties::Result EditProperties::operateInternal()
+EditProperties::Result EditProperties::operateInternal(Context ctx)
 {
   smtk::attribute::StringItemPtr nameItem = this->parameters()->findString("name");
   smtk::attribute::IntItemPtr typeItem = this->parameters()->findInt("type");
diff --git a/smtk/operation/operators/EditProperties.h b/smtk/operation/operators/EditProperties.h
index 66e2c938d27dcc4ce5e313b6a73b3915f0f295f6..04f9e1904fdcca0a6e77f5bbedb70328de5160da 100644
--- a/smtk/operation/operators/EditProperties.h
+++ b/smtk/operation/operators/EditProperties.h
@@ -34,7 +34,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/operation/operators/ImportPythonOperation.cxx b/smtk/operation/operators/ImportPythonOperation.cxx
index 2d5b6a8602e6fbcea4235bb94c042b67da1c43f6..66809af50b926bafd92cb14a064deb3e5b426ccb 100644
--- a/smtk/operation/operators/ImportPythonOperation.cxx
+++ b/smtk/operation/operators/ImportPythonOperation.cxx
@@ -119,7 +119,7 @@ bool ImportPythonOperation::importOperation(
   return manager.registerOperation(Metadata(typeName, index, specification, create));
 }
 
-ImportPythonOperation::Result ImportPythonOperation::operateInternal()
+ImportPythonOperation::Result ImportPythonOperation::operateInternal(Context ctx)
 {
   // Access the python operation's file name
   smtk::attribute::FileItemPtr fileItem = this->parameters()->findFile("filename");
diff --git a/smtk/operation/operators/ImportPythonOperation.h b/smtk/operation/operators/ImportPythonOperation.h
index f530563ea322bffed42400966024b967a7efb114..694ac3d73c5a5e3c26e93f4eda90079d283b4f79 100644
--- a/smtk/operation/operators/ImportPythonOperation.h
+++ b/smtk/operation/operators/ImportPythonOperation.h
@@ -42,7 +42,7 @@ public:
     const std::string& opName);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   void generateSummary(Result&) override;
   Specification createSpecification() override;
 };
diff --git a/smtk/operation/operators/ImportResource.cxx b/smtk/operation/operators/ImportResource.cxx
index cffe92d0ef19b11dfbd1e110af04d966aa588ce3..5c3288d488d0763e24e83d642c105b487b1be62a 100644
--- a/smtk/operation/operators/ImportResource.cxx
+++ b/smtk/operation/operators/ImportResource.cxx
@@ -67,7 +67,7 @@ bool ImportResource::ableToOperate()
   return true;
 }
 
-ImportResource::Result ImportResource::operateInternal()
+ImportResource::Result ImportResource::operateInternal(Context ctx)
 {
   auto manager = m_manager.lock();
 
diff --git a/smtk/operation/operators/ImportResource.h b/smtk/operation/operators/ImportResource.h
index 2fe5c6ba24f2b87d4d9bde8c29ee6b246595aa88..c88a087d69f4c4c935ce20892851689d99e9c65f 100644
--- a/smtk/operation/operators/ImportResource.h
+++ b/smtk/operation/operators/ImportResource.h
@@ -32,7 +32,7 @@ public:
 protected:
   ImportResource();
 
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
 
   Specification createSpecification() override;
   void generateSummary(Result&) override;
diff --git a/smtk/operation/operators/MarkModified.cxx b/smtk/operation/operators/MarkModified.cxx
index 3795e9813d833ffbe911e892ab688b9b6cdf6395..48277aac877b6ed0c7b1b0ec6e2e1144c0bb1c7d 100644
--- a/smtk/operation/operators/MarkModified.cxx
+++ b/smtk/operation/operators/MarkModified.cxx
@@ -26,7 +26,7 @@ namespace smtk
 namespace operation
 {
 
-MarkModified::Result MarkModified::operateInternal()
+MarkModified::Result MarkModified::operateInternal(Context ctx)
 {
   auto params = this->parameters();
   auto result = this->createResult(smtk::operation::Operation::Outcome::SUCCEEDED);
diff --git a/smtk/operation/operators/MarkModified.h b/smtk/operation/operators/MarkModified.h
index 0d6e7e11dae38ef94dd3e9a852a0aa87c1c11267..3e656419c1663639f9b2410865a93c00d67cc590 100644
--- a/smtk/operation/operators/MarkModified.h
+++ b/smtk/operation/operators/MarkModified.h
@@ -31,7 +31,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   void generateSummary(Operation::Result&) override;
   const char* xmlDescription() const override;
 };
diff --git a/smtk/operation/operators/ReadResource.cxx b/smtk/operation/operators/ReadResource.cxx
index 62cf820a701a03ea3f11b9467971c01e9e54e38a..0fd6a7e060834a2bbb0de5c43f51c10c005e0cf9 100644
--- a/smtk/operation/operators/ReadResource.cxx
+++ b/smtk/operation/operators/ReadResource.cxx
@@ -56,7 +56,7 @@ bool ReadResource::ableToOperate()
   return true;
 }
 
-ReadResource::Result ReadResource::operateInternal()
+ReadResource::Result ReadResource::operateInternal(Context ctx)
 {
   auto manager = m_manager.lock();
 
diff --git a/smtk/operation/operators/ReadResource.h b/smtk/operation/operators/ReadResource.h
index cd410a50869788daa34468971ca5efc129ce3369..a62352d953c2b0e66c8353a7e7fa477eb230aef5 100644
--- a/smtk/operation/operators/ReadResource.h
+++ b/smtk/operation/operators/ReadResource.h
@@ -30,7 +30,7 @@ public:
 protected:
   ReadResource();
 
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
 
   const char* xmlDescription() const override;
   void markModifiedResources(Result&) override;
diff --git a/smtk/operation/operators/RemoveResource.cxx b/smtk/operation/operators/RemoveResource.cxx
index eff87cd57a5bc1f7b8d1b8675c9d0394d05d0688..9c7e8bb710d44dc9e2d632b6271948d8bdd24e85 100644
--- a/smtk/operation/operators/RemoveResource.cxx
+++ b/smtk/operation/operators/RemoveResource.cxx
@@ -46,7 +46,7 @@ bool RemoveResource::ableToOperate()
   return true;
 }
 
-RemoveResource::Result RemoveResource::operateInternal()
+RemoveResource::Result RemoveResource::operateInternal(Context ctx)
 {
   // Access the resource manager (provided by the operation manager that created
   // this operation
diff --git a/smtk/operation/operators/RemoveResource.h b/smtk/operation/operators/RemoveResource.h
index 0d068664a5a6dff543b524b2d102d180ac5dc9d7..dcb43a8b458c0c846a8dbd84aec88920d6a73323 100644
--- a/smtk/operation/operators/RemoveResource.h
+++ b/smtk/operation/operators/RemoveResource.h
@@ -37,10 +37,10 @@ protected:
 
   bool ableToOperate() override;
 
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
 
   /// Do not report success as the base class prints specific console
-  /// messages after operateInternal() completes.
+  /// messages after operateInternal(Context ctx) completes.
   void generateSummary(Result&) override {}
 
   const char* xmlDescription() const override;
diff --git a/smtk/operation/operators/SetProperty.cxx b/smtk/operation/operators/SetProperty.cxx
index 10fb15c05938010013279742d95c96e27af4e17e..ded7a246e4787943eac61b6977c0a0b8999e57b8 100644
--- a/smtk/operation/operators/SetProperty.cxx
+++ b/smtk/operation/operators/SetProperty.cxx
@@ -64,7 +64,7 @@ void SetPropertyValue(
   }
 }
 
-SetProperty::Result SetProperty::operateInternal()
+SetProperty::Result SetProperty::operateInternal(Context ctx)
 {
   smtk::attribute::StringItemPtr nameItem = this->parameters()->findString("name");
   smtk::attribute::StringItemPtr stringItem = this->parameters()->findString("string value");
diff --git a/smtk/operation/operators/SetProperty.h b/smtk/operation/operators/SetProperty.h
index ffe3ab0dad03efdd4b5bc2b88e3fc65dfbc26a00..f4f929fa5303a9226f3876c65449131d4fddd3e4 100644
--- a/smtk/operation/operators/SetProperty.h
+++ b/smtk/operation/operators/SetProperty.h
@@ -28,7 +28,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 } // namespace operation
diff --git a/smtk/operation/operators/WriteResource.cxx b/smtk/operation/operators/WriteResource.cxx
index 2d38d771903ffde1e4d6616a6743ae3bfb6bd780..d1adc51c79826cae24998087df26ddeb2e8be3c0 100644
--- a/smtk/operation/operators/WriteResource.cxx
+++ b/smtk/operation/operators/WriteResource.cxx
@@ -68,7 +68,7 @@ bool WriteResource::ableToOperate()
   return true;
 }
 
-smtk::operation::Operation::Result WriteResource::operateInternal()
+smtk::operation::Operation::Result WriteResource::operateInternal(Context ctx)
 {
   auto manager = m_manager.lock();
 
diff --git a/smtk/operation/operators/WriteResource.h b/smtk/operation/operators/WriteResource.h
index e4bacfff34991df68d003582dceca077012c191f..dcba668c8fec4548b80bd950527abd3cf765984f 100644
--- a/smtk/operation/operators/WriteResource.h
+++ b/smtk/operation/operators/WriteResource.h
@@ -30,7 +30,7 @@ public:
 protected:
   WriteResource();
 
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
 
   const char* xmlDescription() const override;
   void markModifiedResources(Result&) override;
diff --git a/smtk/operation/pybind11/PyOperation.h b/smtk/operation/pybind11/PyOperation.h
index 87d9c038f7cc9b534d343d843f58cd5a57183743..33ed2e9c7a788439c5f7cecc6e84094d9a367475 100644
--- a/smtk/operation/pybind11/PyOperation.h
+++ b/smtk/operation/pybind11/PyOperation.h
@@ -166,7 +166,7 @@ public:
     PYBIND11_OVERLOAD(smtk::io::Logger&, Operation, log, );
   }
 
-  Result operateInternal() override
+  Result operateInternal(Context ctx) override
     {
       Result result = nullptr;
       PyOperation::runOnMainThread([&]()
diff --git a/smtk/operation/pybind11/PybindObserver.h b/smtk/operation/pybind11/PybindObserver.h
index f58768114aa05a0655a22612afff536582fb38a8..615c5a4c06435cf04dbbaae8589016cae3b39634 100644
--- a/smtk/operation/pybind11/PybindObserver.h
+++ b/smtk/operation/pybind11/PybindObserver.h
@@ -32,7 +32,7 @@ inline py::class_< smtk::operation::Observers > pybind11_init_smtk_operation_Obs
   py::class_< smtk::operation::Observers > instance(m, "Observers");
   instance
     .def(py::init<>())
-    .def("__call__", [](smtk::operation::Observers& observers, smtk::operation::Operation& op, ::smtk::operation::EventType eventType, ::smtk::operation::Operation::Result result) { return observers(op, eventType, result); })
+    .def("__call__", [](smtk::operation::Observers& observers, smtk::operation::Operation& op, ::smtk::operation::EventType eventType, ::smtk::operation::Operation::Result result) { return observers(smtk::common::Context(), op, eventType, result); })
     .def("__len__", &smtk::operation::Observers::size)
     .def("erase", (std::size_t (smtk::operation::Observers::*)(smtk::operation::Observers::Key&)) &smtk::operation::Observers::erase)
     .def("insert", (smtk::operation::Observers::Key (smtk::operation::Observers::*)(smtk::operation::Observer, std::string)) &smtk::operation::Observers::insert, pybind11::keep_alive<1, 2>())
diff --git a/smtk/operation/testing/cxx/TestAsyncOperation.cxx b/smtk/operation/testing/cxx/TestAsyncOperation.cxx
index 7dec9262f4f8bf1f86467e62e241d7fd35e6db8c..a73bbbe20a20200d73a99a934074ad3d95e11ad5 100644
--- a/smtk/operation/testing/cxx/TestAsyncOperation.cxx
+++ b/smtk/operation/testing/cxx/TestAsyncOperation.cxx
@@ -39,12 +39,12 @@ public:
   MyOperation() = default;
   ~MyOperation() override = default;
 
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
 
   const char* xmlDescription() const override;
 };
 
-MyOperation::Result MyOperation::operateInternal()
+MyOperation::Result MyOperation::operateInternal(Context ctx)
 {
   int sleep = this->parameters()->findAs<smtk::attribute::IntItem>("sleep")->value();
   std::this_thread::sleep_for(std::chrono::seconds(sleep));
diff --git a/smtk/operation/testing/cxx/TestAvailableOperations.cxx b/smtk/operation/testing/cxx/TestAvailableOperations.cxx
index 0f22c63fe3d9e6df69e45d7b57669e2fac0c1bee..dc5f4865cdaf639e1a072ea81a4963a2a07bb209 100644
--- a/smtk/operation/testing/cxx/TestAvailableOperations.cxx
+++ b/smtk/operation/testing/cxx/TestAvailableOperations.cxx
@@ -122,7 +122,7 @@ public:
   OperationA() = default;
   ~OperationA() override = default;
 
-  Result operateInternal() override { return this->createResult(Outcome::SUCCEEDED); }
+  Result operateInternal(Context ctx) override { return this->createResult(Outcome::SUCCEEDED); }
 
   const char* xmlDescription() const override;
 };
@@ -175,7 +175,7 @@ public:
   OperationB() = default;
   ~OperationB() override = default;
 
-  Result operateInternal() override { return this->createResult(Outcome::SUCCEEDED); }
+  Result operateInternal(Context ctx) override { return this->createResult(Outcome::SUCCEEDED); }
 
   const char* xmlDescription() const override;
 };
diff --git a/smtk/operation/testing/cxx/TestHints.cxx b/smtk/operation/testing/cxx/TestHints.cxx
index 38ac649433896584f883b70e4c17be722d91f3c7..6ceff86ba6bbf10d009691c604b969d1c15fe7be 100644
--- a/smtk/operation/testing/cxx/TestHints.cxx
+++ b/smtk/operation/testing/cxx/TestHints.cxx
@@ -48,14 +48,14 @@ public:
   MyOperation() = default;
   ~MyOperation() override = default;
 
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
 
   void generateSummary(Result&) override {}
 
   const char* xmlDescription() const override;
 };
 
-MyOperation::Result MyOperation::operateInternal()
+MyOperation::Result MyOperation::operateInternal(Context ctx)
 {
   using namespace smtk::operation;
   // Do our "work"
diff --git a/smtk/operation/testing/cxx/TestMutexedOperation.cxx b/smtk/operation/testing/cxx/TestMutexedOperation.cxx
index 9ac56607977ab3a472006b75fe58275a0deafb1c..3e9410459fe5172966a39e498c9ea77849607a24 100644
--- a/smtk/operation/testing/cxx/TestMutexedOperation.cxx
+++ b/smtk/operation/testing/cxx/TestMutexedOperation.cxx
@@ -99,7 +99,7 @@ public:
 
   smtk::io::Logger& log() const override { return m_logger; }
 
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
 
   Specification createSpecification() override;
 
@@ -107,7 +107,7 @@ private:
   mutable smtk::io::Logger m_logger;
 };
 
-ReadOperation::Result ReadOperation::operateInternal()
+ReadOperation::Result ReadOperation::operateInternal(Context ctx)
 {
   bool semaphoreValue =
     (this->parameters()->findAs<smtk::attribute::IntItem>("semaphore")->value() != 0);
@@ -199,7 +199,7 @@ public:
 
   smtk::io::Logger& log() const override { return m_logger; }
 
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
 
   Specification createSpecification() override;
 
@@ -207,7 +207,7 @@ private:
   mutable smtk::io::Logger m_logger;
 };
 
-WriteOperation::Result WriteOperation::operateInternal()
+WriteOperation::Result WriteOperation::operateInternal(Context ctx)
 {
   if (semaphore)
   {
diff --git a/smtk/operation/testing/cxx/TestOperationGroup.cxx b/smtk/operation/testing/cxx/TestOperationGroup.cxx
index 9761041c337cc6a3ecaf43adfe8ab2dbbaf517ad..48b20fc0964ac5cff6e7aed89b9ca26eb798d429 100644
--- a/smtk/operation/testing/cxx/TestOperationGroup.cxx
+++ b/smtk/operation/testing/cxx/TestOperationGroup.cxx
@@ -41,12 +41,12 @@ public:
   OperationA() = default;
   ~OperationA() override = default;
 
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
 
   Specification createSpecification() override;
 };
 
-OperationA::Result OperationA::operateInternal()
+OperationA::Result OperationA::operateInternal(Context ctx)
 {
   return this->createResult(Outcome::SUCCEEDED);
 }
diff --git a/smtk/operation/testing/cxx/TestOperationLauncher.cxx b/smtk/operation/testing/cxx/TestOperationLauncher.cxx
index 25a9ef73497d0260fdb7688651ac06b59a52f59c..b70f6520b407dd23deb83d14b44cc3f95afa9c01 100644
--- a/smtk/operation/testing/cxx/TestOperationLauncher.cxx
+++ b/smtk/operation/testing/cxx/TestOperationLauncher.cxx
@@ -41,12 +41,12 @@ public:
   MyOperation() = default;
   ~MyOperation() override = default;
 
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
 
   const char* xmlDescription() const override;
 };
 
-MyOperation::Result MyOperation::operateInternal()
+MyOperation::Result MyOperation::operateInternal(Context ctx)
 {
   int sleep = this->parameters()->findAs<smtk::attribute::IntItem>("sleep")->value();
   std::this_thread::sleep_for(std::chrono::seconds(sleep));
diff --git a/smtk/operation/testing/cxx/TestSafeBlockingInvocation.cxx b/smtk/operation/testing/cxx/TestSafeBlockingInvocation.cxx
index 836cb305ca37747a5b598bd524597a66d3b8f7ec..353715fb4c7a9958c24548f2b68166440a128127 100644
--- a/smtk/operation/testing/cxx/TestSafeBlockingInvocation.cxx
+++ b/smtk/operation/testing/cxx/TestSafeBlockingInvocation.cxx
@@ -40,12 +40,12 @@ public:
   MyOperation() = default;
   ~MyOperation() override = default;
 
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
 
   const char* xmlDescription() const override;
 };
 
-MyOperation::Result MyOperation::operateInternal()
+MyOperation::Result MyOperation::operateInternal(Context ctx)
 {
   int sleep = this->parameters()->findAs<smtk::attribute::IntItem>("sleep")->value();
   std::this_thread::sleep_for(std::chrono::seconds(sleep));
diff --git a/smtk/operation/testing/cxx/TestThreadSafeLazyEvaluation.cxx b/smtk/operation/testing/cxx/TestThreadSafeLazyEvaluation.cxx
index 8fdebcd1f9ff20bd234f9d696b3985dfdfb3c69b..9c47fef5598a371e8e94446b56094d7cf823fa7e 100644
--- a/smtk/operation/testing/cxx/TestThreadSafeLazyEvaluation.cxx
+++ b/smtk/operation/testing/cxx/TestThreadSafeLazyEvaluation.cxx
@@ -40,12 +40,12 @@ public:
   MyOperation() = default;
   ~MyOperation() override = default;
 
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
 
   const char* xmlDescription() const override;
 };
 
-MyOperation::Result MyOperation::operateInternal()
+MyOperation::Result MyOperation::operateInternal(Context ctx)
 {
   int sleep = this->parameters()->findAs<smtk::attribute::IntItem>("sleep")->value();
   std::this_thread::sleep_for(std::chrono::seconds(sleep));
diff --git a/smtk/operation/testing/cxx/unitNamingGroup.cxx b/smtk/operation/testing/cxx/unitNamingGroup.cxx
index 0d4513b8a72c5fb6bff8ead3c62c8f68473e11a8..3d7cda9ac7d07142764182fde37e3cbf1599f798 100644
--- a/smtk/operation/testing/cxx/unitNamingGroup.cxx
+++ b/smtk/operation/testing/cxx/unitNamingGroup.cxx
@@ -107,7 +107,7 @@ public:
   SetNameOp() = default;
   ~SetNameOp() override = default;
 
-  Result operateInternal() override { return this->createResult(Outcome::SUCCEEDED); }
+  Result operateInternal(Context ctx) override { return this->createResult(Outcome::SUCCEEDED); }
 
   const char* xmlDescription() const override { return setNameOp_xml.c_str(); }
 };
@@ -153,7 +153,7 @@ public:
   NonCompliantOp() = default;
   ~NonCompliantOp() override = default;
 
-  Result operateInternal() override { return this->createResult(Outcome::SUCCEEDED); }
+  Result operateInternal(Context ctx) override { return this->createResult(Outcome::SUCCEEDED); }
 
   const char* xmlDescription() const override { return nonCompliantOp_xml.c_str(); }
 };
diff --git a/smtk/operation/testing/cxx/unitOperation.cxx b/smtk/operation/testing/cxx/unitOperation.cxx
index bcbb8d162f7f13018f9f02a09a0ffaf3bdaa834a..170d1b43e161d2c2855f4435632c855dd90354ff 100644
--- a/smtk/operation/testing/cxx/unitOperation.cxx
+++ b/smtk/operation/testing/cxx/unitOperation.cxx
@@ -42,7 +42,7 @@ public:
 
   bool ableToOperate() override { return m_outcome != Outcome::UNABLE_TO_OPERATE; }
 
-  Result operateInternal() override { return this->createResult(m_outcome); }
+  Result operateInternal(Context ctx) override { return this->createResult(m_outcome); }
 
   const char* xmlDescription() const override;
 
diff --git a/smtk/project/Manager.cxx b/smtk/project/Manager.cxx
index 10b3317c9777c7573b4fe1abd04ace82ef07343d..768f81988258981eee0997dd7b9cec8a47dff763 100644
--- a/smtk/project/Manager.cxx
+++ b/smtk/project/Manager.cxx
@@ -101,6 +101,7 @@ Manager::Manager(
 
   m_operationManagerObserver = operationManager->observers().insert(
     [this](
+    smtk::common::Context ctx,
       const smtk::operation::Operation&,
       smtk::operation::EventType event,
       smtk::operation::Operation::Result result) -> int {
diff --git a/smtk/project/operators/Add.cxx b/smtk/project/operators/Add.cxx
index 935ab0286cd48667661f36981b44108396c91ab4..d829a43970a2c100aaf544a3b0cd4e9efc4067ca 100644
--- a/smtk/project/operators/Add.cxx
+++ b/smtk/project/operators/Add.cxx
@@ -69,7 +69,7 @@ bool Add::configure(
   return true;
 }
 
-Add::Result Add::operateInternal()
+Add::Result Add::operateInternal(Context ctx)
 {
   smtk::attribute::ReferenceItem::Ptr projectItem = this->parameters()->associations();
   smtk::project::ProjectPtr project = projectItem->valueAs<smtk::project::Project>();
diff --git a/smtk/project/operators/Add.h b/smtk/project/operators/Add.h
index a9c58227951b6ea73a2c392d1f0a2c9932f5174c..f5a3f48a4b47e23ddc6c2154c79a5e23b34a4f12 100644
--- a/smtk/project/operators/Add.h
+++ b/smtk/project/operators/Add.h
@@ -34,7 +34,7 @@ public:
   bool configure(const smtk::attribute::AttributePtr&, const smtk::attribute::ItemPtr&) override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 } // namespace project
diff --git a/smtk/project/operators/Create.cxx b/smtk/project/operators/Create.cxx
index ad8422adc819bee413eca25d1d539be4ecd6e6f9..b54caef7ee304eb904c2f7d6ddf60a0278ac185a 100644
--- a/smtk/project/operators/Create.cxx
+++ b/smtk/project/operators/Create.cxx
@@ -74,7 +74,7 @@ namespace smtk
 namespace project
 {
 
-Create::Result Create::operateInternal()
+Create::Result Create::operateInternal(Context ctx)
 {
   std::string typeName;
   {
diff --git a/smtk/project/operators/Create.h b/smtk/project/operators/Create.h
index b1101c86c9a7acba0b326bb6b5f73519a328085c..9214a351f01dc149e935d0c87507b948b1c116ff 100644
--- a/smtk/project/operators/Create.h
+++ b/smtk/project/operators/Create.h
@@ -31,7 +31,7 @@ public:
   smtkSharedFromThisMacro(smtk::operation::Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   Specification createSpecification() override;
   const char* xmlDescription() const override;
 };
diff --git a/smtk/project/operators/Define.cxx b/smtk/project/operators/Define.cxx
index aa12b794973a724d7a5fbd72c6c0ccdd21292627..6ce4dc6c8364158dd8d3fabd5ca8c324f9f8681c 100644
--- a/smtk/project/operators/Define.cxx
+++ b/smtk/project/operators/Define.cxx
@@ -87,7 +87,7 @@ namespace smtk
 namespace project
 {
 
-Define::Result Define::operateInternal()
+Define::Result Define::operateInternal(Context ctx)
 {
   std::string name;
   {
diff --git a/smtk/project/operators/Define.h b/smtk/project/operators/Define.h
index b679ba5de89a198173b4cec443dafb2171cac222..0c4180f1006cc2f8273cce253f22ac768b6454d1 100644
--- a/smtk/project/operators/Define.h
+++ b/smtk/project/operators/Define.h
@@ -32,7 +32,7 @@ public:
   smtkSharedFromThisMacro(smtk::operation::Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   Specification createSpecification() override;
   const char* xmlDescription() const override;
 };
diff --git a/smtk/project/operators/Print.cxx b/smtk/project/operators/Print.cxx
index 3c69788fc85fb12add84811e895c2ca12bd007c1..ed63fd9c757a789bdd1e6a33100a55ac9f523562 100644
--- a/smtk/project/operators/Print.cxx
+++ b/smtk/project/operators/Print.cxx
@@ -25,7 +25,7 @@ namespace smtk
 namespace project
 {
 
-Print::Result Print::operateInternal()
+Print::Result Print::operateInternal(Context ctx)
 {
   // Access the project to write.
   smtk::attribute::ReferenceItem::Ptr projectItem = this->parameters()->associations();
diff --git a/smtk/project/operators/Print.h b/smtk/project/operators/Print.h
index 2a282407cdf05059b162a60edce026bebbe4d586..2ce6bfd6ccb9f5f4705c3f04687969e66ff28c3e 100644
--- a/smtk/project/operators/Print.h
+++ b/smtk/project/operators/Print.h
@@ -30,7 +30,7 @@ public:
   smtkSharedFromThisMacro(smtk::operation::Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 } // namespace project
diff --git a/smtk/project/operators/Read.cxx b/smtk/project/operators/Read.cxx
index 0e66cc313654de2145a80ed63f40a463a8781714..f1ddbf89cdc1668366c5dea305232e0ad80c166f 100644
--- a/smtk/project/operators/Read.cxx
+++ b/smtk/project/operators/Read.cxx
@@ -71,7 +71,7 @@ void Read::markModifiedResources(Read::Result& result)
   }
 }
 
-Read::Result Read::operateInternal()
+Read::Result Read::operateInternal(Context ctx)
 {
   std::string filename = this->parameters()->findFile("filename")->value();
 
diff --git a/smtk/project/operators/Read.h b/smtk/project/operators/Read.h
index 830b9b0cf0e5717b75e26ce83c636588892d5483..49bc9ab219d20e621caf258f9e52dc2f7f7bdd89 100644
--- a/smtk/project/operators/Read.h
+++ b/smtk/project/operators/Read.h
@@ -32,7 +32,7 @@ public:
 
 protected:
   void markModifiedResources(Result&) override;
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/project/operators/Remove.cxx b/smtk/project/operators/Remove.cxx
index 6e0cec99bd7ffa519a3f375ae3e496c6814c90e9..8ad136a547d277d6ff5291e299466693ed84b13f 100644
--- a/smtk/project/operators/Remove.cxx
+++ b/smtk/project/operators/Remove.cxx
@@ -33,7 +33,7 @@ namespace smtk
 namespace project
 {
 
-Remove::Result Remove::operateInternal()
+Remove::Result Remove::operateInternal(Context ctx)
 {
   smtk::attribute::ReferenceItem::Ptr projectItem = this->parameters()->associations();
   smtk::project::ProjectPtr project = projectItem->valueAs<smtk::project::Project>();
diff --git a/smtk/project/operators/Remove.h b/smtk/project/operators/Remove.h
index b06edd7ed64173b9e7284bc6f6dc7f360b5ae361..cb658f82d9130716e88bf86a9c4b8acc88480460 100644
--- a/smtk/project/operators/Remove.h
+++ b/smtk/project/operators/Remove.h
@@ -28,7 +28,7 @@ public:
   smtkSharedFromThisMacro(smtk::operation::Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 } // namespace project
diff --git a/smtk/project/operators/Write.cxx b/smtk/project/operators/Write.cxx
index 960e67a5c83b43c8fd81e979f1e585bd3924864f..7f4eabb13d85e2e4ba2257666ba3806f7e1e998b 100644
--- a/smtk/project/operators/Write.cxx
+++ b/smtk/project/operators/Write.cxx
@@ -49,7 +49,7 @@ namespace smtk
 namespace project
 {
 
-Write::Result Write::operateInternal()
+Write::Result Write::operateInternal(Context ctx)
 {
   // Access the project to write.
   smtk::attribute::ReferenceItem::Ptr projectItem = this->parameters()->associations();
diff --git a/smtk/project/operators/Write.h b/smtk/project/operators/Write.h
index 5a5c85f51f885db648cf64d7d26735237217cb89..0f36880d24b0aa5301109457f59e9a3d6d108762 100644
--- a/smtk/project/operators/Write.h
+++ b/smtk/project/operators/Write.h
@@ -33,7 +33,7 @@ public:
   smtkSharedFromThisMacro(smtk::operation::Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/project/testing/cxx/TestProjectLifeCycle.cxx b/smtk/project/testing/cxx/TestProjectLifeCycle.cxx
index 9376096fad7e0da07df3aec7964195dccf81fda9..7f6b5b128263de3e77d9728b6f4af7470646990f 100644
--- a/smtk/project/testing/cxx/TestProjectLifeCycle.cxx
+++ b/smtk/project/testing/cxx/TestProjectLifeCycle.cxx
@@ -60,7 +60,7 @@ public:
     return smtk::operation::XMLOperation::ableToOperate();
   }
 
-  Result operateInternal() override
+  Result operateInternal(Context ctx) override
   {
     auto project = m_projManager->create(PROJECT_TYPE);
     if (this->managers())
diff --git a/smtk/resource/GarbageCollector.cxx b/smtk/resource/GarbageCollector.cxx
index 3f40042e48290c23256f85e6bde9a3f0e98243f9..ebb4ab81aa5e192b2784eca2fdacfa9660336bb3 100644
--- a/smtk/resource/GarbageCollector.cxx
+++ b/smtk/resource/GarbageCollector.cxx
@@ -71,6 +71,7 @@ bool GarbageCollector::add(const smtk::operation::OperationPtr& deleter)
   {
     Key key = manager->observers().insert(
       [this](
+      smtk::common::Context ctx,
         const smtk::operation::Operation& op,
         smtk::operation::EventType event,
         smtk::operation::Operation::Result result) -> int {
diff --git a/smtk/resource/testing/cxx/TestGarbageCollector.cxx b/smtk/resource/testing/cxx/TestGarbageCollector.cxx
index 4859d24152a9b69f110ed9341f3175e7936cebb5..e38a351ef6c9b380dfc0b512938d6a2ea9b49e48 100644
--- a/smtk/resource/testing/cxx/TestGarbageCollector.cxx
+++ b/smtk/resource/testing/cxx/TestGarbageCollector.cxx
@@ -127,7 +127,7 @@ public:
 protected:
   DeleterA() = default;
 
-  Result operateInternal() override
+  Result operateInternal(Context ctx) override
   {
     bool ok = true;
     auto associations = this->parameters()->associations();
@@ -214,12 +214,12 @@ public:
   TestOperation() = default;
   ~TestOperation() override = default;
 
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
 
   const char* xmlDescription() const override;
 };
 
-TestOperation::Result TestOperation::operateInternal()
+TestOperation::Result TestOperation::operateInternal(Context ctx)
 {
   auto assoc = this->parameters()->associations();
   if (!assoc->isSet(0))
diff --git a/smtk/session/mesh/operators/CreateUniformGrid.cxx b/smtk/session/mesh/operators/CreateUniformGrid.cxx
index 6f7cfb3b7f93188f1e2cf4fc42e0f1d13fae72da..3028264c60f3f57888d45cc671b67a517df27256 100644
--- a/smtk/session/mesh/operators/CreateUniformGrid.cxx
+++ b/smtk/session/mesh/operators/CreateUniformGrid.cxx
@@ -34,7 +34,7 @@ namespace session
 namespace mesh
 {
 
-CreateUniformGrid::Result CreateUniformGrid::operateInternal()
+CreateUniformGrid::Result CreateUniformGrid::operateInternal(Context ctx)
 {
   // Access the string describing the dimension. The dimension is a string so we
   // can use optional children to assign the lengths of the other parameters.
diff --git a/smtk/session/mesh/operators/CreateUniformGrid.h b/smtk/session/mesh/operators/CreateUniformGrid.h
index c3c9bd00db55f0bc7cc03e5ee05eec3069fbb9ec..c4bbac856b1d48ff3f9de3a878b719208d9ca485 100644
--- a/smtk/session/mesh/operators/CreateUniformGrid.h
+++ b/smtk/session/mesh/operators/CreateUniformGrid.h
@@ -31,7 +31,7 @@ public:
   smtkSharedFromThisMacro(smtk::operation::Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 } // namespace mesh
diff --git a/smtk/session/mesh/operators/EulerCharacteristicRatio.cxx b/smtk/session/mesh/operators/EulerCharacteristicRatio.cxx
index 0683c6e9b8c8ab07fcaa0adb1ab419f44898bb22..0b387fb2f7e47ca7ba5920717eb2de4a4d9cf77a 100644
--- a/smtk/session/mesh/operators/EulerCharacteristicRatio.cxx
+++ b/smtk/session/mesh/operators/EulerCharacteristicRatio.cxx
@@ -34,7 +34,7 @@ namespace session
 namespace mesh
 {
 
-EulerCharacteristicRatio::Result EulerCharacteristicRatio::operateInternal()
+EulerCharacteristicRatio::Result EulerCharacteristicRatio::operateInternal(Context ctx)
 {
   // Access the associated model.
   smtk::model::Model model = this->parameters()->associatedModelEntities<smtk::model::Models>()[0];
diff --git a/smtk/session/mesh/operators/EulerCharacteristicRatio.h b/smtk/session/mesh/operators/EulerCharacteristicRatio.h
index ba2885e5d2ec39fcf04cc43fb461ea6f87003525..4641efdcf288ae5cd9cc92294d8c0e45263b96eb 100644
--- a/smtk/session/mesh/operators/EulerCharacteristicRatio.h
+++ b/smtk/session/mesh/operators/EulerCharacteristicRatio.h
@@ -32,7 +32,7 @@ public:
   smtkSharedFromThisMacro(smtk::operation::Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/session/mesh/operators/Export.cxx b/smtk/session/mesh/operators/Export.cxx
index 5ee15ec3af62b749ebe2019ba8f2a9b4703e1863..ee32391b1d0378ff5101dc7fd31b96994a1d03b1 100644
--- a/smtk/session/mesh/operators/Export.cxx
+++ b/smtk/session/mesh/operators/Export.cxx
@@ -47,7 +47,7 @@ void breakMaterialsByAssociation(const smtk::mesh::ResourcePtr& c)
   }
 }
 
-smtk::session::mesh::Export::Result Export::operateInternal()
+smtk::session::mesh::Export::Result Export::operateInternal(Context ctx)
 {
   smtk::attribute::FileItem::Ptr filePathItem = this->parameters()->findFile("filename");
 
diff --git a/smtk/session/mesh/operators/Export.h b/smtk/session/mesh/operators/Export.h
index 43b92a0bf280599198c4ae0e5f4c49d1cf1db793..342eb9391360e243181cf5742495b16903a9f25a 100644
--- a/smtk/session/mesh/operators/Export.h
+++ b/smtk/session/mesh/operators/Export.h
@@ -29,7 +29,7 @@ public:
   smtkSharedFromThisMacro(smtk::operation::Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/session/mesh/operators/Import.cxx b/smtk/session/mesh/operators/Import.cxx
index 9088e160798f27b5fdfbfe4df20f2821485de747..3f48bd43fcc35dd0fc5b322f72bc786923880241 100644
--- a/smtk/session/mesh/operators/Import.cxx
+++ b/smtk/session/mesh/operators/Import.cxx
@@ -49,7 +49,7 @@ namespace session
 namespace mesh
 {
 
-Import::Result Import::operateInternal()
+Import::Result Import::operateInternal(Context ctx)
 {
   // Get the read file name
   smtk::attribute::FileItem::Ptr filePathItem = this->parameters()->findFile("filename");
diff --git a/smtk/session/mesh/operators/Import.h b/smtk/session/mesh/operators/Import.h
index e3fc261a0d2ea65dd5d792f4f89461525cd86e71..5d48d0764ca6936054069ea4232f238a6c8181e6 100644
--- a/smtk/session/mesh/operators/Import.h
+++ b/smtk/session/mesh/operators/Import.h
@@ -32,7 +32,7 @@ public:
   smtkSharedFromThisMacro(smtk::operation::Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   Specification createSpecification() override;
   const char* xmlDescription() const override;
 
diff --git a/smtk/session/mesh/operators/Merge.cxx b/smtk/session/mesh/operators/Merge.cxx
index f22e89639dd6b2e7b2961f683a915213b8492608..fafeecb0175a07bafe31aa44931003efdd9b88bd 100644
--- a/smtk/session/mesh/operators/Merge.cxx
+++ b/smtk/session/mesh/operators/Merge.cxx
@@ -91,7 +91,7 @@ bool Merge::ableToOperate()
   return true;
 }
 
-Merge::Result Merge::operateInternal()
+Merge::Result Merge::operateInternal(Context ctx)
 {
   // Access the associated model entities
   auto associations = this->parameters()->associations();
diff --git a/smtk/session/mesh/operators/Merge.h b/smtk/session/mesh/operators/Merge.h
index 9db0238eca145ae7c22560b8b414ddf1b8c27130..ac9e9dd9970a6eb84959186be24029f45d00c227 100644
--- a/smtk/session/mesh/operators/Merge.h
+++ b/smtk/session/mesh/operators/Merge.h
@@ -34,7 +34,7 @@ public:
   bool ableToOperate() override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 } // namespace mesh
diff --git a/smtk/session/mesh/operators/Print.cxx b/smtk/session/mesh/operators/Print.cxx
index 4e844b59cfa050947b5f142a53cf6a45d68c69b4..f58503678cdb80adb88a4ef623adb28203952d89 100644
--- a/smtk/session/mesh/operators/Print.cxx
+++ b/smtk/session/mesh/operators/Print.cxx
@@ -37,7 +37,7 @@ namespace session
 namespace mesh
 {
 
-Print::Result Print::operateInternal()
+Print::Result Print::operateInternal(Context ctx)
 {
   // Access the associated model entities
   auto associations = this->parameters()->associations();
diff --git a/smtk/session/mesh/operators/Print.h b/smtk/session/mesh/operators/Print.h
index 327107f63402c60030de906c7b7672c53b8ae858..133c6157cb79ad291f3c2cb9f7f6c3dc13fc76be 100644
--- a/smtk/session/mesh/operators/Print.h
+++ b/smtk/session/mesh/operators/Print.h
@@ -31,7 +31,7 @@ public:
   smtkSharedFromThisMacro(smtk::operation::Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 } // namespace mesh
diff --git a/smtk/session/mesh/operators/Read.cxx b/smtk/session/mesh/operators/Read.cxx
index bd41d7d9eb1be0ca774f478e4f8dcc9a858772dc..dbe2f77c5eee7da521faaea491640d2ae6d2d274 100644
--- a/smtk/session/mesh/operators/Read.cxx
+++ b/smtk/session/mesh/operators/Read.cxx
@@ -40,7 +40,7 @@ namespace session
 namespace mesh
 {
 
-Read::Result Read::operateInternal()
+Read::Result Read::operateInternal(Context ctx)
 {
   std::string filename = this->parameters()->findFile("filename")->value();
 
diff --git a/smtk/session/mesh/operators/Read.h b/smtk/session/mesh/operators/Read.h
index 13ae63439119c8d910ac37099c3da8d0d04e185e..2931b6be4bc521ba5fd0e0bcd95395e4765ed750 100644
--- a/smtk/session/mesh/operators/Read.h
+++ b/smtk/session/mesh/operators/Read.h
@@ -40,7 +40,7 @@ public:
   smtkSharedFromThisMacro(smtk::operation::Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
   void markModifiedResources(Result&) override;
 };
diff --git a/smtk/session/mesh/operators/Transform.cxx b/smtk/session/mesh/operators/Transform.cxx
index 1efca253a237acb476637e6827cff1cdd4113f6f..19989942148aaf9bfad1b44fec6c2d568a6773b5 100644
--- a/smtk/session/mesh/operators/Transform.cxx
+++ b/smtk/session/mesh/operators/Transform.cxx
@@ -37,7 +37,7 @@ namespace session
 namespace mesh
 {
 
-Transform::Result Transform::operateInternal()
+Transform::Result Transform::operateInternal(Context ctx)
 {
   // Access the associated model.
   smtk::model::Model model = this->parameters()->associatedModelEntities<smtk::model::Models>()[0];
diff --git a/smtk/session/mesh/operators/Transform.h b/smtk/session/mesh/operators/Transform.h
index bfc2684bacc530db8bd09110faa7751deeec8f87..879ef3bcdcd9abc5d18ae8563661e0ee8f11d566 100644
--- a/smtk/session/mesh/operators/Transform.h
+++ b/smtk/session/mesh/operators/Transform.h
@@ -31,7 +31,7 @@ public:
   smtkSharedFromThisMacro(smtk::operation::Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 } // namespace mesh
diff --git a/smtk/session/mesh/operators/Write.cxx b/smtk/session/mesh/operators/Write.cxx
index a13d2d30741f1c39c9e29d63042b7f2e666873bb..7b731d9c118074dad7c6e17588317b48519b1701 100644
--- a/smtk/session/mesh/operators/Write.cxx
+++ b/smtk/session/mesh/operators/Write.cxx
@@ -61,7 +61,7 @@ bool Write::ableToOperate()
   return true;
 }
 
-Write::Result Write::operateInternal()
+Write::Result Write::operateInternal(Context ctx)
 {
   auto resourceItem = this->parameters()->associations();
 
diff --git a/smtk/session/mesh/operators/Write.h b/smtk/session/mesh/operators/Write.h
index cc255ccb527024bdb83469e221227271742b6de4..88e5e782b3e890659da06938e639d5c380a6c1ff 100644
--- a/smtk/session/mesh/operators/Write.h
+++ b/smtk/session/mesh/operators/Write.h
@@ -34,7 +34,7 @@ public:
   bool ableToOperate() override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
   void markModifiedResources(Result&) override;
 };
diff --git a/smtk/session/oscillator/operators/CreateModel.cxx b/smtk/session/oscillator/operators/CreateModel.cxx
index 627889c7cc1acdce7edf12ab93fca921d3ea5632..b87e9c342cee46cec5afbcc7c2566829634af8ca 100644
--- a/smtk/session/oscillator/operators/CreateModel.cxx
+++ b/smtk/session/oscillator/operators/CreateModel.cxx
@@ -34,7 +34,7 @@ namespace session
 namespace oscillator
 {
 
-CreateModel::Result CreateModel::operateInternal()
+CreateModel::Result CreateModel::operateInternal(Context ctx)
 {
   Result result;
 
diff --git a/smtk/session/oscillator/operators/CreateModel.h b/smtk/session/oscillator/operators/CreateModel.h
index 71f4b0949ad507eb976501b55d719b1150645f41..25011deb29e9237109d41452758f02447fb23416 100644
--- a/smtk/session/oscillator/operators/CreateModel.h
+++ b/smtk/session/oscillator/operators/CreateModel.h
@@ -43,7 +43,7 @@ public:
   smtkSharedFromThisMacro(smtk::operation::Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/session/oscillator/operators/EditDomain.cxx b/smtk/session/oscillator/operators/EditDomain.cxx
index ec01fa6994a7eb8910c96a1953b114542474fbdd..fdee2d4ae5072f7becd6ef33bed0648dbcc0631f 100644
--- a/smtk/session/oscillator/operators/EditDomain.cxx
+++ b/smtk/session/oscillator/operators/EditDomain.cxx
@@ -41,7 +41,7 @@ namespace session
 namespace oscillator
 {
 
-EditDomain::Result EditDomain::operateInternal()
+EditDomain::Result EditDomain::operateInternal(Context ctx)
 {
   // Access the string describing the dimension. The dimension is a string so we
   // can use optional children to assign the lengths of the other parameters.
diff --git a/smtk/session/oscillator/operators/EditDomain.h b/smtk/session/oscillator/operators/EditDomain.h
index 1d892c23df562f70c999ad006072b7ddc8e526cf..4cc77cae9c2790982eaecf649d98524264d2892d 100644
--- a/smtk/session/oscillator/operators/EditDomain.h
+++ b/smtk/session/oscillator/operators/EditDomain.h
@@ -32,7 +32,7 @@ public:
   smtkSharedFromThisMacro(smtk::operation::Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 } // namespace oscillator
diff --git a/smtk/session/oscillator/operators/EditSource.cxx b/smtk/session/oscillator/operators/EditSource.cxx
index 5b4f69e29c66e9183ecc34069992618bd7c76d65..f8a09cc2f8e4b9522ee2cb759229b69ac373fd23 100644
--- a/smtk/session/oscillator/operators/EditSource.cxx
+++ b/smtk/session/oscillator/operators/EditSource.cxx
@@ -103,7 +103,7 @@ bool EditSource::configure(
   return true;
 }
 
-EditSource::Result EditSource::operateInternal()
+EditSource::Result EditSource::operateInternal(Context ctx)
 {
   // Access the origin, size and discretization parameters
   smtk::attribute::DoubleItemPtr centerItem =
diff --git a/smtk/session/oscillator/operators/EditSource.h b/smtk/session/oscillator/operators/EditSource.h
index e931b4c17eabd1df85f47feaf3242563aa14293e..b753c6b4ae0492030f4cb00da5b9eb5245273acc 100644
--- a/smtk/session/oscillator/operators/EditSource.h
+++ b/smtk/session/oscillator/operators/EditSource.h
@@ -42,7 +42,7 @@ public:
     const smtk::attribute::ItemPtr& changedItem) override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 
   void assignName(smtk::model::Model& model, smtk::model::AuxiliaryGeometry& source);
diff --git a/smtk/session/oscillator/operators/Export.cxx b/smtk/session/oscillator/operators/Export.cxx
index 92b1a405d1b630b2dc46d9a6ba807864632e79b9..4eeeec5c97040f692f6312ac034207a125ba31b3 100644
--- a/smtk/session/oscillator/operators/Export.cxx
+++ b/smtk/session/oscillator/operators/Export.cxx
@@ -46,7 +46,7 @@ namespace session
 namespace oscillator
 {
 
-Export::Result Export::operateInternal()
+Export::Result Export::operateInternal(Context ctx)
 {
   smtk::attribute::FileItem::Ptr filenameItem = this->parameters()->findFile("filename");
   std::string filename = filenameItem->value();
diff --git a/smtk/session/oscillator/operators/Export.h b/smtk/session/oscillator/operators/Export.h
index b460f2f2062cc58ca6d071fe7a3cd5249940a99c..448c86bdf841c41bc0d337f2f9342fd8bd4c3954 100644
--- a/smtk/session/oscillator/operators/Export.h
+++ b/smtk/session/oscillator/operators/Export.h
@@ -32,7 +32,7 @@ public:
   smtkSharedFromThisMacro(smtk::operation::Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/session/oscillator/operators/Read.cxx b/smtk/session/oscillator/operators/Read.cxx
index d791112792d7010e87483987fde74a3036ef4a9e..1e78809427943efc3fd326e97aaba87b18405c93 100644
--- a/smtk/session/oscillator/operators/Read.cxx
+++ b/smtk/session/oscillator/operators/Read.cxx
@@ -40,7 +40,7 @@ namespace session
 namespace oscillator
 {
 
-Read::Result Read::operateInternal()
+Read::Result Read::operateInternal(Context ctx)
 {
   std::string filename = this->parameters()->findFile("filename")->value();
 
diff --git a/smtk/session/oscillator/operators/Read.h b/smtk/session/oscillator/operators/Read.h
index 6d0dd23e98c52bc0c01edb94ce1f3da1cda80bdf..2f4b96109b90a50655c5a03fdad3fa8157a38170 100644
--- a/smtk/session/oscillator/operators/Read.h
+++ b/smtk/session/oscillator/operators/Read.h
@@ -32,7 +32,7 @@ public:
   smtkSuperclassMacro(smtk::operation::XMLOperation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
   void markModifiedResources(Result&) override;
 };
diff --git a/smtk/session/oscillator/operators/Write.cxx b/smtk/session/oscillator/operators/Write.cxx
index 1dc5b2e3b166fce16b31835c50be191ccedb34f0..561ad92ae0603c1e8449d36aeb2dfa4078f72229 100644
--- a/smtk/session/oscillator/operators/Write.cxx
+++ b/smtk/session/oscillator/operators/Write.cxx
@@ -49,7 +49,7 @@ bool Write::ableToOperate()
   return true;
 }
 
-Write::Result Write::operateInternal()
+Write::Result Write::operateInternal(Context ctx)
 {
   auto resourceItem = this->parameters()->associations();
 
diff --git a/smtk/session/oscillator/operators/Write.h b/smtk/session/oscillator/operators/Write.h
index 5301439fab61bb3695a0376fac819e8eae4056c2..3b92ca67ec232e92e627142cb0235038224a8003 100644
--- a/smtk/session/oscillator/operators/Write.h
+++ b/smtk/session/oscillator/operators/Write.h
@@ -35,7 +35,7 @@ public:
   bool ableToOperate() override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
   void markModifiedResources(Result&) override;
 };
diff --git a/smtk/session/polygon/operators/CleanGeometry.cxx b/smtk/session/polygon/operators/CleanGeometry.cxx
index 03843247e5b83cbbd7465ca3e755ff0e931b1933..381827f5ded0bd618bd394bbf4ff2577f6e8836c 100644
--- a/smtk/session/polygon/operators/CleanGeometry.cxx
+++ b/smtk/session/polygon/operators/CleanGeometry.cxx
@@ -654,7 +654,7 @@ bool CleanGeometry::deleteIfDuplicates(T& edgePair, U& modified, U& expunged)
   *              + This must fix any vertex uses/vertices referred to by edges,
   *                delete old vertices, and mark edges/uses modified.
   */
-CleanGeometry::Result CleanGeometry::operateInternal()
+CleanGeometry::Result CleanGeometry::operateInternal(Context ctx)
 {
   auto cleanItems = this->parameters()->associations();
   auto inputs = cleanItems->as<smtk::model::CellSet>([](smtk::resource::PersistentObjectPtr obj) {
diff --git a/smtk/session/polygon/operators/CleanGeometry.h b/smtk/session/polygon/operators/CleanGeometry.h
index 1c21336a2413214a4604bcafcc419ad609a8b64c..b28101eb22d6bb83357d01377f83a172d043db0f 100644
--- a/smtk/session/polygon/operators/CleanGeometry.h
+++ b/smtk/session/polygon/operators/CleanGeometry.h
@@ -32,7 +32,7 @@ public:
   smtkSuperclassMacro(Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 
   template<typename T, typename U, typename V, typename W, typename X>
diff --git a/smtk/session/polygon/operators/CreateEdge.cxx b/smtk/session/polygon/operators/CreateEdge.cxx
index 7642450046963add01737f65249b7c5236196fec..ec146b98c07c892877c35440d4ae0a41568f2e2d 100644
--- a/smtk/session/polygon/operators/CreateEdge.cxx
+++ b/smtk/session/polygon/operators/CreateEdge.cxx
@@ -55,7 +55,7 @@ void printSegment(internal::pmodel::Ptr storage, const std::string& msg, T& seg)
 }
 */
 
-CreateEdge::Result CreateEdge::operateInternal()
+CreateEdge::Result CreateEdge::operateInternal(Context ctx)
 {
   // Discover how the user wants to specify scaling.
   smtk::attribute::IntItem::Ptr constructionMethodItem =
diff --git a/smtk/session/polygon/operators/CreateEdge.h b/smtk/session/polygon/operators/CreateEdge.h
index ab43b39450e5109e0f547b0169afaadd356eabc7..9d0bc65779c0edd7ae339df416c4e3acb9907ac4 100644
--- a/smtk/session/polygon/operators/CreateEdge.h
+++ b/smtk/session/polygon/operators/CreateEdge.h
@@ -32,7 +32,7 @@ public:
   smtkSuperclassMacro(Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/session/polygon/operators/CreateEdgeFromPoints.cxx b/smtk/session/polygon/operators/CreateEdgeFromPoints.cxx
index 9dc57a41fd9eff4503c30da8c7c5bafbdccdfed0..0d0840a9d2e7d19583426b8a9804341ed21cef81 100644
--- a/smtk/session/polygon/operators/CreateEdgeFromPoints.cxx
+++ b/smtk/session/polygon/operators/CreateEdgeFromPoints.cxx
@@ -40,7 +40,7 @@ namespace polygon
 
 typedef std::vector<std::pair<size_t, internal::Segment>> SegmentSplitsT;
 
-CreateEdgeFromPoints::Result CreateEdgeFromPoints::operateInternal()
+CreateEdgeFromPoints::Result CreateEdgeFromPoints::operateInternal(Context ctx)
 {
   auto modelItem = this->parameters()->associations();
 
diff --git a/smtk/session/polygon/operators/CreateEdgeFromPoints.h b/smtk/session/polygon/operators/CreateEdgeFromPoints.h
index e15ff3677a5daa73a60d1e3c4dd859b8bf4c89e5..b260183c730ffbef2e0c4b3487ec4a7fb5d94839 100644
--- a/smtk/session/polygon/operators/CreateEdgeFromPoints.h
+++ b/smtk/session/polygon/operators/CreateEdgeFromPoints.h
@@ -39,7 +39,7 @@ public:
   Result process(std::vector<double>& pnts, int numCoordsPerPoint, smtk::model::Model& parentModel);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/session/polygon/operators/CreateEdgeFromVertices.cxx b/smtk/session/polygon/operators/CreateEdgeFromVertices.cxx
index a50b0a1cf34e1528dd4b6d7ef96f56f53277885f..6aa83f7359628cf6a92eb5a65992d5fa6aeea168 100644
--- a/smtk/session/polygon/operators/CreateEdgeFromVertices.cxx
+++ b/smtk/session/polygon/operators/CreateEdgeFromVertices.cxx
@@ -36,7 +36,7 @@ namespace polygon
 
 typedef std::vector<std::pair<size_t, internal::Segment>> SegmentSplitsT;
 
-CreateEdgeFromVertices::Result CreateEdgeFromVertices::operateInternal()
+CreateEdgeFromVertices::Result CreateEdgeFromVertices::operateInternal(Context ctx)
 {
   auto modelItem = this->parameters()->associations();
   auto ment = modelItem->valueAs<smtk::model::Entity>();
diff --git a/smtk/session/polygon/operators/CreateEdgeFromVertices.h b/smtk/session/polygon/operators/CreateEdgeFromVertices.h
index 31e65bdc1861dc84d9eca3ca09b3995aa036eb8d..f1f8c66c57ddf4e909fa371d5e9586b08a373488 100644
--- a/smtk/session/polygon/operators/CreateEdgeFromVertices.h
+++ b/smtk/session/polygon/operators/CreateEdgeFromVertices.h
@@ -32,7 +32,7 @@ public:
   smtkSuperclassMacro(Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/session/polygon/operators/CreateFaces.cxx b/smtk/session/polygon/operators/CreateFaces.cxx
index 54de7d9b0cb5ce646baf3e6469449c00c76d51cb..d4c725ba468cc6da88545cc7bc85e73adbf43c98 100644
--- a/smtk/session/polygon/operators/CreateFaces.cxx
+++ b/smtk/session/polygon/operators/CreateFaces.cxx
@@ -138,7 +138,7 @@ bool CreateFaces::populateEdgeMap()
   return true;
 }
 
-CreateFaces::Result CreateFaces::operateInternal()
+CreateFaces::Result CreateFaces::operateInternal(Context ctx)
 {
   auto modelItem = this->parameters()->associations();
   smtk::model::Model model = modelItem->valueAs<smtk::model::Entity>();
diff --git a/smtk/session/polygon/operators/CreateFaces.h b/smtk/session/polygon/operators/CreateFaces.h
index b91aff8c5aa23c7becfdc59b1c13e4f631e5a5be..342e79b57e17e03d245c572f0ea62ec7d9e60477 100644
--- a/smtk/session/polygon/operators/CreateFaces.h
+++ b/smtk/session/polygon/operators/CreateFaces.h
@@ -73,7 +73,7 @@ protected:
   friend class Neighborhood;
 
   virtual bool populateEdgeMap();
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 
   void evaluateLoop(RegionId faceNumber, OrientedEdges& loop, std::set<RegionId>& borders);
diff --git a/smtk/session/polygon/operators/CreateModel.cxx b/smtk/session/polygon/operators/CreateModel.cxx
index 5fae02e4bddde7fd856a0ee07dcb17ca78ee4cc2..ec24b8cd20f678b5a3cb662f302a639e3f23e62e 100644
--- a/smtk/session/polygon/operators/CreateModel.cxx
+++ b/smtk/session/polygon/operators/CreateModel.cxx
@@ -31,7 +31,7 @@ namespace session
 namespace polygon
 {
 
-CreateModel::Result CreateModel::operateInternal()
+CreateModel::Result CreateModel::operateInternal(Context ctx)
 {
   // Discover how the user wants to specify scaling.
   smtk::attribute::IntItem::Ptr constructionMethodItem =
diff --git a/smtk/session/polygon/operators/CreateModel.h b/smtk/session/polygon/operators/CreateModel.h
index 28273306cb2f0b58cbf6dca041c7992f2d08a57e..483461fc463111a960b74162d102ccd88a4b2ad1 100644
--- a/smtk/session/polygon/operators/CreateModel.h
+++ b/smtk/session/polygon/operators/CreateModel.h
@@ -42,7 +42,7 @@ public:
   smtkSuperclassMacro(Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/session/polygon/operators/CreateVertices.cxx b/smtk/session/polygon/operators/CreateVertices.cxx
index bf86f79b8f1fd564b60c2188b87dc6398f2947b5..944019368f39eec5b113b11b4c07f692b5188029 100644
--- a/smtk/session/polygon/operators/CreateVertices.cxx
+++ b/smtk/session/polygon/operators/CreateVertices.cxx
@@ -34,7 +34,7 @@ namespace session
 namespace polygon
 {
 
-CreateVertices::Result CreateVertices::operateInternal()
+CreateVertices::Result CreateVertices::operateInternal(Context ctx)
 {
   smtk::attribute::GroupItem::Ptr pointsInfo;
   smtk::attribute::IntItem::Ptr coordinatesItem = this->parameters()->findInt("point dimension");
diff --git a/smtk/session/polygon/operators/CreateVertices.h b/smtk/session/polygon/operators/CreateVertices.h
index cac38896e02441b594d8ebc1000d43ad915cf2bc..e99ef77420775008a1404ad48831c1f4f68c72f1 100644
--- a/smtk/session/polygon/operators/CreateVertices.h
+++ b/smtk/session/polygon/operators/CreateVertices.h
@@ -31,7 +31,7 @@ public:
   smtkSuperclassMacro(Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/session/polygon/operators/Delete.cxx b/smtk/session/polygon/operators/Delete.cxx
index b0bed98ad3415d13e4492d4d8b9e7649680f757a..d5520d76435195539dee6a0a1134e5824567d006 100644
--- a/smtk/session/polygon/operators/Delete.cxx
+++ b/smtk/session/polygon/operators/Delete.cxx
@@ -311,7 +311,7 @@ void Delete::addBoundaryCells(
   }
 }
 
-Delete::Result Delete::operateInternal()
+Delete::Result Delete::operateInternal(Context ctx)
 {
   smtk::attribute::VoidItem::Ptr deleteHigherDimen =
     this->parameters()->findVoid("delete higher-dimensional neighbors");
diff --git a/smtk/session/polygon/operators/Delete.h b/smtk/session/polygon/operators/Delete.h
index 6040ee69a0f89f546349dd3dca60768c68698753..64d2d1e0e68817716c1fa3352cdefff3767d104d 100644
--- a/smtk/session/polygon/operators/Delete.h
+++ b/smtk/session/polygon/operators/Delete.h
@@ -44,7 +44,7 @@ public:
   smtkSuperclassMacro(Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 
   template<typename U, typename V, typename W, typename X>
diff --git a/smtk/session/polygon/operators/DemoteVertex.cxx b/smtk/session/polygon/operators/DemoteVertex.cxx
index 38521e209bb39403de4990e0616ef6f939f394d6..4175cf729d3dd578a25044ec4ad43034c1010d73 100644
--- a/smtk/session/polygon/operators/DemoteVertex.cxx
+++ b/smtk/session/polygon/operators/DemoteVertex.cxx
@@ -35,7 +35,7 @@ namespace session
 namespace polygon
 {
 
-DemoteVertex::Result DemoteVertex::operateInternal()
+DemoteVertex::Result DemoteVertex::operateInternal(Context ctx)
 {
   auto vertItem = this->parameters()->associations();
   smtk::model::Vertex vertexToDemote(vertItem->valueAs<smtk::model::Entity>());
diff --git a/smtk/session/polygon/operators/DemoteVertex.h b/smtk/session/polygon/operators/DemoteVertex.h
index 7129301f488ef312ff8a3f216f20d9c5aa935aa8..8ea4f1636aa741c9fdac530113f3c267c4ef0788 100644
--- a/smtk/session/polygon/operators/DemoteVertex.h
+++ b/smtk/session/polygon/operators/DemoteVertex.h
@@ -32,7 +32,7 @@ public:
   smtkSuperclassMacro(Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/session/polygon/operators/ExtractContours.cxx b/smtk/session/polygon/operators/ExtractContours.cxx
index 0cd8d3446fd2554be1dd98a72adccfd5f305c27d..09855f8a2e717b05962c5a7c5a59c38128a6f7b0 100644
--- a/smtk/session/polygon/operators/ExtractContours.cxx
+++ b/smtk/session/polygon/operators/ExtractContours.cxx
@@ -101,7 +101,7 @@ int internal_createEdge(
   return static_cast<int>(createdEds.size());
 }
 
-ExtractContours::Result ExtractContours::operateInternal()
+ExtractContours::Result ExtractContours::operateInternal(Context ctx)
 {
   // ableToOperate should have verified that aux is valid
   smtk::model::AuxiliaryGeometry aux =
diff --git a/smtk/session/polygon/operators/ExtractContours.h b/smtk/session/polygon/operators/ExtractContours.h
index bd1c99706dcb4ae87a41a20b80108765cac7fb0b..db1acb4de3fa60cf7eeddd61c125034c402b3f93 100644
--- a/smtk/session/polygon/operators/ExtractContours.h
+++ b/smtk/session/polygon/operators/ExtractContours.h
@@ -39,7 +39,7 @@ public:
   bool ableToOperate() override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/session/polygon/operators/ForceCreateFace.cxx b/smtk/session/polygon/operators/ForceCreateFace.cxx
index 1ffd474ec5b2a49b60ae6d840190576809fc61e1..93e741fa389ca3998919d500beb6f239e5bcb26c 100644
--- a/smtk/session/polygon/operators/ForceCreateFace.cxx
+++ b/smtk/session/polygon/operators/ForceCreateFace.cxx
@@ -78,7 +78,7 @@ bool ForceCreateFace::ableToOperate()
 }
 
 /// Create one or more polygonal faces without sanity checks.
-smtk::operation::Operation::Result ForceCreateFace::operateInternal()
+smtk::operation::Operation::Result ForceCreateFace::operateInternal(Context ctx)
 {
   int method = this->parameters()->findInt("construction method")->discreteIndex();
 
diff --git a/smtk/session/polygon/operators/ForceCreateFace.h b/smtk/session/polygon/operators/ForceCreateFace.h
index 881c9abd461e6ad63b61bffdb411c29b9c520634..0a50689c6949d6065d1eb04d78c587edc56e1e01 100644
--- a/smtk/session/polygon/operators/ForceCreateFace.h
+++ b/smtk/session/polygon/operators/ForceCreateFace.h
@@ -46,7 +46,7 @@ public:
   bool ableToOperate() override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/session/polygon/operators/Import.cxx b/smtk/session/polygon/operators/Import.cxx
index 029c2ee936b01035377753d8d7c7ed71ec372fe8..0670b4824e65e28dc579701a6dc4d8deb600ba4c 100644
--- a/smtk/session/polygon/operators/Import.cxx
+++ b/smtk/session/polygon/operators/Import.cxx
@@ -375,7 +375,7 @@ bool Import::ableToOperate()
   return (ext == ".vtp" || ext == ".vtk");
 }
 
-Import::Result Import::operateInternal()
+Import::Result Import::operateInternal(Context ctx)
 {
   Result result;
   std::string filename = this->parameters()->findFile("filename")->value();
diff --git a/smtk/session/polygon/operators/Import.h b/smtk/session/polygon/operators/Import.h
index 5eaf9fc178473a6d92b8a3c99b204b64eda30968..2ad7e7f6c8adb416e72c293ea9c25f2f1a60456b 100644
--- a/smtk/session/polygon/operators/Import.h
+++ b/smtk/session/polygon/operators/Import.h
@@ -49,7 +49,7 @@ public:
 
 protected:
   Import();
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
   int taggedPolyData2PolygonModelEntities(
     smtk::session::polygon::Resource::Ptr& resource,
diff --git a/smtk/session/polygon/operators/ImportPPG.cxx b/smtk/session/polygon/operators/ImportPPG.cxx
index 2477fe1256bfd027d6ce025764e3e3e2a12323a4..8a66a1e9b3c86ae2376494f88e3f4688123b1580 100644
--- a/smtk/session/polygon/operators/ImportPPG.cxx
+++ b/smtk/session/polygon/operators/ImportPPG.cxx
@@ -633,7 +633,7 @@ ImportPPG::~ImportPPG()
   delete m_internal;
 }
 
-smtk::operation::Operation::Result ImportPPG::operateInternal()
+smtk::operation::Operation::Result ImportPPG::operateInternal(Context ctx)
 {
   m_internal->clear();
 
diff --git a/smtk/session/polygon/operators/ImportPPG.h b/smtk/session/polygon/operators/ImportPPG.h
index 3bfdb388c44caa0339d5757e3ff5be6e08db3324..26f16e569ebf97f3dce6c822651c549796f25fa5 100644
--- a/smtk/session/polygon/operators/ImportPPG.h
+++ b/smtk/session/polygon/operators/ImportPPG.h
@@ -48,7 +48,7 @@ public:
 
 protected:
   ImportPPG();
-  smtk::operation::Operation::Result operateInternal() override;
+  smtk::operation::Operation::Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 
 private:
diff --git a/smtk/session/polygon/operators/LegacyRead.cxx b/smtk/session/polygon/operators/LegacyRead.cxx
index 05fdfd2a4a032256ccd067bf4c3d0b570c4a9371..20755625a9865b3255703f3037039b9bed122642 100644
--- a/smtk/session/polygon/operators/LegacyRead.cxx
+++ b/smtk/session/polygon/operators/LegacyRead.cxx
@@ -31,7 +31,7 @@ namespace session
 namespace polygon
 {
 
-LegacyRead::Result LegacyRead::operateInternal()
+LegacyRead::Result LegacyRead::operateInternal(Context ctx)
 {
   std::string filename = this->parameters()->findFile("filename")->value();
 
diff --git a/smtk/session/polygon/operators/LegacyRead.h b/smtk/session/polygon/operators/LegacyRead.h
index 330927b3ce7353fb9629e8a54cbaf83f719deb6d..3f5ae7277613bfab17f151d41a659fd1f665ac29 100644
--- a/smtk/session/polygon/operators/LegacyRead.h
+++ b/smtk/session/polygon/operators/LegacyRead.h
@@ -39,7 +39,7 @@ public:
   smtkSuperclassMacro(Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/session/polygon/operators/Read.cxx b/smtk/session/polygon/operators/Read.cxx
index ac414eb0b4da44c7fb9feed49d5476413f927f7c..41e9813edfb97bc177041494564bef7956b889da 100644
--- a/smtk/session/polygon/operators/Read.cxx
+++ b/smtk/session/polygon/operators/Read.cxx
@@ -31,7 +31,7 @@ namespace session
 namespace polygon
 {
 
-Read::Result Read::operateInternal()
+Read::Result Read::operateInternal(Context ctx)
 {
   std::string filename = this->parameters()->findFile("filename")->value();
 
diff --git a/smtk/session/polygon/operators/Read.h b/smtk/session/polygon/operators/Read.h
index 2fe8d659410f6e238158572d3e4fa04ded9b0938..2b2dee707e52e2c01b0c1b3883d9ecf36b69c788 100644
--- a/smtk/session/polygon/operators/Read.h
+++ b/smtk/session/polygon/operators/Read.h
@@ -32,7 +32,7 @@ public:
   smtkSuperclassMacro(Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   void markModifiedResources(Result& res) override;
   const char* xmlDescription() const override;
 };
diff --git a/smtk/session/polygon/operators/SplitEdge.cxx b/smtk/session/polygon/operators/SplitEdge.cxx
index ae93b7c7637a5c06b9841afe15d0b86f12d353a4..e1f0fac3e46ef1bf660f3fd8bad5f9ee2345b0f1 100644
--- a/smtk/session/polygon/operators/SplitEdge.cxx
+++ b/smtk/session/polygon/operators/SplitEdge.cxx
@@ -34,7 +34,7 @@ namespace session
 namespace polygon
 {
 
-SplitEdge::Result SplitEdge::operateInternal()
+SplitEdge::Result SplitEdge::operateInternal(Context ctx)
 {
   smtk::attribute::IntItem::Ptr pointIdItem = this->parameters()->findInt("point id");
   smtk::attribute::DoubleItem::Ptr pointItem = this->parameters()->findDouble("point");
diff --git a/smtk/session/polygon/operators/SplitEdge.h b/smtk/session/polygon/operators/SplitEdge.h
index ddee4dd46a7e74c0882780dcd965716ecca0d7ce..6817d050a0bedb98af54ebb7f3a50883d5bef5b8 100644
--- a/smtk/session/polygon/operators/SplitEdge.h
+++ b/smtk/session/polygon/operators/SplitEdge.h
@@ -32,7 +32,7 @@ public:
   smtkSuperclassMacro(Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/session/polygon/operators/TweakEdge.cxx b/smtk/session/polygon/operators/TweakEdge.cxx
index 8008a37ed78f0e2cfca41cd96705ab9d2672d03a..7a8b4dea6e2debd7e2a59ef65512644715b0edc9 100644
--- a/smtk/session/polygon/operators/TweakEdge.cxx
+++ b/smtk/session/polygon/operators/TweakEdge.cxx
@@ -35,7 +35,7 @@ namespace session
 namespace polygon
 {
 
-TweakEdge::Result TweakEdge::operateInternal()
+TweakEdge::Result TweakEdge::operateInternal(Context ctx)
 {
   auto edgeItem = this->parameters()->associations();
   auto pointsItem = this->parameters()->findDouble("points");
diff --git a/smtk/session/polygon/operators/TweakEdge.h b/smtk/session/polygon/operators/TweakEdge.h
index b56c15a7770c72c2b2c85e001d272bf7a1acc237..7253c49f801c1e5bec2fe8bb507de63ee8ae5b75 100644
--- a/smtk/session/polygon/operators/TweakEdge.h
+++ b/smtk/session/polygon/operators/TweakEdge.h
@@ -30,7 +30,7 @@ public:
   smtkSuperclassMacro(Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/session/polygon/operators/Write.cxx b/smtk/session/polygon/operators/Write.cxx
index 23d2ab9b0795761ff867c0e07ab99f4e708efc01..8e7183fc93824cd8b5e587be44d24a57a5ef7f72 100644
--- a/smtk/session/polygon/operators/Write.cxx
+++ b/smtk/session/polygon/operators/Write.cxx
@@ -44,7 +44,7 @@ bool Write::ableToOperate()
   return true;
 }
 
-Write::Result Write::operateInternal()
+Write::Result Write::operateInternal(Context ctx)
 {
   auto resourceItem = this->parameters()->associations();
 
diff --git a/smtk/session/polygon/operators/Write.h b/smtk/session/polygon/operators/Write.h
index 001673da7a9d12484dee64a24373dba835761e57..f3a0786faf4a0ec6c84b4c49253bb69a33e25613 100644
--- a/smtk/session/polygon/operators/Write.h
+++ b/smtk/session/polygon/operators/Write.h
@@ -34,7 +34,7 @@ public:
   bool ableToOperate() override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/session/vtk/operators/Export.cxx b/smtk/session/vtk/operators/Export.cxx
index de129824c0b39e14fddeab8eff0b078ecc9cdb75..08c962b3615147e54d4ae5cb385d3dfad5033a4d 100644
--- a/smtk/session/vtk/operators/Export.cxx
+++ b/smtk/session/vtk/operators/Export.cxx
@@ -62,7 +62,7 @@ namespace session
 namespace vtk
 {
 
-Export::Result Export::operateInternal()
+Export::Result Export::operateInternal(Context ctx)
 {
   smtk::attribute::FileItem::Ptr filenameItem = this->parameters()->findFile("filename");
   smtk::attribute::StringItem::Ptr filetypeItem = this->parameters()->findString("filetype");
diff --git a/smtk/session/vtk/operators/Export.h b/smtk/session/vtk/operators/Export.h
index c94c86f2e7816c0dd6e4b0ac9d8b76f333e9e3ea..7d4f835948894bd6ba66db285dfa94dd0b3af7a7 100644
--- a/smtk/session/vtk/operators/Export.h
+++ b/smtk/session/vtk/operators/Export.h
@@ -27,7 +27,7 @@ public:
   smtkSharedFromThisMacro(smtk::operation::Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   virtual Result exportExodus();
   virtual Result exportSLAC();
   virtual Result exportLabelMap();
diff --git a/smtk/session/vtk/operators/Import.cxx b/smtk/session/vtk/operators/Import.cxx
index 1e279be865448a47d030f85adab4338d791923dc..64b21f91a557ee2cbf1370c8b7ba66f0c8712d54 100644
--- a/smtk/session/vtk/operators/Import.cxx
+++ b/smtk/session/vtk/operators/Import.cxx
@@ -67,7 +67,7 @@ namespace session
 namespace vtk
 {
 
-Import::Result Import::operateInternal()
+Import::Result Import::operateInternal(Context ctx)
 {
   smtk::attribute::FileItem::Ptr filenameItem = this->parameters()->findFile("filename");
   smtk::attribute::StringItem::Ptr filetypeItem = this->parameters()->findString("filetype");
diff --git a/smtk/session/vtk/operators/Import.h b/smtk/session/vtk/operators/Import.h
index 55730acffd0a8239ef75dbf4dd9bc3aaaacfbfa4..2962031a4a63ff07a48e466acbfaa14982c551ef 100644
--- a/smtk/session/vtk/operators/Import.h
+++ b/smtk/session/vtk/operators/Import.h
@@ -35,7 +35,7 @@ public:
   smtkSuperclassMacro(Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   virtual Result importExodus(const smtk::session::vtk::Resource::Ptr&);
   virtual Result importSLAC(const smtk::session::vtk::Resource::Ptr&);
   virtual Result importLabelMap(const smtk::session::vtk::Resource::Ptr&);
diff --git a/smtk/session/vtk/operators/LegacyRead.cxx b/smtk/session/vtk/operators/LegacyRead.cxx
index bfbc1bef984634e40d7b10d768b7384e410cb6fa..44db835d08f876d7dee628f9d7e0b62a9c30919c 100644
--- a/smtk/session/vtk/operators/LegacyRead.cxx
+++ b/smtk/session/vtk/operators/LegacyRead.cxx
@@ -35,7 +35,7 @@ namespace session
 namespace vtk
 {
 
-LegacyRead::Result LegacyRead::operateInternal()
+LegacyRead::Result LegacyRead::operateInternal(Context ctx)
 {
   std::string filename = this->parameters()->findFile("filename")->value();
 
diff --git a/smtk/session/vtk/operators/LegacyRead.h b/smtk/session/vtk/operators/LegacyRead.h
index 46202b97bd317529c4671c0039e2390e108ba548..6fc78866f8f2e57d50517f753c7f97de68ae9f2e 100644
--- a/smtk/session/vtk/operators/LegacyRead.h
+++ b/smtk/session/vtk/operators/LegacyRead.h
@@ -39,7 +39,7 @@ public:
   smtkSuperclassMacro(Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/session/vtk/operators/Read.cxx b/smtk/session/vtk/operators/Read.cxx
index 62475622cd94d11a9f8b14e15e713c1afdb5821e..0db2c0c023076245f85ea951758d1a6c5aab6832 100644
--- a/smtk/session/vtk/operators/Read.cxx
+++ b/smtk/session/vtk/operators/Read.cxx
@@ -35,7 +35,7 @@ namespace session
 namespace vtk
 {
 
-Read::Result Read::operateInternal()
+Read::Result Read::operateInternal(Context ctx)
 {
   std::string filename = this->parameters()->findFile("filename")->value();
 
diff --git a/smtk/session/vtk/operators/Read.h b/smtk/session/vtk/operators/Read.h
index 2662427357ffe890ecd7ea08726da20aa631cf6d..4d429a213b6c29eb831cb183d82fc282d14de63e 100644
--- a/smtk/session/vtk/operators/Read.h
+++ b/smtk/session/vtk/operators/Read.h
@@ -32,7 +32,7 @@ public:
   smtkSuperclassMacro(Operation);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
   void markModifiedResources(Result&) override;
 };
diff --git a/smtk/session/vtk/operators/Write.cxx b/smtk/session/vtk/operators/Write.cxx
index e736f50b7bd583114fd07ca969b27f433cdc9ffd..650516a9b0e5cd192656a2b299f93a85caafa9b7 100644
--- a/smtk/session/vtk/operators/Write.cxx
+++ b/smtk/session/vtk/operators/Write.cxx
@@ -83,7 +83,7 @@ bool Write::ableToOperate()
   return true;
 }
 
-Write::Result Write::operateInternal()
+Write::Result Write::operateInternal(Context ctx)
 {
   auto resourceItem = this->parameters()->associations();
 
diff --git a/smtk/session/vtk/operators/Write.h b/smtk/session/vtk/operators/Write.h
index 1b67f762e29ee8981b666662805e0d26bd211afa..bfc79b4782dc68ffebc749c43139e7b74b78f6a7 100644
--- a/smtk/session/vtk/operators/Write.h
+++ b/smtk/session/vtk/operators/Write.h
@@ -34,7 +34,7 @@ public:
   bool ableToOperate() override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
   void markModifiedResources(Result&) override;
 };
diff --git a/smtk/task/Agent.cxx b/smtk/task/Agent.cxx
index af7753795e1a7914a2a2b71d470b818d88d822af..2e08d79ced77e207e22e5cddbf91dcdf2202645c 100644
--- a/smtk/task/Agent.cxx
+++ b/smtk/task/Agent.cxx
@@ -47,7 +47,7 @@ Agent::Configuration Agent::configuration() const
   return config;
 }
 
-void Agent::portDataUpdated(const Port*) {}
+void Agent::portDataUpdated(Context ctx, const Port*) {}
 
 bool Agent::getViewData(smtk::common::TypeContainer& configuration) const
 {
diff --git a/smtk/task/Agent.h b/smtk/task/Agent.h
index bffb6fb45bfe78ce22c4c523a788cd64463a3ff6..d64e241c85b61aabd31da03d62e049880436b61a 100644
--- a/smtk/task/Agent.h
+++ b/smtk/task/Agent.h
@@ -13,6 +13,7 @@
 #include "smtk/CoreExports.h"
 #include "smtk/SharedFromThis.h"
 #include "smtk/SystemConfig.h"
+#include "smtk/common/Context.h"
 #include "smtk/common/Deprecation.h"
 #include "smtk/common/Managers.h"
 #include "smtk/common/Observers.h"
@@ -48,6 +49,8 @@ class Task;
 class SMTKCORE_EXPORT Agent
 {
 public:
+  using Context = smtk::common::Context;
+
   /// The set of values that an agent's acceptChildCategories method can return.
   enum class CategoryEvaluation
   {
@@ -85,7 +88,7 @@ public:
   /// This will be called when an input \a port connection is modified upstream
   /// of this agent, so \a port should always be an input port of this agent's
   /// parent task.
-  virtual void portDataUpdated(const Port* port);
+  virtual void portDataUpdated(Context ctx, const Port* port);
 
   ///\brief Return the agent's parent task
   Task* parent() const { return m_parent; }
diff --git a/smtk/task/FillOutAttributes.cxx b/smtk/task/FillOutAttributes.cxx
index 3979561dfa48035892d5215e96ba4119af308be5..366b641c7a650bffcef8311ddc042a092b5fe398 100644
--- a/smtk/task/FillOutAttributes.cxx
+++ b/smtk/task/FillOutAttributes.cxx
@@ -115,6 +115,7 @@ void FillOutAttributes::configure(const Configuration& config)
     {
       m_observer = operationManager->observers().insert(
         [this](
+        smtk::common::Context ctx,
           const smtk::operation::Operation& op,
           smtk::operation::EventType event,
           smtk::operation::Operation::Result result) { return this->update(op, event, result); },
@@ -188,7 +189,7 @@ std::shared_ptr<PortData> FillOutAttributes::portData(const Port* port) const
   return data;
 }
 
-void FillOutAttributes::portDataUpdated(const Port* port)
+void FillOutAttributes::portDataUpdated(Context ctx, const Port* port)
 {
   if (m_ports.empty() || m_ports["in"] != port)
   {
diff --git a/smtk/task/FillOutAttributes.h b/smtk/task/FillOutAttributes.h
index 87fbbb97950ecb2300fb2b5e0f5083492dd93533..c5482396205938d9607ff1d585381d765bd8531d 100644
--- a/smtk/task/FillOutAttributes.h
+++ b/smtk/task/FillOutAttributes.h
@@ -115,7 +115,7 @@ public:
   std::shared_ptr<PortData> portData(const Port* port) const override;
 
   /// Update the task based on new port data.
-  void portDataUpdated(const Port* port) override;
+  void portDataUpdated(Context ctx, const Port* port) override;
 
   /// Provide the attribute resource(s) that the user should edit.
   bool getViewData(smtk::common::TypeContainer& configuration) const override;
diff --git a/smtk/task/FillOutAttributesAgent.cxx b/smtk/task/FillOutAttributesAgent.cxx
index 5d3aa9fe0f833d0dff413035419ed1b9f86dc9b3..0667e7fa887e1ce372a975eef880180fbd532d60 100644
--- a/smtk/task/FillOutAttributesAgent.cxx
+++ b/smtk/task/FillOutAttributesAgent.cxx
@@ -103,6 +103,7 @@ void FillOutAttributesAgent::configure(const Configuration& config)
     {
       m_observer = operationManager->observers().insert(
         [this](
+        smtk::common::Context ctx,
           const smtk::operation::Operation& op,
           smtk::operation::EventType event,
           smtk::operation::Operation::Result result) { return this->update(op, event, result); },
@@ -201,7 +202,7 @@ std::shared_ptr<PortData> FillOutAttributesAgent::portData(const Port* port) con
   return data;
 }
 
-void FillOutAttributesAgent::portDataUpdated(const Port* port)
+void FillOutAttributesAgent::portDataUpdated(Context ctx, const Port* port)
 {
   // Only respond if the port is our input.
   if (!port || m_inputPort != port)
@@ -256,7 +257,7 @@ void FillOutAttributesAgent::portDataUpdated(const Port* port)
     if (m_outputPort)
     {
       // Propagate changes downstream.
-      m_parent->portDataUpdated(m_outputPort);
+      m_parent->portDataUpdated(ctx, m_outputPort);
     }
   }
 }
diff --git a/smtk/task/FillOutAttributesAgent.h b/smtk/task/FillOutAttributesAgent.h
index 7f936ce0e97fe2b916f24b9148142047ab12969d..e47615ef7e9a1bc38b24c5ea7089d077623a026d 100644
--- a/smtk/task/FillOutAttributesAgent.h
+++ b/smtk/task/FillOutAttributesAgent.h
@@ -74,7 +74,7 @@ public:
   std::shared_ptr<PortData> portData(const Port* port) const override;
 
   ///\brief Tell the agent that the data on \a port has been updated.
-  void portDataUpdated(const Port* port) override;
+  void portDataUpdated(Context ctx, const Port* port) override;
 
   ///\brief Insert an attribute resource pointer into \a configuration.
   bool getViewData(smtk::common::TypeContainer& configuration) const override;
diff --git a/smtk/task/GatherObjectsAgent.cxx b/smtk/task/GatherObjectsAgent.cxx
index 2f350cb1d35890ded8447288c828d343c0fcbce0..9cc6c9dae55f19024be40b08d6a9abe74177b4cc 100644
--- a/smtk/task/GatherObjectsAgent.cxx
+++ b/smtk/task/GatherObjectsAgent.cxx
@@ -125,7 +125,7 @@ std::shared_ptr<PortData> GatherObjectsAgent::portData(const Port* port) const
 bool GatherObjectsAgent::addObjectInRole(
   smtk::resource::PersistentObject* object,
   smtk::string::Token role,
-  bool signal)
+  bool signal, Context ctx)
 {
   if (!object || !role.valid())
   {
@@ -162,7 +162,7 @@ bool GatherObjectsAgent::addObjectInRole(
     auto it = m_parent->ports().find(m_outputPortName);
     if (it != m_parent->ports().end())
     {
-      m_parent->portDataUpdated(it->second);
+      m_parent->portDataUpdated(ctx, it->second);
     }
   }
   return true;
@@ -171,7 +171,7 @@ bool GatherObjectsAgent::addObjectInRole(
 bool GatherObjectsAgent::removeObjectFromRole(
   smtk::resource::PersistentObject* object,
   smtk::string::Token role,
-  bool signal)
+  bool signal, Context ctx)
 {
   if (!object || !role.valid())
   {
@@ -214,7 +214,7 @@ bool GatherObjectsAgent::removeObjectFromRole(
           auto it = m_parent->ports().find(m_outputPortName);
           if (it != m_parent->ports().end())
           {
-            m_parent->portDataUpdated(it->second);
+            m_parent->portDataUpdated(ctx, it->second);
           }
         }
         return true;
@@ -224,7 +224,7 @@ bool GatherObjectsAgent::removeObjectFromRole(
   return false;
 }
 
-bool GatherObjectsAgent::clearOutputPort(bool signal)
+bool GatherObjectsAgent::clearOutputPort(bool signal, Context ctx)
 {
   bool wasNotEmpty = !m_objects.empty();
   m_objects.clear();
@@ -233,7 +233,7 @@ bool GatherObjectsAgent::clearOutputPort(bool signal)
     auto it = m_parent->ports().find(m_outputPortName);
     if (it != m_parent->ports().end())
     {
-      m_parent->portDataUpdated(it->second);
+      m_parent->portDataUpdated(ctx, it->second);
     }
   }
   return wasNotEmpty;
diff --git a/smtk/task/GatherObjectsAgent.h b/smtk/task/GatherObjectsAgent.h
index 284b0c1ce20b9530fa40c5f7e6105047b01fa509..0683025da208711c032c27ffae50f1d0a0665d42 100644
--- a/smtk/task/GatherObjectsAgent.h
+++ b/smtk/task/GatherObjectsAgent.h
@@ -63,7 +63,7 @@ public:
   bool addObjectInRole(
     smtk::resource::PersistentObject* object,
     smtk::string::Token role,
-    bool signal = false);
+    bool signal = false, Context ctx = Context());
 
   ///\brief Remove a persistent \a object from this port's output for the given \a role.
   ///
@@ -73,13 +73,13 @@ public:
   bool removeObjectFromRole(
     smtk::resource::PersistentObject* object,
     smtk::string::Token role,
-    bool signal = false);
+    bool signal = false, Context ctx = Context());
 
   ///\brief Clear the data to be reported on the output port.
   ///
   /// If the port was modified and \a signal is true,
   /// then Task::portDataUpdated() is invoked for this agent's port.
-  bool clearOutputPort(bool signal = false);
+  bool clearOutputPort(bool signal = false, Context ctx = Context());
 
   /// Return this agent's output port (or null).
   Port* outputPort() const;
diff --git a/smtk/task/Manager.cxx b/smtk/task/Manager.cxx
index 8d973e38c5204e38fcb45db916a4d1c7f0bfbe65..48b36a911e2edb4bc1c155b30e3c2912831c8059 100644
--- a/smtk/task/Manager.cxx
+++ b/smtk/task/Manager.cxx
@@ -123,10 +123,11 @@ void Manager::setManagers(const smtk::common::Managers::Ptr& managers)
     {
       m_taskEventObserver = opMgr->observers().insert(
         [this](
+          smtk::common::Context ctx,
           const smtk::operation::Operation& op,
           smtk::operation::EventType event,
           smtk::operation::Operation::Result result) {
-          return this->handleOperation(op, event, result);
+          return this->handleOperation(ctx, op, event, result);
         },
         Manager::operationObserverPriority(),
         false,
@@ -150,6 +151,7 @@ smtk::resource::Resource* Manager::resource() const
 }
 
 int Manager::handleOperation(
+  smtk::common::Context ctx,
   const smtk::operation::Operation& op,
   smtk::operation::EventType event,
   smtk::operation::Operation::Result result)
@@ -186,7 +188,7 @@ int Manager::handleOperation(
         // connected to this port that have multiple
         // inputs need to be told to reconfigure (without the
         // data from this port).
-        this->removePortFromDownstream(port);
+        this->removePortFromDownstream(ctx, port);
       }
       // Now that we've traversed connections, clear them.
       // This is defensive programming; we don't want stale pointers
@@ -195,7 +197,7 @@ int Manager::handleOperation(
     }
     else
     {
-      this->handlePortDataReferences(comp.get());
+      this->handlePortDataReferences(ctx, comp.get());
     }
   }
   if (expungedResources)
@@ -203,7 +205,7 @@ int Manager::handleOperation(
     // See if any removed resources were used as port inputs.
     for (const auto& resource : *expungedResources)
     {
-      this->handlePortDataReferences(resource.get());
+      this->handlePortDataReferences(ctx, resource.get());
     }
   }
   // TODO: Handle workflows
@@ -211,7 +213,7 @@ int Manager::handleOperation(
   {
     if (auto port = std::dynamic_pointer_cast<smtk::task::Port>(comp))
     {
-      this->handleCreatedOrModifiedPort(port);
+      this->handleCreatedOrModifiedPort(ctx, port);
     }
     else if (auto task = std::dynamic_pointer_cast<smtk::task::Task>(comp))
     {
@@ -227,7 +229,7 @@ int Manager::handleOperation(
   {
     if (auto port = std::dynamic_pointer_cast<smtk::task::Port>(comp))
     {
-      this->handleCreatedOrModifiedPort(port);
+      this->handleCreatedOrModifiedPort(ctx, port);
     }
     else if (auto task = std::dynamic_pointer_cast<smtk::task::Task>(comp))
     {
@@ -265,7 +267,7 @@ int Manager::handleOperation(
   return 0;
 }
 
-bool Manager::handlePortDataReferences(smtk::resource::PersistentObject* obj)
+bool Manager::handlePortDataReferences(smtk::common::Context ctx, smtk::resource::PersistentObject* obj)
 {
   // Any non-Port object may be an input to a Port.
   // Look in the m_portData map to see if this is the case.
@@ -282,7 +284,7 @@ bool Manager::handlePortDataReferences(smtk::resource::PersistentObject* obj)
         auto* downstreamTask = downstreamPort->parent();
         if (downstreamTask)
         {
-          downstreamTask->portDataUpdated(downstreamPort);
+          downstreamTask->portDataUpdated(ctx, downstreamPort);
         }
       }
     }
@@ -310,7 +312,7 @@ bool Manager::removeUpstreamMentions(const std::shared_ptr<smtk::task::Port>& po
   return didRemove;
 }
 
-bool Manager::removePortFromDownstream(const std::shared_ptr<smtk::task::Port>& port)
+bool Manager::removePortFromDownstream(smtk::common::Context ctx, const std::shared_ptr<smtk::task::Port>& port)
 {
   bool didRemove = false;
   if (port->direction() != Port::Direction::Out)
@@ -330,7 +332,7 @@ bool Manager::removePortFromDownstream(const std::shared_ptr<smtk::task::Port>&
           auto* downstreamTask = downstreamPort->parent();
           if (downstreamTask)
           {
-            downstreamTask->portDataUpdated(downstreamPort);
+            downstreamTask->portDataUpdated(ctx, downstreamPort);
           }
         }
       }
@@ -341,7 +343,7 @@ bool Manager::removePortFromDownstream(const std::shared_ptr<smtk::task::Port>&
   return didRemove;
 }
 
-void Manager::handleCreatedOrModifiedPort(const std::shared_ptr<smtk::task::Port>& port)
+void Manager::handleCreatedOrModifiedPort(smtk::common::Context ctx, const std::shared_ptr<smtk::task::Port>& port)
 {
   if (port->direction() == Port::Direction::Out)
   {
@@ -354,7 +356,7 @@ void Manager::handleCreatedOrModifiedPort(const std::shared_ptr<smtk::task::Port
         auto* downstreamTask = downstreamPort->parent();
         if (downstreamTask)
         {
-          downstreamTask->portDataUpdated(downstreamPort);
+          downstreamTask->portDataUpdated(ctx, downstreamPort);
         }
       }
     }
@@ -377,7 +379,7 @@ void Manager::handleCreatedOrModifiedPort(const std::shared_ptr<smtk::task::Port
         // result.
         if (m_portData[conn].insert(port.get()).second)
         {
-          port->parent()->portDataUpdated(port.get());
+          port->parent()->portDataUpdated(ctx, port.get());
         }
       }
     }
diff --git a/smtk/task/Manager.h b/smtk/task/Manager.h
index 9dd682795e2cd0fc54b445f5e1fd8ed3a8b1a607..43d7fa859b01777b09f2dc1fff62a98ec0c39a9b 100644
--- a/smtk/task/Manager.h
+++ b/smtk/task/Manager.h
@@ -172,23 +172,24 @@ public:
 private:
   /// A method invoked when the \a m_manager's operation manager runs an operation.
   int handleOperation(
+    smtk::common::Context ctx,
     const smtk::operation::Operation& op,
     smtk::operation::EventType event,
     smtk::operation::Operation::Result result);
 
   /// If a port directly references \a obj as a connection, remove \a obj
   /// and potentially notify the consuming port's task.
-  bool handlePortDataReferences(smtk::resource::PersistentObject* obj);
+  bool handlePortDataReferences(smtk::common::Context ctx, smtk::resource::PersistentObject* obj);
   /// Remove an input \a port from upstream output ports.
   bool removeUpstreamMentions(const std::shared_ptr<smtk::task::Port>& port);
   /// Remove an output \a port from all its downstream input ports.
   ///
   /// This may invoke the downstream-task's portDataUpdated() method
   /// (if there are any remaining inputs).
-  bool removePortFromDownstream(const std::shared_ptr<smtk::task::Port>& port);
+  bool removePortFromDownstream(smtk::common::Context ctx, const std::shared_ptr<smtk::task::Port>& port);
 
   /// Invoke methods on upstream/downstream objects when \a port is created/modified.
-  void handleCreatedOrModifiedPort(const std::shared_ptr<smtk::task::Port>& port);
+  void handleCreatedOrModifiedPort(smtk::common::Context ctx, const std::shared_ptr<smtk::task::Port>& port);
 
   TaskInstances m_taskInstances;
   AdaptorInstances m_adaptorInstances;
diff --git a/smtk/task/PortForwardingAgent.cxx b/smtk/task/PortForwardingAgent.cxx
index a09316a1d18a28801cfd5a12be5ebf6a4a776623..b6d253de6ead0beaf587bc86cef49656f2f5abdb 100644
--- a/smtk/task/PortForwardingAgent.cxx
+++ b/smtk/task/PortForwardingAgent.cxx
@@ -242,7 +242,7 @@ std::shared_ptr<PortData> PortForwardingAgent::portData(const Port* port) const
   return result;
 }
 
-void PortForwardingAgent::portDataUpdated(const Port* port)
+void PortForwardingAgent::portDataUpdated(Context ctx, const Port* port)
 {
   // Collect a list of output ports whose data needs to be updated
   // because \a port is attached from upstream via this agent.
@@ -257,7 +257,7 @@ void PortForwardingAgent::portDataUpdated(const Port* port)
   // Notify connections on downstream ports once (for this input \a port):
   for (const auto& downstreamPort : downstreamPorts)
   {
-    this->parent()->portDataUpdated(downstreamPort);
+    this->parent()->portDataUpdated(ctx, downstreamPort);
   }
 }
 
diff --git a/smtk/task/PortForwardingAgent.h b/smtk/task/PortForwardingAgent.h
index b403d6b6070f85ae7a745baf84e55b30c427f1f3..ce25fd3e392b1de9ac33b35b0df091ae71aecdd8 100644
--- a/smtk/task/PortForwardingAgent.h
+++ b/smtk/task/PortForwardingAgent.h
@@ -88,7 +88,7 @@ public:
   /// This assumes that \a port is an input port of the task and
   /// forces portDataUpdated() to be called on each downstream
   /// of \a port.
-  void portDataUpdated(const Port* port) override;
+  void portDataUpdated(Context ctx, const Port* port) override;
 
 protected:
   std::vector<Forward> m_forwards;
diff --git a/smtk/task/SubmitOperation.cxx b/smtk/task/SubmitOperation.cxx
index 950a811031bcdebcd787593966762039ae45aa14..22b40547de30060a606b887cf2ba05472d2a1d25 100644
--- a/smtk/task/SubmitOperation.cxx
+++ b/smtk/task/SubmitOperation.cxx
@@ -219,6 +219,7 @@ void SubmitOperation::configure(const Configuration& config)
     {
       m_observer = operationManager->observers().insert(
         [this](
+        smtk::common::Context ctx,
           const smtk::operation::Operation& op,
           smtk::operation::EventType event,
           smtk::operation::Operation::Result result) { return this->update(op, event, result); },
diff --git a/smtk/task/SubmitOperationAgent.cxx b/smtk/task/SubmitOperationAgent.cxx
index 97c6c5869e3ae2d9e21953a2d7320c3c88534e21..b280011b3130e1e6f5ebe7a53bb852eba6ace89e 100644
--- a/smtk/task/SubmitOperationAgent.cxx
+++ b/smtk/task/SubmitOperationAgent.cxx
@@ -304,6 +304,7 @@ void SubmitOperationAgent::configure(const Configuration& config)
       }
       m_observer = operationManager->observers().insert(
         [this](
+        smtk::common::Context ctx,
           const smtk::operation::Operation& op,
           smtk::operation::EventType event,
           smtk::operation::Operation::Result result) { return this->update(op, event, result); },
@@ -507,7 +508,7 @@ std::shared_ptr<PortData> SubmitOperationAgent::portData(const Port* port) const
   return data;
 }
 
-void SubmitOperationAgent::portDataUpdated(const Port* port)
+void SubmitOperationAgent::portDataUpdated(Context ctx, const Port* port)
 {
   if (!port)
   {
diff --git a/smtk/task/SubmitOperationAgent.h b/smtk/task/SubmitOperationAgent.h
index afd87e50f622302c60d721b2bfac48e9a5d3fe17..5694dc2ae4b3441b4f6a578748d39eab5e68e225 100644
--- a/smtk/task/SubmitOperationAgent.h
+++ b/smtk/task/SubmitOperationAgent.h
@@ -264,7 +264,7 @@ public:
   std::shared_ptr<PortData> portData(const Port* port) const override;
 
   ///\brief  Tell the agent that the data on \a port has been updated.
-  void portDataUpdated(const Port* port) override;
+  void portDataUpdated(Context ctx, const Port* port) override;
 
   /// Return the operation this task requires users to configure and submit.
   smtk::operation::Operation* operation() const { return m_operation.get(); }
diff --git a/smtk/task/Task.cxx b/smtk/task/Task.cxx
index 531e3783fdcff98660d1ff40324a242b5d5ec86c..70ab95a2d034045c031bed8751b4b546857db02f 100644
--- a/smtk/task/Task.cxx
+++ b/smtk/task/Task.cxx
@@ -398,7 +398,7 @@ std::shared_ptr<PortData> Task::portData(const Port* port) const
   return this->outputPortData(port);
 }
 
-void Task::portDataUpdated(const Port* port)
+void Task::portDataUpdated(Context ctx, const Port* port)
 {
   if (!port)
   {
@@ -410,7 +410,7 @@ void Task::portDataUpdated(const Port* port)
   {
     for (const auto& agent : m_agents)
     {
-      agent->portDataUpdated(port);
+      agent->portDataUpdated(ctx, port);
     }
   }
   else // port->direction() == Port::Direction::Out
@@ -421,7 +421,7 @@ void Task::portDataUpdated(const Port* port)
       {
         if (auto* connParent = connPort->parent())
         {
-          connParent->portDataUpdated(connPort);
+          connParent->portDataUpdated(ctx, connPort);
         }
       }
     }
diff --git a/smtk/task/Task.h b/smtk/task/Task.h
index 8d45c3acd7b90f5c828a672dc8050f11cf825345..934c829d340f006284f14640452dfc7dd6c1ecfc 100644
--- a/smtk/task/Task.h
+++ b/smtk/task/Task.h
@@ -16,6 +16,7 @@
 #include "smtk/CoreExports.h"
 #include "smtk/SharedFromThis.h"
 #include "smtk/SystemConfig.h"
+#include "smtk/common/Context.h"
 #include "smtk/common/Deprecation.h"
 #include "smtk/common/Managers.h"
 #include "smtk/common/Observers.h"
@@ -74,6 +75,8 @@ public:
   smtkSuperclassMacro(smtk::resource::Component);
   smtkCreateMacro(smtk::resource::PersistentObject);
 
+  using Context = smtk::common::Context;
+
   /// A task's state changes may be observed.
   using Observer = std::function<void(Task&, State, State)>;
   /// The collection of all observers of this task instance.
@@ -200,7 +203,7 @@ public:
   /// Because this function will be called on the user-interface thread,
   /// it is acceptable to take actions affecting the user interface,
   /// including changing the state of this task.
-  virtual void portDataUpdated(const Port* port);
+  virtual void portDataUpdated(Context ctx, const Port* port);
 
   /// Set/get style classes for the task.
   /// A style class specifies how applications should present the task
diff --git a/smtk/task/TrivialProducerAgent.cxx b/smtk/task/TrivialProducerAgent.cxx
index 8cba737887eeeecdce191b22186914f648ee5ab1..6c60221926c869f8a38e6e26d8900cc4c69d0343 100644
--- a/smtk/task/TrivialProducerAgent.cxx
+++ b/smtk/task/TrivialProducerAgent.cxx
@@ -76,7 +76,8 @@ void TrivialProducerAgent::configure(const Configuration& config)
   }
   if (addedData && m_outputPort)
   {
-    this->portDataUpdated(m_outputPort);
+    // TODO: This call probably shouldn't be here. Context cannot be passed.
+    this->portDataUpdated(Context(), m_outputPort);
   }
 }
 
diff --git a/smtk/task/adaptor/ConfigureOperation.cxx b/smtk/task/adaptor/ConfigureOperation.cxx
index 8620211c54a8f9f88c1d62f6042c8ee3a179b396..d5ecc27db34b7a89632fb1c5eef682fcdb0991c0 100644
--- a/smtk/task/adaptor/ConfigureOperation.cxx
+++ b/smtk/task/adaptor/ConfigureOperation.cxx
@@ -317,6 +317,7 @@ bool ConfigureOperation::setupAttributeObserver()
   auto opManager = managers->get<smtk::operation::Manager::Ptr>();
   m_attributeObserver = opManager->observers().insert(
     [this](
+    smtk::common::Context ctx,
       const smtk::operation::Operation& op,
       smtk::operation::EventType eventType,
       smtk::operation::Operation::Result result) -> int {
diff --git a/smtk/task/operators/AddDependency.cxx b/smtk/task/operators/AddDependency.cxx
index dfddfcf671b4f71cb79575062585de124f24034a..7c32122bf5bfb891eb3b7dadb8fc83bf8d8d02ae 100644
--- a/smtk/task/operators/AddDependency.cxx
+++ b/smtk/task/operators/AddDependency.cxx
@@ -59,7 +59,7 @@ bool AddDependency::ableToOperate()
   return this->Superclass::ableToOperate();
 }
 
-AddDependency::Result AddDependency::operateInternal()
+AddDependency::Result AddDependency::operateInternal(Context ctx)
 {
   auto fromTask = this->parameters()->associations()->valueAs<smtk::task::Task>();
   auto toTask = this->parameters()->findComponent("to")->valueAs<smtk::task::Task>();
diff --git a/smtk/task/operators/AddDependency.h b/smtk/task/operators/AddDependency.h
index bcb2e9af7f8c2810397c34f8bb035c8421cd67e7..f1228ec83751e828d9e82d3227349f447c3fdc36 100644
--- a/smtk/task/operators/AddDependency.h
+++ b/smtk/task/operators/AddDependency.h
@@ -37,7 +37,7 @@ public:
   bool ableToOperate() override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/task/operators/ConnectPorts.cxx b/smtk/task/operators/ConnectPorts.cxx
index e4830010a381e0d0bd1c145af1969dfaa34f8862..fa60691f89dd15ac8810d08e42851d0b04509d50 100644
--- a/smtk/task/operators/ConnectPorts.cxx
+++ b/smtk/task/operators/ConnectPorts.cxx
@@ -122,7 +122,7 @@ bool ConnectPorts::ableToOperate()
   return this->Superclass::ableToOperate();
 }
 
-ConnectPorts::Result ConnectPorts::operateInternal()
+ConnectPorts::Result ConnectPorts::operateInternal(Context ctx)
 {
   auto fromPorts = this->parameters()->associations();
   auto toPorts = this->parameters()->findComponent("to");
diff --git a/smtk/task/operators/ConnectPorts.h b/smtk/task/operators/ConnectPorts.h
index 72d03ac10a60a00508707a58e9af365eac069c20..ee0ff7f846a56481d69ce415e8f4fde4ff87b110 100644
--- a/smtk/task/operators/ConnectPorts.h
+++ b/smtk/task/operators/ConnectPorts.h
@@ -40,7 +40,7 @@ public:
   bool ableToOperate() override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/task/operators/DisconnectPorts.cxx b/smtk/task/operators/DisconnectPorts.cxx
index 378c443b3331aa10078b656e8cca36bfa90b7067..f00f5685dc71a443516b3dd55ddbfd7efa212396 100644
--- a/smtk/task/operators/DisconnectPorts.cxx
+++ b/smtk/task/operators/DisconnectPorts.cxx
@@ -79,7 +79,7 @@ bool DisconnectPorts::ableToOperate()
   return this->Superclass::ableToOperate();
 }
 
-DisconnectPorts::Result DisconnectPorts::operateInternal()
+DisconnectPorts::Result DisconnectPorts::operateInternal(Context ctx)
 {
   Result result = this->createResult(smtk::operation::Operation::Outcome::SUCCEEDED);
   auto modified = result->findComponent("modified");
diff --git a/smtk/task/operators/DisconnectPorts.h b/smtk/task/operators/DisconnectPorts.h
index ef9958bcd97f878822f951160b7203de9fa0fb7d..639b0f7c45369e3a21a409ffc631c145f819301a 100644
--- a/smtk/task/operators/DisconnectPorts.h
+++ b/smtk/task/operators/DisconnectPorts.h
@@ -40,7 +40,7 @@ public:
   bool ableToOperate() override;
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/task/operators/EmplaceWorklet.cxx b/smtk/task/operators/EmplaceWorklet.cxx
index 7bc21cddae31c5bc15f0bb2be63fc317799e47e6..58572fefdc580cc3fe35dc7e849fd1909d4a9ddf 100644
--- a/smtk/task/operators/EmplaceWorklet.cxx
+++ b/smtk/task/operators/EmplaceWorklet.cxx
@@ -49,7 +49,7 @@ namespace smtk
 namespace task
 {
 
-EmplaceWorklet::Result EmplaceWorklet::operateInternal()
+EmplaceWorklet::Result EmplaceWorklet::operateInternal(Context ctx)
 {
   auto worklet = this->parameters()->associations()->valueAs<smtk::task::Worklet>();
   auto project = worklet ? dynamic_pointer_cast<smtk::project::Project>(worklet->resource())
diff --git a/smtk/task/operators/EmplaceWorklet.h b/smtk/task/operators/EmplaceWorklet.h
index f1f3971a484dd6343d24f7dcab2b5d3771dc1981..3b1227e633dcd14a92da92b64e99df163653dec2 100644
--- a/smtk/task/operators/EmplaceWorklet.h
+++ b/smtk/task/operators/EmplaceWorklet.h
@@ -32,7 +32,7 @@ public:
   smtkCreateMacro(EmplaceWorklet);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/task/operators/RemoveDependency.cxx b/smtk/task/operators/RemoveDependency.cxx
index 81b780934a04c9269c120f1c6c81742d36ed22d9..15bbca88205f4358f023662b16494bce43d649bd 100644
--- a/smtk/task/operators/RemoveDependency.cxx
+++ b/smtk/task/operators/RemoveDependency.cxx
@@ -44,7 +44,7 @@ namespace smtk
 namespace task
 {
 
-RemoveDependency::Result RemoveDependency::operateInternal()
+RemoveDependency::Result RemoveDependency::operateInternal(Context ctx)
 {
   // First, accumulate task pairs while validating that all dependencies exist.
   auto endpoints = this->parameters()->findGroup("task endpoints");
diff --git a/smtk/task/operators/RemoveDependency.h b/smtk/task/operators/RemoveDependency.h
index 960d8f69f0c47abd5b4ad1bddc3a9519ae78758f..9d593f7c249e40ba21cea4337432dd2626e49221 100644
--- a/smtk/task/operators/RemoveDependency.h
+++ b/smtk/task/operators/RemoveDependency.h
@@ -32,7 +32,7 @@ public:
   smtkCreateMacro(RemoveDependency);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/task/operators/RenameTask.cxx b/smtk/task/operators/RenameTask.cxx
index 54ca98c27a11ed8d0e2535b3b13eeca18c609d24..d49c3ceda736e98bb2a024c15fe116ce658f3fbd 100644
--- a/smtk/task/operators/RenameTask.cxx
+++ b/smtk/task/operators/RenameTask.cxx
@@ -44,7 +44,7 @@ namespace smtk
 namespace task
 {
 
-RenameTask::Result RenameTask::operateInternal()
+RenameTask::Result RenameTask::operateInternal(Context ctx)
 {
   auto task = this->parameters()->associations()->valueAs<smtk::task::Task>();
   auto project = task ? dynamic_pointer_cast<smtk::project::Project>(task->resource())
diff --git a/smtk/task/operators/RenameTask.h b/smtk/task/operators/RenameTask.h
index 5c30ad6e342f029eae378295f2d610a4dc15503b..99f228ae02ad144ff4969cb5be88a7a2ad4a3be3 100644
--- a/smtk/task/operators/RenameTask.h
+++ b/smtk/task/operators/RenameTask.h
@@ -36,7 +36,7 @@ public:
   void setTask(const Task::Ptr& task);
 
 protected:
-  Result operateInternal() override;
+  Result operateInternal(Context ctx) override;
   const char* xmlDescription() const override;
 };
 
diff --git a/smtk/task/pybind11/PybindGatherObjectsAgent.h b/smtk/task/pybind11/PybindGatherObjectsAgent.h
index 4e64296f5542e4880b06bda85a301f19e7e7409f..f690f92d0130be6e55830bf478b64bfe5288d7b3 100644
--- a/smtk/task/pybind11/PybindGatherObjectsAgent.h
+++ b/smtk/task/pybind11/PybindGatherObjectsAgent.h
@@ -20,37 +20,45 @@
 
 namespace py = pybind11;
 
-inline py::class_< smtk::task::GatherObjectsAgent, smtk::task::Agent > pybind11_init_smtk_task_GatherObjectsAgent(py::module &m)
+inline py::class_<smtk::task::GatherObjectsAgent, smtk::task::Agent>
+pybind11_init_smtk_task_GatherObjectsAgent(py::module& m)
 {
-  py::class_< smtk::task::GatherObjectsAgent, smtk::task::Agent > instance(m, "GatherObjectsAgent");
-  instance
-    .def("typeName", &smtk::task::GatherObjectsAgent::typeName)
-    .def("addObjectInRole", [](
+  py::class_<smtk::task::GatherObjectsAgent, smtk::task::Agent> instance(m, "GatherObjectsAgent");
+  instance.def("typeName", &smtk::task::GatherObjectsAgent::typeName)
+    .def(
+      "addObjectInRole",
+      [](
         smtk::task::GatherObjectsAgent& self,
         const smtk::resource::PersistentObject::Ptr& object,
         smtk::string::Token role,
-        bool signal)
-      {
-        return self.addObjectInRole(object.get(), role, signal);
-      }, py::arg("object"), py::arg("role"), py::arg("signal") = false)
-    .def("removeObjectFromRole", [](
+        bool signal) { return self.addObjectInRole(object.get(), role, signal); },
+      py::arg("object"),
+      py::arg("role"),
+      py::arg("signal") = false)
+    .def(
+      "removeObjectFromRole",
+      [](
         smtk::task::GatherObjectsAgent& self,
         const smtk::resource::PersistentObject::Ptr& object,
         smtk::string::Token role,
-        bool signal)
-      {
-        return self.removeObjectFromRole(object.get(), role, signal);
-      }, py::arg("object"), py::arg("role"), py::arg("signal") = false)
-    .def("clearOutputPort", &smtk::task::GatherObjectsAgent::clearOutputPort, py::arg("signal") = false)
-    .def("outputPort", [](smtk::task::GatherObjectsAgent& self)
-      {
-        return self.outputPort()->shared_from_this();
-      })
-    .def("data", [](smtk::task::GatherObjectsAgent& self)
-      {
-        return self.portData(self.outputPort());
-      }, py::return_value_policy::reference_internal)
-    ;
+        bool signal) { return self.removeObjectFromRole(object.get(), role, signal); },
+      py::arg("object"),
+      py::arg("role"),
+      py::arg("signal") = false)
+    //.def("clearOutputPort", &smtk::task::GatherObjectsAgent::clearOutputPort, py::arg("signal") = false, smtk::common::Context())
+    .def(
+      "clearOutputPort",
+      [](smtk::task::GatherObjectsAgent& self, bool signal) {
+        return self.clearOutputPort(signal);
+      },
+      py::arg("signal") = false)
+    .def(
+      "outputPort",
+      [](smtk::task::GatherObjectsAgent& self) { return self.outputPort()->shared_from_this(); })
+    .def(
+      "data",
+      [](smtk::task::GatherObjectsAgent& self) { return self.portData(self.outputPort()); },
+      py::return_value_policy::reference_internal);
   return instance;
 }
 
diff --git a/smtk/task/testing/cxx/TestConfigureOperation.cxx b/smtk/task/testing/cxx/TestConfigureOperation.cxx
index 44e77349855d2939a825f577bfa798ff09d12a64..428c64cd63a8041d7a553e486a63a7959499ae58 100644
--- a/smtk/task/testing/cxx/TestConfigureOperation.cxx
+++ b/smtk/task/testing/cxx/TestConfigureOperation.cxx
@@ -170,7 +170,7 @@ public:
     return spec;
   }
 
-  Result operateInternal() override
+  Result operateInternal(Context ctx) override
   {
     std::cerr << "Running SimpleOperation!\n";
     return this->createResult(m_outcome);
diff --git a/smtk/task/testing/cxx/TestTaskPorts.cxx b/smtk/task/testing/cxx/TestTaskPorts.cxx
index 327385da40e5d25d02c1b89476d54fc967f7665d..9828ac38d00e720dc037876e6cbfe9ab67f54504 100644
--- a/smtk/task/testing/cxx/TestTaskPorts.cxx
+++ b/smtk/task/testing/cxx/TestTaskPorts.cxx
@@ -247,7 +247,7 @@ int TestTaskPorts(int, char*[])
   attInPort->connections().insert(attrib.get());
   // Signal that connections have been modified.
   // This should cause a change in state.
-  fillOutAttributes->portDataUpdated(attInPort);
+  fillOutAttributes->portDataUpdated(smtk::common::Context(), attInPort);
 
   printTaskStates(taskManager);
   test(
diff --git a/smtk/view/PhraseModel.cxx b/smtk/view/PhraseModel.cxx
index 83f503cb8699801d55ce5b8e8e975efc7f130a6b..f5ae12b9d9f35973e8c9bbcd2aaae9becfdc6020 100644
--- a/smtk/view/PhraseModel.cxx
+++ b/smtk/view/PhraseModel.cxx
@@ -242,16 +242,19 @@ bool PhraseModel::addSource(const smtk::common::TypeContainer& managers)
                                 false, // observeImmediately
                                 description.str() + "Update phrases when resources change.")
                             : smtk::resource::Observers::Key();
-  auto operHandle = operMgr
-    ? operMgr->observers().insert(
-        [this](const Operation& op, operation::EventType event, const Operation::Result& res) {
-          this->handleOperationEvent(op, event, res);
-          return 0;
-        },
-        PhraseModel::operationObserverPriority(),
-        /*initialize*/ true,
-        description.str() + "Update phrases based on operation results.")
-    : smtk::operation::Observers::Key();
+  auto operHandle = operMgr ? operMgr->observers().insert(
+                                [this](
+                                  smtk::common::Context ctx,
+                                  const Operation& op,
+                                  operation::EventType event,
+                                  const Operation::Result& res) {
+                                  this->handleOperationEvent(op, event, res);
+                                  return 0;
+                                },
+                                PhraseModel::operationObserverPriority(),
+                                /*initialize*/ true,
+                                description.str() + "Update phrases based on operation results.")
+                            : smtk::operation::Observers::Key();
   auto selnHandle = seln ? seln->observers().insert(
                              [this](const std::string& src, smtk::view::SelectionPtr seln) {
                                this->handleSelectionEvent(src, seln);