diff --git a/shadowdog.json b/shadowdog.json
index f719e89..6194d73 100644
--- a/shadowdog.json
+++ b/shadowdog.json
@@ -1,7 +1,6 @@
 {
   "$schema": "./src/config/schema.json",
   "plugins": [
-    "shadowdog-rake",
     {
       "name": "shadowdog-local-cache",
       "options": {
diff --git a/src/config.ts b/src/config.ts
index 55f1161..a6c74cd 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -3,7 +3,9 @@ import { logMessage } from './utils'
 import { z } from 'zod'
 import chalk from 'chalk'
 
-const PluginTypeEnum = z.enum(['shadowdog-rake', 'shadowdog-local-cache'])
+// TODO: rake plugin
+// const PluginTypeEnum = z.enum(['shadowdog-rake', 'shadowdog-local-cache'])
+const PluginTypeEnum = z.enum(['shadowdog-local-cache'])
 
 export const configSchema = z
   .object({
@@ -23,7 +25,7 @@ export const configSchema = z
       .array(
         z.union([
           PluginTypeEnum.describe('Plugin name'),
-          z.object({ name: PluginTypeEnum, options: z.object({}) }).strict(),
+          z.object({ name: PluginTypeEnum, options: z.any() }).strict(),
         ]),
       )
       .optional()
diff --git a/src/config/schema.json b/src/config/schema.json
index 0151637..8f3d6fe 100644
--- a/src/config/schema.json
+++ b/src/config/schema.json
@@ -25,7 +25,7 @@
         "anyOf": [
           {
             "type": "string",
-            "enum": ["shadowdog-rake", "shadowdog-local-cache"],
+            "enum": ["shadowdog-local-cache"],
             "description": "Plugin name"
           },
           {
@@ -33,15 +33,11 @@
             "properties": {
               "name": {
                 "type": "string",
-                "enum": ["shadowdog-rake", "shadowdog-local-cache"]
+                "enum": ["shadowdog-local-cache"]
               },
-              "options": {
-                "type": "object",
-                "properties": {},
-                "additionalProperties": false
-              }
+              "options": {}
             },
-            "required": ["name", "options"],
+            "required": ["name"],
             "additionalProperties": false
           }
         ]
diff --git a/src/daemon.ts b/src/daemon.ts
index d628819..bd93243 100644
--- a/src/daemon.ts
+++ b/src/daemon.ts
@@ -14,14 +14,52 @@ import { logMessage } from './utils'
 import chalk from 'chalk'
 import { Client } from 'minio'
 
+// TODO: Add the rest of the plugins
 import shadowdogRake from './plugins/shadowdog-rake'
 import shadowdogLocalCache from './plugins/shadowdog-local-cache'
 
 const PLUGINS_MAP = {
-  'shadowdog-rake': shadowdogRake,
   'shadowdog-local-cache': shadowdogLocalCache,
 } as const
 
+type Result = any
+
+export type Middleware<Context = any> = (
+  ctx: Context,
+  next: () => Promise<Result>,
+  abort: () => void,
+) => Promise<Result>
+
+class TaskManager {
+  middlewares: Array<{ middleware: Middleware; options: any }>
+
+  constructor() {
+    this.middlewares = []
+  }
+
+  use(middleware: Middleware, options: any = {}) {
+    this.middlewares.push({ middleware, options })
+  }
+
+  async execute(context: any) {
+    let index = -1
+    let isAborted = false
+
+    const abort = () => {
+      isAborted = true
+    }
+
+    const next = async () => {
+      if (isAborted || ++index >= this.middlewares.length) return context.result
+      const current = this.middlewares[index]
+      return current.middleware({ ...context, options: current.options }, next, abort)
+    }
+
+    context.result = await next()
+    return context.result
+  }
+}
+
 const setupWatchers = (config: ConfigFile, socketPath: string, client: Client | null) => {
   return Promise.all<chokidar.FSWatcher>(
     config.watchers
@@ -112,22 +150,32 @@ const setupWatchers = (config: ConfigFile, socketPath: string, client: Client |
 
             await Promise.all(
               watcherConfig.commands.map(async (commandConfig) => {
-                await Promise.all(
-                  config.plugins.map((pluginName) => {
-                    if (typeof pluginName === 'object') {
-                      return PLUGINS_MAP[pluginName.name].preProcessing(
-                        watcherConfig,
-                        commandConfig,
-                        pluginName.options as any, // TODO: check this
-                      )
-                    }
-                    return PLUGINS_MAP[pluginName].preProcessing(
-                      watcherConfig,
-                      commandConfig,
-                      {} as any,
-                    ) // TODO: check this
-                  }),
-                )
+                const taskManager = new TaskManager()
+
+                config.plugins.forEach((pluginName) => {
+                  if (typeof pluginName === 'object') {
+                    return taskManager.use(PLUGINS_MAP[pluginName.name], pluginName.options)
+                  }
+                  taskManager.use(PLUGINS_MAP[pluginName])
+                })
+
+                taskManager.use(() => {
+                  return runTask({
+                    command: commandConfig.command,
+                    workingDirectory: process.cwd(),
+                    filePath,
+                    onSpawn: (task) => {
+                      tasks.push(task)
+                    },
+                  })
+                })
+
+                return taskManager.execute({
+                  watcherConfig,
+                  commandConfig,
+                })
+
+                ///////////////////////////// REVIEW THIS CODE /////////////////////////////
 
                 // At this point we need to execute the command because cache couldn't be reused
 
@@ -146,46 +194,46 @@ const setupWatchers = (config: ConfigFile, socketPath: string, client: Client |
                 //   })
                 // }
 
-                try {
-                  await runTask({
-                    command: commandConfig.command,
-                    workingDirectory: process.cwd(),
-                    filePath,
-                    onSpawn: (task) => {
-                      tasks.push(task)
-                    },
-                  })
+                // try {
+                //   await runTask({
+                //     command: commandConfig.command,
+                //     workingDirectory: process.cwd(),
+                //     filePath,
+                //     onSpawn: (task) => {
+                //       tasks.push(task)
+                //     },
+                //   })
 
-                  // TODO: notifications
-                  // await notifyState(socketPath, {
-                  //   type: 'CHANGED_FILE',
-                  //   payload: {
-                  //     file: files,
-                  //     ready: true,
-                  //   },
-                  // })
-
-                  return Promise.all(
-                    config.plugins.map((pluginName) => {
-                      if (typeof pluginName === 'object') {
-                        return PLUGINS_MAP[pluginName.name].postProcessing(
-                          commandConfig,
-                          pluginName.options as any, // TODO: check this
-                        )
-                      }
-                      return PLUGINS_MAP[pluginName].postProcessing(commandConfig, {} as any) // TODO: check this
-                    }),
-                  )
-                } catch (error) {
-                  // TODO: notifications
-                  // return notifyState(socketPath, {
-                  //   type: 'ERROR',
-                  //   payload: {
-                  //     file: filePath,
-                  //     errorMessage: (error as Error).message,
-                  //   },
-                  // })
-                }
+                // TODO: notifications
+                // await notifyState(socketPath, {
+                //   type: 'CHANGED_FILE',
+                //   payload: {
+                //     file: files,
+                //     ready: true,
+                //   },
+                // })
+
+                //   return Promise.all(
+                //     config.plugins.map((pluginName) => {
+                //       if (typeof pluginName === 'object') {
+                //         return PLUGINS_MAP[pluginName.name].postProcessing(
+                //           commandConfig,
+                //           pluginName.options as any, // TODO: check this
+                //         )
+                //       }
+                //       return PLUGINS_MAP[pluginName].postProcessing(commandConfig, {} as any) // TODO: check this
+                //     }),
+                //   )
+                // } catch (error) {
+                // TODO: notifications
+                // return notifyState(socketPath, {
+                //   type: 'ERROR',
+                //   payload: {
+                //     file: filePath,
+                //     errorMessage: (error as Error).message,
+                //   },
+                // })
+                // }
               }),
             )
           }
diff --git a/src/plugins/shadowdog-local-cache.ts b/src/plugins/shadowdog-local-cache.ts
index d14796f..c8ff746 100644
--- a/src/plugins/shadowdog-local-cache.ts
+++ b/src/plugins/shadowdog-local-cache.ts
@@ -6,10 +6,7 @@ import chalk from 'chalk'
 import path from 'path'
 import { CommandConfig, WatcherConfig } from '../config'
 import { compressFolder, decompressFile, logMessage } from '../utils'
-
-interface PluginOptions {
-  path: string
-}
+import { Middleware } from '../daemon'
 
 const restoreCache = async (
   commandConfig: CommandConfig,
@@ -125,26 +122,33 @@ const filterFn = (ignore: string[] | undefined, outputPath: string, filePath: st
   return keep
 }
 
-const preProcessing = async (
-  watcherConfig: WatcherConfig,
-  commandConfig: CommandConfig,
-  options: PluginOptions,
-) => {
+interface PluginOptions {
+  path: string
+}
+
+interface Context {
+  commandConfig: CommandConfig
+  watcherConfig: WatcherConfig
+  options: PluginOptions
+}
+
+const middleware: Middleware<Context> = async (ctx, next, abort) => {
   const currentCache = computeCache(
-    [...watcherConfig.files, ...(watcherConfig.invalidators?.files ?? [])],
-    watcherConfig.invalidators?.environment ?? [],
+    [...ctx.watcherConfig.files, ...(ctx.watcherConfig.invalidators?.files ?? [])],
+    ctx.watcherConfig.invalidators?.environment ?? [],
   )
 
-  const hasBeenRestored = await restoreCache(commandConfig, currentCache, options)
+  const hasBeenRestored = await restoreCache(ctx.commandConfig, currentCache, ctx.options)
 
   if (hasBeenRestored) {
-    return
+    abort()
+    return 'Cache restored'
   }
-}
 
-const postProcessing = (commandConfig: CommandConfig, { path: cachePath }: PluginOptions) => {
+  await next()
+
   return Promise.all(
-    commandConfig.artifacts.map(async (artifact) => {
+    ctx.commandConfig.artifacts.map(async (artifact) => {
       if (!fs.existsSync(path.join(process.cwd(), artifact.output))) {
         logMessage(
           `📦 Not able to store artifact '${chalk.blue(
@@ -167,7 +171,7 @@ const postProcessing = (commandConfig: CommandConfig, { path: cachePath }: Plugi
       const cacheFileName = computeFileCacheName(currentCache, artifact.output)
 
       const cacheFilePath = path.join(
-        cachePath,
+        ctx.options.path,
         `${cacheFileName}${artifact.compressed ? '.tar.gz' : ''}`,
       )
 
@@ -198,7 +202,4 @@ const postProcessing = (commandConfig: CommandConfig, { path: cachePath }: Plugi
   )
 }
 
-export default {
-  preProcessing,
-  postProcessing,
-}
+export default middleware