diff --git a/source/armarx/control/components/control_skill_provider/Component.cpp b/source/armarx/control/components/control_skill_provider/Component.cpp
index efea3043895e74ac3341cd822fa60bf0b6212ca3..de1c6ddaa38d1599bdc57d4bc3f493d6093affb1 100644
--- a/source/armarx/control/components/control_skill_provider/Component.cpp
+++ b/source/armarx/control/components/control_skill_provider/Component.cpp
@@ -11,30 +11,30 @@ namespace armarx::control::components::control_skill_provider
         ::armarx::PropertyDefinitionsPtr def =
             new ::armarx::ComponentPropertyDefinitions(getConfigIdentifier());
 
-        def->component(remote_.kinematicUnit);
+        def->component(remote.kinematicUnit);
 
-        def->required(properties_.robotName, "RobotName", "Name of the robot.");
+        def->required(properties.robotName, "RobotName", "Name of the robot.");
 
         return def;
     }
 
-    Component::Component()
-    {
-        addPlugin(remote_.virtualRobotReader);
-    }
-
     void
     Component::onInitComponent()
     {
-        skills_.moveJoints = addSkill<skills::MoveJoints>();
     }
 
     void
     Component::onConnectComponent()
     {
-        skills_.moveJoints->connect({.kinematicUnit = remote_.kinematicUnit,
-                                     .virtualRobotReader = remote_.virtualRobotReader->get(),
-                                     .robotName = properties_.robotName});
+        armarx::armem::robot_state::VirtualRobotReader robotStateReader;
+        robotStateReader.connect(memoryNameSystem());
+
+        {
+            skills::MoveJoints::Remote skillRemote{.kinematicUnit = remote.kinematicUnit,
+                                                   .virtualRobotReader = robotStateReader,
+                                                   .robotName = properties.robotName};
+            addSkillFactory<skills::MoveJoints>(skillRemote);
+        }
     }
 
     void
diff --git a/source/armarx/control/components/control_skill_provider/Component.h b/source/armarx/control/components/control_skill_provider/Component.h
index 14ac9199ac989a4c4d011dc0c8335c98cdcb7100..214b560dce35e393960dd44679f6d365c3ca1ad6 100644
--- a/source/armarx/control/components/control_skill_provider/Component.h
+++ b/source/armarx/control/components/control_skill_provider/Component.h
@@ -3,6 +3,7 @@
 #include <ArmarXCore/core/Component.h>
 
 #include <RobotAPI/interface/units/KinematicUnitInterface.h>
+#include <RobotAPI/libraries/armem/client/plugins/PluginUser.h>
 #include <RobotAPI/libraries/armem/client/plugins/ReaderWriterPlugin.h>
 #include <RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotReader.h>
 #include <RobotAPI/libraries/skills/provider/SkillProviderComponentPlugin.h>
@@ -18,12 +19,11 @@ namespace armarx::control::components::control_skill_provider
     class Component :
         virtual public ::armarx::Component,
         virtual public ::armarx::control::components::control_skill_provider::ComponentInterface,
-        virtual public ::armarx::SkillProviderComponentPluginUser
+        virtual public ::armarx::SkillProviderComponentPluginUser,
+        virtual public ::armarx::armem::client::PluginUser
     {
 
     public:
-        Component();
-
         /// @see armarx::ManagedIceObject::getDefaultName()
         std::string getDefaultName() const override;
 
@@ -52,19 +52,12 @@ namespace armarx::control::components::control_skill_provider
         struct Remote
         {
             ::armarx::KinematicUnitInterfacePrx kinematicUnit;
-            ::armarx::armem::client::plugins::ReaderWriterPlugin<
-                ::armarx::armem::robot_state::VirtualRobotReader>* virtualRobotReader;
-        } remote_;
+        } remote;
 
         struct Properties
         {
             std::string robotName;
-        } properties_;
-
-        struct Skills
-        {
-            skills::MoveJoints* moveJoints;
-        } skills_;
+        } properties;
 
         static const std::string defaultName;
     };
diff --git a/source/armarx/control/skills/skills/MoveJoints.cpp b/source/armarx/control/skills/skills/MoveJoints.cpp
index f500221f7c21ec8c3d0abda8ae5ddbdc3e0e3ac3..186932cd1012dd9e01210973678df36b078a03b8 100644
--- a/source/armarx/control/skills/skills/MoveJoints.cpp
+++ b/source/armarx/control/skills/skills/MoveJoints.cpp
@@ -5,20 +5,21 @@
 namespace armarx::control::skills::skills
 {
 
-    class AbortedException : public std::exception
-    {
-    public:
-        ~AbortedException() override = default;
-    };
-
-    MoveJoints::MoveJoints() : ::armarx::skills::SpecializedSkill<ParamType>(GetSkillDescription())
+    MoveJoints::MoveJoints(const Remote& r) :
+        ::armarx::skills::SimpleSpecializedSkill<ParamType>(GetSkillDescription()), remote(r)
     {
     }
 
-    armarx::skills::Skill::InitResult
-    MoveJoints::init(const SpecializedInitInput& in)
+    ::armarx::skills::Skill::ExitResult
+    MoveJoints::exit(const SpecializedExitInput& in)
     {
-        ARMARX_CHECK(remote_.has_value()); // connect(Remote) has been called
+        std::vector<std::string> jointNames;
+        for (const auto& [jointName, _] : in.parameters.jointsTargetValues)
+        {
+            jointNames.push_back(jointName);
+        }
+
+        remote.kinematicUnit->releaseJoints(jointNames);
         return {::armarx::skills::TerminatedSkillStatus::Succeeded};
     }
 
@@ -27,22 +28,22 @@ namespace armarx::control::skills::skills
     {
 
         std::vector<std::string> jointNames;
-        for (const auto& [jointName, _] : in.params.jointsTargetValues)
+        for (const auto& [jointName, _] : in.parameters.jointsTargetValues)
         {
             jointNames.push_back(jointName);
         }
 
         // get VirtualRobot
         const VirtualRobot::RobotPtr virtualRobot =
-            remote_->virtualRobotReader.getRobot(remote_->robotName);
+            remote.virtualRobotReader.getRobot(remote.robotName);
         if (not virtualRobot)
         {
-            ARMARX_ERROR << "Could not get robot '" << remote_->robotName << "'";
+            ARMARX_ERROR << "Could not get robot '" << remote.robotName << "'";
             return {::armarx::skills::TerminatedSkillStatus::Failed};
         }
 
         // check jointsTargetValues are valid (joints exist, target values are within limits)
-        if (not checkJointsTargetValuesValid(in.params.jointsTargetValues, virtualRobot))
+        if (not checkJointsTargetValuesValid(in.parameters.jointsTargetValues, virtualRobot))
         {
             return {::armarx::skills::TerminatedSkillStatus::Failed};
         }
@@ -51,7 +52,7 @@ namespace armarx::control::skills::skills
         ARMARX_INFO << "Requesting joints";
         try
         {
-            remote_->kinematicUnit->requestJoints(jointNames);
+            remote.kinematicUnit->requestJoints(jointNames);
         }
         catch (armarx::KinematicUnitUnavailable e)
         {
@@ -61,35 +62,26 @@ namespace armarx::control::skills::skills
         }
 
         // move joints
-        ARMARX_INFO << "Moving joints to " << in.params.jointsTargetValues;
+        ARMARX_INFO << "Moving joints to " << in.parameters.jointsTargetValues;
 
-        switchControlMode(in.params.jointsTargetValues, ePositionControl);
+        switchControlMode(in.parameters.jointsTargetValues, ePositionControl);
 
-        try
+        if (in.parameters.inSimulation)
         {
-            if (in.params.inSimulation)
-            {
-                // trajectories from joint value updates through the KinematicUnit are not simulated
-                // -> simulate manually
-                moveJointsSimulation(in.params.jointsTargetValues,
-                                     in.params.simulationJointSpeed,
-                                     in.params.simulationJointSpeedOverride,
-                                     virtualRobot);
-            }
-            else
-            {
-                moveJoints(in.params.jointsTargetValues,
-                           in.params.accuracy,
-                           in.params.accuracyOverride,
-                           virtualRobot);
-            }
+            // trajectories from joint value updates through the KinematicUnit are not simulated
+            // -> simulate manually
+            moveJointsSimulation(in.parameters.jointsTargetValues,
+                                 in.parameters.simulationJointSpeed,
+                                 in.parameters.simulationJointSpeedOverride,
+                                 virtualRobot);
         }
-        catch (const AbortedException&) // skill got aborted
+        else
         {
-            remote_->kinematicUnit->releaseJoints(jointNames);
-            return {::armarx::skills::TerminatedSkillStatus::Aborted};
+            moveJoints(in.parameters.jointsTargetValues,
+                       in.parameters.accuracy,
+                       in.parameters.accuracyOverride,
+                       virtualRobot);
         }
-        remote_->kinematicUnit->releaseJoints(jointNames);
         return {::armarx::skills::TerminatedSkillStatus::Succeeded};
     }
 
@@ -125,7 +117,7 @@ namespace armarx::control::skills::skills
         {
             modeMap[jointName] = controlMode;
         }
-        remote_->kinematicUnit->switchControlMode(modeMap);
+        remote.kinematicUnit->switchControlMode(modeMap);
     }
 
     void
@@ -134,7 +126,7 @@ namespace armarx::control::skills::skills
                            const NameValueMap& accuracyOverride,
                            const VirtualRobot::RobotPtr& virtualRobot)
     {
-        remote_->kinematicUnit->setJointAngles(jointsTargetValues);
+        remote.kinematicUnit->setJointAngles(jointsTargetValues);
 
         // wait until target values are reached
         ARMARX_INFO << "Waiting until target values are reached";
@@ -142,9 +134,30 @@ namespace armarx::control::skills::skills
         const Clock clock;
         const Duration sleepTime = Duration::MilliSeconds(20);
 
+        auto do_if_terminate_and_not_reached = [&]()
+        {
+            ARMARX_INFO << "Skill got aborted, stopping movement";
+            syncVirtualRobot(virtualRobot);
+
+            // stop movement
+            switchControlMode(jointsTargetValues, eVelocityControl);
+
+            NameValueMap targetJointVelocities;
+            for (auto& [jointName, _] : jointsTargetValues)
+            {
+                targetJointVelocities[jointName] = 0;
+            }
+            remote.kinematicUnit->setJointVelocities(targetJointVelocities);
+
+            throwIfSkillShouldTerminate(); // throws exception
+
+            ARMARX_INFO << "Target values reached";
+        };
+
         bool reached = false;
-        while (not checkWhetherSkillShouldStopASAP() and not reached)
+        while (not reached)
         {
+            throwIfSkillShouldTerminate(do_if_terminate_and_not_reached);
             syncVirtualRobot(virtualRobot);
 
             reached = true;
@@ -166,25 +179,6 @@ namespace armarx::control::skills::skills
             }
             clock.waitFor(sleepTime);
         }
-
-        if (not reached) // skill got aborted
-        {
-            ARMARX_INFO << "Skill got aborted, stopping movement";
-            syncVirtualRobot(virtualRobot);
-
-            // stop movement
-            switchControlMode(jointsTargetValues, eVelocityControl);
-
-            NameValueMap targetJointVelocities;
-            for (auto& [jointName, _] : jointsTargetValues)
-            {
-                targetJointVelocities[jointName] = 0;
-            }
-            remote_->kinematicUnit->setJointVelocities(targetJointVelocities);
-
-            throw AbortedException();
-        }
-        ARMARX_INFO << "Target values reached";
     }
 
     void
@@ -222,8 +216,9 @@ namespace armarx::control::skills::skills
 
         const armarx::DateTime start = armarx::DateTime::Now();
         double t = 0;
-        while (not checkWhetherSkillShouldStopASAP() and t < maxDuration)
+        while (t < maxDuration)
         {
+            throwIfSkillShouldTerminate();
             t = std::min((armarx::DateTime::Now() - start).toSecondsDouble(), maxDuration);
 
             NameValueMap nextValues;
@@ -233,17 +228,10 @@ namespace armarx::control::skills::skills
                 nextValues[name] = value;
             }
 
-            remote_->kinematicUnit->setJointAngles(nextValues);
+            remote.kinematicUnit->setJointAngles(nextValues);
 
             clock.waitFor(sleepTime);
         }
-
-        if (t < maxDuration)
-        {
-            ARMARX_INFO << "Skill got aborted";
-            throw AbortedException();
-        }
-
         ARMARX_INFO << "Target values reached";
     }
 
@@ -251,7 +239,7 @@ namespace armarx::control::skills::skills
     MoveJoints::syncVirtualRobot(const VirtualRobot::RobotPtr& virtualRobot)
     {
         ARMARX_CHECK(
-            remote_->virtualRobotReader.synchronizeRobot(*virtualRobot, armarx::DateTime::Now()))
+            remote.virtualRobotReader.synchronizeRobot(*virtualRobot, armarx::DateTime::Now()))
             << "Robot state synchronization failed";
     }
 
diff --git a/source/armarx/control/skills/skills/MoveJoints.h b/source/armarx/control/skills/skills/MoveJoints.h
index 8fda53d29cd8ceb763ff64214d0f80dadc7b2b19..40752ce4433a75cd3aef6d32e7730a2db50f7e5f 100644
--- a/source/armarx/control/skills/skills/MoveJoints.h
+++ b/source/armarx/control/skills/skills/MoveJoints.h
@@ -3,7 +3,7 @@
 #include <RobotAPI/interface/units/KinematicUnitInterface.h>
 #include <RobotAPI/libraries/armem/client/MemoryNameSystem.h>
 #include <RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotReader.h>
-#include <RobotAPI/libraries/skills/provider/SpecializedSkill.h>
+#include <RobotAPI/libraries/skills/provider/SimpleSpecializedSkill.h>
 
 #include <armarx/control/skills/skills/aron/MoveJointsParams.aron.generated.h>
 
@@ -18,42 +18,33 @@ namespace armarx::control::skills::skills
    * simulate trajectory when in simulation (otherwise trajectories from joint value updates through
    * the KinematicUnit are not simulated).
    */
-    class MoveJoints : public ::armarx::skills::SpecializedSkill<MoveJointsParams>
+    class MoveJoints : public ::armarx::skills::SimpleSpecializedSkill<MoveJointsParams>
     {
 
-    public:
-        static ::armarx::skills::SkillDescription
-        GetSkillDescription()
-        {
-            return {.skillName = "MoveJoints",
-                    .description =
-                        "Moves joints to specified target values using the KinematicUnit",
-                    .robots = {},
-                    .timeout = ::armarx::Duration::Minutes(1),
-                    .acceptedType = ParamType::ToAronType()};
-        }
-
-        MoveJoints();
-
-
     public:
         struct Remote
         {
-            ::armarx::KinematicUnitInterfacePrx& kinematicUnit;
-            ::armarx::armem::robot_state::VirtualRobotReader& virtualRobotReader;
-            const std::string& robotName;
+            ::armarx::KinematicUnitInterfacePrx kinematicUnit;
+            ::armarx::armem::robot_state::VirtualRobotReader virtualRobotReader;
+            std::string robotName;
         };
 
-        void
-        connect(const Remote& remote)
+        static ::armarx::skills::SkillDescription
+        GetSkillDescription()
         {
-            this->remote_.emplace(remote);
+            return {armarx::skills::SkillID("MoveJoints"),
+                    "Moves joints to specified target values using the KinematicUnit",
+                    nullptr,
+                    ::armarx::Duration::Minutes(1),
+                    ParamType::ToAronType()};
         }
 
+        MoveJoints(const Remote&);
+
 
     private:
-        ::armarx::skills::Skill::InitResult init(const SpecializedInitInput& in) override;
         ::armarx::skills::Skill::MainResult main(const SpecializedMainInput& in) override;
+        ::armarx::skills::Skill::ExitResult exit(const SpecializedExitInput& in) override;
 
         bool checkJointsTargetValuesValid(const NameValueMap& jointsTargetValues,
                                           const VirtualRobot::RobotPtr& virtualRobot);
@@ -74,7 +65,7 @@ namespace armarx::control::skills::skills
         void syncVirtualRobot(const VirtualRobot::RobotPtr& virtualRobot);
 
     private:
-        std::optional<Remote> remote_;
+        Remote remote;
     };
 
 } // namespace armarx::control::skills::skills