From 9385b3333f61af9cc80e6a27eb4368d4e5bd8d4d Mon Sep 17 00:00:00 2001
From: Fabian Peller-Konrad <fabian.peller-konrad@kit.edu>
Date: Thu, 13 Jan 2022 17:09:20 +0100
Subject: [PATCH] finalized first working version of skill provider and skill
 manager adapted some aron visitor stuff for type visitors (similar to data
 visitors)

---
 .../SkillProviderExample/CMakeLists.txt       |   1 +
 .../SkillProviderExample.cpp                  |  44 +-
 .../SkillProviderExample.h                    |   9 +-
 .../server/SkillsMemory/SkillsMemory.cpp      | 121 ++--
 .../armem/server/SkillsMemory/SkillsMemory.h  |  27 +-
 source/RobotAPI/gui-plugins/CMakeLists.txt    |   2 +-
 .../SkillManagerPlugin/CMakeLists.txt         |  16 +
 .../SkillManagerMonitorWidget.ui}             |  93 ++-
 .../SkillManagerMonitorWidgetController.cpp   | 607 ++++++++++++++++++
 .../SkillManagerMonitorWidgetController.h     | 195 ++++++
 .../SkillObserverMonitor/CMakeLists.txt       |  16 -
 .../SkillObserverMonitorWidgetController.cpp  | 152 -----
 .../SkillObserverMonitorWidgetController.h    | 120 ----
 source/RobotAPI/interface/CMakeLists.txt      |   2 +-
 ...nterface.ice => SkillManagerInterface.ice} |   8 +-
 .../interface/skills/SkillMemoryInterface.ice |   6 +-
 .../skills/SkillProviderInterface.ice         |  38 +-
 .../skills/StatechartListenerInterface.ice    |   2 +-
 .../libraries/armem_skills/CMakeLists.txt     |   6 +-
 .../libraries/armem_skills/aron/Skill.xml     |  23 +-
 .../client/SkillProviderComponentPlugin.cpp   | 140 ++--
 .../client/SkillProviderComponentPlugin.h     |  76 ++-
 .../server/SkillManagerComponentPlugin.cpp    |  65 ++
 ...Plugin.h => SkillManagerComponentPlugin.h} |  15 +-
 .../server/SkillObserverComponentPlugin.cpp   |  52 --
 .../segment/ExecutableSkillLibrarySegment.cpp |  24 +-
 .../segment/ExecutableSkillLibrarySegment.h   |   7 +-
 .../server/segment/SkillEventSegment.cpp      |  27 +
 .../server/segment/SkillEventSegment.h        |  31 +
 .../segment/SkillExecutionRequestSegment.cpp  |   4 +-
 .../aron/core/type/variant/Variant.h          |   1 +
 .../aron/core/type/variant/container/Dict.cpp |   2 +-
 .../aron/core/type/variant/container/List.cpp |   2 +-
 .../core/type/variant/container/Object.cpp    |   5 +-
 .../aron/core/type/variant/container/Object.h |   2 +-
 .../aron/core/type/variant/container/Pair.cpp |   4 +-
 .../core/type/variant/container/Tuple.cpp     |   3 +-
 .../type/visitor/variant/VariantVisitor.cpp   | 148 +++++
 .../type/visitor/variant/VariantVisitor.h     |  47 ++
 39 files changed, 1572 insertions(+), 571 deletions(-)
 create mode 100644 source/RobotAPI/gui-plugins/SkillManagerPlugin/CMakeLists.txt
 rename source/RobotAPI/gui-plugins/{SkillObserverMonitor/SkillObserverMonitorWidget.ui => SkillManagerPlugin/SkillManagerMonitorWidget.ui} (60%)
 create mode 100644 source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp
 create mode 100644 source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h
 delete mode 100644 source/RobotAPI/gui-plugins/SkillObserverMonitor/CMakeLists.txt
 delete mode 100644 source/RobotAPI/gui-plugins/SkillObserverMonitor/SkillObserverMonitorWidgetController.cpp
 delete mode 100644 source/RobotAPI/gui-plugins/SkillObserverMonitor/SkillObserverMonitorWidgetController.h
 rename source/RobotAPI/interface/skills/{SkillObserverInterface.ice => SkillManagerInterface.ice} (77%)
 create mode 100644 source/RobotAPI/libraries/armem_skills/server/SkillManagerComponentPlugin.cpp
 rename source/RobotAPI/libraries/armem_skills/server/{SkillObserverComponentPlugin.h => SkillManagerComponentPlugin.h} (62%)
 delete mode 100644 source/RobotAPI/libraries/armem_skills/server/SkillObserverComponentPlugin.cpp
 create mode 100644 source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.cpp
 create mode 100644 source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.h

diff --git a/source/RobotAPI/components/armem/client/SkillProviderExample/CMakeLists.txt b/source/RobotAPI/components/armem/client/SkillProviderExample/CMakeLists.txt
index a90a8a25c..012e47bbd 100644
--- a/source/RobotAPI/components/armem/client/SkillProviderExample/CMakeLists.txt
+++ b/source/RobotAPI/components/armem/client/SkillProviderExample/CMakeLists.txt
@@ -6,6 +6,7 @@ set(COMPONENT_LIBS
     ArmarXGuiComponentPlugins
     RobotAPICore 
     RobotAPIInterfaces 
+    aron
     armem_skills
     aronjsonconverter
 )
diff --git a/source/RobotAPI/components/armem/client/SkillProviderExample/SkillProviderExample.cpp b/source/RobotAPI/components/armem/client/SkillProviderExample/SkillProviderExample.cpp
index 3404a3312..c22bf43ed 100644
--- a/source/RobotAPI/components/armem/client/SkillProviderExample/SkillProviderExample.cpp
+++ b/source/RobotAPI/components/armem/client/SkillProviderExample/SkillProviderExample.cpp
@@ -2,11 +2,13 @@
 
 #include "SkillProviderExample.h"
 
+#include <RobotAPI/libraries/aron/core/type/variant/container/Object.h>
+#include <RobotAPI/libraries/aron/core/type/variant/primitive/String.h>
 #include <RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.h>
 
 namespace armarx::skills::example
 {
-    SkillImplementation::Status HelloWorldSkill::execute(const aron::data::DictPtr& d)
+    SkillImplementation::Status HelloWorldSkill::execute(const aron::data::DictPtr& d, const CallbackT&)
     {
         ARMARX_IMPORTANT << "Hi, from the Hello World Skill.\n" <<
                             "I received the following data: \n" <<
@@ -15,6 +17,24 @@ namespace armarx::skills::example
         return SkillImplementation::Status::Succeeded;
     }
 
+    SkillImplementation::Status CallbackSkill::execute(const aron::data::DictPtr& d, const CallbackT& callback)
+    {
+        ARMARX_IMPORTANT << "Logging three updates via the callback";
+        auto up1 = std::make_shared<aron::data::Dict>();
+        up1->addElement("updateInfo", std::make_shared<aron::data::String>("Update 1"));
+        callback(up1);
+
+        auto up2 = std::make_shared<aron::data::Dict>();
+        up2->addElement("updateInfo", std::make_shared<aron::data::String>("Update 2"));
+        callback(up2);
+
+        auto up3 = std::make_shared<aron::data::Dict>();
+        up3->addElement("updateInfo", std::make_shared<aron::data::String>("Update 3"));
+        callback(up3);
+
+        return SkillImplementation::Status::Succeeded;
+    }
+
 
     SkillProviderExample::SkillProviderExample() :
         SkillProviderComponentPluginUser()
@@ -35,20 +55,34 @@ namespace armarx::skills::example
     {
         // Add example skill
         {
+            auto helloWorldAcceptedType = std::make_shared<aron::type::Object>("helloWorldAcceptedType");
+            auto helloWorldAcceptedTypeText = std::make_shared<aron::type::String>(aron::Path({"text"}));
+            helloWorldAcceptedType->addMemberType("text", helloWorldAcceptedTypeText);
+
             skills::SkillDescription helloWorldDesc;
-            helloWorldDesc.acceptedType = nullptr; // accept everything
             helloWorldDesc.documentation = "This skill logs a message on ARMARX_IMPORTANT";
             helloWorldDesc.name = "HelloWorld";
+            helloWorldDesc.acceptedType = helloWorldAcceptedType->toObjectDTO();
+            helloWorldDesc.timeoutMs = 1000;
             addSkill(std::make_shared<HelloWorldSkill>(), helloWorldDesc);
         }
 
-        // Add another example skill
+        // Add another lambda example skill
         {
             skills::SkillDescription fooDesc;
-            fooDesc.acceptedType = nullptr;
+            fooDesc.acceptedType = nullptr; // accept everything
             fooDesc.documentation = "This skill does exactly nothing.";
             fooDesc.name = "Foo";
-            addSkill([](const aron::data::DictPtr&){ return true; }, fooDesc);
+            addSkill([](const aron::data::DictPtr&){ std::cout << "Hello from Foo" << std::endl; return true; }, fooDesc);
+        }
+
+        // Add another example skill
+        {
+            skills::SkillDescription cbDesc;
+            cbDesc.acceptedType = nullptr; // accept everything
+            cbDesc.documentation = "This skill does shows callbacks.";
+            cbDesc.name = "ShowMeCallbacks";
+            addSkill(std::make_shared<CallbackSkill>(), cbDesc);
         }
     }
 
diff --git a/source/RobotAPI/components/armem/client/SkillProviderExample/SkillProviderExample.h b/source/RobotAPI/components/armem/client/SkillProviderExample/SkillProviderExample.h
index c9eb9026c..a6a9374a9 100644
--- a/source/RobotAPI/components/armem/client/SkillProviderExample/SkillProviderExample.h
+++ b/source/RobotAPI/components/armem/client/SkillProviderExample/SkillProviderExample.h
@@ -35,7 +35,14 @@ namespace armarx::skills::example
     class HelloWorldSkill : public SkillImplementation
     {
     public:
-        Status execute(const aron::data::DictPtr&) override;
+        Status execute(const aron::data::DictPtr&, const CallbackT&) override;
+    };
+
+
+    class CallbackSkill : public SkillImplementation
+    {
+    public:
+        Status execute(const aron::data::DictPtr&, const CallbackT&) override;
     };
 
     /**
diff --git a/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.cpp b/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.cpp
index dbeb06e78..a11304d70 100644
--- a/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.cpp
+++ b/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.cpp
@@ -30,10 +30,6 @@
 #include <ArmarXCore/core/time/TimeUtil.h>
 #include <ArmarXCore/core/logging/Logging.h>
 
-
-#include <RobotAPI/libraries/armem/core/error.h>
-#include <RobotAPI/libraries/armem/server/MemoryRemoteGui.h>
-
 #include <RobotAPI/libraries/armem/core/error.h>
 #include <RobotAPI/libraries/armem/core/wm/memory_definitions.h>
 #include <RobotAPI/libraries/armem/server/wm/memory_definitions.h>
@@ -44,12 +40,12 @@ namespace armarx
 {
 
     SkillsMemory::SkillsMemory():
-        LightweightRemoteGuiComponentPluginUser(),
         ReadWritePluginUser(),
         StatechartListenerComponentPluginUser(),
-        SkillObserverComponentPluginUser(),
+        SkillManagerComponentPluginUser(),
         statechartListenerProviderSegment(iceAdapter()),
         executableSkillCoreSegment(iceAdapter()),
+        skillEventCoreSegment(iceAdapter()),
         skillExecutionRequestCoreSegment(iceAdapter())
     {
     }
@@ -64,7 +60,7 @@ namespace armarx
         executableSkillCoreSegment.defineProperties(defs, prefix + "executableskill.");
         skillExecutionRequestCoreSegment.defineProperties(defs, prefix + "executionrequest.");
 
-        setMemoryName("Skill");
+        setMemoryName(MemoryName);
         return defs;
     }
 
@@ -80,13 +76,12 @@ namespace armarx
         statechartListenerProviderSegment.init();
         executableSkillCoreSegment.init();
         skillExecutionRequestCoreSegment.init();
+        skillEventCoreSegment.init();
     }
 
 
     void SkillsMemory::onConnectComponent()
     {
-        createRemoteGuiTab();
-        RemoteGui_startRunningTask();
     }
 
 
@@ -100,20 +95,15 @@ namespace armarx
     {
     }
 
-    armem::data::AddSegmentsResult SkillsMemory::addSegments(const armem::data::AddSegmentsInput& input, const Ice::Current&)
-    {
-        // This function is overloaded to trigger the remote gui rebuild.
-        armem::data::AddSegmentsResult result = ReadWritePluginUser::addSegments(input, false);
-        tab.rebuild = true;
-        return result;
-    }
-
 
     armem::data::CommitResult SkillsMemory::commit(const armem::data::Commit& commit, const Ice::Current&)
     {
-        // This function is overloaded to trigger the remote gui rebuild and to check for skill executions
+        // This function is overloaded to check for skill executions
+        // First pass arg to parent func to ensure that data is written into memory and that clients are notified
         armem::data::CommitResult result = ReadWritePluginUser::commit(commit);
 
+        auto myPrx = getProxy<skills::SkillManagerInterfacePrx>(getName());
+
         for (const auto& up : commit.updates)
         {
             if (up.entityID.coreSegmentName == skills::segment::SkillExecutionRequestCoreSegment::CoreSegmentName)
@@ -122,8 +112,7 @@ namespace armarx
                 {
                     ARMARX_CHECK_NOT_NULL(instance);
 
-                    auto aron = aron::data::Variant::FromAronDTO(instance);
-                    auto dict = aron::data::Dict::DynamicCastAndCheck(aron);
+                    auto dict = std::make_shared<aron::data::Dict>(instance);
 
                     // we got a skill execution request
                     skills::arondto::SkillExecutionRequest request;
@@ -131,18 +120,17 @@ namespace armarx
 
                     auto params = aron::data::Dict::DynamicCastAndCheck(dict->at("params")); // ToDo remov and add to request
 
-                    executableSkillCoreSegment.directlyExecuteSkill(request, params);
+                    executableSkillCoreSegment.directlyExecuteSkill(request, myPrx, params);
                 }
             }
         }
 
-        tab.rebuild = true;
         return result;
     }
 
     void SkillsMemory::addProvider(const std::string& skillProviderName, const skills::SkillProviderInterfacePrx& provider, const Ice::Current &current)
     {
-        SkillObserverComponentPluginUser::addProvider(skillProviderName, provider, current);
+        SkillManagerComponentPluginUser::addProvider(skillProviderName, provider, current);
 
         executableSkillCoreSegment.addSkillProvider(skillProviderName, provider);
     }
@@ -151,7 +139,7 @@ namespace armarx
     {
         executableSkillCoreSegment.removeSkillProvider(skillProviderName);
 
-        SkillObserverComponentPluginUser::removeProvider(skillProviderName, current);
+        SkillManagerComponentPluginUser::removeProvider(skillProviderName, current);
     }
 
     void SkillsMemory::executeSkill(const std::string& skillProviderName, const skills::SkillParametrization& params, const Ice::Current &current)
@@ -163,49 +151,86 @@ namespace armarx
         skills::arondto::SkillExecutionRequest request;
         request.clientId = "";
         request.providerName = skillProviderName;
-        request.skillName = params.name;
+        request.skillName = params.skillName;
 
         auto aron = request.toAron();
-        aron->addElement("params", aron::data::Variant::FromAronDTO(params.params));
 
+        aron::data::DictPtr aron_params = nullptr;
+        if (params.params) aron_params = std::make_shared<aron::data::Dict>(params.params);
+
+        aron->addElement("params", aron_params); // todo add as any type
+
+        armem::MemoryID skillExecutionMemID = skillExecutionRequestCoreSegment.getCoreSegment().id();
+        skillExecutionMemID.providerSegmentName = request.providerName;
+        skillExecutionMemID.entityName = request.skillName;
+
+        entityUpdate.entityID = skillExecutionMemID;
         entityUpdate.instancesData = { aron };
         entityUpdate.confidence = 1.0;
         entityUpdate.timeCreated = armem::Time::now();
 
-        iceAdapter().commit(comm); // commit and notify
+        armem::data::Commit iceCommit;
+        armarx::armem::toIce(iceCommit, comm);
+        commit(iceCommit, current); // commit and notify
     }
 
-    void SkillsMemory::reportStatechartTransitionWithParameters(const ProfilerStatechartTransitionWithParameters& x, const Ice::Current&)
+    void SkillsMemory::updateStatusForSkill(const std::string& providerName, const skills::SkillStatus& statusUpdate, const Ice::Current &current)
     {
-        statechartListenerProviderSegment.reportStatechartTransitionWithParameters(x);
-    }
+        // add update for skill to memory
+        static std::map<armarx::skills::Execution::Status, std::string> ExecutionStatus2String = {
+            {armarx::skills::Execution::Status::Idle, "Idle"},
+            {armarx::skills::Execution::Status::Scheduled, "Scheduled"},
+            {armarx::skills::Execution::Status::Running, "Running"},
+            {armarx::skills::Execution::Status::RunningButWaitingForDependencies, "RunningButWaitingForDependencies"},
+            {armarx::skills::Execution::Status::Aborted, "Aborted"},
+            {armarx::skills::Execution::Status::Failed, "Failed"},
+            {armarx::skills::Execution::Status::Succeeded, "Succeeded"}
+        };
 
-    void SkillsMemory::reportStatechartTransitionWithParametersList(const ProfilerStatechartTransitionWithParametersList& x, const Ice::Current&)
-    {
-        statechartListenerProviderSegment.reportStatechartTransitionWithParametersList(x);
-    }
+        // create commit about new update
+        armarx::skills::arondto::SkillExecutionEvent event;
+        event.providerName = providerName;
+        event.skillName = statusUpdate.usedParameterization.skillName;
+        event.status = ExecutionStatus2String.at(statusUpdate.status);
 
+        aron::data::DictPtr aron_params = nullptr;
+        if (statusUpdate.usedParameterization.params) aron_params = std::make_shared<aron::data::Dict>(statusUpdate.usedParameterization.params);
 
+        aron::data::DictPtr aron_result = nullptr;
+        if (statusUpdate.returnValue) aron_result = std::make_shared<aron::data::Dict>(statusUpdate.returnValue);
 
-    void SkillsMemory::createRemoteGuiTab()
-    {
-        using namespace armarx::RemoteGui::Client;
+        armem::MemoryID commitId = skillEventCoreSegment.getCoreSegment().id();
+        commitId.providerSegmentName = event.providerName;
+        commitId.entityName = event.skillName;
 
-        {
-            // Core segments are locked by MemoryRemoteGui.
-            tab.memoryGroup = armem::server::MemoryRemoteGui().makeGroupBox(workingMemory());
-        }
+        auto aron = event.toAron();
+        aron->addElement("result", aron_result);
+        aron->addElement("params", aron_params);
 
-        VBoxLayout root = {tab.memoryGroup, VSpacer()};
-        RemoteGui_createTab(getName(), root, &tab);
+        armem::Commit comm;
+        auto& entityUpdate = comm.add();
+        entityUpdate.confidence = 1.0;
+        entityUpdate.timeCreated = armem::Time::now();
+        entityUpdate.instancesData = { aron };
+        entityUpdate.entityID = commitId;
+
+        armem::data::Commit iceCommit;
+        armarx::armem::toIce(iceCommit, comm);
+        commit(iceCommit, current); // commit and notify
     }
 
 
-    void SkillsMemory::RemoteGui_update()
+
+    /*
+     * Statechart stuff
+     */
+    void SkillsMemory::reportStatechartTransitionWithParameters(const ProfilerStatechartTransitionWithParameters& x, const Ice::Current&)
     {
-        if (tab.rebuild.exchange(false))
-        {
-            createRemoteGuiTab();
-        }
+        statechartListenerProviderSegment.reportStatechartTransitionWithParameters(x);
+    }
+
+    void SkillsMemory::reportStatechartTransitionWithParametersList(const ProfilerStatechartTransitionWithParametersList& x, const Ice::Current&)
+    {
+        statechartListenerProviderSegment.reportStatechartTransitionWithParametersList(x);
     }
 }
diff --git a/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.h b/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.h
index cc1f95b9b..42e19e753 100644
--- a/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.h
+++ b/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.h
@@ -29,11 +29,9 @@
 #include <ArmarXCore/interface/core/Profiler.h>
 #include <ArmarXCore/observers/ObserverObjectFactories.h>
 
-#include <ArmarXGui/libraries/ArmarXGuiComponentPlugins/LightweightRemoteGuiComponentPlugin.h>
-
 #include <RobotAPI/interface/skills/SkillMemoryInterface.h>
 
-#include <RobotAPI/libraries/armem_skills/server/SkillObserverComponentPlugin.h>
+#include <RobotAPI/libraries/armem_skills/server/SkillManagerComponentPlugin.h>
 #include <RobotAPI/libraries/armem_skills/server/StatechartListenerComponentPlugin.h>
 #include <RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.h>
 
@@ -41,6 +39,7 @@
 #include <RobotAPI/libraries/armem_skills/server/segment/StatechartListenerSegment.h>
 #include <RobotAPI/libraries/armem_skills/server/segment/ExecutableSkillLibrarySegment.h>
 #include <RobotAPI/libraries/armem_skills/server/segment/SkillExecutionRequestSegment.h>
+#include <RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.h>
 
 namespace armarx
 {
@@ -58,10 +57,9 @@ namespace armarx
     class SkillsMemory :
         virtual public armarx::Component,
         virtual public skills::SkillMemoryInterface,
-        virtual public LightweightRemoteGuiComponentPluginUser,
         virtual public armem::server::ReadWritePluginUser,
         virtual public StatechartListenerComponentPluginUser,
-        virtual public SkillObserverComponentPluginUser
+        virtual public SkillManagerComponentPluginUser
     {
     public:
 
@@ -74,20 +72,15 @@ namespace armarx
         void reportStatechartTransitionWithParameters(const ProfilerStatechartTransitionWithParameters&, const Ice::Current&) override;
         void reportStatechartTransitionWithParametersList(const ProfilerStatechartTransitionWithParametersList&, const Ice::Current&) override;
 
-        // Override SkillObserver to add memory functions
+        // Override SkillManager to add memory functions
         void addProvider(const std::string&, const skills::SkillProviderInterfacePrx& provider, const Ice::Current &current) override;
         void removeProvider(const std::string&, const Ice::Current &current) override;
         void executeSkill(const std::string&, const skills::SkillParametrization& params, const Ice::Current &current) override;
+        void updateStatusForSkill(const std::string& providerName, const skills::SkillStatus& statusUpdate, const Ice::Current &current) override;
 
         // WritingInterface interface
-        armem::data::AddSegmentsResult addSegments(const armem::data::AddSegmentsInput& input, const Ice::Current&) override;
         armem::data::CommitResult commit(const armem::data::Commit& commit, const Ice::Current&) override;
 
-
-        // LightweightRemoteGuiComponentPluginUser interface
-        void createRemoteGuiTab();
-        void RemoteGui_update() override;
-
     protected:
 
         /// @see armarx::ManagedIceObject::onInitComponent()
@@ -108,6 +101,8 @@ namespace armarx
 
     private:
 
+        static constexpr const char* MemoryName = "Skill";
+
         struct Properties
         {
         };
@@ -115,13 +110,7 @@ namespace armarx
 
         skills::segment::StatechartListenerProviderSegment statechartListenerProviderSegment;
         skills::segment::ExecutableSkillLibraryCoreSegment executableSkillCoreSegment;
+        skills::segment::SkillEventCoreSegment skillEventCoreSegment;
         skills::segment::SkillExecutionRequestCoreSegment skillExecutionRequestCoreSegment;
-
-        struct RemoteGuiTab : RemoteGui::Client::Tab
-        {
-            std::atomic_bool rebuild = false;
-            RemoteGui::Client::GroupBox memoryGroup;
-        };
-        RemoteGuiTab tab;
     };
 }
diff --git a/source/RobotAPI/gui-plugins/CMakeLists.txt b/source/RobotAPI/gui-plugins/CMakeLists.txt
index d61010d07..3f50debe2 100644
--- a/source/RobotAPI/gui-plugins/CMakeLists.txt
+++ b/source/RobotAPI/gui-plugins/CMakeLists.txt
@@ -18,7 +18,7 @@ add_subdirectory(ObjectPoseGui)
 add_subdirectory(ArMemMemoryViewer)
 add_subdirectory(ArVizDrawerGui)
 add_subdirectory(FTSensorCalibrationGui)
-add_subdirectory(SkillObserverMonitor)
+add_subdirectory(SkillManagerPlugin)
 add_subdirectory(GraspCandidateViewer)
 add_subdirectory(BoxToGraspCandidates)
 
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/CMakeLists.txt b/source/RobotAPI/gui-plugins/SkillManagerPlugin/CMakeLists.txt
new file mode 100644
index 000000000..445d668cf
--- /dev/null
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/CMakeLists.txt
@@ -0,0 +1,16 @@
+set(LIB_NAME "SkillManagerMonitorGuiPlugin")
+armarx_set_target("${LIB_NAME}")
+
+armarx_build_if(ArmarXGui_FOUND "ArmarXGui not available")
+
+# do not rename this variable, it is used in armarx_gui_library()...
+set(SOURCES SkillManagerMonitorWidgetController.cpp)
+set(HEADERS SkillManagerMonitorWidgetController.h)
+set(GUI_UIS SkillManagerMonitorWidget.ui)
+
+# Add more libraries you depend on here, e.g. ${QT_LIBRARIES}.
+set(COMPONENT_LIBS RobotAPIInterfaces aron aronjsonconverter SimpleConfigDialog)
+
+if(ArmarXGui_FOUND)
+    armarx_gui_plugin("${LIB_NAME}" "${SOURCES}" "" "${GUI_UIS}" "" "${COMPONENT_LIBS}")
+endif()
diff --git a/source/RobotAPI/gui-plugins/SkillObserverMonitor/SkillObserverMonitorWidget.ui b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidget.ui
similarity index 60%
rename from source/RobotAPI/gui-plugins/SkillObserverMonitor/SkillObserverMonitorWidget.ui
rename to source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidget.ui
index 16ded1c1b..258061d25 100644
--- a/source/RobotAPI/gui-plugins/SkillObserverMonitor/SkillObserverMonitorWidget.ui
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidget.ui
@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <ui version="4.0">
- <class>SkillObserverMonitorWidget</class>
- <widget class="QWidget" name="SkillObserverMonitorWidget">
+ <class>SkillManagerMonitorWidget</class>
+ <widget class="QWidget" name="SkillManagerMonitorWidget">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>1148</width>
-    <height>859</height>
+    <width>1015</width>
+    <height>498</height>
    </rect>
   </property>
   <property name="windowTitle">
-   <string>SkillObserverMonitorWidget</string>
+   <string>SkillManagerMonitorWidget</string>
   </property>
   <layout class="QVBoxLayout" name="verticalLayout">
    <item>
@@ -19,25 +19,35 @@
      <property name="orientation">
       <enum>Qt::Horizontal</enum>
      </property>
-     <widget class="QWidget" name="widget" native="true">
+     <widget class="QGroupBox" name="groupBoxSkills">
+      <property name="title">
+       <string>Manager</string>
+      </property>
       <layout class="QGridLayout" name="gridLayout">
+       <item row="0" column="0">
+        <widget class="QPushButton" name="pushButtonRefreshProvidedSkills">
+         <property name="text">
+          <string>Refresh</string>
+         </property>
+        </widget>
+       </item>
        <item row="1" column="0">
         <widget class="QTreeWidget" name="treeWidgetSkills">
-         <attribute name="headerVisible">
-          <bool>false</bool>
-         </attribute>
          <column>
           <property name="text">
-           <string notr="true">1</string>
+           <string>Skill</string>
+          </property>
+         </column>
+         <column>
+          <property name="text">
+           <string>HasType</string>
+          </property>
+         </column>
+         <column>
+          <property name="text">
+           <string>State</string>
           </property>
          </column>
-        </widget>
-       </item>
-       <item row="0" column="0">
-        <widget class="QPushButton" name="pushButtonRefreshProvidedSkills">
-         <property name="text">
-          <string>Refresh</string>
-         </property>
         </widget>
        </item>
       </layout>
@@ -47,7 +57,40 @@
        <string>Skill Details</string>
       </property>
       <layout class="QGridLayout" name="gridLayout_2">
-       <item row="3" column="0">
+       <item row="5" column="0">
+        <widget class="QPushButton" name="pushButtonStopSkill">
+         <property name="text">
+          <string>Stop</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="0">
+        <widget class="QPushButton" name="pushButtonExecuteSkill">
+         <property name="text">
+          <string>Execute</string>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="0">
+        <widget class="QTreeWidget" name="treeWidgetSkillDetails">
+         <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="6" column="0">
         <spacer name="verticalSpacer">
          <property name="orientation">
           <enum>Qt::Vertical</enum>
@@ -60,20 +103,6 @@
          </property>
         </spacer>
        </item>
-       <item row="1" column="0">
-        <widget class="QPushButton" name="pushButtonStopSkill">
-         <property name="text">
-          <string>Stop</string>
-         </property>
-        </widget>
-       </item>
-       <item row="0" column="0">
-        <widget class="QPushButton" name="pushButtonStartSkill">
-         <property name="text">
-          <string>Start</string>
-         </property>
-        </widget>
-       </item>
       </layout>
      </widget>
     </widget>
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp
new file mode 100644
index 000000000..2405e4561
--- /dev/null
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp
@@ -0,0 +1,607 @@
+/*
+ * 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 <ArmarXCore/util/CPPUtility/Iterator.h>
+
+#include "SkillManagerMonitorWidgetController.h"
+
+// debug
+#include <RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.h>
+
+//config
+namespace armarx
+{
+    QPointer<QDialog> SkillManagerMonitorWidgetController::getConfigDialog(QWidget* parent)
+    {
+        if (!dialog)
+        {
+            dialog = new SimpleConfigDialog(parent);
+            dialog->addProxyFinder<skills::SkillManagerInterfacePrx>("SkillManager", "", "Skill*");
+        }
+        return qobject_cast<SimpleConfigDialog*>(dialog);
+    }
+    void SkillManagerMonitorWidgetController::configured()
+    {
+        observerName = dialog->getProxyName("SkillManager");
+    }
+    void SkillManagerMonitorWidgetController::loadSettings(QSettings* settings)
+    {
+        observerName = settings->value("SkillManager", "SkillManager").toString().toStdString();
+    }
+    void SkillManagerMonitorWidgetController::saveSettings(QSettings* settings)
+    {
+        settings->setValue("SkillManager", QString::fromStdString(observerName));
+    }
+}
+
+//visitors
+namespace armarx
+{
+
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::createSimpleTreeViewWidget(Input& i)
+    {
+        ARMARX_CHECK_NOT_NULL(i);
+        ARMARX_CHECK_NOT_NULL(parentItem);
+
+        auto key = i->getPath().getLastElement();
+        createdQWidgetItem = new QTreeWidgetItem(parentItem);
+        createdQWidgetItem->setText(0, QString::fromStdString(key));
+        createdQWidgetItem->setText(2, QString::fromStdString(i->getShortName()));
+        createdQWidgetItem->setFlags(createdQWidgetItem->flags() | Qt::ItemIsEditable);
+    }
+
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::ObjectPtr& i)
+    {
+        ARMARX_CHECK_NOT_NULL(i);
+        ARMARX_CHECK_NOT_NULL(parentItem);
+
+        auto key = i->getObjectName();
+        if (i->getPath().hasElement())
+        {
+            key = i->getPath().getLastElement();
+        }
+
+        createdQWidgetItem = new QTreeWidgetItem(parentItem);
+        createdQWidgetItem->setText(0, QString::fromStdString(key));
+
+        for (const auto& [key, value] : i->getMemberTypes())
+        {
+            SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor v(createdQWidgetItem);
+            aron::type::visit(v, value);
+
+            if (v.createdQWidgetItem)
+            {
+                createdQWidgetItem->addChild(v.createdQWidgetItem);
+            }
+        }
+    }
+
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::DictPtr& i)
+    { createSimpleTreeViewWidget(i); }
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::PairPtr& i)
+    { createSimpleTreeViewWidget(i); }
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::TuplePtr& i)
+    { createSimpleTreeViewWidget(i); }
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::ListPtr& i)
+    { createSimpleTreeViewWidget(i); }
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::NDArrayPtr& i)
+    { createSimpleTreeViewWidget(i); }
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::MatrixPtr& i)
+    { createSimpleTreeViewWidget(i); }
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::QuaternionPtr& i)
+    { createSimpleTreeViewWidget(i); }
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::PositionPtr& i)
+    { createSimpleTreeViewWidget(i); }
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::OrientationPtr& i)
+    { createSimpleTreeViewWidget(i); }
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::PosePtr& i)
+    { createSimpleTreeViewWidget(i); }
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::ImagePtr& i)
+    { createSimpleTreeViewWidget(i); }
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::PointCloudPtr& i)
+    { createSimpleTreeViewWidget(i); }
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::IntEnumPtr& i)
+    { createSimpleTreeViewWidget(i); }
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::IntPtr& i)
+    { createSimpleTreeViewWidget(i); }
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::LongPtr& i)
+    { createSimpleTreeViewWidget(i); }
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::FloatPtr& i)
+    { createSimpleTreeViewWidget(i); }
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::DoublePtr& i)
+    { createSimpleTreeViewWidget(i); }
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::BoolPtr& i)
+    { createSimpleTreeViewWidget(i); }
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::StringPtr& i)
+    { createSimpleTreeViewWidget(i); }
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitAronVariant(const aron::type::TimePtr& i)
+    { createSimpleTreeViewWidget(i); }
+
+    void SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor::visitUnknown(Input&)
+    {
+        ARMARX_WARNING_S << "Received an unknown type when trying to create a tree view widget for a skill argument type.";
+    }
+
+
+
+
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::ObjectPtr& i)
+    {
+        auto createdAronDict = std::make_shared<aron::data::Dict>();
+        createdAron = createdAronDict;
+        QTreeWidgetItem* el = parentItem->child(index);
+
+        unsigned int x = 0;
+        for (const auto& [key, value] : i->getMemberTypes())
+        {
+            SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor v(el, x++);
+            aron::type::visit(v, value);
+
+            if (v.createdAron)
+            {
+                createdAronDict->addElement(key, v.createdAron);
+            }
+        }
+    }
+
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::DictPtr& i)
+    {
+        // TODO
+    }
+
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::PairPtr& i)
+    {
+        // TODO
+    }
+
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::TuplePtr& i)
+    {
+        // TODO
+    }
+
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::ListPtr& i)
+    {
+        // TODO
+    }
+
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::NDArrayPtr& i)
+    {
+        // TODO
+    }
+
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::MatrixPtr& i)
+    {
+        // TODO
+    }
+
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::QuaternionPtr& i)
+    {
+        // TODO
+    }
+
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::PositionPtr& i)
+    {
+        // TODO
+    }
+
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::OrientationPtr& i)
+    {
+        // TODO
+    }
+
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::PosePtr& i)
+    {
+        // TODO
+    }
+
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::ImagePtr& i)
+    {
+        // TODO
+    }
+
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::PointCloudPtr& i)
+    {
+        // TODO
+    }
+
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::IntEnumPtr& i)
+    {
+        // TODO
+    }
+
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::IntPtr& i)
+    {
+        auto createdAronInt = std::make_shared<aron::data::Int>();
+        createdAron = createdAronInt;
+        QTreeWidgetItem* el = parentItem->child(index);
+
+        std::string str = el->text(1).toStdString();
+        if (str.empty())
+        {
+            createdAronInt->setValue(0);
+            return;
+        }
+
+        int val = std::stoi(str);
+        createdAronInt->setValue(val);
+    }
+
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::LongPtr& i)
+    {
+        auto createdAronLong = std::make_shared<aron::data::Long>();
+        createdAron = createdAronLong;
+        QTreeWidgetItem* el = parentItem->child(index);
+
+        std::string str = el->text(1).toStdString();
+        if (str.empty())
+        {
+            createdAronLong->setValue(0);
+            return;
+        }
+
+        long val = std::stol(str);
+        createdAronLong->setValue(val);
+    }
+
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::FloatPtr& i)
+    {
+        auto createdAronFloat = std::make_shared<aron::data::Float>();
+        createdAron = createdAronFloat;
+        QTreeWidgetItem* el = parentItem->child(index);
+
+        std::string str = el->text(1).toStdString();
+        if (str.empty())
+        {
+            createdAronFloat->setValue(0.0);
+            return;
+        }
+
+        float val = std::stof(str);
+        createdAronFloat->setValue(val);
+    }
+
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::DoublePtr& i)
+    {
+        auto createdAronDouble = std::make_shared<aron::data::Double>();
+        createdAron = createdAronDouble;
+        QTreeWidgetItem* el = parentItem->child(index);
+
+        std::string str = el->text(1).toStdString();
+        if (str.empty())
+        {
+            createdAronDouble->setValue(0.0);
+            return;
+        }
+
+        float val = std::stod(str);
+        createdAronDouble->setValue(val);
+    }
+
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::BoolPtr& i)
+    {
+        auto createdAronBool = std::make_shared<aron::data::Bool>();
+        createdAron = createdAronBool;
+        QTreeWidgetItem* el = parentItem->child(index);
+
+        std::string str = el->text(1).toStdString();
+        if (str.empty() || str == "false" || str == "no")
+        {
+            createdAronBool->setValue(false);
+            return;
+        }
+
+        if (str == "true" || str == "yes")
+        {
+            createdAronBool->setValue(true);
+            return;
+        }
+
+        bool val = std::stoi(str);
+        createdAronBool->setValue(val);
+    }
+
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::StringPtr& i)
+    {
+        auto createdAronString = std::make_shared<aron::data::String>();
+        createdAron = createdAronString;
+        QTreeWidgetItem* el = parentItem->child(index);
+
+        std::string str = el->text(1).toStdString();
+        createdAronString->setValue(str);
+    }
+
+    void
+    SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitAronVariant(const aron::type::TimePtr& i)
+    {
+        auto l = std::make_shared<aron::type::Long>();
+        visitLong(l);
+    }
+
+    void SkillManagerMonitorWidgetController::SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor::visitUnknown(Input&)
+    {
+        ARMARX_WARNING_S << "Received an unknown type when trying to convert a skill argument type to an aron data object.";
+    }
+}
+
+namespace armarx
+{
+    SkillManagerMonitorWidgetController::SkillManagerMonitorWidgetController()
+    {
+        widget.setupUi(getWidget());
+        connect(widget.pushButtonRefreshProvidedSkills, &QPushButton::clicked,
+                this, &SkillManagerMonitorWidgetController::refreshSkills);
+
+        connect(widget.pushButtonExecuteSkill, &QPushButton::clicked,
+                this, &SkillManagerMonitorWidgetController::executeSkill);
+        connect(widget.pushButtonStopSkill, &QPushButton::clicked,
+                this, &SkillManagerMonitorWidgetController::stopSkill);
+
+        connect(widget.treeWidgetSkills, &QTreeWidget::currentItemChanged,
+                this, &SkillManagerMonitorWidgetController::skillSelectionChanged);
+
+        connect(widget.treeWidgetSkillDetails, &QTreeWidget::itemDoubleClicked,
+                this, &SkillManagerMonitorWidgetController::onTreeWidgetItemDoubleClicked);
+    }
+
+    SkillManagerMonitorWidgetController::~SkillManagerMonitorWidgetController()
+    {
+
+    }
+
+    void SkillManagerMonitorWidgetController::onInitComponent()
+    {
+        usingProxy(observerName);
+    }
+
+
+    void SkillManagerMonitorWidgetController::onConnectComponent()
+    { getProxy(observer, observerName);
+        widget.groupBoxSkills->setTitle(QString::fromStdString(observerName));
+        widget.treeWidgetSkillDetails->setEditTriggers(QAbstractItemView::EditTrigger::NoEditTriggers);
+    }
+
+    void SkillManagerMonitorWidgetController::onDisconnectComponent()
+    {
+        // reset all
+        skills.clear();
+        widget.treeWidgetSkills->clear();
+        widget.treeWidgetSkillDetails->clear();
+        skillsArgumentsTreeWidgetItem = nullptr;
+        selectedSkill.providerName = "";
+        selectedSkill.skillName = "";
+    }
+
+    void SkillManagerMonitorWidgetController::refreshSkills()
+    {
+        // get all skills
+        skills.clear();
+        for (const auto& [providerName, provider] : observer->getSkillProviders())
+        {
+            SkillProviderData providerData;
+            providerData.providerName = providerName;
+            providerData.skillDescriptions = provider->getSkills();
+            skills.insert(std::make_pair(providerName, providerData));
+        }
+
+        // put skills into tree view
+        widget.treeWidgetSkills->clear();
+        for (const auto& [providerName, provider] : skills)
+        {
+            auto it = new QTreeWidgetItem(widget.treeWidgetSkills);
+            it->setText(0, QString::fromStdString(providerName));
+            for (const auto& [name, sk] : provider.skillDescriptions)
+            {
+                auto itsk = new QTreeWidgetItem(it);
+                it->addChild(itsk);
+                itsk->setText(0, QString::fromStdString(name));
+            }
+        }
+    }
+
+    void SkillManagerMonitorWidgetController::executeSkill()
+    {
+        if (selectedSkill.providerName.empty() or selectedSkill.skillName.empty())
+        {
+            return;
+        }
+
+        const auto& prv = skills.at(selectedSkill.providerName);
+        if (!prv.skillDescriptions.count(selectedSkill.skillName))
+        {
+            return;
+        }
+
+        const auto& skillDescription = prv.skillDescriptions.at(selectedSkill.skillName);
+        skills::SkillParametrization params;
+        params.skillName = selectedSkill.skillName;
+
+        // create argument aron (if there is an accepted type set)
+        if (skillsArgumentsTreeWidgetItem)
+        {
+            auto aron_accepted_type = std::make_shared<aron::type::Object>(*skillDescription.acceptedType);
+
+            SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor v(skillsArgumentsTreeWidgetItem, 0);
+            aron::type::visit(v, aron_accepted_type);
+
+            auto aron_args = aron::data::Dict::DynamicCastAndCheck(v.createdAron);
+            params.params = aron_args->toAronDictPtr();
+        }
+
+        ARMARX_INFO << "Executing skill from GUI: " << selectedSkill.providerName << "/" << selectedSkill.skillName;
+        observer->executeSkill(selectedSkill.providerName, params);
+    }
+
+    void SkillManagerMonitorWidgetController::stopSkill()
+    {
+        if (selectedSkill.providerName.empty() or selectedSkill.skillName.empty())
+        {
+            return;
+        }
+
+        const auto& prv = skills.at(selectedSkill.providerName);
+        if (!prv.skillDescriptions.count(selectedSkill.skillName))
+        {
+            return;
+        }
+
+        // TODO
+        ARMARX_INFO << "Stopping skill from GUI: " << selectedSkill.providerName << "/" << selectedSkill.skillName;
+        //observer->abortSkill(skills.selectedSkill);
+    }
+
+    void SkillManagerMonitorWidgetController::skillSelectionChanged(QTreeWidgetItem* current, QTreeWidgetItem*)
+    {
+        widget.groupBoxSkillDetails->setEnabled(false);
+
+        if (!current)
+        {
+            // gui has died?
+            return;
+        }
+
+        if (!current->parent())
+        {
+            return;
+        }
+
+        SelectedSkill newSelectedSkill;
+
+        // setup selected skill
+        newSelectedSkill.providerName = current->parent()->text(0).toStdString();
+        newSelectedSkill.skillName = current->text(0).toStdString();
+
+        // setup groupBox
+        widget.groupBoxSkillDetails->setTitle(QString::fromStdString(newSelectedSkill.providerName + "/" + newSelectedSkill.skillName));
+        widget.groupBoxSkillDetails->setEnabled(true);
+
+        if (newSelectedSkill.providerName == selectedSkill.providerName and newSelectedSkill.skillName == selectedSkill.skillName)
+        {
+            return;
+        }
+
+        selectedSkill = newSelectedSkill;
+
+        // setup table view
+        widget.treeWidgetSkillDetails->clear();
+        skillsArgumentsTreeWidgetItem = nullptr;
+
+        auto skillDesc = skills.at(selectedSkill.providerName).skillDescriptions.at(selectedSkill.skillName);
+
+        {
+            auto it = new QTreeWidgetItem(widget.treeWidgetSkillDetails,
+                                          {QString::fromStdString("Name"), QString::fromStdString(skillDesc.name)});
+            widget.treeWidgetSkillDetails->addTopLevelItem(it);
+        }
+
+        {
+            auto it = new QTreeWidgetItem(widget.treeWidgetSkillDetails,
+                                          {QString::fromStdString("Robot"), QString::fromStdString(simox::alg::join(skillDesc.robots, ", "))});
+            widget.treeWidgetSkillDetails->addTopLevelItem(it);
+        }
+
+        {
+            auto it = new QTreeWidgetItem(widget.treeWidgetSkillDetails,
+                                          {QString::fromStdString("Description"), QString::fromStdString(skillDesc.documentation)});
+            widget.treeWidgetSkillDetails->addTopLevelItem(it);
+        }
+
+        {
+            auto it = new QTreeWidgetItem(widget.treeWidgetSkillDetails,
+                                          {QString::fromStdString("Timeout"), QString::fromStdString(std::to_string(skillDesc.timeoutMs)) + " ms"});
+            widget.treeWidgetSkillDetails->addTopLevelItem(it);
+        }
+
+        if (skillDesc.acceptedType)
+        {
+            auto aron_args = std::make_shared<aron::type::Object>(*skillDesc.acceptedType);
+
+            skillsArgumentsTreeWidgetItem = new QTreeWidgetItem(widget.treeWidgetSkillDetails,
+                                          {QString::fromStdString("Arguments")});
+
+            SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor v(skillsArgumentsTreeWidgetItem);
+            aron::type::visit(v, aron_args);
+
+            if (v.createdQWidgetItem)
+            {
+                skillsArgumentsTreeWidgetItem->addChild(v.createdQWidgetItem);
+            }
+        }
+        else
+        {
+            auto it = new QTreeWidgetItem(widget.treeWidgetSkillDetails, {QString::fromStdString("No args")});
+            widget.treeWidgetSkillDetails->addTopLevelItem(it);
+        }
+    }
+
+    void SkillManagerMonitorWidgetController::onTreeWidgetItemDoubleClicked(QTreeWidgetItem * item, int column)
+    {
+        if (column == 1)
+        {
+            widget.treeWidgetSkillDetails->editItem(item, column);
+        }
+    }
+}
+
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h
new file mode 100644
index 000000000..48ace9548
--- /dev/null
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.h
@@ -0,0 +1,195 @@
+/*
+ * 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 <ArmarXCore/core/system/ImportExportComponent.h>
+
+#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h>
+#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXComponentWidgetController.h>
+#include <ArmarXGui/libraries/SimpleConfigDialog/SimpleConfigDialog.h>
+
+#include <RobotAPI/interface/skills/SkillMemoryInterface.h>
+
+#include <RobotAPI/gui-plugins/SkillManagerPlugin/ui_SkillManagerMonitorWidget.h>
+
+
+#include <RobotAPI/libraries/aron/core/type/variant/All.h>
+#include <RobotAPI/libraries/aron/core/data/variant/All.h>
+#include <RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.h>
+
+namespace armarx
+{
+    class ARMARXCOMPONENT_IMPORT_EXPORT
+        SkillManagerMonitorWidgetController:
+        public armarx::ArmarXComponentWidgetControllerTemplate < SkillManagerMonitorWidgetController >
+    {
+        Q_OBJECT
+
+    public:
+
+        // Convert aron type to tree widget
+        class SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor :
+                public armarx::aron::type::ConstVariantVisitor
+        {
+        public:
+            QTreeWidgetItem* parentItem;
+            QTreeWidgetItem* createdQWidgetItem;
+
+            SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor() = delete;
+            SkillManagerMonitorArgumentTreeViewWidgetCreatorVisitor(QTreeWidgetItem* i) :
+                parentItem(i)
+            {}
+
+            void createSimpleTreeViewWidget(Input& i);
+
+            void visitAronVariant(const aron::type::ObjectPtr&) override;
+            void visitAronVariant(const aron::type::DictPtr& i) override;
+            void visitAronVariant(const aron::type::PairPtr& i) override;
+            void visitAronVariant(const aron::type::TuplePtr& i) override;
+            void visitAronVariant(const aron::type::ListPtr& i) override;
+            void visitAronVariant(const aron::type::NDArrayPtr& i) override;
+            void visitAronVariant(const aron::type::MatrixPtr& i) override;
+            void visitAronVariant(const aron::type::QuaternionPtr& i) override;
+            void visitAronVariant(const aron::type::PositionPtr& i) override;
+            void visitAronVariant(const aron::type::OrientationPtr& i) override;
+            void visitAronVariant(const aron::type::PosePtr& i) override;
+            void visitAronVariant(const aron::type::ImagePtr& i) override;
+            void visitAronVariant(const aron::type::PointCloudPtr& i) override;
+            void visitAronVariant(const aron::type::IntEnumPtr& i) override;
+            void visitAronVariant(const aron::type::IntPtr& i) override;
+            void visitAronVariant(const aron::type::LongPtr& i) override;
+            void visitAronVariant(const aron::type::FloatPtr& i) override;
+            void visitAronVariant(const aron::type::DoublePtr& i) override;
+            void visitAronVariant(const aron::type::BoolPtr& i) override;
+            void visitAronVariant(const aron::type::StringPtr& i) override;
+            void visitAronVariant(const aron::type::TimePtr& i) override;
+            void visitUnknown(Input&) override;
+        };
+
+
+        // Conversion from TreeView to aron data
+        class SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor :
+                public armarx::aron::type::ConstVariantVisitor
+        {
+        public:
+            QTreeWidgetItem* parentItem;
+            int index;
+            aron::data::VariantPtr createdAron;
+
+            SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor() = delete;
+            SkillManagerMonitorArgumentTreeViewWidgetConverterVisitor(QTreeWidgetItem* i, int x) :
+                parentItem(i), index(x)
+            {}
+
+            void visitAronVariant(const aron::type::ObjectPtr&) override;
+            void visitAronVariant(const aron::type::DictPtr&) override;
+            void visitAronVariant(const aron::type::PairPtr&) override;
+            void visitAronVariant(const aron::type::TuplePtr&) override;
+            void visitAronVariant(const aron::type::ListPtr&) override;
+            void visitAronVariant(const aron::type::NDArrayPtr&) override;
+            void visitAronVariant(const aron::type::MatrixPtr&) override;
+            void visitAronVariant(const aron::type::QuaternionPtr&) override;
+            void visitAronVariant(const aron::type::PositionPtr&) override;
+            void visitAronVariant(const aron::type::OrientationPtr&) override;
+            void visitAronVariant(const aron::type::PosePtr&) override;
+            void visitAronVariant(const aron::type::ImagePtr&) override;
+            void visitAronVariant(const aron::type::PointCloudPtr&) override;
+            void visitAronVariant(const aron::type::IntEnumPtr&) override;
+            void visitAronVariant(const aron::type::IntPtr&) override;
+            void visitAronVariant(const aron::type::LongPtr&) override;
+            void visitAronVariant(const aron::type::FloatPtr&) override;
+            void visitAronVariant(const aron::type::DoublePtr&) override;
+            void visitAronVariant(const aron::type::BoolPtr&) override;
+            void visitAronVariant(const aron::type::StringPtr&) override;
+            void visitAronVariant(const aron::type::TimePtr&) override;
+            void visitUnknown(Input&) override;
+        };
+
+
+        /// Controller Constructor
+        explicit SkillManagerMonitorWidgetController();
+        /// Controller destructor
+        virtual ~SkillManagerMonitorWidgetController();
+
+        void loadSettings(QSettings* settings) override;
+        void saveSettings(QSettings* settings) override;
+        QPointer<QDialog> getConfigDialog(QWidget* parent) override;
+        void configured() override;
+
+        /**
+         * Returns the Widget name displayed in the ArmarXGui to create an
+         * instance of this class.
+         */
+        static QString GetWidgetName()
+        {
+            return "Skills.Manager";
+        }
+
+        void onInitComponent() override;
+        void onConnectComponent() override;
+        void onDisconnectComponent() override;
+
+    private slots:
+        void skillSelectionChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous);
+
+        void stopSkill();
+        void executeSkill();
+
+        void refreshSkills();
+
+        void onTreeWidgetItemDoubleClicked(QTreeWidgetItem * item, int column);
+
+    private:
+        /**
+         * Widget Form
+         */
+        Ui::SkillManagerMonitorWidget  widget;
+        QPointer<SimpleConfigDialog>    dialog;
+
+        std::string observerName = "SkillManager";
+        skills::SkillManagerInterfacePrx observer = nullptr;
+
+        struct SelectedSkill
+        {
+            std::string providerName;
+            std::string skillName;
+        };
+
+        struct SkillProviderData
+        {
+            std::string providerName;
+            skills::SkillDescriptionMap skillDescriptions;
+        };
+
+        // Data taken from observer
+        std::map<std::string, SkillProviderData> skills = {};
+
+        // User Input
+        SelectedSkill selectedSkill;
+
+        // Helper to get the treeWidgetItem easily
+        QTreeWidgetItem* skillsArgumentsTreeWidgetItem = nullptr;
+    };
+}
+
+
diff --git a/source/RobotAPI/gui-plugins/SkillObserverMonitor/CMakeLists.txt b/source/RobotAPI/gui-plugins/SkillObserverMonitor/CMakeLists.txt
deleted file mode 100644
index 8552f06fc..000000000
--- a/source/RobotAPI/gui-plugins/SkillObserverMonitor/CMakeLists.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-#set(LIB_NAME "SkillObserverMonitorGuiPlugin")
-#armarx_set_target("${LIB_NAME}")
-
-#armarx_build_if(ArmarXGui_FOUND "ArmarXGui not available")
-
-# do not rename this variable, it is used in armarx_gui_library()...
-#set(SOURCES SkillObserverMonitorWidgetController.cpp)
-#set(HEADERS SkillObserverMonitorWidgetController.h)
-#set(GUI_UIS SkillObserverMonitorWidget.ui)
-
-# Add more libraries you depend on here, e.g. ${QT_LIBRARIES}.
-#set(COMPONENT_LIBS RobotAPIInterfaces SimpleConfigDialog)
-
-#if(ArmarXGui_FOUND)
-#    armarx_gui_plugin("${LIB_NAME}" "${SOURCES}" "" "${GUI_UIS}" "" "${COMPONENT_LIBS}")
-#endif()
diff --git a/source/RobotAPI/gui-plugins/SkillObserverMonitor/SkillObserverMonitorWidgetController.cpp b/source/RobotAPI/gui-plugins/SkillObserverMonitor/SkillObserverMonitorWidgetController.cpp
deleted file mode 100644
index f2295a435..000000000
--- a/source/RobotAPI/gui-plugins/SkillObserverMonitor/SkillObserverMonitorWidgetController.cpp
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * 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::SkillObserverMonitorWidgetController
- * \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 <ArmarXCore/util/CPPUtility/Iterator.h>
-
-#include "SkillObserverMonitorWidgetController.h"
-
-//config
-namespace armarx
-{
-    /*QPointer<QDialog> SkillObserverMonitorWidgetController::getConfigDialog(QWidget* parent)
-    {
-        if (!dialog)
-        {
-            dialog = new SimpleConfigDialog(parent);
-            //dialog->addProxyFinder<skills::SkillObserverInterfacePrx>("SkillObserver", "", "Skill*");
-        }
-        return qobject_cast<SimpleConfigDialog*>(dialog);
-    }
-    void SkillObserverMonitorWidgetController::configured()
-    {
-        skills.observerName = dialog->getProxyName("SkillObserver");
-    }
-    void SkillObserverMonitorWidgetController::loadSettings(QSettings* settings)
-    {
-        skills.observerName = settings->value("SkillObserver", "SkillObserver").toString().toStdString();
-    }
-
-    void SkillObserverMonitorWidgetController::saveSettings(QSettings* settings)
-    {
-        settings->setValue("SkillObserver", QString::fromStdString(skills.observerName));
-    }
-}
-//other
-namespace armarx
-{
-    SkillObserverMonitorWidgetController::SkillObserverMonitorWidgetController()
-    {
-        widget.setupUi(getWidget());
-        connect(widget.pushButtonRefreshProvidedSkills, &QPushButton::clicked,
-                this, &SkillObserverMonitorWidgetController::refreshProvidedSkills);
-        connect(widget.pushButtonStartSkill, &QPushButton::clicked,
-                this, &SkillObserverMonitorWidgetController::startSkill);
-        connect(widget.pushButtonStopSkill, &QPushButton::clicked,
-                this, &SkillObserverMonitorWidgetController::stopSkill);
-        connect(widget.treeWidgetSkills, &QTreeWidget::currentItemChanged,
-                this, &SkillObserverMonitorWidgetController::skillSelectionChanged);
-    }
-
-
-    SkillObserverMonitorWidgetController::~SkillObserverMonitorWidgetController()
-    {
-
-    }
-
-    void SkillObserverMonitorWidgetController::onInitComponent()
-    {
-        usingProxy(skills.observerName);
-    }
-
-
-    void SkillObserverMonitorWidgetController::onConnectComponent()
-    {
-        //getProxy(skills.observer, skills.observerName);
-    }
-
-    void SkillObserverMonitorWidgetController::refreshProvidedSkills()
-    {
-        //skills.skills = skills.observer->getSkills();
-        skills.providerIndex.clear();
-        widget.treeWidgetSkills->clear();
-        for (const auto& [i, pr] : MakeIndexedContainer(skills.skills))
-        {
-            skills.providerIndex[pr.providerName] = i;
-            auto it = new QTreeWidgetItem(widget.treeWidgetSkills);
-            widget.treeWidgetSkills->addTopLevelItem(it);
-            it->setText(0, QString::fromStdString(pr.providerName));
-            for (const auto& [name, sk] : pr.skills)
-            {
-                auto itsk = new QTreeWidgetItem(it);
-                it->addChild(itsk);
-                itsk->setText(0, QString::fromStdString(name));
-            }
-        }
-    }
-
-    void SkillObserverMonitorWidgetController::startSkill()
-    {
-        if (skills.idxActiveProvider < 0 || skills.idxActiveProvider > static_cast<int>(skills.skills.size()))
-        {
-            return;
-        }
-        const auto& prv = skills.skills.at(skills.idxActiveProvider);
-        if (!prv.skills.count(skills.selectedSkill))
-        {
-            return;
-        }
-        skills::SkillParametrization param;
-        param.skillName = skills.selectedSkill;
-        prv.provider->executeSkill(param);
-    }
-
-    void SkillObserverMonitorWidgetController::stopSkill()
-    {
-        if (skills.idxActiveProvider < 0 || skills.idxActiveProvider > static_cast<int>(skills.skills.size()))
-        {
-            return;
-        }
-        const auto& prv = skills.skills.at(skills.idxActiveProvider);
-        if (!prv.skills.count(skills.selectedSkill))
-        {
-            return;
-        }
-        prv.provider->abortSkill(skills.selectedSkill);
-    }
-
-    void SkillObserverMonitorWidgetController::skillSelectionChanged(QTreeWidgetItem* current, QTreeWidgetItem*)
-    {
-        skills.idxActiveProvider = -1;
-        widget.groupBoxSkillDetails->setEnabled(false);
-
-        if (!current->parent())
-        {
-            return;
-        }
-        skills.idxActiveProvider = skills.providerIndex.at(current->parent()->text(0).toStdString());
-        skills.selectedSkill     = current->text(0).toStdString();
-        widget.groupBoxSkillDetails->setEnabled(true);
-    }*/
-}
-
diff --git a/source/RobotAPI/gui-plugins/SkillObserverMonitor/SkillObserverMonitorWidgetController.h b/source/RobotAPI/gui-plugins/SkillObserverMonitor/SkillObserverMonitorWidgetController.h
deleted file mode 100644
index bca23983f..000000000
--- a/source/RobotAPI/gui-plugins/SkillObserverMonitor/SkillObserverMonitorWidgetController.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * 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::SkillObserverMonitorWidgetController
- * @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 <ArmarXCore/core/system/ImportExportComponent.h>
-
-#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h>
-#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXComponentWidgetController.h>
-#include <ArmarXGui/libraries/SimpleConfigDialog/SimpleConfigDialog.h>
-
-#include <RobotAPI/interface/skills/SkillMemoryInterface.h>
-
-#include <RobotAPI/gui-plugins/SkillObserverMonitor/ui_SkillObserverMonitorWidget.h>
-
-namespace armarx
-{
-    /**
-    \page RobotAPI-GuiPlugins-SkillObserverMonitor SkillObserverMonitor
-    \brief The SkillObserverMonitor allows visualizing ...
-
-    \image html SkillObserverMonitor.png
-    The user can
-
-    API Documentation \ref SkillObserverMonitorWidgetController
-
-    \see SkillObserverMonitorGuiPlugin
-    */
-
-
-    /**
-     * \class SkillObserverMonitorGuiPlugin
-     * \ingroup ArmarXGuiPlugins
-     * \brief SkillObserverMonitorGuiPlugin brief description
-     *
-     * Detailed description
-     */
-
-    /**
-     * \class SkillObserverMonitorWidgetController
-     * \brief SkillObserverMonitorWidgetController brief one line description
-     *
-     * Detailed description
-     */
-    /*class ARMARXCOMPONENT_IMPORT_EXPORT
-        SkillObserverMonitorWidgetController:
-        public armarx::ArmarXComponentWidgetControllerTemplate < SkillObserverMonitorWidgetController >
-    {
-        Q_OBJECT
-
-    public:
-        /// Controller Constructor
-        explicit SkillObserverMonitorWidgetController();
-        /// Controller destructor
-        virtual ~SkillObserverMonitorWidgetController();
-
-        void loadSettings(QSettings* settings) override;
-        void saveSettings(QSettings* settings) override;
-        QPointer<QDialog> getConfigDialog(QWidget* parent) override;
-        void configured() override;*/
-
-        /**
-         * Returns the Widget name displayed in the ArmarXGui to create an
-         * instance of this class.
-         */
-        /*static QString GetWidgetName()
-        {
-            return "Skills.ObserverMonitor";
-        }
-
-        /// \see armarx::Component::onInitComponent()
-        void onInitComponent() override;
-
-        /// \see armarx::Component::onConnectComponent()
-        void onConnectComponent() override;
-
-    private slots:
-        void skillSelectionChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous);
-        void stopSkill();
-        void startSkill();
-        void refreshProvidedSkills();
-
-    private:*/
-        /**
-         * Widget Form
-         */
-        /*Ui::SkillObserverMonitorWidget  widget;
-        QPointer<SimpleConfigDialog>    dialog;
-        struct SkillData
-        {
-            std::string                         observerName;
-            //skills::SkillObserverInterfacePrx   observer;
-            skills::ProviderSkillsSeq           skills;
-            std::map<std::string, int>          providerIndex;
-            int                                 idxActiveProvider = -1;
-            std::string                         selectedSkill;
-        };
-        SkillData skills;
-    };*/
-}
-
-
diff --git a/source/RobotAPI/interface/CMakeLists.txt b/source/RobotAPI/interface/CMakeLists.txt
index 77cca5e95..638e9737b 100644
--- a/source/RobotAPI/interface/CMakeLists.txt
+++ b/source/RobotAPI/interface/CMakeLists.txt
@@ -137,7 +137,7 @@ set(SLICE_FILES
     components/ObstacleAvoidance/DSObstacleAvoidanceInterface.ice
     components/ObstacleAvoidance/DynamicObstacleManagerInterface.ice
 
-    skills/SkillObserverInterface.ice
+    skills/SkillManagerInterface.ice
     skills/StatechartListenerInterface.ice
     skills/SkillMemoryInterface.ice
     skills/SkillProviderInterface.ice
diff --git a/source/RobotAPI/interface/skills/SkillObserverInterface.ice b/source/RobotAPI/interface/skills/SkillManagerInterface.ice
similarity index 77%
rename from source/RobotAPI/interface/skills/SkillObserverInterface.ice
rename to source/RobotAPI/interface/skills/SkillManagerInterface.ice
index 81d6c4212..48c538cc6 100644
--- a/source/RobotAPI/interface/skills/SkillObserverInterface.ice
+++ b/source/RobotAPI/interface/skills/SkillManagerInterface.ice
@@ -13,7 +13,7 @@
  * 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::ArmarXObjects::SkillObserver
+ * @package    RobotAPI::ArmarXObjects::SkillManager
  * @author     Raphael Grimm ( raphael dot grimm at kit dot edu )
  * @date       2020
  * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
@@ -28,12 +28,16 @@ module armarx
 {
     module skills
     {
-        interface SkillObserverInterface
+        interface SkillManagerInterface // rename to manager
         {
             void addProvider(string providerName, SkillProviderInterface* provider);
             void removeProvider(string providerName);
+            SkillProviderMap getSkillProviders();
 
             void executeSkill(string providerName, SkillParametrization skill);
+
+            // used for callbacks from providers to update their skill execution status
+            void updateStatusForSkill(string providerName, SkillStatus statusUpdate);
         };
     }
 }
diff --git a/source/RobotAPI/interface/skills/SkillMemoryInterface.ice b/source/RobotAPI/interface/skills/SkillMemoryInterface.ice
index 51d516b22..8025d4cdb 100644
--- a/source/RobotAPI/interface/skills/SkillMemoryInterface.ice
+++ b/source/RobotAPI/interface/skills/SkillMemoryInterface.ice
@@ -13,7 +13,7 @@
  * 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::ArmarXObjects::SkillObserver
+ * @package    RobotAPI::ArmarXObjects::SkillManager
  * @author     Raphael Grimm ( raphael dot grimm at kit dot edu )
  * @date       2020
  * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
@@ -25,7 +25,7 @@
 #include <ArmarXCore/interface/core/Profiler.ice>
 
 #include <RobotAPI/interface/skills/SkillProviderInterface.ice>
-#include <RobotAPI/interface/skills/SkillObserverInterface.ice>
+#include <RobotAPI/interface/skills/SkillManagerInterface.ice>
 #include <RobotAPI/interface/skills/StatechartListenerInterface.ice>
 #include <RobotAPI/interface/armem/server/MemoryInterface.ice>
 
@@ -33,7 +33,7 @@ module armarx
 {
     module skills
     {
-        interface SkillMemoryInterface extends armem::server::MemoryInterface, StatechartListenerInterface, SkillObserverInterface
+        interface SkillMemoryInterface extends armem::server::MemoryInterface, StatechartListenerInterface, SkillManagerInterface
         {
         };
     }
diff --git a/source/RobotAPI/interface/skills/SkillProviderInterface.ice b/source/RobotAPI/interface/skills/SkillProviderInterface.ice
index 8e710ed82..24c4f4e4e 100644
--- a/source/RobotAPI/interface/skills/SkillProviderInterface.ice
+++ b/source/RobotAPI/interface/skills/SkillProviderInterface.ice
@@ -13,7 +13,7 @@
  * 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::ArmarXObjects::SkillObserver
+ * @package    RobotAPI::ArmarXObjects::SkillManager
  * @author     Raphael Grimm ( raphael dot grimm at kit dot edu )
  * @date       2020
  * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
@@ -34,9 +34,11 @@ module armarx
         struct SkillDescription
         {
             string                        name;
-            string                        robot;
-            string                        documentation;
-            aron::type::dto::AronObject   acceptedType;
+            StringList                    robots;
+            string                        documentation; // rename to what?
+            long                          timeoutMs; // Millisecs
+
+            aron::type::dto::AronObject   acceptedType; // the name of the object is irrelevant and only used in GUI
         };
         dictionary<string, SkillDescription> SkillDescriptionMap;
 
@@ -48,35 +50,37 @@ module armarx
                 Scheduled,
                 RunningButWaitingForDependencies,
                 Running,
+
+                // terminating values
                 Failed,
                 Succeeded,
                 Aborted
             };
         };
 
+        interface SkillManagerInterface;
+        struct SkillParametrization
+        {
+            string                   skillName;
+            aron::data::dto::Dict    params;
+        };
+
         struct SkillStatus
         {
             Execution::Status       status;
-            aron::data::dto::Dict   usedParams;
-            aron::data::dto::Dict   returnValue;
-            string                  message;
-            string                  error;
+            SkillParametrization    usedParameterization;
+            aron::data::dto::Dict   returnValue; // can be anything
+            //string                  message;
+            //string                  error;
         };
 
         dictionary<string, SkillStatus> SkillStatusMap;
 
-
-        struct SkillParametrization
-        {
-            string                   name;
-            aron::data::dto::Dict    params;
-        };
-
         interface SkillProviderInterface
         {
             SkillDescriptionMap getSkills();
-            SkillStatusMap getSkillExecutionStatus();
-            void executeSkill(SkillParametrization skill);
+            SkillStatus getSkillExecutionStatus(string name);
+            void executeSkill(SkillParametrization skill, SkillManagerInterface* callbackInterface); // use nullptr if you do not want to have callbacks
             SkillStatus abortSkill(string skill);
         };
 
diff --git a/source/RobotAPI/interface/skills/StatechartListenerInterface.ice b/source/RobotAPI/interface/skills/StatechartListenerInterface.ice
index 2081d8e56..abcd88398 100644
--- a/source/RobotAPI/interface/skills/StatechartListenerInterface.ice
+++ b/source/RobotAPI/interface/skills/StatechartListenerInterface.ice
@@ -13,7 +13,7 @@
  * 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::ArmarXObjects::SkillObserver
+ * @package    RobotAPI::ArmarXObjects::SkillManager
  * @author     Raphael Grimm ( raphael dot grimm at kit dot edu )
  * @date       2020
  * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
diff --git a/source/RobotAPI/libraries/armem_skills/CMakeLists.txt b/source/RobotAPI/libraries/armem_skills/CMakeLists.txt
index bec7daa0d..19e4c5a56 100644
--- a/source/RobotAPI/libraries/armem_skills/CMakeLists.txt
+++ b/source/RobotAPI/libraries/armem_skills/CMakeLists.txt
@@ -16,20 +16,22 @@ armarx_add_library(
         ./aron_conversions.cpp
 
         ./server/StatechartListenerComponentPlugin.cpp
-        ./server/SkillObserverComponentPlugin.cpp
+        ./server/SkillManagerComponentPlugin.cpp
         ./server/segment/StatechartListenerSegment.cpp
         ./server/segment/ExecutableSkillLibrarySegment.cpp
         ./server/segment/SkillExecutionRequestSegment.cpp
+        ./server/segment/SkillEventSegment.cpp
 
         ./client/SkillProviderComponentPlugin.cpp
     HEADERS  
         ./aron_conversions.h
 
         ./server/StatechartListenerComponentPlugin.h
-        ./server/SkillObserverComponentPlugin.h
+        ./server/SkillManagerComponentPlugin.h
         ./server/segment/StatechartListenerSegment.h
         ./server/segment/ExecutableSkillLibrarySegment.h
         ./server/segment/SkillExecutionRequestSegment.h
+        ./server/segment/SkillEventSegment.h
 
         ./client/SkillProviderComponentPlugin.h
 )
diff --git a/source/RobotAPI/libraries/armem_skills/aron/Skill.xml b/source/RobotAPI/libraries/armem_skills/aron/Skill.xml
index 46af4143e..838960afb 100644
--- a/source/RobotAPI/libraries/armem_skills/aron/Skill.xml
+++ b/source/RobotAPI/libraries/armem_skills/aron/Skill.xml
@@ -16,8 +16,10 @@ The memory should look like the following:
                 <String />
             </ObjectChild>
 
-            <ObjectChild key='robot'>
-                <String />
+            <ObjectChild key='robots'>
+                <List>
+                    <String />
+                </List>
             </ObjectChild>
 
             <ObjectChild key='documentation'>
@@ -49,5 +51,22 @@ The memory should look like the following:
             <!-- ToDo: add params wih any type -->
         </Object>
 
+        <Object name='armarx::skills::arondto::SkillExecutionEvent'>
+            <ObjectChild key='providerName'>
+                <String />
+            </ObjectChild>
+
+            <ObjectChild key='skillName'>
+                <String />
+            </ObjectChild>
+
+            <ObjectChild key='status'>
+                <String />
+            </ObjectChild>
+
+            <!-- ToDo: add params with any type -->
+            <!-- ToDo: add result with any type -->
+        </Object>
+
     </GenerateTypes>
 </AronTypeDefinition>
diff --git a/source/RobotAPI/libraries/armem_skills/client/SkillProviderComponentPlugin.cpp b/source/RobotAPI/libraries/armem_skills/client/SkillProviderComponentPlugin.cpp
index d47ca065f..35b128e53 100644
--- a/source/RobotAPI/libraries/armem_skills/client/SkillProviderComponentPlugin.cpp
+++ b/source/RobotAPI/libraries/armem_skills/client/SkillProviderComponentPlugin.cpp
@@ -2,6 +2,8 @@
 
 #include <ArmarXCore/core/Component.h>
 
+#include <RobotAPI/libraries/aron/core/data/variant/primitive/All.h>
+
 namespace armarx::plugins
 {
     void SkillProviderComponentPlugin::preOnInitComponent()
@@ -19,13 +21,13 @@ namespace armarx::plugins
     {
         auto& p = parent<SkillProviderComponentPluginUser>();
         std::string providerName = p.getName();
-        skillObserver->addProvider(providerName, skillProvider);
+        SkillManager->addProvider(providerName, skillProvider);
     }
 
     void SkillProviderComponentPlugin::postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties)
     {
         std::string prefix = "skill.";
-        properties->component(skillObserver, "SkillMemory", prefix + "SkillObserver", "The name of the SkillObserver (or SkillMemory) proxy.");
+        properties->component(SkillManager, "SkillMemory", prefix + "SkillManager", "The name of the SkillManager (or SkillMemory) proxy.");
     }
 }
 
@@ -40,6 +42,7 @@ namespace armarx
     void SkillProviderComponentPluginUser::addSkill(const skills::SkillImplementationPtr& fun, const skills::SkillDescription& desc)
     {
         std::lock_guard l(skillsMutex);
+        std::string providerName = getName();
         std::string skillName = desc.name;
 
         if (skillImplementations.find(skillName) != skillImplementations.end())
@@ -49,7 +52,7 @@ namespace armarx
         }
 
         ARMARX_DEBUG << "Adding skill " << skillName << " to list";
-        SkillImplementationWrapper skill(fun, desc);
+        SkillImplementationWrapper skill(fun, providerName, desc);
         skillImplementations.insert({skillName, skill});
     }
 
@@ -70,22 +73,19 @@ namespace armarx
         return skillDesciptions;
     }
 
-    skills::SkillStatusMap SkillProviderComponentPluginUser::getSkillExecutionStatus(const Ice::Current &current)
+    skills::SkillStatus SkillProviderComponentPluginUser::getSkillExecutionStatus(const std::string& skill, const Ice::Current &current)
     {
         std::lock_guard l(skillsMutex);
-        skills::SkillStatusMap skillStatus;
-        for (const auto& [key, skillImplementation] : skillImplementations)
-        {
-            std::lock_guard l(skillImplementation.skillStatusMutex);
-            skillStatus.insert({key, skillImplementation.status});
-        }
-        return skillStatus;
+        auto& skillImplementation = skillImplementations.at(skill);
+
+        std::lock_guard l2(skillImplementation.skillStatusMutex);
+        return skillImplementation.status;
     }
 
-    void SkillProviderComponentPluginUser::executeSkill(const skills::SkillParametrization& params, const Ice::Current &current)
+    void SkillProviderComponentPluginUser::executeSkill(const skills::SkillParametrization& params, const skills::SkillManagerInterfacePrx& callbackInterface, const Ice::Current &current)
     {
         std::lock_guard l(skillsMutex);
-        std::string skillName = params.name;
+        std::string skillName = params.skillName;
         ARMARX_CHECK_EXPRESSION(skillImplementations.count(skillName) > 0);
 
         auto& impl = skillImplementations.at(skillName);
@@ -96,31 +96,38 @@ namespace armarx
         }
 
         // update input params
-        impl.status.usedParams = params.params;
+        impl.reset();
+        impl.callbackInterface = callbackInterface;
+        impl.status.usedParameterization = params;
 
         // recreate thread and execute skill
-        impl.stop = false;
         impl.task = std::thread{ [&] { impl.execute(); } };
     }
 
     skills::SkillStatus SkillProviderComponentPluginUser::abortSkill(const std::string& skillName, const Ice::Current &current)
     {
         std::lock_guard l(skillsMutex);
-        if (skillImplementations.count(skillName))
+        ARMARX_CHECK_EXPRESSION(skillImplementations.count(skillName) > 0);
+        auto& impl = skillImplementations.at(skillName);
+        impl.stop = true;
+        if (impl.task.joinable())
         {
-            auto& impl = skillImplementations.at(skillName);
-            impl.stop = true;
-            if (impl.task.joinable())
-            {
-                impl.task.join();
-
-                std::lock_guard l(impl.skillStatusMutex);
-                impl.status.status = skills::Execution::Aborted;
-            }
+            impl.task.join();
 
-            return skillImplementations.at(skillName).status;
+            std::lock_guard l(impl.skillStatusMutex);
+            impl.status.status = skills::Execution::Aborted;
         }
-        return {};
+
+        return skillImplementations.at(skillName).status;
+    }
+
+    void SkillProviderComponentPluginUser::SkillImplementationWrapper::reset()
+    {
+        std::lock_guard l(skillStatusMutex);
+        stop = false;
+        status.status = skills::Execution::Status::Idle;
+        status.returnValue = nullptr;
+        skillStarted = 0;
     }
 
     void SkillProviderComponentPluginUser::SkillImplementationWrapper::execute()
@@ -128,10 +135,26 @@ namespace armarx
         ARMARX_INFO_S << "Executing skill: " << description.name;
         try
         {
+            // set scheduled and reset skill
+            {
+                std::lock_guard l(skillStatusMutex);
+                status.status = skills::Execution::Scheduled;
+
+                // do callback
+                if (callbackInterface)
+                {
+                    callbackInterface->updateStatusForSkill(providerName, status);
+                }
+            }
+
             // wait for dependencies
             {
                 std::lock_guard l(skillStatusMutex);
                 status.status = skills::Execution::RunningButWaitingForDependencies;
+                if (callbackInterface)
+                {
+                    callbackInterface->updateStatusForSkill(providerName, status);
+                }
             }
 
             if (stop) return;
@@ -140,33 +163,78 @@ namespace armarx
 
             if (initialized != skills::SkillImplementation::Status::Succeeded)
             {
-                status.error = "Could not initialize the skill.";
-                {
-                    std::lock_guard l(skillStatusMutex);
-                    status.status = skills::Execution::Failed;
-                }
+                // create message to return
+                auto returnDict = std::make_shared<aron::data::Dict>();
+                auto message = std::make_shared<aron::data::String>("Could not initialize the skill.");
+                returnDict->addElement("message", message);
+                status.returnValue = returnDict->toAronDictPtr();
+
+                throw armarx::LocalException("The Skill '"+description.name+"' failed during initialization.");
             }
 
             // execute
             {
                 std::lock_guard l(skillStatusMutex);
                 status.status = skills::Execution::Running;
+                if (callbackInterface)
+                {
+                    callbackInterface->updateStatusForSkill(providerName, status);
+                }
             }
 
             if (stop) return;
-            auto params = std::make_shared<aron::data::Dict>(status.usedParams);
-            auto result = skill->execute(params);
+            aron::data::DictPtr aron_params = nullptr;
+            if (status.usedParameterization.params) // check if params are set.
+            {
+                aron_params = std::make_shared<aron::data::Dict>(status.usedParameterization.params);
+            }
+            else
+            {
+               if (description.acceptedType)
+               {
+                    throw armarx::LocalException("The Skill '"+description.name+"' requires a type but no params are NULL.");
+               }
+            }
+
+            auto updateCallback = [&](const aron::data::DictPtr& update)
+            {
+                if (update)
+                {
+                    status.returnValue = update->toAronDictPtr();
+                    callbackInterface->updateStatusForSkill(providerName, status);
+                }
+            };
+            auto result = skill->execute(aron_params, updateCallback);
             if (stop) return;
 
             {
+                if (result == skills::SkillImplementation::Status::Failed)
+                {
+                    throw armarx::LocalException("The Skill '"+description.name+"' failed during execution.");
+                }
+                if (result == skills::SkillImplementation::Status::TimeoutReached)
+                {
+                    throw armarx::LocalException("The Skill '"+description.name+"' reached timeout during execution.");
+                }
+
                 std::lock_guard l(skillStatusMutex);
-                status.status = ((result == skills::SkillImplementation::Status::Succeeded) ? skills::Execution::Succeeded : skills::Execution::Failed);
+                status.status = skills::Execution::Succeeded;
+                if (callbackInterface)
+                {
+                    callbackInterface->updateStatusForSkill(providerName, status);
+                }
             }
         }
-        catch (...)
+        catch (const std::exception& ex)
         {
+            ARMARX_WARNING_S << "Skill " << description.name << " died with exception:\n" << ex.what();
+
             std::lock_guard l(skillStatusMutex);
             status.status = skills::Execution::Failed;
+            if (callbackInterface)
+            {
+                callbackInterface->updateStatusForSkill(providerName, status);
+            }
         }
     }
 }
diff --git a/source/RobotAPI/libraries/armem_skills/client/SkillProviderComponentPlugin.h b/source/RobotAPI/libraries/armem_skills/client/SkillProviderComponentPlugin.h
index 666ee05e1..8f5cc81fb 100644
--- a/source/RobotAPI/libraries/armem_skills/client/SkillProviderComponentPlugin.h
+++ b/source/RobotAPI/libraries/armem_skills/client/SkillProviderComponentPlugin.h
@@ -10,7 +10,7 @@
 
 #include <ArmarXCore/core/services/tasks/RunningTask.h>
 
-#include <RobotAPI/interface/skills/SkillObserverInterface.h>
+#include <RobotAPI/interface/skills/SkillManagerInterface.h>
 #include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h>
 
 namespace armarx::plugins
@@ -28,7 +28,7 @@ namespace armarx::plugins
         void postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties) override;
 
     private:
-        skills::SkillObserverInterfacePrx skillObserver;
+        skills::SkillManagerInterfacePrx SkillManager;
         skills::SkillProviderInterfacePrx skillProvider;
     };
 }
@@ -40,6 +40,8 @@ namespace armarx
         class SkillImplementation
         {
         public:
+            using CallbackT = std::function<void(const aron::data::DictPtr&)>;
+
             enum class Status
             {
                 Succeeded,
@@ -52,34 +54,19 @@ namespace armarx
                 return Status::Succeeded;
             }
 
-            virtual Status execute(const aron::data::DictPtr&)
+            /// Override this method with the actual implementation. The callback is for status updates
+            virtual Status execute(const aron::data::DictPtr& params, const CallbackT& callback)
             {
                 ARMARX_WARNING_S << "You have to override this method!";
                 return Status::Succeeded;
             }
 
-            void reset()
+            /// Use this if you do not need a callback
+            Status execute(const aron::data::DictPtr& params)
             {
-                skillStarted = 0;
-            }
-
-        protected:
-            bool isTimeoutReached() const
-            {
-                if (timeoutMs < 0)
-                {
-                    return false;
-                }
-
-                auto now = IceUtil::Time::now().toMilliSeconds();
-                return (now - skillStarted) >= timeoutMs;
+                auto fun = [](const aron::data::DictPtr&) {};
+                return execute(params, fun);
             }
-
-        public:
-            long timeoutMs = -1;
-
-        protected:
-            long skillStarted = 0;
         };
 
         class LambdaSkillImplementation : public SkillImplementation
@@ -90,7 +77,7 @@ namespace armarx
             LambdaSkillImplementation() = delete;
             LambdaSkillImplementation(const FunT& f) : fun(f) {};
 
-            SkillImplementation::Status execute(const aron::data::DictPtr& data) override
+            SkillImplementation::Status execute(const aron::data::DictPtr& data, const CallbackT& callback) override
             {
                 bool res = fun(data);
                 return res ? Status::Succeeded : Status::Failed;
@@ -112,35 +99,56 @@ namespace armarx
     public:
         struct SkillImplementationWrapper
         {
-            skills::SkillDescription description;
-            skills::SkillImplementationPtr skill;
+            // fixed values. Do not change after skill instantiation
+            const std::string providerName;
+            const skills::SkillDescription description;
+            const skills::SkillImplementationPtr skill;
 
-            // Current execution status
+            // Current execution status. Changes during execution
             skills::SkillStatus status;
 
-            // Task
+            // Used callback interface. May change on start
+            skills::SkillManagerInterfacePrx callbackInterface = nullptr;
+
+            // Info
+            long skillStarted = 0;
+
+            // Task information. task is recreated every time the skill restarts
             mutable std::mutex skillStatusMutex;
             std::atomic_bool stop = false;
             std::thread task;
 
-            SkillImplementationWrapper(const skills::SkillImplementationPtr& fun, const skills::SkillDescription& desc) :
-                description(desc), skill(fun)
+            SkillImplementationWrapper(const skills::SkillImplementationPtr& fun, const std::string& providerName, const skills::SkillDescription& desc) :
+                providerName(providerName), description(desc), skill(fun)
             {
-                status.status = skills::Execution::Status::Idle;
+                reset();
             }
 
             SkillImplementationWrapper(const SkillImplementationWrapper& s) :
-                SkillImplementationWrapper(s.skill, s.description)
+                SkillImplementationWrapper(s.skill, s.providerName, s.description)
             {}
 
             void execute();
+            void reset();
+
+        private:
+            bool isTimeoutReached() const
+            {
+                if (description.timeoutMs < 0)
+                {
+                    return false;
+                }
+
+                auto now = IceUtil::Time::now().toMilliSeconds();
+                return (now - skillStarted) >= description.timeoutMs;
+            }
         };
 
         SkillProviderComponentPluginUser();
 
         skills::SkillDescriptionMap getSkills(const Ice::Current &current) override;
-        skills::SkillStatusMap getSkillExecutionStatus(const Ice::Current &current) override;
-        void executeSkill(const skills::SkillParametrization &skill, const Ice::Current &current) override;
+        skills::SkillStatus getSkillExecutionStatus(const std::string& skill, const Ice::Current &current) override;
+        void executeSkill(const skills::SkillParametrization &skill, const skills::SkillManagerInterfacePrx& callbackInterface, const Ice::Current &current) override;
         skills::SkillStatus abortSkill(const std::string &skill, const Ice::Current &current) override;
 
     protected:
diff --git a/source/RobotAPI/libraries/armem_skills/server/SkillManagerComponentPlugin.cpp b/source/RobotAPI/libraries/armem_skills/server/SkillManagerComponentPlugin.cpp
new file mode 100644
index 000000000..ee2445911
--- /dev/null
+++ b/source/RobotAPI/libraries/armem_skills/server/SkillManagerComponentPlugin.cpp
@@ -0,0 +1,65 @@
+#include "SkillManagerComponentPlugin.h"
+
+#include <ArmarXCore/core/Component.h>
+
+namespace armarx::plugins
+{
+    void SkillManagerComponentPlugin::preOnInitComponent()
+    {}
+
+    void SkillManagerComponentPlugin::preOnConnectComponent()
+    {}
+
+    void SkillManagerComponentPlugin::postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties)
+    {}
+}
+
+
+namespace armarx
+{
+    SkillManagerComponentPluginUser::SkillManagerComponentPluginUser()
+    {
+        addPlugin(plugin);
+    }
+
+    void SkillManagerComponentPluginUser::addProvider(const std::string& providerName, const skills::SkillProviderInterfacePrx& provider, const Ice::Current&)
+    {
+        std::lock_guard l(skillProviderMapMutex);
+        if (skillProviderMap.find(providerName) == skillProviderMap.end())
+        {
+            ARMARX_INFO << "Adding a provider with name '" << providerName << "'.";
+            skillProviderMap.insert({providerName, provider});
+        }
+    }
+
+    void SkillManagerComponentPluginUser::removeProvider(const std::string& providerName, const Ice::Current&)
+    {
+        std::lock_guard l(skillProviderMapMutex);
+        if (auto it = skillProviderMap.find(providerName); it != skillProviderMap.end())
+        {
+            skillProviderMap.erase(it);
+        }
+    }
+
+    skills::SkillProviderMap SkillManagerComponentPluginUser::getSkillProviders(const Ice::Current&)
+    {
+        return skillProviderMap;
+    }
+
+    void SkillManagerComponentPluginUser::executeSkill(const std::string& providerName, const skills::SkillParametrization& params, const Ice::Current&)
+    {
+        if (auto it = skillProviderMap.find(providerName); it != skillProviderMap.end())
+        {
+            auto myPrx = getProxy<skills::SkillManagerInterfacePrx>(getName());
+            it->second->executeSkill(params, myPrx);
+        }
+        throw LocalException("Could not execute a skill of provider '" + providerName + "' because the provider does not exist.");
+    }
+
+    void SkillManagerComponentPluginUser::updateStatusForSkill(const std::string& providerName, const skills::SkillStatus& statusUpdate, const Ice::Current&)
+    {
+        (void) providerName;
+        (void) statusUpdate;
+        // If you want to use the status, implement this method!
+    }
+}
diff --git a/source/RobotAPI/libraries/armem_skills/server/SkillObserverComponentPlugin.h b/source/RobotAPI/libraries/armem_skills/server/SkillManagerComponentPlugin.h
similarity index 62%
rename from source/RobotAPI/libraries/armem_skills/server/SkillObserverComponentPlugin.h
rename to source/RobotAPI/libraries/armem_skills/server/SkillManagerComponentPlugin.h
index cbd2e60e6..8e976fbf0 100644
--- a/source/RobotAPI/libraries/armem_skills/server/SkillObserverComponentPlugin.h
+++ b/source/RobotAPI/libraries/armem_skills/server/SkillManagerComponentPlugin.h
@@ -5,11 +5,11 @@
 #include <ArmarXCore/core/ComponentPlugin.h>
 #include <ArmarXCore/core/ManagedIceObject.h>
 
-#include <RobotAPI/interface/skills/SkillObserverInterface.h>
+#include <RobotAPI/interface/skills/SkillManagerInterface.h>
 
 namespace armarx::plugins
 {
-    class SkillObserverComponentPlugin : public ComponentPlugin
+    class SkillManagerComponentPlugin : public ComponentPlugin
     {
     public:
         using ComponentPlugin::ComponentPlugin;
@@ -24,19 +24,22 @@ namespace armarx::plugins
 
 namespace armarx
 {
-    class SkillObserverComponentPluginUser :
+    class SkillManagerComponentPluginUser :
             virtual public ManagedIceObject,
-            virtual public skills::SkillObserverInterface
+            virtual public skills::SkillManagerInterface
     {
     public:
-        SkillObserverComponentPluginUser();
+        SkillManagerComponentPluginUser();
 
         void addProvider(const std::string&, const skills::SkillProviderInterfacePrx& provider, const Ice::Current &current) override;
         void removeProvider(const std::string&, const Ice::Current &current) override;
+        skills::SkillProviderMap getSkillProviders(const Ice::Current &current) override;
         void executeSkill(const std::string&, const skills::SkillParametrization& params, const Ice::Current &current) override;
+        void updateStatusForSkill(const std::string& providerName, const skills::SkillStatus& statusUpdate, const Ice::Current &current) override;
+
 
     private:
-        armarx::plugins::SkillObserverComponentPlugin* plugin = nullptr;
+        armarx::plugins::SkillManagerComponentPlugin* plugin = nullptr;
 
     protected:
         std::mutex skillProviderMapMutex;
diff --git a/source/RobotAPI/libraries/armem_skills/server/SkillObserverComponentPlugin.cpp b/source/RobotAPI/libraries/armem_skills/server/SkillObserverComponentPlugin.cpp
deleted file mode 100644
index 479fd5843..000000000
--- a/source/RobotAPI/libraries/armem_skills/server/SkillObserverComponentPlugin.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-#include "SkillObserverComponentPlugin.h"
-
-#include <ArmarXCore/core/Component.h>
-
-namespace armarx::plugins
-{
-    void SkillObserverComponentPlugin::preOnInitComponent()
-    {}
-
-    void SkillObserverComponentPlugin::preOnConnectComponent()
-    {}
-
-    void SkillObserverComponentPlugin::postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties)
-    {}
-}
-
-
-namespace armarx
-{
-    SkillObserverComponentPluginUser::SkillObserverComponentPluginUser()
-    {
-        addPlugin(plugin);
-    }
-
-    void SkillObserverComponentPluginUser::addProvider(const std::string& providerName, const skills::SkillProviderInterfacePrx& provider, const Ice::Current &current)
-    {
-        std::lock_guard l(skillProviderMapMutex);
-        if (skillProviderMap.find(providerName) == skillProviderMap.end())
-        {
-            ARMARX_INFO << "Adding a provider with name '" << providerName << "'.";
-            skillProviderMap.insert({providerName, provider});
-        }
-    }
-
-    void SkillObserverComponentPluginUser::removeProvider(const std::string& providerName, const Ice::Current &current)
-    {
-        std::lock_guard l(skillProviderMapMutex);
-        if (auto it = skillProviderMap.find(providerName); it != skillProviderMap.end())
-        {
-            skillProviderMap.erase(it);
-        }
-    }
-
-    void SkillObserverComponentPluginUser::executeSkill(const std::string& providerName, const skills::SkillParametrization& params, const Ice::Current &current)
-    {
-        if (auto it = skillProviderMap.find(providerName); it != skillProviderMap.end())
-        {
-            it->second->executeSkill(params);
-        }
-        throw LocalException("Could not execute a skill of provider '" + providerName + "' because the provider does not exist.");
-    }
-}
diff --git a/source/RobotAPI/libraries/armem_skills/server/segment/ExecutableSkillLibrarySegment.cpp b/source/RobotAPI/libraries/armem_skills/server/segment/ExecutableSkillLibrarySegment.cpp
index 8b9d00133..d5bd93058 100644
--- a/source/RobotAPI/libraries/armem_skills/server/segment/ExecutableSkillLibrarySegment.cpp
+++ b/source/RobotAPI/libraries/armem_skills/server/segment/ExecutableSkillLibrarySegment.cpp
@@ -35,7 +35,7 @@ namespace armarx::skills::segment
             skillDescription.name = desc.name;
             skillDescription.documentation = desc.documentation;
             skillDescription.iceInfo = skillProvider->ice_toString();
-            skillDescription.robot = desc.robot;
+            skillDescription.robots = desc.robots;
             if (desc.acceptedType)
             {
                 aron::type::VariantPtr t = aron::type::Variant::FromAronDTO(*desc.acceptedType);
@@ -54,12 +54,15 @@ namespace armarx::skills::segment
         }
     }
 
-    void ExecutableSkillLibraryProviderSegment::directlyExecuteSkill(const skills::arondto::SkillExecutionRequest& req, const aron::data::DictPtr& params)
+    void ExecutableSkillLibraryProviderSegment::directlyExecuteSkill(const skills::arondto::SkillExecutionRequest& req, const skills::SkillManagerInterfacePrx& callbackInterface, const aron::data::DictPtr& params)
     {
         skills::SkillParametrization parameterization;
-        parameterization.name = req.skillName;
-        parameterization.params = params->toAronDictPtr();
-        skillProvider->executeSkill(parameterization); // ToDo: put in thread?
+        parameterization.skillName = req.skillName;
+        if (params) // may be null
+        {
+            parameterization.params = params->toAronDictPtr();
+        }
+        skillProvider->executeSkill(parameterization, callbackInterface);
     }
 
     ExecutableSkillLibraryCoreSegment::ExecutableSkillLibraryCoreSegment(armem::server::MemoryToIceAdapter& iceMemory):
@@ -86,20 +89,25 @@ namespace armarx::skills::segment
         }
         else
         {
-            ARMARX_WARNING << "Could not insert a skillProvider '"<<providerSegmentName<<"' to the segment '" << getCoreSegment().id().str() << "'. This may leave the skillObserver and the memory unsynchronized.";
+            ARMARX_WARNING << "Could not insert a skillProvider '"<<providerSegmentName<<"' to the segment '" << getCoreSegment().id().str() << "'. This may leave the SkillManager and the memory unsynchronized.";
         }
     }
 
+    SkillProviderInterfacePrx ExecutableSkillLibraryCoreSegment::getSkillProvider(const std::string& providerName) const
+    {
+        return providerSegments.at(providerName).skillProvider;
+    }
+
     void ExecutableSkillLibraryCoreSegment::removeSkillProvider(const std::string& providerName)
     {
         providerSegments.erase(providerName);
     }
 
-    void ExecutableSkillLibraryCoreSegment::directlyExecuteSkill(const skills::arondto::SkillExecutionRequest& req, const aron::data::DictPtr& params)
+    void ExecutableSkillLibraryCoreSegment::directlyExecuteSkill(const skills::arondto::SkillExecutionRequest& req, const skills::SkillManagerInterfacePrx& callbackInterface, const aron::data::DictPtr& params)
     {
         if (const auto& it = providerSegments.find(req.providerName); it != providerSegments.end())
         {
-            it->second.directlyExecuteSkill(req, params);
+            it->second.directlyExecuteSkill(req, callbackInterface, params);
         }
     }
 
diff --git a/source/RobotAPI/libraries/armem_skills/server/segment/ExecutableSkillLibrarySegment.h b/source/RobotAPI/libraries/armem_skills/server/segment/ExecutableSkillLibrarySegment.h
index 2f8652067..dd2dba322 100644
--- a/source/RobotAPI/libraries/armem_skills/server/segment/ExecutableSkillLibrarySegment.h
+++ b/source/RobotAPI/libraries/armem_skills/server/segment/ExecutableSkillLibrarySegment.h
@@ -25,9 +25,9 @@ namespace armarx::skills::segment
         void defineProperties(PropertyDefinitionsPtr defs, const std::string &prefix);
         void init();
 
-        void directlyExecuteSkill(const skills::arondto::SkillExecutionRequest&, const aron::data::DictPtr& params);
+        void directlyExecuteSkill(const skills::arondto::SkillExecutionRequest&, const skills::SkillManagerInterfacePrx& callbackInterface, const aron::data::DictPtr& params);
 
-    private:
+    public:
         SkillProviderInterfacePrx skillProvider;
     };
 
@@ -45,8 +45,9 @@ namespace armarx::skills::segment
         void init();
 
         void addSkillProvider(const std::string& providerName, const SkillProviderInterfacePrx& provider);
+        SkillProviderInterfacePrx getSkillProvider(const std::string& providerName) const;
         void removeSkillProvider(const std::string& providerName);
-        void directlyExecuteSkill(const skills::arondto::SkillExecutionRequest&, const aron::data::DictPtr& params);
+        void directlyExecuteSkill(const skills::arondto::SkillExecutionRequest&, const skills::SkillManagerInterfacePrx& callbackInterface, const aron::data::DictPtr& params);
 
         size_t size() const;
 
diff --git a/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.cpp b/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.cpp
new file mode 100644
index 000000000..012a2c0ad
--- /dev/null
+++ b/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.cpp
@@ -0,0 +1,27 @@
+#include "SkillEventSegment.h"
+
+#include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h>
+#include <SimoxUtility/algorithm/string.h>
+
+#include <RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.h>
+
+#include <RobotAPI/libraries/armem_skills/aron/Skill.aron.generated.h>
+
+namespace armarx::skills::segment
+{
+
+    SkillEventCoreSegment::SkillEventCoreSegment(armem::server::MemoryToIceAdapter& iceMemory):
+        Base(iceMemory, CoreSegmentName)
+    {
+    }
+
+    void SkillEventCoreSegment::defineProperties(PropertyDefinitionsPtr defs, const std::string &prefix)
+    {
+        // No properties! (meaning no name and no max size)
+    }
+
+    void SkillEventCoreSegment::init()
+    {
+        Base::init();
+    }
+}
diff --git a/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.h b/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.h
new file mode 100644
index 000000000..7867bc934
--- /dev/null
+++ b/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <thread>
+
+// Base Class
+#include <RobotAPI/libraries/armem/server/segment/SpecializedSegment.h>
+
+// ArmarX
+#include <RobotAPI/interface/skills/SkillProviderInterface.h>
+
+#include <RobotAPI/libraries/armem_skills/aron/Skill.aron.generated.h>
+
+namespace armarx::skills::segment
+{
+    class SkillEventCoreSegment :
+        public armem::server::segment::SpecializedCoreSegment
+    {
+        using Base = armem::server::segment::SpecializedCoreSegment;
+
+    public:
+        static constexpr const char* CoreSegmentName = "SkillEvent";
+
+        SkillEventCoreSegment(armem::server::MemoryToIceAdapter& iceMemory);
+
+        void defineProperties(PropertyDefinitionsPtr defs, const std::string &prefix);
+        void init();
+
+    private:
+        std::map<std::string, std::map<std::string, std::thread>> pollers;
+    };
+}
diff --git a/source/RobotAPI/libraries/armem_skills/server/segment/SkillExecutionRequestSegment.cpp b/source/RobotAPI/libraries/armem_skills/server/segment/SkillExecutionRequestSegment.cpp
index 158e8c5e1..a4a02d913 100644
--- a/source/RobotAPI/libraries/armem_skills/server/segment/SkillExecutionRequestSegment.cpp
+++ b/source/RobotAPI/libraries/armem_skills/server/segment/SkillExecutionRequestSegment.cpp
@@ -12,7 +12,7 @@ namespace armarx::skills::segment
 {
 
     SkillExecutionRequestProviderSegment::SkillExecutionRequestProviderSegment(const std::string& provName, const SkillProviderInterfacePrx& prx, armem::server::MemoryToIceAdapter& iceMemory):
-        Base(iceMemory, provName, SkillExecutionRequestCoreSegment::CoreSegmentName, skills::arondto::SkillExecutionRequest::toAronType())
+        Base(iceMemory, provName, SkillExecutionRequestCoreSegment::CoreSegmentName/*, skills::arondto::SkillExecutionRequest::toAronType()*/)
     {
     }
 
@@ -27,7 +27,7 @@ namespace armarx::skills::segment
     }
 
     SkillExecutionRequestCoreSegment::SkillExecutionRequestCoreSegment(armem::server::MemoryToIceAdapter& iceMemory):
-        Base(iceMemory, CoreSegmentName, skills::arondto::SkillExecutionRequest::toAronType())
+        Base(iceMemory, CoreSegmentName/*, skills::arondto::SkillExecutionRequest::toAronType()*/)
     {
     }
 
diff --git a/source/RobotAPI/libraries/aron/core/type/variant/Variant.h b/source/RobotAPI/libraries/aron/core/type/variant/Variant.h
index faaf06cdc..ab996582c 100644
--- a/source/RobotAPI/libraries/aron/core/type/variant/Variant.h
+++ b/source/RobotAPI/libraries/aron/core/type/variant/Variant.h
@@ -33,6 +33,7 @@
 // #include <SimoxUtility/algorithm/string.h>
 
 // ArmarX
+#include <RobotAPI/libraries/aron/core/Path.h>
 #include <RobotAPI/libraries/aron/core/Exception.h>
 #include <RobotAPI/interface/aron.h>
 #include <RobotAPI/libraries/aron/core/Descriptor.h>
diff --git a/source/RobotAPI/libraries/aron/core/type/variant/container/Dict.cpp b/source/RobotAPI/libraries/aron/core/type/variant/container/Dict.cpp
index 1ba76b626..3919bf844 100644
--- a/source/RobotAPI/libraries/aron/core/type/variant/container/Dict.cpp
+++ b/source/RobotAPI/libraries/aron/core/type/variant/container/Dict.cpp
@@ -37,7 +37,7 @@ namespace armarx::aron::type
 
     Dict::Dict(const type::dto::Dict& o, const Path& path) :
         detail::ContainerVariant<type::dto::Dict, Dict>(o, type::Descriptor::eDict, path),
-        acceptedType(FromAronDTO(*o.acceptedType))
+        acceptedType(FromAronDTO(*o.acceptedType, path.withAcceptedType()))
     {
     }
 
diff --git a/source/RobotAPI/libraries/aron/core/type/variant/container/List.cpp b/source/RobotAPI/libraries/aron/core/type/variant/container/List.cpp
index 2f65cb75b..807d64fed 100644
--- a/source/RobotAPI/libraries/aron/core/type/variant/container/List.cpp
+++ b/source/RobotAPI/libraries/aron/core/type/variant/container/List.cpp
@@ -36,7 +36,7 @@ namespace armarx::aron::type
 
     List::List(const type::dto::List& o, const Path& path) :
         detail::ContainerVariant<type::dto::List, List>(o, type::Descriptor::eList, path),
-        acceptedType(FromAronDTO(*o.acceptedType))
+        acceptedType(FromAronDTO(*o.acceptedType, path.withAcceptedType()))
     {
     }
 
diff --git a/source/RobotAPI/libraries/aron/core/type/variant/container/Object.cpp b/source/RobotAPI/libraries/aron/core/type/variant/container/Object.cpp
index d252ae8fc..52eb6ed43 100644
--- a/source/RobotAPI/libraries/aron/core/type/variant/container/Object.cpp
+++ b/source/RobotAPI/libraries/aron/core/type/variant/container/Object.cpp
@@ -47,9 +47,10 @@ namespace armarx::aron::type
     Object::Object(const type::dto::AronObject& o, const Path& path) :
         detail::ContainerVariant<type::dto::AronObject, Object>(o, type::Descriptor::eObject, path)
     {
+        setObjectName(o.objectName);
         for (const auto& [key, t] : o.elementTypes)
         {
-            memberTypes[key] = FromAronDTO(*t);
+            memberTypes[key] = FromAronDTO(*t, path.withElement(key));
         }
     }
 
@@ -155,7 +156,7 @@ namespace armarx::aron::type
 
     type::dto::AronObjectPtr Object::toObjectDTO() const
     {
-        // TODO: Shall we allow empty objects?
+        // TODO: Shall we allow empty objects? For now yes!
         //if(acceptedTypeNavigators.empty())
         //{
         //    throw exception::AronExceptionWithPathInfo("ObjectNavigator", "getResult", "No accepted types set", getPath());
diff --git a/source/RobotAPI/libraries/aron/core/type/variant/container/Object.h b/source/RobotAPI/libraries/aron/core/type/variant/container/Object.h
index 50ce062d4..4c2f58738 100644
--- a/source/RobotAPI/libraries/aron/core/type/variant/container/Object.h
+++ b/source/RobotAPI/libraries/aron/core/type/variant/container/Object.h
@@ -45,7 +45,7 @@ namespace armarx::aron::type
     {
     public:
         // constructors
-        Object(const std::string&, const std::map<std::string, VariantPtr>&, const Path& = Path());
+        Object(const std::string&, const std::map<std::string, VariantPtr>& = {}, const Path& = Path());
         Object(const type::dto::AronObject&, const Path& = Path());
 
         // public member functions
diff --git a/source/RobotAPI/libraries/aron/core/type/variant/container/Pair.cpp b/source/RobotAPI/libraries/aron/core/type/variant/container/Pair.cpp
index d1cebcd3d..48e0c6f4d 100644
--- a/source/RobotAPI/libraries/aron/core/type/variant/container/Pair.cpp
+++ b/source/RobotAPI/libraries/aron/core/type/variant/container/Pair.cpp
@@ -39,8 +39,8 @@ namespace armarx::aron::type
 
     Pair::Pair(const type::dto::Pair& o, const Path& path) :
         detail::ContainerVariant<type::dto::Pair, Pair>(o, type::Descriptor::ePair, path),
-        acceptedType1(FromAronDTO(*o.acceptedType1)),
-        acceptedType2(FromAronDTO(*o.acceptedType2))
+        acceptedType1(FromAronDTO(*o.acceptedType1, path.withAcceptedTypeIndex(0))),
+        acceptedType2(FromAronDTO(*o.acceptedType2, path.withAcceptedTypeIndex(1)))
     {
     }
 
diff --git a/source/RobotAPI/libraries/aron/core/type/variant/container/Tuple.cpp b/source/RobotAPI/libraries/aron/core/type/variant/container/Tuple.cpp
index e189a85c7..9fdca45e7 100644
--- a/source/RobotAPI/libraries/aron/core/type/variant/container/Tuple.cpp
+++ b/source/RobotAPI/libraries/aron/core/type/variant/container/Tuple.cpp
@@ -42,9 +42,10 @@ namespace armarx::aron::type
     Tuple::Tuple(const type::dto::Tuple& o, const Path& path) :
         detail::ContainerVariant<type::dto::Tuple, Tuple>(o, type::Descriptor::eTuple, path)
     {
+        unsigned int i = 0;
         for (const auto& t : o.elementTypes)
         {
-            acceptedTypes.push_back(FromAronDTO(*t));
+            acceptedTypes.push_back(FromAronDTO(*t, path.withAcceptedTypeIndex(i++)));
         }
     }
 
diff --git a/source/RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.cpp b/source/RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.cpp
index ae5b60e7f..241a1ec27 100644
--- a/source/RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.cpp
+++ b/source/RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.cpp
@@ -45,6 +45,154 @@ namespace armarx::aron::type
         return GetDescriptor(n);
     }
 
+    void ConstVariantVisitor::visitObject(Input& i)
+    {
+        auto aron = type::Object::DynamicCastAndCheck(i);
+        visitAronVariant(aron);
+    }
+
+    void ConstVariantVisitor::visitDict(Input& i)
+    {
+        auto aron = type::Dict::DynamicCastAndCheck(i);
+        visitAronVariant(aron);
+    }
+
+    void ConstVariantVisitor::visitPair(Input& i)
+    {
+        auto aron = type::Pair::DynamicCastAndCheck(i);
+        visitAronVariant(aron);
+    }
+
+    void ConstVariantVisitor::visitTuple(Input& i)
+    {
+        auto aron = type::Tuple::DynamicCastAndCheck(i);
+        visitAronVariant(aron);
+    }
+
+    void ConstVariantVisitor::visitList(Input& i)
+    {
+        auto aron = type::List::DynamicCastAndCheck(i);
+        visitAronVariant(aron);
+    }
+
+    void ConstVariantVisitor::visitMatrix(Input& i)
+    {
+        auto aron = type::Matrix::DynamicCastAndCheck(i);
+        visitAronVariant(aron);
+    }
+
+    void ConstVariantVisitor::visitNDArray(Input& i)
+    {
+        auto aron = type::NDArray::DynamicCastAndCheck(i);
+        visitAronVariant(aron);
+    }
+
+    void ConstVariantVisitor::visitOrientation(Input& i)
+    {
+        auto aron = type::Orientation::DynamicCastAndCheck(i);
+        visitAronVariant(aron);
+    }
+
+    void ConstVariantVisitor::visitPosition(Input& i)
+    {
+        auto aron = type::Position::DynamicCastAndCheck(i);
+        visitAronVariant(aron);
+    }
+
+    void ConstVariantVisitor::visitPose(Input& i)
+    {
+        auto aron = type::Pose::DynamicCastAndCheck(i);
+        visitAronVariant(aron);
+    }
+
+    void ConstVariantVisitor::visitQuaternion(Input & i)
+    {
+        auto aron = type::Quaternion::DynamicCastAndCheck(i);
+        visitAronVariant(aron);
+    }
+
+    void ConstVariantVisitor::visitImage(Input& i)
+    {
+        auto aron = type::Image::DynamicCastAndCheck(i);
+        visitAronVariant(aron);
+    }
+
+    void ConstVariantVisitor::visitPointCloud(Input& i)
+    {
+        auto aron = type::PointCloud::DynamicCastAndCheck(i);
+        visitAronVariant(aron);
+    }
+
+    void ConstVariantVisitor::visitIntEnum(Input& i)
+    {
+        auto aron = type::IntEnum::DynamicCastAndCheck(i);
+        visitAronVariant(aron);
+    }
+
+    void ConstVariantVisitor::visitInt(Input& i)
+    {
+        auto aron = type::Int::DynamicCastAndCheck(i);
+        visitAronVariant(aron);
+    }
+
+    void ConstVariantVisitor::visitLong(Input& i)
+    {
+        auto aron = type::Long::DynamicCastAndCheck(i);
+        visitAronVariant(aron);
+    }
+
+    void ConstVariantVisitor::visitFloat(Input& i)
+    {
+        auto aron = type::Float::DynamicCastAndCheck(i);
+        visitAronVariant(aron);
+    }
+
+    void ConstVariantVisitor::visitDouble(Input& i)
+    {
+        auto aron = type::Double::DynamicCastAndCheck(i);
+        visitAronVariant(aron);
+    }
+
+    void ConstVariantVisitor::visitBool(Input& i)
+    {
+        auto aron = type::Bool::DynamicCastAndCheck(i);
+        visitAronVariant(aron);
+    }
+
+    void ConstVariantVisitor::visitString(Input& i)
+    {
+        auto aron = type::String::DynamicCastAndCheck(i);
+        visitAronVariant(aron);
+    }
+
+    void ConstVariantVisitor::visitTime(Input& i)
+    {
+        auto aron = type::Time::DynamicCastAndCheck(i);
+        visitAronVariant(aron);
+    }
+
+    void ConstVariantVisitor::visitAronVariant(const type::ObjectPtr&) {}
+    void ConstVariantVisitor::visitAronVariant(const type::DictPtr&) {}
+    void ConstVariantVisitor::visitAronVariant(const type::PairPtr&) {}
+    void ConstVariantVisitor::visitAronVariant(const type::TuplePtr&) {}
+    void ConstVariantVisitor::visitAronVariant(const type::ListPtr&) {}
+    void ConstVariantVisitor::visitAronVariant(const type::NDArrayPtr&) {}
+    void ConstVariantVisitor::visitAronVariant(const type::MatrixPtr&) {}
+    void ConstVariantVisitor::visitAronVariant(const type::QuaternionPtr&) {}
+    void ConstVariantVisitor::visitAronVariant(const type::PositionPtr&) {}
+    void ConstVariantVisitor::visitAronVariant(const type::OrientationPtr&) {}
+    void ConstVariantVisitor::visitAronVariant(const type::PosePtr&) {}
+    void ConstVariantVisitor::visitAronVariant(const type::ImagePtr&) {}
+    void ConstVariantVisitor::visitAronVariant(const type::PointCloudPtr&) {}
+    void ConstVariantVisitor::visitAronVariant(const type::IntEnumPtr&) {}
+    void ConstVariantVisitor::visitAronVariant(const type::IntPtr&) {}
+    void ConstVariantVisitor::visitAronVariant(const type::LongPtr&) {}
+    void ConstVariantVisitor::visitAronVariant(const type::FloatPtr&) {}
+    void ConstVariantVisitor::visitAronVariant(const type::DoublePtr&) {}
+    void ConstVariantVisitor::visitAronVariant(const type::BoolPtr&) {}
+    void ConstVariantVisitor::visitAronVariant(const type::StringPtr&) {}
+    void ConstVariantVisitor::visitAronVariant(const type::TimePtr&) {}
+
     /****************************************************************************
      * RecursiveVariantVisitor
      ***************************************************************************/
diff --git a/source/RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.h b/source/RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.h
index 4f08dca8f..355b3fee2 100644
--- a/source/RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.h
+++ b/source/RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.h
@@ -40,6 +40,53 @@ namespace armarx::aron::type
         static type::Descriptor GetDescriptor(Input& n);
         type::Descriptor getDescriptor(Input& n) override;
         virtual ~ConstVariantVisitor() = default;
+
+        // Already implemented so that they cast the input and call specilized method below
+        // Override if you do not want to use the specialized methods
+        void visitObject(Input&) override;
+        void visitDict(Input&) override;
+        void visitPair(Input&) override;
+        void visitTuple(Input&) override;
+        void visitList(Input&) override;
+        void visitMatrix(Input&) override;
+        void visitNDArray(Input&) override;
+        void visitQuaternion(Input&) override;
+        void visitOrientation(Input&) override;
+        void visitPosition(Input&) override;
+        void visitPose(Input&) override;
+        void visitImage(Input&) override;
+        void visitPointCloud(Input&) override;
+        void visitIntEnum(Input&) override;
+        void visitInt(Input&) override;
+        void visitLong(Input&) override;
+        void visitFloat(Input&) override;
+        void visitDouble(Input&) override;
+        void visitBool(Input&) override;
+        void visitString(Input&) override;
+        void visitTime(Input&) override;
+
+        // Use these if you do not want to cast manually
+        virtual void visitAronVariant(const type::ObjectPtr&);
+        virtual void visitAronVariant(const type::DictPtr&);
+        virtual void visitAronVariant(const type::ListPtr&);
+        virtual void visitAronVariant(const type::PairPtr&);
+        virtual void visitAronVariant(const type::TuplePtr&);
+        virtual void visitAronVariant(const type::MatrixPtr&);
+        virtual void visitAronVariant(const type::NDArrayPtr&);
+        virtual void visitAronVariant(const type::QuaternionPtr&);
+        virtual void visitAronVariant(const type::OrientationPtr&);
+        virtual void visitAronVariant(const type::PositionPtr&);
+        virtual void visitAronVariant(const type::PosePtr&);
+        virtual void visitAronVariant(const type::PointCloudPtr&);
+        virtual void visitAronVariant(const type::ImagePtr&);
+        virtual void visitAronVariant(const type::IntEnumPtr&);
+        virtual void visitAronVariant(const type::IntPtr&);
+        virtual void visitAronVariant(const type::LongPtr&);
+        virtual void visitAronVariant(const type::TimePtr&);
+        virtual void visitAronVariant(const type::FloatPtr&);
+        virtual void visitAronVariant(const type::DoublePtr&);
+        virtual void visitAronVariant(const type::BoolPtr&);
+        virtual void visitAronVariant(const type::StringPtr&);
     };
 
     /**
-- 
GitLab