diff --git a/.github/workflows/dispatch-integration-test.yml b/.github/workflows/dispatch-integration-test.yml
new file mode 100644
index 000000000..6fe4904d7
--- /dev/null
+++ b/.github/workflows/dispatch-integration-test.yml
@@ -0,0 +1,23 @@
+name: Run if-check on requested branch
+
+on: 
+  workflow_dispatch: 
+
+jobs:
+  run:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout code
+        uses: actions/checkout@v4
+      
+      - name: Set up Node.js
+        uses: actions/setup-node@v4
+        with:
+          node-version: 18
+          cache: 'npm'
+
+      - name: Install dependencies
+        run: npm install
+
+      - name: Run integration tests
+        run: npm run if-check -- -d manifests/outputs
diff --git a/manifests/examples/builtins/time-sync/success.yml b/manifests/examples/builtins/time-sync/success.yml
index 6d1841e97..90b80580f 100644
--- a/manifests/examples/builtins/time-sync/success.yml
+++ b/manifests/examples/builtins/time-sync/success.yml
@@ -1,23 +1,16 @@
 name: time-sync
 description: successful path
 tags:
+'time-sync':
+  start-time: '2023-12-12T00:00:00.000Z'
+  end-time: '2023-12-12T00:01:00.000Z'
+  interval: 5
+  allow-padding: true
 initialize:
-  output:
-    - yaml
-  plugins:
-    'time-sync':
-      method: TimeSync
-      path: "builtin"
-      global-config: 
-        start-time: '2023-12-12T00:00:00.000Z'
-        end-time: '2023-12-12T00:01:00.000Z'
-        interval: 5
-        allow-padding: true
+  plugins: {}
 tree:
   children:
     child:
-      pipeline:
-        - time-sync
       config:
       inputs:
         - timestamp: '2023-12-12T00:00:00.000Z'
diff --git a/src/__tests__/if-run/lib/compute.test.ts b/src/__tests__/if-run/lib/compute.test.ts
index b019d4c67..1549f22f8 100644
--- a/src/__tests__/if-run/lib/compute.test.ts
+++ b/src/__tests__/if-run/lib/compute.test.ts
@@ -19,6 +19,59 @@ describe('lib/compute: ', () => {
       kind: 'execute',
     },
   });
+  const mockObservePlugin = () => ({
+    execute: () => [
+      {timestamp: '2024-09-02', duration: 40, 'cpu/utilization': 30},
+      {timestamp: '2024-09-03', duration: 60, 'cpu/utilization': 40},
+    ],
+    metadata: {
+      kind: 'execute',
+    },
+  });
+  const mockObservePluginTimeSync = () => ({
+    execute: () => [
+      {
+        timestamp: '2023-12-12T00:00:00.000Z',
+        duration: 60,
+        'cpu/utilization': 30,
+      },
+      {
+        timestamp: '2023-12-12T00:01:00.000Z',
+        duration: 60,
+        'cpu/utilization': 40,
+      },
+    ],
+    metadata: {
+      kind: 'execute',
+    },
+  });
+  const mockTimeSync = () => ({
+    execute: () => [
+      {
+        timestamp: '2023-12-12T00:00:00.000Z',
+        duration: 30,
+        'cpu/utilization': 30,
+      },
+      {
+        timestamp: '2023-12-12T00:00:30.000Z',
+        duration: 30,
+        'cpu/utilization': 30,
+      },
+      {
+        timestamp: '2023-12-12T00:01:00.000Z',
+        duration: 30,
+        'cpu/utilization': 40,
+      },
+      {
+        timestamp: '2023-12-12T00:01:30.000Z',
+        duration: 30,
+        'cpu/utilization': 40,
+      },
+    ],
+    metadata: {
+      kind: 'execute',
+    },
+  });
   /**
    * Compute params.
    */
@@ -35,7 +88,11 @@ describe('lib/compute: ', () => {
         },
       },
     },
-    pluginStorage: pluginStorage().set('mock', mockExecutePlugin()),
+    pluginStorage: pluginStorage()
+      .set('mock', mockExecutePlugin())
+      .set('mock-observe', mockObservePlugin())
+      .set('mock-observe-time-sync', mockObservePluginTimeSync())
+      .set('time-sync', mockTimeSync()),
   };
 
   describe('compute(): ', () => {
@@ -221,4 +278,77 @@ describe('lib/compute: ', () => {
       expect(response.children.mockChild.outputs).toEqual(expectedResult);
     });
   });
+
+  it('computes simple tree with observe plugin.', async () => {
+    const tree = {
+      children: {
+        mockChild: {
+          pipeline: {observe: ['mock-observe']},
+        },
+      },
+    };
+
+    const response = await compute(tree, paramsExecute);
+    const expectedResult = [
+      {timestamp: '2024-09-02', duration: 40, 'cpu/utilization': 30},
+      {timestamp: '2024-09-03', duration: 60, 'cpu/utilization': 40},
+    ];
+
+    expect(response.children.mockChild.inputs).toEqual(expectedResult);
+  });
+
+  it('computes simple tree with time sync plugin.', async () => {
+    const tree = {
+      children: {
+        mockChild: {
+          pipeline: {observe: ['mock-observe-time-sync']},
+        },
+      },
+    };
+    const timeSync = {
+      'start-time': '2023-12-12T00:00:00.000Z',
+      'end-time': '2023-12-12T00:02:00.000Z',
+      interval: 5,
+      'allow-padding': true,
+    };
+
+    const response = await compute(tree, {...paramsExecute, timeSync});
+    const expectedInputs = [
+      {
+        timestamp: '2023-12-12T00:00:00.000Z',
+        duration: 60,
+        'cpu/utilization': 30,
+      },
+      {
+        timestamp: '2023-12-12T00:01:00.000Z',
+        duration: 60,
+        'cpu/utilization': 40,
+      },
+    ];
+    const expectedOutput = [
+      {
+        timestamp: '2023-12-12T00:00:00.000Z',
+        duration: 30,
+        'cpu/utilization': 30,
+      },
+      {
+        timestamp: '2023-12-12T00:00:30.000Z',
+        duration: 30,
+        'cpu/utilization': 30,
+      },
+      {
+        timestamp: '2023-12-12T00:01:00.000Z',
+        duration: 30,
+        'cpu/utilization': 40,
+      },
+      {
+        timestamp: '2023-12-12T00:01:30.000Z',
+        duration: 30,
+        'cpu/utilization': 40,
+      },
+    ];
+
+    expect(response.children.mockChild.inputs).toEqual(expectedInputs);
+    expect(response.children.mockChild.outputs).toEqual(expectedOutput);
+  });
 });
diff --git a/src/__tests__/if-run/lib/initialize.test.ts b/src/__tests__/if-run/lib/initialize.test.ts
index f00142260..0eccda08b 100644
--- a/src/__tests__/if-run/lib/initialize.test.ts
+++ b/src/__tests__/if-run/lib/initialize.test.ts
@@ -18,7 +18,6 @@ import {ERRORS} from '@grnsft/if-core/utils';
 
 import {initialize} from '../../../if-run/lib/initialize';
 import {STRINGS} from '../../../if-run/config';
-import {GlobalPlugins} from '../../../common/types/manifest';
 
 const {
   MissingPluginPathError,
@@ -30,8 +29,9 @@ const {MISSING_METHOD, MISSING_PATH, INVALID_MODULE_PATH} = STRINGS;
 describe('lib/initalize: ', () => {
   describe('initalize(): ', () => {
     it('creates instance with get and set methods.', async () => {
-      const plugins = {};
-      const response = await initialize(plugins);
+      const context = {initialize: {plugins: {}}};
+      // @ts-ignore
+      const response = await initialize(context);
 
       expect(response).toHaveProperty('get');
       expect(response).toHaveProperty('set');
@@ -40,15 +40,20 @@ describe('lib/initalize: ', () => {
     });
 
     it('checks if plugin is initalized, warning is logged and plugin has execute and metadata props.', async () => {
-      const plugins: GlobalPlugins = {
-        mockavizta: {
-          path: 'mockavizta',
-          method: 'Mockavizta',
+      const context = {
+        initialize: {
+          plugins: {
+            mockavizta: {
+              path: 'mockavizta',
+              method: 'Mockavizta',
+            },
+          },
         },
       };
-      const storage = await initialize(plugins);
+      // @ts-ignore
+      const storage = await initialize(context);
 
-      const pluginName = Object.keys(plugins)[0];
+      const pluginName = Object.keys(context.initialize.plugins)[0];
       const module = storage.get(pluginName);
       expect(module).toHaveProperty('execute');
       expect(module).toHaveProperty('metadata');
@@ -56,36 +61,45 @@ describe('lib/initalize: ', () => {
     });
 
     it('checks if plugin is initalized with global config and has execute and metadata.', async () => {
-      const plugins: GlobalPlugins = {
-        mockavizta: {
-          path: 'mockavizta',
-          method: 'Mockavizta',
-          'global-config': {
-            verbose: true,
+      const context = {
+        initialize: {
+          plugins: {
+            mockavizta: {
+              path: 'mockavizta',
+              method: 'Mockavizta',
+              'global-config': {
+                verbose: true,
+              },
+            },
           },
         },
       };
-      const storage = await initialize(plugins);
+      // @ts-ignore
+      const storage = await initialize(context);
 
-      const pluginName = Object.keys(plugins)[0];
+      const pluginName = Object.keys(context.initialize.plugins)[0];
       const module = storage.get(pluginName);
       expect(module).toHaveProperty('execute');
       expect(module).toHaveProperty('metadata');
     });
 
     it('throws error if plugin does not have path property.', async () => {
-      const plugins: GlobalPlugins = {
-        // @ts-ignore
-        mockavizta: {
-          method: 'Mockavizta',
-          'global-config': {
-            verbose: true,
+      const context = {
+        initialize: {
+          plugins: {
+            mockavizta: {
+              method: 'Mockavizta',
+              'global-config': {
+                verbose: true,
+              },
+            },
           },
         },
       };
 
       try {
-        await initialize(plugins);
+        // @ts-ignore
+        await initialize(context);
       } catch (error) {
         expect(error).toBeInstanceOf(MissingPluginPathError);
 
@@ -96,18 +110,22 @@ describe('lib/initalize: ', () => {
     });
 
     it('throws error if plugin does not have path property.', async () => {
-      const plugins: GlobalPlugins = {
-        // @ts-ignore
-        mockavizta: {
-          path: 'mockavizta',
-          'global-config': {
-            verbose: true,
+      const context = {
+        initialize: {
+          plugins: {
+            mockavizta: {
+              path: 'mockavizta',
+              'global-config': {
+                verbose: true,
+              },
+            },
           },
         },
       };
 
       try {
-        await initialize(plugins);
+        // @ts-ignore
+        await initialize(context);
       } catch (error) {
         expect(error).toBeInstanceOf(MissingPluginMethodError);
 
@@ -118,59 +136,115 @@ describe('lib/initalize: ', () => {
     });
 
     it('checks if builtin plugin is initalized.', async () => {
-      const plugins: GlobalPlugins = {
-        mockavizta: {
-          path: 'builtin',
-          method: 'Mockavizta',
-          'global-config': {
-            verbose: true,
+      const context = {
+        initialize: {
+          plugins: {
+            mockavizta: {
+              path: 'builtin',
+              method: 'Mockavizta',
+              'global-config': {
+                verbose: true,
+              },
+            },
           },
         },
       };
-      const storage = await initialize(plugins);
+      // @ts-ignore
+      const storage = await initialize(context);
 
-      const pluginName = Object.keys(plugins)[0];
+      const pluginName = Object.keys(context.initialize.plugins)[0];
       const module = storage.get(pluginName);
       expect(module).toHaveProperty('execute');
       expect(module).toHaveProperty('metadata');
     });
 
+    it('checks if time sync plugin is initalized.', async () => {
+      const context = {
+        initialize: {
+          plugins: {
+            'time-sync': {
+              path: 'lib/time-sync',
+              method: 'TimeSync',
+              'global-config': {},
+            },
+          },
+        },
+      };
+      // @ts-ignore
+      const storage = await initialize(context);
+
+      const pluginName = Object.keys(context.initialize.plugins)[0];
+      const module = storage.get(pluginName);
+      expect(module).toHaveProperty('execute');
+      expect(module).toHaveProperty('metadata');
+    });
+
+    it('initalizes time sync based on context.', async () => {
+      const context = {
+        initialize: {
+          plugins: {},
+        },
+        'time-sync': {
+          'start-time': '2024-09-04',
+          'end-time': '2024-09-05',
+          'allow-padding': true,
+          interval: 5,
+        },
+      };
+      // @ts-ignore
+      const storage = await initialize(context);
+      const module = storage.get('time-sync');
+
+      expect(module).toHaveProperty('execute');
+      expect(module).toHaveProperty('metadata');
+    });
+
     it('checks if github plugin is initalized.', async () => {
-      const plugins: GlobalPlugins = {
-        mockavizta: {
-          path: 'https://github.com/mockavizta',
-          method: 'Mockavizta',
-          'global-config': {
-            verbose: true,
+      const context = {
+        initialize: {
+          plugins: {
+            mockavizta: {
+              path: 'https://github.com/mockavizta',
+              method: 'Mockavizta',
+              'global-config': {
+                verbose: true,
+              },
+            },
           },
         },
       };
-      const storage = await initialize(plugins);
+      // @ts-ignore
+      const storage = await initialize(context);
 
-      const pluginName = Object.keys(plugins)[0];
+      const pluginName = Object.keys(context.initialize.plugins)[0];
       const module = storage.get(pluginName);
       expect(module).toHaveProperty('execute');
       expect(module).toHaveProperty('metadata');
     });
 
     it('throws error if plugin path is invalid.', async () => {
-      const plugins: GlobalPlugins = {
-        mockavizta: {
-          path: 'failing-mock',
-          method: 'Mockavizta',
-          'global-config': {
-            verbose: true,
+      const context = {
+        initialize: {
+          plugins: {
+            mockavizta: {
+              path: 'failing-mock',
+              method: 'Mockavizta',
+              'global-config': {
+                verbose: true,
+              },
+            },
           },
         },
       };
 
       try {
-        await initialize(plugins);
+        // @ts-ignore
+        await initialize(context);
       } catch (error: any) {
         expect(error).toBeInstanceOf(PluginInitializationError);
         expect(error.message).toEqual(
           INVALID_MODULE_PATH(
-            plugins.mockavizta.path,
+            context.initialize.plugins.mockavizta.path,
             new Error(
               "Cannot find module 'failing-mock' from 'src/if-run/lib/initialize.ts'"
             )
diff --git a/src/__tests__/if-run/builtins/time-sync.test.ts b/src/__tests__/if-run/lib/time-sync.test.ts
similarity index 99%
rename from src/__tests__/if-run/builtins/time-sync.test.ts
rename to src/__tests__/if-run/lib/time-sync.test.ts
index 314ed06d4..2d5a9c983 100644
--- a/src/__tests__/if-run/builtins/time-sync.test.ts
+++ b/src/__tests__/if-run/lib/time-sync.test.ts
@@ -4,7 +4,7 @@ import {Settings, DateTime} from 'luxon';
 import {AggregationParams} from '../../../common/types/manifest';
 
 import {storeAggregationMetrics} from '../../../if-run/lib/aggregate';
-import {TimeSync} from '../../../if-run/builtins/time-sync';
+import {TimeSync} from '../../../if-run/lib/time-sync';
 
 import {STRINGS} from '../../../if-run/config';
 
diff --git a/src/common/util/validations.ts b/src/common/util/validations.ts
index 9f2d4c495..1907ed82f 100644
--- a/src/common/util/validations.ts
+++ b/src/common/util/validations.ts
@@ -51,40 +51,51 @@ export const manifestSchema = z.object({
     })
     .optional()
     .nullable(),
+  'time-sync': z
+    .object({
+      'start-time': z.string(),
+      'end-time': z.string(),
+      interval: z.number().gt(0),
+      'allow-padding': z.boolean(),
+    })
+    .optional()
+    .nullable(),
   initialize: z.object({
     plugins: z.record(
       z.string(),
-      z.object({
-        path: z.string(),
-        method: z.string(),
-        'global-config': z.record(z.string(), z.any()).optional(),
-        'parameter-metadata': z
-          .object({
-            inputs: z
-              .record(
-                z.string(),
-                z.object({
-                  unit: z.string(),
-                  description: z.string(),
-                  'aggregation-method': z.string(),
-                })
-              )
-              .optional()
-              .nullable(),
-            outputs: z
-              .record(
-                z.string(),
-                z.object({
-                  unit: z.string(),
-                  description: z.string(),
-                  'aggregation-method': z.string(),
-                })
-              )
-              .optional()
-              .nullable(),
-          })
-          .optional(),
-      })
+      z
+        .object({
+          path: z.string(),
+          method: z.string(),
+          'global-config': z.record(z.string(), z.any()).optional(),
+          'parameter-metadata': z
+            .object({
+              inputs: z
+                .record(
+                  z.string(),
+                  z.object({
+                    unit: z.string(),
+                    description: z.string(),
+                    'aggregation-method': z.string(),
+                  })
+                )
+                .optional()
+                .nullable(),
+              outputs: z
+                .record(
+                  z.string(),
+                  z.object({
+                    unit: z.string(),
+                    description: z.string(),
+                    'aggregation-method': z.string(),
+                  })
+                )
+                .optional()
+                .nullable(),
+            })
+            .optional(),
+        })
+        .optional()
     ),
   }),
   execution: z
diff --git a/src/if-run/builtins/index.ts b/src/if-run/builtins/index.ts
index a8ccc76fd..49b30c882 100644
--- a/src/if-run/builtins/index.ts
+++ b/src/if-run/builtins/index.ts
@@ -1,4 +1,3 @@
-export {TimeSync} from './time-sync';
 export {Interpolation} from './interpolation';
 export {MockObservations} from './mock-observations';
 export {Divide} from './divide';
diff --git a/src/if-run/config/strings.ts b/src/if-run/config/strings.ts
index 24835f8ed..59354912b 100644
--- a/src/if-run/config/strings.ts
+++ b/src/if-run/config/strings.ts
@@ -47,6 +47,7 @@ Note that for the '--output' option you also need to define the output type in y
   CHECKING_AGGREGATION_METHOD: (unitName: string) =>
     `Checking aggregation method for ${unitName}`,
   INITIALIZING_PLUGINS: 'Initializing plugins',
+  INITIALIZING_TIME_SYNC: 'Initializing time synchronization',
   INITIALIZING_PLUGIN: (pluginName: string) => `Initializing ${pluginName}`,
   LOADING_PLUGIN_FROM_PATH: (pluginName: string, path: string) =>
     `Loading ${pluginName} from ${path}`,
diff --git a/src/if-run/index.ts b/src/if-run/index.ts
index 732cc9fec..293fef905 100644
--- a/src/if-run/index.ts
+++ b/src/if-run/index.ts
@@ -41,15 +41,20 @@ const impactEngine = async () => {
 
   try {
     const {tree, ...context} = validateManifest(envManifest);
-    const pluginStorage = await initialize(context.initialize.plugins);
+    const pluginStorage = await initialize(context);
     const computedTree = await compute(tree, {
       context,
       pluginStorage,
       observe,
       regroup,
       compute: computeFlag,
+      timeSync: context['time-sync'],
     });
 
+    if (context['time-sync']) {
+      delete context.initialize.plugins['time-sync'];
+    }
+
     if (context.aggregation) {
       storeAggregationMetrics({metrics: context.aggregation?.metrics});
     }
diff --git a/src/if-run/lib/compute.ts b/src/if-run/lib/compute.ts
index dfd742ef4..7840a80bd 100644
--- a/src/if-run/lib/compute.ts
+++ b/src/if-run/lib/compute.ts
@@ -75,7 +75,7 @@ const computeNode = async (node: Node, params: ComputeParams): Promise<any> => {
 
   let inputStorage = structuredClone(node.inputs) as PluginParams[];
   inputStorage = mergeDefaults(inputStorage, defaults);
-  const pipelineCopy = structuredClone(pipeline);
+  const pipelineCopy = structuredClone(pipeline) || {};
 
   /**
    * If iteration is on observe pipeline, then executes observe plugins and sets the inputs value.
@@ -88,17 +88,16 @@ const computeNode = async (node: Node, params: ComputeParams): Promise<any> => {
 
       if (isExecute(plugin)) {
         inputStorage = await plugin.execute(inputStorage, nodeConfig);
+        node.inputs = inputStorage;
 
         if (params.context.explainer) {
           addExplainData({
             pluginName,
             metadata: plugin.metadata,
-            pluginData: params.context.initialize.plugins[pluginName],
+            pluginData: params.context.initialize!.plugins[pluginName],
           });
         }
 
-        debugLogger.setExecutingPluginName();
-
         node.outputs = inputStorage;
       }
     }
@@ -107,8 +106,8 @@ const computeNode = async (node: Node, params: ComputeParams): Promise<any> => {
   /**
    * If regroup is requested, execute regroup strategy, delete child's inputs, outputs and empty regroup array.
    */
-  if ((noFlags || params.regroup) && pipeline.regroup) {
-    node.children = Regroup(inputStorage, pipeline.regroup);
+  if ((noFlags || params.regroup) && pipelineCopy.regroup) {
+    node.children = Regroup(inputStorage, pipelineCopy.regroup);
     delete node.inputs;
     delete node.outputs;
 
@@ -123,6 +122,16 @@ const computeNode = async (node: Node, params: ComputeParams): Promise<any> => {
     });
   }
 
+  /**
+   * Adds `time-sync` as the first plugin of compute phase if requested.
+   */
+  if (params.timeSync) {
+    pipelineCopy.compute = [
+      'time-sync',
+      ...((pipelineCopy && pipelineCopy.compute) || []),
+    ];
+  }
+
   /**
    * If iteration is on compute plugin, then executes compute plugins and sets the outputs value.
    */
diff --git a/src/if-run/lib/explain.ts b/src/if-run/lib/explain.ts
index add1a02b6..dce49b75a 100644
--- a/src/if-run/lib/explain.ts
+++ b/src/if-run/lib/explain.ts
@@ -30,8 +30,8 @@ export const addExplainData = (params: ExplainParams) => {
   const {pluginName, pluginData, metadata} = params;
   const plugin = {
     [pluginName]: {
-      method: pluginData.method,
-      path: pluginData.path,
+      method: pluginData!.method,
+      path: pluginData!.path,
       inputs: metadata?.inputs || 'undefined',
       outputs: metadata?.outputs || 'undefined',
     },
diff --git a/src/if-run/lib/initialize.ts b/src/if-run/lib/initialize.ts
index 5adcc2b18..afa93a2da 100644
--- a/src/if-run/lib/initialize.ts
+++ b/src/if-run/lib/initialize.ts
@@ -9,7 +9,7 @@ import {pluginStorage} from '../util/plugin-storage';
 import {CONFIG, STRINGS} from '../config';
 
 import {PluginInterface} from '../types/interface';
-import {GlobalPlugins, PluginOptions} from '../../common/types/manifest';
+import {Context, PluginOptions} from '../../common/types/manifest';
 import {PluginStorageInterface} from '../types/plugin-storage';
 
 const {
@@ -27,6 +27,7 @@ const {
   LOADING_PLUGIN_FROM_PATH,
   INITIALIZING_PLUGIN,
   INITIALIZING_PLUGINS,
+  INITIALIZING_TIME_SYNC,
 } = STRINGS;
 
 /**
@@ -59,6 +60,8 @@ const handModule = (method: string, pluginPath: string) => {
 
   if (pluginPath === 'builtin') {
     pluginPath = path.normalize(`${__dirname}/../builtins`);
+  } else if (pluginPath === 'lib/time-sync') {
+    pluginPath = path.normalize(`${__dirname}/../${pluginPath}`);
   } else {
     if (pluginPath?.startsWith(GITHUB_PATH)) {
       const parts = pluginPath.split('/');
@@ -84,7 +87,7 @@ const initPlugin = async (
     path,
     'global-config': globalConfig,
     'parameter-metadata': parameterMetadata,
-  } = initPluginParams;
+  } = initPluginParams!;
 
   console.debug(INITIALIZING_PLUGIN(method));
 
@@ -105,12 +108,24 @@ const initPlugin = async (
  * Registers all plugins from `manifest`.`initialize` property.
  */
 export const initialize = async (
-  plugins: GlobalPlugins
+  context: Context
 ): Promise<PluginStorageInterface> => {
   console.debug(INITIALIZING_PLUGINS);
-
+  const {plugins} = context.initialize;
   const storage = pluginStorage();
 
+  /**
+   * If `time-sync` is requested, then add it to plugins.
+   */
+  if (context['time-sync']) {
+    console.debug(INITIALIZING_TIME_SYNC);
+    plugins['time-sync'] = {
+      path: 'lib/time-sync',
+      method: 'TimeSync',
+      'global-config': context['time-sync'],
+    };
+  }
+
   for await (const pluginName of Object.keys(plugins)) {
     const plugin = await initPlugin(plugins[pluginName]);
     storage.set(pluginName, plugin);
diff --git a/src/if-run/builtins/time-sync.ts b/src/if-run/lib/time-sync.ts
similarity index 94%
rename from src/if-run/builtins/time-sync.ts
rename to src/if-run/lib/time-sync.ts
index 9d589c491..e9f4ee1bc 100644
--- a/src/if-run/builtins/time-sync.ts
+++ b/src/if-run/lib/time-sync.ts
@@ -36,6 +36,21 @@ const {
   INVALID_DATETIME,
 } = STRINGS;
 
+/**
+ * Time synchronization plugin converted into framework integrated tool.
+ * It can't be requested in `initialize.plugins` section anymore. Instead describe configuration in context.
+ * @example
+ * ```yaml
+ * name: time-sync
+ * description: sample in time sync lib
+ * tags: sample, time, sync
+ * time-sync:
+ *   start-time: '2023-12-12T00:00:00.000Z'
+ *   end-time: '2023-12-12T00:01:00.000Z'
+ *   interval: 5
+ *   allow-padding: true
+ * ```
+ */
 export const TimeSync = (
   globalConfig: TimeNormalizerConfig,
   parametersMetadata: PluginParametersMetadata
@@ -131,14 +146,16 @@ export const TimeSync = (
     return resampleInputs(sortedInputs, timeParams) as PluginParams[];
   };
 
+  /**
+   * Dates are passed to `time-sync` both in ISO 8601 format
+   * and as a Date object (from the deserialization of a YAML file).
+   * If the YAML parser fails to identify as a date, it passes as a string.
+   */
   const parseDate = (date: Date | string) => {
     if (!date) {
       return DateTime.invalid('Invalid date');
     }
 
-    // dates are passed to time-sync.ts both in ISO 8601 format
-    // and as a Date object (from the deserialization of a YAML file)
-    // if the YAML parser fails to identify as a date, it passes as a string
     if (isDate(date)) {
       return DateTime.fromJSDate(date);
     }
diff --git a/src/if-run/types/compute.ts b/src/if-run/types/compute.ts
index 6777bf553..da31b2635 100644
--- a/src/if-run/types/compute.ts
+++ b/src/if-run/types/compute.ts
@@ -13,6 +13,13 @@ export type PhasedPipeline = {
   compute?: string[];
 };
 
+type TimeSyncConfig = {
+  'start-time': string;
+  'end-time': string;
+  interval: number;
+  'allow-padding': boolean;
+};
+
 export type ComputeParams = {
   pluginStorage: PluginStorageInterface;
   context: Context;
@@ -22,6 +29,7 @@ export type ComputeParams = {
   observe?: Boolean;
   regroup?: Boolean;
   compute?: Boolean;
+  timeSync?: TimeSyncConfig | undefined | null;
 };
 
 export type Node = {
diff --git a/src/if-run/types/explain.ts b/src/if-run/types/explain.ts
index b1b684882..c7f1a6d38 100644
--- a/src/if-run/types/explain.ts
+++ b/src/if-run/types/explain.ts
@@ -1,7 +1,9 @@
 import {ParameterMetadata} from '@grnsft/if-core/types';
 
+import {PluginOptions} from '../../common/types/manifest';
+
 export type ExplainParams = {
   pluginName: string;
-  pluginData: {method: string; path: string};
+  pluginData: PluginOptions;
   metadata: {inputs?: ParameterMetadata; outputs?: ParameterMetadata};
 };
diff --git a/src/if-run/types/interface.ts b/src/if-run/types/interface.ts
index 6834a3ebb..7b6c19b33 100644
--- a/src/if-run/types/interface.ts
+++ b/src/if-run/types/interface.ts
@@ -4,6 +4,3 @@ export type PluginInterface = ExecutePlugin | GroupByPlugin;
 
 export const isExecute = (plugin: PluginInterface): plugin is ExecutePlugin =>
   (plugin as ExecutePlugin).metadata.kind === 'execute';
-
-export const isGroupBy = (plugin: PluginInterface): plugin is GroupByPlugin =>
-  (plugin as GroupByPlugin).metadata.kind === 'groupby';