diff --git a/flamenco_worker/runner.py b/flamenco_worker/runner.py
index ff2aa72cab988ac44ae4a4c0661e8bd02f727807..926f6afac900f2073e3516521b06e60911dbce6c 100644
--- a/flamenco_worker/runner.py
+++ b/flamenco_worker/runner.py
@@ -77,6 +77,30 @@ class TaskRunner:
         settings['render_output'] = os.path.normpath(settings['render_output']).replace(head, os.path.normpath(fworker.worker_output_dir))
         return
 
+    def check_src_dir(self, settings: dict, fworker: worker.FlamencoWorker):
+        if not fworker.worker_output_dir:
+            return
+	
+        if not settings.get('src'):
+            return
+
+        (head, tail) = os.path.split(os.path.normpath(settings['src']))
+
+        settings['src'] = os.path.normpath(settings['src']).replace(head, os.path.normpath(fworker.worker_output_dir))
+        return
+
+    def check_dest_dir(self, settings: dict, fworker: worker.FlamencoWorker):
+        if not fworker.worker_output_dir:
+            return
+	
+        if not settings.get('dest'):
+            return
+
+        (head, tail) = os.path.split(os.path.normpath(settings['dest']))
+
+        settings['dest'] = os.path.normpath(settings['dest']).replace(head, os.path.normpath(fworker.worker_output_dir))
+        return
+
     async def execute(self, task: dict, fworker: worker.FlamencoWorker) -> bool:
         """Executes a task, returns True iff the entire task was run succesfully."""
 
@@ -97,6 +121,8 @@ class TaskRunner:
             self.check_blender_cmd(cmd_settings, fworker)       
             self.check_storage_dir(cmd_settings, fworker)
             self.check_output_dir(cmd_settings, fworker)
+            self.check_src_dir(cmd_settings, fworker)
+            self.check_dest_dir(cmd_settings, fworker)
             self.wait_storage_data(cmd_settings, fworker)
 
             if cmd_settings is None or not isinstance(cmd_settings, dict):
diff --git a/flamenco_worker/runner.py~ b/flamenco_worker/runner.py~
new file mode 100644
index 0000000000000000000000000000000000000000..103d8fd47c490a9fcbd88c107a1ad3117768d340
--- /dev/null
+++ b/flamenco_worker/runner.py~
@@ -0,0 +1,172 @@
+"""Task runner."""
+
+import asyncio
+
+import attr
+import os
+
+import os.path
+import time
+
+from . import attrs_extra
+from . import worker
+
+
+@attr.s
+class TaskRunner:
+    """Runs tasks, sending updates back to the worker."""
+
+    shutdown_future = attr.ib(validator=attr.validators.instance_of(asyncio.Future))
+    last_command_idx = attr.ib(default=0, init=False)
+
+    _log = attrs_extra.log('%s.TaskRunner' % __name__)
+
+    def __attrs_post_init__(self):
+        self.current_command = None
+
+    def wait_storage_data(self, settings: dict, fworker: worker.FlamencoWorker):
+        if not settings.get('filepath'):
+            return
+
+        wait_count=0
+        filepath = settings['filepath'] + '.run'
+
+        while not os.path.exists(filepath):
+            self._log.info('Wait %d s on %s.', wait_count * 10, filepath)
+
+            wait_count = wait_count + 1
+            if wait_count > 360:
+                raise ValueError('File %s does not exist' % (filepath))
+
+            time.sleep(10)		
+        return
+
+    def check_blender_cmd(self, settings: dict, fworker: worker.FlamencoWorker):
+        if not fworker.worker_blender_cmd:
+            return
+
+        if not settings.get('blender_cmd'):
+            return
+
+        settings['blender_cmd'] = fworker.worker_blender_cmd
+        return
+
+    def check_storage_dir(self, settings: dict, fworker: worker.FlamencoWorker):
+        if not fworker.worker_storage_dir:
+            return
+
+        if not settings.get('filepath'):
+            return
+
+        (head, tail) = os.path.split(os.path.normpath(settings['filepath']))
+        (head, tail) = os.path.split(head)
+
+        settings['filepath'] = os.path.normpath(settings['filepath']).replace(head, os.path.normpath(fworker.worker_storage_dir))
+        return
+
+    def check_output_dir(self, settings: dict, fworker: worker.FlamencoWorker):
+        if not fworker.worker_output_dir:
+            return
+	
+        if not settings.get('render_output'):
+            return
+
+        (head, tail) = os.path.split(os.path.normpath(settings['render_output']))
+        (head, tail) = os.path.split(head)
+
+        settings['render_output'] = os.path.normpath(settings['render_output']).replace(head, os.path.normpath(fworker.worker_output_dir))
+        return
+
+    def check_src_dir(self, settings: dict, fworker: worker.FlamencoWorker):
+        if not fworker.worker_output_dir:
+            return
+	
+        if not settings.get('src'):
+            return
+
+        (head, tail) = os.path.split(os.path.normpath(settings['src']))
+        (head, tail) = os.path.split(head)
+        (head, tail) = os.path.split(head)
+
+        settings['src'] = os.path.normpath(settings['src']).replace(head, os.path.normpath(fworker.worker_output_dir))
+        return
+
+    def check_dest_dir(self, settings: dict, fworker: worker.FlamencoWorker):
+        if not fworker.worker_output_dir:
+            return
+	
+        if not settings.get('dest'):
+            return
+
+        (head, tail) = os.path.split(os.path.normpath(settings['dest']))
+        (head, tail) = os.path.split(head)
+        (head, tail) = os.path.split(head)
+
+        settings['dest'] = os.path.normpath(settings['dest']).replace(head, os.path.normpath(fworker.worker_output_dir))
+        return
+
+    async def execute(self, task: dict, fworker: worker.FlamencoWorker) -> bool:
+        """Executes a task, returns True iff the entire task was run succesfully."""
+
+        from .commands import command_handlers
+
+        task_id = task['_id']
+
+        for cmd_idx, cmd_info in enumerate(task['commands']):
+            self.last_command_idx = cmd_idx
+
+            # Figure out the command name
+            cmd_name = cmd_info.get('name')
+            if not cmd_name:
+                raise ValueError('Command %i of task %s has no name' % (cmd_idx, task_id))
+
+            cmd_settings = cmd_info.get('settings')
+            print(cmd_settings)   
+            self.check_blender_cmd(cmd_settings, fworker)       
+            self.check_storage_dir(cmd_settings, fworker)
+            self.check_output_dir(cmd_settings, fworker)
+            self.check_src_dir(cmd_settings, fworker)
+            self.check_dest_dir(cmd_settings, fworker)
+            self.wait_storage_data(cmd_settings, fworker)
+
+            if cmd_settings is None or not isinstance(cmd_settings, dict):
+                raise ValueError('Command %i of task %s has malformed settings %r' %
+                                 (cmd_idx, task_id, cmd_settings))
+
+            # Find the handler class
+            try:
+                cmd_cls = command_handlers[cmd_name]
+            except KeyError:
+                raise ValueError('Command %i of task %s has unknown command name %r' %
+                                 (cmd_idx, task_id, cmd_name))
+
+            # Construct & execute the handler.
+            cmd = cmd_cls(
+                worker=fworker,
+                task_id=task_id,
+                command_idx=cmd_idx,
+            )
+            self.current_command = cmd
+            success = await cmd.run(cmd_settings)
+
+            if not success:
+                self._log.warning('Command %i of task %s was not succesful, aborting task.',
+                                  cmd_idx, task_id)
+                return False
+
+        self._log.info('Task %s completed succesfully.', task_id)
+        self.current_command = None
+        return True
+
+    async def abort_current_task(self):
+        """Aborts the current task by aborting the currently running command.
+
+        Asynchronous, because a subprocess has to be wait()ed upon before returning.
+        """
+
+        if self.current_command is None:
+            self._log.info('abort_current_task: no command running, nothing to abort.')
+            return
+
+        self._log.warning('abort_current_task: Aborting command %s', self.current_command)
+        await self.current_command.abort()