diff --git a/source/RobotAPI/libraries/skills_gui/CMakeLists.txt b/source/RobotAPI/libraries/skills_gui/CMakeLists.txt
index 6d4e90f1733417f277f76c304b3dde8f520be10e..e446267a7428837d49f8949cac20a9dda6da3e56 100644
--- a/source/RobotAPI/libraries/skills_gui/CMakeLists.txt
+++ b/source/RobotAPI/libraries/skills_gui/CMakeLists.txt
@@ -48,6 +48,9 @@ set(SOURCES
     skill_executions/SkillExecutionTreeWidgetItem.cpp
 
     memory/SkillMemoryProxy.cpp
+    memory/MemoryCommunicatorBase.cpp
+
+    skills/SkillTreeWidget.cpp
 )
 set(HEADERS
     aron_tree_widget/visitors/AronTreeWidgetCreator.h
@@ -77,6 +80,9 @@ set(HEADERS
     skill_executions/SkillExecutionTreeWidgetItem.h
 
     memory/SkillMemoryProxy.h
+    memory/MemoryCommunicatorBase.h
+
+    skills/SkillTreeWidget.h
 )
 
 armarx_gui_library("${LIB_NAME}" "${SOURCES}" "${GUI_MOC_HDRS}" "${GUI_UIS}" "" "${LIBRARIES}")
diff --git a/source/RobotAPI/libraries/skills_gui/memory/MemoryCommunicatorBase.cpp b/source/RobotAPI/libraries/skills_gui/memory/MemoryCommunicatorBase.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5950600afad2f71a04b0997885d986a23d82d824
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/memory/MemoryCommunicatorBase.cpp
@@ -0,0 +1 @@
+#include "MemoryCommunicatorBase.h"
diff --git a/source/RobotAPI/libraries/skills_gui/memory/MemoryCommunicatorBase.h b/source/RobotAPI/libraries/skills_gui/memory/MemoryCommunicatorBase.h
new file mode 100644
index 0000000000000000000000000000000000000000..2fce5940100c5f89e0bfa8a235dabd2caab2ffcc
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/memory/MemoryCommunicatorBase.h
@@ -0,0 +1,22 @@
+#ifndef MEMORYCOMMUNICATOR_H
+#define MEMORYCOMMUNICATOR_H
+
+#include "SkillMemoryProxy.h"
+
+namespace armarx::skills::gui
+{
+    /*
+     * This base class holds a skill memory proxy.
+     */
+    class MemoryCommunicatorBase
+    {
+    protected:
+        // We don't want to instantiate the base class
+        MemoryCommunicatorBase(std::shared_ptr<SkillMemoryProxy> _memory) : memory(_memory)
+        {
+        }
+        std::shared_ptr<SkillMemoryProxy> memory;
+    };
+} // namespace armarx::skills::gui
+
+#endif // MEMORYCOMMUNICATOR_H
diff --git a/source/RobotAPI/libraries/skills_gui/memory/SkillMemoryProxy.h b/source/RobotAPI/libraries/skills_gui/memory/SkillMemoryProxy.h
index 3bb6ff4c016afb130a3c47e8a98b7b1801de2043..d5ba4676b14ee9e7956b717328b1603edf0648c0 100644
--- a/source/RobotAPI/libraries/skills_gui/memory/SkillMemoryProxy.h
+++ b/source/RobotAPI/libraries/skills_gui/memory/SkillMemoryProxy.h
@@ -51,7 +51,7 @@ namespace armarx::skills::gui
 
         /*
          * Returns a snapshot, which contains the most current update from memory.
-         * Calling this function will not use an Ice call!
+         * Calling this function will *not* use an Ice call!
          * Use this instead of holding the state in a widget.
          */
         Snapshot& getLatestUpdate();
@@ -65,7 +65,8 @@ namespace armarx::skills::gui
         void fetchUpdates();
 
     private:
-        skills::dti::SkillMemoryInterfacePrx* memory = nullptr;
+        mutable std::mutex updateMutex;
+        skills::dti::SkillMemoryInterfacePrx* memory;
         Snapshot snapshot;
     };
 } // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/skill_executions/SkillExecutionTreeWidget.h b/source/RobotAPI/libraries/skills_gui/skill_executions/SkillExecutionTreeWidget.h
index dac8bb0391b9343496fb88be4b098d2858c2488e..d8a23d34496aebebca3703b9db3f8f35b8b2a843 100644
--- a/source/RobotAPI/libraries/skills_gui/skill_executions/SkillExecutionTreeWidget.h
+++ b/source/RobotAPI/libraries/skills_gui/skill_executions/SkillExecutionTreeWidget.h
@@ -7,14 +7,16 @@
 
 #include "RobotAPI/libraries/skills/core/SkillExecutionID.h"
 
+#include "../memory/MemoryCommunicatorBase.h"
 #include "SkillExecutionTreeWidgetItem.h"
 
 namespace armarx::skills::gui
 {
-    class SkillExecutionTreeWidget : public QTreeWidget
+    class SkillExecutionTreeWidget : public QTreeWidget, public MemoryCommunicatorBase
     {
     public:
-        SkillExecutionTreeWidget(QWidget* parent) : QTreeWidget(parent)
+        SkillExecutionTreeWidget(QWidget* parent, std::shared_ptr<SkillMemoryProxy> _memory) :
+            QTreeWidget(parent), MemoryCommunicatorBase(_memory)
         {
         }
 
diff --git a/source/RobotAPI/libraries/skills_gui/skill_executions/SkillExecutionTreeWidgetItem.h b/source/RobotAPI/libraries/skills_gui/skill_executions/SkillExecutionTreeWidgetItem.h
index 035a26ada75478d476cb975cb0c34a510c8b292f..ef160643c4f0c4c27a773e412a45c2647b7559b3 100644
--- a/source/RobotAPI/libraries/skills_gui/skill_executions/SkillExecutionTreeWidgetItem.h
+++ b/source/RobotAPI/libraries/skills_gui/skill_executions/SkillExecutionTreeWidgetItem.h
@@ -6,23 +6,20 @@
 #include <RobotAPI/libraries/skills/core/SkillExecutionID.h>
 #include <RobotAPI/libraries/skills/core/SkillStatusUpdate.h>
 
+#include "../memory/MemoryCommunicatorBase.h"
 #include "SkillExecutionTreeWidgetItem.h"
 
 namespace armarx::skills::gui
 {
-    class SkillExecutionTreeWidgetItem : QTreeWidgetItem
+    class SkillExecutionTreeWidgetItem : QTreeWidgetItem, public MemoryCommunicatorBase
     {
     public:
         SkillExecutionTreeWidgetItem() = delete;
 
         // After constructing an item, it must be manually inserted into the tree!
-        SkillExecutionTreeWidgetItem(const skills::SkillExecutionID& id) : executionId(id)
-        {
-        }
-
-        // When using this constructor, the new item will be appended to the bottom of the tree
-        SkillExecutionTreeWidgetItem(const skills::SkillExecutionID& id, QTreeWidget* parent) :
-            QTreeWidgetItem(parent), executionId(id)
+        SkillExecutionTreeWidgetItem(const skills::SkillExecutionID& id,
+                                     std::shared_ptr<SkillMemoryProxy> _memory) :
+            MemoryCommunicatorBase(_memory), executionId(id)
         {
         }
 
@@ -36,8 +33,7 @@ namespace armarx::skills::gui
     private slots:
         void runContextMenu(const QPoint& pos);
 
-    private:
-        // private since we don't want to overwrite the executionId
+    protected:
         skills::SkillExecutionID executionId;
     };
 } // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidget.cpp b/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidget.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d848b4d62869284c8541e7d673873f3112c1150d
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidget.cpp
@@ -0,0 +1 @@
+#include "SkillTreeWidget.h"
diff --git a/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidget.h b/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidget.h
new file mode 100644
index 0000000000000000000000000000000000000000..ae47f1a364d434b48518d3c4d433c42f7e61842b
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidget.h
@@ -0,0 +1,21 @@
+#ifndef ARMARX_SKILLS_GUI_SKILLTREEWIDGET_H
+#define ARMARX_SKILLS_GUI_SKILLTREEWIDGET_H
+
+#include <QTreeWidget>
+
+#include "../memory/MemoryCommunicatorBase.h"
+
+namespace armarx::skills::gui
+{
+    class SkillTreeWidget : public QTreeWidget, public MemoryCommunicatorBase
+    {
+    public:
+        SkillTreeWidget(QWidget* parent, std::shared_ptr<SkillMemoryProxy> _memory) :
+            QTreeWidget(parent), MemoryCommunicatorBase(_memory)
+        {
+        }
+    };
+
+} // namespace armarx::skills::gui
+
+#endif // ARMARX_SKILLS_GUI_SKILLTREEWIDGET_H