diff --git a/source/RobotAPI/gui-plugins/ArMemMemoryViewer/ArMemMemoryViewerWidgetController.cpp b/source/RobotAPI/gui-plugins/ArMemMemoryViewer/ArMemMemoryViewerWidgetController.cpp
index ff461269fd3c68bf57c6c69d77116c62dc807d5c..8d7c5a48cb0bb387f21b4a9495bbc73f3e9f1c9b 100644
--- a/source/RobotAPI/gui-plugins/ArMemMemoryViewer/ArMemMemoryViewerWidgetController.cpp
+++ b/source/RobotAPI/gui-plugins/ArMemMemoryViewer/ArMemMemoryViewerWidgetController.cpp
@@ -22,44 +22,42 @@
 
 #include "ArMemMemoryViewerWidgetController.h"
 
-#include <RobotAPI/libraries/armem_gui/gui_utils.h>
-
 #include <string>
 
+#include <RobotAPI/libraries/armem_gui/gui_utils.h>
 
 namespace armarx
 {
 
-    QString ArMemMemoryViewerWidgetController::GetWidgetName()
+    QString
+    ArMemMemoryViewerWidgetController::GetWidgetName()
     {
         return "ArMem.MemoryViewer";
     }
 
-
-    QIcon ArMemMemoryViewerWidgetController::GetWidgetIcon()
+    QIcon
+    ArMemMemoryViewerWidgetController::GetWidgetIcon()
     {
         return QIcon(":icons/memory-128.png");
     }
 
-
     ArMemMemoryViewerWidgetController::ArMemMemoryViewerWidgetController()
     {
         widget.setupUi(getWidget());
 
         viewer = std::make_unique<MemoryViewer>(
 
-                     widget.updateWidgetLayout,
+            widget.updateWidgetLayout,
 
-                     widget.memoryGroupBox,
-                     widget.treesLayout,
+            widget.memoryGroupBox,
+            widget.treesLayout,
 
-                     widget.instanceGroupBox,
-                     widget.treesLayout,
+            widget.instanceGroupBox,
+            widget.treesLayout,
 
-                     widget.diskControlWidgetLayout,
+            widget.diskControlWidgetLayout,
 
-                     widget.statusLabel
-                 );
+            widget.statusLabel);
         viewer->setLogTag("ArMem Memory Viewer");
 
         armarx::gui::useSplitter(widget.treesLayout);
@@ -71,33 +69,38 @@ namespace armarx
     {
     }
 
-
-    void ArMemMemoryViewerWidgetController::onInitComponent()
+    void
+    ArMemMemoryViewerWidgetController::onInitComponent()
     {
         emit lifecycleServer.initialized(this);
     }
 
-    void ArMemMemoryViewerWidgetController::onConnectComponent()
+    void
+    ArMemMemoryViewerWidgetController::onConnectComponent()
     {
         emit lifecycleServer.connected(this);
     }
 
-    void ArMemMemoryViewerWidgetController::onDisconnectComponent()
+    void
+    ArMemMemoryViewerWidgetController::onDisconnectComponent()
     {
         emit lifecycleServer.disconnected(this);
     }
 
-
-    void ArMemMemoryViewerWidgetController::loadSettings(QSettings* settings)
+    void
+    ArMemMemoryViewerWidgetController::loadSettings(QSettings* settings)
     {
         viewer->loadSettings(settings);
     }
-    void ArMemMemoryViewerWidgetController::saveSettings(QSettings* settings)
+
+    void
+    ArMemMemoryViewerWidgetController::saveSettings(QSettings* settings)
     {
         viewer->saveSettings(settings);
     }
 
-    QPointer<QDialog> ArMemMemoryViewerWidgetController::getConfigDialog(QWidget* parent)
+    QPointer<QDialog>
+    ArMemMemoryViewerWidgetController::getConfigDialog(QWidget* parent)
     {
         if (!configDialog)
         {
@@ -107,11 +110,12 @@ namespace armarx
         return qobject_cast<QDialog*>(configDialog);
     }
 
-    void ArMemMemoryViewerWidgetController::configured()
+    void
+    ArMemMemoryViewerWidgetController::configured()
     {
         if (configDialog)
         {
             viewer->readConfigDialog(configDialog.data());
         }
     }
-}
+} // namespace armarx
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/CMakeLists.txt b/source/RobotAPI/gui-plugins/SkillManagerPlugin/CMakeLists.txt
index 5df70b65810beeead4599151d25b15960a26e615..fae8ace92bdcf18f9e15018a3d38bf8ec025c141 100644
--- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/CMakeLists.txt
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/CMakeLists.txt
@@ -28,6 +28,7 @@ set(SOURCES
     ColorPalettes.cpp
     SkillManagerMonitorWidgetController.cpp
     PeriodicUpdateWidget.cpp
+    #SkillExecutionTreeWidget.cpp
 )
 
 set(HEADERS
@@ -55,6 +56,7 @@ set(HEADERS
     ColorPalettes.h
     SkillManagerMonitorWidgetController.h
     PeriodicUpdateWidget.h
+    #SkillExecutionTreeWidget.h
 )
 
 set(GUI_UIS
@@ -70,6 +72,7 @@ set(COMPONENT_LIBS
     SkillsMemory
     aronjsonconverter
     SimpleConfigDialog
+    skills_gui
 )
 
 if(ArmarXGui_FOUND)
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidget.ui b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidget.ui
index 82569fa85833ef3eb89476da914b7ba02606864b..88daea56ca801bdcd88785d54cb748c97b5e8ebc 100644
--- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidget.ui
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidget.ui
@@ -19,7 +19,7 @@
   <property name="windowTitle">
    <string>SkillManagerMonitorWidget</string>
   </property>
-  <layout class="QGridLayout" name="gridLayout_3" rowstretch="0,0,0,0">
+  <layout class="QGridLayout" name="gridLayout_3" rowstretch="0,0,0,0,0,0">
    <item row="3" column="0" colspan="2">
     <widget class="QSplitter" name="splitter_2">
      <property name="enabled">
@@ -97,44 +97,7 @@
        <property name="title">
         <string>Manager</string>
        </property>
-       <layout class="QGridLayout" name="gridLayout">
-        <item row="5" column="0" colspan="3">
-         <widget class="QTreeWidget" name="treeWidgetSkills">
-          <column>
-           <property name="text">
-            <string>Skill</string>
-           </property>
-          </column>
-          <column>
-           <property name="text">
-            <string>HasInputType</string>
-           </property>
-          </column>
-          <column>
-           <property name="text">
-            <string>HasOutputType</string>
-           </property>
-          </column>
-         </widget>
-        </item>
-        <item row="4" column="1">
-         <widget class="QPushButton" name="pushButtonSearch">
-          <property name="text">
-           <string>Search</string>
-          </property>
-         </widget>
-        </item>
-        <item row="4" column="0">
-         <widget class="QLineEdit" name="lineEditSearch">
-          <property name="text">
-           <string/>
-          </property>
-          <property name="placeholderText">
-           <string>Search...</string>
-          </property>
-         </widget>
-        </item>
-       </layout>
+       <layout class="QGridLayout" name="gridLayout"/>
       </widget>
       <widget class="QGroupBox" name="groupBoxSkillDetails">
        <property name="enabled">
@@ -149,140 +112,7 @@
        <property name="title">
         <string>Skill Details</string>
        </property>
-       <layout class="QVBoxLayout" name="verticalLayout">
-        <item>
-         <widget class="QSplitter" name="splitter_2">
-          <property name="enabled">
-           <bool>true</bool>
-          </property>
-          <property name="sizePolicy">
-           <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
-            <horstretch>0</horstretch>
-            <verstretch>0</verstretch>
-           </sizepolicy>
-          </property>
-          <property name="orientation">
-           <enum>Qt::Vertical</enum>
-          </property>
-          <property name="childrenCollapsible">
-           <bool>false</bool>
-          </property>
-          <widget class="QWidget" name="groupBoxSkillDetailsTop" native="true">
-           <layout class="QVBoxLayout" name="verticalLayout_2">
-            <property name="leftMargin">
-             <number>0</number>
-            </property>
-            <property name="topMargin">
-             <number>0</number>
-            </property>
-            <property name="rightMargin">
-             <number>0</number>
-            </property>
-            <property name="bottomMargin">
-             <number>0</number>
-            </property>
-            <item>
-             <layout class="QGridLayout" name="gridLayout_5">
-              <item row="0" column="0">
-               <widget class="QPushButton" name="pushButtonPaste">
-                <property name="text">
-                 <string>Set args from clipboard</string>
-                </property>
-               </widget>
-              </item>
-              <item row="0" column="3">
-               <widget class="QPushButton" name="pushButtonReset">
-                <property name="text">
-                 <string>Reset args to profile</string>
-                </property>
-               </widget>
-              </item>
-              <item row="1" column="0" colspan="4">
-               <widget class="QComboBox" name="comboBoxProfiles">
-                <item>
-                 <property name="text">
-                  <string>&lt;No Profile selected. Using root&gt;</string>
-                 </property>
-                </item>
-               </widget>
-              </item>
-              <item row="0" column="1">
-               <widget class="QPushButton" name="pushButtonCopy">
-                <property name="text">
-                 <string>Copy args to clipboard</string>
-                </property>
-               </widget>
-              </item>
-              <item row="0" column="2">
-               <widget class="QLabel" name="label_2">
-                <property name="text">
-                 <string/>
-                </property>
-               </widget>
-              </item>
-             </layout>
-            </item>
-            <item>
-             <widget class="QWidget" name="skillDescription" native="true"/>
-            </item>
-           </layout>
-          </widget>
-          <widget class="QWidget" name="groupBoxSkillDetailsBottom" native="true">
-           <layout class="QVBoxLayout" name="verticalLayout_3">
-            <property name="leftMargin">
-             <number>0</number>
-            </property>
-            <property name="topMargin">
-             <number>0</number>
-            </property>
-            <property name="rightMargin">
-             <number>0</number>
-            </property>
-            <property name="bottomMargin">
-             <number>0</number>
-            </property>
-            <item>
-             <widget class="QTreeWidget" name="treeWidgetSkillDetails">
-              <property name="contextMenuPolicy">
-               <enum>Qt::CustomContextMenu</enum>
-              </property>
-              <property name="editTriggers">
-               <set>QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed</set>
-              </property>
-              <column>
-               <property name="text">
-                <string>Key</string>
-               </property>
-              </column>
-              <column>
-               <property name="text">
-                <string>Value</string>
-               </property>
-              </column>
-              <column>
-               <property name="text">
-                <string>Type</string>
-               </property>
-              </column>
-              <column>
-               <property name="text">
-                <string>defaultValue (hidden in GUI)</string>
-               </property>
-              </column>
-             </widget>
-            </item>
-            <item>
-             <widget class="QPushButton" name="pushButtonExecuteSkill">
-              <property name="text">
-               <string>Request Execution</string>
-              </property>
-             </widget>
-            </item>
-           </layout>
-          </widget>
-         </widget>
-        </item>
-       </layout>
+       <layout class="QVBoxLayout" name="verticalLayout"/>
       </widget>
      </widget>
     </widget>
@@ -331,6 +161,13 @@
      </item>
     </layout>
    </item>
+   <item row="5" column="0" colspan="2">
+    <widget class="QLabel" name="connectionStatusLabel">
+     <property name="text">
+      <string>(hidden in GUI)</string>
+     </property>
+    </widget>
+   </item>
   </layout>
  </widget>
  <resources/>
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp
index bbeaa5a4d9a889808db465419f732e5903031a31..245ea08034c8c5aa912447fce57fdbe7d7efb58f 100644
--- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp
@@ -22,6 +22,7 @@
 
 #include "SkillManagerMonitorWidgetController.h"
 
+#include <memory>
 #include <optional>
 #include <regex>
 #include <string>
@@ -31,7 +32,6 @@
 #include <RobotAPI/libraries/skills/core/Skill.h>
 
 #include "aronTreeWidget/visitors/AronTreeWidgetConverter.h"
-#include "aronTreeWidget/visitors/AronTreeWidgetCreator.h"
 #include "aronTreeWidget/visitors/AronTreeWidgetModalCreator.h"
 
 // modals
@@ -51,7 +51,6 @@
 
 #include "aronTreeWidget/Data.h"
 #include "aronTreeWidget/modal/text/AronTreeWidgetTextInputModalController.h"
-#include "aronTreeWidget/visitors/AronTreeWidgetConverter.h"
 #include "aronTreeWidget/visitors/AronTreeWidgetCreator.h"
 #include "aronTreeWidget/visitors/AronTreeWidgetModalCreator.h"
 #include "aronTreeWidget/widgets/SkillDescriptionWidget.h"
@@ -59,8 +58,6 @@
 //configSk
 namespace armarx
 {
-    const skills::SkillID SkillManagerMonitorWidgetController::SelectedSkill::UNK_SKILL_ID =
-        skills::SkillID{.providerId = ::std::nullopt, .skillName = skills::SkillID::UNKNOWN};
 
     QPointer<QDialog>
     SkillManagerMonitorWidgetController::getConfigDialog(QWidget* parent)
@@ -68,7 +65,7 @@ namespace armarx
         if (!dialog)
         {
             dialog = new SimpleConfigDialog(parent);
-            dialog->addProxyFinder<skills::dti::SkillMemoryInterfacePrx>(
+            dialog->addProxyFinder<skills::manager::dti::SkillManagerInterfacePrx>(
                 "SkillMemory", "", "SkillMem*");
         }
         return qobject_cast<SimpleConfigDialog*>(dialog);
@@ -96,728 +93,81 @@ namespace armarx
 // Others
 namespace armarx
 {
-    void
-    SkillManagerMonitorWidgetController::prepareAndRunMenu(const QPoint& pos)
-    {
-        QMenu* menu = new QMenu();
-
-        // Stop skill
-        QAction* stopSkillAction = new QAction("Stop execution", this);
-        skills::SkillStatus currentStatus =
-            skillStatusUpdates.at(selectedSkill.skillExecutionId).status;
-        stopSkillAction->setDisabled(currentStatus == skills::SkillStatus::Aborted ||
-                                     currentStatus == skills::SkillStatus::Failed ||
-                                     currentStatus == skills::SkillStatus::Succeeded);
-
-        QAction* rerunSkillAction = new QAction("Re-run with similar params", this);
-        menu->addAction(stopSkillAction);
-        menu->addAction(rerunSkillAction);
-        connect(stopSkillAction,
-                &QAction::triggered,
-                this,
-                &SkillManagerMonitorWidgetController::stopSkill);
-        connect(rerunSkillAction,
-                &QAction::triggered,
-                this,
-                &SkillManagerMonitorWidgetController::rerunSkillWithSimilarParams);
-
-        // Temporarily disable rerun-skill-Action
-        rerunSkillAction->setDisabled(true);
-
-        // open menu
-        menu->popup(widget.treeWidgetSkillExecutions->viewport()->mapToGlobal(pos));
-    }
-
-    SkillExecutionInfoTreeWidgetItem*
-    SkillExecutionInfoTreeWidgetItem::SearchRecursiveForMatch(
-        SkillExecutionInfoTreeWidgetItem* haystack,
-        const skills::SkillExecutionID& needle)
-    {
-        if (!haystack)
-        {
-            return nullptr;
-        }
-
-        if (needle == haystack->executionId)
-        {
-            return haystack;
-        }
-        for (int i = 0; i < haystack->childCount(); ++i)
-        {
-            auto el = static_cast<SkillExecutionInfoTreeWidgetItem*>(haystack->child(i));
-            return SkillExecutionInfoTreeWidgetItem::SearchRecursiveForMatch(el, needle);
-        }
-        return nullptr;
-    }
-
     SkillManagerMonitorWidgetController::SkillManagerMonitorWidgetController()
     {
-        widget.setupUi(getWidget());
-        this->updateWidget = new PeriodicUpdateWidget(2.0, 60);
-        widget.updateWidgetLayout->insertWidget(0, updateWidget);
-
-        this->stopAllButton = new QPushButton("Stop all executions");
-        widget.stopAllLayout->addWidget(stopAllButton);
-
-
-        skillDescriptionWidget = new SkillDescriptionWidget();
-        widget.skillDescription->parentWidget()->layout()->replaceWidget(widget.skillDescription,
-                                                                         skillDescriptionWidget);
-        widget.skillDescription = skillDescriptionWidget;
-
-
-        connect(this->stopAllButton,
-                &QPushButton::clicked,
-                this,
-                &SkillManagerMonitorWidgetController::stopAllExecutions);
-        connect(widget.treeWidgetSkillExecutions,
-                &QTreeWidget::customContextMenuRequested,
-                this,
-                &SkillManagerMonitorWidgetController::prepareAndRunMenu);
-
-        connect(updateWidget,
-                &armarx::PeriodicUpdateWidget::update,
-                this,
-                &SkillManagerMonitorWidgetController::refreshSkillsAndExecutions);
-
-        connect(widget.pushButtonCopy,
-                &QPushButton::clicked,
-                this,
-                &SkillManagerMonitorWidgetController::copyCurrentConfig);
-        connect(widget.pushButtonPaste,
-                &QPushButton::clicked,
-                this,
-                &SkillManagerMonitorWidgetController::pasteCurrentConfig);
-
-        connect(widget.pushButtonExecuteSkill,
-                &QPushButton::clicked,
-                this,
-                &SkillManagerMonitorWidgetController::executeSelectedSkill);
-
-        connect(widget.treeWidgetSkills,
-                &QTreeWidget::currentItemChanged,
-                this,
-                &SkillManagerMonitorWidgetController::skillSelectionChanged);
-
-        connect(widget.treeWidgetSkillExecutions,
-                &QTreeWidget::currentItemChanged,
-                this,
-                &SkillManagerMonitorWidgetController::skillExecutionSelectionChanged);
-
-        /*connect(widget.pushButtonRefreshNow,
-                &QPushButton::clicked,
-                this,
-                &SkillManagerMonitorWidgetController::refreshSkills);*/
-        connect(widget.pushButtonSearch,
-                &QPushButton::clicked,
-                this,
-                &SkillManagerMonitorWidgetController::searchSkills);
-        // alternatively run search when pressing enter
-        connect(widget.lineEditSearch,
-                &QLineEdit::returnPressed,
-                this,
-                &SkillManagerMonitorWidgetController::searchSkills);
-    }
-
-    SkillManagerMonitorWidgetController::~SkillManagerMonitorWidgetController()
-    {
-    }
-
-    void
-    SkillManagerMonitorWidgetController::onInitComponent()
-    {
-        usingProxy(observerName);
-    }
-
-    void
-    SkillManagerMonitorWidgetController::onConnectComponent()
-    {
-        widget.groupBoxSkills->setTitle(QString::fromStdString(observerName));
-        widget.treeWidgetSkillDetails->setEditTriggers(
-            QAbstractItemView::EditTrigger::NoEditTriggers);
-        widget.treeWidgetSkillDetails->setColumnHidden(3, true);
-
-        getProxy(memory, observerName, 1000);
-        this->updateWidget->startTimerIfEnabled();
-        connected = true;
-    }
-
-    void
-    SkillManagerMonitorWidgetController::onDisconnectComponent()
-    {
-        connected = false;
-        memory = nullptr;
-
-        // reset all
-        skills.clear();
-        widget.treeWidgetSkills->clear();
-        widget.treeWidgetSkillDetails->clear();
-        skillsArgumentsTreeWidgetItem = nullptr;
-        selectedSkill.skillId.providerId->providerName = "";
-        selectedSkill.skillId.skillName = "";
-        this->updateWidget->stopTimer();
-    }
 
-    void
-    SkillManagerMonitorWidgetController::searchSkills()
-    {
-        this->currentSkillSearch = widget.lineEditSearch->text();
-    }
-
-    void
-    SkillManagerMonitorWidgetController::refreshSkillsAndExecutions()
-    {
-        refreshSkills();
-        refreshExecutions();
-    }
-
-    void
-    SkillManagerMonitorWidgetController::matchSkillUpdateToSearch(
-        std::map<skills::manager::dto::SkillID, skills::manager::dto::SkillDescription>& update)
-    {
-        /*
-        if (this->currentSkillSearch.isEmpty())
-        {
-            return;
-        }
-
-        // TODO: whitespace to wildcard
-
-        std::string search = this->currentSkillSearch.toLower().toStdString();
-        std::transform(search.begin(), search.end(), search.begin(),
-                       [](unsigned char c){ return std::tolower(c); });
-
-        for (auto it = update.begin(); it != update.end();)
-        {
-            if (simox::alg::to_lower(skills::SkillID::FromIce(it->first).skillName)
-                    .find(this->currentSkillSearch.toLower().toStdString()))
-            {
-                it = update.erase(it);
-            }
-            else
-            {
-                ++it;
-            }
-        }
-*/
-    }
-
-    void
-    SkillManagerMonitorWidgetController::refreshSkills()
-    {
-        if (!memory)
-        {
-            // check if null
-            return;
-        }
-
-        /* CHECK OWN SKILLS LIST */
-        // remove non-existing ones
-        try
-        {
-            std::scoped_lock l(updateMutex);
-
-            auto managerSkills = memory->getSkillDescriptions();
-            this->matchSkillUpdateToSearch(managerSkills);
-
-            // completely recreate internal skills map
-            skills.clear();
-            for (const auto& [sid, desc] : managerSkills)
-            {
-                auto description = skills::SkillDescription::FromIce(desc);
-                auto skillId = skills::SkillID::FromIce(sid);
-                auto providerId = skillId.providerId.value_or(
-                    skills::ProviderID{.providerName = "UNKNOWN PROVIDER NAME"});
-
-                ARMARX_CHECK(skillId.isFullySpecified());
-
-                auto& providedSkillsMap = skills[providerId]; // create new if not existent
-                providedSkillsMap.insert({skillId, description});
-            }
-
-            // update tree view. Remove non-existing elements
-            int i = 0;
-            while (i < widget.treeWidgetSkills->topLevelItemCount())
-            {
-                auto* providerItem = widget.treeWidgetSkills->topLevelItem(i);
-                auto providerName = providerItem->text(0).toStdString();
-                skills::ProviderID providerId{.providerName = providerName};
-
-                if (skills.find(providerId) == skills.end())
-                {
-                    providerItem = nullptr; // reset
-                    auto remove = widget.treeWidgetSkills->takeTopLevelItem(i);
-                    delete remove;
-                    continue;
-                }
-
-                ++i;
-                auto& providedSkills = skills.at(providerId);
-
-                int j = 0;
-                while (j < providerItem->childCount())
-                {
-                    auto* skillItem = providerItem->child(j);
-                    auto skillName = skillItem->text(0).toStdString();
-
-                    skills::SkillID skillId{.providerId =
-                                                skills::ProviderID{.providerName = providerName},
-                                            .skillName = skillName};
-
-                    if (providedSkills.find(skillId) == providedSkills.end())
-                    {
-                        skillItem = nullptr;
-                        auto remove = providerItem->takeChild(j);
-                        delete remove;
-                        continue;
-                    }
-
-                    ++j;
-                }
-            }
-
-            // update tree view. Add new elements
-            for (const auto& [providerId, providedSkills] : skills)
-            {
-                QTreeWidgetItem* providerItem = nullptr;
-                for (int i = 0; i < widget.treeWidgetSkills->topLevelItemCount(); ++i)
-                {
-                    auto el = widget.treeWidgetSkills->topLevelItem(i);
-                    auto providerName = el->text(0).toStdString();
-                    skills::ProviderID elProviderId{.providerName = providerName};
-
-                    if (providerId == elProviderId)
-                    {
-                        providerItem = el;
-                        break;
-                    }
-                }
-
-                if (!providerItem)
-                {
-                    providerItem = new QTreeWidgetItem(widget.treeWidgetSkills);
-                    providerItem->setText(0, QString::fromStdString(providerId.providerName));
-                }
-
-                for (const auto& [skillId, skill] : providedSkills)
-                {
-                    QTreeWidgetItem* skillItem = nullptr;
-                    for (int i = 0; i < providerItem->childCount(); ++i)
-                    {
-                        auto el = providerItem->child(i);
-                        auto skillName = el->text(0).toStdString();
-                        skills::SkillID elSkillId{providerId, skillName};
-
-                        if (skillId == elSkillId)
-                        {
-                            skillItem = el;
-                            break;
-                        }
-                    }
-
-                    if (!skillItem)
-                    {
-                        skillItem = new SkillInfoTreeWidgetItem(skill, providerItem);
-                        skillItem->setText(0, QString::fromStdString(skillId.skillName));
-                    }
-                }
-            }
-        }
-        catch (...)
-        {
-            // perhaps the manager died during the method?
-        }
-    }
-
-    void
-    SkillManagerMonitorWidgetController::refreshExecutions()
-    {
-        static std::map<skills::SkillStatus, std::string> ExecutionStatus2String = {
-            // Main states
-            {skills::SkillStatus::Constructing, "Constructing"},
-            {skills::SkillStatus::Initializing, "Initializing"},
-            {skills::SkillStatus::Preparing, "Preparing"},
-            {skills::SkillStatus::Running, "Running"},
-
-            // Terminating
-            {skills::SkillStatus::Aborted, "Aborted"},
-            {skills::SkillStatus::Failed, "Failed"},
-            {skills::SkillStatus::Succeeded, "Succeeded"}};
-
-        if (!memory)
-        {
-            // check if null
-            return;
-        }
-
-        try
-        {
-            std::scoped_lock l(updateMutex);
-
-            auto currentManagerStatuses = memory->getSkillExecutionStatuses();
-
-            for (const auto& [k, v] : currentManagerStatuses)
-            {
-                auto executionId = skills::SkillExecutionID::FromIce(k);
-                auto statusUpdate = skills::SkillStatusUpdate::FromIce(v);
-
-                // update maps
-                skillStatusUpdates[executionId] = statusUpdate;
-                //skillExecutionParams.insert_or_assign(executionId,
-                //                                      statusUpdate.usedParameterization);
-
-                SkillExecutionInfoTreeWidgetItem* found = nullptr;
-                for (int i = 0; i < widget.treeWidgetSkillExecutions->topLevelItemCount(); ++i)
-                {
-                    auto c = static_cast<SkillExecutionInfoTreeWidgetItem*>(
-                        widget.treeWidgetSkillExecutions->topLevelItem(i));
-
-                    found =
-                        SkillExecutionInfoTreeWidgetItem::SearchRecursiveForMatch(c, executionId);
-
-                    if (found)
-                    {
-                        for (std::pair<skills::SkillStatus, std::string> i : ExecutionStatus2String)
-                        {
-                            if (i.first == statusUpdate.status)
-                            {
-                                found->setText(3, QString::fromStdString(i.second));
-                            }
-                        }
-
-                        break;
-                    }
-                }
-
-                if (!found)
-                {
-                    // TODO: Sort to executor!
-                    auto item = new SkillExecutionInfoTreeWidgetItem(executionId);
-
-                    item->setText(0,
-                                  QString::fromStdString(
-                                      executionId.executionStartedTime.toDateTimeString()));
-                    item->setText(1, QString::fromStdString(executionId.executorName));
-                    item->setText(2, QString::fromStdString(executionId.skillId.toString()));
-                    for (std::pair<skills::SkillStatus, std::string> i : ExecutionStatus2String)
-                    {
-                        if (i.first == statusUpdate.status)
-                        {
-                            item->setText(3, QString::fromStdString(i.second));
-                        }
-                    }
-
-                    widget.treeWidgetSkillExecutions->insertTopLevelItem(0, item);
-                }
-            }
-        }
-        catch (...)
-        {
-            // perhaps the manager died during the method?
-        }
-    }
-
-    void
-    SkillManagerMonitorWidgetController::executeSelectedSkill()
-    {
-        auto data = getConfigAsAron();
-        executeSkillWithParams(selectedSkill.skillId, data);
-    }
-
-    void
-    SkillManagerMonitorWidgetController::rerunSkillWithSimilarParams()
-    {
-        // TODO: disabled until skillparameterization is replaced
-        //skills::SkillParameterization selectedExecutionParams =
-        //skillExecutionParams.at(selectedSkill.skillExecutionId);
-        //executeSkillWithParams(selectedSkill.skillExecutionId.skillId,
-        //                       selectedExecutionParams.parameterization);
-
-        executeSelectedSkill();
-    }
-
-    void
-    SkillManagerMonitorWidgetController::executeSkillWithParams(skills::SkillID skillId,
-                                                                aron::data::DictPtr params)
-    {
-        std::scoped_lock l(updateMutex);
-
-        auto providerId = skillId.providerId;
-        if (!providerId.has_value())
-        {
-            return;
-        }
-        const auto& skillDescriptions = skills.at(providerId.value());
-        if (skillDescriptions.find(skillId) == skillDescriptions.end())
-        {
-            return;
-        }
-
-        char hostname[HOST_NAME_MAX];
-        gethostname(hostname, HOST_NAME_MAX);
-
-        skills::SkillExecutionRequest req{
-            .skillId = selectedSkill.skillId,
-            .executorName = "Skills.Manager GUI (hostname: " + std::string(hostname) + ")",
-            .parameters = params};
-
-        ARMARX_CHECK(selectedSkill.skillId.isFullySpecified()); // sanity check
-        ARMARX_IMPORTANT << "Executing skill from GUI: " << selectedSkill.skillId << ".";
-        // Note that we execute the skill in a seperate thread so that the GUI thread does not freeze.
-        memory->begin_executeSkill(req.toManagerIce());
-    }
-
-    void
-    SkillManagerMonitorWidgetController::stopAllExecutions()
-    {
-        QTreeWidget const* tree = widget.treeWidgetSkillExecutions;
+        widget.setupUi(getWidget());
 
-        int const max_retries = 3;
-        int left_retries = max_retries;
-        bool retry = false;
+        // setup memory
+        this->mem_wrapper = std::make_shared<skills::gui::SkillManagerWrapper>();
 
-        do
-        {
-            retry = false;
-
-            for (ssize_t i = 0; i < tree->topLevelItemCount(); ++i)
-            {
-                SkillExecutionInfoTreeWidgetItem const* item =
-                    dynamic_cast<SkillExecutionInfoTreeWidgetItem*>(
-                        widget.treeWidgetSkillExecutions->topLevelItem(i));
-
-                if (not item)
-                {
-                    // At this point, dynamic-casting failed and we don't know anything about the
-                    // type.
-                    ARMARX_ERROR << "Cannot stop unknown skill.";
-                    retry = true;
-                    continue;
-                }
-
-                try
-                {
-                    ARMARX_INFO << "Aborting skill '" << item->executionId.skillId.skillName
-                                << "'...";
-                    memory->abortSkillAsync(item->executionId.toManagerIce());
-                }
-                catch (Ice::Exception const& e)
-                {
-                    retry = true;
-                    ARMARX_ERROR << "Unhandeled Ice exception while aborting skill '"
-                                 << item->executionId.skillId.skillName << "'.";
-                }
-                catch (...)
-                {
-                    retry = true;
-                    ARMARX_ERROR << "Unhandled error while aborting skill '"
-                                 << item->executionId.skillId.skillName << "'.";
-                }
-            }
-
-            if (retry)
-            {
-                left_retries -= 1;
-
-                if (left_retries > 0)
-                {
-                    ARMARX_WARNING << "There where errors aborting skills.  Retrying...";
-                }
-                else
-                {
-                    ARMARX_ERROR << "Couldn't abort all skills after " << max_retries
-                                 << " tries.  Giving up.";
-                    retry = false;
-                }
-            }
-        } while (retry);
-    }
+        viewer = std::make_unique<armarx::skills::gui::SkillMemoryGUI>(
+            widget.treeWidgetSkillExecutions,
+            widget.groupBoxSkillExecutions->layout(),
 
-    void
-    SkillManagerMonitorWidgetController::stopSkill()
-    {
-        std::scoped_lock l(updateMutex);
+            widget.groupBoxSkills,
+            widget.splitter,
 
-        /*
-        if (selectedSkill.skillExecutionId.skillId.fullySpecified())
-        {
-            ARMARX_INFO << "The user requested to stop a skill, which was not fully specified!";
-            return;
-        }
+            widget.groupBoxSkillDetails,
+            widget.splitter,
 
-        const auto& skillDescriptions = skills.at(*selectedSkill.skillId.providerId);
-        if (!skillDescriptions.count(selectedSkill.skillId.skillName))
-        {
-            return;
-        }
-*/
+            widget.updateWidgetLayout,
 
-        ARMARX_INFO << "Stopping skill from GUI: " << selectedSkill.skillExecutionId.toString();
+            widget.stopAllLayout,
 
-        memory->abortSkillAsync(selectedSkill.skillExecutionId.toManagerIce());
-    }
+            widget.connectionStatusLabel,
 
-    void
-    SkillManagerMonitorWidgetController::skillExecutionSelectionChanged(QTreeWidgetItem* current,
-                                                                        QTreeWidgetItem*)
-    {
-        std::scoped_lock l(updateMutex);
-        widget.groupBoxSkillExecutions->setEnabled(false);
-
-        if (!current)
-        {
-            // gui has died?
-            return;
-        }
+            this->mem_wrapper);
 
-        auto c = static_cast<SkillExecutionInfoTreeWidgetItem*>(current);
-        selectedSkill.skillExecutionId = c->executionId;
-        widget.groupBoxSkillExecutions->setEnabled(true);
+        connectSignals();
     }
 
     void
-    SkillManagerMonitorWidgetController::skillSelectionChanged(QTreeWidgetItem* current,
-                                                               QTreeWidgetItem*)
+    SkillManagerMonitorWidgetController::connectSignals()
     {
-        std::scoped_lock l(updateMutex);
-        widget.groupBoxSkillDetails->setEnabled(false);
-
-        if (!current)
-        {
-            // gui has died?
-            return;
-        }
-
-        if (!current->parent())
-        {
-            // no parent available. Perhaps provider clicked? Reset selected skill.
-            selectedSkill.skillId = SelectedSkill::UNK_SKILL_ID;
-            return;
-        }
-
-        auto c = static_cast<SkillInfoTreeWidgetItem*>(current);
-        auto skillDescription = c->skillDescription;
-
-
-        if (selectedSkill.skillId == skillDescription.skillId)
-        {
-            // no change
-            return;
-        }
-
-        selectedSkill.skillId = skillDescription.skillId;
-
-        // setup groupBox
-        widget.groupBoxSkillDetails->setTitle(
-            QString::fromStdString(selectedSkill.skillId.toString()));
-        widget.groupBoxSkillDetails->setEnabled(true);
-
-        // setup table view
-        widget.treeWidgetSkillDetails->clear();
-        aronTreeWidgetController = nullptr;
-        skillsArgumentsTreeWidgetItem = nullptr;
-
-        // We assert that the skill exists
-        ARMARX_CHECK(skills.count(*selectedSkill.skillId.providerId) > 0);
-        ARMARX_CHECK(skills.at(*selectedSkill.skillId.providerId).count(selectedSkill.skillId) > 0);
-        auto skillDesc = skills.at(*selectedSkill.skillId.providerId).at(selectedSkill.skillId);
-
-        {
-            auto it = new QTreeWidgetItem(widget.treeWidgetSkillDetails,
-                                          {QString::fromStdString("Name"),
-                                           QString::fromStdString(skillDesc.skillId.skillName)});
-            widget.treeWidgetSkillDetails->addTopLevelItem(it);
-        }
-
-        {
-            auto it = new QTreeWidgetItem(widget.treeWidgetSkillDetails,
-                                          {QString::fromStdString("Description"),
-                                           QString::fromStdString(skillDesc.description)});
-            widget.treeWidgetSkillDetails->addTopLevelItem(it);
-        }
-
-        {
-            auto it = new QTreeWidgetItem(
-                widget.treeWidgetSkillDetails,
-                {QString::fromStdString("Timeout"),
-                 QString::fromStdString(std::to_string(skillDesc.timeout.toMilliSeconds())) +
-                     " ms"});
-            widget.treeWidgetSkillDetails->addTopLevelItem(it);
-        }
-
-        // select root profile
-        widget.comboBoxProfiles->setCurrentIndex(0);
-
-        // remove any profile
-        while (widget.comboBoxProfiles->count() > 1)
-        {
-            widget.comboBoxProfiles->removeItem(1);
-        }
-
-        // add new profiles for this skill
-        // TODO: Where stored?
+        // disconnect
+        connect(this,
+                &SkillManagerMonitorWidgetController::disconnectGui,
+                this->mem_wrapper.get(),
+                &skills::gui::SkillManagerWrapper::disconnectMemory);
+        connect(this,
+                &SkillManagerMonitorWidgetController::disconnectGui,
+                this->viewer.get(),
+                &skills::gui::SkillMemoryGUI::disconnectGui);
 
-        skillsArgumentsTreeWidgetItem = new QTreeWidgetItem(widget.treeWidgetSkillDetails,
-                                                            {QString::fromStdString("Arguments")});
-        auto aron_args = skillDesc.parametersType;
-        auto default_args_of_profile = skillDesc.rootProfileDefaults;
-
-        aronTreeWidgetController =
-            std::make_shared<AronTreeWidgetController>(widget.treeWidgetSkillDetails,
-                                                       skillsArgumentsTreeWidgetItem,
-                                                       aron_args,
-                                                       default_args_of_profile);
-
-        // automatically expand args
-        skillsArgumentsTreeWidgetItem->setExpanded(true);
+        // connect
+        connect(this,
+                &SkillManagerMonitorWidgetController::connectGui,
+                viewer.get(),
+                &skills::gui::SkillMemoryGUI::connectGui);
     }
 
-    aron::data::DictPtr
-    SkillManagerMonitorWidgetController::getConfigAsAron() const
+    SkillManagerMonitorWidgetController::~SkillManagerMonitorWidgetController()
     {
-        // create argument aron (if there is an accepted type set)
-        if (aronTreeWidgetController)
-        {
-            return aronTreeWidgetController->convertToAron();
-        }
-        return nullptr;
     }
 
     void
-    SkillManagerMonitorWidgetController::copyCurrentConfig()
+    SkillManagerMonitorWidgetController::onInitComponent()
     {
-        auto data = getConfigAsAron();
-        if (!data)
-        {
-            return;
-        }
-
-        auto json = aron::data::converter::AronNlohmannJSONConverter::ConvertToNlohmannJSON(data);
-        QClipboard* clipboard = QApplication::clipboard();
-        clipboard->setText(QString::fromStdString(json.dump(2)));
+        usingProxy(observerName);
     }
 
     void
-    SkillManagerMonitorWidgetController::pasteCurrentConfig()
+    SkillManagerMonitorWidgetController::onConnectComponent()
     {
-        QClipboard* clipboard = QApplication::clipboard();
-        std::string s = clipboard->text().toStdString();
-        nlohmann::json json = nlohmann::json::parse(s);
-        auto data =
-            aron::data::converter::AronNlohmannJSONConverter::ConvertFromNlohmannJSONObject(json);
-
-        if (!aronTreeWidgetController)
-        {
-            return;
-        }
 
-        aronTreeWidgetController->setFromAron(data);
+        getProxy(this->memory, observerName, 1000);
+        connected = true;
+        mem_wrapper->connectMemory(this->memory);
+        emit connectGui(observerName);
     }
 
     void
-    SkillManagerMonitorWidgetController::resetCurrentConfig()
+    SkillManagerMonitorWidgetController::onDisconnectComponent()
     {
-        // TODO
+        connected = false;
+        memory = nullptr;
+        emit disconnectGui();
     }
 
 } // namespace armarx
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h
index 786f13d869aee2c6c80d7de9058e840ef0305db1..ca80a304b536833542ad35957423e6dbdc029267 100644
--- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h
@@ -33,7 +33,6 @@
 #include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h>
 #include <ArmarXGui/libraries/SimpleConfigDialog/SimpleConfigDialog.h>
 
-#include "RobotAPI/gui-plugins/SkillManagerPlugin/PeriodicUpdateWidget.h"
 #include <RobotAPI/gui-plugins/SkillManagerPlugin/ui_SkillManagerMonitorWidget.h>
 #include <RobotAPI/interface/skills/SkillMemoryInterface.h>
 #include <RobotAPI/libraries/aron/core/data/variant/All.h>
@@ -42,57 +41,10 @@
 #include <RobotAPI/libraries/skills/core/ProviderID.h>
 #include <RobotAPI/libraries/skills/core/SkillDescription.h>
 #include <RobotAPI/libraries/skills/core/SkillStatusUpdate.h>
-
-#include "aronTreeWidget/AronTreeWidgetController.h"
+#include <RobotAPI/libraries/skills_gui/SkillMemoryGui.h>
 
 namespace armarx
 {
-    class SkillDescriptionWidget;
-
-    class SkillInfoTreeWidgetItem : public QTreeWidgetItem
-    {
-    public:
-        SkillInfoTreeWidgetItem(const skills::SkillDescription& desc, QTreeWidgetItem* parent) :
-            QTreeWidgetItem(parent), skillDescription(desc)
-        {
-        }
-
-        SkillInfoTreeWidgetItem(const skills::SkillDescription& desc, QTreeWidget* parent) :
-            QTreeWidgetItem(parent), skillDescription(desc)
-        {
-        }
-
-        skills::SkillDescription skillDescription;
-    };
-
-    class SkillExecutionInfoTreeWidgetItem : public QTreeWidgetItem
-    {
-        //Q_OBJECT
-    public:
-        SkillExecutionInfoTreeWidgetItem(const skills::SkillExecutionID& id,
-                                         QTreeWidgetItem* parent) :
-            QTreeWidgetItem(parent), executionId(id)
-        {
-        }
-
-        // After constructing an item, it must be manually inserted into the tree!
-        SkillExecutionInfoTreeWidgetItem(const skills::SkillExecutionID& id) : executionId(id)
-        {
-        }
-
-        // When using this constructor, the new item will be appended to the bottom of the tree!
-        SkillExecutionInfoTreeWidgetItem(const skills::SkillExecutionID& id, QTreeWidget* parent) :
-            QTreeWidgetItem(parent), executionId(id)
-        {
-        }
-
-        static SkillExecutionInfoTreeWidgetItem*
-        SearchRecursiveForMatch(SkillExecutionInfoTreeWidgetItem* el,
-                                const skills::SkillExecutionID& needle);
-
-        skills::SkillExecutionID executionId;
-    };
-
     class ARMARXCOMPONENT_IMPORT_EXPORT SkillManagerMonitorWidgetController :
         public armarx::ArmarXComponentWidgetControllerTemplate<SkillManagerMonitorWidgetController>
     {
@@ -123,84 +75,20 @@ namespace armarx
         void onConnectComponent() override;
         void onDisconnectComponent();
 
-    private slots:
-        void skillSelectionChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous);
-        void skillExecutionSelectionChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous);
-
-        void stopAllExecutions();
-        void stopSkill(); // TODO: rename
-        void executeSelectedSkill();
-
-        void refreshSkills();
-        void refreshExecutions();
-        void refreshSkillsAndExecutions();
-
-        void copyCurrentConfig();
-        void pasteCurrentConfig();
-        void resetCurrentConfig();
-
-        void prepareAndRunMenu(const QPoint& pos);
-        void rerunSkillWithSimilarParams();
-
-        void searchSkills();
-
-
-    private:
-        aron::data::DictPtr getConfigAsAron() const;
+    signals:
+        void disconnectGui();
+        void connectGui(std::string observerName);
 
     private:
-        /**
-         * Widget Form
-         */
+        armarx::skills::manager::dti::SkillManagerInterfacePrx memory;
         Ui::SkillManagerMonitorWidget widget;
+        std::unique_ptr<armarx::skills::gui::SkillMemoryGUI> viewer = nullptr;
         QPointer<SimpleConfigDialog> dialog;
-        QString currentSkillSearch;
 
         std::string observerName = "SkillManager";
-        skills::dti::SkillMemoryInterfacePrx memory = nullptr;
-
-        // Data taken from observer (snapshot of it)
-        mutable std::mutex updateMutex;
-        std::map<skills::ProviderID, std::map<skills::SkillID, skills::SkillDescription>> skills =
-            {};
-        std::map<skills::SkillExecutionID, skills::SkillStatusUpdate> skillStatusUpdates = {};
-
-        // store copies (!) of skill descriptions
-        //std::map<skills::SkillExecutionID, skills::SkillParameterization> skillExecutionParams = {};
-
-        // User Input
-        struct SelectedSkill
-        {
-            static const skills::SkillID UNK_SKILL_ID;
-
-            skills::SkillID skillId;
-            skills::SkillExecutionID skillExecutionId;
-
-            // make default constructable
-            SelectedSkill() :
-                skillId(UNK_SKILL_ID),
-                skillExecutionId{.skillId = UNK_SKILL_ID,
-                                 .executorName = skills::SkillExecutionID::UNKNOWN,
-                                 .executionStartedTime = armarx::core::time::DateTime::Invalid()}
-            {
-            }
-        }
-
-        selectedSkill;
-
-        void executeSkillWithParams(skills::SkillID skillId, aron::data::DictPtr params);
-        void matchSkillUpdateToSearch(std::map<skills::manager::dto::SkillID,
-                                               skills::manager::dto::SkillDescription>& update);
-
-
-        PeriodicUpdateWidget* updateWidget =
-            nullptr; // TODO: this should not be held by the controller!
-        QPushButton* stopAllButton = nullptr; // also this. Oh well...
+        std::shared_ptr<skills::gui::SkillManagerWrapper> mem_wrapper = nullptr;
 
-        // Helper to get the treeWidgetItem easily
-        QTreeWidgetItem* skillsArgumentsTreeWidgetItem = nullptr;
-        AronTreeWidgetControllerPtr aronTreeWidgetController = nullptr;
-        SkillDescriptionWidget* skillDescriptionWidget = nullptr;
+        void connectSignals();
 
         // connected flag
         std::atomic_bool connected = false;
diff --git a/source/RobotAPI/libraries/CMakeLists.txt b/source/RobotAPI/libraries/CMakeLists.txt
index 4d481f8619df7851446f95712d8dce766513c943..aab6379138035bbabb26599742ec74372779fd66 100644
--- a/source/RobotAPI/libraries/CMakeLists.txt
+++ b/source/RobotAPI/libraries/CMakeLists.txt
@@ -41,3 +41,5 @@ add_subdirectory(GraspingUtility)
 add_subdirectory(obstacle_avoidance)
 
 add_subdirectory(robot_name_service)
+
+add_subdirectory(skills_gui)
diff --git a/source/RobotAPI/libraries/skills/core/ProviderID.cpp b/source/RobotAPI/libraries/skills/core/ProviderID.cpp
index 53d6aad6807a7002a80a097d94b1e1fb5ec9f864..c8d6708f1ce7157256b0eacd0889c836f1dc9137 100644
--- a/source/RobotAPI/libraries/skills/core/ProviderID.cpp
+++ b/source/RobotAPI/libraries/skills/core/ProviderID.cpp
@@ -1,7 +1,5 @@
 #include "ProviderID.h"
 
-#include "SkillID.h"
-
 namespace armarx
 {
     namespace skills
diff --git a/source/RobotAPI/libraries/skills/core/SkillDescription.h b/source/RobotAPI/libraries/skills/core/SkillDescription.h
index 4bc8a3cd8fe92f7ebdf13c32b1e812be8596fbbd..784afd9321f4d677109c1f43672f0bdff4846db8 100644
--- a/source/RobotAPI/libraries/skills/core/SkillDescription.h
+++ b/source/RobotAPI/libraries/skills/core/SkillDescription.h
@@ -30,6 +30,16 @@ namespace armarx
             static SkillDescription FromIce(const provider::dto::SkillDescription& i,
                                             const std::optional<ProviderID>& = std::nullopt);
             static SkillDescription FromIce(const manager::dto::SkillDescription& i);
+
+            bool
+            operator==(const SkillDescription& other) const
+            {
+                return this->skillId == other.skillId && this->description == other.description &&
+                       this->rootProfileDefaults == other.rootProfileDefaults &&
+                       this->timeout == other.timeout &&
+                       this->parametersType == other.parametersType &&
+                       this->resultType == other.resultType;
+            }
         };
 
         template <class T>
diff --git a/source/RobotAPI/libraries/skills/core/SkillExecutionID.h b/source/RobotAPI/libraries/skills/core/SkillExecutionID.h
index 53fc20a1013f5924c77159580899ae824bd1ad86..39f3bc008324d046486d4eb1cd486ef87a1860f8 100644
--- a/source/RobotAPI/libraries/skills/core/SkillExecutionID.h
+++ b/source/RobotAPI/libraries/skills/core/SkillExecutionID.h
@@ -36,13 +36,13 @@ namespace armarx
             bool
             operator<(const SkillExecutionID& other) const
             {
-                return this->toString() < other.toString();
+                return this->executionStartedTime < other.executionStartedTime;
             }
 
             bool
             operator<=(const SkillExecutionID& other) const
             {
-                return this->toString() <= other.toString();
+                return this->executionStartedTime <= other.executionStartedTime;
             }
 
             skills::manager::dto::SkillExecutionID toManagerIce() const;
diff --git a/source/RobotAPI/libraries/skills_gui/CMakeLists.txt b/source/RobotAPI/libraries/skills_gui/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a1e53c1a2d96b3a6e50d4720efbd9be38d6760de
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/CMakeLists.txt
@@ -0,0 +1,121 @@
+set(LIB_NAME       skills_gui)
+
+armarx_component_set_name("${LIB_NAME}")
+armarx_set_target("Library: ${LIB_NAME}")
+
+set(LIBRARIES
+    ArmarXCore
+    ArmarXCoreInterfaces
+    ArmarXGuiBase
+    RobotAPISkillsCore
+    RobotAPISkillsManager
+    RobotAPIInterfaces
+    aron
+)
+
+set(COMPONENT_LIBS
+    RobotAPIInterfaces
+    aron
+    RobotAPISkills
+    RobotAPISkillsManager
+    RobotAPISkillsMemory
+    SkillsMemory
+    aronjsonconverter
+    SimpleConfigDialog
+)
+
+set(SOURCES
+    aron_tree_widget/visitors/AronTreeWidgetCreator.cpp
+    aron_tree_widget/visitors/AronTreeWidgetConverter.cpp
+    aron_tree_widget/visitors/AronTreeWidgetSetter.cpp
+    aron_tree_widget/visitors/AronTreeWidgetModalCreator.cpp
+    aron_tree_widget/visitors/AronTreeWidgetContextMenu.cpp
+    aron_tree_widget/widgets/CustomWidget.cpp
+    aron_tree_widget/widgets/EditMatrixWidget.cpp
+    aron_tree_widget/widgets/IntEnumWidget.cpp
+    aron_tree_widget/widgets/QuaternionWidget.cpp
+    aron_tree_widget/widgets/SkillDescriptionWidget.cpp
+    aron_tree_widget/Data.cpp
+    aron_tree_widget/ListDictHelper.cpp
+    aron_tree_widget/AronTreeWidgetItem.cpp
+    aron_tree_widget/AronTreeWidgetController.cpp
+    aron_tree_widget/modal/text/AronTreeWidgetTextInputModalController.cpp
+    aron_tree_widget/modal/dict/AronTreeWidgetDictInputModalController.cpp
+    aron_tree_widget/modal/float_double/AronTreeWidgetFloatInputModalController.cpp
+    aron_tree_widget/modal/int_long/AronTreeWidgetIntInputModalController.cpp
+    aron_tree_widget/modal/bool/AronTreeWidgetBoolInputModalController.cpp
+    aron_tree_widget/modal/AronTreeWidgetModal.cpp
+    aron_tree_widget/ColorPalettes.cpp
+    
+    executions/SkillExecutionTreeWidget.cpp
+    executions/SkillExecutionTreeWidgetItem.cpp
+
+    memory/SkillManagerWrapper.cpp
+    memory/MemoryCommunicatorBase.cpp
+
+    skills/SkillTreeWidget.cpp
+    skills/SkillGroupBox.cpp
+    skills/SkillTreeWidgetItem.cpp
+
+    skill_details/SkillDetailsGroupBox.cpp
+    skill_details/ProfileMenuWidget.cpp
+    skill_details/SkillDetailsTreeWidget.cpp
+    
+    SkillMemoryGui.cpp
+    gui_utils.cpp
+    StatusLabel.cpp
+)
+set(HEADERS
+    aron_tree_widget/visitors/AronTreeWidgetCreator.h
+    aron_tree_widget/visitors/AronTreeWidgetConverter.h
+    aron_tree_widget/visitors/AronTreeWidgetSetter.h
+    aron_tree_widget/visitors/AronTreeWidgetModalCreator.h
+    aron_tree_widget/visitors/AronTreeWidgetContextMenu.h
+    aron_tree_widget/widgets/NDArrayHelper.h
+    aron_tree_widget/widgets/EditMatrixWidget.h
+    aron_tree_widget/widgets/CustomWidget.h
+    aron_tree_widget/widgets/IntEnumWidget.h
+    aron_tree_widget/widgets/QuaternionWidget.h
+    aron_tree_widget/widgets/SkillDescriptionWidget.h
+    aron_tree_widget/Data.h
+    aron_tree_widget/ListDictHelper.h
+    aron_tree_widget/AronTreeWidgetItem.h
+    aron_tree_widget/AronTreeWidgetController.h
+    aron_tree_widget/modal/AronTreeWidgetModal.h
+    aron_tree_widget/modal/text/AronTreeWidgetTextInputModalController.h
+    aron_tree_widget/modal/dict/AronTreeWidgetDictInputModalController.h
+    aron_tree_widget/modal/float_double/AronTreeWidgetFloatInputModalController.h
+    aron_tree_widget/modal/int_long/AronTreeWidgetIntInputModalController.h
+    aron_tree_widget/modal/bool/AronTreeWidgetBoolInputModalController.h
+    aron_tree_widget/ColorPalettes.h
+    
+    executions/SkillExecutionTreeWidget.h
+    executions/SkillExecutionTreeWidgetItem.h
+
+    memory/SkillManagerWrapper.h
+    memory/MemoryCommunicatorBase.h
+
+    skills/SkillTreeWidget.h
+    skills/SkillGroupBox.h
+    skills/SkillTreeWidgetItem
+
+    skill_details/SkillDetailsGroupBox.h
+    skill_details/ProfileMenuWidget.h
+    skill_details/SkillDetailsTreeWidget.h
+    
+    SkillMemoryGui.h
+    gui_utils.h
+    StatusLabel.h
+)
+
+armarx_gui_library("${LIB_NAME}" "${SOURCES}" "${GUI_MOC_HDRS}" "${GUI_UIS}" "" "${LIBRARIES}")
+
+set(GUI_UIS
+    aronTreeWidget/modal/text/AronTreeWidgetTextInputModal.ui
+)
+
+add_library(${PROJECT_NAME}::skills_gui ALIAS skills_gui)
+
+
+# add unit tests
+#add_subdirectory(test)
diff --git a/source/RobotAPI/libraries/skills_gui/SkillMemoryGui.cpp b/source/RobotAPI/libraries/skills_gui/SkillMemoryGui.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4d74cf11e2b5c208a30eb553c986a9636dabd562
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/SkillMemoryGui.cpp
@@ -0,0 +1,137 @@
+#include "SkillMemoryGui.h"
+
+#include "gui_utils.h"
+
+namespace armarx::skills::gui
+{
+    SkillMemoryGUI::SkillMemoryGUI(QTreeWidget* _skillExecutionTreeWidget,
+                                   QLayout* _skillExecutionTreeWidgetParentLayout,
+                                   QGroupBox* _skillGroupBox,
+                                   QSplitter* _skillGroupBoxParentLayout,
+                                   QGroupBox* _skillDetailGroupBox,
+                                   QSplitter* _skillDetailGroupBoxParentLayout,
+                                   QHBoxLayout* _updateWidgetLayout,
+
+                                   QLayout* stopAllLayout,
+
+                                   QWidget* _connectionStatusLabel,
+
+                                   std::shared_ptr<SkillManagerWrapper> _memory)
+    {
+        Logging::setTag("SkillMemoryGui");
+
+        // parameter check
+        ARMARX_CHECK(_skillExecutionTreeWidgetParentLayout);
+        ARMARX_CHECK(_skillGroupBoxParentLayout);
+        ARMARX_CHECK(_skillDetailGroupBoxParentLayout);
+        ARMARX_CHECK(_memory);
+
+        ARMARX_CHECK(_skillExecutionTreeWidget);
+        ARMARX_CHECK(_skillGroupBox);
+        ARMARX_CHECK(_skillDetailGroupBox);
+        ARMARX_CHECK(_updateWidgetLayout);
+        ARMARX_CHECK(_connectionStatusLabel);
+        ARMARX_CHECK(_memory);
+
+        // setup memory
+        this->memory = _memory;
+
+        // Update widget
+        this->updateWidgetLayout = _updateWidgetLayout;
+        this->updateWidget = new PeriodicUpdateWidget();
+        this->updateWidgetLayout->insertWidget(0, updateWidget);
+
+
+        // replace skillExecutionTreeWidget
+        this->skillExecutionTreeWidget = new SkillExecutionTreeWidget(memory);
+        armarx::gui::replaceWidget(_skillExecutionTreeWidget,
+                                   this->skillExecutionTreeWidget,
+                                   _skillExecutionTreeWidgetParentLayout);
+
+        // replace skillGroupBox
+        this->skillGroupBox = new SkillGroupBox(memory);
+
+        // replace skillDetailGroupBox
+        this->skillDetailGroupBox = new SkillDetailGroupBox(memory);
+
+        armarx::gui::clearSplitter(_skillGroupBoxParentLayout);
+        _skillGroupBoxParentLayout->insertWidget(0, this->skillDetailGroupBox);
+        _skillGroupBoxParentLayout->insertWidget(0, this->skillGroupBox);
+
+        // setup stop all button
+        stopAllButton = new QPushButton(QString::fromStdString(STOP_ALL_BUTTON_TEXT));
+        stopAllLayout->addWidget(stopAllButton);
+
+        this->connectionStatusLabel = new StatusLabel();
+        armarx::gui::replaceWidget(_connectionStatusLabel,
+                                   this->connectionStatusLabel,
+                                   _connectionStatusLabel->parentWidget()->layout());
+
+        setupUi();
+    }
+
+    void
+    SkillMemoryGUI::setupUi()
+    {
+        stopAllButton->setStyleSheet("background-color: red");
+        connectSignals();
+    }
+
+    void
+    SkillMemoryGUI::connectSignals()
+    {
+        connect(skillGroupBox,
+                &SkillGroupBox::updateSkillDetails,
+                skillDetailGroupBox,
+                &SkillDetailGroupBox::updateSkillDetails);
+
+        // disconnect gui
+        connect(this, &SkillMemoryGUI::disconnectGui, skillGroupBox, &SkillGroupBox::disconnectGui);
+        connect(this,
+                &SkillMemoryGUI::disconnectGui,
+                skillDetailGroupBox,
+                &SkillDetailGroupBox::disconnectGui);
+        connect(this,
+                &SkillMemoryGUI::disconnectGui,
+                skillExecutionTreeWidget,
+                &SkillExecutionTreeWidget::disconnectGui);
+        connect(
+            this, &SkillMemoryGUI::disconnectGui, updateWidget, &PeriodicUpdateWidget::stopTimer);
+
+        // connect gui
+        connect(this,
+                &SkillMemoryGUI::connectGui,
+                updateWidget,
+                &PeriodicUpdateWidget::startTimerIfEnabled);
+        connect(this, &SkillMemoryGUI::connectGui, skillGroupBox, &SkillGroupBox::connectGui);
+
+        // update cascade
+        connect(this, &SkillMemoryGUI::updateGui, skillGroupBox, &SkillGroupBox::updateGui);
+
+        // we don't want to update the skill details periodically, update can be triggered manually
+        /*
+        connect(
+            this, &SkillMemoryGUI::updateGui, skillDetailGroupBox, &SkillDetailGroupBox::updateGui);
+        */
+        connect(this,
+                &SkillMemoryGUI::updateGui,
+                skillExecutionTreeWidget,
+                &SkillExecutionTreeWidget::updateExecutions);
+
+        // timer -> update
+        connect(
+            this->updateWidget, &PeriodicUpdateWidget::update, this, &SkillMemoryGUI::updateGui);
+
+        // stop all
+        connect(stopAllButton,
+                &QPushButton::clicked,
+                memory.get(),
+                &SkillManagerWrapper::stopAllExecutions);
+
+        // status label
+        connect(memory.get(),
+                &SkillManagerWrapper::connectionUpdate,
+                connectionStatusLabel,
+                &StatusLabel::handleMessage);
+    }
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/SkillMemoryGui.h b/source/RobotAPI/libraries/skills_gui/SkillMemoryGui.h
new file mode 100644
index 0000000000000000000000000000000000000000..64361f811ef2251ad679fad0c2efa1395a5aa563
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/SkillMemoryGui.h
@@ -0,0 +1,80 @@
+#ifndef SKILLMEMORYGUI_H
+#define SKILLMEMORYGUI_H
+
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QSplitter>
+#include <QTreeWidget>
+#include <QWidget>
+
+#include <ArmarXCore/core/logging/Logging.h>
+
+#include <ArmarXGui/libraries/ArmarXGuiBase/widgets/PeriodicUpdateWidget.h>
+
+#include "RobotAPI/libraries/skills_gui/StatusLabel.h"
+
+#include "./aron_tree_widget/widgets/SkillDescriptionWidget.h"
+#include "./executions/SkillExecutionTreeWidget.h"
+#include "./memory/SkillManagerWrapper.h"
+#include "./skill_details/SkillDetailsGroupBox.h"
+#include "./skills/SkillGroupBox.h"
+
+namespace armarx::skills::gui
+{
+    class SkillMemoryGUI : public QObject, public armarx::Logging
+    {
+        Q_OBJECT
+
+    public:
+        static const constexpr char* STOP_ALL_BUTTON_TEXT = "Stop all executions";
+        SkillMemoryGUI(QTreeWidget* _skillExecutionTreeWidget,
+                       QLayout* _skillExecutionTreeWidgetParentLayout,
+                       QGroupBox* _skillGroupBox,
+                       QSplitter* _skillGroupBoxParentLayout,
+                       QGroupBox* _skillDetailGroupBox,
+                       QSplitter* _skillDetailGroupBoxParentLayout,
+                       QHBoxLayout* _updateWidgetLayout,
+
+                       QLayout* stopAllLayout,
+
+                       QWidget* connectionStatusLabel,
+
+                       std::shared_ptr<SkillManagerWrapper> _memory);
+
+    signals:
+        /**
+         * @brief Notify affected widgets to clear all saved state.
+         */
+        void disconnectGui();
+
+        /**
+         * @brief Notify widgets of new connection.
+         * @param observerName the observer name.
+         */
+        void connectGui(std::string observerName);
+
+        /**
+         * @brief Notify widgets to update themselves
+         */
+        void updateGui();
+
+    private:
+        void setupUi();
+        void connectSignals();
+
+        SkillExecutionTreeWidget* skillExecutionTreeWidget = nullptr;
+        SkillGroupBox* skillGroupBox = nullptr;
+        SkillDetailGroupBox* skillDetailGroupBox = nullptr;
+        QBoxLayout* updateWidgetLayout = nullptr;
+
+        std::shared_ptr<SkillManagerWrapper> memory = nullptr;
+
+        PeriodicUpdateWidget* updateWidget = nullptr;
+
+        QPushButton* stopAllButton = nullptr;
+
+        StatusLabel* connectionStatusLabel = nullptr;
+    };
+} // namespace armarx::skills::gui
+
+#endif // SKILLMEMORYGUI_H
diff --git a/source/RobotAPI/libraries/skills_gui/StatusLabel.cpp b/source/RobotAPI/libraries/skills_gui/StatusLabel.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6b65f166aa9677f0eed55b95436a1a76777471f3
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/StatusLabel.cpp
@@ -0,0 +1,52 @@
+#include "StatusLabel.h"
+
+#include <QHBoxLayout>
+
+namespace armarx::skills::gui
+{
+
+    StatusLabel::StatusLabel()
+    {
+        this->label = new QLabel("");
+        this->resetButton = new QPushButton("");
+        this->setupUi();
+    }
+
+    void
+    StatusLabel::handleMessage(const std::string& message, std::string const& error)
+    {
+        this->label->setText(QString::fromStdString(message));
+        this->resetButton->setHidden(false);
+        label->setToolTip(QString::fromStdString(error));
+    }
+
+    void
+    StatusLabel::resetLabel()
+    {
+        this->label->setText(QString::fromStdString(""));
+        this->resetButton->setHidden(true);
+    }
+
+    void
+    StatusLabel::setupUi()
+    {
+        QHBoxLayout* layout = new QHBoxLayout();
+        layout->addWidget(resetButton);
+        layout->addWidget(label);
+        this->setLayout(layout);
+        layout->setStretch(1, 2);
+        label->setStyleSheet("QLabel { color : red; }");
+        this->resetButton->setHidden(true);
+
+        label->setMinimumHeight(35);
+        label->setMaximumHeight(35);
+
+        QPixmap pixmap(":/icons/delete.ico");
+        QIcon ButtonIcon(pixmap);
+        resetButton->setIcon(ButtonIcon);
+        resetButton->setIconSize(pixmap.rect().size() / 2);
+
+        connect(this->resetButton, &QPushButton::clicked, this, &StatusLabel::resetLabel);
+    }
+
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/StatusLabel.h b/source/RobotAPI/libraries/skills_gui/StatusLabel.h
new file mode 100644
index 0000000000000000000000000000000000000000..b8e0f91e425e3715d5d5f617f877cfeeceee9a39
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/StatusLabel.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include <QLabel>
+#include <QPushButton>
+
+namespace armarx::skills::gui
+{
+    class StatusLabel : public QWidget
+    {
+    public:
+        /**
+         * @brief Constructor for StatusLabel
+         */
+        StatusLabel();
+
+    public slots:
+        /**
+         * @brief Display a message to indicate an update.
+         */
+        void handleMessage(std::string const& message, std::string const& error);
+
+    private slots:
+        /**
+         * @brief Reset the label to default state.
+         */
+        void resetLabel();
+
+    private:
+        void setupUi();
+
+        // contents
+        QLabel* label = nullptr;
+        QPushButton* resetButton = nullptr;
+    };
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/AronTreeWidgetController.cpp b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/AronTreeWidgetController.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..79d606639c320ffeba73918967d9a832de446e68
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/AronTreeWidgetController.cpp
@@ -0,0 +1,163 @@
+#include "AronTreeWidgetController.h"
+
+#include "RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetModalCreator.h"
+
+#include "visitors/AronTreeWidgetContextMenu.h"
+#include "visitors/AronTreeWidgetConverter.h"
+#include "visitors/AronTreeWidgetSetter.h"
+
+namespace armarx::skills::gui
+{
+    AronTreeWidgetController::AronTreeWidgetController(QTreeWidget* tree,
+                                                       QTreeWidgetItem* parent,
+                                                       const aron::type::ObjectPtr& type,
+                                                       const aron::data::DictPtr& data) :
+        parent(parent), tree(tree), type(type)
+    {
+        connect(tree,
+                SIGNAL(customContextMenuRequested(const QPoint&)),
+                this,
+                SLOT(ShowContextMenu(const QPoint&)));
+        connect(tree,
+                &QTreeWidget::itemDoubleClicked,
+                this,
+                &AronTreeWidgetController::onTreeWidgetItemDoubleClicked);
+
+        if (type) // if there is a type set, we create a tree widget from the type
+        {
+            AronTreeWidgetCreatorVisitor v(parent);
+            v.setTopLevelWidget(tree);
+            aron::type::visit(v, type);
+
+            if (data) // check if there is a default argument set. Prefill the GUI with it
+            {
+                setFromAron(data);
+            }
+        }
+        // there is no type but a default configuration. Prefill the GUI with the default arguments
+        else if (data)
+        {
+            // TODO: There is no visitor for that (yet)...
+            // create type from data, ...
+        }
+        else
+        {
+            new QTreeWidgetItem(parent, {QString::fromStdString("No args")});
+        }
+
+        // connect change handling after args init
+        connect(tree,
+                &QTreeWidget::itemChanged,
+                this,
+                &AronTreeWidgetController::onTreeWidgetItemChanged);
+    }
+
+    aron::data::DictPtr
+    AronTreeWidgetController::convertToAron() const
+    {
+        if (parent && type)
+        {
+            AronTreeWidgetConverterVisitor v(parent, 0);
+            aron::type::visit(v, type);
+
+            auto aron_args = aron::data::Dict::DynamicCastAndCheck(v.createdAron);
+            return aron_args;
+        }
+        return nullptr;
+    }
+
+    void
+    AronTreeWidgetController::setFromAron(const aron::data::DictPtr& data)
+    {
+        if (parent)
+        {
+            AronTreeWidgetSetterVisitor v(parent, 0);
+            aron::data::visit(v, data);
+        }
+    }
+
+    void
+    AronTreeWidgetController::ShowContextMenu(const QPoint& pos)
+    {
+        tree->blockSignals(true);
+
+        auto idx = tree->indexAt(pos);
+        AronTreeWidgetItem* clickedItem = AronTreeWidgetItem::DynamicCast(tree->itemAt(pos));
+        if (clickedItem)
+        {
+            AronTreeWidgetContextMenuVisitor visitor(clickedItem, pos, tree, idx.row());
+
+            aron::type::visit(visitor, clickedItem->aronType);
+            visitor.showMenuAndExecute();
+        }
+
+        tree->blockSignals(false);
+    }
+
+    void
+    AronTreeWidgetController::onTreeWidgetItemDoubleClicked(QTreeWidgetItem* item, int column)
+    {
+        if (!item)
+        {
+            return;
+        }
+        tree->blockSignals(true);
+
+        auto* aronItem = AronTreeWidgetItem::DynamicCast(item);
+        if (column == 1 && aronItem)
+        {
+
+
+            std::string name =
+                aronItem->text(aron_tree_widget::constantes::TREE_WIDGET_ITEM_NAME).toStdString();
+            // depending on aron type, create extra gui element.
+            armarx::skills::gui::AronTreeWidgetModalCreatorVisitor v(name, aronItem, tree);
+            aron::type::visit(v, aronItem->aronType);
+            auto modal = v.createdModal;
+
+            // if no modal is created, we instead use the edit field directly
+            if (modal)
+            {
+                modal->exec();
+            }
+            else if (aronItem->col1Editable)
+            {
+                item->treeWidget()->editItem(item, column);
+            }
+        }
+        else if (column == 0 && aronItem && aronItem->col0Editable)
+        {
+            item->treeWidget()->editItem(item, column);
+        }
+
+        tree->blockSignals(false);
+    }
+
+    void
+    AronTreeWidgetController::onTreeWidgetItemChanged(QTreeWidgetItem* item, int column)
+    {
+        tree->blockSignals(true);
+
+        auto* aronElem = AronTreeWidgetItem::DynamicCast(item);
+        if (aronElem)
+        {
+            aronElem->onUserChange(column);
+        }
+        // start conversion for entire tree -- this also sets the highlighting
+        if (parent->childCount() == 1)
+        {
+            auto* aronTreeRoot = AronTreeWidgetItem::DynamicCast(parent->child(0));
+            aronTreeRoot->resetError();
+            if (aronTreeRoot)
+            {
+                AronTreeWidgetConverterVisitor v(parent, 0);
+                aron::type::visit(v, type);
+                aronTreeRoot->setValueErrorState(v.hasDirectError(), v.onlyChildFailedConversion());
+            }
+        }
+        // else perhaps the GUI was stopped or died.
+
+        tree->blockSignals(false);
+    }
+
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/AronTreeWidgetController.h b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/AronTreeWidgetController.h
new file mode 100644
index 0000000000000000000000000000000000000000..2b6608fe17e09acddbe5cbde6192ce9625f0de8c
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/AronTreeWidgetController.h
@@ -0,0 +1,52 @@
+#pragma once
+
+#include <stack>
+
+#include <QTreeWidget>
+
+#include <ArmarXCore/core/system/ImportExportComponent.h>
+
+#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXComponentWidgetController.h>
+#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h>
+
+#include "AronTreeWidgetItem.h"
+#include "Data.h"
+#include "visitors/AronTreeWidgetCreator.h"
+
+namespace armarx::skills::gui
+{
+    // Main controller for any AronTreeWidget GUI. It attaches itself to the parent and needs the active widget.
+    // It's responsible to handle all signals for non-widget fields and click events.
+    class AronTreeWidgetController : public QObject
+    {
+        Q_OBJECT
+    public:
+        AronTreeWidgetController(QTreeWidget* tree,
+                                 QTreeWidgetItem* parent,
+                                 const aron::type::ObjectPtr& type,
+                                 const aron::data::DictPtr& data = nullptr);
+
+        aron::data::DictPtr convertToAron() const;
+        void setFromAron(const aron::data::DictPtr&);
+
+    private:
+        QTreeWidgetItem* parent;
+        QTreeWidget* tree;
+
+        aron::type::ObjectPtr type;
+
+    private slots:
+        // allows most primitive fields to be directly editable in the tree
+        // only String will open up a new widget
+        void onTreeWidgetItemDoubleClicked(QTreeWidgetItem* item, int column);
+        // check the new user input. Maybe undo if the field must not be edited.
+        // Also highlight if the input cannot be parsed. (Or the errors are now fixed)
+        void onTreeWidgetItemChanged(QTreeWidgetItem* item, int column);
+
+    public slots:
+        // hook for items to show a context menu (add  / delete element)
+        void ShowContextMenu(const QPoint&);
+    };
+
+    using AronTreeWidgetControllerPtr = std::shared_ptr<AronTreeWidgetController>;
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/AronTreeWidgetItem.cpp b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/AronTreeWidgetItem.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d76cee191fda8cb927548a795b53291875ae14e6
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/AronTreeWidgetItem.cpp
@@ -0,0 +1,200 @@
+#include "AronTreeWidgetItem.h"
+
+#include <QAction>
+#include <QMenu>
+
+#include <RobotAPI/libraries/aron/core/type/variant/All.h>
+
+#include "ColorPalettes.h"
+#include "visitors/AronTreeWidgetConverter.h"
+#include "widgets/CustomWidget.h"
+
+namespace armarx::skills::gui
+{
+    AronTreeWidgetItem*
+    AronTreeWidgetItem::DynamicCast(QTreeWidgetItem* i)
+    {
+        return dynamic_cast<AronTreeWidgetItem*>(i);
+    }
+
+    AronTreeWidgetItem*
+    AronTreeWidgetItem::DynamicCastAndCheck(QTreeWidgetItem* i)
+    {
+        if (!i)
+        {
+            return nullptr;
+        }
+        auto c = DynamicCast(i);
+        ARMARX_CHECK_NOT_NULL(c);
+        return c;
+    }
+
+    bool
+    AronTreeWidgetItem::isValueErrorneous()
+    {
+        return itemValueError;
+    }
+
+    void
+    AronTreeWidgetItem::setValueErrorState(bool isErrorSource, bool isTransitiveError)
+    {
+        itemValueError |= isErrorSource;
+        transitiveValueError |= isTransitiveError;
+
+
+        if (CustomWidget::DynamicCast(treeWidget()->itemWidget(this, 1)))
+        {
+            // The widgets handle errors themselves
+            return;
+        }
+        auto palette = gui_color_palette::getNormalPalette();
+        if (itemValueError)
+        {
+            palette = gui_color_palette::getErrorPalette();
+        }
+        else if (transitiveValueError)
+        {
+            palette = gui_color_palette::getIndirectErrorPalette();
+        }
+
+        QTreeWidgetItem::setBackground(1, QBrush(palette.color(QPalette::Base)));
+    }
+
+    void
+    AronTreeWidgetItem::setKeyErrorState(bool hasError)
+    {
+        ARMARX_CHECK(col0Editable); //only editable keys should call this function!
+        auto palette =
+            hasError ? gui_color_palette::getErrorPalette() : gui_color_palette::getNormalPalette();
+
+        keyValueError = hasError;
+
+        QTreeWidgetItem::setBackground(1, QBrush(palette.color(QPalette::Base)));
+    }
+
+    void
+    AronTreeWidgetItem::resetError()
+    {
+        keyValueError = false;
+        itemValueError = false;
+        transitiveValueError = false;
+        // also reset children
+        for (int i = 0; i < childCount(); ++i)
+        {
+            auto* arChild = AronTreeWidgetItem::DynamicCastAndCheck(QTreeWidgetItem::child(i));
+            arChild->resetError();
+        }
+    }
+
+    void
+    AronTreeWidgetItem::checkKeyValidityOfChildren()
+    {
+        ARMARX_CHECK(aronType->getDescriptor() == aron::type::Descriptor::DICT);
+        // return if check failed
+        if (aronType->getDescriptor() != aron::type::Descriptor::DICT)
+        {
+            return;
+        }
+        // iterate through children; memorize keys
+        std::map<QString, std::vector<int>> found_keys;
+        auto numChildren = childCount();
+        for (int i = 0; i < numChildren; ++i)
+        {
+            auto* casted = AronTreeWidgetItem::DynamicCastAndCheck(child(i));
+            if (!casted)
+            {
+                // soft error here, we already report it above. - Definetly programming error
+                continue;
+            }
+            auto& vec = found_keys[casted->text(0)];
+            vec.push_back(i);
+        }
+        // highlight keys that conflict
+        // memorize children that are not ok
+        std::set<int> errorneous_indices;
+        for (auto [key, vals] : found_keys)
+        {
+            if (vals.size() > 1)
+            {
+                for (int i : vals)
+                {
+                    auto* casted = AronTreeWidgetItem::DynamicCastAndCheck(child(i));
+                    if (!casted)
+                    {
+                        // soft error here, we already report it above. - Definetly programming error
+                        continue;
+                    }
+                    casted->setKeyErrorState(true);
+                    errorneous_indices.emplace(i);
+                }
+            }
+        }
+        // clear potential error state of other elements
+        for (int i = 0; i < numChildren; ++i)
+        {
+            if (errorneous_indices.find(i) != errorneous_indices.end())
+            {
+                continue;
+            }
+            auto* casted = AronTreeWidgetItem::DynamicCastAndCheck(child(i));
+            if (!casted)
+            {
+                // soft error here, we already report it above. - Definetly programming error
+                continue;
+            }
+            casted->setKeyErrorState(false);
+        }
+    }
+
+    void
+    AronTreeWidgetItem::onUserChange(int changedColumn)
+    {
+        QTreeWidgetItem* qParent = QTreeWidgetItem::parent();
+        ARMARX_CHECK(qParent);
+        AronTreeWidgetItem* aronParent = DynamicCast(qParent);
+        if (changedColumn == 0)
+        {
+            if (col0Editable)
+            {
+                // Topmost should always be an Object and col0 is not editable in the child then...
+                // -> aronParent should never be nullptr
+                ARMARX_CHECK(aronParent);
+                // check if the element is child of a dict. If so, validate uniqueness of keys
+                if (aronParent->aronType->getDescriptor() == aron::type::Descriptor::DICT)
+                {
+                    aronParent->checkKeyValidityOfChildren();
+                }
+            }
+            else
+            {
+                // maybe while editing keys, we try to edit a key that should not change by tabbing.
+                // Catch that here and undo the edit
+                preventIllegalKeyChange();
+            }
+        }
+    }
+
+    void
+    AronTreeWidgetItem::preventIllegalKeyChange()
+    {
+        if (!col0Editable)
+        {
+            setText(0, unchangeableKey);
+        }
+    }
+
+    AronTreeWidgetItem::AronTreeWidgetItem(bool editKey,
+                                           bool editVal,
+                                           QString key,
+                                           aron::type::VariantPtr type) :
+        aronType(type), col0Editable(editKey), col1Editable(editVal)
+    {
+        this->setText(0, key);
+        // add hook to check for edited keys for children of dictionaries
+        if (!editKey)
+        {
+            unchangeableKey = std::move(key);
+        }
+    }
+
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/AronTreeWidgetItem.h b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/AronTreeWidgetItem.h
new file mode 100644
index 0000000000000000000000000000000000000000..e1bf488e9b4bbec1cc04674e312bcabd783dabdf
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/AronTreeWidgetItem.h
@@ -0,0 +1,65 @@
+#pragma once
+
+#include <QTreeWidget>
+
+#include <ArmarXCore/core/system/ImportExportComponent.h>
+
+#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXComponentWidgetController.h>
+#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h>
+
+#include <RobotAPI/libraries/aron/core/type/variant/Variant.h>
+
+#include "Data.h"
+
+namespace armarx::skills::gui
+{
+    // Internal derived QtTreeWidgetItem class. Contains additional information to compare its data agains aron types.
+    // It contains 3 columns: Key ; Value ; Type
+    // The key can only be edited if the parent object is a dict
+    class AronTreeWidgetItem : public QObject, public QTreeWidgetItem
+    {
+        Q_OBJECT
+    public:
+        AronTreeWidgetItem(bool editKey, bool editVal, QString key, aron::type::VariantPtr type);
+
+        using QTreeWidgetItem::QTreeWidgetItem;
+
+        static AronTreeWidgetItem* DynamicCast(QTreeWidgetItem*);
+        static AronTreeWidgetItem* DynamicCastAndCheck(QTreeWidgetItem*);
+
+        aron::type::VariantPtr aronType;
+        // if editing the first column should be allowed
+        const bool col0Editable = false;
+        // if editing the second column should be allowed
+        const bool col1Editable = false;
+
+        bool isValueErrorneous();
+        // marks the gui in a specific color. Also stores if there is currently an error.
+        // the only way to reset the color back to normal is with resetError() (error is sticky)
+        void setValueErrorState(bool isErrorSource, bool isTransitiveError);
+        void setKeyErrorState(bool hasError);
+        // reset error storage that influences coloring for this and all children
+        void resetError();
+
+        // Checks if the children of a dict are unique
+        // should not be called on other types! (does nothing then)
+        void checkKeyValidityOfChildren();
+
+        // main logic on changes. Gets called from the onTreeWidgetItemChanged() slot in AronTreeWidgetController.
+        // (This class cannot directly consume this signal, at least I did not find a nice way...)
+        void onUserChange(int changedColumn);
+
+    private:
+        // because the editable keyword counts for all columns, it is possible to TAB into uneditable keys.
+        // We do not want those to change, so just change them back once they finished editing.
+        void preventIllegalKeyChange();
+
+        bool itemValueError = false;
+        bool transitiveValueError = false;
+        bool keyValueError = false;
+        // hacky storage of previous key value for items that usually should not be editable.
+        // Problem: Dict-keys are editable, one can tab from that to any other value field and edit it.
+        // Fix: Once the change is commited, the AronTreeWidgetController notices the change and checks if it was allowed.
+        QString unchangeableKey = "";
+    };
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/ColorPalettes.cpp b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/ColorPalettes.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ad2e711d96b2cc5cb5a139ac8805bf590fd0591f
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/ColorPalettes.cpp
@@ -0,0 +1,33 @@
+#include "ColorPalettes.h"
+
+namespace armarx::skills::gui::gui_color_palette
+{
+    QPalette
+    getErrorPalette()
+    {
+        QPalette errorPalette;
+        errorPalette.setColor(QPalette::Base, Qt::red);
+        return errorPalette;
+    }
+
+    QPalette
+    getNormalPalette()
+    {
+
+        QPalette normalPalette;
+
+        normalPalette.setColor(QPalette::Base, Qt::white);
+        return normalPalette;
+    }
+
+    QPalette
+    getIndirectErrorPalette()
+    {
+        QPalette indirectErr;
+        static QColor orange = QColor::fromRgb(255, 165, 0);
+        // orange color
+        indirectErr.setColor(QPalette::Base, orange);
+        return indirectErr;
+    }
+
+} // namespace armarx::skills::gui::gui_color_palette
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/ColorPalettes.h b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/ColorPalettes.h
new file mode 100644
index 0000000000000000000000000000000000000000..79386a831608667395a2405f45d79d751d926b32
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/ColorPalettes.h
@@ -0,0 +1,11 @@
+#pragma once
+#include <QPalette>
+
+namespace armarx::skills::gui::gui_color_palette
+{
+    QPalette getNormalPalette();
+
+    QPalette getErrorPalette();
+
+    QPalette getIndirectErrorPalette();
+} // namespace armarx::skills::gui::gui_color_palette
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/Data.cpp b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/Data.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f668ffd67c7aa5ccdb889f4e7794a0e08f919d9a
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/Data.cpp
@@ -0,0 +1,6 @@
+#include "Data.h"
+
+namespace armarx::skills::gui
+{
+
+}
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/Data.h b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/Data.h
new file mode 100644
index 0000000000000000000000000000000000000000..57fadd8343a1b4deab96c56c193851f37ed1d2be
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/Data.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <string>
+
+namespace armarx::skills::gui::aron_tree_widget::constantes
+{
+    const int TREE_WIDGET_ITEM_NAME = 0;
+    const int TREE_WIDGET_ITEM_VALUE = 1;
+    const int TREE_WIDGET_ITEM_TYPE = 2;
+
+    const std::string ITEM_EMPTY_MESSAGE = "(double click to edit)";
+    const std::string NEW_ITEM_DEFAULT_MESSAGE = "(Please set via main GUI (not in modal))";
+} // namespace armarx::skills::gui::aron_tree_widget::constantes
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/ListDictHelper.cpp b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/ListDictHelper.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d8c763e7b227d90fd101ecce44ff7d79ed905fac
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/ListDictHelper.cpp
@@ -0,0 +1,28 @@
+#include "ListDictHelper.h"
+
+namespace armarx::skills::gui::misc
+{
+    QString
+    generateNumElementsText(int num)
+    {
+        QString numElemsText = "<";
+        if (num == 0)
+        {
+            numElemsText.append("no");
+        }
+        else
+        {
+            numElemsText.append(QString::number(num));
+        }
+        if (num > 1 || num == 0)
+        {
+            numElemsText.append(" elements>");
+        }
+        else
+        {
+            numElemsText.append(" element>");
+        }
+        return numElemsText;
+    }
+
+} // namespace armarx::skills::gui::misc
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/ListDictHelper.h b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/ListDictHelper.h
new file mode 100644
index 0000000000000000000000000000000000000000..553eca828bb37b5acec0b1bee96cf8c7a5addcbd
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/ListDictHelper.h
@@ -0,0 +1,7 @@
+#include <QString>
+
+namespace armarx::skills::gui::misc
+{
+    // helper that generates a string on how many items are available
+    QString generateNumElementsText(int num);
+} // namespace armarx::skills::gui::misc
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/AronTreeWidgetModal.cpp b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/AronTreeWidgetModal.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..83189ef6d168fd33dd8e5745c9b4cb2f908bdf9a
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/AronTreeWidgetModal.cpp
@@ -0,0 +1,22 @@
+#include "AronTreeWidgetModal.h"
+
+namespace armarx::skills::gui
+{
+    AronTreeWidgetModal::AronTreeWidgetModal(const std::string& label,
+                                             AronTreeWidgetItem* item,
+                                             QTreeWidget* parent) :
+        QDialog(parent), item(item), label(label), parent(parent)
+    {
+        init.aronType = item->aronType;
+        init.setText(aron_tree_widget::constantes::TREE_WIDGET_ITEM_NAME,
+                     item->text(aron_tree_widget::constantes::TREE_WIDGET_ITEM_NAME));
+        init.setText(aron_tree_widget::constantes::TREE_WIDGET_ITEM_VALUE,
+                     item->text(aron_tree_widget::constantes::TREE_WIDGET_ITEM_VALUE));
+        init.setText(aron_tree_widget::constantes::TREE_WIDGET_ITEM_TYPE,
+                     item->text(aron_tree_widget::constantes::TREE_WIDGET_ITEM_TYPE));
+        for (int i = 0; i < item->childCount(); ++i)
+        {
+            init.addChild(item->child(i)->clone());
+        }
+    }
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/AronTreeWidgetModal.h b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/AronTreeWidgetModal.h
new file mode 100644
index 0000000000000000000000000000000000000000..ba1b39e5b7ef2fc4a09f0f6208bb931e743b7e6c
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/AronTreeWidgetModal.h
@@ -0,0 +1,65 @@
+#pragma once
+
+#include <stack>
+
+#include <QDialog>
+#include <QTreeWidget>
+
+#include <ArmarXCore/core/system/ImportExportComponent.h>
+
+#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXComponentWidgetController.h>
+#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h>
+
+#include "../AronTreeWidgetItem.h"
+#include "../Data.h"
+
+namespace armarx::skills::gui
+{
+    class AronTreeWidgetModal : public QDialog
+    {
+        Q_OBJECT
+
+    public:
+        AronTreeWidgetModal(const std::string& label,
+                            AronTreeWidgetItem* item,
+                            QTreeWidget* parent);
+
+    protected slots:
+
+        virtual void
+        reset()
+        {
+            item->aronType = init.aronType;
+            item->setText(aron_tree_widget::constantes::TREE_WIDGET_ITEM_NAME,
+                          init.text(aron_tree_widget::constantes::TREE_WIDGET_ITEM_NAME));
+            item->setText(aron_tree_widget::constantes::TREE_WIDGET_ITEM_VALUE,
+                          init.text(aron_tree_widget::constantes::TREE_WIDGET_ITEM_VALUE));
+            item->setText(aron_tree_widget::constantes::TREE_WIDGET_ITEM_TYPE,
+                          init.text(aron_tree_widget::constantes::TREE_WIDGET_ITEM_TYPE));
+            for (int i = 0; i < item->childCount(); ++i)
+            {
+                item->removeChild(item->child(i));
+            }
+            for (int i = 0; i < init.childCount(); ++i)
+            {
+                item->addChild(init.child(i)->clone());
+            }
+        }
+
+        virtual void
+        submit()
+        {
+            accept();
+        }
+
+    protected:
+        AronTreeWidgetItem init;
+        AronTreeWidgetItem* item;
+
+    private:
+        std::string label;
+        QTreeWidget* parent;
+    };
+
+    using AronTreeWidgetModalControllerPtr = std::shared_ptr<AronTreeWidgetModal>;
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/bool/AronTreeWidgetBoolInputModal.ui b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/bool/AronTreeWidgetBoolInputModal.ui
new file mode 100644
index 0000000000000000000000000000000000000000..69f4a5c99b277ba4808ecc45081df86e0ab55ef0
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/bool/AronTreeWidgetBoolInputModal.ui
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AronTreeWidgetBoolInputModalWidget</class>
+ <widget class="QWidget" name="AronTreeWidgetBoolInputModalWidget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>1015</width>
+    <height>498</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>SkillManagerMonitorWidget</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QSplitter" name="splitter">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <widget class="QGroupBox" name="groupBoxInput">
+      <property name="title">
+       <string>InputField</string>
+      </property>
+      <layout class="QGridLayout" name="gridLayout">
+       <item row="1" column="0">
+        <widget class="QPushButton" name="pushButtonReset">
+         <property name="text">
+          <string>Reset</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="1">
+        <widget class="QPushButton" name="pushButtonSubmit">
+         <property name="text">
+          <string>Submit</string>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="0" colspan="2">
+        <widget class="QTextEdit" name="textEditInput"/>
+       </item>
+      </layout>
+     </widget>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/bool/AronTreeWidgetBoolInputModalController.cpp b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/bool/AronTreeWidgetBoolInputModalController.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5ae3401afed2a7d933e473600273309ef6e3f4b2
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/bool/AronTreeWidgetBoolInputModalController.cpp
@@ -0,0 +1,34 @@
+#include "AronTreeWidgetBoolInputModalController.h"
+
+namespace armarx::skills::gui
+{
+    AronTreeWidgetBoolInputModalController::AronTreeWidgetBoolInputModalController(
+        const std::string& label,
+        AronTreeWidgetItem* item,
+        QTreeWidget* parent) :
+        AronTreeWidgetModal(label, item, parent)
+    {
+        widget.setupUi(this);
+
+        // TODO
+    }
+
+    void
+    AronTreeWidgetBoolInputModalController::submit()
+    {
+        item->setText(aron_tree_widget::constantes::TREE_WIDGET_ITEM_VALUE,
+                      widget.textEditInput->toPlainText());
+
+        AronTreeWidgetModal::submit();
+    }
+
+    void
+    AronTreeWidgetBoolInputModalController::reset()
+    {
+        AronTreeWidgetModal::reset();
+
+        // reset to initial value
+        widget.textEditInput->setPlainText(
+            init.text(aron_tree_widget::constantes::TREE_WIDGET_ITEM_VALUE));
+    }
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/bool/AronTreeWidgetBoolInputModalController.h b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/bool/AronTreeWidgetBoolInputModalController.h
new file mode 100644
index 0000000000000000000000000000000000000000..cbac189299a1fa4d9e5f705c159f0f87fdf90a9d
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/bool/AronTreeWidgetBoolInputModalController.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <QDialog>
+
+#include "RobotAPI/libraries/skills_gui/bool/ui_AronTreeWidgetBoolInputModal.h"
+
+#include "../AronTreeWidgetModal.h"
+
+namespace armarx::skills::gui
+{
+    class AronTreeWidgetBoolInputModalController : public AronTreeWidgetModal
+    {
+
+    public:
+        AronTreeWidgetBoolInputModalController(const std::string& label,
+                                               AronTreeWidgetItem* item,
+                                               QTreeWidget* parent);
+
+    private slots:
+
+        void submit() final;
+        void reset() final;
+
+    private:
+        Ui::AronTreeWidgetBoolInputModalWidget widget;
+    };
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/dict/AronTreeWidgetDictInputModal.ui b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/dict/AronTreeWidgetDictInputModal.ui
new file mode 100644
index 0000000000000000000000000000000000000000..b9b800ed26a2b2170b8ab06633e8e795b1957be4
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/dict/AronTreeWidgetDictInputModal.ui
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AronTreeWidgetDictInputModalWidget</class>
+ <widget class="QWidget" name="AronTreeWidgetDictInputModalWidget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>1015</width>
+    <height>498</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>SkillManagerMonitorWidget</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QSplitter" name="splitter">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <widget class="QGroupBox" name="groupBoxInput">
+      <property name="title">
+       <string>InputField</string>
+      </property>
+      <layout class="QGridLayout" name="gridLayout">
+       <item row="0" column="0" colspan="5">
+        <widget class="QTreeWidget" name="treeWidgetDict">
+         <column>
+          <property name="text">
+           <string>Key</string>
+          </property>
+         </column>
+         <column>
+          <property name="text">
+           <string>Value</string>
+          </property>
+         </column>
+         <column>
+          <property name="text">
+           <string>Type</string>
+          </property>
+         </column>
+        </widget>
+       </item>
+       <item row="1" column="3" colspan="2">
+        <widget class="QPushButton" name="pushButtonAddElement">
+         <property name="text">
+          <string>+ Add element</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="0" colspan="3">
+        <widget class="QLineEdit" name="lineEditKey">
+         <property name="maximumSize">
+          <size>
+           <width>880</width>
+           <height>16777215</height>
+          </size>
+         </property>
+         <property name="text">
+          <string>Enter Key</string>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="0">
+        <widget class="QPushButton" name="pushButtonReset">
+         <property name="text">
+          <string>Reset</string>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="1" colspan="4">
+        <widget class="QPushButton" name="pushButtonSubmit">
+         <property name="text">
+          <string>Submit</string>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/dict/AronTreeWidgetDictInputModalController.cpp b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/dict/AronTreeWidgetDictInputModalController.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..57d43b6d40917ec1b6a54c6c1eacd560aed72876
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/dict/AronTreeWidgetDictInputModalController.cpp
@@ -0,0 +1,89 @@
+#include "AronTreeWidgetDictInputModalController.h"
+
+#include <RobotAPI/libraries/aron/core/type/variant/All.h>
+
+#include "../../visitors/AronTreeWidgetCreator.h"
+
+namespace armarx::skills::gui
+{
+    AronTreeWidgetDictInputModalController::AronTreeWidgetDictInputModalController(
+        const std::string& label,
+        AronTreeWidgetItem* item,
+        QTreeWidget* parent) :
+        AronTreeWidgetModal(label, item, parent)
+    {
+        widget.setupUi(this);
+
+        // set header
+        widget.groupBoxInput->setTitle(QString::fromStdString(label));
+        reset();
+
+        // connect signals
+        connect(widget.pushButtonAddElement,
+                &QPushButton::clicked,
+                this,
+                &AronTreeWidgetDictInputModalController::addEmptyElement);
+
+        connect(widget.pushButtonReset,
+                &QPushButton::clicked,
+                this,
+                &AronTreeWidgetDictInputModalController::reset);
+        connect(widget.pushButtonSubmit,
+                &QPushButton::clicked,
+                this,
+                &AronTreeWidgetDictInputModalController::submit);
+    }
+
+    void
+    AronTreeWidgetDictInputModalController::submit()
+    {
+        /*
+        for (const auto& added : addedItems)
+        {
+            item->addChild(added->copy());
+        }
+*/
+
+        AronTreeWidgetModal::submit();
+    }
+
+    void
+    AronTreeWidgetDictInputModalController::reset()
+    {
+        AronTreeWidgetModal::reset();
+
+        // reset to initial value
+        widget.treeWidgetDict->clear();
+        for (int i = 0; i < init.childCount(); ++i)
+        {
+            auto el = init.child(i);
+            widget.treeWidgetDict->addTopLevelItem(el->clone());
+        }
+    }
+
+    void
+    AronTreeWidgetDictInputModalController::addEmptyElement()
+    {
+        QString s = widget.lineEditKey->text();
+        widget.lineEditKey->setText("Enter Key");
+
+        if (widget.treeWidgetDict->findItems(s, Qt::MatchFlag::MatchExactly, 0).empty())
+        {
+            auto t = item->aronType;
+            auto d = aron::type::Dict::DynamicCastAndCheck(t);
+            auto ac = d->getAcceptedType();
+
+            AronTreeWidgetCreatorVisitor v(nullptr);
+            v.setTopLevelWidget(widget.treeWidgetDict);
+            aron::type::visit(v, ac);
+
+            if (v.createdQWidgetItem)
+            {
+                v.createdQWidgetItem->setText(aron_tree_widget::constantes::TREE_WIDGET_ITEM_NAME,
+                                              s);
+                addedItems.push_back(v.createdQWidgetItem);
+                widget.treeWidgetDict->addTopLevelItem(v.createdQWidgetItem);
+            }
+        }
+    }
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/dict/AronTreeWidgetDictInputModalController.h b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/dict/AronTreeWidgetDictInputModalController.h
new file mode 100644
index 0000000000000000000000000000000000000000..f2e992b19eb4d68df7a86c98c538acebc89b8464
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/dict/AronTreeWidgetDictInputModalController.h
@@ -0,0 +1,37 @@
+#pragma once
+
+#include <stack>
+
+#include <QDialog>
+
+#include <ArmarXCore/core/system/ImportExportComponent.h>
+
+#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXComponentWidgetController.h>
+#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h>
+#include <ArmarXGui/libraries/SimpleConfigDialog/SimpleConfigDialog.h>
+
+#include "RobotAPI/libraries/skills_gui/dict/ui_AronTreeWidgetDictInputModal.h"
+
+#include "../AronTreeWidgetModal.h"
+
+namespace armarx::skills::gui
+{
+    class AronTreeWidgetDictInputModalController : public AronTreeWidgetModal
+    {
+    public:
+        AronTreeWidgetDictInputModalController(const std::string& label,
+                                               AronTreeWidgetItem* item,
+                                               QTreeWidget* parent);
+
+    private slots:
+
+        void submit() final;
+        void reset() final;
+
+        void addEmptyElement();
+
+    private:
+        std::vector<AronTreeWidgetItem*> addedItems;
+        Ui::AronTreeWidgetDictInputModalWidget widget;
+    };
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/float_double/AronTreeWidgetFloatInputModal.ui b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/float_double/AronTreeWidgetFloatInputModal.ui
new file mode 100644
index 0000000000000000000000000000000000000000..ba3734066df16e227142f6636d7cb6e39c415646
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/float_double/AronTreeWidgetFloatInputModal.ui
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AronTreeWidgetFloatInputModalWidget</class>
+ <widget class="QWidget" name="AronTreeWidgetFloatInputModalWidget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>1015</width>
+    <height>498</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>SkillManagerMonitorWidget</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QSplitter" name="splitter">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <widget class="QGroupBox" name="groupBoxInput">
+      <property name="title">
+       <string>InputField</string>
+      </property>
+      <layout class="QGridLayout" name="gridLayout">
+       <item row="1" column="0">
+        <widget class="QPushButton" name="pushButtonReset">
+         <property name="text">
+          <string>Reset</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="1">
+        <widget class="QPushButton" name="pushButtonSubmit">
+         <property name="text">
+          <string>Submit</string>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="0" colspan="2">
+        <widget class="QTextEdit" name="textEditInput"/>
+       </item>
+      </layout>
+     </widget>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/float_double/AronTreeWidgetFloatInputModalController.cpp b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/float_double/AronTreeWidgetFloatInputModalController.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..79ce1bdb67c81465e9631348f50a4689de21a093
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/float_double/AronTreeWidgetFloatInputModalController.cpp
@@ -0,0 +1,34 @@
+#include "AronTreeWidgetFloatInputModalController.h"
+
+namespace armarx::skills::gui
+{
+    AronTreeWidgetFloatInputModalController::AronTreeWidgetFloatInputModalController(
+        const std::string& label,
+        AronTreeWidgetItem* item,
+        QTreeWidget* parent) :
+        AronTreeWidgetModal(label, item, parent)
+    {
+        widget.setupUi(this);
+
+        // TODO
+    }
+
+    void
+    AronTreeWidgetFloatInputModalController::submit()
+    {
+        item->setText(aron_tree_widget::constantes::TREE_WIDGET_ITEM_VALUE,
+                      widget.textEditInput->toPlainText());
+
+        AronTreeWidgetModal::submit();
+    }
+
+    void
+    AronTreeWidgetFloatInputModalController::reset()
+    {
+        AronTreeWidgetModal::reset();
+
+        // reset to initial value
+        widget.textEditInput->setPlainText(
+            init.text(aron_tree_widget::constantes::TREE_WIDGET_ITEM_VALUE));
+    }
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/float_double/AronTreeWidgetFloatInputModalController.h b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/float_double/AronTreeWidgetFloatInputModalController.h
new file mode 100644
index 0000000000000000000000000000000000000000..a68834c9a75becaf7eb7075e7947485ae7523dee
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/float_double/AronTreeWidgetFloatInputModalController.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <QDialog>
+
+#include "RobotAPI/libraries/skills_gui/float_double/ui_AronTreeWidgetFloatInputModal.h"
+
+#include "../AronTreeWidgetModal.h"
+
+namespace armarx::skills::gui
+{
+    class AronTreeWidgetFloatInputModalController : public AronTreeWidgetModal
+    {
+
+    public:
+        AronTreeWidgetFloatInputModalController(const std::string& label,
+                                                AronTreeWidgetItem* item,
+                                                QTreeWidget* parent);
+
+    private slots:
+
+        void submit() final;
+        void reset() final;
+
+    private:
+        Ui::AronTreeWidgetFloatInputModalWidget widget;
+    };
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/int_long/AronTreeWidgetIntInputModal.ui b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/int_long/AronTreeWidgetIntInputModal.ui
new file mode 100644
index 0000000000000000000000000000000000000000..538a78e766e997ad9811ff11b6036f088de332e2
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/int_long/AronTreeWidgetIntInputModal.ui
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AronTreeWidgetIntInputModalWidget</class>
+ <widget class="QWidget" name="AronTreeWidgetIntInputModalWidget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>1015</width>
+    <height>498</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>SkillManagerMonitorWidget</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QSplitter" name="splitter">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <widget class="QGroupBox" name="groupBoxInput">
+      <property name="title">
+       <string>InputField</string>
+      </property>
+      <layout class="QGridLayout" name="gridLayout">
+       <item row="1" column="0">
+        <widget class="QPushButton" name="pushButtonReset">
+         <property name="text">
+          <string>Reset</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="1">
+        <widget class="QPushButton" name="pushButtonSubmit">
+         <property name="text">
+          <string>Submit</string>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="0" colspan="2">
+        <widget class="QTextEdit" name="textEditInput"/>
+       </item>
+      </layout>
+     </widget>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/int_long/AronTreeWidgetIntInputModalController.cpp b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/int_long/AronTreeWidgetIntInputModalController.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..72f849c2745c63b41ea0c054dbf70f2f282ba48a
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/int_long/AronTreeWidgetIntInputModalController.cpp
@@ -0,0 +1,34 @@
+#include "AronTreeWidgetIntInputModalController.h"
+
+namespace armarx::skills::gui
+{
+    AronTreeWidgetIntInputModalController::AronTreeWidgetIntInputModalController(
+        const std::string& label,
+        AronTreeWidgetItem* item,
+        QTreeWidget* parent) :
+        AronTreeWidgetModal(label, item, parent)
+    {
+        widget.setupUi(this);
+
+        // TODO
+    }
+
+    void
+    AronTreeWidgetIntInputModalController::submit()
+    {
+        item->setText(aron_tree_widget::constantes::TREE_WIDGET_ITEM_VALUE,
+                      widget.textEditInput->toPlainText());
+
+        AronTreeWidgetModal::submit();
+    }
+
+    void
+    AronTreeWidgetIntInputModalController::reset()
+    {
+        AronTreeWidgetModal::reset();
+
+        // reset to initial value
+        widget.textEditInput->setPlainText(
+            init.text(aron_tree_widget::constantes::TREE_WIDGET_ITEM_VALUE));
+    }
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/int_long/AronTreeWidgetIntInputModalController.h b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/int_long/AronTreeWidgetIntInputModalController.h
new file mode 100644
index 0000000000000000000000000000000000000000..15b3382a4af234d0c435d25787d3f7b3aff822e1
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/int_long/AronTreeWidgetIntInputModalController.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <QDialog>
+
+#include "RobotAPI/libraries/skills_gui/int_long/ui_AronTreeWidgetIntInputModal.h"
+
+#include "../AronTreeWidgetModal.h"
+
+namespace armarx::skills::gui
+{
+    class AronTreeWidgetIntInputModalController : public AronTreeWidgetModal
+    {
+
+    public:
+        AronTreeWidgetIntInputModalController(const std::string& label,
+                                              AronTreeWidgetItem* item,
+                                              QTreeWidget* parent);
+
+    private slots:
+
+        void submit() final;
+        void reset() final;
+
+    private:
+        Ui::AronTreeWidgetIntInputModalWidget widget;
+    };
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/text/AronTreeWidgetTextInputModal.ui b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/text/AronTreeWidgetTextInputModal.ui
new file mode 100644
index 0000000000000000000000000000000000000000..ed40962f96639ff34eed30b85331d7774b2eef9d
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/text/AronTreeWidgetTextInputModal.ui
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AronTreeWidgetTextInputModalWidget</class>
+ <widget class="QWidget" name="AronTreeWidgetTextInputModalWidget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>1015</width>
+    <height>498</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>SkillManagerMonitorWidget</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QSplitter" name="splitter">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <widget class="QGroupBox" name="groupBoxInput">
+      <property name="title">
+       <string>InputField</string>
+      </property>
+      <layout class="QGridLayout" name="gridLayout">
+       <item row="1" column="0">
+        <widget class="QPushButton" name="pushButtonReset">
+         <property name="text">
+          <string>Reset</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="1">
+        <widget class="QPushButton" name="pushButtonSubmit">
+         <property name="text">
+          <string>Submit</string>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="0" colspan="2">
+        <widget class="QTextEdit" name="textEditInput"/>
+       </item>
+      </layout>
+     </widget>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/text/AronTreeWidgetTextInputModalController.cpp b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/text/AronTreeWidgetTextInputModalController.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cfce5ccafb7be7b9b14f76cb99f383fefc452eb2
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/text/AronTreeWidgetTextInputModalController.cpp
@@ -0,0 +1,46 @@
+#include "AronTreeWidgetTextInputModalController.h"
+
+namespace armarx::skills::gui
+{
+    AronTreeWidgetTextInputModalController::AronTreeWidgetTextInputModalController(
+        const std::string& label,
+        AronTreeWidgetItem* item,
+        QTreeWidget* parent) :
+        AronTreeWidgetModal(label, item, parent)
+    {
+        widget.setupUi(this);
+
+        // set header
+        widget.groupBoxInput->setTitle(QString::fromStdString(label));
+        reset();
+
+        // connect signals
+        connect(widget.pushButtonReset,
+                &QPushButton::clicked,
+                this,
+                &AronTreeWidgetTextInputModalController::reset);
+        connect(widget.pushButtonSubmit,
+                &QPushButton::clicked,
+                this,
+                &AronTreeWidgetTextInputModalController::submit);
+    }
+
+    void
+    AronTreeWidgetTextInputModalController::submit()
+    {
+        item->setText(aron_tree_widget::constantes::TREE_WIDGET_ITEM_VALUE,
+                      widget.textEditInput->toPlainText());
+
+        AronTreeWidgetModal::submit();
+    }
+
+    void
+    AronTreeWidgetTextInputModalController::reset()
+    {
+        AronTreeWidgetModal::reset();
+
+        // reset to initial value
+        widget.textEditInput->setPlainText(
+            init.text(aron_tree_widget::constantes::TREE_WIDGET_ITEM_VALUE));
+    }
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/text/AronTreeWidgetTextInputModalController.h b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/text/AronTreeWidgetTextInputModalController.h
new file mode 100644
index 0000000000000000000000000000000000000000..1089a595ec1a9f935785b71519bb821bbddc648f
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/modal/text/AronTreeWidgetTextInputModalController.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <QDialog>
+
+#include "RobotAPI/libraries/skills_gui/text/ui_AronTreeWidgetTextInputModal.h"
+
+#include "../AronTreeWidgetModal.h"
+
+namespace armarx::skills::gui
+{
+    class AronTreeWidgetTextInputModalController : public AronTreeWidgetModal
+    {
+
+    public:
+        AronTreeWidgetTextInputModalController(const std::string& label,
+                                               AronTreeWidgetItem* item,
+                                               QTreeWidget* parent);
+
+    private slots:
+
+        void submit() final;
+        void reset() final;
+
+    private:
+        Ui::AronTreeWidgetTextInputModalWidget widget;
+    };
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetContextMenu.cpp b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetContextMenu.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b02b713032456e3b5a7d37dd3a4f7be294236b87
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetContextMenu.cpp
@@ -0,0 +1,242 @@
+#include "AronTreeWidgetContextMenu.h"
+
+#include <QMenu>
+#include <QPoint>
+#include <QTreeWidget>
+#include <QTreeWidgetItem>
+
+#include "../AronTreeWidgetItem.h"
+#include "../ListDictHelper.h"
+#include "AronTreeWidgetCreator.h"
+
+namespace armarx::skills::gui
+{
+    AronTreeWidgetContextMenuVisitor::AronTreeWidgetContextMenuVisitor(
+        AronTreeWidgetItem* i,
+        const QPoint& pos,
+        QTreeWidget* contextMenuParent,
+        int x) :
+        parentItem(i), contextMenuParent(contextMenuParent), pos(pos), index(x)
+    {
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::addDeleteAction()
+    {
+        auto* castedParent = AronTreeWidgetItem::DynamicCast(parentItem->QTreeWidgetItem::parent());
+        if (!castedParent)
+        {
+            // must be top level element
+            return;
+        }
+        auto aronType = castedParent->aronType->getDescriptor();
+        if (aron::type::Descriptor::DICT == aronType || aron::type::Descriptor::LIST == aronType)
+        {
+            QMenu contextMenu("Context menu", contextMenuParent);
+            actions.emplace_back("remove element", contextMenuParent);
+            action_callbacks.push_back([this]() mutable { this->executeDelete(); });
+        }
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::executeDelete()
+    {
+        auto* containerPtr = parentItem->QTreeWidgetItem::parent();
+        containerPtr->removeChild(parentItem);
+        auto* castedContainer = AronTreeWidgetItem::DynamicCast(containerPtr);
+
+        // if the parent item is a List, we need to redo the numbers
+        if (castedContainer &&
+            castedContainer->aronType->getDescriptor() == aron::type::Descriptor::LIST)
+        {
+            // start renumbering from the removed child onwards
+            for (int i = index; i < castedContainer->childCount(); ++i)
+            {
+                std::string numberString = std::to_string(i);
+                castedContainer->child(i)->setText(0, numberString.c_str());
+            }
+            // This displays the number of children also when the list is collapsed
+            QString numElemsText = misc::generateNumElementsText(castedContainer->childCount());
+            containerPtr->setText(1, numElemsText);
+            // set italic
+            auto currFont = castedContainer->font(1);
+            currFont.setItalic(true);
+            castedContainer->setFont(1, currFont);
+        }
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::ObjectPtr&)
+    {
+        addDeleteAction();
+    }
+
+    // lol
+    void
+    AronTreeWidgetContextMenuVisitor::addAddAction()
+    {
+        actions.emplace_back("Add element", contextMenuParent);
+        action_callbacks.push_back([this]() mutable { this->executeAddElement(); });
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::executeAddElement()
+    {
+        AronTreeWidgetCreatorVisitor creator(parentItem);
+        aron::type::visit(creator, parentItem->aronType->getChildren()[0]);
+
+        if (!creator.createdQWidgetItem)
+        {
+            throw std::runtime_error("Creation of TreeElementChild failed unexpectedly");
+        }
+        // if it is a list, we update the number of children at the top
+        auto* castedContainer = AronTreeWidgetItem::DynamicCast(parentItem);
+
+        // if the parent item is a List, we need to redo the numbers
+        if (castedContainer &&
+            castedContainer->aronType->getDescriptor() == aron::type::Descriptor::LIST)
+        {
+            // This displays the number of children also when the list is collapsed
+            auto numElemsText = misc::generateNumElementsText(castedContainer->childCount());
+            castedContainer->setText(1, numElemsText);
+            // set italic
+            auto currFont = castedContainer->font(1);
+            currFont.setItalic(true);
+            castedContainer->setFont(1, currFont);
+        }
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::DictPtr&)
+    {
+        addAddAction();
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::PairPtr&)
+    {
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::TuplePtr&)
+    {
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::ListPtr&)
+    {
+        addAddAction();
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::NDArrayPtr&)
+    {
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::MatrixPtr&)
+    {
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::QuaternionPtr&)
+    {
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::ImagePtr&)
+    {
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::PointCloudPtr&)
+    {
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::IntEnumPtr&)
+    {
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::IntPtr&)
+    {
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::LongPtr&)
+    {
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::FloatPtr&)
+    {
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::DoublePtr&)
+    {
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::BoolPtr&)
+    {
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitAronVariant(const aron::type::StringPtr&)
+    {
+        addDeleteAction();
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::visitUnknown(Input&)
+    {
+        ARMARX_WARNING << "Tried to open Context menu on unknown aron type";
+    }
+
+    void
+    AronTreeWidgetContextMenuVisitor::showMenuAndExecute()
+    {
+        QMenu menu("Context Menu", contextMenuParent);
+        for (auto& el : actions)
+        {
+            menu.addAction(&el);
+        }
+        auto* chosenAction = menu.exec(contextMenuParent->mapToGlobal(pos));
+
+        if (!chosenAction)
+        {
+            return;
+        }
+
+        // not elegant, but is a small loop anyway
+        auto it = actions.begin();
+        size_t count = 0;
+        while (it != actions.end())
+        {
+            if (chosenAction == &*it)
+            {
+                action_callbacks[count]();
+                break;
+            }
+            ++it;
+            ++count;
+        }
+    }
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetContextMenu.h b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetContextMenu.h
new file mode 100644
index 0000000000000000000000000000000000000000..d83339329e6f69aa9769a2dc5b138fa0d0144ab6
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetContextMenu.h
@@ -0,0 +1,67 @@
+#pragma once
+
+
+#include <QAction>
+
+#include <RobotAPI/libraries/aron/core/data/variant/All.h>
+#include <RobotAPI/libraries/aron/core/type/variant/All.h>
+#include <RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.h>
+
+class QTreeWidget;
+class QPoint;
+
+namespace armarx::skills::gui
+{
+
+    class AronTreeWidgetItem;
+
+    // Visitor on aron types. It creates a  context menu dependent on the type of the AronTreeWidgetItem.
+    // Its only used for Lists and Dicts.
+    class AronTreeWidgetContextMenuVisitor : public armarx::aron::type::ConstVariantVisitor
+    {
+
+        AronTreeWidgetItem* parentItem;
+        QTreeWidget* contextMenuParent;
+        const QPoint& pos;
+        int index;
+
+    public:
+        AronTreeWidgetContextMenuVisitor() = delete;
+        AronTreeWidgetContextMenuVisitor(AronTreeWidgetItem* i,
+                                         const QPoint& pos,
+                                         QTreeWidget* contextMenuParent,
+                                         int x);
+
+        void visitAronVariant(const aron::type::ObjectPtr&) final;
+        void visitAronVariant(const aron::type::DictPtr&) final;
+        void visitAronVariant(const aron::type::PairPtr&) final;
+        void visitAronVariant(const aron::type::TuplePtr&) final;
+        void visitAronVariant(const aron::type::ListPtr&) final;
+        void visitAronVariant(const aron::type::NDArrayPtr&) final;
+        void visitAronVariant(const aron::type::MatrixPtr&) final;
+        void visitAronVariant(const aron::type::QuaternionPtr&) final;
+        void visitAronVariant(const aron::type::ImagePtr&) final;
+        void visitAronVariant(const aron::type::PointCloudPtr&) final;
+        void visitAronVariant(const aron::type::IntEnumPtr&) final;
+        void visitAronVariant(const aron::type::IntPtr&) final;
+        void visitAronVariant(const aron::type::LongPtr&) final;
+        void visitAronVariant(const aron::type::FloatPtr&) final;
+        void visitAronVariant(const aron::type::DoublePtr&) final;
+        void visitAronVariant(const aron::type::BoolPtr&) final;
+        void visitAronVariant(const aron::type::StringPtr&) final;
+        void visitUnknown(Input&) final;
+
+        void showMenuAndExecute();
+
+    private:
+        std::list<QAction> actions;
+        std::vector<std::function<void()>> action_callbacks;
+
+        // Creates a remove option if the element is a direct child of a list or dict
+        void addDeleteAction();
+        void executeDelete();
+
+        void addAddAction();
+        void executeAddElement();
+    };
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetConverter.cpp b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetConverter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..63fc8b0de060b4f79de3a06cb168e8ede1e4efc2
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetConverter.cpp
@@ -0,0 +1,636 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * ArmarX is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ArmarX is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * \package    RobotAPI::gui-plugins::SkillManagerMonitorWidgetController
+ * \author     Raphael Grimm ( raphael dot grimm at kit dot edu )
+ * \date       2020
+ * \copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#include <string>
+
+// base class
+#include "AronTreeWidgetConverter.h"
+
+// armarx
+#include <SimoxUtility/algorithm/string.h>
+
+#include <ArmarXCore/core/logging/Logging.h>
+
+#include "RobotAPI/libraries/aron/core/data/variant/All.h"
+
+// qt
+#include <QTreeWidgetItem>
+
+#include "../widgets/EditMatrixWidget.h"
+#include "../widgets/IntEnumWidget.h"
+#include "../widgets/QuaternionWidget.h"
+
+namespace armarx::skills::gui
+{
+    bool
+    AronTreeWidgetConverterVisitor::isConversionSuccessful()
+    {
+        return !isDirectError && !hasTransitiveError;
+    }
+
+    bool
+    AronTreeWidgetConverterVisitor::onlyChildFailedConversion()
+    {
+        return hasTransitiveError;
+    }
+
+    bool
+    AronTreeWidgetConverterVisitor::hasDirectError() const
+    {
+        return isDirectError;
+    }
+
+    void
+    AronTreeWidgetConverterVisitor::handleErrors(AronTreeWidgetConverterVisitor childV,
+                                                 bool ownFault)
+    {
+        ARMARX_TRACE;
+        isDirectError |= ownFault;
+        hasTransitiveError |= childV.isDirectError || childV.hasTransitiveError;
+
+        auto* aronItem = AronTreeWidgetItem::DynamicCast(parentItem->child(index));
+        ARMARX_CHECK(aronItem);
+        aronItem->setValueErrorState(isDirectError, hasTransitiveError);
+    }
+
+    void
+    AronTreeWidgetConverterVisitor::handleErrors(bool ownFault)
+    {
+        ARMARX_TRACE;
+        isDirectError = ownFault;
+        auto* aronItem = AronTreeWidgetItem::DynamicCast(parentItem->child(index));
+        ARMARX_CHECK(aronItem);
+        aronItem->setValueErrorState(isDirectError, false);
+    }
+
+    void
+    AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::ObjectPtr& i)
+    {
+        ARMARX_TRACE;
+        auto createdAronDict = std::make_shared<aron::data::Dict>(i->getPath());
+        createdAron = createdAronDict;
+        QTreeWidgetItem* el = parentItem->child(index);
+
+        if (i->getMaybe() != armarx::aron::type::Maybe::NONE)
+        {
+            // its a maybetype. We have to check the state
+            if (el->checkState(1) == Qt::CheckState::Unchecked)
+            {
+                createdAron = nullptr;
+                return;
+            }
+        }
+
+        unsigned int x = 0;
+        for (const auto& [key, value] : i->getMemberTypes())
+        {
+            ARMARX_TRACE;
+            AronTreeWidgetConverterVisitor v(el, x++);
+            aron::type::visit(v, value);
+
+            handleErrors(v);
+            if (v.isConversionSuccessful())
+            {
+                createdAronDict->addElement(key, v.createdAron);
+            }
+        }
+    }
+
+    void
+    AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::DictPtr& i)
+    {
+        ARMARX_TRACE;
+        auto createdAronDict = std::make_shared<aron::data::Dict>(i->getPath());
+        createdAron = createdAronDict;
+        QTreeWidgetItem* el = parentItem->child(index);
+
+        if (i->getMaybe() != armarx::aron::type::Maybe::NONE)
+        {
+            // its a maybetype. We have to check the state
+            if (el->checkState(1) == Qt::CheckState::Unchecked)
+            {
+                createdAron = nullptr;
+                return;
+            }
+        }
+
+        for (int x = 0; x < el->childCount(); ++x)
+        {
+            auto it = el->child(x);
+            AronTreeWidgetConverterVisitor v(el, x);
+            aron::type::visit(v, i->getAcceptedType());
+            auto key = it->text(0).toStdString();
+            // TODO: handle key errors more elegantly / separately, fine for now
+            handleErrors(v, createdAronDict->hasElement(key));
+            if (v.createdAron && v.isConversionSuccessful() && !createdAronDict->hasElement(key))
+            {
+                createdAronDict->addElement(key, v.createdAron);
+            }
+        }
+    }
+
+    void
+    AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::ListPtr& i)
+    {
+        ARMARX_TRACE;
+        auto createdAronList = std::make_shared<aron::data::List>(i->getPath());
+        createdAron = createdAronList;
+        auto* el = parentItem->child(index);
+
+        if (i->getMaybe() != armarx::aron::type::Maybe::NONE)
+        {
+            // its a maybetype. We have to check the state
+            if (el->checkState(1) == Qt::CheckState::Unchecked)
+            {
+                createdAron = nullptr;
+                return;
+            }
+        }
+
+        auto childrenTypes = i->getChildren();
+        ARMARX_CHECK(childrenTypes.size() == 1);
+        for (int j = 0; j < el->childCount(); ++j)
+        {
+            AronTreeWidgetConverterVisitor convVisitor(el, j);
+            aron::type::visit(convVisitor, childrenTypes[0]);
+            handleErrors(convVisitor);
+
+            if (convVisitor.createdAron && convVisitor.isConversionSuccessful())
+            {
+                createdAronList->addElement(convVisitor.createdAron);
+            }
+        }
+    }
+
+    void
+    AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::PairPtr& i)
+    {
+        ARMARX_TRACE;
+        auto createdAronPair = std::make_shared<aron::data::List>(i->getPath());
+        createdAron = createdAronPair;
+        auto* el = parentItem->child(index);
+
+        if (i->getMaybe() != armarx::aron::type::Maybe::NONE)
+        {
+            // its a maybetype. We have to check the state
+            if (el->checkState(1) == Qt::CheckState::Unchecked)
+            {
+                createdAron = nullptr;
+                return;
+            }
+        }
+
+        for (int j = 0; j < 2; ++j)
+        {
+            AronTreeWidgetConverterVisitor convVisitor(el, j);
+            handleErrors(convVisitor);
+            if (convVisitor.createdAron && convVisitor.isConversionSuccessful())
+            {
+                createdAronPair->addElement(convVisitor.createdAron);
+            }
+        }
+    }
+
+    void
+    AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::TuplePtr& i)
+    {
+        ARMARX_TRACE;
+        auto createdAronList = std::make_shared<aron::data::List>(i->getPath());
+        createdAron = createdAronList;
+        QTreeWidgetItem* el = parentItem->child(index);
+
+        if (i->getMaybe() != armarx::aron::type::Maybe::NONE)
+        {
+            // its a maybetype. We have to check the state
+            if (el->checkState(1) == Qt::CheckState::Unchecked)
+            {
+                createdAron = nullptr;
+                return;
+            }
+        }
+
+        for (int x = 0; x < el->childCount(); ++x)
+        {
+            auto* it = el->child(x);
+            AronTreeWidgetConverterVisitor v(it, x);
+            aron::type::visit(v, i->getAcceptedType(x));
+            handleErrors(v);
+
+            if (v.createdAron)
+            {
+                createdAronList->addElement(v.createdAron);
+            }
+        }
+    }
+
+    void
+    AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::NDArrayPtr& i)
+    {
+        ARMARX_TRACE;
+        ARMARX_ERROR << "Currently do not support supplying raw NDArrays!";
+    }
+
+    void
+    AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::MatrixPtr& i)
+    {
+        ARMARX_TRACE;
+        auto createdMatrix = std::make_shared<aron::data::NDArray>(i->getPath());
+        int dataSize = 0;
+        switch (i->getElementType())
+        {
+            case armarx::aron::type::matrix::INT16:
+                dataSize = 2;
+                break;
+            case armarx::aron::type::matrix::INT32:
+            case armarx::aron::type::matrix::FLOAT32:
+                dataSize = 4;
+                break;
+            case armarx::aron::type::matrix::FLOAT64:
+            case armarx::aron::type::matrix::INT64:
+                dataSize = 8;
+                break;
+        };
+
+        // UGLY HACK: FIX ME!!!
+        switch (i->getElementType())
+        {
+            case armarx::aron::type::matrix::INT16:
+                createdMatrix->setType("short");
+                break;
+            case armarx::aron::type::matrix::INT32:
+                createdMatrix->setType("int");
+                break;
+            case armarx::aron::type::matrix::FLOAT32:
+                createdMatrix->setType("float");
+                break;
+            case armarx::aron::type::matrix::FLOAT64:
+                createdMatrix->setType("double");
+                break;
+            case armarx::aron::type::matrix::INT64:
+                createdMatrix->setType("long");
+                break;
+        };
+
+        createdMatrix->setShape({i->getRows(), i->getCols(), dataSize});
+        int totalByteSize = i->getRows() * i->getCols() * dataSize;
+        createdAron = createdMatrix;
+        auto* el = parentItem->child(index);
+
+        if (i->getMaybe() != armarx::aron::type::Maybe::NONE)
+        {
+            // its a maybetype. We have to check the state
+            if (el->checkState(1) == Qt::CheckState::Unchecked)
+            {
+                createdAron = nullptr;
+                return;
+            }
+        }
+
+
+        auto* rootWidget = el->treeWidget();
+        ARMARX_CHECK(rootWidget);
+        auto* widget = rootWidget->itemWidget(el, 1);
+        auto* matrixWidget = EditMatrixWidget::DynamicCastAndCheck(widget);
+
+        handleErrors(matrixWidget->hasParseErrors());
+        if (matrixWidget->hasParseErrors())
+        {
+            return;
+        }
+        // write to aron data
+        std::vector<unsigned char> elems;
+        elems.reserve(totalByteSize);
+        // CAUTION: Raw data has column based storage
+        for (size_t col = 0; col < (size_t)i->getCols(); ++col)
+        {
+            for (size_t row = 0; row < (size_t)i->getRows(); ++row)
+            {
+                // gets us directly the byte wise format
+                auto parsed = matrixWidget->parseElement(row, col);
+                // append vector to vector
+                elems.insert(elems.end(), parsed.begin(), parsed.end());
+            }
+        }
+        createdMatrix->setData(totalByteSize, elems.data());
+    }
+
+    void
+    AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::QuaternionPtr& i)
+    {
+        ARMARX_TRACE;
+        auto createdQuat = std::make_shared<aron::data::NDArray>(i->getPath());
+        createdAron = createdQuat;
+        int dataSize = i->getElementType() == aron::type::quaternion::ElementType::FLOAT32 ? 4 : 8;
+        createdQuat->setShape({1, 4, dataSize});
+        createdQuat->setType(i->getFullName());
+        auto* el = parentItem->child(index);
+
+        if (i->getMaybe() != armarx::aron::type::Maybe::NONE)
+        {
+            // its a maybetype. We have to check the state
+            if (el->checkState(1) == Qt::CheckState::Unchecked)
+            {
+                createdAron = nullptr;
+                return;
+            }
+        }
+
+        auto* itemWidget = el->treeWidget()->itemWidget(el, 1);
+        auto* quatWidget = QuaternionWidget::DynamicCastAndCheck(itemWidget);
+
+        // error handling
+        handleErrors(quatWidget->hasParseErrors());
+        if (quatWidget->hasParseErrors())
+        {
+            return;
+        }
+
+        // write to aron data
+        auto serialized = quatWidget->parseAllToNDArray();
+        if ((int)serialized.size() != dataSize * 4)
+        {
+            ARMARX_ERROR
+                << "serialized quaternions did not return byte sequence of correct length!";
+        }
+        createdQuat->setData(serialized.size(), serialized.data());
+    }
+
+    void
+    AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::ImagePtr& i)
+    {
+        ARMARX_TRACE;
+        // TODO
+    }
+
+    void
+    AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::PointCloudPtr& i)
+    {
+        ARMARX_TRACE;
+        // TODO
+    }
+
+    void
+    AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::IntEnumPtr& i)
+    {
+        ARMARX_TRACE;
+        QTreeWidgetItem* el = parentItem->child(index);
+
+        if (i->getMaybe() != armarx::aron::type::Maybe::NONE)
+        {
+            // its a maybetype. We have to check the state
+            if (el->checkState(1) == Qt::CheckState::Unchecked)
+            {
+                createdAron = nullptr;
+                return;
+            }
+        }
+
+        auto* genericWidget = el->treeWidget()->itemWidget(el, 1);
+        auto* intEnumWidget = IntEnumWidget::DynamicCastAndCheck(genericWidget);
+        if (!intEnumWidget)
+        {
+            // already reporting error; continue here
+            return;
+        }
+        bool success;
+        std::tie(success, createdAron) = intEnumWidget->parseToAron();
+
+        handleErrors(!success);
+    }
+
+    void
+    AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::IntPtr& i)
+    {
+        ARMARX_TRACE;
+        auto createdAronInt = std::make_shared<aron::data::Int>(i->getPath());
+        createdAron = createdAronInt;
+        QTreeWidgetItem* el = parentItem->child(index);
+
+        if (i->getMaybe() != armarx::aron::type::Maybe::NONE)
+        {
+            // its a maybetype. We have to check the state
+            if (el->checkState(1) == Qt::CheckState::Unchecked)
+            {
+                createdAron = nullptr;
+                return;
+            }
+        }
+
+        std::string str = el->text(1).toStdString();
+        if (str.empty())
+        {
+            createdAronInt->setValue(0);
+            return;
+        }
+        try
+        {
+            int val = simox::alg::to_<int>(str);
+            createdAronInt->setValue(val);
+        }
+        catch (const simox::error::SimoxError& err)
+        {
+            handleErrors();
+            ARMARX_VERBOSE << "Conversion from String to Int failed. Error:\"" << err.what()
+                           << "\"";
+            return;
+        }
+        handleErrors(false);
+    }
+
+    void
+    AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::LongPtr& i)
+    {
+        ARMARX_TRACE;
+        auto createdAronLong = std::make_shared<aron::data::Long>(i->getPath());
+        createdAron = createdAronLong;
+        QTreeWidgetItem* el = parentItem->child(index);
+
+        if (i->getMaybe() != armarx::aron::type::Maybe::NONE)
+        {
+            // its a maybetype. We have to check the state
+            if (el->checkState(1) == Qt::CheckState::Unchecked)
+            {
+                createdAron = nullptr;
+                return;
+            }
+        }
+
+        std::string str = el->text(1).toStdString();
+        if (str.empty())
+        {
+            //TODO: similar behaviour for rest?
+            str = el->text(3).toStdString();
+        }
+        try
+        {
+            createdAronLong->setValue(simox::alg::to_<long>(str));
+        }
+        catch (const simox::error::SimoxError& err)
+        {
+            handleErrors();
+            ARMARX_VERBOSE << "Conversion from String to Long failed. Error:\"" << err.what()
+                           << "\"";
+            return;
+        }
+        handleErrors(false);
+    }
+
+    void
+    AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::FloatPtr& i)
+    {
+        ARMARX_TRACE;
+        auto createdAronFloat = std::make_shared<aron::data::Float>(i->getPath());
+        createdAron = createdAronFloat;
+        QTreeWidgetItem* el = parentItem->child(index);
+
+        if (i->getMaybe() != armarx::aron::type::Maybe::NONE)
+        {
+            // its a maybetype. We have to check the state
+            if (el->checkState(1) == Qt::CheckState::Unchecked)
+            {
+                createdAron = nullptr;
+                return;
+            }
+        }
+
+        std::string str = el->text(1).toStdString();
+        if (str.empty())
+        {
+            str = el->text(3).toStdString();
+        }
+        try
+        {
+            createdAronFloat->setValue(simox::alg::to_<float>(str));
+        }
+        catch (const simox::error::SimoxError& err)
+        {
+            handleErrors();
+            ARMARX_VERBOSE << "Conversion from String to Float failed. Error:\"" << err.what()
+                           << "\"";
+            return;
+        }
+        handleErrors(false);
+    }
+
+    void
+    AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::DoublePtr& i)
+    {
+        ARMARX_TRACE;
+        auto createdAronDouble = std::make_shared<aron::data::Double>(i->getPath());
+        createdAron = createdAronDouble;
+        QTreeWidgetItem* el = parentItem->child(index);
+
+        if (i->getMaybe() != armarx::aron::type::Maybe::NONE)
+        {
+            // its a maybetype. We have to check the state
+            if (el->checkState(1) == Qt::CheckState::Unchecked)
+            {
+                createdAron = nullptr;
+                return;
+            }
+        }
+
+        std::string str = el->text(1).toStdString();
+        if (str.empty())
+        {
+            str = el->text(3).toStdString();
+        }
+        try
+        {
+            createdAronDouble->setValue(simox::alg::to_<double>(str));
+        }
+        catch (const simox::error::SimoxError& err)
+        {
+            handleErrors();
+            ARMARX_VERBOSE << "Conversion from String to Double failed. Error:\"" << err.what()
+                           << "\"";
+            return;
+        }
+        handleErrors(false);
+    }
+
+    void
+    AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::BoolPtr& i)
+    {
+        ARMARX_TRACE;
+        auto createdAronBool = std::make_shared<aron::data::Bool>(i->getPath());
+        createdAron = createdAronBool;
+        QTreeWidgetItem* el = parentItem->child(index);
+
+        if (i->getMaybe() != armarx::aron::type::Maybe::NONE)
+        {
+            // its a maybetype. We have to check the state
+            if (el->checkState(1) == Qt::CheckState::Unchecked)
+            {
+                createdAron = nullptr;
+                return;
+            }
+        }
+
+        std::string str = el->text(1).toStdString();
+        if (str.empty())
+        {
+            str = el->text(3).toStdString();
+        }
+        try
+        {
+            createdAronBool->setValue(simox::alg::to_<bool>(str));
+        }
+        catch (const simox::error::SimoxError& err)
+        {
+            handleErrors();
+            ARMARX_VERBOSE << "Conversion from String to Bool failed. Error:\"" << err.what()
+                           << "\"";
+            return;
+        }
+        handleErrors(false);
+    }
+
+    void
+    AronTreeWidgetConverterVisitor::visitAronVariant(const aron::type::StringPtr& i)
+    {
+        ARMARX_TRACE;
+        auto createdAronString = std::make_shared<aron::data::String>(i->getPath());
+        createdAron = createdAronString;
+        QTreeWidgetItem* el = parentItem->child(index);
+
+        if (i->getMaybe() != armarx::aron::type::Maybe::NONE)
+        {
+            // its a maybetype. We have to check the state
+            if (el->checkState(1) == Qt::CheckState::Unchecked)
+            {
+                createdAron = nullptr;
+                return;
+            }
+        }
+
+        std::string str = el->text(1).toStdString();
+        createdAronString->setValue(str);
+    }
+
+    void
+    AronTreeWidgetConverterVisitor::visitUnknown(Input&)
+    {
+        ARMARX_WARNING_S << "Received an unknown type when trying to convert a skill argument type "
+                            "to an aron data object.";
+    }
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetConverter.h b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetConverter.h
new file mode 100644
index 0000000000000000000000000000000000000000..ff16506dabdfdcda5d23e128fb8975e435bb8158
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetConverter.h
@@ -0,0 +1,84 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * ArmarX is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ArmarX is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @package    RobotAPI::gui-plugins::SkillManagerMonitorWidgetController
+ * @author     Raphael Grimm ( raphael dot grimm at kit dot edu )
+ * @date       2020
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+#pragma once
+
+#include <RobotAPI/libraries/aron/core/data/variant/All.h>
+#include <RobotAPI/libraries/aron/core/type/variant/All.h>
+#include <RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.h>
+
+// forward declarations of qt
+class QTreeWidgetItem;
+
+namespace armarx::skills::gui
+{
+    // Conversion from TreeView to aron data
+    class AronTreeWidgetConverterVisitor : public armarx::aron::type::ConstVariantVisitor
+    {
+    public:
+        QTreeWidgetItem* parentItem;
+        int index;
+        aron::data::VariantPtr createdAron = nullptr;
+
+        AronTreeWidgetConverterVisitor() = delete;
+
+        AronTreeWidgetConverterVisitor(QTreeWidgetItem* i, int x) : parentItem(i), index(x)
+        {
+        }
+
+        // if the conversion was successful after calling visit()
+        bool isConversionSuccessful();
+        // returns true if this type itself was sucessfully parsed, but some contained object failed.
+        // also false if there is no error
+        bool onlyChildFailedConversion();
+
+        bool hasDirectError() const;
+
+    private:
+        bool isDirectError = false;
+        bool hasTransitiveError = false;
+        // adds all errors from other visitor to our own error collection -> collecting errors
+        // with ownFault, we also add this node to the collection
+        void handleErrors(AronTreeWidgetConverterVisitor childV, bool ownFault = false);
+        // we are the cause...
+        void handleErrors(bool ownFault = true);
+
+    public:
+        void visitAronVariant(const aron::type::ObjectPtr&) final;
+        void visitAronVariant(const aron::type::DictPtr&) final;
+        void visitAronVariant(const aron::type::PairPtr&) final;
+        void visitAronVariant(const aron::type::TuplePtr&) final;
+        void visitAronVariant(const aron::type::ListPtr&) final;
+        void visitAronVariant(const aron::type::NDArrayPtr&) final;
+        void visitAronVariant(const aron::type::MatrixPtr&) final;
+        void visitAronVariant(const aron::type::QuaternionPtr&) final;
+        void visitAronVariant(const aron::type::ImagePtr&) final;
+        void visitAronVariant(const aron::type::PointCloudPtr&) final;
+        void visitAronVariant(const aron::type::IntEnumPtr&) final;
+        void visitAronVariant(const aron::type::IntPtr&) final;
+        void visitAronVariant(const aron::type::LongPtr&) final;
+        void visitAronVariant(const aron::type::FloatPtr&) final;
+        void visitAronVariant(const aron::type::DoublePtr&) final;
+        void visitAronVariant(const aron::type::BoolPtr&) final;
+        void visitAronVariant(const aron::type::StringPtr&) final;
+        void visitUnknown(Input&) final;
+    };
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetCreator.cpp b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetCreator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..037c8dab99d890443224e1491d25337dd901c085
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetCreator.cpp
@@ -0,0 +1,354 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * ArmarX is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ArmarX is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * \package    RobotAPI::gui-plugins::SkillManagerMonitorWidgetController
+ * \author     Raphael Grimm ( raphael dot grimm at kit dot edu )
+ * \date       2020
+ * \copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#include <string>
+
+#include "../widgets/EditMatrixWidget.h"
+#include "../widgets/IntEnumWidget.h"
+#include "../widgets/QuaternionWidget.h"
+
+// base class
+#include "AronTreeWidgetCreator.h"
+
+// data
+#include <QComboBox>
+
+#include "../AronTreeWidgetItem.h"
+#include "../Data.h"
+#include "../ListDictHelper.h"
+#include "AronTreeWidgetContextMenu.h"
+
+namespace armarx::skills::gui
+{
+
+    AronTreeWidgetCreatorVisitor::AronTreeWidgetCreatorVisitor(QTreeWidgetItem* parentInstance) :
+        parentOfCreatedObj(parentInstance)
+    {
+        // The parent of the root aron Tree Widget will not be aron type.
+        // there an explicit setTopLevelWidget() is required.
+        auto* aronParent = AronTreeWidgetItem::DynamicCast(parentInstance);
+        if (aronParent)
+        {
+            toplevelWidget = aronParent->treeWidget();
+        }
+    }
+
+    std::string
+    AronTreeWidgetCreatorVisitor::generateUniqueKeyFromSet(std::set<std::string>&& usedKeys)
+    {
+        size_t num = 0;
+        while (true)
+        {
+            std::string proposedName = this->defaultMapKeyName + std::to_string(num);
+            auto it = usedKeys.find(proposedName);
+            if (it == usedKeys.end())
+            {
+                break;
+            }
+            ++num;
+        }
+        return this->defaultMapKeyName + std::to_string(num);
+    }
+
+    void
+    AronTreeWidgetCreatorVisitor::insertNewTreeViewWidget(Input& i, const std::string& defaul)
+    {
+        ARMARX_CHECK_NOT_NULL(i);
+
+        auto key = i->getPath().getLastElement();
+        bool isDictChild = false;
+        // edit key, to be a unique string, if the parent is a dict
+        auto* aronParent = AronTreeWidgetItem::DynamicCast(parentOfCreatedObj);
+        if (aronParent && aronParent->aronType->getDescriptor() == aron::type::Descriptor::DICT)
+        {
+            isDictChild = true;
+            std::set<std::string> usedKeys;
+            for (int i = 0; i < parentOfCreatedObj->childCount(); ++i)
+            {
+                auto* sibling = AronTreeWidgetItem::DynamicCast(parentOfCreatedObj->child(i));
+                if (sibling)
+                {
+                    usedKeys.insert(sibling->text(0).toStdString());
+                }
+            }
+            key = generateUniqueKeyFromSet(std::move(usedKeys));
+        }
+        // if it's a list -> choose the right number
+        else if (aronParent &&
+                 aronParent->aronType->getDescriptor() == aron::type::Descriptor::LIST)
+        {
+            key = std::to_string(parentOfCreatedObj->childCount());
+        }
+
+        createdQWidgetItem =
+            new AronTreeWidgetItem(isDictChild, editableValue, QString::fromStdString(key), i);
+
+        if (i->getMaybe() != armarx::aron::type::Maybe::NONE)
+        {
+            createdQWidgetItem->setCheckState(1, Qt::CheckState::Unchecked);
+        }
+        createdQWidgetItem->setText(1, QString::fromStdString(defaul));
+        createdQWidgetItem->setText(2, QString::fromStdString(i->getShortName()));
+        createdQWidgetItem->setText(
+            3,
+            QString::fromStdString(
+                aron_tree_widget::constantes::
+                    ITEM_EMPTY_MESSAGE) /*QString::fromStdString(i->getDefaultFromString())*/);
+
+        if (editableValue || isDictChild)
+        {
+            createdQWidgetItem->setFlags(createdQWidgetItem->flags() | Qt::ItemIsEditable);
+        }
+        parentOfCreatedObj->addChild(createdQWidgetItem);
+    }
+
+    void
+    AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::ObjectPtr& i)
+    {
+        ARMARX_CHECK_NOT_NULL(i);
+
+        auto key = i->getObjectName();
+        if (i->getPath().hasElement())
+        {
+            key = i->getPath().getLastElement();
+        }
+
+        createdQWidgetItem =
+            new AronTreeWidgetItem(editableValue, false, QString::fromStdString(key), i);
+
+        if (i->getMaybe() != armarx::aron::type::Maybe::NONE)
+        {
+            createdQWidgetItem->setCheckState(1, Qt::CheckState::Unchecked);
+        }
+
+        parentOfCreatedObj->addChild(createdQWidgetItem);
+
+        for (const auto& [key, value] : i->getMemberTypes())
+        {
+            AronTreeWidgetCreatorVisitor v(createdQWidgetItem);
+            aron::type::visit(v, value);
+
+            assert(v.createdQWidgetItem);
+        }
+    }
+
+    void
+    AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::DictPtr& i)
+    {
+        ARMARX_CHECK_NOT_NULL(i);
+
+        insertNewTreeViewWidget(i, "");
+        // The DictType has only one member, its key-type. This also must be present
+        ARMARX_CHECK_EQUAL(i->getChildren().size(), 1);
+    }
+
+    void
+    AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::PairPtr& pair)
+    {
+        // create default, uneditable tree widget item.
+        insertNewTreeViewWidget(pair, "");
+        // attach two children
+        ARMARX_CHECK(pair->getChildren().size() == 2);
+        for (size_t i = 0; i < 2; ++i)
+        {
+            AronTreeWidgetCreatorVisitor v(createdQWidgetItem);
+            aron::type::visit(v, pair->getChildren()[i]);
+            if (v.createdQWidgetItem)
+            {
+                std::string descr = "p[" + std::to_string(i) + "]";
+                v.createdQWidgetItem->setText(0, descr.c_str());
+            }
+        }
+    }
+
+    void
+    AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::TuplePtr& tuple)
+    {
+        // CAUTION; UNTESTED
+        // create default, uneditable tree widget item.
+        insertNewTreeViewWidget(tuple, "");
+        // attach all children
+        for (size_t i = 0; i < tuple->getChildren().size(); ++i)
+        {
+            AronTreeWidgetCreatorVisitor v(createdQWidgetItem);
+            aron::type::visit(v, tuple->getChildren()[i]);
+            if (v.createdQWidgetItem)
+            {
+                std::string descr = "tup[" + std::to_string(i) + "]";
+                v.createdQWidgetItem->setText(0, descr.c_str());
+            }
+        }
+    }
+
+    void
+    AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::ListPtr& i)
+    {
+        insertNewTreeViewWidget(i, "");
+        auto txt = misc::generateNumElementsText(0);
+        createdQWidgetItem->setText(1, txt);
+    }
+
+    void
+    AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::NDArrayPtr& i)
+    {
+        insertNewTreeViewWidget(i, "");
+    }
+
+    void
+    AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::MatrixPtr& i)
+    {
+        editableValue = false;
+        insertNewTreeViewWidget(i, "");
+        // special code to print the type of base type used
+        QString type = "";
+        switch (i->getElementType())
+        {
+            case armarx::aron::type::matrix::INT16:
+                type = "<int16>";
+                break;
+            case armarx::aron::type::matrix::INT32:
+                type = "<int32>";
+                break;
+            case armarx::aron::type::matrix::INT64:
+                type = "<int64>";
+                break;
+            case armarx::aron::type::matrix::FLOAT32:
+                type = "<float>";
+                break;
+            case armarx::aron::type::matrix::FLOAT64:
+                type = "<double>";
+                break;
+        }
+        type = createdQWidgetItem->text(2) + type;
+        createdQWidgetItem->setText(2, type);
+
+        // Widget fiddling source: https://blog.manash.io/quick-qt-6-how-to-add-qpushbutton-or-widgets-to-a-qtreewidget-as-qtreewidgetitem-2ae9f54c0e5f
+        // overlay custom widget in column 1
+        auto* toplevelWidget = createdQWidgetItem->treeWidget();
+        EditMatrixWidget* matWidget = new EditMatrixWidget(
+            i->getRows(), i->getCols(), i->getElementType(), createdQWidgetItem);
+        toplevelWidget->setItemWidget(createdQWidgetItem, 1, matWidget);
+    }
+
+    void
+    AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::QuaternionPtr& i)
+    {
+        editableValue = false;
+        insertNewTreeViewWidget(i, "");
+        // special code to print the type of base type used
+        QString type = "";
+        switch (i->getElementType())
+        {
+            case armarx::aron::type::quaternion::FLOAT32:
+                type = "<float>";
+                break;
+            case armarx::aron::type::quaternion::FLOAT64:
+                type = "<double>";
+                break;
+        }
+        type = createdQWidgetItem->text(2) + type;
+        createdQWidgetItem->setText(2, type);
+
+        auto* toplevelWidget = createdQWidgetItem->treeWidget();
+        QuaternionWidget* quatWidget =
+            new QuaternionWidget(i->getElementType(), createdQWidgetItem);
+        toplevelWidget->setItemWidget(createdQWidgetItem, 1, quatWidget);
+    }
+
+    void
+    AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::ImagePtr& i)
+    {
+        insertNewTreeViewWidget(i, "");
+    }
+
+    void
+    AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::PointCloudPtr& i)
+    {
+        insertNewTreeViewWidget(i, "");
+    }
+
+    void
+    AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::IntEnumPtr& i)
+    {
+        editableValue = false;
+        ARMARX_CHECK_NOT_NULL(i);
+        ARMARX_CHECK_GREATER(i->getAcceptedValueNames().size(), 0);
+
+        insertNewTreeViewWidget(i, "");
+        IntEnumWidget* widget = new IntEnumWidget(i, createdQWidgetItem);
+        createdQWidgetItem->treeWidget()->setItemWidget(createdQWidgetItem, 1, widget);
+    }
+
+    void
+    AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::IntPtr& i)
+    {
+        editableValue = true;
+        insertNewTreeViewWidget(i, "0");
+    }
+
+    void
+    AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::LongPtr& i)
+    {
+        editableValue = true;
+        insertNewTreeViewWidget(i, "0");
+    }
+
+    void
+    AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::FloatPtr& i)
+    {
+        editableValue = true;
+        insertNewTreeViewWidget(i, "0.0");
+    }
+
+    void
+    AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::DoublePtr& i)
+    {
+        editableValue = true;
+        insertNewTreeViewWidget(i, "0.0");
+    }
+
+    void
+    AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::BoolPtr& i)
+    {
+        editableValue = true;
+        insertNewTreeViewWidget(i, "false");
+    }
+
+    void
+    AronTreeWidgetCreatorVisitor::visitAronVariant(const aron::type::StringPtr& i)
+    {
+        insertNewTreeViewWidget(i, "");
+    }
+
+    void
+    AronTreeWidgetCreatorVisitor::visitUnknown(Input&)
+    {
+        ARMARX_WARNING_S << "Received an unknown type when trying to create a tree view widget for "
+                            "a skill argument type.";
+    }
+
+    void
+    AronTreeWidgetCreatorVisitor::setTopLevelWidget(QTreeWidget* widget)
+    {
+        toplevelWidget = widget;
+    }
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetCreator.h b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetCreator.h
new file mode 100644
index 0000000000000000000000000000000000000000..ee3943dcd481d28abce4ef58d6f3e87956002cd8
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetCreator.h
@@ -0,0 +1,81 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * ArmarX is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ArmarX is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @package    RobotAPI::gui-plugins::SkillManagerMonitorWidgetController
+ * @author     Raphael Grimm ( raphael dot grimm at kit dot edu )
+ * @date       2020
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+#pragma once
+
+#include <QTreeWidgetItem>
+
+#include <RobotAPI/libraries/aron/core/data/variant/All.h>
+#include <RobotAPI/libraries/aron/core/type/variant/All.h>
+#include <RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.h>
+
+namespace armarx::skills::gui
+{
+    class AronTreeWidgetItem;
+
+    // Convert aron type to tree widgets
+    class AronTreeWidgetCreatorVisitor : public armarx::aron::type::ConstVariantVisitor
+    {
+    public:
+        AronTreeWidgetItem* createdQWidgetItem = nullptr;
+
+        AronTreeWidgetCreatorVisitor() = delete;
+
+        // Takes the parent tree element and attaches the newly crated object during visit() to it.
+        // This allows us to also use information of the parent object during creation (like if this child is a dict entry or part of a list)
+        // IMPORTANT: For the root element, manually set the topLevelWidget after this constructor
+        AronTreeWidgetCreatorVisitor(QTreeWidgetItem* parentInstance);
+
+        void insertNewTreeViewWidget(Input& i, const std::string&);
+
+
+        void visitAronVariant(const aron::type::ObjectPtr&) final;
+        void visitAronVariant(const aron::type::DictPtr& i) final;
+        void visitAronVariant(const aron::type::PairPtr& i) final;
+        void visitAronVariant(const aron::type::TuplePtr& i) final;
+        void visitAronVariant(const aron::type::ListPtr& i) final;
+        void visitAronVariant(const aron::type::NDArrayPtr& i) final;
+        void visitAronVariant(const aron::type::MatrixPtr& i) final;
+        void visitAronVariant(const aron::type::QuaternionPtr& i) final;
+        void visitAronVariant(const aron::type::ImagePtr& i) final;
+        void visitAronVariant(const aron::type::PointCloudPtr& i) final;
+        void visitAronVariant(const aron::type::IntEnumPtr& i) final;
+        void visitAronVariant(const aron::type::IntPtr& i) final;
+        void visitAronVariant(const aron::type::LongPtr& i) final;
+        void visitAronVariant(const aron::type::FloatPtr& i) final;
+        void visitAronVariant(const aron::type::DoublePtr& i) final;
+        void visitAronVariant(const aron::type::BoolPtr& i) final;
+        void visitAronVariant(const aron::type::StringPtr& i) final;
+        void visitUnknown(Input&) final;
+
+        // setter for the widget attachment point. Only needs to be manually set for the root element.
+        void setTopLevelWidget(QTreeWidget* widget);
+
+    private:
+        void handleEditable();
+        std::string generateUniqueKeyFromSet(std::set<std::string>&& usedKeys);
+        QTreeWidgetItem* parentOfCreatedObj = nullptr;
+        QTreeWidget* toplevelWidget = nullptr;
+        const std::string defaultMapKeyName = "key_";
+        // controls, if values (column 1) can be edited directly
+        bool editableValue = false;
+    };
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetModalCreator.cpp b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetModalCreator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..81a75a5da145e85c1f39c84c49dc8bf1372a21a5
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetModalCreator.cpp
@@ -0,0 +1,53 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * ArmarX is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ArmarX is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * \package    RobotAPI::gui-plugins::SkillManagerMonitorWidgetController
+ * \author     Raphael Grimm ( raphael dot grimm at kit dot edu )
+ * \date       2020
+ * \copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#include "AronTreeWidgetModalCreator.h"
+
+#include <string>
+
+#include <SimoxUtility/algorithm/string.h>
+
+// modals
+#include "../modal/text/AronTreeWidgetTextInputModalController.h"
+//#include "../modal/dict/AronTreeWidgetDictInputModalController.h"
+
+// qt
+#include <QTreeWidget>
+
+//visitors
+namespace armarx::skills::gui
+{
+
+    void
+    AronTreeWidgetModalCreatorVisitor::visitAronVariant(const aron::type::StringPtr& i)
+    {
+        createdModal =
+            std::make_shared<AronTreeWidgetTextInputModalController>(label, item, parent);
+    }
+
+    void
+    AronTreeWidgetModalCreatorVisitor::visitUnknown(Input&)
+    {
+        ARMARX_WARNING_S << "Received an unknown type when trying to create a tree view widget "
+                            "modal for a skill argument type.";
+    }
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetModalCreator.h b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetModalCreator.h
new file mode 100644
index 0000000000000000000000000000000000000000..413ea9bcff79e8f650a00b66d12165d6832a64db
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetModalCreator.h
@@ -0,0 +1,55 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * ArmarX is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ArmarX is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @package    RobotAPI::gui-plugins::SkillManagerMonitorWidgetController
+ * @author     Raphael Grimm ( raphael dot grimm at kit dot edu )
+ * @date       2020
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+#pragma once
+
+#include <RobotAPI/libraries/aron/core/data/variant/All.h>
+#include <RobotAPI/libraries/aron/core/type/variant/All.h>
+#include <RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.h>
+
+#include "../modal/AronTreeWidgetModal.h"
+
+namespace armarx::skills::gui
+{
+    // Convert aron type to tree widget.
+    // (Widgets are only created for string types to enter longer texts.
+    // However, the visitor implementation allows modals for differnt types. Might be useful in the future..)
+    class AronTreeWidgetModalCreatorVisitor : public armarx::aron::type::ConstVariantVisitor
+    {
+    public:
+        std::string label = "";
+        AronTreeWidgetItem* item = nullptr;
+        QTreeWidget* parent = nullptr;
+        AronTreeWidgetModalControllerPtr createdModal = nullptr;
+
+        AronTreeWidgetModalCreatorVisitor() = delete;
+
+        AronTreeWidgetModalCreatorVisitor(const std::string& label,
+                                          AronTreeWidgetItem* item,
+                                          QTreeWidget* parent) :
+            label(label), item(item), parent(parent)
+        {
+        }
+
+        void visitAronVariant(const aron::type::StringPtr& i) final;
+        void visitUnknown(Input&) final;
+    };
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetSetter.cpp b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetSetter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1ae9dbc9d8aa99ae0e0eabfb489a29dfdf0a8d78
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetSetter.cpp
@@ -0,0 +1,403 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * ArmarX is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ArmarX is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * \package    RobotAPI::gui-plugins::SkillManagerMonitorWidgetController
+ * \author     Raphael Grimm ( raphael dot grimm at kit dot edu )
+ * \date       2020
+ * \copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#include "AronTreeWidgetSetter.h"
+
+#include <string>
+
+#include "../ListDictHelper.h"
+#include "../widgets/EditMatrixWidget.h"
+#include "../widgets/IntEnumWidget.h"
+#include "../widgets/QuaternionWidget.h"
+#include "AronTreeWidgetContextMenu.h"
+#include "AronTreeWidgetCreator.h"
+
+template <typename T>
+std::string
+usString(T number, size_t precision = 3)
+{
+    std::stringstream ss;
+    const char* locale = "C";
+    ss.imbue(std::locale(locale));
+
+    ss << std::fixed << std::setprecision(precision) << number;
+    return ss.str();
+}
+
+//visitors
+namespace armarx::skills::gui
+{
+    bool
+    AronTreeWidgetSetterVisitor::checkTreeWidgetItemForSimilarName(const std::string& name) const
+    {
+        QTreeWidgetItem* el = parentItem->child(index);
+
+        // do not check attribute name, if the element is part of a list or map
+        auto* castedThis = AronTreeWidgetItem::DynamicCast(el->parent());
+        if (castedThis)
+        {
+            auto descr = castedThis->aronType->getDescriptor();
+            if (descr == aron::type::Descriptor::LIST || descr == aron::type::Descriptor::DICT)
+            {
+                return true;
+            }
+        }
+        std::string n = el->text(0).toStdString();
+        if (name != n)
+        {
+            ARMARX_WARNING_S << "Could not set a tree widget value for the element with key '"
+                             << name << "' because it is different from the expected name '" << n
+                             << "'.";
+            return false;
+        }
+        return true;
+    }
+
+    void
+    AronTreeWidgetSetterVisitor::adjustNumberOfChildren(AronTreeWidgetItem* parent,
+                                                        size_t numChildren)
+    {
+        if (((size_t)parent->childCount()) < numChildren)
+        {
+            // The type to create must be the only child of the current aron type
+            ARMARX_CHECK_EQUAL(parent->aronType->childrenSize(), 1);
+            size_t childrenToAdd = numChildren - parent->childCount();
+            for (size_t j = 0; j < childrenToAdd; ++j)
+            {
+                AronTreeWidgetCreatorVisitor childCreator(parent);
+                aron::type::visit(childCreator, parent->aronType->getChildren()[0]);
+                ARMARX_CHECK_NOT_NULL(childCreator.createdQWidgetItem);
+            }
+        }
+        else if ((size_t)parent->childCount() > numChildren)
+        {
+            size_t numChilds = (size_t)parent->childCount() - numChildren;
+            // pop the last child
+            for (size_t j = 0; j < numChilds; ++j)
+            {
+                parent->removeChild(parent->child(parent->childCount() - 1));
+            }
+        }
+    }
+
+    void
+    AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::DictPtr& i)
+    {
+        // either it is the root or it has a name
+        if (i->getPath().size() == 0 ||
+            checkTreeWidgetItemForSimilarName(i->getPath().getLastElement()))
+        {
+            AronTreeWidgetItem* el = AronTreeWidgetItem::DynamicCast(parentItem->child(index));
+            auto* aronTreeWidget = AronTreeWidgetItem::DynamicCastAndCheck(el);
+            // allocate enough child items
+            adjustNumberOfChildren(aronTreeWidget, i->childrenSize());
+
+            // write child values
+            unsigned int x = 0;
+            for (const auto& [key, value] : i->getElements())
+            {
+                el->child(x)->setText(0, {key.c_str()});
+
+                AronTreeWidgetSetterVisitor v(el, x++);
+                aron::data::visit(v, value);
+            }
+
+            if (el->aronType && el->aronType->getMaybe() != armarx::aron::type::Maybe::NONE)
+            {
+                el->setCheckState(1, Qt::CheckState::Checked);
+            }
+        }
+    }
+
+    void
+    AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::ListPtr& i)
+    {
+        if (checkTreeWidgetItemForSimilarName(i->getPath().getLastElement()))
+        {
+            AronTreeWidgetItem* el = AronTreeWidgetItem::DynamicCast(parentItem->child(index));
+            auto* aronTreeWidget = AronTreeWidgetItem::DynamicCastAndCheck(el);
+            adjustNumberOfChildren(aronTreeWidget, i->childrenSize());
+
+            unsigned int x = 0;
+            for (const auto& value : i->getElements())
+            {
+                AronTreeWidgetSetterVisitor v(el, x);
+                aron::data::visit(v, value);
+                auto* currChild = el->child(x);
+                std::string listNum = usString(x);
+                currChild->setText(0, listNum.c_str());
+
+                ++x;
+            }
+            // This displays the number of children also when the list is collapsed
+            QString numElemsText = misc::generateNumElementsText(i->getElements().size());
+            aronTreeWidget->setText(1, numElemsText);
+            // set italic
+            auto currFont = aronTreeWidget->font(1);
+            currFont.setItalic(true);
+            aronTreeWidget->setFont(1, currFont);
+
+            if (el->aronType && el->aronType->getMaybe() != armarx::aron::type::Maybe::NONE)
+            {
+                el->setCheckState(1, Qt::CheckState::Checked);
+            }
+        }
+    }
+
+    void
+    visitMatrix(EditMatrixWidget* matrixWidget,
+                const std::shared_ptr<armarx::aron::type::Matrix>& matrixType,
+                const aron::data::NDArrayPtr& arr)
+    {
+        auto elemType = matrixType->getElementType();
+        auto* rawData = arr->getData();
+        // string can convert any item
+        auto toString = [elemType, rawData](size_t elementNr) -> std::string
+        {
+            switch (elemType)
+            {
+                case aron::type::matrix::ElementType::FLOAT32:
+                {
+                    static_assert(sizeof(float) == 4);
+                    float* interpreted = reinterpret_cast<float*>(rawData);
+                    float laundered = std::launder(interpreted)[elementNr];
+                    return usString<float>(laundered);
+                }
+                case aron::type::matrix::ElementType::FLOAT64:
+                {
+                    static_assert(sizeof(double) == 8);
+                    double* interpreted = reinterpret_cast<double*>(rawData);
+                    float laundered = std::launder(interpreted)[elementNr];
+                    return usString<double>(laundered);
+                }
+                case aron::type::matrix::ElementType::INT16:
+                {
+                    int16_t* interpreted = reinterpret_cast<int16_t*>(rawData);
+                    int16_t laudered = std::launder(interpreted)[elementNr];
+                    return usString<int16_t>(laudered);
+                }
+                case aron::type::matrix::ElementType::INT32:
+                {
+                    int32_t* interpreted = reinterpret_cast<int32_t*>(rawData);
+                    int32_t laudered = std::launder(interpreted)[elementNr];
+                    return usString<int32_t>(laudered);
+                }
+                case aron::type::matrix::ElementType::INT64:
+                {
+                    int64_t* interpreted = reinterpret_cast<int64_t*>(rawData);
+                    int64_t laudered = std::launder(interpreted)[elementNr];
+                    return usString<int64_t>(laudered);
+                }
+            }
+            return "Error!";
+        };
+
+
+        for (size_t row = 0; (int)row < matrixType->getRows(); ++row)
+        {
+            for (size_t col = 0; (int)col < matrixType->getCols(); ++col)
+            {
+                matrixWidget->setText(row, col, toString(col * matrixType->getRows() + row));
+            }
+        }
+    }
+
+    void
+    visitQuaternion(QuaternionWidget* quatWidget,
+                    std::shared_ptr<armarx::aron::type::Quaternion>& quatType,
+                    const aron::data::NDArrayPtr& arr)
+    {
+        auto elemType = quatType->getElementType();
+        auto rawData = arr->getData();
+        auto shape = arr->getShape();
+        // string can convert any item
+        auto toString = [elemType, rawData](size_t elementNr) -> std::string
+        {
+            switch (elemType)
+            {
+                case aron::type::quaternion::ElementType::FLOAT32:
+                {
+                    static_assert(sizeof(float) == 4);
+                    float* interpreted = reinterpret_cast<float*>(rawData);
+                    float laundered = std::launder(interpreted)[elementNr];
+                    return usString<float>(laundered);
+                }
+                case aron::type::quaternion::ElementType::FLOAT64:
+                {
+                    static_assert(sizeof(double) == 8);
+                    double* interpreted = reinterpret_cast<double*>(rawData);
+
+                    float laundered = std::launder(interpreted)[elementNr];
+                    return usString<double>(laundered);
+                }
+            }
+            return "Error!";
+        };
+        for (size_t i = 0; i < 4; ++i)
+        {
+            quatWidget->setText((QuaternionWidget::QuaternionComponents)i, toString(i));
+        }
+    }
+
+    void
+    AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::NDArrayPtr& arr)
+    {
+        // Matrices are handled as NDArray. Raw ndarrays cannot be created currently
+        auto* el = AronTreeWidgetItem::DynamicCast(parentItem->child(index));
+        ARMARX_CHECK(el);
+
+        auto matrixCast = aron::type::Matrix::DynamicCast(el->aronType);
+        auto quaternionCast = aron::type::Quaternion::DynamicCast(el->aronType);
+
+        auto* rootWidget = el->treeWidget();
+        ARMARX_CHECK(rootWidget);
+        auto* matrixWidget = EditMatrixWidget::DynamicCast(rootWidget->itemWidget(el, 1));
+        auto* quaternionWidget = QuaternionWidget::DynamicCast(rootWidget->itemWidget(el, 1));
+
+        if (matrixCast && matrixWidget)
+        {
+            visitMatrix(matrixWidget, matrixCast, arr);
+        }
+        else if (quaternionCast && quaternionWidget)
+        {
+            visitQuaternion(quaternionWidget, quaternionCast, arr);
+        }
+        else
+        {
+            ARMARX_ERROR
+                << "we do not support raw NDArrays. Ask Fabian Peller for more information.";
+        }
+
+        if (el->aronType && el->aronType->getMaybe() != armarx::aron::type::Maybe::NONE)
+        {
+            el->setCheckState(1, Qt::CheckState::Checked);
+        }
+    }
+
+    void
+    AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::IntPtr& i)
+    {
+        if (checkTreeWidgetItemForSimilarName(i->getPath().getLastElement()))
+        {
+            AronTreeWidgetItem* el = AronTreeWidgetItem::DynamicCast(parentItem->child(index));
+            auto* enumWidget = IntEnumWidget::DynamicCast(el->treeWidget()->itemWidget(el, 1));
+            auto newText = QString::fromStdString(usString<int>(i->getValue()));
+            if (enumWidget)
+            {
+                // Its an IntEnum! -> Ask the custom widget
+                enumWidget->setText(newText);
+            }
+            else
+            {
+                // Its just an int. -> do the QTreeWidgetItem call
+                el->setText(1, newText);
+            }
+
+            if (el->aronType && el->aronType->getMaybe() != armarx::aron::type::Maybe::NONE)
+            {
+                el->setCheckState(1, Qt::CheckState::Checked);
+            }
+        }
+    }
+
+    void
+    AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::LongPtr& i)
+    {
+        if (checkTreeWidgetItemForSimilarName(i->getPath().getLastElement()))
+        {
+            AronTreeWidgetItem* el = AronTreeWidgetItem::DynamicCast(parentItem->child(index));
+            el->setText(1, QString::fromStdString(usString<long>(i->getValue())));
+
+            if (el->aronType && el->aronType->getMaybe() != armarx::aron::type::Maybe::NONE)
+            {
+                el->setCheckState(1, Qt::CheckState::Checked);
+            }
+        }
+    }
+
+    void
+    AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::FloatPtr& i)
+    {
+        if (checkTreeWidgetItemForSimilarName(i->getPath().getLastElement()))
+        {
+            AronTreeWidgetItem* el = AronTreeWidgetItem::DynamicCast(parentItem->child(index));
+            el->setText(1, QString::fromStdString(usString<float>(i->getValue())));
+
+            if (el->aronType && el->aronType->getMaybe() != armarx::aron::type::Maybe::NONE)
+            {
+                el->setCheckState(1, Qt::CheckState::Checked);
+            }
+        }
+    }
+
+    void
+    AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::DoublePtr& i)
+    {
+        if (checkTreeWidgetItemForSimilarName(i->getPath().getLastElement()))
+        {
+            AronTreeWidgetItem* el = AronTreeWidgetItem::DynamicCast(parentItem->child(index));
+            el->setText(1, QString::fromStdString(usString<double>(i->getValue())));
+
+            if (el->aronType && el->aronType->getMaybe() != armarx::aron::type::Maybe::NONE)
+            {
+                el->setCheckState(1, Qt::CheckState::Checked);
+            }
+        }
+    }
+
+    void
+    AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::BoolPtr& i)
+    {
+        if (checkTreeWidgetItemForSimilarName(i->getPath().getLastElement()))
+        {
+            AronTreeWidgetItem* el = AronTreeWidgetItem::DynamicCast(parentItem->child(index));
+            el->setText(1, QString::fromStdString(usString<bool>(i->getValue())));
+
+            if (el->aronType && el->aronType->getMaybe() != armarx::aron::type::Maybe::NONE)
+            {
+                el->setCheckState(1, Qt::CheckState::Checked);
+            }
+        }
+    }
+
+    void
+    AronTreeWidgetSetterVisitor::visitAronVariant(const aron::data::StringPtr& i)
+    {
+        if (checkTreeWidgetItemForSimilarName(i->getPath().getLastElement()))
+        {
+            AronTreeWidgetItem* el = AronTreeWidgetItem::DynamicCast(parentItem->child(index));
+            el->setText(1, QString::fromStdString(i->getValue()));
+
+            if (el->aronType && el->aronType->getMaybe() != armarx::aron::type::Maybe::NONE)
+            {
+                el->setCheckState(1, Qt::CheckState::Checked);
+            }
+        }
+    }
+
+    void
+    AronTreeWidgetSetterVisitor::visitUnknown(Input&)
+    {
+        ARMARX_WARNING_S << "Received an unknown type when trying to set a skill argument type "
+                            "from an aron data object.";
+    }
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetSetter.h b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetSetter.h
new file mode 100644
index 0000000000000000000000000000000000000000..010b1e2e20a3e8850707fe55a97bc1d859f53236
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/visitors/AronTreeWidgetSetter.h
@@ -0,0 +1,65 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * ArmarX is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ArmarX is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @package    RobotAPI::gui-plugins::SkillManagerMonitorWidgetController
+ * @author     Raphael Grimm ( raphael dot grimm at kit dot edu )
+ * @date       2020
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+#pragma once
+
+#include <stack>
+
+#include <RobotAPI/libraries/aron/core/data/variant/All.h>
+#include <RobotAPI/libraries/aron/core/data/visitor/variant/VariantVisitor.h>
+#include <RobotAPI/libraries/aron/core/type/variant/All.h>
+
+#include "../AronTreeWidgetItem.h"
+
+namespace armarx::skills::gui
+{
+    // Conversion from aron data to Tree View data
+    // This should be used to programatically change data to be displayed in the GUI.
+    // This code will not be called, if changes are made on the GUI side.
+    class AronTreeWidgetSetterVisitor : public armarx::aron::data::ConstVariantVisitor
+    {
+    public:
+        QTreeWidgetItem* parentItem;
+        int index;
+        AronTreeWidgetItem* qWidgetItem;
+
+        AronTreeWidgetSetterVisitor() = delete;
+
+        AronTreeWidgetSetterVisitor(QTreeWidgetItem* i, int x) : parentItem(i), index(x)
+        {
+        }
+
+        virtual void visitAronVariant(const aron::data::DictPtr&) final;
+        virtual void visitAronVariant(const aron::data::ListPtr&) final;
+        virtual void visitAronVariant(const aron::data::NDArrayPtr&) final;
+        virtual void visitAronVariant(const aron::data::IntPtr&) final;
+        virtual void visitAronVariant(const aron::data::LongPtr&) final;
+        virtual void visitAronVariant(const aron::data::FloatPtr&) final;
+        virtual void visitAronVariant(const aron::data::DoublePtr&) final;
+        virtual void visitAronVariant(const aron::data::BoolPtr&) final;
+        virtual void visitAronVariant(const aron::data::StringPtr&) final;
+        void visitUnknown(Input&) final;
+
+    private:
+        bool checkTreeWidgetItemForSimilarName(const std::string& name) const;
+        void adjustNumberOfChildren(AronTreeWidgetItem* parent, size_t numChildren);
+    };
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/CustomWidget.cpp b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/CustomWidget.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e8ebdb950ce55318b868c124124880e1228ef901
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/CustomWidget.cpp
@@ -0,0 +1,42 @@
+#include "CustomWidget.h"
+
+#include "ArmarXCore/core/exceptions/local/ExpressionException.h"
+
+namespace armarx::skills::gui
+{
+    CustomWidget::CustomWidget(QTreeWidgetItem* overlayingItem) : overlayingItem(overlayingItem)
+    {
+        // connect to general QTreeWidgetItem callback.
+        // This also lets the conversion start for other objects. (Not just this widget)
+        ARMARX_CHECK(connect(this,
+                             SIGNAL(elemChanged(QTreeWidgetItem*, int)),
+                             overlayingItem->treeWidget(),
+                             SIGNAL(itemChanged(QTreeWidgetItem*, int))));
+    }
+
+    CustomWidget*
+    CustomWidget::DynamicCast(QWidget* elem)
+    {
+        return dynamic_cast<CustomWidget*>(elem);
+    }
+
+    CustomWidget*
+    CustomWidget::DynamicCastAndCheck(QWidget* elem)
+    {
+        if (!elem)
+        {
+            return nullptr;
+        }
+        auto* casted = DynamicCast(elem);
+        ARMARX_CHECK_NOT_NULL(casted);
+        return casted;
+    }
+
+    void
+    CustomWidget::setSupressSignals(bool doSupress)
+    {
+        QObject::blockSignals(doSupress);
+    }
+
+
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/CustomWidget.h b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/CustomWidget.h
new file mode 100644
index 0000000000000000000000000000000000000000..16b397116351f31d510a9871b28fb1066d2f4b01
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/CustomWidget.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <QTreeWidgetItem>
+#include <QWidget>
+
+namespace armarx::skills::gui
+{
+
+    class CustomWidget : public QWidget
+    {
+        Q_OBJECT
+
+    public:
+        CustomWidget(QTreeWidgetItem* overlayingItem);
+        static CustomWidget* DynamicCast(QWidget*);
+        static CustomWidget* DynamicCastAndCheck(QWidget*);
+
+        virtual void setSupressSignals(bool doSupress);
+
+    protected:
+        QTreeWidgetItem* overlayingItem;
+
+    signals:
+        void elemChanged(QTreeWidgetItem* elem, int col);
+    };
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/EditMatrixWidget.cpp b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/EditMatrixWidget.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c40c0821533ad3ce24d23dcc76611f4a5e1cb3f3
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/EditMatrixWidget.cpp
@@ -0,0 +1,252 @@
+#include "EditMatrixWidget.h"
+
+#include <QGridLayout>
+#include <QLabel>
+
+#include "ArmarXCore/core/exceptions/local/ExpressionException.h"
+#include "ArmarXCore/core/logging/Logging.h"
+
+#include "../ColorPalettes.h"
+#include "../visitors/AronTreeWidgetCreator.h"
+#include "NDArrayHelper.h"
+
+namespace armarx::skills::gui
+{
+    EditMatrixWidget::EditMatrixWidget(long numRows,
+                                       long numCols,
+                                       aron::type::matrix::ElementType elemType,
+                                       QTreeWidgetItem* currentItem) :
+        CustomWidget(currentItem)
+    {
+        realRows = numRows;
+        realCols = numCols;
+        this->elemType = elemType;
+        // init surrounding layout
+        outerVerticalLayout = new QVBoxLayout();
+        innerHorizontalLayout = new QHBoxLayout();
+        outerVerticalLayout->addItem(innerHorizontalLayout);
+
+
+        QGridLayout* innerGrid = new QGridLayout();
+        const long createRows = std::min(numRows, MAX_ROWS_DISPLAY);
+        const long createCols = std::min(numCols, MAX_COLS_DISPLAY);
+
+        for (long i = 0; i < createRows * createCols; ++i)
+        {
+            auto* edit = new QLineEdit();
+            dispElements.push_back(edit);
+            int currRow = i / createCols;
+            int currCol = i % createCols;
+
+            innerGrid->addWidget(edit, currRow, currCol);
+            std::stringstream ss;
+            ss << "(" << currRow << ", " << currCol << ")";
+            std::string text = ss.str();
+
+            edit->setText(text.c_str());
+        }
+        innerHorizontalLayout->addItem(innerGrid);
+
+        // check, if we need to signal to the user, that not all elements are displayed.
+        if (numRows > MAX_ROWS_DISPLAY)
+        {
+            QLabel* fullLabel = new QLabel("...");
+            outerVerticalLayout->addWidget(fullLabel);
+        }
+        if (numCols > MAX_COLS_DISPLAY)
+        {
+            QLabel* fullLabel = new QLabel("...");
+            innerHorizontalLayout->addWidget(fullLabel);
+        }
+        setLayout(outerVerticalLayout);
+
+        // add hidden elements in vector
+        {
+            const auto hiddenCols = numCols - createCols;
+            // the 0th element holds all columns that are
+            // to the right of the displayed cols AND besides the displayed rows!
+            hiddenElems.push_back(std::vector<std::string>(hiddenCols * createRows, ""));
+
+            // add all rows that are hidden
+            for (long i = 0; i < numRows - createRows; ++i)
+            {
+                // add full cols; everything is hidden here
+                hiddenElems.push_back(std::vector<std::string>(numCols, ""));
+            }
+        }
+
+        for (size_t i = 0; i < dispElements.size(); ++i)
+        {
+            ARMARX_CHECK(connect(
+                dispElements[i], SIGNAL(editingFinished()), this, SLOT(matrixElementChanged())));
+        }
+    }
+
+    EditMatrixWidget*
+    EditMatrixWidget::DynamicCast(QWidget* elem)
+    {
+        return dynamic_cast<EditMatrixWidget*>(elem);
+    }
+
+    EditMatrixWidget*
+    EditMatrixWidget::DynamicCastAndCheck(QWidget* elem)
+    {
+        if (!elem)
+        {
+            return nullptr;
+        }
+        auto* casted = DynamicCast(elem);
+        ARMARX_CHECK_NOT_NULL(casted);
+        return casted;
+    }
+
+    void
+    EditMatrixWidget::setText(long row, long col, const std::string& str)
+    {
+        ARMARX_CHECK(row < realRows);
+        ARMARX_CHECK(col < realCols);
+        auto dispCols = getDisplayedCols();
+        auto dispRows = getDisplayedRows();
+        if (row < dispRows && col < dispCols)
+        {
+            dispElements[row * dispCols + col]->setText(str.c_str());
+            dispElements[row * dispCols + col]->setCursorPosition(0);
+        }
+        else if (row < dispRows)
+        {
+            long idx = row * (realCols - dispCols) + col - dispCols;
+            hiddenElems.at(0).at(idx) = str;
+        }
+        else
+        {
+            hiddenElems.at(row - dispRows + 1).at(col) = str;
+        }
+    }
+
+    std::string
+    EditMatrixWidget::getText(long row, long col)
+    {
+        ARMARX_CHECK(row < realRows);
+        ARMARX_CHECK(col < realCols);
+        const auto dispRows = getDisplayedRows();
+        const auto dispCols = getDisplayedCols();
+        if (row < dispRows && col < dispCols)
+        {
+            auto txt = dispElements.at(row * dispCols + col)->text();
+            return txt.toStdString();
+        }
+        else if (row < getDisplayedRows())
+        {
+            // the stuff besides the displayed rows
+            long idx = row * (realCols - dispCols) + col - dispCols;
+            return hiddenElems.at(0).at(idx);
+        }
+        else
+        {
+            // stuff beneath displayed rows
+            return hiddenElems.at(row - dispRows + 1).at(col);
+        }
+    }
+
+    void
+    EditMatrixWidget::highlightUnparsableEntries()
+    {
+        auto dispRows = getDisplayedRows();
+        auto dispCols = getDisplayedCols();
+        for (long row = 0; row < dispRows; ++row)
+        {
+            for (long col = 0; col < dispCols; ++col)
+            {
+                auto parsed = parseElement(row, col);
+                if (parsed.empty())
+                {
+                    dispElements.at(row * dispCols + col)
+                        ->setPalette(gui_color_palette::getErrorPalette());
+                }
+                else
+                {
+                    dispElements.at(row * dispCols + col)
+                        ->setPalette(gui_color_palette::getNormalPalette());
+                }
+            }
+        }
+    }
+
+    bool
+    EditMatrixWidget::hasParseErrors()
+    {
+        // also parse the hidden stuff!
+        for (long row = 0; row < realRows; ++row)
+        {
+            for (long col = 0; col < realCols; ++col)
+            {
+                auto parsed = parseElement(row, col);
+                if (parsed.empty())
+                {
+                    if (row >= getDisplayedRows() || col >= getDisplayedCols())
+                    {
+                        ARMARX_ERROR
+                            << "Programming error! Could not parse content in EditMatrixWidget "
+                               "that was set programatically from inside the SkillManagerPlugin. "
+                               "The error occured in row "
+                            << row << " and col " << col << ".";
+                    }
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    std::vector<unsigned char>
+    EditMatrixWidget::parseElement(long row, long col)
+    {
+        std::string str = getText(row, col);
+        try
+        {
+            switch (elemType)
+            {
+                case armarx::aron::type::matrix::INT16:
+                    return NDArrayHelper::toByteVector<int16_t>(str);
+
+                case armarx::aron::type::matrix::INT32:
+                    return NDArrayHelper::toByteVector<int32_t>(str);
+
+                case armarx::aron::type::matrix::INT64:
+                    return NDArrayHelper::toByteVector<int64_t>(str);
+
+                case armarx::aron::type::matrix::FLOAT32:
+                    return NDArrayHelper::toByteVector<float>(str);
+
+                case armarx::aron::type::matrix::FLOAT64:
+                    return NDArrayHelper::toByteVector<double>(str);
+            }
+        }
+        catch (const simox::error::SimoxError& err)
+        {
+            return {};
+        }
+        return {};
+    }
+
+    long
+    EditMatrixWidget::getDisplayedRows() const
+    {
+        return std::min(realRows, MAX_ROWS_DISPLAY);
+    }
+
+    long
+    EditMatrixWidget::getDisplayedCols() const
+    {
+        return std::min(realCols, MAX_COLS_DISPLAY);
+    }
+
+    void
+    EditMatrixWidget::matrixElementChanged()
+    {
+        blockSignals(true);
+        highlightUnparsableEntries();
+        blockSignals(false);
+        emit elemChanged(overlayingItem, 1);
+    }
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/EditMatrixWidget.h b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/EditMatrixWidget.h
new file mode 100644
index 0000000000000000000000000000000000000000..9d0c8cbfbd9463ab37d8498410381aebd54c6956
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/EditMatrixWidget.h
@@ -0,0 +1,81 @@
+#pragma once
+#include <vector>
+
+#include <QHBoxLayout>
+#include <QLineEdit>
+#include <QObject>
+#include <QTreeWidgetItem>
+#include <QVBoxLayout>
+
+#include "RobotAPI/libraries/aron/core/type/variant/ndarray/Matrix.h"
+
+#include "CustomWidget.h"
+
+namespace armarx::skills::gui
+{
+    // Custom Widget used to display Matrices
+    // MAX_ROWS_DISPLAY and MAX_COLS_DISPLAY are the maximal number of elements displayable
+    // everything else will not be displayed. However, there can still be made changes to this data with setText()
+    class EditMatrixWidget : public CustomWidget
+    {
+        Q_OBJECT
+    public:
+        EditMatrixWidget() = delete;
+        EditMatrixWidget(long numRows,
+                         long numCols,
+                         aron::type::matrix::ElementType elemType,
+                         QTreeWidgetItem* currentWidget);
+
+        static EditMatrixWidget* DynamicCast(QWidget*);
+        static EditMatrixWidget* DynamicCastAndCheck(QWidget*);
+
+        // Sets the text on all visible rows and cols.
+        void setText(long row, long col, const std::string& str);
+        std::string getText(long row, long col);
+        void highlightUnparsableEntries();
+        bool hasParseErrors();
+        // returns an empty vector if parsing failed. Else, contains the individual bytes.
+        std::vector<unsigned char> parseElement(long row, long col);
+
+
+    private:
+        // Dimensions of the underlying Type to represent
+        long realRows = 1;
+        long realCols = 1;
+
+        // maximum of rows / cols to display
+        static constexpr long MAX_ROWS_DISPLAY = 5;
+        static constexpr long MAX_COLS_DISPLAY = 5;
+        long getDisplayedRows() const;
+        long getDisplayedCols() const;
+
+        // Want to add dots to show the user that not all is displayed. This needs some wrapping layouts
+        QVBoxLayout* outerVerticalLayout;
+        QHBoxLayout* innerHorizontalLayout;
+
+        // Using row major layout
+        std::vector<QLineEdit*> dispElements;
+        // rows<cols<text>>: stores get and set messages for hidden elements (if there is not enough space for all elements)
+        std::vector<std::vector<std::string>> hiddenElems;
+
+        template <typename T>
+        static std::vector<unsigned char> toByteVector(const std::string& str);
+
+        // TODO: It would be nice to have this code somewhere else, this way, at least the GUI-responses
+        // are restricted to this Widget (signal & slot stuff)
+        aron::type::matrix::ElementType elemType;
+
+    private slots:
+        void matrixElementChanged();
+    };
+
+    template <typename T>
+    std::vector<unsigned char>
+    EditMatrixWidget::toByteVector(const std::string& str)
+    {
+        auto val = simox::alg::to_<T>(str);
+        std::vector<unsigned char> res(sizeof(val), 0);
+        *reinterpret_cast<T*>(res.data()) = val;
+        return res;
+    }
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/IntEnumWidget.cpp b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/IntEnumWidget.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bbbee283d5aee3f75a0ce77b07a3e5dbca18eab7
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/IntEnumWidget.cpp
@@ -0,0 +1,139 @@
+#include "IntEnumWidget.h"
+
+#include <QHBoxLayout>
+
+#include "RobotAPI/libraries/aron/core/type/variant/All.h"
+
+#include "../ColorPalettes.h"
+#include "../visitors/AronTreeWidgetConverter.h"
+
+namespace armarx::skills::gui
+{
+    IntEnumWidget::IntEnumWidget(const aron::type::IntEnumPtr& enumPtr,
+                                 QTreeWidgetItem* currentItem) :
+        CustomWidget(currentItem), element_type(enumPtr)
+    {
+        auto names = enumPtr->getAcceptedValueNames();
+        auto outerLayout = new QHBoxLayout();
+        outerLayout->setContentsMargins(0, 0, 0, 0);
+        innerWidget = new QComboBox();
+        outerLayout->addWidget(innerWidget);
+
+        for (const auto& n : names)
+        {
+            innerWidget->addItem(n.c_str());
+        }
+        innerWidget->setInsertPolicy(QComboBox::NoInsert);
+        innerWidget->setEditable(true);
+        innerWidget->setCurrentIndex(0);
+
+        setLayout(outerLayout);
+        ARMARX_CHECK(connect(innerWidget,
+                             SIGNAL(currentTextChanged(const QString&)),
+                             this,
+                             SLOT(textChanged(const QString&))));
+    }
+
+    IntEnumWidget*
+    IntEnumWidget::DynamicCast(QWidget* widget)
+    {
+        return dynamic_cast<IntEnumWidget*>(widget);
+    }
+
+    IntEnumWidget*
+    IntEnumWidget::DynamicCastAndCheck(QWidget* elem)
+    {
+        if (!elem)
+        {
+            return nullptr;
+        }
+        auto* casted = DynamicCast(elem);
+        ARMARX_CHECK_NOT_NULL(casted);
+        return casted;
+    }
+
+    bool
+    IntEnumWidget::hasParseErrors()
+    {
+        return parseToAron().first;
+    }
+
+    void
+    IntEnumWidget::setText(const QString& text)
+    {
+        innerWidget->setEditText(text);
+        highlightUnparsableEntries();
+    }
+
+    QString
+    IntEnumWidget::getText()
+    {
+        return innerWidget->currentText();
+    }
+
+    std::pair<bool, aron::data::IntPtr>
+    IntEnumWidget::parseToAron()
+    {
+        auto crAron = std::make_shared<aron::data::Int>(element_type->getPath());
+
+        // first look for strings in value map
+        auto valueMap = element_type->getAcceptedValueMap();
+        std::string toParse = getText().toStdString();
+
+        auto searchRes = valueMap.find(toParse);
+        if (searchRes != valueMap.end())
+        {
+            crAron->setValue(searchRes->second);
+            return {true, crAron};
+        }
+        // maybe its the number directly
+        auto accVals = element_type->getAcceptedValues();
+        int res;
+        try
+        {
+            res = simox::alg::to_<int>(toParse);
+        }
+        catch (const simox::error::SimoxError& err)
+        {
+            ARMARX_VERBOSE << "Failed to parse IntEnum: Could not convert  \'" << toParse
+                           << "\' to an int. It also was not one of the accepted strings.";
+            return {false, nullptr};
+        }
+        if (std::find(accVals.begin(), accVals.end(), res) != accVals.end())
+        {
+
+            crAron->setValue(res);
+        }
+        else
+        {
+            ARMARX_VERBOSE << "Parsed int " << res
+                           << "but this int is not part of the accepted values.";
+            return {false, nullptr};
+        }
+        return {true, crAron};
+    }
+
+    void
+    IntEnumWidget::highlightUnparsableEntries()
+    {
+        auto parsed = parseToAron().first;
+        if (parsed)
+        {
+            innerWidget->setPalette(gui_color_palette::getNormalPalette());
+        }
+        else
+        {
+            innerWidget->setPalette(gui_color_palette::getErrorPalette());
+        }
+    }
+
+    void
+    IntEnumWidget::textChanged(const QString&)
+    {
+        setSupressSignals(true);
+        highlightUnparsableEntries();
+        setSupressSignals(false);
+        // fire change signal
+        emit CustomWidget::elemChanged(overlayingItem, 1);
+    }
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/IntEnumWidget.h b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/IntEnumWidget.h
new file mode 100644
index 0000000000000000000000000000000000000000..ba70937ad28318fe512641ba7d9068978c07244a
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/IntEnumWidget.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#include <QComboBox>
+
+#include "RobotAPI/libraries/aron/core/data/variant/primitive/Int.h"
+#include "RobotAPI/libraries/aron/core/type/variant/forward_declarations.h"
+
+#include "../AronTreeWidgetItem.h"
+#include "CustomWidget.h"
+
+namespace armarx::skills::gui
+{
+    // Custom wrapper around the QComboBox widget to represent IntEnums
+    // This class handles parsing once the user edited the field and is also responsible
+    // to parse the according aron data from text
+    class IntEnumWidget : public CustomWidget
+    {
+        Q_OBJECT
+    public:
+        IntEnumWidget(const aron::type::IntEnumPtr&, QTreeWidgetItem* currentItem);
+        // needs to be called after the constructor, because qt needs the meta object to be fully constructed at this point
+        void postCtorCall();
+
+        static IntEnumWidget* DynamicCast(QWidget*);
+        static IntEnumWidget* DynamicCastAndCheck(QWidget*);
+
+        bool hasParseErrors();
+        void setText(const QString& text);
+        QString getText();
+        std::pair<bool, aron::data::IntPtr> parseToAron();
+
+    private:
+        const aron::type::IntEnumPtr element_type;
+        QComboBox* innerWidget;
+
+        bool noParseErrors = true;
+
+        void highlightUnparsableEntries();
+    private slots:
+        void textChanged(const QString&);
+    };
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/NDArrayHelper.cpp b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/NDArrayHelper.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a9599a2dbdfd456e1237542d34006f5d4c4c9bbf
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/NDArrayHelper.cpp
@@ -0,0 +1 @@
+#include "NDArrayHelper.h"
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/NDArrayHelper.h b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/NDArrayHelper.h
new file mode 100644
index 0000000000000000000000000000000000000000..bd74b4ef50ae33cab07e836157085cf23d3f517c
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/NDArrayHelper.h
@@ -0,0 +1,33 @@
+#pragma once
+#include <string>
+#include <vector>
+
+#include <SimoxUtility/algorithm/string.h>
+
+namespace armarx::skills::gui
+{
+    class NDArrayHelper
+    {
+    public:
+        // Uses the simox utility to parse floatingpoint and fixed precision types
+        // it then writes the result into a byte vector
+        // an empty byte vector encodes a parsing error.
+        template <typename T>
+        std::vector<unsigned char> static toByteVector(const std::string& str)
+        {
+            try
+            {
+                auto val = simox::alg::to_<T>(str);
+                std::vector<unsigned char> res(sizeof(val), 0);
+                T* reinterpPtr = reinterpret_cast<T*>(res.data());
+                T* laundered = std::launder(reinterpPtr);
+                *laundered = val;
+                return res;
+            }
+            catch (const simox::error::SimoxError& err)
+            {
+                return {};
+            }
+        }
+    };
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/QuaternionWidget.cpp b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/QuaternionWidget.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e8a48aa71942e5f86e837a8fc516e7d475615f66
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/QuaternionWidget.cpp
@@ -0,0 +1,161 @@
+#include "QuaternionWidget.h"
+
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QLineEdit>
+
+#include "../ColorPalettes.h"
+#include "NDArrayHelper.h"
+
+namespace armarx::skills::gui
+{
+
+    QuaternionWidget*
+    QuaternionWidget::DynamicCast(QWidget* elem)
+    {
+        return dynamic_cast<QuaternionWidget*>(elem);
+    }
+
+    QuaternionWidget*
+    QuaternionWidget::DynamicCastAndCheck(QWidget* elem)
+    {
+        if (!elem)
+        {
+            return nullptr;
+        }
+        auto* casted = DynamicCast(elem);
+        ARMARX_CHECK_NOT_NULL(casted);
+        return casted;
+    }
+
+    void
+    QuaternionWidget::setText(QuaternionComponents col, const std::string& str)
+    {
+        size_t idx = (size_t)col;
+        xyzw_components.at(idx)->setText(str.c_str());
+        highlightUnparsableEntries();
+    }
+
+    bool
+    QuaternionWidget::hasParseErrors()
+    {
+        return parseErrors;
+    }
+
+    QuaternionWidget::QuaternionWidget(aron::type::quaternion::ElementType elType,
+                                       QTreeWidgetItem* currentItem) :
+        CustomWidget(currentItem), element_type(elType)
+    {
+        auto outerLayout = new QHBoxLayout();
+        auto labelCol1 = new QVBoxLayout();
+        auto labelCol2 = new QVBoxLayout();
+        auto xzEdit = new QVBoxLayout();
+        auto ywEdit = new QVBoxLayout();
+
+        outerLayout->addLayout(labelCol1);
+        outerLayout->addLayout(xzEdit);
+        outerLayout->addLayout(labelCol2);
+        outerLayout->addLayout(ywEdit);
+
+        xyzw_components.reserve(4);
+        for (size_t i = 0; i < 4; ++i)
+        {
+            xyzw_components.push_back(new QLineEdit());
+        }
+
+        // Tabbing order >> Viewing order. Thats why the indeces are a bit switched
+        labelCol1->addWidget(new QLabel("x"));
+        xzEdit->addWidget(xyzw_components.at(0));
+
+        labelCol2->addWidget(new QLabel("z"));
+        ywEdit->addWidget(xyzw_components.at(2));
+
+        labelCol1->addWidget(new QLabel("y"));
+        xzEdit->addWidget(xyzw_components.at(1));
+
+        labelCol2->addWidget(new QLabel("w"));
+        ywEdit->addWidget(xyzw_components.at(3));
+
+        for (const auto& el : xyzw_components)
+        {
+            ARMARX_CHECK(
+                connect(el, SIGNAL(editingFinished()), this, SLOT(quaternionElementChanged())));
+        }
+
+        setLayout(outerLayout);
+        highlightUnparsableEntries();
+    }
+
+    void
+    QuaternionWidget::highlightUnparsableEntries()
+    {
+        parseErrors = false;
+        for (size_t i = 0; i < 4; ++i)
+        {
+            bool ok = false;
+            switch (element_type)
+            {
+                case armarx::aron::type::quaternion::FLOAT32:
+                {
+                    float flt;
+                    std::tie(ok, flt) = parseQuatVals<float>((QuaternionComponents)i);
+                    break;
+                }
+                case armarx::aron::type::quaternion::FLOAT64:
+                {
+                    double dbl;
+                    std::tie(ok, dbl) = parseQuatVals<double>((QuaternionComponents)i);
+                    break;
+                }
+            }
+            if (ok)
+            {
+                xyzw_components.at(i)->setPalette(gui_color_palette::getNormalPalette());
+            }
+            else
+            {
+                xyzw_components.at(i)->setPalette(gui_color_palette::getErrorPalette());
+                parseErrors = true;
+            }
+        }
+    }
+
+    std::vector<unsigned char>
+    QuaternionWidget::parseAllToNDArray()
+    {
+        std::vector<unsigned char> res;
+        bool success = true;
+        if (element_type == aron::type::quaternion::FLOAT32)
+        {
+            res.reserve(16);
+            for (size_t i = 0; i < 4; ++i)
+            {
+                auto bytevec =
+                    NDArrayHelper::toByteVector<float>(xyzw_components.at(i)->text().toStdString());
+                success &= !bytevec.empty();
+                res.insert(res.end(), bytevec.begin(), bytevec.end());
+            }
+        }
+        else
+        {
+            res.reserve(32);
+            for (size_t i = 0; i < 4; ++i)
+            {
+                auto bytevec = NDArrayHelper::toByteVector<double>(
+                    xyzw_components.at(i)->text().toStdString());
+                success &= !bytevec.empty();
+                res.insert(res.end(), bytevec.begin(), bytevec.end());
+            }
+        }
+        return (success) ? res : std::vector<unsigned char>();
+    }
+
+    void
+    QuaternionWidget::quaternionElementChanged()
+    {
+        CustomWidget::setSupressSignals(true);
+        highlightUnparsableEntries();
+        CustomWidget::setSupressSignals(false);
+        emit CustomWidget::elemChanged(overlayingItem, 1);
+    }
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/QuaternionWidget.h b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/QuaternionWidget.h
new file mode 100644
index 0000000000000000000000000000000000000000..f743e3acf3a2eafdfd03f3eb35bddb48b49cfbb4
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/QuaternionWidget.h
@@ -0,0 +1,67 @@
+#pragma once
+#include <vector>
+
+#include <QLineEdit>
+#include <QObject>
+#include <QVBoxLayout>
+
+#include "RobotAPI/libraries/aron/core/type/variant/ndarray/Matrix.h"
+
+#include "CustomWidget.h"
+
+namespace armarx::skills::gui
+{
+    // Custom Widget which represents a Quaternion - This class does not normalize the inputs
+    // It can parse its data to NDArray and also handles user edit signals itself. (And also the highlighting if errors occur)
+    class QuaternionWidget : public CustomWidget
+    {
+        Q_OBJECT
+    public:
+        QuaternionWidget(aron::type::quaternion::ElementType type, QTreeWidgetItem* currentItem);
+
+        static QuaternionWidget* DynamicCast(QWidget*);
+        static QuaternionWidget* DynamicCastAndCheck(QWidget*);
+
+        enum struct QuaternionComponents
+        {
+            X = 0,
+            Y,
+            Z,
+            W
+        };
+        void setText(QuaternionComponents col, const std::string& str);
+        std::string getText(QuaternionComponents col);
+        bool hasParseErrors();
+        std::vector<unsigned char> parseAllToNDArray();
+
+    private:
+        std::vector<QLineEdit*> xyzw_components;
+        aron::type::quaternion::ElementType element_type;
+        bool parseErrors = false;
+
+        void highlightUnparsableEntries();
+        template <typename T>
+        std::pair<bool, T> parseQuatVals(QuaternionComponents comp);
+
+    private slots:
+        void quaternionElementChanged();
+    };
+
+    template <typename T>
+    std::pair<bool, T>
+    QuaternionWidget::parseQuatVals(QuaternionWidget::QuaternionComponents comp)
+    {
+        // size_t data_size = element_type == aron::type::quaternion::ElementType::FLOAT32 ? 4 : 8;
+        try
+        {
+            T val = simox::alg::to_<T>(xyzw_components.at((size_t)comp)->text().toStdString());
+            return {true, val};
+        }
+        catch (const simox::error::SimoxError& err)
+        {
+            return {false, NAN};
+        }
+    }
+
+
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/SkillDescriptionWidget.cpp b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/SkillDescriptionWidget.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b0132b59f6dedb147a3820d0a7d0dbcce89a4c1c
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/SkillDescriptionWidget.cpp
@@ -0,0 +1,69 @@
+#include "SkillDescriptionWidget.h"
+
+#include <sstream>
+
+#include <QGridLayout>
+#include <QLabel>
+#include <QTextEdit>
+
+#include <ArmarXGui/libraries/ArmarXGuiBase/widgets/cpp-markdown/markdown.h> // ToDo: Move cpp-markdown to own Axii module.
+
+namespace armarx::skills::gui
+{
+
+    static std::string
+    markdownToHtml(const std::string& markdownText, size_t spacesPerTab = 2)
+    {
+        ::markdown::Document document(spacesPerTab);
+        document.read(markdownText);
+
+        std::stringstream html;
+        document.write(html);
+        return html.str();
+    }
+
+    SkillDescriptionWidget::SkillDescriptionWidget(QWidget* parent) : QWidget{parent}
+    {
+        QGridLayout* layout = new QGridLayout;
+        setLayout(layout);
+
+        layout->setMargin(0);
+
+        int row = 0;
+        int col = 0;
+
+        layout->addWidget(new QLabel("Name:"), row, col++);
+        name = new QLabel;
+        layout->addWidget(name, row, col++);
+
+        // Add some padding.
+        layout->addWidget(new QLabel(), row, col++);
+
+        {
+            QLabel* label = new QLabel("Timeout:");
+            label->setAlignment(Qt::AlignmentFlag::AlignRight);
+            layout->addWidget(label, row, col++);
+        }
+        timeout = new QLabel;
+        timeout->setAlignment(Qt::AlignmentFlag::AlignRight);
+        layout->addWidget(timeout, row, col++);
+
+        ++row;
+        int numCols = col;
+        col = 0;
+
+        description = new QTextEdit;
+        description->setReadOnly(true);
+        layout->addWidget(description, row, col, 1, numCols);
+        ++row;
+    }
+
+    void
+    SkillDescriptionWidget::setSkillDescription(const skills::SkillDescription& desc)
+    {
+        name->setText(QString::fromStdString(desc.skillId.skillName));
+        description->setHtml(QString::fromStdString(markdownToHtml(desc.description)));
+        timeout->setText(QString::fromStdString(desc.timeout.toDurationString()));
+    }
+
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/SkillDescriptionWidget.h b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/SkillDescriptionWidget.h
new file mode 100644
index 0000000000000000000000000000000000000000..5344c50d4188c7e700b7b4b9a8518c3d71794dec
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/SkillDescriptionWidget.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <QWidget>
+
+#include <RobotAPI/libraries/skills/core/SkillDescription.h>
+
+class QLabel;
+class QTextEdit;
+
+namespace armarx::skills::gui
+{
+
+    class SkillDescriptionWidget : public QWidget
+    {
+    public:
+        SkillDescriptionWidget(QWidget* parent = nullptr);
+
+        void setSkillDescription(const skills::SkillDescription& desc);
+
+    private:
+        QLabel* name = nullptr;
+        QTextEdit* description = nullptr;
+        QLabel* timeout = nullptr;
+    };
+
+
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/executions/SkillExecutionTreeWidget.cpp b/source/RobotAPI/libraries/skills_gui/executions/SkillExecutionTreeWidget.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..02c8c1df0871cb69f09ceb05fe0adb41e6d0a2e7
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/executions/SkillExecutionTreeWidget.cpp
@@ -0,0 +1,183 @@
+#include "SkillExecutionTreeWidget.h"
+
+#include <mutex>
+
+#include <QMenu>
+#include <QTreeWidgetItem>
+
+#include "SkillExecutionTreeWidgetItem.h"
+
+namespace armarx::skills::gui
+{
+
+    void
+    SkillExecutionTreeWidget::runContextMenu(const QPoint& pos)
+    {
+        // sanity check
+        ARMARX_CHECK(selectionValid());
+
+        QMenu* menu = new QMenu();
+
+        // Stop skill
+        QAction* stopSkillAction = new QAction("Stop execution", this);
+        const auto& executions = memory->fetchExecutions();
+        if (executions.count(selectedExecution.skillExecutionId) == 0)
+            return;
+        skills::SkillStatus currentStatus =
+            memory->fetchExecutions().at(selectedExecution.skillExecutionId).status;
+        stopSkillAction->setDisabled(currentStatus == skills::SkillStatus::Aborted ||
+                                     currentStatus == skills::SkillStatus::Failed ||
+                                     currentStatus == skills::SkillStatus::Succeeded);
+
+        QAction* rerunSkillAction = new QAction("Re-run with similar params", this);
+        menu->addAction(stopSkillAction);
+        menu->addAction(rerunSkillAction);
+        connect(stopSkillAction,
+                &QAction::triggered,
+                this,
+                &SkillExecutionTreeWidget::stopSelectedExecution);
+        connect(rerunSkillAction,
+                &QAction::triggered,
+                this,
+                &SkillExecutionTreeWidget::rerunSkillWithSimilarParams);
+
+        // open menu
+        menu->popup(this->viewport()->mapToGlobal(pos));
+    }
+
+    void
+    SkillExecutionTreeWidget::stopSelectedExecution()
+    {
+        if (!selectionValid())
+            return;
+        memory->stopExecution(this->selectedExecution.skillExecutionId);
+    }
+
+    void
+    SkillExecutionTreeWidget::rerunSkillWithSimilarParams()
+    {
+        if (!selectionValid())
+            return;
+        // we don't want to hold state in the gui, so we need to get the parameters from memory:
+        skills::SkillExecutionID currentExecutionId = this->selectedExecution.skillExecutionId;
+        auto executions = memory->fetchExecutions();
+        if (executions.empty())
+            return;
+
+        if (executions.count(currentExecutionId) == 0)
+        {
+            // we didn't find an entry for the execution id
+            ARMARX_IMPORTANT << "The selected execution was not found in memory. The GUI is unable "
+                                "to determine the parametrization for this execution.";
+            return;
+        }
+        auto params = executions[currentExecutionId].parameters;
+
+        ARMARX_INFO << "Re-executing the skill " << currentExecutionId.skillId
+                    << " with previous parameters.";
+
+        // give all information to manager
+        this->memory->startExecutionWithParams(currentExecutionId.skillId, params);
+    }
+
+    void
+    SkillExecutionTreeWidget::disconnectGui()
+    {
+        this->selectedExecution = SelectedExecution();
+        this->clear();
+    }
+
+    void
+    SkillExecutionTreeWidget::setupUi()
+    {
+        this->setColumnCount(6);
+
+        this->setContextMenuPolicy(Qt::CustomContextMenu);
+
+        QTreeWidgetItem* qtreewidgetitem = this->headerItem();
+        qtreewidgetitem->setText(5, "");
+        qtreewidgetitem->setText(4, "");
+        qtreewidgetitem->setText(3, "Status");
+        qtreewidgetitem->setText(2, "SkillID");
+        qtreewidgetitem->setText(1, "Executor");
+        qtreewidgetitem->setText(0, "Timestamp");
+
+        this->setColumnWidth(4, 30);
+
+        connectSignals();
+    }
+
+    void
+    SkillExecutionTreeWidget::connectSignals()
+    {
+        connect(this,
+                &QTreeWidget::customContextMenuRequested,
+                this,
+                &SkillExecutionTreeWidget::runContextMenu);
+        connect(this,
+                &QTreeWidget::currentItemChanged,
+                this,
+                &SkillExecutionTreeWidget::executionSelectionChanged);
+    }
+
+    inline bool
+    SkillExecutionTreeWidget::selectionValid()
+    {
+        return selectedExecution.skillExecutionId.skillId.skillName != skills::SkillID::UNKNOWN;
+    }
+
+    void
+    SkillExecutionTreeWidget::executionSelectionChanged(QTreeWidgetItem* current,
+                                                        QTreeWidgetItem* previous)
+    {
+        // update internal state
+        SkillExecutionTreeWidgetItem* selected =
+            dynamic_cast<SkillExecutionTreeWidgetItem*>(current);
+        if (selected)
+        {
+            this->selectedExecution.skillExecutionId = selected->getExecutionId();
+        }
+    }
+
+    void
+    SkillExecutionTreeWidget::updateExecutions()
+    {
+        auto currentManagerStatuses = memory->fetchExecutions();
+        if (currentManagerStatuses.empty())
+            return;
+
+        for (const auto& [k, v] : currentManagerStatuses)
+        {
+            skills::SkillExecutionID executionId = k;
+            skills::SkillStatusUpdate statusUpdate = v;
+
+            SkillExecutionTreeWidgetItem* found = nullptr;
+            for (int i = 0; i < this->topLevelItemCount(); ++i)
+            {
+                auto c = dynamic_cast<SkillExecutionTreeWidgetItem*>(topLevelItem(i));
+                if (!c)
+                {
+                    // the item is probably not the correct type, skip...
+                    continue;
+                }
+
+                found = SkillExecutionTreeWidgetItem::SearchRecursiveForMatch(c, executionId);
+
+                if (found)
+                {
+                    found->updateItem(statusUpdate.status);
+
+                    break;
+                }
+            }
+
+            if (!found)
+            {
+                // TODO: Sort to executor!
+                auto item = new SkillExecutionTreeWidgetItem(executionId, memory, this);
+
+                item->updateItem(statusUpdate.status);
+            }
+        }
+    }
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/executions/SkillExecutionTreeWidget.h b/source/RobotAPI/libraries/skills_gui/executions/SkillExecutionTreeWidget.h
new file mode 100644
index 0000000000000000000000000000000000000000..795045302b4b47655e196e4cea566d53140f90d6
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/executions/SkillExecutionTreeWidget.h
@@ -0,0 +1,62 @@
+#ifndef SKILLEXECUTIONTREEWIDGET_H
+#define SKILLEXECUTIONTREEWIDGET_H
+
+#include <QTreeWidget>
+
+#include <ArmarXCore/core/time.h>
+
+#include "../memory/MemoryCommunicatorBase.h"
+
+namespace armarx::skills::gui
+{
+
+    class SkillExecutionTreeWidget : public QTreeWidget, public MemoryCommunicatorBase
+    {
+    public:
+        SkillExecutionTreeWidget(std::shared_ptr<SkillManagerWrapper> _memory,
+                                 QWidget* parent = nullptr) :
+            QTreeWidget(parent), MemoryCommunicatorBase(_memory)
+        {
+            setupUi();
+        }
+
+        struct SelectedExecution
+        {
+            skills::SkillExecutionID skillExecutionId;
+
+            // make default constructable
+            SelectedExecution() :
+                skillExecutionId{
+                    .skillId = {.providerId = std::nullopt, .skillName = skills::SkillID::UNKNOWN},
+                    .executorName = skills::SkillExecutionID::UNKNOWN,
+                    .executionStartedTime = armarx::core::time::DateTime::Invalid()}
+            {
+            }
+        };
+
+        SelectedExecution& getSelectedExecution();
+
+    public slots:
+        void disconnectGui();
+        void updateExecutions();
+
+    private slots:
+        void executionSelectionChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous);
+        void runContextMenu(const QPoint& pos);
+        void stopSelectedExecution();
+        void rerunSkillWithSimilarParams();
+
+    private:
+        void setupUi();
+        void connectSignals();
+
+        /**
+         * @brief Checks the validity of the selected item at run time.
+         * @return the validity.
+         */
+        bool selectionValid();
+        SelectedExecution selectedExecution;
+    };
+} // namespace armarx::skills::gui
+
+#endif // SKILLEXECUTIONTREEWIDGET_H
diff --git a/source/RobotAPI/libraries/skills_gui/executions/SkillExecutionTreeWidgetItem.cpp b/source/RobotAPI/libraries/skills_gui/executions/SkillExecutionTreeWidgetItem.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..947671ff7fd44d0c9a9545bf82a721447f0ce952
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/executions/SkillExecutionTreeWidgetItem.cpp
@@ -0,0 +1,95 @@
+#include "SkillExecutionTreeWidgetItem.h"
+
+namespace armarx::skills::gui
+{
+    SkillExecutionTreeWidgetItem*
+    SkillExecutionTreeWidgetItem::SearchRecursiveForMatch(SkillExecutionTreeWidgetItem* haystack,
+                                                          const SkillExecutionID& needle)
+    {
+        if (!haystack)
+        {
+            return nullptr;
+        }
+
+        if (needle == haystack->executionId)
+        {
+            return haystack;
+        }
+        for (int i = 0; i < haystack->childCount(); ++i)
+        {
+            auto el = dynamic_cast<SkillExecutionTreeWidgetItem*>(haystack->child(i));
+            if (!el)
+            {
+                // Dynamic casting failed. Skip element...
+                // We assume, that only this type can contain children in the tree.
+                continue;
+            }
+            return SkillExecutionTreeWidgetItem::SearchRecursiveForMatch(el, needle);
+        }
+        return nullptr;
+    }
+
+    SkillExecutionID
+    SkillExecutionTreeWidgetItem::getExecutionId()
+    {
+        return this->executionId;
+    }
+
+    void
+    SkillExecutionTreeWidgetItem::updateItem(skills::SkillStatus& skillStatus)
+    {
+        this->setText(0,
+                      QString::fromStdString(executionId.executionStartedTime.toDateTimeString()));
+        this->setText(1, QString::fromStdString(executionId.executorName));
+        this->setText(2, QString::fromStdString(executionId.skillId.toString()));
+        for (std::pair<skills::SkillStatus, std::string> i : EXECUTION_STATUS_TO_STRING)
+        {
+            if (i.first == skillStatus)
+            {
+                this->setText(3, QString::fromStdString(i.second));
+            }
+        }
+        updateButtonState(skillStatus);
+    }
+
+    void
+    SkillExecutionTreeWidgetItem::abortExecution()
+    {
+        memory->stopExecution(executionId);
+    }
+
+    void
+    SkillExecutionTreeWidgetItem::setupUi()
+    {
+        parentTree->insertTopLevelItem(0, this);
+        abortButton = new QPushButton();
+        abortButton->setMinimumHeight(20);
+        abortButton->setMaximumHeight(20);
+        parentTree->setItemWidget(this, 4, abortButton);
+
+        QPixmap pix(":/icons/process-stop-7.ico");
+        QIcon icon(pix);
+
+        abortButton->setIcon(icon);
+
+
+        connectSignals();
+    }
+
+    void
+    SkillExecutionTreeWidgetItem::connectSignals()
+    {
+        connect(abortButton,
+                &QPushButton::clicked,
+                this,
+                &SkillExecutionTreeWidgetItem::abortExecution);
+    }
+
+    void
+    SkillExecutionTreeWidgetItem::updateButtonState(SkillStatus& skillStatus)
+    {
+        abortButton->setDisabled(skillStatus == SkillStatus::Aborted ||
+                                 skillStatus == SkillStatus::Failed ||
+                                 skillStatus == SkillStatus::Succeeded);
+    }
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/executions/SkillExecutionTreeWidgetItem.h b/source/RobotAPI/libraries/skills_gui/executions/SkillExecutionTreeWidgetItem.h
new file mode 100644
index 0000000000000000000000000000000000000000..cd0376f8f9c123f6046e061a4955293fc833c9ec
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/executions/SkillExecutionTreeWidgetItem.h
@@ -0,0 +1,68 @@
+#ifndef SKILLEXECUTIONTREEWIDGETITEM_H
+#define SKILLEXECUTIONTREEWIDGETITEM_H
+
+#include <QPushButton>
+#include <QTreeWidgetItem>
+
+#include "RobotAPI/libraries/skills_gui/executions/SkillExecutionTreeWidget.h"
+#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
+{
+    static const std::map<skills::SkillStatus, std::string> EXECUTION_STATUS_TO_STRING = {
+        // Main states
+        {skills::SkillStatus::Constructing, "Constructing"},
+        {skills::SkillStatus::Initializing, "Initializing"},
+        {skills::SkillStatus::Preparing, "Preparing"},
+        {skills::SkillStatus::Running, "Running"},
+
+        // Terminating
+        {skills::SkillStatus::Aborted, "Aborted"},
+        {skills::SkillStatus::Failed, "Failed"},
+        {skills::SkillStatus::Succeeded, "Succeeded"}};
+
+    class SkillExecutionTreeWidgetItem :
+        public QObject,
+        public QTreeWidgetItem,
+        public MemoryCommunicatorBase
+    {
+        Q_OBJECT
+    public:
+        SkillExecutionTreeWidgetItem() = delete;
+
+        SkillExecutionTreeWidgetItem(const skills::SkillExecutionID& id,
+                                     std::shared_ptr<SkillManagerWrapper> _memory,
+                                     SkillExecutionTreeWidget* parent) :
+            MemoryCommunicatorBase(_memory), executionId(id), parentTree(parent)
+        {
+            setupUi();
+        }
+
+        static SkillExecutionTreeWidgetItem*
+        SearchRecursiveForMatch(SkillExecutionTreeWidgetItem* haystack,
+                                const skills::SkillExecutionID& needle);
+
+        skills::SkillExecutionID getExecutionId();
+
+        void updateItem(skills::SkillStatus& skillStatus);
+
+    protected:
+        skills::SkillExecutionID executionId;
+
+    public slots:
+        void abortExecution();
+
+    private:
+        void setupUi();
+        void connectSignals();
+        void updateButtonState(skills::SkillStatus& skillStatus);
+        SkillExecutionTreeWidget* parentTree = nullptr;
+        QPushButton* abortButton = nullptr;
+    };
+} // namespace armarx::skills::gui
+
+#endif // SKILLEXECUTIONTREEWIDGETITEM_H
diff --git a/source/RobotAPI/libraries/skills_gui/gui_utils.cpp b/source/RobotAPI/libraries/skills_gui/gui_utils.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..666228c764379671d6ca59d142fefc02446c42d6
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/gui_utils.cpp
@@ -0,0 +1,109 @@
+#include "gui_utils.h"
+
+#include <QLayout>
+#include <QLayoutItem>
+#include <QSplitter>
+#include <QTreeWidgetItem>
+#include <QWidget>
+
+#include <ArmarXCore/core/exceptions/local/ExpressionException.h>
+
+void
+armarx::gui::clearLayout(QLayout* layout)
+{
+    // Source: https://stackoverflow.com/a/4857631
+
+    ARMARX_CHECK(layout);
+
+    QLayoutItem* item;
+    while ((item = layout->takeAt(0)))
+    {
+        if (item->layout())
+        {
+            clearLayout(item->layout());
+            delete item->layout();
+        }
+        if (item->widget())
+        {
+            delete item->widget();
+        }
+        delete item;
+    }
+}
+
+void
+armarx::gui::clearItem(QTreeWidgetItem* item)
+{
+    while (item->childCount() > 0)
+    {
+        delete item->takeChild(0);
+    }
+}
+
+QSplitter*
+armarx::gui::useSplitter(QLayout* layout)
+{
+    ARMARX_CHECK(layout);
+
+    // Check all items
+    for (int i = 0; i < layout->count(); ++i)
+    {
+        ARMARX_CHECK_NOT_NULL(layout->itemAt(i)->widget())
+            << "QSplitter only supports widgets, but layout item #" << i << " is not a widget.";
+    }
+
+    QSplitter* splitter;
+    if (dynamic_cast<QHBoxLayout*>(layout))
+    {
+        splitter = new QSplitter(Qt::Orientation::Horizontal);
+    }
+    else if (dynamic_cast<QVBoxLayout*>(layout))
+    {
+        splitter = new QSplitter(Qt::Orientation::Vertical);
+    }
+    else
+    {
+        splitter = new QSplitter();
+    }
+
+    while (layout->count() > 0)
+    {
+        const int index = 0;
+        if (layout->itemAt(index))
+        {
+            QLayoutItem* item = layout->takeAt(index);
+
+            ARMARX_CHECK(item->widget());
+            splitter->addWidget(item->widget());
+
+            delete item;
+        }
+    }
+    ARMARX_CHECK_EQUAL(layout->count(), 0);
+
+    layout->addWidget(splitter);
+    ARMARX_CHECK_EQUAL(layout->count(), 1);
+    ARMARX_CHECK_EQUAL(layout->itemAt(0)->widget(), splitter);
+
+    return splitter;
+}
+
+armarx::gui::LeadingZeroSpinBox::LeadingZeroSpinBox(int numDigits, int base) :
+    numDigits(numDigits), base(base)
+{
+}
+
+QString
+armarx::gui::LeadingZeroSpinBox::textFromValue(int value) const
+{
+    return QString("%1").arg(value, numDigits, base, QChar('0'));
+}
+
+void
+armarx::gui::clearSplitter(QSplitter* splitter)
+{
+    for (int i = 0; i < splitter->count(); ++i)
+    {
+        splitter->widget(i)->deleteLater();
+    }
+}
diff --git a/source/RobotAPI/libraries/skills_gui/gui_utils.h b/source/RobotAPI/libraries/skills_gui/gui_utils.h
new file mode 100644
index 0000000000000000000000000000000000000000..3901038ba99f7b59494df40210af0da867ba6ff3
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/gui_utils.h
@@ -0,0 +1,100 @@
+#pragma once
+
+#include <iostream>
+
+#include <QLayout>
+#include <QLayoutItem>
+#include <QSpinBox>
+#include <QSplitter>
+#include <QTreeWidgetItem>
+#include <QWidget>
+
+#include <mutex>
+
+#include <ArmarXCore/core/exceptions/local/ExpressionException.h>
+
+namespace armarx::gui
+{
+    /**
+     * @brief Clear a layout.
+     *
+     * Recursively take and delete all items in `layout`.
+     *
+     * @param layout The layout.
+     */
+    void clearLayout(QLayout* layout);
+
+    void clearSplitter(QSplitter* splitter);
+
+    /**
+     * @brief Clear a tree widget item
+     *
+     * Take and delete all children of `item`.
+     *
+     * @param item The tree widget item.
+     */
+    void clearItem(QTreeWidgetItem* item);
+
+    template <class WidgetT>
+    void
+    replaceWidget(WidgetT*& old, QWidget* neu, QLayout* parentLayout)
+    {
+        ARMARX_CHECK(old);
+        ARMARX_CHECK(neu);
+        ARMARX_CHECK(parentLayout);
+        QLayoutItem* oldItem = parentLayout->replaceWidget(old, neu);
+        if (oldItem)
+        {
+            delete oldItem;
+            delete old;
+            old = nullptr;
+        }
+    }
+
+    template <class WidgetT>
+    void
+    replaceWidget(WidgetT*& old, QWidget* neu, QSplitter*& parentLayout)
+    {
+        ARMARX_CHECK(old);
+        ARMARX_CHECK(neu);
+        ARMARX_CHECK(parentLayout);
+        int index = parentLayout->indexOf(old);
+        ARMARX_CHECK(index >= 0) << "Could not find widget in splitter";
+        QWidget* oldItem = parentLayout->replaceWidget(index, neu);
+        if (oldItem)
+        {
+            // deleting the widget(s) directly will segfault for some reason
+            oldItem->deleteLater();
+            old->deleteLater();
+            old = nullptr;
+        }
+    }
+
+    /**
+     * @brief Let items in `layout` be children of a splitter.
+     *
+     * Items in `layout` are moved to a new `QSplitter`, which will
+     * be the only child of `layout`.
+     * If `layout` is a Q{H,V}BoxLayout, the respective orientation
+     * will be adopted.
+     *
+     * @param The parent layout.
+     * @return The splitter item.
+     */
+    QSplitter* useSplitter(QLayout* layout);
+
+    // Source: https://stackoverflow.com/a/26538572
+    class LeadingZeroSpinBox : public QSpinBox
+    {
+        using QSpinBox::QSpinBox;
+
+    public:
+        LeadingZeroSpinBox(int numDigits, int base);
+
+        QString textFromValue(int value) const override;
+
+    private:
+        int numDigits;
+        int base;
+    };
+} // namespace armarx::gui
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..adefacd9358f9982555cbc860dc0a96a3f58c77f
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/memory/MemoryCommunicatorBase.h
@@ -0,0 +1,27 @@
+#ifndef MEMORYCOMMUNICATOR_H
+#define MEMORYCOMMUNICATOR_H
+
+#include <memory>
+
+#include "SkillManagerWrapper.h"
+
+namespace armarx::skills::gui
+{
+    /*
+     * This is a convenience base class to prevent repeatedly putting the SkillManagerWrapper in
+     * every widget.
+     */
+    class MemoryCommunicatorBase
+    {
+    protected:
+        // We don't want to instantiate the base class
+        MemoryCommunicatorBase(std::shared_ptr<SkillManagerWrapper> _memory) : memory(_memory)
+        {
+        }
+
+        // The interface of the memory, used by the skill memory gui
+        std::shared_ptr<SkillManagerWrapper> memory;
+    };
+} // namespace armarx::skills::gui
+
+#endif // MEMORYCOMMUNICATOR_H
diff --git a/source/RobotAPI/libraries/skills_gui/memory/SkillManagerWrapper.cpp b/source/RobotAPI/libraries/skills_gui/memory/SkillManagerWrapper.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..92277c0eba7e1277a658e8ed685156d70bd100bc
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/memory/SkillManagerWrapper.cpp
@@ -0,0 +1,312 @@
+#include "SkillManagerWrapper.h"
+
+#include <mutex>
+
+#include "RobotAPI/libraries/skills/core/SkillExecutionRequest.h"
+
+namespace armarx::skills::gui
+{
+    using StatusMap = std::map<skills::SkillExecutionID, skills::SkillStatusUpdate>;
+    using SkillMap =
+        std::map<skills::ProviderID, std::map<skills::SkillID, skills::SkillDescription>>;
+
+    const StatusMap
+    SkillManagerWrapper::fetchExecutions()
+    {
+        if (!memory)
+        {
+            // check if null
+            return {};
+        }
+
+        try
+        {
+            std::scoped_lock l(mutex_memory);
+
+            // we return this map
+            StatusMap statusMap;
+
+            auto currentManagerStatuses = memory->getSkillExecutionStatuses();
+
+            // iterate over raw data and convert to common types
+            for (const auto& [k, v] : currentManagerStatuses)
+            {
+                auto executionId = skills::SkillExecutionID::FromIce(k);
+                auto statusUpdate = skills::SkillStatusUpdate::FromIce(v);
+
+                // update maps
+                statusMap[executionId] = statusUpdate;
+            }
+            return statusMap;
+        }
+        catch (Ice::Exception const& e)
+        {
+            ARMARX_WARNING
+                << "Unhandled Ice exception encountered while updating executions. Exception was: "
+                << e;
+            emit connectionUpdate("Could not fetch executions", e.what());
+            return {};
+        }
+        catch (...)
+        {
+            ARMARX_WARNING << "Unknown exception encountered while updating executions.";
+            return {};
+        }
+    }
+
+    void
+    SkillManagerWrapper::filterSkillUpdate(
+        std::map<skills::manager::dto::SkillID, skills::manager::dto::SkillDescription>& update)
+    {
+        // empty search => do not filter
+        if (this->currentSkillSearch.empty())
+        {
+            return;
+        }
+
+        // TODO: whitespace to wildcard
+
+        std::string key = simox::alg::to_lower(this->currentSkillSearch);
+
+        for (auto it = update.begin(); it != update.end();)
+        {
+            if (simox::alg::to_lower(skills::SkillID::FromIce(it->first).skillName).find(key))
+            {
+                it = update.erase(it);
+            }
+            else
+            {
+                ++it;
+            }
+        }
+    }
+
+    const SkillMap
+    SkillManagerWrapper::fetchSkills()
+    {
+        if (!memory)
+        {
+            return {};
+        }
+
+        try
+        {
+            std::scoped_lock l(mutex_memory);
+
+            SkillMap skills;
+
+            auto managerSkills = memory->getSkillDescriptions();
+
+            this->filterSkillUpdate(managerSkills);
+
+
+            for (const auto& [sid, desc] : managerSkills)
+            {
+                auto description = skills::SkillDescription::FromIce(desc);
+                auto skillId = skills::SkillID::FromIce(sid);
+                auto providerId = skillId.providerId.value_or(
+                    skills::ProviderID{.providerName = "UNKNOWN PROVIDER NAME"});
+
+                ARMARX_CHECK(skillId.isFullySpecified());
+
+                auto& providedSkillsMap = skills[providerId]; // create new if not existing
+                providedSkillsMap.insert({skillId, description});
+            }
+
+            return skills;
+        }
+        catch (Ice::Exception const& e)
+        {
+            ARMARX_WARNING
+                << "Unhandled Ice exception encountered while updating skills. Exception was: "
+                << e;
+            emit connectionUpdate("Could not fetch skills", e.what());
+            return {};
+        }
+        catch (...)
+        {
+            ARMARX_WARNING << "Unknown exception encountered while updating skills.";
+            return {};
+        }
+    }
+
+    void
+    SkillManagerWrapper::connectMemory(
+        skills::manager::dti::SkillManagerInterfacePrx const& updatedMemory)
+    {
+        std::scoped_lock l(mutex_memory);
+        this->memory = updatedMemory;
+    }
+
+    void
+    SkillManagerWrapper::disconnectMemory()
+    {
+        // clear memory
+
+        std::scoped_lock l(mutex_memory);
+        this->memory = nullptr;
+    }
+
+    void
+    SkillManagerWrapper::acceptSearchRequest(std::string const& search)
+    {
+        this->currentSkillSearch = search;
+    }
+
+    void
+    SkillManagerWrapper::stopAllExecutions()
+    {
+        ARMARX_IMPORTANT << "Stopping all running executions.";
+        const auto& executions = this->fetchExecutions();
+        for (auto& [executionId, status] : executions)
+        {
+            // select all running executions...
+            if (!status.hasBeenTerminated())
+            {
+                // ... and kill them.
+                this->stopExecution(executionId, 3);
+            }
+        }
+    }
+
+    const std::optional<ProviderID>
+    SkillManagerWrapper::findFirstProvider(SkillMap const& map, SkillID const& skillId)
+    {
+        // check if id already contains a provider. If so, this function should not have been called!
+        if (skillId.isProviderSpecified())
+        {
+            ARMARX_WARNING << "The memory snapshot was searched for any provider, when a provider "
+                              "was specified.";
+            // we continue, but this might result in unexpected behaviour...
+        }
+
+        for (auto& [prov, skillMap] : map)
+        {
+            for (auto& [skill, desc] : skillMap)
+            {
+                if (skill == skillId)
+                {
+                    return prov;
+                }
+            }
+        }
+        return std::nullopt;
+    }
+
+    void
+    SkillManagerWrapper::stopExecution(skills::SkillExecutionID const& executionId,
+                                       const unsigned int max_retries)
+    {
+        // memory???
+        if (!memory)
+        {
+            return;
+        }
+
+        unsigned int retries = max_retries;
+        bool retry = false;
+
+        do
+        {
+            try
+            {
+                ARMARX_INFO << "Aborting skill '" << executionId.skillId.skillName << "'...";
+                std::scoped_lock l(mutex_memory);
+                this->memory->abortSkillAsync(executionId.toManagerIce());
+            }
+            catch (Ice::Exception const& e)
+            {
+                retry = true;
+                ARMARX_ERROR << "Unhandeled Ice exception while aborting skill '"
+                             << executionId.skillId.skillName << "'.";
+                emit connectionUpdate("Could not abort skill " + executionId.skillId.skillName,
+                                      e.what());
+            }
+            catch (...)
+            {
+                retry = true;
+                ARMARX_ERROR << "Unhandled error while aborting skill '"
+                             << executionId.skillId.skillName << "'.";
+            }
+
+            if (retry)
+            {
+                retries -= 1;
+
+                if (retries > 0)
+                {
+                    ARMARX_WARNING << "There where errors aborting skills.  Retrying...";
+                }
+                else
+                {
+                    ARMARX_ERROR << "Couldn't abort all skills after " << max_retries
+                                 << " tries.  Giving up.";
+                    retry = false;
+                }
+            }
+        } while (retry);
+    }
+
+    void
+    SkillManagerWrapper::startExecutionWithParams(skills::SkillID& skillId,
+                                                  aron::data::DictPtr const params)
+    {
+        // Memory???
+        if (!memory)
+        {
+            return;
+        }
+
+        auto providerId = skillId.providerId;
+        if (!providerId.has_value())
+        {
+            ARMARX_IMPORTANT << "The skill: '" << skillId.skillName
+                             << "' has been requested to be executed, but no provider was "
+                                "given. Aborting...";
+            return;
+        }
+
+        std::map<skills::SkillID, skills::SkillDescription> skillDescriptions;
+        {
+            skillDescriptions = this->fetchSkills().at(providerId.value());
+        }
+
+        if (skillDescriptions.find(skillId) == skillDescriptions.end())
+        {
+            ARMARX_IMPORTANT << "The Skill: '" << skillId.skillName
+                             << "' has been requested to be executed, but no skill description was "
+                                "found. Aborting...";
+            return;
+        }
+
+        char hostname[HOST_NAME_MAX];
+        gethostname(hostname, HOST_NAME_MAX);
+
+        skills::SkillExecutionRequest req{
+            .skillId = skillId,
+            .executorName = "Skills.Manager GUI (hostname: " + std::string(hostname) + ")",
+            .parameters = params};
+
+        ARMARX_CHECK(skillId.isFullySpecified()); // sanity check
+        ARMARX_IMPORTANT << "Executing skill from GUI: " << skillId << ".";
+
+        try
+        {
+            std::scoped_lock l(mutex_memory);
+            memory->executeSkillAsync(req.toManagerIce());
+        }
+        catch (Ice::Exception const& e)
+        {
+            ARMARX_ERROR << "Unhandeled Ice exception while executing skill '" << skillId.skillName
+                         << "'. Aborting...";
+            emit connectionUpdate("Execution failed of skill " + skillId.skillName, e.what());
+        }
+        catch (...)
+        {
+            ARMARX_ERROR << "Unhandled error while executing skill '" << skillId.skillName
+                         << "'. Aborting...";
+        }
+    }
+
+
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/memory/SkillManagerWrapper.h b/source/RobotAPI/libraries/skills_gui/memory/SkillManagerWrapper.h
new file mode 100644
index 0000000000000000000000000000000000000000..22eec04e20bfd499aa444eae74136be6d4c5490f
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/memory/SkillManagerWrapper.h
@@ -0,0 +1,103 @@
+#pragma once
+
+#include <mutex>
+
+#include <QObject>
+
+#include "RobotAPI/libraries/skills/core/ProviderID.h"
+#include "RobotAPI/libraries/skills/core/SkillDescription.h"
+#include "RobotAPI/libraries/skills/core/SkillExecutionID.h"
+#include "RobotAPI/libraries/skills/core/SkillStatusUpdate.h"
+#include <RobotAPI/interface/skills/SkillManagerInterface.h>
+
+namespace armarx::skills::gui
+{
+    using StatusMap = std::map<skills::SkillExecutionID, skills::SkillStatusUpdate>;
+    using SkillMap =
+        std::map<skills::ProviderID, std::map<skills::SkillID, skills::SkillDescription>>;
+
+    class SkillManagerWrapper : public QObject
+    {
+        Q_OBJECT
+    public:
+        SkillManagerWrapper(skills::manager::dti::SkillManagerInterfacePrx& _memory,
+                            QObject* parent = nullptr) :
+            QObject(parent), memory(_memory)
+        {
+        }
+
+        // We can instantiate the proxy without memory, if it's not connected yet.
+        SkillManagerWrapper(QObject* parent = nullptr) : QObject(parent)
+        {
+        }
+
+        /**
+         * @brief Updates the memory pointer. This should be called whenever the GUI connects/reconnects.
+         */
+        void connectMemory(skills::manager::dti::SkillManagerInterfacePrx const& updatedMemory);
+
+        // Basic functions to work with. These will produce Ice calls!
+        /**
+         * @brief Attempts to start an execution with given parameters. If an Ice exception is encountered, a message will be logged and the method will abort.
+         * @param skillId The skill to execute.
+         * @param params The parameters to execute with.
+         */
+        void startExecutionWithParams(skills::SkillID& skillId, aron::data::DictPtr const params);
+
+        /**
+         * @brief Attempts to stop an execution. If this doesn't succeed, it will retry.
+         * @param executionId The ExecutionID to abort.
+         * @param max_retries The amount of times to retry, if aborting fails.
+         */
+        void stopExecution(skills::SkillExecutionID const& executionId,
+                           const unsigned int max_retries = 0);
+
+        /**
+         * @brief Fetches and returns the latest skills update from memory.
+         * @return The map representing all skills in memory. Empty, if error occurred.
+         */
+        const SkillMap fetchSkills();
+
+        /**
+         * @brief Fetches and returns the latest status update from memory.
+         * @return The map containing status updates for all execution ids. Empty, if error occurred.
+         */
+        const StatusMap fetchExecutions();
+
+        static const std::optional<skills::ProviderID> findFirstProvider(SkillMap const& map,
+                                                                         SkillID const& skillId);
+
+    signals:
+        void connectionUpdate(std::string const& message, std::string const& error);
+
+    public slots:
+        /**
+         * @brief Disconnects the interface from memory.
+         */
+        void disconnectMemory();
+
+        /**
+         * @brief Applies the search word to the update filter.
+         * @param search The search word.
+         */
+        void acceptSearchRequest(std::string const& search);
+
+        /**
+         * @brief Stops all available (and running) executions.
+         */
+        void stopAllExecutions();
+
+    private:
+        mutable std::mutex mutex_memory;
+
+        armarx::skills::manager::dti::SkillManagerInterfacePrx memory;
+        std::string currentSkillSearch = "";
+
+        /**
+         * @brief Modifies the given map to match the search.
+         * @param update The map to modify.
+         */
+        void filterSkillUpdate(std::map<skills::manager::dto::SkillID,
+                                        skills::manager::dto::SkillDescription>& update);
+    };
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/skill_details/ProfileMenuWidget.cpp b/source/RobotAPI/libraries/skills_gui/skill_details/ProfileMenuWidget.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..20295978a7ea67e75136277af2a1e617e5a9aae5
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/skill_details/ProfileMenuWidget.cpp
@@ -0,0 +1,43 @@
+#include "ProfileMenuWidget.h"
+
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QVBoxLayout>
+
+namespace armarx::skills::gui
+{
+
+    void
+    ProfileMenuWidget::setupUi()
+    {
+        setArgsFromClipboard = new QPushButton();
+        copyArgsToClipboard = new QPushButton();
+        resetArgsToProfile = new QPushButton();
+        profileSelector = new QComboBox();
+
+        // layouting
+        QVBoxLayout* mainLayout = new QVBoxLayout();
+        QHBoxLayout* topLayout = new QHBoxLayout();
+
+        mainLayout->addLayout(topLayout);
+        mainLayout->addWidget(profileSelector);
+
+        topLayout->addWidget(setArgsFromClipboard);
+        topLayout->addWidget(copyArgsToClipboard);
+        // this is not good. We should probably use a QSpacerItem here...
+        topLayout->addWidget(new QLabel());
+        topLayout->addWidget(resetArgsToProfile);
+
+        this->setLayout(mainLayout);
+
+        // Text
+        setArgsFromClipboard->setText(QString::fromStdString(SET_ARGS_BUTTON_TEXT));
+        copyArgsToClipboard->setText(QString::fromStdString(COPY_ARGS_BUTTON_TEXT));
+        resetArgsToProfile->setText(QString::fromStdString(RESET_ARGS_BUTTON_TEXT));
+        profileSelector->addItem(QString::fromStdString(DEFAULT_PROFILE_TEXT));
+        profileSelector->setDisabled(true);
+        profileSelector->setToolTip(QString::fromStdString(PROFILE_NOT_IMPLEMENTED));
+    }
+
+
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/skill_details/ProfileMenuWidget.h b/source/RobotAPI/libraries/skills_gui/skill_details/ProfileMenuWidget.h
new file mode 100644
index 0000000000000000000000000000000000000000..32dc1f278649060b97d58f680f2a8c74d5e1f75a
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/skill_details/ProfileMenuWidget.h
@@ -0,0 +1,40 @@
+#ifndef PROFILEMENUWIDGET_H
+#define PROFILEMENUWIDGET_H
+
+#include <QComboBox>
+#include <QPushButton>
+#include <QWidget>
+
+#include "../memory/MemoryCommunicatorBase.h"
+
+namespace armarx::skills::gui
+{
+    class ProfileMenuWidget : public QWidget, public MemoryCommunicatorBase
+    {
+        Q_OBJECT
+    public:
+        static const constexpr char* SET_ARGS_BUTTON_TEXT = "Set Args from Clipboard";
+        static const constexpr char* COPY_ARGS_BUTTON_TEXT = "Copy Args to Clipboard";
+        static const constexpr char* RESET_ARGS_BUTTON_TEXT = "Reset Args to Profile";
+        static const constexpr char* DEFAULT_PROFILE_TEXT = "<No Profile selected. Using root>";
+        static const constexpr char* PROFILE_NOT_IMPLEMENTED =
+            "Profiles other than the root profile are currently not supported.";
+
+        // contents are public, as this class is just a convenience wrapper
+        QPushButton* setArgsFromClipboard = nullptr;
+        QPushButton* copyArgsToClipboard = nullptr;
+        QPushButton* resetArgsToProfile = nullptr;
+        QComboBox* profileSelector = nullptr;
+
+        ProfileMenuWidget(std::shared_ptr<SkillManagerWrapper> _memory, QWidget* parent = nullptr) :
+            QWidget(parent), MemoryCommunicatorBase(_memory)
+        {
+            setupUi();
+        }
+
+    private:
+        void setupUi();
+    };
+} // namespace armarx::skills::gui
+
+#endif // PROFILEMENUWIDGET_H
diff --git a/source/RobotAPI/libraries/skills_gui/skill_details/SkillDetailsGroupBox.cpp b/source/RobotAPI/libraries/skills_gui/skill_details/SkillDetailsGroupBox.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b54d55c8a21b3ef8f1eb912e52473a9bcfbd230f
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/skill_details/SkillDetailsGroupBox.cpp
@@ -0,0 +1,148 @@
+#include "SkillDetailsGroupBox.h"
+
+namespace armarx::skills::gui
+{
+    void
+    SkillDetailGroupBox::updateSkillDetails(SkillID& _skillId)
+    {
+        if (_skillId.skillName == SkillID::UNKNOWN)
+            return;
+
+        auto const& skills = memory->fetchSkills();
+
+        std::optional<skills::ProviderID> provider_opt;
+        // check skillId
+        if (_skillId.isProviderSpecified())
+        {
+            provider_opt = _skillId.providerId;
+        }
+        else
+        {
+            // find first provider to provide the skill
+            provider_opt = SkillManagerWrapper::findFirstProvider(skills, _skillId);
+        }
+
+        if (provider_opt == std::nullopt)
+        {
+            // skill was not found in snapshot. Abort...
+            return;
+        }
+
+        // construct skill id (with guaranteed valid provider)
+        skills::SkillID skillId = {provider_opt, _skillId.skillName};
+
+
+        // Maybe the search doesn't include the shown skill?
+        if (skills.count(skillId.providerId.value()) == 0 ||
+            skills.at(skillId.providerId.value()).count(skillId) == 0)
+        {
+            // reset details widget
+            skillDetailsTreeWidget->resetWidget();
+            return;
+        }
+
+
+        // get skill description
+        skills::SkillDescription descr = skills.at(skillId.providerId.value()).at(skillId);
+
+        // ------------ update widgets ------------
+
+        setDisabled(true);
+
+        // setup groupBox
+        this->setTitle(QString::fromStdString(skillId.toString()));
+        setDisabled(false);
+
+        // setup table view
+        skillDetailsTreeWidget->updateContents(skillId, descr);
+
+        // description widget
+        skillDescriptionWidget->setSkillDescription(descr);
+
+
+        // add new profiles for this skill
+        // TODO: Where stored?
+    }
+
+    void
+    SkillDetailGroupBox::connectGui(std::string observerName)
+    {
+        skillDetailsTreeWidget->setEditTriggers(QAbstractItemView::EditTrigger::NoEditTriggers);
+    }
+
+    void
+    SkillDetailGroupBox::handleExecutionRequest()
+    {
+        auto data = skillDetailsTreeWidget->getConfigAsAron();
+        auto skillId = skillDetailsTreeWidget->getShownId();
+        if (skillId.has_value())
+        {
+            memory->startExecutionWithParams(skillId.value(), data);
+        }
+    }
+
+    void
+    SkillDetailGroupBox::resizeEvent(QResizeEvent* event)
+    {
+        QGroupBox::resizeEvent(event);
+        skillDetailsTreeWidget->resizeContents();
+    }
+
+    void
+    SkillDetailGroupBox::setupUi()
+    {
+        this->setTitle(QString::fromStdString(GROUP_BOX_TITLE));
+
+        this->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
+
+        // construct all sub widgets
+        this->executeSkillButton = new QPushButton();
+        this->profileMenuWidget = new ProfileMenuWidget(this->memory, this);
+        this->skillDetailsTreeWidget = new SkillDetailsTreeWidget(this->memory, this);
+        this->skillDescriptionWidget = new SkillDescriptionWidget(this);
+        this->layout = new QVBoxLayout();
+
+        // Layouting
+        this->setLayout(layout);
+
+        layout->addWidget(this->profileMenuWidget);
+        layout->addWidget(this->skillDescriptionWidget);
+        layout->addWidget(this->skillDetailsTreeWidget);
+        layout->addWidget(this->executeSkillButton);
+
+        // Text
+        this->executeSkillButton->setText(
+            QString::fromStdString(SkillDetailGroupBox::EXECUTE_SKILL_BUTTON_TEXT));
+
+        connectSignals();
+    }
+
+    void
+    SkillDetailGroupBox::connectSignals()
+    {
+        connect(executeSkillButton,
+                &QPushButton::clicked,
+                this,
+                &SkillDetailGroupBox::handleExecutionRequest);
+        connect(this,
+                &SkillDetailGroupBox::disconnectGui,
+                skillDetailsTreeWidget,
+                &SkillDetailsTreeWidget::disconnectGui);
+
+        // profile buttons
+        connect(profileMenuWidget->copyArgsToClipboard,
+                &QPushButton::clicked,
+                skillDetailsTreeWidget,
+                &SkillDetailsTreeWidget::copyCurrentConfig);
+        connect(profileMenuWidget->setArgsFromClipboard,
+                &QPushButton::clicked,
+                skillDetailsTreeWidget,
+                &SkillDetailsTreeWidget::pasteCurrentConfig);
+        connect(profileMenuWidget->resetArgsToProfile,
+                &QPushButton::clicked,
+                skillDetailsTreeWidget,
+                &SkillDetailsTreeWidget::resetCurrentConfig);
+    }
+
+
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/skill_details/SkillDetailsGroupBox.h b/source/RobotAPI/libraries/skills_gui/skill_details/SkillDetailsGroupBox.h
new file mode 100644
index 0000000000000000000000000000000000000000..918fa2ec3241ae512645c878de16d53042fb0005
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/skill_details/SkillDetailsGroupBox.h
@@ -0,0 +1,66 @@
+#ifndef SKILLDETAILGROUPBOX_H
+#define SKILLDETAILGROUPBOX_H
+
+#include <QGroupBox>
+#include <QPushButton>
+#include <QVBoxLayout>
+
+#include "RobotAPI/libraries/skills_gui/aron_tree_widget/AronTreeWidgetController.h"
+#include "RobotAPI/libraries/skills_gui/aron_tree_widget/widgets/SkillDescriptionWidget.h"
+
+#include "../aron_tree_widget/widgets/SkillDescriptionWidget.h"
+#include "../memory/MemoryCommunicatorBase.h"
+#include "ProfileMenuWidget.h"
+#include "SkillDetailsTreeWidget.h"
+
+namespace armarx::skills::gui
+{
+    class SkillDetailGroupBox : public QGroupBox, public MemoryCommunicatorBase
+    {
+        Q_OBJECT
+    public:
+        static const constexpr char* EXECUTE_SKILL_BUTTON_TEXT = "Request Execution";
+        static const constexpr char* GROUP_BOX_TITLE = "Skill Description";
+
+        SkillDetailGroupBox(std::shared_ptr<SkillManagerWrapper> _memory,
+                            QWidget* parent = nullptr) :
+            QGroupBox(parent), MemoryCommunicatorBase(_memory)
+        {
+            setupUi();
+        }
+
+    signals:
+        void disconnectGui();
+
+        /**
+         * @brief Notify widgets to update themselves
+         */
+        void updateGui();
+
+    public slots:
+        /**
+         * @brief Update subwidgets of an updated skill selection.
+         * @param skillId
+         */
+        void updateSkillDetails(skills::SkillID& skillId);
+
+        void connectGui(std::string observerName);
+
+    private slots:
+        void handleExecutionRequest();
+        void resizeEvent(QResizeEvent* event) override;
+
+    private:
+        void setupUi();
+        void connectSignals();
+
+        QVBoxLayout* layout = nullptr;
+        QPushButton* executeSkillButton = nullptr;
+        SkillDetailsTreeWidget* skillDetailsTreeWidget = nullptr;
+        SkillDescriptionWidget* skillDescriptionWidget = nullptr;
+
+        ProfileMenuWidget* profileMenuWidget = nullptr;
+    };
+} // namespace armarx::skills::gui
+
+#endif // SKILLDETAILGROUPBOX_H
diff --git a/source/RobotAPI/libraries/skills_gui/skill_details/SkillDetailsTreeWidget.cpp b/source/RobotAPI/libraries/skills_gui/skill_details/SkillDetailsTreeWidget.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0287c5468f3a6b1f27e182e88bdbf589f4736af5
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/skill_details/SkillDetailsTreeWidget.cpp
@@ -0,0 +1,219 @@
+#include "SkillDetailsTreeWidget.h"
+
+#include <QApplication>
+#include <QClipboard>
+#include <QHeaderView>
+#include <QResizeEvent>
+#include <QVBoxLayout>
+
+#include <RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.h>
+
+namespace armarx::skills::gui
+{
+    SkillDetailsTreeWidget::SkillDetailsTreeWidget(std::shared_ptr<SkillManagerWrapper> _memory,
+                                                   QWidget* parent) :
+        QTreeWidget(parent), MemoryCommunicatorBase(_memory)
+    {
+        setupUi();
+    }
+
+    std::optional<SkillID>
+    SkillDetailsTreeWidget::getShownId()
+    {
+        if (shownSkill.has_value())
+        {
+            return shownSkill.value().skillId;
+        }
+        else
+        {
+            return std::nullopt;
+        }
+    }
+
+    void
+    SkillDetailsTreeWidget::updateContents(const SkillID& skillId, const SkillDescription& descr)
+    {
+        // dont touch the widget if the skill id didn't change
+        // note: this is only relevant when periodic updates are enabled
+        /*
+        if (shownSkill.has_value() && skillId == shownSkill.value().skillId)
+            return;
+        */
+
+        // check the parameters: did they change?
+        if (shownSkill.has_value())
+        {
+            auto remDesc = shownSkill.value().descr;
+            if (descr.rootProfileDefaults != remDesc.rootProfileDefaults)
+            {
+                // TODO: ask the user if they want to reset to defaults
+                // for now, we just overwrite without asking... (and do nothing)
+            }
+            // other cases: if the parameter types change, we *have* to reset; else the skill
+            // cannot be started with the parameters.
+            // same goes for the result type.
+        }
+
+        this->resetWidget();
+
+        auto aron_args = descr.parametersType;
+        auto default_args_of_profile = descr.rootProfileDefaults;
+        // ideally we want to use the invisible root item, but aron expects a parent...
+        QTreeWidgetItem* aronTreeWidgetItem = new QTreeWidgetItem(this);
+        aronTreeWidgetItem->setText(0, QString::fromStdString("Parameters"));
+
+        aronTreeWidgetController = std::make_shared<AronTreeWidgetController>(
+            this, aronTreeWidgetItem, aron_args, default_args_of_profile);
+
+
+        this->expandAll();
+        resizeContents();
+
+        // update the ShownSkill
+        shownSkill = {skillId, descr};
+    }
+
+    void
+    SkillDetailsTreeWidget::disconnectGui()
+    {
+        this->aronTreeWidgetController = nullptr;
+    }
+
+    void
+    SkillDetailsTreeWidget::updateGui()
+    {
+        if (!shownSkill.has_value())
+            return;
+        skills::SkillID sid = shownSkill.value().skillId;
+
+        // we assume the id to be fully specified, as it is checked while constructing
+        // sanity check
+        ARMARX_CHECK(sid.isFullySpecified());
+
+        // maybe the search is empty?
+        auto skillsMap = memory->fetchSkills();
+        if (skillsMap.count(sid.providerId.value()) == 0 ||
+            skillsMap.at(sid.providerId.value()).count(sid) == 0)
+        {
+            this->resetWidget();
+            return;
+        }
+
+        auto descr = memory->fetchSkills().at(sid.providerId.value()).at(sid);
+
+        this->updateContents(sid, descr);
+    }
+
+    void
+    SkillDetailsTreeWidget::setupUi()
+    {
+        this->setColumnCount(3);
+
+        this->setContextMenuPolicy(Qt::CustomContextMenu);
+        this->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed);
+
+        QTreeWidgetItem* qtreewidgetitem2 = this->headerItem();
+        qtreewidgetitem2->setText(3, "defaultValue (hidden in GUI)");
+        qtreewidgetitem2->setText(2, "Type");
+        qtreewidgetitem2->setText(1, "Value");
+        qtreewidgetitem2->setText(0, "Key");
+
+        setColumnHidden(3, true);
+    }
+
+    /**
+     * Problem: columns 0 and 1 have arbitrary size; so we want to limit their size, to make sure
+     * everything is visible without scrolling. Column 2 is limited by design, as it only contains
+     * type information.
+     */
+    void
+    SkillDetailsTreeWidget::resizeContents()
+    {
+        // take remainder of width (which we want to assign to dynamic columns)
+        const int widthRemainder = this->width() - typeWidth;
+
+        // we want to assign half of it to each dynamic column
+        const int dynamicColumnSize = widthRemainder / 2;
+
+        // set width...
+
+        this->setColumnWidth(0, dynamicColumnSize);
+
+        this->setColumnWidth(1, dynamicColumnSize);
+    }
+
+    aron::data::DictPtr
+    SkillDetailsTreeWidget::getConfigAsAron()
+    {
+        // create argument aron (if there is an accepted type set)
+        if (aronTreeWidgetController)
+        {
+            return aronTreeWidgetController->convertToAron();
+        }
+        return nullptr;
+    }
+
+    void
+    SkillDetailsTreeWidget::copyCurrentConfig()
+    {
+        auto data = getConfigAsAron();
+        if (!data)
+        {
+            return;
+        }
+
+        auto json = aron::data::converter::AronNlohmannJSONConverter::ConvertToNlohmannJSON(data);
+        QClipboard* clipboard = QApplication::clipboard();
+        clipboard->setText(QString::fromStdString(json.dump(2)));
+    }
+
+    void
+    SkillDetailsTreeWidget::pasteCurrentConfig()
+    {
+        QClipboard* clipboard = QApplication::clipboard();
+        std::string s = clipboard->text().toStdString();
+        nlohmann::json json = nlohmann::json::parse(s);
+        auto data =
+            aron::data::converter::AronNlohmannJSONConverter::ConvertFromNlohmannJSONObject(json);
+
+        if (!aronTreeWidgetController)
+        {
+            return;
+        }
+
+        aronTreeWidgetController->setFromAron(data);
+    }
+
+    void
+    SkillDetailsTreeWidget::resetCurrentConfig()
+    {
+        // this will always reset the args to the root profile
+        // good while there is only the root, not good when profiles are properly implemented
+
+
+        if (!shownSkill.has_value())
+        {
+            return;
+        }
+        skills::SkillID& skillId = shownSkill.value().skillId;
+        auto& skills = memory->fetchSkills();
+        ARMARX_CHECK(skillId.isProviderSpecified());
+
+        // find description
+        // did the provider die?
+        if (skills.count(skillId.providerId.value()) == 0 ||
+            skills.at(skillId.providerId.value()).count(skillId) == 0)
+            return;
+        skills::SkillDescription descr = skills.at(skillId.providerId.value()).at(skillId);
+        this->updateContents(skillId, descr);
+    }
+
+    void
+    SkillDetailsTreeWidget::resetWidget()
+    {
+        this->clear();
+        aronTreeWidgetController = nullptr;
+    }
+
+
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/skill_details/SkillDetailsTreeWidget.h b/source/RobotAPI/libraries/skills_gui/skill_details/SkillDetailsTreeWidget.h
new file mode 100644
index 0000000000000000000000000000000000000000..1ac3bcdd1e59c8d6b842943ab09f7da174273273
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/skill_details/SkillDetailsTreeWidget.h
@@ -0,0 +1,52 @@
+#ifndef SKILLDETAILSTREEWIDGET_H
+#define SKILLDETAILSTREEWIDGET_H
+
+#include <QTreeWidget>
+
+#include "RobotAPI/libraries/skills_gui/aron_tree_widget/AronTreeWidgetController.h"
+
+#include "../memory/MemoryCommunicatorBase.h"
+
+namespace armarx::skills::gui
+{
+    class SkillDetailsTreeWidget : public QTreeWidget, public MemoryCommunicatorBase
+    {
+        Q_OBJECT
+    public:
+        SkillDetailsTreeWidget(std::shared_ptr<SkillManagerWrapper> _memory,
+                               QWidget* parent = nullptr);
+
+        std::optional<skills::SkillID> getShownId();
+        void updateContents(skills::SkillID const& skillId, skills::SkillDescription const& descr);
+
+        aron::data::DictPtr getConfigAsAron();
+        void copyCurrentConfig();
+        void pasteCurrentConfig();
+        void resetWidget();
+
+    public slots:
+        // this will reset the args to the profile defaults
+        void resetCurrentConfig();
+        void disconnectGui();
+        void updateGui();
+        void resizeContents();
+
+    private:
+        struct ShownSkill
+        {
+            skills::SkillID skillId;
+            skills::SkillDescription descr;
+        };
+
+        std::optional<ShownSkill> shownSkill;
+
+        // The size, which we assume the last column to be.
+        // If the last column has too little space, increase this value.
+        const int typeWidth = 200;
+
+        AronTreeWidgetControllerPtr aronTreeWidgetController = nullptr;
+        void setupUi();
+    };
+} // namespace armarx::skills::gui
+
+#endif // SKILLDETAILSTREEWIDGET_H
diff --git a/source/RobotAPI/libraries/skills_gui/skills/SkillGroupBox.cpp b/source/RobotAPI/libraries/skills_gui/skills/SkillGroupBox.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..91fb11c021677e96890a001a0538fc6cf98f4aa0
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/skills/SkillGroupBox.cpp
@@ -0,0 +1,74 @@
+#include "SkillGroupBox.h"
+
+#include <QHBoxLayout>
+#include <QVBoxLayout>
+
+namespace armarx::skills::gui
+{
+    void
+    SkillGroupBox::handleSearch()
+    {
+        std::string search = this->searchBar->text().toStdString();
+        emit searchRequest(search);
+    }
+
+    void
+    SkillGroupBox::connectGui(std::string observerName)
+    {
+        setTitle(QString::fromStdString(observerName));
+    }
+
+    void
+    SkillGroupBox::setupUi()
+    {
+        this->setTitle(QString::fromStdString(GROUP_BOX_TITLE));
+
+        this->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
+
+
+        // construct widgets
+        this->searchBar = new QLineEdit();
+        this->acceptSearchButton = new QPushButton();
+        this->skillTreeWidget = new SkillTreeWidget(memory, this);
+
+        // layouting
+        QHBoxLayout* searchLayout = new QHBoxLayout();
+        QVBoxLayout* layout = new QVBoxLayout();
+        this->setLayout(layout);
+        layout->addLayout(searchLayout);
+        layout->addWidget(this->skillTreeWidget);
+
+        searchLayout->addWidget(this->searchBar);
+        searchLayout->addWidget(this->acceptSearchButton);
+
+        // text
+        this->searchBar->setPlaceholderText(QString::fromStdString("Search ..."));
+        this->acceptSearchButton->setText(QString::fromStdString("Search"));
+
+        connectSignals();
+    }
+
+    void
+    SkillGroupBox::connectSignals()
+    {
+        connect(
+            this->acceptSearchButton, &QPushButton::clicked, this, &SkillGroupBox::handleSearch);
+        connect(this->searchBar, &QLineEdit::editingFinished, this, &SkillGroupBox::handleSearch);
+        connect(this,
+                &SkillGroupBox::searchRequest,
+                this->memory.get(),
+                &SkillManagerWrapper::acceptSearchRequest);
+
+        connect(skillTreeWidget,
+                &SkillTreeWidget::updateSkillDetails,
+                this,
+                &SkillGroupBox::updateSkillDetails);
+
+        // disconnect
+        connect(
+            this, &SkillGroupBox::disconnectGui, skillTreeWidget, &SkillTreeWidget::disconnectGui);
+
+        // update cascade
+        connect(this, &SkillGroupBox::updateGui, skillTreeWidget, &SkillTreeWidget::updateSkills);
+    }
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/skills/SkillGroupBox.h b/source/RobotAPI/libraries/skills_gui/skills/SkillGroupBox.h
new file mode 100644
index 0000000000000000000000000000000000000000..2ac6044ba72807ef300ae48fa19fe53d9230d1f3
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/skills/SkillGroupBox.h
@@ -0,0 +1,62 @@
+#ifndef SKILLGROUPBOX_H
+#define SKILLGROUPBOX_H
+
+#include <QGroupBox>
+#include <QLineEdit>
+#include <QPushButton>
+
+#include "../memory/MemoryCommunicatorBase.h"
+#include "SkillTreeWidget.h"
+
+namespace armarx::skills::gui
+{
+    class SkillGroupBox : public QGroupBox, public MemoryCommunicatorBase
+    {
+        Q_OBJECT
+    public:
+        static const constexpr char* GROUP_BOX_TITLE = "Skills";
+
+        SkillGroupBox(std::shared_ptr<SkillManagerWrapper> _memory, QWidget* parent = nullptr) :
+            QGroupBox(parent), MemoryCommunicatorBase(_memory)
+        {
+            setupUi();
+        }
+
+    signals:
+        /**
+         * @brief Output signal to controller.
+         */
+        void searchRequest(std::string search);
+
+        /**
+         * @brief Notify the skill description widget of an updated selection.
+         * @param skillId
+         */
+        void updateSkillDetails(skills::SkillID& skillId);
+
+        void disconnectGui();
+
+        /**
+         * @brief Notify widgets to update themselves
+         */
+        void updateGui();
+
+    public slots:
+        void connectGui(std::string observerName);
+
+    private slots:
+        /**
+         * Takes string from line edit and emits the search request.
+         */
+        void handleSearch();
+
+    private:
+        void setupUi();
+        void connectSignals();
+        QLineEdit* searchBar = nullptr;
+        QPushButton* acceptSearchButton = nullptr;
+        SkillTreeWidget* skillTreeWidget = nullptr;
+    };
+} // namespace armarx::skills::gui
+
+#endif // SKILLGROUPBOX_H
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..9909cc1675edf8ae1ae94a33ae878bde21955498
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidget.cpp
@@ -0,0 +1,152 @@
+#include "SkillTreeWidget.h"
+
+#include "RobotAPI/libraries/skills_gui/skills/SkillTreeWidgetItem.h"
+
+namespace armarx::skills::gui
+{
+    void
+    SkillTreeWidget::skillSelectionChanged(QTreeWidgetItem* current, int)
+    {
+        if (!current)
+        {
+            // gui has died?
+            return;
+        }
+
+        auto c = dynamic_cast<SkillTreeWidgetItem*>(current);
+        if (!c)
+        {
+            // we don't know what to do with the item. Abort...
+            return;
+        }
+
+        selectedSkill.skillId = c->skillId;
+        emit updateSkillDetails(selectedSkill.skillId);
+    }
+
+    void
+    SkillTreeWidget::updateSkills()
+    {
+        const auto skills = memory->fetchSkills();
+
+        // update tree view. Remove non-existing elements
+        int i = 0;
+        while (i < this->topLevelItemCount())
+        {
+            auto* providerItem = this->topLevelItem(i);
+            auto providerName = providerItem->text(0).toStdString();
+            skills::ProviderID providerId{.providerName = providerName};
+
+            if (skills.find(providerId) == skills.end())
+            {
+                providerItem = nullptr; // reset
+                auto remove = this->takeTopLevelItem(i);
+                delete remove;
+                continue;
+            }
+
+            ++i;
+
+            // sanity check
+            ARMARX_CHECK(skills.count(providerId) > 0);
+            auto& providedSkills = skills.at(providerId);
+
+            int j = 0;
+            while (j < providerItem->childCount())
+            {
+                auto* skillItem = providerItem->child(j);
+                auto skillName = skillItem->text(0).toStdString();
+
+                skills::SkillID skillId{.providerId =
+                                            skills::ProviderID{.providerName = providerName},
+                                        .skillName = skillName};
+
+                if (providedSkills.find(skillId) == providedSkills.end())
+                {
+                    skillItem = nullptr;
+                    auto remove = providerItem->takeChild(j);
+                    delete remove;
+                    continue;
+                }
+
+                ++j;
+            }
+        }
+
+        // update tree view. Add new elements
+        for (const auto& [providerId, providedSkills] : skills)
+        {
+            QTreeWidgetItem* providerItem = nullptr;
+            for (int i = 0; i < this->topLevelItemCount(); ++i)
+            {
+                auto el = this->topLevelItem(i);
+                auto providerName = el->text(0).toStdString();
+                skills::ProviderID elProviderId{.providerName = providerName};
+
+                if (providerId == elProviderId)
+                {
+                    providerItem = el;
+                    break;
+                }
+            }
+
+            if (!providerItem)
+            {
+                providerItem = new QTreeWidgetItem(this);
+                providerItem->setText(0, QString::fromStdString(providerId.providerName));
+            }
+
+            for (const auto& [skillId, skill] : providedSkills)
+            {
+                QTreeWidgetItem* skillItem = nullptr;
+                for (int i = 0; i < providerItem->childCount(); ++i)
+                {
+                    auto el = providerItem->child(i);
+                    auto skillName = el->text(0).toStdString();
+                    skills::SkillID elSkillId{providerId, skillName};
+
+                    if (skillId == elSkillId)
+                    {
+                        skillItem = el;
+                        break;
+                    }
+                }
+
+                if (!skillItem)
+                {
+                    skillItem = new SkillTreeWidgetItem(skillId, providerItem);
+                    skillItem->setText(0, QString::fromStdString(skillId.skillName));
+                }
+            }
+        }
+    }
+
+    void
+    SkillTreeWidget::disconnectGui()
+    {
+        this->clear();
+        selectedSkill = SelectedSkill();
+    }
+
+    void
+    SkillTreeWidget::setupUi()
+    {
+        this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+
+        QTreeWidgetItem* qtreewidgetitem = this->headerItem();
+
+        qtreewidgetitem->setText(0, "Skill");
+
+        connectSignals();
+    }
+
+    void
+    SkillTreeWidget::connectSignals()
+    {
+        // The selectionChanged signal does not trigger when clicking the active item
+        // => we use itemClicked
+        connect(this, &QTreeWidget::itemClicked, this, &SkillTreeWidget::skillSelectionChanged);
+    }
+
+
+} // namespace armarx::skills::gui
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..c076d2101f0016056f13dd4a75adc7022fa5a50a
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidget.h
@@ -0,0 +1,60 @@
+#ifndef ARMARX_SKILLS_GUI_SKILLTREEWIDGET_H
+#define ARMARX_SKILLS_GUI_SKILLTREEWIDGET_H
+
+#include <QTreeWidget>
+
+#include <RobotAPI/libraries/skills/core/SkillID.h>
+
+#include "../memory/MemoryCommunicatorBase.h"
+
+namespace armarx::skills::gui
+{
+
+    class SkillTreeWidget : public QTreeWidget, public MemoryCommunicatorBase
+    {
+        Q_OBJECT
+    public:
+        SkillTreeWidget(std::shared_ptr<SkillManagerWrapper> _memory, QWidget* parent = nullptr) :
+            QTreeWidget(parent), MemoryCommunicatorBase(_memory)
+        {
+            setupUi();
+        }
+
+        struct SelectedSkill
+        {
+            skills::SkillID skillId;
+
+            // make default constructable
+            SelectedSkill() :
+                skillId({.providerId = std::nullopt, .skillName = skills::SkillID::UNKNOWN})
+            {
+            }
+        };
+
+        SelectedSkill& getSelectedSkill();
+
+    signals:
+        /**
+         * @brief Notify the skill description widget of an updated selection.
+         * @param skillId
+         */
+        void updateSkillDetails(skills::SkillID& skillId);
+
+    public slots:
+        void disconnectGui();
+        void updateSkills();
+
+    private slots:
+        void skillSelectionChanged(QTreeWidgetItem* current, int column);
+
+
+    private:
+        SelectedSkill selectedSkill;
+
+        void setupUi();
+        void connectSignals();
+    };
+
+} // namespace armarx::skills::gui
+
+#endif // ARMARX_SKILLS_GUI_SKILLTREEWIDGET_H
diff --git a/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidgetItem.cpp b/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidgetItem.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e4845c11d5bc6264a0f4200d412eb6eb28198b19
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidgetItem.cpp
@@ -0,0 +1,6 @@
+#include "SkillTreeWidgetItem.h"
+
+namespace armarx::skills::gui
+{
+
+} // namespace armarx::skills::gui
diff --git a/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidgetItem.h b/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidgetItem.h
new file mode 100644
index 0000000000000000000000000000000000000000..2a2ae418e4f546027753a4faf62daf7693ee0f7a
--- /dev/null
+++ b/source/RobotAPI/libraries/skills_gui/skills/SkillTreeWidgetItem.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <QTreeWidgetItem>
+#include "RobotAPI/libraries/skills/core/SkillID.h"
+
+
+
+namespace armarx::skills::gui
+{
+    class SkillTreeWidgetItem : public QTreeWidgetItem
+    {
+    public:
+        SkillTreeWidgetItem(const skills::SkillID& desc, QTreeWidgetItem* parent) :
+            QTreeWidgetItem(parent), skillId(desc)
+        {
+        }
+
+        SkillTreeWidgetItem(const skills::SkillID& desc, QTreeWidget* parent) :
+            QTreeWidgetItem(parent), skillId(desc)
+        {
+        }
+
+        skills::SkillID skillId;
+    };
+}
+