diff --git a/experiments/bulk_running_experiments.ipynb b/experiments/bulk_running_experiments.ipynb
index 083112feae71fdfd90d2543e2878337e64a2b7d7..0f1e0554a03e03bcd2913469c1ccab9a737504b0 100644
--- a/experiments/bulk_running_experiments.ipynb
+++ b/experiments/bulk_running_experiments.ipynb
@@ -210,6 +210,8 @@
     "        # # f\"observation.pdm_hybrid_ckpt={hybrid_ckpt}\",\n",
     "        f\"observation.occlusion_cfg.occlusion=true\",\n",
     "        f\"observation.occlusion_cfg.manager_type=wedge\",\n",
+    "        \"+modify_scenario_simulations=true\",\n",
+    "        \"+modifier_types=[left-and-right]\",\n",
     "        \"+occlusion=true\",\n",
     "        \"+occlusion.manager_type=wedge\",  # options: [range, shadow, wedge]\n",
     "        \"+occlusion.uncloak_reaction_time=1.5\",\n",
diff --git a/nuplan/planning/scenario_builder/nuplan_db/nuplan_scenario.py b/nuplan/planning/scenario_builder/nuplan_db/nuplan_scenario.py
index 0fbfb6fd9d10fefa429ded367f81a7723c72528b..3d2629dc4185a686713a565e9b41def48376601f 100644
--- a/nuplan/planning/scenario_builder/nuplan_db/nuplan_scenario.py
+++ b/nuplan/planning/scenario_builder/nuplan_db/nuplan_scenario.py
@@ -121,6 +121,7 @@ class NuPlanScenario(AbstractScenario):
         # So, we must check and download the file here as well.
         self._log_file = download_file_if_necessary(self._data_root, self._log_file_load_path)
         self._log_name: str = absolute_path_to_log_name(self._log_file)
+        self.modifier = ""
 
     def __reduce__(self) -> Tuple[Type[NuPlanScenario], Tuple[Any, ...]]:
         """
@@ -190,7 +191,7 @@ class NuPlanScenario(AbstractScenario):
     @property
     def scenario_name(self) -> str:
         """Inherited, see superclass."""
-        return self.token
+        return self.token + self.modifier
 
     @property
     def scenario_type(self) -> str:
diff --git a/nuplan/planning/scenario_builder/scenario_modifier/abstract_scenario_modifier.py b/nuplan/planning/scenario_builder/scenario_modifier/abstract_scenario_modifier.py
new file mode 100644
index 0000000000000000000000000000000000000000..c19fa792597cb63d169a2fed9cb598e8d25a0a01
--- /dev/null
+++ b/nuplan/planning/scenario_builder/scenario_modifier/abstract_scenario_modifier.py
@@ -0,0 +1,14 @@
+from abc import ABCMeta, abstractmethod
+from typing import List
+
+from nuplan.planning.scenario_builder.abstract_scenario import AbstractScenario
+from nuplan.planning.simulation.runner.simulations_runner import SimulationRunner
+
+class AbstractScenarioModifier(metaclass=ABCMeta):
+    @abstractmethod
+    def modify_scenario(self, runner: SimulationRunner) -> List[SimulationRunner]:
+        """We convert one abstract scenario into many abstract scenarios by modifying the scenario in some way.
+        :param runner: a simualtion runner
+        :return: we return a list of scenarios that are modified versions of the input scenario
+        """
+        pass
\ No newline at end of file
diff --git a/nuplan/planning/scenario_builder/scenario_modifier/left_and_right_modifier.py b/nuplan/planning/scenario_builder/scenario_modifier/left_and_right_modifier.py
new file mode 100644
index 0000000000000000000000000000000000000000..69bea3ad9ccdeb4cded77c9b42fb35c373b718b2
--- /dev/null
+++ b/nuplan/planning/scenario_builder/scenario_modifier/left_and_right_modifier.py
@@ -0,0 +1,78 @@
+from typing import List
+
+import copy
+from nuplan.common.actor_state.tracked_objects_types import TrackedObjectType
+
+from nuplan.planning.scenario_builder.abstract_scenario import AbstractScenario
+from nuplan.planning.scenario_builder.scenario_modifier.abstract_scenario_modifier import AbstractScenarioModifier
+
+
+from nuplan.common.actor_state.agent import Agent
+from nuplan.common.actor_state.oriented_box import OrientedBox
+from nuplan.common.actor_state.scene_object import SceneObjectMetadata
+from nuplan.common.actor_state.state_representation import StateSE2, StateVector2D
+import math
+
+from nuplan.planning.simulation.runner.simulations_runner import SimulationRunner
+class LeftAndRightModifier(AbstractScenarioModifier):
+    def __init__(self):
+        super().__init__() #maybe we will need this later
+        
+    def modify_scenario(self, runner: SimulationRunner) -> List[SimulationRunner]:
+        """We convert one abstract scenario into many abstract scenarios by modifying the scenario in some way.
+        :param scenario: a scenario
+        :return: we return a list of scenarios that are modified versions of the input scenario
+        """
+        modified_simulation_runners = []
+        print('original object', runner)
+        left = copy.deepcopy(runner)
+        right = copy.deepcopy(runner)
+        
+        scenario = runner.scenario
+        
+        
+        angle = scenario.initial_ego_state.center.heading
+        inserted_agent = Agent(
+            tracked_object_type=TrackedObjectType.VEHICLE,
+            oriented_box=OrientedBox(StateSE2(scenario.initial_ego_state.center.x - 2, scenario.initial_ego_state.center.y, angle), 5, 2, 2),
+            velocity=StateVector2D(scenario.initial_ego_state.agent._velocity.x, scenario.initial_ego_state.agent._velocity.y),
+            metadata=SceneObjectMetadata(1623707858950113, "inserted_left", -2, "inserted_left"),
+            angular_velocity=0.0,
+        )
+
+        inserted_goal = StateSE2(scenario.initial_ego_state.center.x+100, scenario.initial_ego_state.center.y+100, 1.25)
+        
+        iter = runner.simulation._time_controller.get_iteration()
+        left.simulation._observations.add_agent_to_scene(
+            inserted_agent, inserted_goal, iter.time_point
+        )
+        
+        left.scenario.modifier = "left"
+        
+        ##############################
+        
+        angle = scenario.initial_ego_state.center.heading
+        inserted_agent = Agent(
+            tracked_object_type=TrackedObjectType.VEHICLE,
+            oriented_box=OrientedBox(StateSE2(scenario.initial_ego_state.center.x + 2, scenario.initial_ego_state.center.y, angle), 5, 2, 2),
+            velocity=StateVector2D(scenario.initial_ego_state.agent._velocity.x, scenario.initial_ego_state.agent._velocity.y),
+            metadata=SceneObjectMetadata(1623707858950113, "inserted_right", -2, "inserted_right"),
+            angular_velocity=0.0,
+        )
+
+        inserted_goal = StateSE2(scenario.initial_ego_state.center.x+100, scenario.initial_ego_state.center.y+100, 1.25)
+        
+        iter = runner.simulation._time_controller.get_iteration()
+        right.simulation._observations.add_agent_to_scene(
+            inserted_agent, inserted_goal, iter.time_point
+        )
+        
+        right.scenario.modifier = "right"
+        print('modded scenario')
+        print(right.scenario.scenario_name)
+        #######################################
+        
+        modified_simulation_runners.append(left)
+        modified_simulation_runners.append(right)
+        
+        return modified_simulation_runners
\ No newline at end of file
diff --git a/nuplan/planning/script/builders/scenario_modifier_builder.py b/nuplan/planning/script/builders/scenario_modifier_builder.py
new file mode 100644
index 0000000000000000000000000000000000000000..1a49e6cab69c407bdb73d8b42dc1a7e8f4d6cdae
--- /dev/null
+++ b/nuplan/planning/script/builders/scenario_modifier_builder.py
@@ -0,0 +1,19 @@
+from typing import List
+
+from nuplan.planning.scenario_builder.scenario_modifier.abstract_scenario_modifier import AbstractScenarioModifier
+from nuplan.planning.scenario_builder.scenario_modifier.left_and_right_modifier import LeftAndRightModifier
+
+
+def build_scenario_modifiers(scenario_modifier_types: List[str]) -> List[AbstractScenarioModifier]:
+    modifiers = []
+    for type in scenario_modifier_types:
+        if type == "left-and-right":
+            modifiers.append(LeftAndRightModifier()) #this one is an example and just injects an agent to the left of ego in one modifiecation of the scenario and to the right in another
+        # elif type == "occluder-injection":
+        #     modifiers.append(OccluderInjection())
+        # elif type == "occludie-injection":
+        #     modifiers.append(OccludieInjection())
+        else:
+            raise ValueError(f"Unknown scenario modifier type: {type}")
+    
+    return modifiers
\ No newline at end of file
diff --git a/nuplan/planning/script/builders/simulation_builder.py b/nuplan/planning/script/builders/simulation_builder.py
index 52abd74a11c3fc7fc3104946adc9b33a3da52f44..7c12b4127f6c25502afde3bfa9b6f83e322956f0 100644
--- a/nuplan/planning/script/builders/simulation_builder.py
+++ b/nuplan/planning/script/builders/simulation_builder.py
@@ -27,6 +27,8 @@ from nuplan.planning.simulation.simulation_time_controller.abstract_simulation_t
 )
 from nuplan.planning.utils.multithreading.worker_pool import WorkerPool
 
+from nuplan.planning.script.builders.scenario_modifier_builder import build_scenario_modifiers
+
 logger = logging.getLogger(__name__)
 
 
@@ -138,6 +140,20 @@ def build_simulations(
                 simulation_history_buffer_duration=cfg.simulation_history_buffer_duration,
             )
             simulations.append(SimulationRunner(simulation, planner))
-
+            
+    # here we need to convert those simulations to our special scenarios
+    if 'modify_scenario_simulations' in cfg and cfg.modify_scenario_simulations:
+        offshoot_scenario_simulations = []
+        scenario_modifiers = build_scenario_modifiers(cfg.modifier_types)
+        logger.info('Modyfing Scenarios...')
+        original_num_runners = len(simulations)
+        for simulation in simulations:
+            for modifier in scenario_modifiers:
+                offshoot_scenario_simulations.extend(modifier.modify_scenario(simulation))
+        simulations = offshoot_scenario_simulations
+        logger.info(f'Created {len(simulations)} modified scenarios from {original_num_runners} scenarios.')   
+    for simulation in simulations:
+        print('c')
+        print(simulation.scenario.scenario_name)
     logger.info('Building simulations...DONE!')
     return simulations
diff --git a/nuplan/planning/script/run_simulation.py b/nuplan/planning/script/run_simulation.py
index 9e3e5cff00c21868b1afcc9dc35d52371cce640f..469e8a3afb028c84cc75cd4bc0ded007171f4223 100644
--- a/nuplan/planning/script/run_simulation.py
+++ b/nuplan/planning/script/run_simulation.py
@@ -106,6 +106,9 @@ def run_simulation(cfg: DictConfig, planners: Optional[Union[AbstractPlanner, Li
         pre_built_planners=planners,
         callbacks_worker=callbacks_worker_pool,
     )
+    
+    for runner in runners:
+        print('d', runner.scenario.scenario_name)
 
     if common_builder.profiler:
         # Stop simulation construction profiling
diff --git a/nuplan/planning/simulation/observation/ml_planner_agents.py b/nuplan/planning/simulation/observation/ml_planner_agents.py
index 07179e423bfb08b3c582c6704f7c6ea6389f2b57..2fde6f896ed84289797ed1589b6d22d44020ffee 100644
--- a/nuplan/planning/simulation/observation/ml_planner_agents.py
+++ b/nuplan/planning/simulation/observation/ml_planner_agents.py
@@ -306,8 +306,12 @@ class MLPlannerAgents(AbstractObservation):
     def add_agent_to_scene(self, agent: Agent, goal: StateSE2, timepoint_record: TimePoint):
         """
         Adds agent to the scene with a given goal during the simulation runtime.
+        Gets dict of tracked agents, or lazily creates them it 
+        from vehicles at simulation start if it does not exist.
         """
 
+        self._agents = self._get_agents() #this action is idempotent
+            
         route_plan = self._get_roadblock_path(agent, goal)
 
         if route_plan:
diff --git a/nuplan/planning/simulation/runner/executor.py b/nuplan/planning/simulation/runner/executor.py
index 1f42051ee29ae02c36815748d65abab64cc058ee..33b6633783e52c5ff61838e34c7137f49bf4a9ff 100644
--- a/nuplan/planning/simulation/runner/executor.py
+++ b/nuplan/planning/simulation/runner/executor.py
@@ -23,6 +23,10 @@ def run_simulation(sim_runner: AbstractRunner, exit_on_failure: bool = False) ->
     """
     # Store start time so that if the simulations fail, we know how long they ran for
     start_time = time.perf_counter()
+    print('hihihi')
+    print(sim_runner.scenario.modifier)
+    print(sim_runner)
+    print('a', sim_runner.scenario.scenario_name)
     try:
         return sim_runner.run()
     except Exception as e:
@@ -80,9 +84,23 @@ def execute_runners(
     # Start simulations
     number_of_sims = len(runners)
     logger.info(f"Starting {number_of_sims} simulations using {worker.__class__.__name__}!")
+    
+    for runner in runners:
+        print('hohoho')
+        print(runner.scenario.modifier)
+        print(runner)
+        print('e', runner.scenario.scenario_name)
+        
+    #run_simulation(runners[0], exit_on_failure) this if you just want to run one without ray.map
+    
+        
     reports: List[RunnerReport] = worker.map(
         Task(fn=run_simulation, num_gpus=num_gpus, num_cpus=num_cpus), runners, exit_on_failure, verbose=verbose
     )
+    reports = []
+    print(len(reports))
+    for report in reports:
+        print(report.scenario_name, report.planner_name, report.log_name)
     # Store the results in a dictionary so we can easily store error tracebacks in the next step, if needed
     results: Dict[Tuple[str, str, str], RunnerReport] = {
         (report.scenario_name, report.planner_name, report.log_name): report for report in reports
@@ -116,6 +134,7 @@ def execute_runners(
     failed_simulations = str()
     number_of_successful = 0
     runner_reports: List[RunnerReport] = list(results.values())
+    print(len(runner_reports))
     for result in runner_reports:
         if result.succeeded:
             number_of_successful += 1