diff --git a/bin/build_detector.sh b/bin/build_detector.sh
index 3c0d89e0e45ada1e2e03dcb6f49ed91d4051169c..299f7fadc8b840cd0888248b44ef362492748dcf 100755
--- a/bin/build_detector.sh
+++ b/bin/build_detector.sh
@@ -65,7 +65,7 @@ echo "Building and installing the ${JUGGLER_DETECTOR} package"
 mkdir -p ${DETECTOR_PREFIX}/build
 pushd ${DETECTOR_PREFIX}/build
 cmake ${DETECTOR_PATH} -DCMAKE_INSTALL_PREFIX=${LOCAL_PREFIX} -DCMAKE_CXX_STANDARD=17 && make -j30 install || exit 1
-cmake ${DETECTOR_PATH} -DCMAKE_INSTALL_PREFIX=${LOCAL_PREFIX}  -DCMAKE_CXX_STANDARD=17  && make -j30 install
+cmake ${DETECTOR_PATH} -DCMAKE_INSTALL_PREFIX=${LOCAL_PREFIX} -DCMAKE_CXX_STANDARD=17 && make -j30 install
 
 ## =============================================================================
 ## Step 3: That's all!
diff --git a/util/collect_benchmarks.py b/bin/collect_benchmarks.py
similarity index 100%
rename from util/collect_benchmarks.py
rename to bin/collect_benchmarks.py
diff --git a/util/collect_tests.py b/bin/collect_tests.py
similarity index 100%
rename from util/collect_tests.py
rename to bin/collect_tests.py
diff --git a/util/compile_analyses.py b/bin/compile_analyses.py
similarity index 100%
rename from util/compile_analyses.py
rename to bin/compile_analyses.py
diff --git a/bin/env.sh b/bin/env.sh
index 4b7b1e7660dae23b5a9ad23661236024b2b96b30..f19c4f3003caae32efc9dd6893125f7b15c747e3 100755
--- a/bin/env.sh
+++ b/bin/env.sh
@@ -13,6 +13,7 @@
 ##
 ## It also defines the following additional variables for internal usage
 ##  - LOCAL_PREFIX:           prefix for packages installed during the benchmark
+##  - LOCAL_DATA_PATH:        local storage for pipeline jobs
 ##  - DETECTOR_PREFIX:        prefix for the detector definitions
 ##  - DETECTOR_PATH:          actual path with the detector definitions
 ##
@@ -70,6 +71,7 @@ export JUGGLER_INSTALL_PREFIX=`realpath ${JUGGLER_INSTALL_PREFIX}`
 
 ## Location of local data for pass data from job to job within pipeline.
 ## Not saved as artifacts.
+## Local /scratch directory is presumed to be writable. 
 if [ ! -n  "${LOCAL_DATA_PATH}" ] ; then 
   export LOCAL_DATA_PATH="/scratch/${CI_PROJECT_NAME}_${CI_PIPELINE_ID}"
 fi
@@ -100,8 +102,8 @@ echo "JUGGLER_N_EVENTS:           ${JUGGLER_N_EVENTS}"
 echo "JUGGLER_N_THREADS:          ${JUGGLER_N_THREADS}"
 echo "JUGGLER_RNG_SEED:           ${JUGGLER_RNG_SEED}"
 echo "JUGGLER_INSTALL_PREFIX:     ${JUGGLER_INSTALL_PREFIX}"
-echo "LOCAL_DATA_PATH:            ${LOCAL_DATA_PATH}"
 echo "LOCAL_PREFIX:               ${LOCAL_PREFIX}"
+echo "LOCAL_DATA_PATH:            ${LOCAL_DATA_PATH}"
 echo "DETECTOR_PREFIX:            ${DETECTOR_PREFIX}"
 echo "DETECTOR_PATH:              ${DETECTOR_PATH}"
 echo "ROOT_BUILD_DIR:             ${ROOT_BUILD_DIR}"
diff --git a/util/run_many.py b/bin/run_many.py
similarity index 100%
rename from util/run_many.py
rename to bin/run_many.py
diff --git a/options/tracker_reconstruction.py b/options/tracker_reconstruction.py
deleted file mode 100644
index 3101824c52cada8cfe524da2dfb8e9c3b027af99..0000000000000000000000000000000000000000
--- a/options/tracker_reconstruction.py
+++ /dev/null
@@ -1,237 +0,0 @@
-from Gaudi.Configuration import *
-
-from GaudiKernel.DataObjectHandleBase import DataObjectHandleBase
-from Configurables import ApplicationMgr, EICDataSvc, PodioOutput, GeoSvc
-from GaudiKernel import SystemOfUnits as units
-
-detector_name = "topside"
-if "JUGGLER_DETECTOR" in os.environ :
-  detector_name = str(os.environ["JUGGLER_DETECTOR"])
-
-# todo add checks
-input_sim_file  = str(os.environ["JUGGLER_SIM_FILE"])
-output_rec_file = str(os.environ["JUGGLER_REC_FILE"])
-n_events = str(os.environ["JUGGLER_N_EVENTS"])
-
-detector_path = detector_name
-if "DETECTOR_PATH" in os.environ :
-    detector_path = str(os.environ["DETECTOR_PATH"])
-
-geo_service  = GeoSvc("GeoSvc",
-        detectors=["{}/{}.xml".format(detector_path, detector_name)])
-podioevent   = EICDataSvc("EventDataSvc", inputs=[input_sim_file], OutputLevel=DEBUG)
-
-from Configurables import PodioInput
-from Configurables import Jug__Base__InputCopier_dd4pod__Geant4ParticleCollection_dd4pod__Geant4ParticleCollection_ as MCCopier
-from Configurables import Jug__Base__InputCopier_dd4pod__CalorimeterHitCollection_dd4pod__CalorimeterHitCollection_ as CalCopier
-from Configurables import Jug__Base__InputCopier_dd4pod__TrackerHitCollection_dd4pod__TrackerHitCollection_ as TrkCopier
-
-from Configurables import Jug__Digi__ExampleCaloDigi as ExampleCaloDigi
-from Configurables import Jug__Digi__UFSDTrackerDigi as UFSDTrackerDigi
-from Configurables import Jug__Digi__EMCalorimeterDigi as EMCalorimeterDigi
-
-from Configurables import Jug__Base__MC2DummyParticle as MC2DummyParticle
-
-from Configurables import Jug__Reco__TrackerHitReconstruction as TrackerHitReconstruction
-
-from Configurables import Jug__Reco__TrackerSourceLinker as TrackerSourceLinker
-from Configurables import Jug__Reco__Tracker2SourceLinker as Tracker2SourceLinker
-#from Configurables import Jug__Reco__TrackerSourcesLinker as TrackerSourcesLinker
-#from Configurables import Jug__Reco__TrackingHitsSourceLinker as TrackingHitsSourceLinker
-from Configurables import Jug__Reco__TrackParamTruthInit as TrackParamTruthInit
-from Configurables import Jug__Reco__TrackParamClusterInit as TrackParamClusterInit
-from Configurables import Jug__Reco__TrackParamVertexClusterInit as TrackParamVertexClusterInit
-
-from Configurables import Jug__Reco__TrackFindingAlgorithm as TrackFindingAlgorithm
-from Configurables import Jug__Reco__ParticlesFromTrackFit as ParticlesFromTrackFit
-from Configurables import Jug__Reco__EMCalReconstruction as EMCalReconstruction
-
-from Configurables import Jug__Reco__SimpleClustering as SimpleClustering
-
-
-
-podioinput = PodioInput("PodioReader", 
-                        collections=["mcparticles","SiTrackerEndcapHits","SiTrackerBarrelHits","EcalBarrelHits"])#, OutputLevel=DEBUG)
-#"SiVertexBarrelHits",
-
-dummy = MC2DummyParticle("MC2Dummy",
-        inputCollection="mcparticles",
-        outputCollection="DummyReconstructedParticles")
-
-## copiers to get around input --> output copy bug. Note the "2" appended to the output collection.
-copier = MCCopier("MCCopier", 
-        inputCollection="mcparticles", 
-        outputCollection="mcparticles2") 
-trkcopier = TrkCopier("TrkCopier", 
-        inputCollection="SiTrackerBarrelHits", 
-        outputCollection="SiTrackerBarrelHits2") 
-
-ecal_digi = EMCalorimeterDigi("ecal_digi", 
-        inputHitCollection="EcalBarrelHits", 
-        outputHitCollection="RawEcalBarrelHits")
-
-ufsd_digi = UFSDTrackerDigi("ufsd_digi", 
-        inputHitCollection="SiTrackerBarrelHits",
-        outputHitCollection="SiTrackerBarrelRawHits",
-        timeResolution=8)
-ufsd_digi2 = UFSDTrackerDigi("ufsd_digi2", 
-        inputHitCollection="SiTrackerEndcapHits",
-        outputHitCollection="SiTrackerEndcapRawHits",
-        timeResolution=8)
-
-#vtx_digi = UFSDTrackerDigi("vtx_digi", 
-#        inputHitCollection="SiVertexBarrelHits",
-#        outputHitCollection="SiVertexBarrelRawHits",
-#        timeResolution=8)
-
-
-ecal_reco = EMCalReconstruction("ecal_reco", 
-        inputHitCollection="RawEcalBarrelHits", 
-        outputHitCollection="RecEcalBarrelHits",
-        minModuleEdep=0.0*units.MeV,
-        OutputLevel=DEBUG)
-
-simple_cluster = SimpleClustering("simple_cluster", 
-        inputHitCollection="RecEcalBarrelHits", 
-        outputClusters="SimpleClusters",
-        minModuleEdep=1.0*units.MeV,
-        maxDistance=50.0*units.cm,
-        OutputLevel=DEBUG)
-
-trk_barrel_reco = TrackerHitReconstruction("trk_barrel_reco",
-        inputHitCollection="SiTrackerBarrelRawHits",
-        outputHitCollection="TrackerBarrelRecHits")
-
-trk_endcap_reco = TrackerHitReconstruction("trk_endcap_reco",
-        inputHitCollection="SiTrackerEndcapRawHits",
-        outputHitCollection="TrackerEndcapRecHits")
-
-#vtx_barrel_reco = TrackerHitReconstruction("vtx_barrel_reco",
-#        inputHitCollection = vtx_digi.outputHitCollection,
-#        outputHitCollection="VertexBarrelRecHits")
-
-# Source linker 
-sourcelinker = TrackerSourceLinker("trk_srclinker",
-        inputHitCollection="TrackerBarrelRecHits",
-        outputSourceLinks="BarrelTrackSourceLinks",
-        OutputLevel=DEBUG)
-
-trk_hits_srclnkr = Tracker2SourceLinker("trk_hits_srclnkr",
-        TrackerBarrelHits="TrackerBarrelRecHits",
-        TrackerEndcapHits="TrackerEndcapRecHits",
-        outputMeasurements="lnker2Measurements",
-        outputSourceLinks="lnker2Links",
-        allTrackerHits="linker2AllHits",
-        OutputLevel=DEBUG)
-
-## Track param init
-truth_trk_init = TrackParamTruthInit("truth_trk_init",
-        inputMCParticles="mcparticles",
-        outputInitialTrackParameters="InitTrackParams",
-        OutputLevel=DEBUG)
-
-clust_trk_init = TrackParamClusterInit("clust_trk_init",
-        inputClusters="SimpleClusters",
-        outputInitialTrackParameters="InitTrackParamsFromClusters",
-        OutputLevel=DEBUG)
-
-#vtxcluster_trk_init = TrackParamVertexClusterInit("vtxcluster_trk_init",
-#        inputVertexHits="VertexBarrelRecHits",
-#        inputClusters="SimpleClusters",
-#        outputInitialTrackParameters="InitTrackParamsFromVtxClusters",
-#        maxHitRadius=40.0*units.mm,
-#        OutputLevel=DEBUG)
-
-# Tracking algorithms
-trk_find_alg = TrackFindingAlgorithm("trk_find_alg",
-        inputSourceLinks = sourcelinker.outputSourceLinks,
-        inputMeasurements = sourcelinker.outputMeasurements,
-        inputInitialTrackParameters= "InitTrackParams",#"InitTrackParamsFromClusters", 
-        outputTrajectories="trajectories",
-        OutputLevel=DEBUG)
-parts_from_fit = ParticlesFromTrackFit("parts_from_fit",
-        inputTrajectories="trajectories",
-        outputParticles="ReconstructedParticles",
-        outputTrackParameters="outputTrackParameters",
-        OutputLevel=DEBUG)
-
-trk_find_alg1 = TrackFindingAlgorithm("trk_find_alg1",
-        inputSourceLinks = trk_hits_srclnkr.outputSourceLinks,
-        inputMeasurements = trk_hits_srclnkr.outputMeasurements,
-        inputInitialTrackParameters= "InitTrackParamsFromClusters", 
-        outputTrajectories="trajectories1",
-        OutputLevel=DEBUG)
-parts_from_fit1 = ParticlesFromTrackFit("parts_from_fit1",
-        inputTrajectories="trajectories1",
-        outputParticles="ReconstructedParticles1",
-        outputTrackParameters="outputTrackParameters1",
-        OutputLevel=DEBUG)
-
-trk_find_alg2 = TrackFindingAlgorithm("trk_find_alg2",
-        inputSourceLinks = trk_hits_srclnkr.outputSourceLinks,
-        inputMeasurements = trk_hits_srclnkr.outputMeasurements,
-        inputInitialTrackParameters= "InitTrackParams",#"InitTrackParamsFromClusters", 
-        #inputInitialTrackParameters= "InitTrackParamsFromVtxClusters", 
-        outputTrajectories="trajectories2",
-        OutputLevel=DEBUG)
-parts_from_fit2 = ParticlesFromTrackFit("parts_from_fit2",
-        inputTrajectories="trajectories2",
-        outputParticles="ReconstructedParticles2",
-        outputTrackParameters="outputTrackParameters2",
-        OutputLevel=DEBUG)
-
-
-#types = []
-## this printout is useful to check that the type information is passed to python correctly
-#print("---------------------------------------\n")
-#print("---\n# List of input and output types by class")
-#for configurable in sorted([ PodioInput, EICDataSvc, PodioOutput,
-#                             TrackerHitReconstruction,ExampleCaloDigi, 
-#                             UFSDTrackerDigi, TrackerSourceLinker,
-#                             PodioOutput],
-#                           key=lambda c: c.getType()):
-#    print("\"{}\":".format(configurable.getType()))
-#    props = configurable.getDefaultProperties()
-#    for propname, prop in sorted(props.items()):
-#        print(" prop name: {}".format(propname))
-#        if isinstance(prop, DataObjectHandleBase):
-#            types.append(prop.type())
-#            print("  {}: \"{}\"".format(propname, prop.type()))
-#print("---")
-
-out = PodioOutput("out", filename=output_rec_file)
-out.outputCommands = ["keep *", 
-        "drop BarrelTrackSourceLinks", 
-        "drop InitTrackParams",
-        "drop trajectories",
-        "drop outputSourceLinks",
-        "drop outputInitialTrackParameters",
-        "drop mcparticles"
-        ]
-
-ApplicationMgr(
-    TopAlg = [podioinput, 
-              dummy,
-              copier, trkcopier,
-              ecal_digi, ufsd_digi2,ufsd_digi, #vtx_digi, 
-              ecal_reco, 
-              simple_cluster,
-              trk_barrel_reco, 
-              trk_endcap_reco, 
-              #vtx_barrel_reco, 
-              sourcelinker, trk_hits_srclnkr,
-              clust_trk_init, 
-              truth_trk_init, 
-              #vtxcluster_trk_init, 
-              trk_find_alg, parts_from_fit,
-              trk_find_alg1, parts_from_fit1,
-              trk_find_alg2, parts_from_fit2,
-              out
-              ],
-    EvtSel = 'NONE',
-    EvtMax   = n_events,
-    ExtSvc = [podioevent,geo_service],
-    OutputLevel=DEBUG
- )
-
-
diff --git a/share/common.yml b/share/common.yml
new file mode 100644
index 0000000000000000000000000000000000000000..985b5c9a70f6a7ab349532f7b0af9b94d50151a5
--- /dev/null
+++ b/share/common.yml
@@ -0,0 +1,14 @@
+common:setup:
+  stage: config
+  artifacts:
+    expire_in: 72 hours 
+    paths:
+      - .local/detector
+      - .local/lib
+      - .local/bin
+      - .local/include
+      - results
+      - config
+  script:
+    - git clone ${CI_REPOSITORY_URL} setup 
+    - source setup/bin/env.sh && ./setup./
diff --git a/util/parse_cmd.sh b/util/parse_cmd.sh
deleted file mode 100755
index 04028d8958d03df22f7b2d964a75acf2d9b47317..0000000000000000000000000000000000000000
--- a/util/parse_cmd.sh
+++ /dev/null
@@ -1,127 +0,0 @@
-#!/bin/bash
-
-## =============================================================================
-## Generic utility script to parse command line arguments for the various
-## bash scripts that control the CI. This script should be source'd with
-## command line arguments from a bash-like (non-POSIX) shell such as
-## bash or zsh.
-##
-## To control some of the functionality of the script, you can set the following
-## environment variables prior to calling the script:
-##   - REQUIRE_DECAY:     require the --decay flag to be set
-## =============================================================================
-
-## Commented out because this should be taken care of by the 
-## calling script to not enforce a fixed directory structure.
-## make sure we launch this script from the project root directory
-#PROJECT_ROOT="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"/..
-#pushd ${PROJECT_ROOT}
-
-## =============================================================================
-## Step 1: Process the command line arguments
-
-function print_the_help {
-  echo "USAGE:    --ebeam E --pbeam E --config C1 --decay D2"
-  echo "          [--config C2 --decay D2 --decay D3 ...]"
-  echo "REQUIRED ARGUMENTS:"
-  echo "          --ebeam       Electron beam energy"
-  echo "          --pbeam       Ion beam energy"
-  echo "          --config      Generator configuration identifiers (at least one)"
-  if [ ! -z ${REQUIRE_DECAY} ]; then
-    echo "        --decay       Specific decay particle (e.g. muon)."
-  fi
-  if [ ! -z ${REQUIRE_LEADING} ]; then
-    echo "        --leading     Leading particle of interest (e.g. jpsi)."
-  fi
-  echo "          -h,--help     Print this message"
-  echo ""
-  echo "  Generate multiple monte carlo samples for a desired process." 
-  exit
-}
-
-## Required variables
-EBEAM=
-PBEAM=
-DECAYS=
-CONFIG=
-
-while [ $# -gt 0 ]
-do
-  key="$1"
-  case $key in
-    --config)
-      CONFIG="$2"
-      shift # past argument
-      shift # past value
-      ;;
-    --ebeam)
-      EBEAM="$2"
-      shift # past argument
-      shift # past value
-      ;;
-    --pbeam)
-      PBEAM="$2"
-      shift # past argument
-      shift # past value
-      ;;
-    --leading)
-      LEADING="$2"
-      shift # past argument
-      shift # past value
-      ;;
-    --decay)
-      DECAY="$2"
-      shift # past argument
-      shift # past value
-      ;;
-    -h|--help)
-      print_the_help
-      exit 0
-      ;;
-    *)    # unknown option
-      echo "unknown option"
-      exit 1
-      ;;
-  esac
-done
-
-if [ -z $CONFIG ]; then
-  echo "ERROR: CONFIG not defined: --config <config>"
-  print_the_help
-  exit 1
-elif [ -z $EBEAM ]; then
-  echo "ERROR: EBEAM not defined: --ebeam <energy>"
-  print_the_help
-  exit 1
-elif [ -z $PBEAM ]; then
-  echo "ERROR: PBEAM not defined: --pbeam <energy>"
-  print_the_help
-  exit 1
-elif [ -z $LEADING ] && [ ! -z $REQUIRE_LEADING ]; then
-  echo "ERROR: LEADING not defined: --leading <channel>"
-  print_the_help
-  exit 1
-elif [ ! -z $LEADING ] && [ -z $REQUIRE_LEADING ]; then
-  echo "ERROR: LEADING flag specified but not required"
-  print_the_help
-  exit 1
-elif [ -z $DECAY ] && [ ! -z $REQUIRE_DECAY ]; then
-  echo "ERROR: DECAY not defined: --decay <channel>"
-  print_the_help
-  exit 1
-elif [ ! -z $DECAY ] && [ -z $REQUIRE_DECAY ]; then
-  echo "ERROR: DECAY flag specified but not required"
-  print_the_help
-  exit 1
-fi
-
-## Export the configured variables
-export CONFIG
-export EBEAM
-export PBEAM
-if [ ! -z $REQUIRE_LEADING ]; then
-  export LEADING
-fi
-if [ ! -z $REQUIRE_DECAY ]; then
-  export DECAY
-fi