From f712c8512d086cd32f008f367e7403eeb92cb325 Mon Sep 17 00:00:00 2001
From: Fabian Peller <fabian.peller-konrad@kit.edu>
Date: Tue, 17 Oct 2023 18:17:28 +0200
Subject: [PATCH] added utility to run subskills from within a skill so that
 automatically onStopRequested and onTimeoutReached are called. Skill Proxy
 has been moved to core package of skills.

split example skills in seperate files

remove getLatesNUpdates from skillsMemory interface as the same behavior can be reached through getSkillStatusUpdates(). Added methods to coreSegment.

added skillExecutionRequest to memory when skill is asyncronolously called
---
 .../server/SkillsMemory/SkillsMemory.cpp      |  31 ++-
 .../armem/server/SkillsMemory/SkillsMemory.h  |  11 +-
 .../SkillProviderExample/CMakeLists.txt       |  10 +
 .../skills/SkillProviderExample/Callback.cpp  |  39 ++++
 .../skills/SkillProviderExample/Callback.h    |  41 ++++
 .../skills/SkillProviderExample/Chaining.cpp  |  39 ++++
 .../skills/SkillProviderExample/Chaining.h    |  40 ++++
 .../SkillProviderExample/HelloWorld.cpp       |  49 +++++
 .../skills/SkillProviderExample/HelloWorld.h  |  42 ++++
 .../SkillProviderExample/Incomplete.cpp       |  55 ++++++
 .../skills/SkillProviderExample/Incomplete.h  |  44 +++++
 .../SkillProviderExample.cpp                  | 184 ------------------
 .../SkillProviderExample.h                    |  69 +------
 .../skills/SkillProviderExample/Timeout.cpp   |  30 +++
 .../skills/SkillProviderExample/Timeout.h     |  42 ++++
 .../SkillManagerMonitorWidgetController.cpp   |  30 +--
 .../interface/skills/SkillMemoryInterface.ice |   6 +-
 .../server/segment/SkillEventSegment.cpp      |  55 ++++--
 .../server/segment/SkillEventSegment.h        |   5 +-
 .../libraries/skills/core/CMakeLists.txt      |   2 +
 .../RobotAPI/libraries/skills/core/Skill.cpp  | 131 +++++++++++--
 source/RobotAPI/libraries/skills/core/Skill.h | 130 ++++++++-----
 .../libraries/skills/core/SkillExecutionID.h  |  39 ++--
 .../libraries/skills/core/SkillProxy.cpp      | 118 +++++++++++
 .../libraries/skills/core/SkillProxy.h        |  63 ++++++
 .../manager/SkillManagerComponentPlugin.cpp   |   3 -
 .../libraries/skills/provider/CMakeLists.txt  |   2 -
 .../skills/provider/PeriodicSkill.cpp         |  24 +--
 .../provider/SkillProviderComponentPlugin.cpp |  35 +++-
 .../libraries/skills/provider/SkillProxy.cpp  |  72 -------
 .../libraries/skills/provider/SkillProxy.h    |  37 ----
 .../skills/provider/SpecializedSkillProxy.cpp |   2 +-
 .../skills/provider/SpecializedSkillProxy.h   |   6 +-
 .../detail/SkillImplementationWrapper.cpp     |  12 +-
 34 files changed, 985 insertions(+), 513 deletions(-)
 create mode 100644 source/RobotAPI/components/skills/SkillProviderExample/Callback.cpp
 create mode 100644 source/RobotAPI/components/skills/SkillProviderExample/Callback.h
 create mode 100644 source/RobotAPI/components/skills/SkillProviderExample/Chaining.cpp
 create mode 100644 source/RobotAPI/components/skills/SkillProviderExample/Chaining.h
 create mode 100644 source/RobotAPI/components/skills/SkillProviderExample/HelloWorld.cpp
 create mode 100644 source/RobotAPI/components/skills/SkillProviderExample/HelloWorld.h
 create mode 100644 source/RobotAPI/components/skills/SkillProviderExample/Incomplete.cpp
 create mode 100644 source/RobotAPI/components/skills/SkillProviderExample/Incomplete.h
 create mode 100644 source/RobotAPI/components/skills/SkillProviderExample/Timeout.cpp
 create mode 100644 source/RobotAPI/components/skills/SkillProviderExample/Timeout.h
 create mode 100644 source/RobotAPI/libraries/skills/core/SkillProxy.cpp
 create mode 100644 source/RobotAPI/libraries/skills/core/SkillProxy.h
 delete mode 100644 source/RobotAPI/libraries/skills/provider/SkillProxy.cpp
 delete mode 100644 source/RobotAPI/libraries/skills/provider/SkillProxy.h

diff --git a/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.cpp b/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.cpp
index 02cbe58ce..d77d73715 100644
--- a/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.cpp
+++ b/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.cpp
@@ -156,6 +156,16 @@ namespace armarx
         return SkillManagerComponentPluginUser::executeSkill(info, current);
     }
 
+    skills::manager::dto::SkillExecutionID
+    SkillsMemory::executeSkillAsync(const skills::manager::dto::SkillExecutionRequest& info,
+                                    const Ice::Current& current)
+    {
+        auto e = skills::SkillExecutionRequest::FromIce(info);
+        skillExecutionRequestCoreSegment.addSkillExecutionRequest(e);
+
+        return SkillManagerComponentPluginUser::executeSkillAsync(info, current);
+    }
+
     void
     SkillsMemory::updateStatusForSkill(const skills::provider::dto::SkillStatusUpdate& update,
                                        const skills::callback::dto::ProviderID& providerId,
@@ -166,14 +176,27 @@ namespace armarx
         skillEventCoreSegment.addSkillUpdateEvent(u);
     }
 
+    IceUtil::Optional<skills::manager::dto::SkillStatusUpdate>
+    SkillsMemory::getSkillExecutionStatus(const skills::manager::dto::SkillExecutionID& executionId,
+                                          const Ice::Current& current)
+    {
+        auto eid = skills::SkillExecutionID::FromIce(executionId);
+        auto op = this->skillEventCoreSegment.getSkillStatusUpdate(eid);
+        if (op.has_value())
+        {
+            return op->toManagerIce();
+        }
+        return {};
+    }
+
     skills::manager::dto::SkillStatusUpdateMap
-    SkillsMemory::getLatestSkillExecutionStatuses(int n, const Ice::Current& current)
+    SkillsMemory::getSkillExecutionStatuses(const Ice::Current& current)
     {
-        auto m = skillEventCoreSegment.getLatestSkillEvents(n);
         skills::manager::dto::SkillStatusUpdateMap ret;
-        for (const auto& [k, v] : m)
+        auto updates = this->skillEventCoreSegment.getSkillStatusUpdates();
+        for (const auto& [k, v] : updates)
         {
-            ret[k.toManagerIce()] = v.toManagerIce();
+            ret.insert({k.toManagerIce(), v.toManagerIce()});
         }
         return ret;
     }
diff --git a/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.h b/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.h
index 81109b0bd..ead9f1912 100644
--- a/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.h
+++ b/source/RobotAPI/components/armem/server/SkillsMemory/SkillsMemory.h
@@ -85,12 +85,21 @@ namespace armarx
         executeSkill(const skills::manager::dto::SkillExecutionRequest& info,
                      const Ice::Current& current) override;
 
+
+        skills::manager::dto::SkillExecutionID
+        executeSkillAsync(const skills::manager::dto::SkillExecutionRequest& info,
+                          const Ice::Current& current) override;
+
         void updateStatusForSkill(const skills::provider::dto::SkillStatusUpdate& update,
                                   const skills::callback::dto::ProviderID& id,
                                   const Ice::Current& current) override;
 
+        IceUtil::Optional<skills::manager::dto::SkillStatusUpdate>
+        getSkillExecutionStatus(const skills::manager::dto::SkillExecutionID& executionId,
+                                const Ice::Current& current) override;
+
         skills::manager::dto::SkillStatusUpdateMap
-        getLatestSkillExecutionStatuses(int n, const Ice::Current& current) override;
+        getSkillExecutionStatuses(const Ice::Current& current) override;
 
         // WritingInterface interface
         armem::data::CommitResult commit(const armem::data::Commit& commit,
diff --git a/source/RobotAPI/components/skills/SkillProviderExample/CMakeLists.txt b/source/RobotAPI/components/skills/SkillProviderExample/CMakeLists.txt
index afbb7ef2a..b13f663e2 100644
--- a/source/RobotAPI/components/skills/SkillProviderExample/CMakeLists.txt
+++ b/source/RobotAPI/components/skills/SkillProviderExample/CMakeLists.txt
@@ -13,10 +13,20 @@ set(COMPONENT_LIBS
 
 set(SOURCES
     SkillProviderExample.cpp
+    HelloWorld.cpp
+    Incomplete.cpp
+    Chaining.cpp
+    Callback.cpp
+    Timeout.cpp
 )
 
 set(HEADERS
     SkillProviderExample.h
+    HelloWorld.h
+    Incomplete.h
+    Chaining.h
+    Callback.h
+    Timeout.h
 )
 
 armarx_add_component("${SOURCES}" "${HEADERS}")
diff --git a/source/RobotAPI/components/skills/SkillProviderExample/Callback.cpp b/source/RobotAPI/components/skills/SkillProviderExample/Callback.cpp
new file mode 100644
index 000000000..d13f3bb8d
--- /dev/null
+++ b/source/RobotAPI/components/skills/SkillProviderExample/Callback.cpp
@@ -0,0 +1,39 @@
+
+#include "Callback.h"
+
+namespace armarx::skills::provider
+{
+    CallbackSkill::CallbackSkill() : SimpleSkill(GetSkillDescription())
+    {
+    }
+
+    SkillDescription
+    CallbackSkill::GetSkillDescription()
+    {
+        return SkillDescription{{"ShowMeCallbacks"},
+                                "This skill does shows callbacks",
+                                {},
+                                armarx::core::time::Duration::MilliSeconds(1000),
+                                nullptr};
+    }
+
+    Skill::MainResult
+    CallbackSkill::main(const MainInput& in)
+    {
+        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"));
+
+        in.callback(skills::SkillStatus::Running, up1);
+
+        auto up2 = std::make_shared<aron::data::Dict>();
+        up2->addElement("updateInfo", std::make_shared<aron::data::String>("Update 2"));
+        in.callback(skills::SkillStatus::Running, up2);
+
+        auto up3 = std::make_shared<aron::data::Dict>();
+        up3->addElement("updateInfo", std::make_shared<aron::data::String>("Update 3"));
+        in.callback(skills::SkillStatus::Running, up3);
+
+        return {TerminatedSkillStatus::Succeeded, nullptr};
+    }
+} // namespace armarx::skills::provider
diff --git a/source/RobotAPI/components/skills/SkillProviderExample/Callback.h b/source/RobotAPI/components/skills/SkillProviderExample/Callback.h
new file mode 100644
index 000000000..c29c2b6f3
--- /dev/null
+++ b/source/RobotAPI/components/skills/SkillProviderExample/Callback.h
@@ -0,0 +1,41 @@
+
+/*
+ * 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/>.
+ *
+ * @author     Fabian Reister ( fabian dot reister at kit dot edu )
+ * @date       2021
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#pragma once
+
+
+// RobotAPI
+#include <RobotAPI/libraries/skills/provider/SimpleSkill.h>
+
+namespace armarx::skills::provider
+{
+    class CallbackSkill : public SimpleSkill
+    {
+    public:
+        CallbackSkill();
+
+        static SkillDescription GetSkillDescription();
+
+    private:
+        Skill::MainResult main(const MainInput&) final;
+    };
+} // namespace armarx::skills::provider
diff --git a/source/RobotAPI/components/skills/SkillProviderExample/Chaining.cpp b/source/RobotAPI/components/skills/SkillProviderExample/Chaining.cpp
new file mode 100644
index 000000000..c40b511a6
--- /dev/null
+++ b/source/RobotAPI/components/skills/SkillProviderExample/Chaining.cpp
@@ -0,0 +1,39 @@
+
+
+#include "Chaining.h"
+
+namespace armarx::skills::provider
+{
+
+    ChainingSkill::ChainingSkill() : SimpleSkill(GetSkillDescription())
+    {
+    }
+
+    SkillDescription
+    ChainingSkill::GetSkillDescription()
+    {
+        return SkillDescription{{"ChainingSkill"},
+                                "This skill calls the Timeout skill three times. The last "
+                                "execution is aborted due to a timeout of this skill.",
+                                {},
+                                armarx::core::time::Duration::MilliSeconds(5000),
+                                nullptr};
+    }
+
+    Skill::MainResult
+    ChainingSkill::main(const MainInput& in)
+    {
+        SkillProxy prx(manager, skills::SkillID(*getSkillId().providerId, "Timeout"));
+
+        ARMARX_INFO << "CALL PROXY FIRST TIME";
+        callSubskill(prx);
+        ARMARX_INFO << "CALL PROXY SECOND TIME";
+        callSubskill(prx);
+        ARMARX_INFO << "CALL PROXY THIRD TIME";
+        callSubskill(prx);
+
+        this->throwIfSkillShouldTerminate();
+
+        return {TerminatedSkillStatus::Succeeded, nullptr};
+    }
+} // namespace armarx::skills::provider
diff --git a/source/RobotAPI/components/skills/SkillProviderExample/Chaining.h b/source/RobotAPI/components/skills/SkillProviderExample/Chaining.h
new file mode 100644
index 000000000..991c4a5aa
--- /dev/null
+++ b/source/RobotAPI/components/skills/SkillProviderExample/Chaining.h
@@ -0,0 +1,40 @@
+
+/*
+ * 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/>.
+ *
+ * @author     Fabian Reister ( fabian dot reister at kit dot edu )
+ * @date       2021
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#pragma once
+
+// RobotAPI
+#include <RobotAPI/libraries/skills/provider/SimpleSkill.h>
+
+namespace armarx::skills::provider
+{
+    class ChainingSkill : public SimpleSkill
+    {
+    public:
+        ChainingSkill();
+
+        static SkillDescription GetSkillDescription();
+
+    private:
+        Skill::MainResult main(const MainInput&) final;
+    };
+} // namespace armarx::skills::provider
diff --git a/source/RobotAPI/components/skills/SkillProviderExample/HelloWorld.cpp b/source/RobotAPI/components/skills/SkillProviderExample/HelloWorld.cpp
new file mode 100644
index 000000000..ccfa7f31a
--- /dev/null
+++ b/source/RobotAPI/components/skills/SkillProviderExample/HelloWorld.cpp
@@ -0,0 +1,49 @@
+
+
+#include "HelloWorld.h"
+
+#include <RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.h>
+#include <RobotAPI/libraries/aron/core/type/variant/container/Object.h>
+#include <RobotAPI/libraries/aron/core/type/variant/primitive/String.h>
+
+namespace armarx::skills::provider
+{
+    HelloWorldSkill::HelloWorldSkill() :
+        SimpleSpecializedSkill<skills::Example::HelloWorldAcceptedType>(GetSkillDescription())
+    {
+    }
+
+    SkillDescription
+    HelloWorldSkill::GetSkillDescription()
+    {
+        armarx::skills::Example::HelloWorldAcceptedType root_profile_params;
+        root_profile_params.some_float = 5;
+        root_profile_params.some_int = 42;
+        root_profile_params.some_text = "YOLO";
+        root_profile_params.some_list_of_matrices.push_back(Eigen::Matrix3f::Zero());
+        root_profile_params.some_matrix = Eigen::Matrix3f::Zero();
+
+        return SkillDescription{{"HelloWorld"},
+                                "This skill logs a message on ARMARX_IMPORTANT",
+                                root_profile_params.toAron(),
+                                armarx::core::time::Duration::MilliSeconds(1000),
+                                armarx::skills::Example::HelloWorldAcceptedType::ToAronType()};
+    }
+
+    Skill::MainResult
+    HelloWorldSkill::main(const SpecializedMainInput& in)
+    {
+        ARMARX_IMPORTANT << "Hi, from the Hello World Skill.\n"
+                         << "I received the following data: \n"
+                         << aron::data::converter::AronNlohmannJSONConverter::ConvertToNlohmannJSON(
+                                in.parameters.toAron())
+                                .dump(2)
+                         << "\n"
+                         << "Type fulfilled? "
+                         << parameters->fullfillsType(
+                                armarx::skills::Example::HelloWorldAcceptedType::ToAronType())
+                         << "\n"
+                         << "(executed at: " << IceUtil::Time::now() << ")";
+        return {TerminatedSkillStatus::Succeeded, nullptr};
+    }
+} // namespace armarx::skills::provider
diff --git a/source/RobotAPI/components/skills/SkillProviderExample/HelloWorld.h b/source/RobotAPI/components/skills/SkillProviderExample/HelloWorld.h
new file mode 100644
index 000000000..840b058fb
--- /dev/null
+++ b/source/RobotAPI/components/skills/SkillProviderExample/HelloWorld.h
@@ -0,0 +1,42 @@
+
+/*
+ * 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/>.
+ *
+ * @author     Fabian Reister ( fabian dot reister at kit dot edu )
+ * @date       2021
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#pragma once
+
+// RobotAPI
+#include <RobotAPI/components/skills/SkillProviderExample/aron/HelloWorldAcceptedType.aron.generated.h>
+#include <RobotAPI/libraries/skills/provider/SimpleSpecializedSkill.h>
+
+namespace armarx::skills::provider
+{
+    // Skills:
+    class HelloWorldSkill : public SimpleSpecializedSkill<skills::Example::HelloWorldAcceptedType>
+    {
+    public:
+        HelloWorldSkill();
+
+        static SkillDescription GetSkillDescription();
+
+    private:
+        Skill::MainResult main(const SpecializedMainInput& in) final;
+    };
+} // namespace armarx::skills::provider
diff --git a/source/RobotAPI/components/skills/SkillProviderExample/Incomplete.cpp b/source/RobotAPI/components/skills/SkillProviderExample/Incomplete.cpp
new file mode 100644
index 000000000..ac9bf9af3
--- /dev/null
+++ b/source/RobotAPI/components/skills/SkillProviderExample/Incomplete.cpp
@@ -0,0 +1,55 @@
+
+
+#include "Incomplete.h"
+
+#include <RobotAPI/components/skills/SkillProviderExample/aron/HelloWorldAcceptedType.aron.generated.h>
+
+#include "HelloWorld.h"
+
+namespace armarx::skills::provider
+{
+
+    IncompleteSkill::IncompleteSkill() : SimpleSkill(GetSkillDescription())
+    {
+    }
+
+    SkillDescription
+    IncompleteSkill::GetSkillDescription()
+    {
+        auto d = HelloWorldSkill::GetSkillDescription();
+        return SkillDescription{{"IncompleteSkill"},
+                                d.description,
+                                {},
+                                d.timeout + armarx::core::time::Duration::Seconds(2),
+                                d.parametersType};
+    }
+
+    Skill::PrepareResult
+    IncompleteSkill::prepare()
+    {
+        if (!first_prepared)
+        {
+            first_prepared = true;
+
+            // set parameters after two seconds...
+            std::thread foo(
+                [&]()
+                {
+                    auto d = HelloWorldSkill::GetSkillDescription();
+                    std::this_thread::sleep_for(std::chrono::milliseconds(2000));
+                    this->setParameters(d.rootProfileDefaults);
+                });
+            foo.detach();
+        }
+
+        return {.status = ActiveOrTerminatedSkillStatus::Succeeded};
+    }
+
+    Skill::MainResult
+    IncompleteSkill::main(const MainInput& in)
+    {
+        auto s = HelloWorldSkill();
+        s.setParameters(in.parameters);
+        return s.mainOfSkill();
+    }
+} // namespace armarx::skills::provider
diff --git a/source/RobotAPI/components/skills/SkillProviderExample/Incomplete.h b/source/RobotAPI/components/skills/SkillProviderExample/Incomplete.h
new file mode 100644
index 000000000..6cf7b6e73
--- /dev/null
+++ b/source/RobotAPI/components/skills/SkillProviderExample/Incomplete.h
@@ -0,0 +1,44 @@
+
+/*
+ * 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/>.
+ *
+ * @author     Fabian Reister ( fabian dot reister at kit dot edu )
+ * @date       2021
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#pragma once
+
+// RobotAPI
+#include <RobotAPI/libraries/skills/provider/SimpleSkill.h>
+
+namespace armarx::skills::provider
+{
+
+    class IncompleteSkill : public SimpleSkill
+    {
+    public:
+        IncompleteSkill();
+
+        static SkillDescription GetSkillDescription();
+
+    private:
+        Skill::PrepareResult prepare() final;
+        Skill::MainResult main(const MainInput&) final;
+
+        std::atomic_bool first_prepared = false;
+    };
+} // namespace armarx::skills::provider
diff --git a/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.cpp b/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.cpp
index 4e82f6d7e..4230249f7 100644
--- a/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.cpp
+++ b/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.cpp
@@ -1,192 +1,8 @@
 
-
 #include "SkillProviderExample.h"
 
-#include <RobotAPI/components/skills/SkillProviderExample/aron/HelloWorldAcceptedType.aron.generated.h>
-#include <RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.h>
-#include <RobotAPI/libraries/aron/core/type/variant/container/Object.h>
-#include <RobotAPI/libraries/aron/core/type/variant/primitive/String.h>
-
 namespace armarx::skills::provider
 {
-    HelloWorldSkill::HelloWorldSkill() :
-        SimpleSpecializedSkill<skills::Example::HelloWorldAcceptedType>(GetSkillDescription())
-    {
-    }
-
-    SkillDescription
-    HelloWorldSkill::GetSkillDescription()
-    {
-        armarx::skills::Example::HelloWorldAcceptedType root_profile_params;
-        root_profile_params.some_float = 5;
-        root_profile_params.some_int = 42;
-        root_profile_params.some_text = "YOLO";
-        root_profile_params.some_list_of_matrices.push_back(Eigen::Matrix3f::Zero());
-        root_profile_params.some_matrix = Eigen::Matrix3f::Zero();
-
-        return SkillDescription{{"HelloWorld"},
-                                "This skill logs a message on ARMARX_IMPORTANT",
-                                root_profile_params.toAron(),
-                                armarx::core::time::Duration::MilliSeconds(1000),
-                                armarx::skills::Example::HelloWorldAcceptedType::ToAronType()};
-    }
-
-    Skill::MainResult
-    HelloWorldSkill::main(const SpecializedMainInput& in)
-    {
-        ARMARX_IMPORTANT << "Hi, from the Hello World Skill.\n"
-                         << "I received the following data: \n"
-                         << aron::data::converter::AronNlohmannJSONConverter::ConvertToNlohmannJSON(
-                                in.parameters.toAron())
-                                .dump(2)
-                         << "\n"
-                         << "Type fulfilled? "
-                         << parameters->fullfillsType(
-                                armarx::skills::Example::HelloWorldAcceptedType::ToAronType())
-                         << "\n"
-                         << "(executed at: " << IceUtil::Time::now() << ")";
-        return {TerminatedSkillStatus::Succeeded, nullptr};
-    }
-
-    IncompleteSkill::IncompleteSkill() : SimpleSkill(GetSkillDescription())
-    {
-    }
-
-    SkillDescription
-    IncompleteSkill::GetSkillDescription()
-    {
-        auto d = HelloWorldSkill::GetSkillDescription();
-        return SkillDescription{{"IncompleteSkill"},
-                                d.description,
-                                {},
-                                d.timeout + armarx::core::time::Duration::Seconds(2),
-                                d.parametersType};
-    }
-
-    Skill::PrepareResult
-    IncompleteSkill::prepare()
-    {
-        if (!first_prepared)
-        {
-            first_prepared = true;
-            std::thread foo(
-                [&]()
-                {
-                    auto d = HelloWorldSkill::GetSkillDescription();
-                    std::this_thread::sleep_for(std::chrono::milliseconds(2000));
-                    this->setParameters(d.rootProfileDefaults);
-                });
-            foo.detach();
-        }
-
-        auto s = HelloWorldSkill();
-        s.setParameters(this->getParameters());
-        s.mainOfSkill();
-
-        return {.status = ActiveOrTerminatedSkillStatus::Succeeded};
-    }
-
-    Skill::MainResult
-    IncompleteSkill::main(const MainInput& in)
-    {
-        auto s = HelloWorldSkill();
-        s.setParameters(in.parameters);
-        return s.mainOfSkill();
-    }
-
-    ChainingSkill::ChainingSkill() : SimpleSkill(GetSkillDescription())
-    {
-    }
-
-    SkillDescription
-    ChainingSkill::GetSkillDescription()
-    {
-        return SkillDescription{{"ChainingSkill"},
-                                "This skill calls the HelloWorld skill three times.",
-                                {},
-                                armarx::core::time::Duration::MilliSeconds(3000),
-                                nullptr};
-    }
-
-    Skill::MainResult
-    ChainingSkill::main(const MainInput& in)
-    {
-        armarx::skills::Example::HelloWorldAcceptedType exec1;
-        armarx::skills::Example::HelloWorldAcceptedType exec2;
-        armarx::skills::Example::HelloWorldAcceptedType exec3;
-
-        exec1.some_text = "Hello from the ChainingSkill 1";
-        exec2.some_text = "Hello from the ChainingSkill 2";
-        exec3.some_text = "Hello from the ChainingSkill 3";
-
-        SkillProxy skillExecPrx(
-            manager, skills::SkillID(skills::ProviderID("SkillProviderExample"), "HelloWorld"));
-
-        skillExecPrx.executeSkill(getSkillId().toString(), exec1.toAron());
-        skillExecPrx.executeSkill(getSkillId().toString(), exec2.toAron());
-        skillExecPrx.executeSkill(getSkillId().toString(), exec3.toAron());
-
-        return {TerminatedSkillStatus::Succeeded, nullptr};
-    }
-
-    TimeoutSkill::TimeoutSkill() :
-        PeriodicSkill(GetSkillDescription(), armarx::core::time::Frequency::Hertz(5))
-    {
-    }
-
-    SkillDescription
-    TimeoutSkill::GetSkillDescription()
-    {
-        return SkillDescription{{"Timeout"},
-                                "This fails with timeout reached",
-                                {},
-                                armarx::core::time::Duration::MilliSeconds(5000),
-                                nullptr};
-    }
-
-    PeriodicSkill::StepResult
-    TimeoutSkill::step()
-    {
-        // do heavy work
-        std::this_thread::sleep_for(std::chrono::milliseconds(500));
-
-        return {ActiveOrTerminatedSkillStatus::Running, nullptr};
-    }
-
-    CallbackSkill::CallbackSkill() : SimpleSkill(GetSkillDescription())
-    {
-    }
-
-    SkillDescription
-    CallbackSkill::GetSkillDescription()
-    {
-        return SkillDescription{{"ShowMeCallbacks"},
-                                "This skill does shows callbacks",
-                                {},
-                                armarx::core::time::Duration::MilliSeconds(1000),
-                                nullptr};
-    }
-
-    Skill::MainResult
-    CallbackSkill::main(const MainInput& in)
-    {
-        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"));
-
-        in.callback(skills::SkillStatus::Running, up1);
-
-        auto up2 = std::make_shared<aron::data::Dict>();
-        up2->addElement("updateInfo", std::make_shared<aron::data::String>("Update 2"));
-        in.callback(skills::SkillStatus::Running, up2);
-
-        auto up3 = std::make_shared<aron::data::Dict>();
-        up3->addElement("updateInfo", std::make_shared<aron::data::String>("Update 3"));
-        in.callback(skills::SkillStatus::Running, up3);
-
-        return {TerminatedSkillStatus::Succeeded, nullptr};
-    }
-
     SkillProviderExample::SkillProviderExample() : SkillProviderComponentPluginUser()
     {
     }
diff --git a/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.h b/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.h
index 24d607450..b8391b088 100644
--- a/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.h
+++ b/source/RobotAPI/components/skills/SkillProviderExample/SkillProviderExample.h
@@ -27,73 +27,16 @@
 #include <ArmarXCore/core/Component.h>
 
 // RobotAPI
-#include <RobotAPI/components/skills/SkillProviderExample/aron/HelloWorldAcceptedType.aron.generated.h>
-#include <RobotAPI/libraries/skills/provider/SimpleSkill.h>
-#include <RobotAPI/libraries/skills/provider/SimpleSpecializedSkill.h>
 #include <RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.h>
-#include <RobotAPI/libraries/skills/provider/SkillProxy.h>
+
+#include "Callback.h"
+#include "Chaining.h"
+#include "HelloWorld.h"
+#include "Incomplete.h"
+#include "Timeout.h"
 
 namespace armarx::skills::provider
 {
-    // Skills:
-    class HelloWorldSkill : public SimpleSpecializedSkill<skills::Example::HelloWorldAcceptedType>
-    {
-    public:
-        HelloWorldSkill();
-
-        static SkillDescription GetSkillDescription();
-
-    private:
-        Skill::MainResult main(const SpecializedMainInput& in) final;
-    };
-
-    class IncompleteSkill : public SimpleSkill
-    {
-    public:
-        IncompleteSkill();
-
-        static SkillDescription GetSkillDescription();
-
-    private:
-        Skill::PrepareResult prepare() final;
-        Skill::MainResult main(const MainInput&) final;
-
-        std::atomic_bool first_prepared = false;
-    };
-
-    class ChainingSkill : public SimpleSkill
-    {
-    public:
-        ChainingSkill();
-
-        static SkillDescription GetSkillDescription();
-
-    private:
-        Skill::MainResult main(const MainInput&) final;
-    };
-
-    class TimeoutSkill : public PeriodicSkill
-    {
-    public:
-        TimeoutSkill();
-
-        static SkillDescription GetSkillDescription();
-
-    private:
-        PeriodicSkill::StepResult step() final;
-    };
-
-    class CallbackSkill : public SimpleSkill
-    {
-    public:
-        CallbackSkill();
-
-        static SkillDescription GetSkillDescription();
-
-    private:
-        Skill::MainResult main(const MainInput&) final;
-    };
-
     /**
      * @defgroup Component-ExampleClient ExampleClient
      * @ingroup RobotAPI-Components
diff --git a/source/RobotAPI/components/skills/SkillProviderExample/Timeout.cpp b/source/RobotAPI/components/skills/SkillProviderExample/Timeout.cpp
new file mode 100644
index 000000000..270dae019
--- /dev/null
+++ b/source/RobotAPI/components/skills/SkillProviderExample/Timeout.cpp
@@ -0,0 +1,30 @@
+
+#include "Timeout.h"
+
+namespace armarx::skills::provider
+{
+
+    TimeoutSkill::TimeoutSkill() :
+        PeriodicSkill(GetSkillDescription(), armarx::core::time::Frequency::Hertz(5))
+    {
+    }
+
+    SkillDescription
+    TimeoutSkill::GetSkillDescription()
+    {
+        return SkillDescription{{"Timeout"},
+                                "This fails with timeout reached",
+                                {},
+                                armarx::core::time::Duration::MilliSeconds(2000),
+                                nullptr};
+    }
+
+    PeriodicSkill::StepResult
+    TimeoutSkill::step()
+    {
+        // do heavy work
+        std::this_thread::sleep_for(std::chrono::milliseconds(50));
+
+        return {ActiveOrTerminatedSkillStatus::Running, nullptr};
+    }
+} // namespace armarx::skills::provider
diff --git a/source/RobotAPI/components/skills/SkillProviderExample/Timeout.h b/source/RobotAPI/components/skills/SkillProviderExample/Timeout.h
new file mode 100644
index 000000000..347e216a9
--- /dev/null
+++ b/source/RobotAPI/components/skills/SkillProviderExample/Timeout.h
@@ -0,0 +1,42 @@
+
+/*
+ * 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/>.
+ *
+ * @author     Fabian Reister ( fabian dot reister at kit dot edu )
+ * @date       2021
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#pragma once
+
+
+// RobotAPI
+#include <RobotAPI/libraries/skills/provider/PeriodicSkill.h>
+
+namespace armarx::skills::provider
+{
+
+    class TimeoutSkill : public PeriodicSkill
+    {
+    public:
+        TimeoutSkill();
+
+        static SkillDescription GetSkillDescription();
+
+    private:
+        PeriodicSkill::StepResult step() final;
+    };
+} // namespace armarx::skills::provider
diff --git a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp
index b7880b87f..87450efc5 100644
--- a/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp
+++ b/source/RobotAPI/gui-plugins/SkillManagerPlugin/SkillManagerMonitorWidgetController.cpp
@@ -356,8 +356,9 @@ namespace armarx
         {
             std::scoped_lock l(updateMutex);
 
-            auto currentManagerStatuses = memory->getLatestSkillExecutionStatuses(
-                100); // we assume that there are no more than 100 new skills..
+            auto currentManagerStatuses =
+                memory
+                    ->getSkillExecutionStatuses(); // we assume that there are no more than 100 new skills..
 
             for (const auto& [k, v] : currentManagerStatuses)
             {
@@ -378,19 +379,19 @@ namespace armarx
                         // update values
                         found->setText(3,
                                        QString::fromStdString(
-                                           statusUpdate.hasBeenConstructed() ? " (\xfb) " : ""));
+                                           statusUpdate.hasBeenConstructed() ? " yes " : " no "));
                         found->setText(4,
                                        QString::fromStdString(
-                                           statusUpdate.hasBeenInitialized() ? " (\xfb) " : ""));
+                                           statusUpdate.hasBeenInitialized() ? " yes " : " no "));
                         found->setText(5,
                                        QString::fromStdString(
-                                           statusUpdate.hasBeenPrepared() ? " (\xfb) " : ""));
+                                           statusUpdate.hasBeenPrepared() ? " yes " : " no "));
                         found->setText(6,
                                        QString::fromStdString(
-                                           statusUpdate.hasBeenRunning() ? " (\xfb) " : ""));
+                                           statusUpdate.hasBeenRunning() ? " yes " : " no "));
                         found->setText(7,
                                        QString::fromStdString(
-                                           statusUpdate.hasBeenTerminated() ? " (\xfb) " : ""));
+                                           statusUpdate.hasBeenTerminated() ? " yes " : " no "));
                         break;
                     }
                 }
@@ -408,18 +409,19 @@ namespace armarx
                     item->setText(2, QString::fromStdString(executionId.skillId.toString()));
                     item->setText(3,
                                   QString::fromStdString(
-                                      statusUpdate.hasBeenConstructed() ? " (\xfb) " : ""));
+                                      statusUpdate.hasBeenConstructed() ? " yes " : " no "));
                     item->setText(4,
                                   QString::fromStdString(
-                                      statusUpdate.hasBeenInitialized() ? " (\xfb) " : ""));
+                                      statusUpdate.hasBeenInitialized() ? " yes " : " no "));
                     item->setText(
                         5,
-                        QString::fromStdString(statusUpdate.hasBeenPrepared() ? " (\xfb) " : ""));
+                        QString::fromStdString(statusUpdate.hasBeenPrepared() ? " yes " : " no "));
                     item->setText(
-                        6, QString::fromStdString(statusUpdate.hasBeenRunning() ? " (\xfb) " : ""));
-                    item->setText(
-                        7,
-                        QString::fromStdString(statusUpdate.hasBeenTerminated() ? " (\xfb) " : ""));
+                        6,
+                        QString::fromStdString(statusUpdate.hasBeenRunning() ? " yes " : " no "));
+                    item->setText(7,
+                                  QString::fromStdString(
+                                      statusUpdate.hasBeenTerminated() ? " yes " : " no "));
                 }
             }
         }
diff --git a/source/RobotAPI/interface/skills/SkillMemoryInterface.ice b/source/RobotAPI/interface/skills/SkillMemoryInterface.ice
index 934d2faba..3d0d8ee61 100644
--- a/source/RobotAPI/interface/skills/SkillMemoryInterface.ice
+++ b/source/RobotAPI/interface/skills/SkillMemoryInterface.ice
@@ -36,11 +36,7 @@ module armarx
         module dti
         {
             interface SkillMemoryInterface extends armem::server::MemoryInterface,
-                dti::StatechartListenerInterface, manager::dti::SkillManagerInterface
-            {
-                manager::dto::SkillStatusUpdateMap getLatestSkillExecutionStatuses(
-                    int n); // returns latest n statusupdates of all providers
-            };
+                dti::StatechartListenerInterface, manager::dti::SkillManagerInterface{};
         }
     }
 }
diff --git a/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.cpp b/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.cpp
index d50fcba80..11dc8d0df 100644
--- a/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.cpp
+++ b/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.cpp
@@ -53,39 +53,58 @@ namespace armarx::skills::segment
     }
 
     std::map<skills::SkillExecutionID, skills::SkillStatusUpdate>
-    SkillEventCoreSegment::getLatestSkillEvents(int n)
+    SkillEventCoreSegment::getSkillStatusUpdates()
     {
         std::map<skills::SkillExecutionID, skills::SkillStatusUpdate> ret;
         auto coreSegment = this->segmentPtr;
         ARMARX_CHECK(coreSegment);
 
-        // 1. get all events and sort them by timestamp.
-        std::vector<skills::SkillStatusUpdate> sorted;
         coreSegment->forEachInstance(
-            [&sorted](const armem::wm::EntityInstance& i)
+            [&](const armem::wm::EntityInstance& i)
             {
                 auto event = i.dataAs<armarx::skills::arondto::SkillStatusUpdate>();
                 skills::SkillStatusUpdate up;
                 armem::fromAron(event, up);
-                sorted.emplace_back(std::move(up));
+
+                if (auto it = ret.find(up.executionId); it != ret.end() && up < it->second)
+                {
+                    return;
+                }
+
+                // set or replace
+                ret[up.executionId] = up;
             });
 
-        std::sort(sorted.begin(),
-                  sorted.end(),
-                  [](const skills::SkillStatusUpdate& a, const skills::SkillStatusUpdate& b)
-                  { return b < a; });
+        //        for (const auto& [k, v] : ret)
+        //        {
+        //            ARMARX_IMPORTANT << "Skill " << k.skillId << " has stati: " << int(v.status);
+        //        }
 
-        for (const auto& el : sorted)
-        {
-            if (ret.size() >= (size_t)n)
-            {
-                break;
-            }
+        return ret;
+    }
 
-            ret.emplace(
-                std::piecewise_construct, std::make_tuple(el.executionId), std::make_tuple(el));
-        }
+    std::optional<skills::SkillStatusUpdate>
+    SkillEventCoreSegment::getSkillStatusUpdate(const skills::SkillExecutionID& id)
+    {
+        std::optional<skills::SkillStatusUpdate> ret = std::nullopt;
+        auto coreSegment = this->segmentPtr;
+        ARMARX_CHECK(coreSegment);
 
+        coreSegment->forEachInstance(
+            [&](const armem::wm::EntityInstance& i)
+            {
+                auto event = i.dataAs<armarx::skills::arondto::SkillStatusUpdate>();
+                skills::SkillStatusUpdate up;
+                armem::fromAron(event, up);
+
+                if (up.executionId == id)
+                {
+                    if (!ret || (ret.has_value() && *ret < up))
+                    {
+                        ret = up;
+                    }
+                }
+            });
         return ret;
     }
 } // namespace armarx::skills::segment
diff --git a/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.h b/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.h
index 492c26090..0537cbdbd 100644
--- a/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.h
+++ b/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.h
@@ -27,7 +27,10 @@ namespace armarx::skills::segment
 
         void addSkillUpdateEvent(const skills::SkillStatusUpdate& update);
 
-        std::map<skills::SkillExecutionID, skills::SkillStatusUpdate> getLatestSkillEvents(int n);
+        std::map<skills::SkillExecutionID, skills::SkillStatusUpdate> getSkillStatusUpdates();
+
+        std::optional<skills::SkillStatusUpdate>
+        getSkillStatusUpdate(const skills::SkillExecutionID& id);
 
     private:
     };
diff --git a/source/RobotAPI/libraries/skills/core/CMakeLists.txt b/source/RobotAPI/libraries/skills/core/CMakeLists.txt
index 66795b7ec..29145e60e 100644
--- a/source/RobotAPI/libraries/skills/core/CMakeLists.txt
+++ b/source/RobotAPI/libraries/skills/core/CMakeLists.txt
@@ -24,6 +24,7 @@ armarx_add_library(
         SkillPreparationInput.cpp
         SkillParameterization.cpp
         Skill.cpp
+        SkillProxy.cpp
         SkillDescription.cpp
     HEADERS
         error/Exception.h
@@ -36,6 +37,7 @@ armarx_add_library(
         SkillPreparationInput.h
         SkillParameterization.h
         Skill.h
+        SkillProxy.h
         SkillDescription.h
 )
 
diff --git a/source/RobotAPI/libraries/skills/core/Skill.cpp b/source/RobotAPI/libraries/skills/core/Skill.cpp
index 7d8d9b9c8..34895c906 100644
--- a/source/RobotAPI/libraries/skills/core/Skill.cpp
+++ b/source/RobotAPI/libraries/skills/core/Skill.cpp
@@ -14,16 +14,76 @@ namespace armarx
         void
         Skill::installConditionWithCallback(std::function<bool()>&& f, std::function<void()>&& cb)
         {
-            std::lock_guard l(conditionCallbacksMutex);
+            std::scoped_lock l(conditionCallbacksMutex);
             conditionCallbacks.push_back({f, cb});
         }
 
+        std::optional<TerminatedSkillStatusUpdate>
+        Skill::callSubskill(const SkillProxy& prx, const aron::data::DictPtr& params)
+        {
+            auto eid = callSubskillAsync(prx, params);
+            auto ret = prx.join(eid);
+            ARMARX_IMPORTANT << "FINISHED SUBSKILL. RET IS " << ret.has_value();
+            return ret;
+        }
+
+        skills::SkillExecutionID
+        Skill::callSubskillAsync(const skills::SkillProxy& prx, const aron::data::DictPtr& params)
+        {
+            std::unique_lock l(subskillsMutex);
+
+            std::string executorHistory = this->executorName + "->" + getSkillId().toString();
+            auto eid = prx.executeSkillAsync(executorHistory, params);
+            this->subskills.push_back(eid);
+            return eid;
+        }
+
+        void
+        Skill::updateParameters(const aron::data::DictPtr& d)
+        {
+            std::scoped_lock l(this->parametersMutex);
+            if (this->parameters == nullptr)
+            {
+                // set params as there has been no update before.
+                this->parameters = d;
+            }
+            else
+            {
+                // merge params into existing. Note that this may update already set params.
+                this->parameters->mergeAndReplaceCopy(d);
+            }
+        }
+
+        void
+        Skill::setParameters(const aron::data::DictPtr& d)
+        {
+            // we only set the params if the skill is not already running
+            if (running or exiting or finished)
+            {
+                return;
+            }
+
+            std::scoped_lock l(this->parametersMutex);
+            this->parameters = d;
+        }
+
+        aron::data::DictPtr
+        Skill::getParameters() const
+        {
+            std::scoped_lock l(this->parametersMutex);
+            return this->parameters;
+        }
+
         Skill::InitResult
         Skill::_init()
         {
             //ARMARX_IMPORTANT << "Initializing skill '" << description.skillName << "'";
             this->initializing = true;
             this->constructing = false;
+            this->preparing = false;
+            this->running = false;
+            this->exiting = false;
+            this->finished = false;
 
             // install timeout condition
             installConditionWithCallback(
@@ -36,7 +96,7 @@ namespace armarx
                 [&]()
                 {
                     armarx::core::time::Metronome metronome(conditionCheckingThreadFrequency);
-                    while (constructing or initializing or preparing or
+                    while (initializing or preparing or
                            running) // when the skill ends/aborts this variable will be set to false
                     {
                         {
@@ -51,13 +111,15 @@ namespace armarx
                                 }
                             }
                         }
+
                         const auto sleepDuration = metronome.waitForNextTick();
                         if (not sleepDuration.isPositive())
                         {
-                            ARMARX_WARNING
-                                << deactivateSpam() << "PeriodicSkill: execution took too long ("
-                                << -sleepDuration << " vs "
-                                << conditionCheckingThreadFrequency.toCycleDuration() << ")";
+                            ARMARX_WARNING << deactivateSpam()
+                                           << "ConditionCheckingThread: execution took too long ("
+                                           << -sleepDuration << " vs "
+                                           << conditionCheckingThreadFrequency.toCycleDuration()
+                                           << ")";
                         }
                     }
                 });
@@ -69,6 +131,10 @@ namespace armarx
         {
             this->preparing = true;
             this->initializing = false;
+            this->constructing = false;
+            this->running = false;
+            this->exiting = false;
+            this->finished = false;
 
             if (shouldSkillTerminate())
             {
@@ -94,7 +160,11 @@ namespace armarx
         Skill::_main()
         {
             this->running = true;
+            this->initializing = false;
+            this->constructing = false;
             this->preparing = false;
+            this->exiting = false;
+            this->finished = false;
             return {.status = TerminatedSkillStatus::Succeeded};
         }
 
@@ -102,16 +172,21 @@ namespace armarx
         Skill::_exit()
         {
             // ARMARX_IMPORTANT << "Exiting Skill '" << description.skillName << "'";
+            this->exiting = true;
             this->running = false;
             this->initializing = false;
             this->constructing = false;
             this->preparing = false;
+            this->finished = false;
 
             if (conditionCheckingThread.joinable())
             {
                 conditionCheckingThread.join();
             }
             exited = armarx::core::time::DateTime::Now();
+
+            this->finished = true;
+            this->exiting = false;
             return {.status = TerminatedSkillStatus::Succeeded};
         }
 
@@ -152,13 +227,6 @@ namespace armarx
             return {.status = skills::mergeSkillStatuseses(_res.status, res.status)};
         }
 
-        void
-        Skill::notifyTimeoutReached()
-        {
-            timeoutReached = true;
-            onTimeoutReached();
-        }
-
         void
         Skill::throwIfSkillShouldTerminate(const std::function<void()>& do_before,
                                            const std::string& abortedMessage)
@@ -224,10 +292,21 @@ namespace armarx
         void
         Skill::notifySkillToStop()
         {
+            std::scoped_lock l(subskillsMutex);
             stopped = true;
+            _onStopRequested();
             onStopRequested();
         }
 
+        void
+        Skill::notifyTimeoutReached()
+        {
+            std::scoped_lock l(subskillsMutex);
+            timeoutReached = true;
+            _onTimeoutReached();
+            onTimeoutReached();
+        }
+
         bool
         Skill::shouldSkillTerminate() const
         {
@@ -235,6 +314,32 @@ namespace armarx
         }
 
         // condition effects
+        void
+        Skill::_onTimeoutReached()
+        {
+            if (!manager)
+            {
+                return;
+            }
+            for (const auto& execId : subskills)
+            {
+                manager->abortSkillAsync(execId.toManagerIce());
+            }
+        }
+
+        void
+        Skill::_onStopRequested()
+        {
+            if (!manager)
+            {
+                return;
+            }
+            for (const auto& execId : subskills)
+            {
+                manager->abortSkillAsync(execId.toManagerIce());
+            }
+        }
+
         void
         Skill::onTimeoutReached()
         {
diff --git a/source/RobotAPI/libraries/skills/core/Skill.h b/source/RobotAPI/libraries/skills/core/Skill.h
index ff3cf1e82..5ec80e77d 100644
--- a/source/RobotAPI/libraries/skills/core/Skill.h
+++ b/source/RobotAPI/libraries/skills/core/Skill.h
@@ -19,6 +19,7 @@
 #include "SkillDescription.h"
 #include "SkillID.h"
 #include "SkillPreparationInput.h"
+#include "SkillProxy.h"
 #include "SkillStatusUpdate.h"
 #include "error/Exception.h"
 
@@ -32,95 +33,112 @@ namespace armarx
             using CallbackT =
                 std::function<void(const SkillStatus s, const armarx::aron::data::DictPtr&)>;
 
+            /// A result struct for skill initialization
             struct InitResult
             {
                 TerminatedSkillStatus status;
             };
 
+            /// A result struct for skill preparing
             struct PrepareResult
             {
                 ActiveOrTerminatedSkillStatus status;
             };
 
+            /// A result struct for th main method of a skill
             struct MainResult
             {
                 TerminatedSkillStatus status;
                 aron::data::DictPtr data = nullptr;
             };
 
+            /// A result struct for skill exit function
             struct ExitResult
             {
                 TerminatedSkillStatus status;
             };
 
+            /// We completely remove the default constructor! A skill without a desciption cannot exist
             Skill() = delete;
+
+            /// Constructor of a skill for inheritance. Every skill must have a skill description
             Skill(const SkillDescription&);
-            virtual ~Skill() = default;
 
-            /// The id of the skill (combination of provider and name must be unique).
+            /// Virtual destructor of a skill
+            virtual ~Skill()
+            {
+                //ARMARX_IMPORTANT << "DESTROY SKILL " << getSkillId();
+            }
+
+            /// Get the id of the skill
             SkillID
             getSkillId() const
             {
                 return description.skillId;
             }
 
+            /// Get the description of a skill
             SkillDescription
             getSkillDescription() const
             {
                 return description;
             }
 
+            /// Set the provider id of the description of the skill.
+            /// This method is called when creating a skill in a skill provider
             void
             setProviderId(const skills::ProviderID& pid)
             {
                 description.skillId.providerId = pid;
             }
 
+            void
+            setCallback(const CallbackT& callback)
+            {
+                this->callback = callback;
+            }
+
+            void
+            setManager(const manager::dti::SkillManagerInterfacePrx& manager)
+            {
+                this->manager = manager;
+            }
+
+            void
+            setExecutorName(const std::string& executorName)
+            {
+                this->executorName = executorName;
+            }
+
+            /// Prepare a skill once. This method is called in a loop as long as it returns RUNNING
+            /// If the loop does not terminate with SUCCEDED the skill execution is failed.
             PrepareResult prepareSkill();
 
+            /// Initialization of a skill. Called directly after construction.
+            /// If this method does not return SUCCEEDED the skill execution is failed.
             InitResult initSkill();
 
+            /// Main method of a skill.
             MainResult mainOfSkill();
 
+            /// Exit method of a skill. It is guaranteed that exit is always called
+            /// (unless there is a segfault or similar)
             ExitResult exitSkill();
 
-            // Condition listeners
-            // used to notify the skill from extern to stop
+            /// Notify the skill from extern to stop
             void notifySkillToStop();
 
-            // returns whether the skill should terminate as soon as possible
+            /// Returns whether the skill should terminate as soon as possible
             bool shouldSkillTerminate() const;
 
-            // merge parameters to the local parameters of the skill
-            void
-            updateParameters(const aron::data::DictPtr& d)
-            {
-                std::scoped_lock l(this->parametersMutex);
-                if (this->parameters == nullptr)
-                {
-                    this->parameters = d;
-                }
-                else
-                {
-                    this->parameters->mergeAndReplaceCopy(d);
-                }
-            }
+            /// Merge parameters to the local parameters of the skill
+            void updateParameters(const aron::data::DictPtr& d);
 
-            // hard set the parameters, ignoring everything that has been set or merged before
-            void
-            setParameters(const aron::data::DictPtr& d)
-            {
-                std::scoped_lock l(this->parametersMutex);
-                this->parameters = d;
-            }
+            /// Hard set the parameters, ignoring everything that has been set or merged before
+            void setParameters(const aron::data::DictPtr& d);
 
-            // get the parameters
-            aron::data::DictPtr
-            getParameters() const
-            {
-                std::scoped_lock l(this->parametersMutex);
-                return this->parameters;
-            }
+            /// Get the parameters of a skill that have been set so far
+            aron::data::DictPtr getParameters() const;
 
         protected:
             void throwIfSkillShouldTerminate(const std::string& abortedMessage = "");
@@ -134,12 +152,17 @@ namespace armarx
             // fires if the skill reaches timeout
             void notifyTimeoutReached();
 
+        private:
             // helper methods to do all the static initialization stuff
             InitResult _init();
             PrepareResult _prepare();
             MainResult _main();
             ExitResult _exit();
 
+            void _onTimeoutReached();
+            void _onStopRequested();
+
+        protected:
             /// Override this method with the actual implementation.
             virtual InitResult init();
 
@@ -152,7 +175,7 @@ namespace armarx
             /// Override this method with the actual implementation.
             virtual ExitResult exit();
 
-        private:
+        protected:
             /// Override these methods if you want to do something special when notification comes
             virtual void onTimeoutReached();
             virtual void onStopRequested();
@@ -162,35 +185,42 @@ namespace armarx
             void installConditionWithCallback(std::function<bool()>&& f,
                                               std::function<void()>&& cb);
 
+            /// call a subskill and block until the subskill terminates.
+            /// If you call a subskill this way it will be stopped if the current skill stops.
+            std::optional<TerminatedSkillStatusUpdate>
+            callSubskill(const skills::SkillProxy& prx, const aron::data::DictPtr& = nullptr);
+
+            /// Similar to callSubskill but non-blocking
+            skills::SkillExecutionID callSubskillAsync(const skills::SkillProxy& prx,
+                                                       const aron::data::DictPtr& = nullptr);
+
         public:
             // running params
             armarx::core::time::DateTime started = armarx::core::time::DateTime::Now();
             armarx::core::time::DateTime exited = armarx::core::time::DateTime::Invalid();
 
-            // parameterization. Will be set from implementation wrapper.
-            // const params after initialization!!
-            CallbackT callback;
+        protected:
+            // parameterization. Will be set from implementation wrapper. No getters available
+            // const after construction!!
+            CallbackT callback = CallbackT();
             manager::dti::SkillManagerInterfacePrx manager = nullptr;
-            std::string executorName = "INVALID EXECUTOR NAME";
+            std::string executorName = "";
 
         protected:
-            // non-const params
+            // non-const params. Const after preparation. Getters are available
             mutable std::mutex parametersMutex;
             armarx::aron::data::DictPtr parameters = nullptr;
 
             // The descripion of the skill
             SkillDescription description;
 
-            // active conditions. First is condition (bool return func)
-            mutable std::mutex conditionCallbacksMutex;
-            std::vector<std::pair<std::function<bool()>, std::function<void()>>>
-                conditionCallbacks = {};
-
-            // Status variables.
+            // Status variables
             std::atomic_bool constructing = true;
             std::atomic_bool initializing = false;
             std::atomic_bool preparing = false;
             std::atomic_bool running = false;
+            std::atomic_bool exiting = false;
+            std::atomic_bool finished = false;
 
             // Conditionals to indicate that an event has occured. Use conditions this way
             std::atomic_bool stopped = false;
@@ -198,8 +228,16 @@ namespace armarx
 
 
         private:
-            std::thread conditionCheckingThread; // A therad that checks the conditions frequently
+            // active conditions. First is condition (bool return func)
+            mutable std::mutex conditionCallbacksMutex;
+            std::vector<std::pair<std::function<bool()>, std::function<void()>>>
+                conditionCallbacks = {};
+
+            std::thread conditionCheckingThread; // A thread that checks the conditions frequently
             armarx::Frequency conditionCheckingThreadFrequency = armarx::Frequency::Hertz(20);
+
+            mutable std::mutex subskillsMutex;
+            std::vector<skills::SkillExecutionID> subskills;
         };
 
         template <class T>
diff --git a/source/RobotAPI/libraries/skills/core/SkillExecutionID.h b/source/RobotAPI/libraries/skills/core/SkillExecutionID.h
index f639b4b4e..6d9975bb4 100644
--- a/source/RobotAPI/libraries/skills/core/SkillExecutionID.h
+++ b/source/RobotAPI/libraries/skills/core/SkillExecutionID.h
@@ -18,10 +18,6 @@ namespace armarx
     {
         struct SkillExecutionID
         {
-            SkillID skillId;
-            std::string executorName;
-            armarx::core::time::DateTime executionStartedTime;
-
             SkillExecutionID() = default;
             SkillExecutionID(const SkillID&,
                              const std::string& executorName,
@@ -30,26 +26,26 @@ namespace armarx
             bool
             operator==(const SkillExecutionID& other) const
             {
-                if (skillId != other.skillId)
-                {
-                    return false;
-                }
-                if (executionStartedTime != other.executionStartedTime)
-                {
-                    return false;
-                }
-                if (executorName != other.executorName)
-                {
-                    return false;
-                }
-                return true;
+                return this->toString() == other.toString();
             }
 
             bool
             operator<(const SkillExecutionID& other) const
             {
-                // We explicitly do not compare skillIds as we ONLY want to bring the executionids in some (temporal) order
-                return executionStartedTime < other.executionStartedTime;
+                return this->toString() < other.toString();
+            }
+
+            bool
+            operator<=(const SkillExecutionID& other) const
+            {
+                return this->toString() <= other.toString();
+            }
+
+            std::string
+            toString() const
+            {
+                return skillId.toString() + " requested by " + executorName + " at " +
+                       executionStartedTime.toDateTimeString();
             }
 
             skills::manager::dto::SkillExecutionID toManagerIce() const;
@@ -60,6 +56,11 @@ namespace armarx
 
             static SkillExecutionID FromIce(const skills::provider::dto::SkillExecutionID&,
                                             const std::optional<skills::ProviderID>& providerName);
+
+
+            SkillID skillId;
+            std::string executorName;
+            armarx::core::time::DateTime executionStartedTime;
         };
 
     } // namespace skills
diff --git a/source/RobotAPI/libraries/skills/core/SkillProxy.cpp b/source/RobotAPI/libraries/skills/core/SkillProxy.cpp
new file mode 100644
index 000000000..f73c43dfd
--- /dev/null
+++ b/source/RobotAPI/libraries/skills/core/SkillProxy.cpp
@@ -0,0 +1,118 @@
+#include "SkillProxy.h"
+
+#include <chrono>
+#include <thread>
+
+namespace armarx
+{
+    namespace skills
+    {
+        SkillProxy::SkillProxy(const manager::dti::SkillManagerInterfacePrx& manager,
+                               const SkillID& skillId) :
+            manager(manager)
+        {
+            ARMARX_CHECK_NOT_NULL(manager);
+            skillDescription = SkillDescription::FromIce(
+                manager->getSkillDescription(skillId.toManagerIce()).value());
+            ARMARX_CHECK(skillDescription.skillId.isFullySpecified());
+        }
+
+        SkillProxy::SkillProxy(const manager::dti::SkillManagerInterfacePrx& manager,
+                               const SkillDescription& skillDesc) :
+            manager(manager), skillDescription(skillDesc)
+        {
+            ARMARX_CHECK_NOT_NULL(manager);
+            ARMARX_CHECK(skillDesc.skillId.isFullySpecified());
+        }
+
+        SkillDescription
+        SkillProxy::getSkillDescription() const
+        {
+            return skillDescription;
+        }
+
+        SkillID
+        SkillProxy::getSkillId() const
+        {
+            return skillDescription.skillId;
+        }
+
+        TerminatedSkillStatusUpdate
+        SkillProxy::executeSkill(const std::string& executorName,
+                                 const aron::data::DictPtr& params) const
+        {
+            ARMARX_CHECK_NOT_NULL(manager);
+            skills::manager::dto::SkillExecutionRequest req;
+            req.executorName = executorName;
+            req.parameters = aron::data::Dict::ToAronDictDTO(params);
+            req.skillId = skillDescription.skillId.toManagerIce();
+
+            auto terminatingUpdateIce = manager->executeSkill(req);
+            return TerminatedSkillStatusUpdate::FromIce(terminatingUpdateIce);
+        }
+
+        SkillExecutionID
+        SkillProxy::executeSkillAsync(const std::string& executorName,
+                                      const aron::data::DictPtr& params) const
+        {
+            ARMARX_CHECK_NOT_NULL(manager);
+            skills::manager::dto::SkillExecutionRequest req;
+            req.executorName = executorName;
+            req.parameters = aron::data::Dict::ToAronDictDTO(params);
+            req.skillId = skillDescription.skillId.toManagerIce();
+
+            auto execIdIce = manager->executeSkillAsync(req);
+            return SkillExecutionID::FromIce(execIdIce);
+        }
+
+        std::optional<TerminatedSkillStatusUpdate>
+        SkillProxy::join(const SkillExecutionID& executionId) const
+        {
+            ARMARX_CHECK_NOT_NULL(manager);
+            auto s = this->manager->getSkillExecutionStatus(executionId.toManagerIce());
+
+            while (s)
+            {
+                auto statusUpdate = skills::SkillStatusUpdate::FromIce(*s);
+
+                if (statusUpdate.hasBeenTerminated())
+                {
+                    break;
+                }
+
+                std::this_thread::sleep_for(std::chrono::milliseconds(50));
+                s = this->manager->getSkillExecutionStatus(executionId.toManagerIce());
+            }
+
+            if (!s)
+            {
+                // Either the manager already removed the result (then it is unknown) or the execution id does not exist.
+                return std::nullopt;
+            }
+
+            return TerminatedSkillStatusUpdate::FromIce(*s);
+        }
+
+        bool
+        SkillProxy::abortSkill(const SkillExecutionID& id) const
+        {
+            ARMARX_CHECK_NOT_NULL(manager);
+            auto r = manager->abortSkill(id.toManagerIce());
+            return r.success;
+        }
+
+        bool
+        SkillProxy::abortSkillAsync(const SkillExecutionID& id) const
+        {
+            ARMARX_CHECK_NOT_NULL(manager);
+            auto r = manager->abortSkillAsync(id.toManagerIce());
+            return r.success;
+        }
+
+        aron::data::DictPtr
+        SkillProxy::getRootProfileParameters() const
+        {
+            return skillDescription.rootProfileDefaults;
+        }
+    } // namespace skills
+} // namespace armarx
diff --git a/source/RobotAPI/libraries/skills/core/SkillProxy.h b/source/RobotAPI/libraries/skills/core/SkillProxy.h
new file mode 100644
index 000000000..e20ca01a0
--- /dev/null
+++ b/source/RobotAPI/libraries/skills/core/SkillProxy.h
@@ -0,0 +1,63 @@
+#pragma once
+
+#include <RobotAPI/libraries/skills/core/SkillDescription.h>
+#include <RobotAPI/libraries/skills/core/SkillStatusUpdate.h>
+
+namespace armarx
+{
+    namespace skills
+    {
+        /* Manages the remote execution of a skill and converts the ice types */
+        class SkillProxy : public armarx::Logging
+        {
+        public:
+            /// We remove the default constructor as every skill proxy requires a manager
+            SkillProxy() = delete;
+
+            /// set the skill proxy using a skillId. Queries the manager to get the description.
+            SkillProxy(const manager::dti::SkillManagerInterfacePrx& manager,
+                       const SkillID& skillId);
+
+            /// set the proxy using a skill description
+            SkillProxy(const manager::dti::SkillManagerInterfacePrx& manager,
+                       const SkillDescription& skillDesc);
+
+            /// copy ctor
+            SkillProxy(const SkillProxy& o) = default;
+
+            /// get the skill description
+            SkillDescription getSkillDescription() const;
+
+            /// get the skill id from the skill description
+            SkillID getSkillId() const;
+
+            // Provide a similar API as the skillprovider
+            /// execute a skill and block until skill terminates
+            TerminatedSkillStatusUpdate
+            executeSkill(const std::string& executorName,
+                         const aron::data::DictPtr& params = nullptr) const;
+
+            /// execute a skill. Do not block during execution
+            SkillExecutionID executeSkillAsync(const std::string& executorName,
+                                               const aron::data::DictPtr& params = nullptr) const;
+
+            /// poll execution status and block until its null or terminated
+            std::optional<TerminatedSkillStatusUpdate>
+            join(const SkillExecutionID& executionId) const;
+
+            /// ask skill to abort ASAP. Blocks until skill stopped
+            bool abortSkill(const SkillExecutionID& executionId) const;
+
+            /// ask skill to abort ASAP
+            bool abortSkillAsync(const SkillExecutionID& executionId) const;
+
+            // Utiliy methods
+            /// get the default parameters of the skill. TODO: Skill profiles in memory!
+            aron::data::DictPtr getRootProfileParameters() const;
+
+        protected:
+            manager::dti::SkillManagerInterfacePrx manager;
+            SkillDescription skillDescription;
+        };
+    } // namespace skills
+} // namespace armarx
diff --git a/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.cpp b/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.cpp
index 4b7cdec1b..233aa841b 100644
--- a/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.cpp
+++ b/source/RobotAPI/libraries/skills/manager/SkillManagerComponentPlugin.cpp
@@ -580,9 +580,6 @@ namespace armarx
         this->plugin->removeProvider(i);
     }
 
-    using SkillProviderInterfacePrxMap =
-        std::map<std::string, skills::provider::dti::SkillProviderInterfacePrx>;
-
     skills::manager::dto::SkillStatusUpdate
     SkillManagerComponentPluginUser::executeSkill(
         const skills::manager::dto::SkillExecutionRequest& info,
diff --git a/source/RobotAPI/libraries/skills/provider/CMakeLists.txt b/source/RobotAPI/libraries/skills/provider/CMakeLists.txt
index 5ccff9120..fba16f3e7 100644
--- a/source/RobotAPI/libraries/skills/provider/CMakeLists.txt
+++ b/source/RobotAPI/libraries/skills/provider/CMakeLists.txt
@@ -21,7 +21,6 @@ armarx_add_library(
         LambdaSkill.cpp
         SimpleSkill.cpp
         SimpleSpecializedSkill.cpp
-        SkillProxy.cpp
         SpecializedSkillProxy.cpp
         PeriodicSkill.cpp
         SpecializedSkill.cpp
@@ -36,7 +35,6 @@ armarx_add_library(
         LambdaSkill.h
         SimpleSkill.h
         SimpleSpecializedSkill.h
-        SkillProxy.h
         SpecializedSkillProxy.h
         PeriodicSkill.h
         SpecializedSkill.h
diff --git a/source/RobotAPI/libraries/skills/provider/PeriodicSkill.cpp b/source/RobotAPI/libraries/skills/provider/PeriodicSkill.cpp
index 02ad14bc1..197159cb7 100644
--- a/source/RobotAPI/libraries/skills/provider/PeriodicSkill.cpp
+++ b/source/RobotAPI/libraries/skills/provider/PeriodicSkill.cpp
@@ -47,8 +47,10 @@ namespace armarx::skills
     {
         armarx::core::time::Metronome metronome(frequency);
 
-        while (not Skill::shouldSkillTerminate())
+        while (true)
         {
+            this->throwIfSkillShouldTerminate();
+
             const auto res = stepOfSkill();
             switch (res.status)
             {
@@ -56,11 +58,11 @@ namespace armarx::skills
                     // nothing to do here
                     break;
                 case ActiveOrTerminatedSkillStatus::Aborted:
-                    return {TerminatedSkillStatus::Aborted, res.data};
+                    return MakeAbortedResult();
                 case ActiveOrTerminatedSkillStatus::Succeeded:
-                    return {TerminatedSkillStatus::Succeeded, res.data};
+                    return MakeSucceededResult(res.data);
                 case ActiveOrTerminatedSkillStatus::Failed:
-                    return {TerminatedSkillStatus::Failed, res.data};
+                    return MakeFailedResult();
             }
 
             const auto sleepDuration = metronome.waitForNextTick();
@@ -72,18 +74,8 @@ namespace armarx::skills
             }
         }
 
-        if (stopped)
-        {
-            return {TerminatedSkillStatus::Aborted, nullptr};
-        }
-
-        if (timeoutReached)
-        {
-            ARMARX_WARNING << "The skill " << getSkillId().toString() << " reached timeout!";
-            return {TerminatedSkillStatus::Failed, nullptr};
-        }
-
-        throw skills::error::SkillException(__PRETTY_FUNCTION__, "Should not happen!");
+        // never happens
+        return MakeSucceededResult();
     }
 
     PeriodicSkill::StepResult
diff --git a/source/RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.cpp b/source/RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.cpp
index 1a5b0b0d1..e5c169c04 100644
--- a/source/RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.cpp
+++ b/source/RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.cpp
@@ -120,7 +120,7 @@ namespace armarx::plugins
         ARMARX_CHECK(execId.skillId.isSkillSpecified());
 
         const std::unique_lock l(skillExecutionsMutex);
-        if (skillExecutions.find(execId) != skillExecutions.end())
+        if (skillExecutions.find(execId) == skillExecutions.end())
         {
             ARMARX_WARNING << "Skill execution for skill '" + execId.skillId.toString() +
                                   "' not found!";
@@ -276,6 +276,21 @@ namespace armarx::plugins
                 });
         }
 
+        // wait until skill is constructed. This assures, that a status update exists.
+        while (true)
+        {
+            {
+                std::scoped_lock l(wrapper->skillStatusesMutex);
+
+                if (wrapper->statusUpdate.hasBeenConstructed())
+                {
+                    break;
+                }
+            }
+
+            std::this_thread::sleep_for(std::chrono::milliseconds(20));
+        }
+
         return executionId;
     }
 
@@ -320,11 +335,21 @@ namespace armarx::plugins
             return false;
         }
 
-        it->second.stopSkill();
+        auto& runtime = it->second;
+        runtime.stopSkill();
 
-        if (auto it = skillExecutions.find(executionId); it != skillExecutions.end())
+        while (true)
         {
-            skillExecutions.erase(it);
+            {
+                std::scoped_lock l(runtime.skillStatusesMutex);
+                auto status = runtime.statusUpdate;
+
+                if (status.hasBeenTerminated())
+                {
+                    break;
+                }
+            }
+            std::this_thread::sleep_for(std::chrono::milliseconds(20));
         }
 
         return true;
@@ -344,7 +369,7 @@ namespace armarx::plugins
             return false;
         }
 
-        std::thread([&]() { it->second.stopSkill(); });
+        it->second.stopSkill();
         return true;
     }
 
diff --git a/source/RobotAPI/libraries/skills/provider/SkillProxy.cpp b/source/RobotAPI/libraries/skills/provider/SkillProxy.cpp
deleted file mode 100644
index 50758fde7..000000000
--- a/source/RobotAPI/libraries/skills/provider/SkillProxy.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-#include "SkillProxy.h"
-
-namespace armarx
-{
-    namespace skills
-    {
-        SkillProxy::SkillProxy(const manager::dti::SkillManagerInterfacePrx& manager,
-                               const SkillID& skillId) :
-            manager(manager),
-            skillDescription(SkillDescription::FromIce(
-                manager->getSkillDescription(skillId.toManagerIce()).value()))
-        {
-        }
-
-        SkillProxy::SkillProxy(const manager::dti::SkillManagerInterfacePrx& manager,
-                               const SkillDescription& skillDesc) :
-            manager(manager), skillDescription(skillDesc)
-        {
-            ARMARX_CHECK(skillDesc.skillId.isFullySpecified());
-        }
-
-        TerminatedSkillStatusUpdate
-        SkillProxy::executeSkill(const std::string& executorName, const aron::data::DictPtr& params)
-        {
-            skills::manager::dto::SkillExecutionRequest req;
-            req.executorName = executorName;
-            req.parameters = params->toAronDictDTO();
-            req.skillId = skillDescription.skillId.toManagerIce();
-
-            auto terminatingUpdateIce = manager->executeSkill(req);
-            return TerminatedSkillStatusUpdate::FromIce(terminatingUpdateIce);
-        }
-
-        SkillExecutionID
-        SkillProxy::executeSkillAsync(const std::string& executorName,
-                                      const aron::data::DictPtr& params)
-        {
-            skills::manager::dto::SkillExecutionRequest req;
-            req.executorName = executorName;
-            req.parameters = params->toAronDictDTO();
-            req.skillId = skillDescription.skillId.toManagerIce();
-
-            auto execReqIce = manager->executeSkillAsync(req);
-            return SkillExecutionID::FromIce(execReqIce);
-        }
-
-        bool
-        SkillProxy::abortSkill(const SkillExecutionID& id)
-        {
-            auto r = manager->abortSkill(id.toManagerIce());
-            return r.success;
-        }
-
-        bool
-        SkillProxy::abortSkillAsync(const SkillExecutionID& id)
-        {
-            auto r = manager->abortSkillAsync(id.toManagerIce());
-            return r.success;
-        }
-
-        aron::data::DictPtr
-        SkillProxy::getDefaultParameters(const std::string& profileName)
-        {
-            if (profileName == "root")
-            {
-                return skillDescription.rootProfileDefaults;
-            }
-            // TODO @fabianPK
-            return nullptr;
-        }
-    } // namespace skills
-} // namespace armarx
diff --git a/source/RobotAPI/libraries/skills/provider/SkillProxy.h b/source/RobotAPI/libraries/skills/provider/SkillProxy.h
deleted file mode 100644
index 8f0fb34be..000000000
--- a/source/RobotAPI/libraries/skills/provider/SkillProxy.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#pragma once
-
-#include <RobotAPI/libraries/skills/core/Skill.h>
-
-namespace armarx
-{
-    namespace skills
-    {
-        /* Manages the remote execution of a skill and converts the ice types */
-        class SkillProxy : public armarx::Logging
-        {
-        public:
-            SkillProxy(const manager::dti::SkillManagerInterfacePrx& manager,
-                       const SkillID& skillId);
-            SkillProxy(const manager::dti::SkillManagerInterfacePrx& manager,
-                       const SkillDescription& skillDesc);
-
-            // Provide a similar API as the skillprovider
-            TerminatedSkillStatusUpdate executeSkill(const std::string& executorName,
-                                                     const aron::data::DictPtr& params = nullptr);
-
-            SkillExecutionID executeSkillAsync(const std::string& executorName,
-                                               const aron::data::DictPtr& params = nullptr);
-
-            bool abortSkill(const SkillExecutionID& executorName);
-
-            bool abortSkillAsync(const SkillExecutionID& executorName);
-
-            // Utiliy methods
-            aron::data::DictPtr getDefaultParameters(const std::string& profileName = "root");
-
-        protected:
-            manager::dti::SkillManagerInterfacePrx manager;
-            SkillDescription skillDescription;
-        };
-    } // namespace skills
-} // namespace armarx
diff --git a/source/RobotAPI/libraries/skills/provider/SpecializedSkillProxy.cpp b/source/RobotAPI/libraries/skills/provider/SpecializedSkillProxy.cpp
index 1074f5499..4f372c5f5 100644
--- a/source/RobotAPI/libraries/skills/provider/SpecializedSkillProxy.cpp
+++ b/source/RobotAPI/libraries/skills/provider/SpecializedSkillProxy.cpp
@@ -1,4 +1,4 @@
-#include "SkillProxy.h"
+#include "SpecializedSkillProxy.h"
 
 namespace armarx
 {
diff --git a/source/RobotAPI/libraries/skills/provider/SpecializedSkillProxy.h b/source/RobotAPI/libraries/skills/provider/SpecializedSkillProxy.h
index 37ecd5a77..4dd53171c 100644
--- a/source/RobotAPI/libraries/skills/provider/SpecializedSkillProxy.h
+++ b/source/RobotAPI/libraries/skills/provider/SpecializedSkillProxy.h
@@ -1,6 +1,6 @@
 #pragma once
 
-#include "SkillProxy.h"
+#include <RobotAPI/libraries/skills/core/SkillProxy.h>
 
 namespace armarx
 {
@@ -27,9 +27,9 @@ namespace armarx
 
             // Utiliy methods
             AronT
-            getDefaultParameters(const std::string& profileName = "root")
+            getRootProfileParameters()
             {
-                auto dict = SkillProxy::getDefaultParameters(profileName);
+                auto dict = SkillProxy::getRootProfileParameters();
                 if (dict)
                 {
                     return AronT::FromAron(dict);
diff --git a/source/RobotAPI/libraries/skills/provider/detail/SkillImplementationWrapper.cpp b/source/RobotAPI/libraries/skills/provider/detail/SkillImplementationWrapper.cpp
index 4ac4757e2..5c20567a2 100644
--- a/source/RobotAPI/libraries/skills/provider/detail/SkillImplementationWrapper.cpp
+++ b/source/RobotAPI/libraries/skills/provider/detail/SkillImplementationWrapper.cpp
@@ -65,6 +65,8 @@ namespace armarx
             const auto& skillName = skillId.skillName;
             const auto& providerId = *skillId.providerId;
             const auto& executorName = statusUpdate.executionId.executorName;
+            const auto& manager =
+                skills::manager::dti::SkillManagerInterfacePrx::checkedCast(callback_interface);
 
             ARMARX_INFO_S << "Executing skill: " << skillName;
 
@@ -119,12 +121,10 @@ namespace armarx
 
             updateStatus(SkillStatus::Constructing);
             this->skill = this->factory.createSkill(providerId);
-            this->skill->executorName = executorName;
-            this->skill->manager = skills::manager::dti::SkillManagerInterfacePrx::checkedCast(
-                callback_interface); // ugly. Get managerPrx from manager!
-
-            this->skill->callback = [&](const SkillStatus s, const armarx::aron::data::DictPtr& d)
-            { updateStatus(s, d); };
+            this->skill->setExecutorName(executorName);
+            this->skill->setManager(manager);
+            this->skill->setCallback([&](const SkillStatus s, const armarx::aron::data::DictPtr& d)
+                                     { updateStatus(s, d); });
 
             // set initial parameters that were attached to the execution request (only add as we are not sure whether some updates already arrived)
             skill->updateParameters(initial_aron_params);
-- 
GitLab