diff --git a/Rec/Allen/src/RunAllen.cpp b/Rec/Allen/src/RunAllen.cpp
index 06f94252c9dc58d6649a5fb04427688a9523d751..800ed6b3ff028d6cc2b94ee9dfe3fd30c980999a 100644
--- a/Rec/Allen/src/RunAllen.cpp
+++ b/Rec/Allen/src/RunAllen.cpp
@@ -129,9 +129,9 @@ StatusCode RunAllen::initialize()
     error() << "Failed to obtain names_of_active_lines from gather_selections " << endmsg;
     return StatusCode::FAILURE;
   }
-  boost::split(m_line_names, selection_names->second, boost::is_any_of(","));
+  boost::split(m_line_names, selection_names->second.get<std::string>(), boost::is_any_of(","));
   if (m_line_names.empty()) {
-    error() << "Failed to obtain any line names from " << selection_names->second << endmsg;
+    error() << "Failed to obtain any line names from " << selection_names->second.get<std::string>() << endmsg;
     return StatusCode::FAILURE;
   }
   else {
diff --git a/configuration/AllenCore/AllenSequenceGenerator.py b/configuration/AllenCore/AllenSequenceGenerator.py
index 71ae4b9d0ebe4407b21cd0d334bb7350eadd267f..5450a6f2a59d6e9aeafd0196864b72cfb92f95f8 100644
--- a/configuration/AllenCore/AllenSequenceGenerator.py
+++ b/configuration/AllenCore/AllenSequenceGenerator.py
@@ -31,7 +31,7 @@ def generate_json_configuration(algorithms, filename):
         if len(algorithm.properties):
             sequence_json[algorithm.name] = {}
             for k, v in algorithm.properties.items():
-                sequence_json[algorithm.name][str(k)] = str(v)
+                sequence_json[algorithm.name][str(k)] = v
 
     # Generate list of configured algorithms
     configured_algorithms = [[f"{algorithm.type.namespace()}::{algorithm.typename}", algorithm.name] for algorithm in algorithms]
diff --git a/configuration/python/AllenConf/HLT1.py b/configuration/python/AllenConf/HLT1.py
index defe3252e341a0e4ca70c5012ee976cebb60b96b..0225d71825f5557b36aa0d84924be8c66c385db7 100644
--- a/configuration/python/AllenConf/HLT1.py
+++ b/configuration/python/AllenConf/HLT1.py
@@ -81,12 +81,12 @@ def default_physics_lines(velo_tracks, forward_tracks, kalman_velo_only,
                 name="Hlt1DiMuonLowMass",
                 pre_scaler_hash_string="di_muon_low_mass_line_pre",
                 post_scaler_hash_string="di_muon_low_mass_line_post",
-                minHighMassTrackPt="500.",
-                minHighMassTrackP="3000.",
-                minMass="0.",
-                maxDoca="0.2",
-                maxVertexChi2="25.",
-                minIPChi2="4.")))
+                minHighMassTrackPt=500.,
+                minHighMassTrackP=3000.,
+                minMass=0.,
+                maxDoca=0.2,
+                maxVertexChi2=25.,
+                minIPChi2=4.)))
     lines.append(
         line_maker("Hlt1DiMuonSoft",
                    make_di_muon_soft_line(forward_tracks, secondary_vertices)))
@@ -138,7 +138,7 @@ def default_monitoring_lines(velo_tracks):
         line_maker(
             "Hlt1NoBeam",
             make_beam_line(
-                beam_crossing_type="0",
+                beam_crossing_type=0,
                 pre_scaler_hash_string="no_beam_line_pre",
                 post_scaler_hash_string="no_beam_line_post"),
             enableGEC=False))
@@ -146,7 +146,7 @@ def default_monitoring_lines(velo_tracks):
         line_maker(
             "Hlt1BeamOne",
             make_beam_line(
-                beam_crossing_type="1",
+                beam_crossing_type=1,
                 pre_scaler_hash_string="beam_one_line_pre",
                 post_scaler_hash_string="beam_one_line_post"),
             enableGEC=False))
@@ -154,7 +154,7 @@ def default_monitoring_lines(velo_tracks):
         line_maker(
             "Hlt1BeamTwo",
             make_beam_line(
-                beam_crossing_type="2",
+                beam_crossing_type=2,
                 pre_scaler_hash_string="beam_two_line_pre",
                 post_scaler_hash_string="beam_two_line_post"),
             enableGEC=False))
@@ -162,7 +162,7 @@ def default_monitoring_lines(velo_tracks):
         line_maker(
             "Hlt1BothBeams",
             make_beam_line(
-                beam_crossing_type="3",
+                beam_crossing_type=3,
                 pre_scaler_hash_string="both_beams_line_pre",
                 post_scaler_hash_string="both_beams_line_post"),
             enableGEC=False))
@@ -175,7 +175,7 @@ def default_monitoring_lines(velo_tracks):
         line_maker(
             "Hlt1ODINLumi",
             make_odin_event_type_line(
-                odin_event_type="0x8",
+                odin_event_type=0x8,
                 pre_scaler_hash_string="odin_lumi_line_pre",
                 post_scaler_hash_string="odin_lumi_line_post"),
             enableGEC=False))
@@ -183,7 +183,7 @@ def default_monitoring_lines(velo_tracks):
         line_maker(
             "Hlt1ODINNoBias",
             make_odin_event_type_line(
-                odin_event_type="0x4",
+                odin_event_type=0x4,
                 pre_scaler_hash_string="odin_no_bias_pre",
                 post_scaler_hash_string="odin_no_bias_post"),
             enableGEC=False))
diff --git a/configuration/python/AllenConf/HLT1_no_calo.py b/configuration/python/AllenConf/HLT1_no_calo.py
index 9a202944d425b7e745bd887cacb1aafdb74fe0fe..4fc21c98b4b8dc05d6813956b22c0b8becc43a79 100644
--- a/configuration/python/AllenConf/HLT1_no_calo.py
+++ b/configuration/python/AllenConf/HLT1_no_calo.py
@@ -99,12 +99,12 @@ def default_physics_lines(forward_tracks, kalman_velo_only,
                 name="Hlt1DiMuonLowMass",
                 pre_scaler_hash_string="di_muon_low_mass_line_pre",
                 post_scaler_hash_string="di_muon_low_mass_line_post",
-                minHighMassTrackPt="500.",
-                minHighMassTrackP="3000.",
-                minMass="0.",
-                maxDoca="0.2",
-                maxVertexChi2="25.",
-                minIPChi2="4."),
+                minHighMassTrackPt=500.,
+                minHighMassTrackP=3000.,
+                minMass=0.,
+                maxDoca=0.2,
+                maxVertexChi2=25.,
+                minIPChi2=4.),
             enableGEC=True))
     lines.append(
         line_maker(
@@ -139,7 +139,7 @@ def default_monitoring_lines(velo_tracks):
         line_maker(
             "Hlt1NoBeam",
             make_beam_line(
-                beam_crossing_type="0",
+                beam_crossing_type=0,
                 pre_scaler_hash_string="no_beam_line_pre",
                 post_scaler_hash_string="no_beam_line_post"),
             enableGEC=False))
@@ -147,7 +147,7 @@ def default_monitoring_lines(velo_tracks):
         line_maker(
             "Hlt1BeamOne",
             make_beam_line(
-                beam_crossing_type="1",
+                beam_crossing_type=1,
                 pre_scaler_hash_string="beam_one_line_pre",
                 post_scaler_hash_string="beam_one_line_post"),
             enableGEC=False))
@@ -155,7 +155,7 @@ def default_monitoring_lines(velo_tracks):
         line_maker(
             "Hlt1BeamTwo",
             make_beam_line(
-                beam_crossing_type="2",
+                beam_crossing_type=2,
                 pre_scaler_hash_string="beam_two_line_pre",
                 post_scaler_hash_string="beam_two_line_post"),
             enableGEC=False))
@@ -163,7 +163,7 @@ def default_monitoring_lines(velo_tracks):
         line_maker(
             "Hlt1BothBeams",
             make_beam_line(
-                beam_crossing_type="3",
+                beam_crossing_type=3,
                 pre_scaler_hash_string="both_beams_line_pre",
                 post_scaler_hash_string="both_beams_line_post"),
             enableGEC=False))
@@ -176,7 +176,7 @@ def default_monitoring_lines(velo_tracks):
         line_maker(
             "Hlt1ODINLumi",
             make_odin_event_type_line(
-                odin_event_type="0x8",
+                odin_event_type=0x8,
                 pre_scaler_hash_string="odin_lumi_line_pre",
                 post_scaler_hash_string="odin_lumi_line_post"),
             enableGEC=False))
@@ -184,7 +184,7 @@ def default_monitoring_lines(velo_tracks):
         line_maker(
             "Hlt1ODINNoBias",
             make_odin_event_type_line(
-                odin_event_type="0x4",
+                odin_event_type=0x4,
                 pre_scaler_hash_string="odin_no_bias_pre",
                 post_scaler_hash_string="odin_no_bias_post"),
             enableGEC=False))
diff --git a/configuration/python/AllenConf/hlt1_monitoring_lines.py b/configuration/python/AllenConf/hlt1_monitoring_lines.py
index bf713b080fae128ad28927762a1e8d3a98e4b562..900c5f67bde958d68d1afb0a7e3f461f0e9fea46 100644
--- a/configuration/python/AllenConf/hlt1_monitoring_lines.py
+++ b/configuration/python/AllenConf/hlt1_monitoring_lines.py
@@ -10,12 +10,12 @@ from AllenCore.generator import make_algorithm
 
 def make_beam_line(pre_scaler_hash_string="beam_line_pre",
                    post_scaler_hash_string="beam_line_post",
-                   beam_crossing_type="0"):
+                   beam_crossing_type=0):
     name_map = {
-        "0": "Hlt1NoBeam",
-        "1": "Hlt1BeamOne",
-        "2": "Hlt1BeamTwo",
-        "3": "Hlt1BothBeams",
+        0: "Hlt1NoBeam",
+        1: "Hlt1BeamOne",
+        2: "Hlt1BeamTwo",
+        3: "Hlt1BothBeams",
     }
     number_of_events = initialize_number_of_events()
     odin = decode_odin()
@@ -59,17 +59,16 @@ def make_velo_micro_bias_line(
 def make_odin_event_type_line(
         pre_scaler_hash_string="odin_event_type_line_pre",
         post_scaler_hash_string="odin_event_type_line_post",
-        odin_event_type="0x8"):
+        odin_event_type=0x8):
     name_map = {0x8: "Hlt1ODINLumi", 0x4: "Hlt1ODINNoBias"}
     number_of_events = initialize_number_of_events()
     odin = decode_odin()
     layout = mep_layout()
-    odin_event_type_int = int(odin_event_type, 0)
 
     return make_algorithm(
         odin_event_type_line_t,
-        name=name_map[odin_event_type_int],
-        odin_event_type=odin_event_type_int,
+        name=name_map[odin_event_type],
+        odin_event_type=odin_event_type,
         host_number_of_events_t=number_of_events["host_number_of_events"],
         dev_odin_raw_input_t=odin["dev_odin_raw_input"],
         dev_odin_raw_input_offsets_t=odin["dev_odin_raw_input_offsets"],
diff --git a/configuration/python/AllenConf/hlt1_muon_lines.py b/configuration/python/AllenConf/hlt1_muon_lines.py
index 9a184ec2f4774b9a49ce311666c48490217beb94..48d045f7ea99d80615cf5a4c0d8858100545749e 100644
--- a/configuration/python/AllenConf/hlt1_muon_lines.py
+++ b/configuration/python/AllenConf/hlt1_muon_lines.py
@@ -60,12 +60,12 @@ def make_di_muon_mass_line(forward_tracks,
                            secondary_vertices,
                            pre_scaler_hash_string="di_muon_mass_line_pre",
                            post_scaler_hash_string="di_muon_mass_line_post",
-                           minHighMassTrackPt="300.",
-                           minHighMassTrackP="6000.",
-                           minMass="2700.",
-                           maxDoca="0.2",
-                           maxVertexChi2="25.",
-                           minIPChi2="0.",
+                           minHighMassTrackPt=300.,
+                           minHighMassTrackP=6000.,
+                           minMass=2700.,
+                           maxDoca=0.2,
+                           maxVertexChi2=25.,
+                           minIPChi2=0.,
                            name="Hlt1DiMuonHighMass"):
     number_of_events = initialize_number_of_events()
     odin = decode_odin()
diff --git a/configuration/python/AllenConf/persistency.py b/configuration/python/AllenConf/persistency.py
index db3fc31643b468ded637ec44ebd63b5781c6ff5e..e2bf4f887de7eb993eb0c81f82a469304c4fa863 100644
--- a/configuration/python/AllenConf/persistency.py
+++ b/configuration/python/AllenConf/persistency.py
@@ -41,7 +41,7 @@ def make_gather_selections(lines):
 
 
 @configurable
-def make_dec_reporter(lines, TCK="0"):
+def make_dec_reporter(lines, TCK=0):
     gather_selections = make_gather_selections(lines)
     number_of_events = initialize_number_of_events()
 
diff --git a/configuration/python/AllenConf/scifi_reconstruction.py b/configuration/python/AllenConf/scifi_reconstruction.py
index 67ea6de8d9adad9ecf5f621bb5932550dce13bc8..c308f303754e0b6a8e86fe9715a522a5724b5935 100644
--- a/configuration/python/AllenConf/scifi_reconstruction.py
+++ b/configuration/python/AllenConf/scifi_reconstruction.py
@@ -62,7 +62,7 @@ def decode_scifi():
 
 
 @configurable
-def make_forward_tracks(decoded_scifi, ut_tracks, hit_window_size="32"):
+def make_forward_tracks(decoded_scifi, ut_tracks, hit_window_size=32):
     number_of_events = initialize_number_of_events()
 
     velo_tracks = ut_tracks["velo_tracks"]
diff --git a/configuration/python/AllenConf/ut_reconstruction.py b/configuration/python/AllenConf/ut_reconstruction.py
index ac971afc1a0b1532ecdf5ab252a93e79115e24ea..ac47ac5d6c4155d8e03e517d699b07a8e704a25c 100644
--- a/configuration/python/AllenConf/ut_reconstruction.py
+++ b/configuration/python/AllenConf/ut_reconstruction.py
@@ -100,18 +100,18 @@ def make_ut_tracks(decoded_ut, velo_tracks, restricted=True):
             "dev_velo_kalman_beamline_states_view"],
         dev_accepted_velo_tracks_t=dev_accepted_velo_tracks_t)
 
-    ut_search_windows_min_momentum = "1250.0"
-    ut_search_windows_min_pt = "275.0"
-    compass_ut_max_considered_before_found = "6"
-    compass_ut_min_momentum_final = "1500.0"
-    compass_ut_min_pt_final = "400.0"
+    ut_search_windows_min_momentum = 1250.0
+    ut_search_windows_min_pt = 275.0
+    compass_ut_max_considered_before_found = 6
+    compass_ut_min_momentum_final = 1500.0
+    compass_ut_min_pt_final = 400.0
 
     if not restricted:
-        ut_search_windows_min_momentum = "1250.0"
-        ut_search_windows_min_pt = "200.0"
-        compass_ut_max_considered_before_found = "6"
-        compass_ut_min_momentum_final = "1500.0"
-        compass_ut_min_pt_final = "250.0"
+        ut_search_windows_min_momentum = 1250.0
+        ut_search_windows_min_pt = 200.0
+        compass_ut_max_considered_before_found = 6
+        compass_ut_min_momentum_final = 1500.0
+        compass_ut_min_pt_final = 250.0
 
     ut_search_windows = make_algorithm(
         ut_search_windows_t,
diff --git a/configuration/python/AllenConf/utils.py b/configuration/python/AllenConf/utils.py
index 8bbc1a3e2fb61a1e3b1ed9cacff63a581e09ad42..26eedea7094c69ec0aa951654796fc7898f80855 100644
--- a/configuration/python/AllenConf/utils.py
+++ b/configuration/python/AllenConf/utils.py
@@ -18,7 +18,7 @@ def initialize_number_of_events():
     }
 
 
-def gec(name="gec", min_scifi_ut_clusters="0", max_scifi_ut_clusters="9750"):
+def gec(name="gec", min_scifi_ut_clusters=0, max_scifi_ut_clusters=9750):
     number_of_events = initialize_number_of_events()
 
     host_ut_banks = make_algorithm(
diff --git a/configuration/python/AllenConf/velo_reconstruction.py b/configuration/python/AllenConf/velo_reconstruction.py
index b06bb4143c8c75c242fc66b45c52df0b9de18609..9c5f1f28a2e7afa35f7d47b60c50a4661b03e330 100644
--- a/configuration/python/AllenConf/velo_reconstruction.py
+++ b/configuration/python/AllenConf/velo_reconstruction.py
@@ -166,6 +166,7 @@ def make_velo_tracks(decoded_velo):
         dev_module_cluster_num_t=dev_module_cluster_num,
         dev_number_of_events_t=number_of_events["dev_number_of_events"],
         dev_velo_clusters_t=dev_velo_clusters,
+        max_skipped_modules=1,
     )
 
     prefix_sum_offsets_velo_tracks = make_algorithm(
diff --git a/main/include/BankTypes.h b/main/include/BankTypes.h
index 760e8216689debaf3aaeb825c7927e8ef6d2883e..20cbe08405f6826d790508cc6a01be4e8f92b339 100644
--- a/main/include/BankTypes.h
+++ b/main/include/BankTypes.h
@@ -11,6 +11,8 @@
 #include <vector>
 #include <cassert>
 #include <gsl/span>
+#include "nlohmann/json.hpp"
+#include "Common.h"
 
 constexpr auto NBankTypes = 11;
 enum class BankTypes { VP, VPRetinaCluster, UT, FT, MUON, ODIN, OTRaw, OTError, Rich, ECal, HCal, Unknown };
@@ -65,4 +67,9 @@ std::unordered_set<BankTypes> banks_set()
   return std::unordered_set<BankTypes> {BANKS...};
 }
 
+// Conversion functions from and to json
+void from_json(const nlohmann::json& j, BankTypes& b);
+
+void to_json(nlohmann::json& j, const BankTypes& b);
+
 #endif
diff --git a/main/include/InputReader.h b/main/include/InputReader.h
index f3fc5199de0cae0b6dc8ab8d5cf3832904fa9e3e..cab5ba0403eb8a8ba6c08521c661b1350a072ed1 100644
--- a/main/include/InputReader.h
+++ b/main/include/InputReader.h
@@ -154,19 +154,22 @@ private:
 
 struct ConfigurationReader {
   ConfigurationReader(const std::string& file_name);
-  ConfigurationReader(const std::map<std::string, std::map<std::string, std::string>>& params) : m_params(params) {}
+  ConfigurationReader(const std::map<std::string, std::map<std::string, nlohmann::json>>& params) : m_params(params) {}
 
-  std::map<std::string, std::string> params(std::string key) const
+  std::map<std::string, nlohmann::json> params(std::string key) const
   {
-    return (m_params.count(key) > 0 ? m_params.at(key) : std::map<std::string, std::string>());
+    return (m_params.count(key) > 0 ? m_params.at(key) : std::map<std::string, nlohmann::json>());
   }
-  std::map<std::string, std::map<std::string, std::string>> params() const { return m_params; }
+  std::map<std::string, std::map<std::string, nlohmann::json>> params() const { return m_params; }
   ConfiguredSequence configured_sequence() const { return m_configured_sequence; }
 
   void save(std::string file_name);
 
+  std::map<std::string, nlohmann::json> get_sequence() const;
+
 private:
-  std::map<std::string, std::map<std::string, std::string>> m_params;
+  std::map<std::string, std::map<std::string, nlohmann::json>> m_params;
+  std::map<std::string, nlohmann::json> m_sequence;
   ConfiguredSequence m_configured_sequence;
 };
 
diff --git a/main/src/Allen.cpp b/main/src/Allen.cpp
index d7cc810980266de246fa5294c9e39f3e352cab38..eb1a149f6812126349148bfe7323984ca773a137 100644
--- a/main/src/Allen.cpp
+++ b/main/src/Allen.cpp
@@ -330,10 +330,10 @@ int allen(
 
   // TODO: Test this
   if (print_config || write_config) {
-    auto algo_config = streams.front()->get_algorithm_configuration();
+    auto algorithm_configuration = streams.front()->get_algorithm_configuration();
     if (print_config) {
       info_cout << "Algorithm configuration\n";
-      for (auto kv : algo_config) {
+      for (auto kv : algorithm_configuration) {
         for (auto kv2 : kv.second) {
           info_cout << " " << kv.first << ":" << kv2.first << " = " << kv2.second << "\n";
         }
@@ -341,7 +341,9 @@ int allen(
     }
     if (write_config) {
       info_cout << "Write full configuration\n";
-      ConfigurationReader saveToJson(algo_config);
+      // Add sequence - this makes the generated json fully operational
+      algorithm_configuration["sequence"] = configuration_reader->get_sequence();
+      ConfigurationReader saveToJson(algorithm_configuration);
       saveToJson.save("config.json");
       return 0;
     }
diff --git a/main/src/BankTypes.cpp b/main/src/BankTypes.cpp
index 668e918da9633dc30bb54c43c073175069bd81f7..ef33a160ca327f504d3bea8e243665e1ea4cdd00 100644
--- a/main/src/BankTypes.cpp
+++ b/main/src/BankTypes.cpp
@@ -43,3 +43,14 @@ BankTypes bank_type(std::string bank_name)
     return BankTypes::Unknown;
   }
 }
+
+void from_json(const nlohmann::json& j, BankTypes& b)
+{
+  std::string s = j.get<std::string>();
+  b = bank_type(s);
+  if (b == BankTypes::Unknown) {
+    throw StrException {"Failed to parse BankType " + s + "."};
+  }
+}
+
+void to_json(nlohmann::json& j, const BankTypes& b) { j = bank_name(b); }
diff --git a/main/src/InputReader.cpp b/main/src/InputReader.cpp
index b84af27f4cbfcdc258126d8283f2c1d24c152a81..5830cbc0d85d600137659fffb1d06bfadb5d6af5 100644
--- a/main/src/InputReader.cpp
+++ b/main/src/InputReader.cpp
@@ -186,21 +186,26 @@ ConfigurationReader::ConfigurationReader(const std::string& file_name)
   for (auto& el : j.items()) {
     std::string component = el.key();
     if (component == "sequence") {
+      m_sequence = {};
       for (auto& el2 : el.value().items()) {
         if (el2.key() == "configured_algorithms") {
+          m_sequence[el2.key()] = el2.value();
           m_configured_sequence.configured_algorithms = ParsedSequence::to_configured<ConfiguredAlgorithm>(
             el2.value().get<ParsedSequence::configured_algorithm_parse_t>());
         }
         else if (el2.key() == "configured_arguments") {
+          m_sequence[el2.key()] = el2.value();
           m_configured_sequence.configured_arguments = ParsedSequence::to_configured<ConfiguredArgument>(
             el2.value().get<ParsedSequence::configured_argument_parse_t>());
         }
         else if (el2.key() == "configured_sequence_arguments") {
+          m_sequence[el2.key()] = el2.value();
           m_configured_sequence.configured_algorithm_arguments =
             ParsedSequence::to_configured<ConfiguredAlgorithmArguments>(
               el2.value().get<ParsedSequence::configured_algorithm_argument_parse_t>());
         }
         else if (el2.key() == "argument_dependencies") {
+          m_sequence[el2.key()] = el2.value();
           m_configured_sequence.argument_dependencies =
             el2.value().get<ParsedSequence::argument_dependencies_parse_t>();
         }
@@ -209,13 +214,7 @@ ConfigurationReader::ConfigurationReader(const std::string& file_name)
     else {
       for (auto& el2 : el.value().items()) {
         std::string property = el2.key();
-        std::string value = "";
-        if (el2.value().is_string()) {
-          value = el2.value().get<std::string>();
-        }
-        else
-          throw StrException("Configuration JSON file " + file_name + " contains non-string parameter values.");
-        m_params[component][property] = value;
+        m_params[component][property] = el2.value();
       }
     }
   }
@@ -229,10 +228,12 @@ ConfigurationReader::ConfigurationReader(const std::string& file_name)
   }
 }
 
+std::map<std::string, nlohmann::json> ConfigurationReader::get_sequence() const { return m_sequence; }
+
 void ConfigurationReader::save(std::string file_name)
 {
   nlohmann::json j(m_params);
   std::ofstream o(file_name);
-  o << std::setw(4) << j;
+  o << j.dump(4);
   o.close();
 }
diff --git a/stream/gear/include/Algorithm.cuh b/stream/gear/include/Algorithm.cuh
index fc425cddd408bc58f78b2077629e4df2f9854b43..ce12d82bd784ce991c57b5734c8f19b85f82ab8c 100644
--- a/stream/gear/include/Algorithm.cuh
+++ b/stream/gear/include/Algorithm.cuh
@@ -12,6 +12,7 @@
 #include "RuntimeOptions.h"
 #include "Constants.cuh"
 #include "HostBuffers.cuh"
+#include "nlohmann/json.hpp"
 #include <any>
 
 namespace {
@@ -86,8 +87,8 @@ namespace Allen {
         *invoke)(void const*, std::any&, const RuntimeOptions&, const Constants&, HostBuffers&, const Allen::Context&) =
         nullptr;
       void (*init)(void*) = nullptr;
-      void (*set_properties)(void*, const std::map<std::string, std::string>&) = nullptr;
-      std::map<std::string, std::string> (*get_properties)(void const*) = nullptr;
+      void (*set_properties)(void*, const std::map<std::string, nlohmann::json>&) = nullptr;
+      std::map<std::string, nlohmann::json> (*get_properties)(void const*) = nullptr;
       std::string (*scope)() = nullptr;
       void (*dtor)(void*) = nullptr;
       void (*run_preconditions)(
@@ -160,7 +161,7 @@ namespace Allen {
             _unused(p);
           }
         },
-        [](void* p, const std::map<std::string, std::string>& algo_config) {
+        [](void* p, const std::map<std::string, nlohmann::json>& algo_config) {
           static_cast<ALGORITHM*>(p)->set_properties(algo_config);
         },
         [](void const* p) { return static_cast<ALGORITHM const*>(p)->get_properties(); },
@@ -245,11 +246,11 @@ namespace Allen {
       (table.invoke)(instance, arg_ref_manager, runtime_options, constants, host_buffers, context);
     }
     void init() { (table.init)(instance); }
-    void set_properties(const std::map<std::string, std::string>& algo_config)
+    void set_properties(const std::map<std::string, nlohmann::json>& algo_config)
     {
       (table.set_properties)(instance, algo_config);
     }
-    std::map<std::string, std::string> get_properties() const { return (table.get_properties)(instance); }
+    std::map<std::string, nlohmann::json> get_properties() const { return (table.get_properties)(instance); }
     std::string scope() const { return (table.scope)(); }
     void run_preconditions(
       std::any& arg_ref_manager,
@@ -307,7 +308,7 @@ namespace Allen {
     Algorithm(Algorithm&&) = delete;
     Algorithm& operator=(Algorithm&&) = delete;
 
-    void set_properties(const std::map<std::string, std::string>& algo_config) override
+    void set_properties(const std::map<std::string, nlohmann::json>& algo_config) override
     {
       for (auto kv : algo_config) {
         auto it = m_properties.find(kv.first);
@@ -318,7 +319,12 @@ namespace Allen {
           throw std::runtime_error {error_message};
         }
         else {
-          it->second->from_string(kv.second);
+          try {
+            it->second->from_json(kv.second);
+          } catch (nlohmann::detail::type_error& e) {
+            std::cerr << "json type error processing property " << kv.first << " of algorithm " << name() << "\n";
+            throw e;
+          }
         }
       }
     }
@@ -344,11 +350,11 @@ namespace Allen {
       return prop->get_value();
     }
 
-    std::map<std::string, std::string> get_properties() const override
+    std::map<std::string, nlohmann::json> get_properties() const override
     {
-      std::map<std::string, std::string> properties;
+      std::map<std::string, nlohmann::json> properties;
       for (const auto& kv : m_properties) {
-        properties.emplace(kv.first, kv.second->to_string());
+        properties.emplace(kv.first, kv.second->to_json());
       }
       return properties;
     }
diff --git a/stream/gear/include/BaseTypes.cuh b/stream/gear/include/BaseTypes.cuh
index 28a327230434fd38acf7e1cdd090c0c45921038b..e3981447b18182df70d4e4fe9ef17a9e15d7f3ee 100644
--- a/stream/gear/include/BaseTypes.cuh
+++ b/stream/gear/include/BaseTypes.cuh
@@ -5,6 +5,7 @@
 
 #include <map>
 #include <string>
+#include "nlohmann/json.hpp"
 
 namespace Allen {
   /**
@@ -14,7 +15,9 @@ namespace Allen {
    */
   class BaseProperty {
   public:
-    virtual bool from_string(const std::string& value) = 0;
+    virtual void from_json(const nlohmann::json& value) = 0;
+
+    virtual nlohmann::json to_json() const = 0;
 
     virtual std::string to_string() const = 0;
 
@@ -28,9 +31,9 @@ namespace Allen {
    *
    */
   struct BaseAlgorithm {
-    virtual void set_properties(const std::map<std::string, std::string>& algo_config) = 0;
+    virtual void set_properties(const std::map<std::string, nlohmann::json>& algo_config) = 0;
 
-    virtual std::map<std::string, std::string> get_properties() const = 0;
+    virtual std::map<std::string, nlohmann::json> get_properties() const = 0;
 
     virtual bool register_property(const std::string& name, BaseProperty* property) = 0;
 
diff --git a/stream/gear/include/Property.cuh b/stream/gear/include/Property.cuh
index 9bf04923fc33df29487ec3733e90d65ed6a394b7..b68cdc7d4add41a33b0cdb954329fbdd5146442f 100644
--- a/stream/gear/include/Property.cuh
+++ b/stream/gear/include/Property.cuh
@@ -19,123 +19,6 @@
 #include <iostream>
 
 namespace Allen {
-  namespace Configuration {
-    namespace Detail {
-      std::regex const array_expr {"\\[(?:\\s*(\\d+)\\s*,?)+\\]"};
-      std::regex const digit_expr {"(\\d+)"};
-    } // namespace Detail
-
-    template<typename T>
-    struct ConvertorFromString {
-      static auto convert(const std::string& s)
-      {
-        if constexpr (std::is_same_v<T, std::string>) {
-          return s;
-        }
-        else if constexpr (std::is_same_v<T, float> || std::is_same_v<T, double>) {
-          return atof(s.c_str());
-        }
-        else if constexpr (std::is_same_v<T, int8_t> || std::is_same_v<T, int16_t> || std::is_same_v<T, int32_t>) {
-          return strtol(s.c_str(), 0, 0);
-        }
-        else if constexpr (std::is_same_v<T, int64_t>) {
-          return strtoll(s.c_str(), 0, 0);
-        }
-        else if constexpr (std::is_same_v<T, uint8_t> || std::is_same_v<T, uint16_t> || std::is_same_v<T, uint32_t>) {
-          return strtoul(s.c_str(), 0, 0);
-        }
-        else if constexpr (std::is_same_v<T, uint64_t>) {
-          return strtoull(s.c_str(), 0, 0);
-        }
-        if constexpr (std::is_same_v<T, bool>) {
-          return atoi(s.c_str());
-        }
-        if constexpr (std::is_same_v<T, char>) {
-          return s.at(0);
-        }
-        else if constexpr (std::is_same_v<T, BankTypes>) {
-          auto bt = bank_type(s);
-          if (bt == BankTypes::Unknown) {
-            throw StrException {"Failed to parse " + s + " into a BankType."};
-          }
-          return bt;
-        }
-        else {
-          throw StrException {"ConvertorFromString instantiated with unsupported type."};
-        }
-      }
-    };
-
-    template<typename T, std::size_t N>
-    struct ConvertorFromString<std::array<T, N>> {
-      static std::array<T, N> convert(const std::string& s)
-      {
-        std::array<T, N> output;
-        std::smatch matches;
-        auto r = std::regex_match(s, matches, Detail::array_expr);
-        if (!r) {
-          throw std::exception {};
-        }
-        auto digits_begin = std::sregex_iterator(s.begin(), s.end(), Detail::digit_expr);
-        auto digits_end = std::sregex_iterator();
-        if (std::distance(digits_begin, digits_end) != N) {
-          throw StrException {"Failed to parse from string, array size mismatch."};
-        }
-        auto i = digits_begin;
-        for (std::size_t idx = 0; idx < N; ++idx, ++i) {
-          output[idx] = ConvertorFromString<T>::convert(i->str());
-        }
-        return output;
-      }
-    };
-
-    template<typename T>
-    struct ConvertorToString {
-      static std::string convert(const T& holder)
-      {
-        if constexpr (std::is_same_v<T, BankTypes>) {
-          return bank_name(holder);
-        }
-        else {
-          std::stringstream s;
-          s << holder;
-          return s.str();
-        }
-      }
-    };
-
-    template<typename T, std::size_t N>
-    struct ConvertorToString<std::array<T, N>> {
-      static std::string convert(const std::array<T, N> holder)
-      {
-        std::stringstream s;
-        s << "[";
-        for (size_t i = 0; i < N; ++i) {
-          s << holder[i];
-          if (i != N - 1) {
-            s << ", ";
-          }
-        }
-        s << "]";
-        return s.str();
-      }
-    };
-
-    // General template
-    template<typename T>
-    bool from_string(T& holder, const std::string& value)
-    {
-      try {
-        holder = ConvertorFromString<typename T::t>::convert(value);
-      } catch (const std::exception&) {
-        std::cerr << "Could not parse JSON string from value \"" << value << "\"\n";
-        return false;
-      }
-
-      return true;
-    }
-  } // namespace Configuration
-
   /**
    * @brief      Store and readout the value of a single configurable algorithm property
    *
@@ -155,17 +38,14 @@ namespace Allen {
 
     V get_value() const { return m_cached_value; }
 
-    virtual bool from_string(const std::string& value) override
-    {
-      V holder;
-      if (!Configuration::from_string<V>(holder, value)) return false;
-      set_value(holder);
-      return true;
-    }
+    void from_json(const nlohmann::json& value) override { set_value(value); }
+
+    nlohmann::json to_json() const override { return m_cached_value.get(); }
 
     std::string to_string() const override
     {
-      return Configuration::ConvertorToString<typename V::t>::convert(m_cached_value.get());
+      nlohmann::json j = m_cached_value.get();
+      return j.dump();
     }
 
     std::string print() const override
@@ -176,7 +56,7 @@ namespace Allen {
       return s.str();
     }
 
-    void set_value(V value) { m_cached_value = value; }
+    void set_value(typename V::t value) { m_cached_value = V {value}; }
 
   private:
     BaseAlgorithm* m_algo = nullptr;
diff --git a/stream/gear/include/Scheduler.cuh b/stream/gear/include/Scheduler.cuh
index 1660cb540240b1ea724aee24fe5ed064074a7499..d5d86f8eb7a471194e20686387d306c26b2b7143 100644
--- a/stream/gear/include/Scheduler.cuh
+++ b/stream/gear/include/Scheduler.cuh
@@ -10,6 +10,7 @@
 #include <utility>
 #include <type_traits>
 #include <AlgorithmDB.h>
+#include "nlohmann/json.hpp"
 
 // use constexpr flag to enable/disable contracts
 #ifdef ENABLE_CONTRACTS
@@ -140,7 +141,7 @@ public:
   }
 
   // Configure constants for algorithms in the sequence
-  void configure_algorithms(const std::map<std::string, std::map<std::string, std::string>>& config)
+  void configure_algorithms(const std::map<std::string, std::map<std::string, nlohmann::json>>& config)
   {
     for (unsigned i = 0; i < m_sequence.size(); ++i) {
       configure(m_sequence[i], config);
@@ -150,7 +151,7 @@ public:
   // Return constants for algorithms in the sequence
   auto get_algorithm_configuration() const
   {
-    std::map<std::string, std::map<std::string, std::string>> config;
+    std::map<std::string, std::map<std::string, nlohmann::json>> config;
     for (unsigned i = 0; i < m_sequence.size(); ++i) {
       get_configuration(m_sequence[i], config);
     }
@@ -203,7 +204,7 @@ public:
 private:
   static void configure(
     Allen::TypeErasedAlgorithm& algorithm,
-    const std::map<std::string, std::map<std::string, std::string>>& config)
+    const std::map<std::string, std::map<std::string, nlohmann::json>>& config)
   {
     auto c = config.find(algorithm.name());
     if (c != config.end()) algorithm.set_properties(c->second);
@@ -213,7 +214,7 @@ private:
 
   static void get_configuration(
     const Allen::TypeErasedAlgorithm& algorithm,
-    std::map<std::string, std::map<std::string, std::string>>& config)
+    std::map<std::string, std::map<std::string, nlohmann::json>>& config)
   {
     config.emplace(algorithm.name(), algorithm.get_properties());
   }
diff --git a/stream/sequence/include/Stream.h b/stream/sequence/include/Stream.h
index ba1d09e7261b7e70a72b12a410b789276819f28f..f89026966698b3541fa7d4cf68c6ddc47c14e03c 100644
--- a/stream/sequence/include/Stream.h
+++ b/stream/sequence/include/Stream.h
@@ -20,6 +20,7 @@
 #include "HostBuffersManager.cuh"
 #include "CheckerInvoker.h"
 #include "Configuration.cuh"
+#include "nlohmann/json.hpp"
 
 struct HostBuffers;
 struct HostBuffersManager;
@@ -58,11 +59,11 @@ public:
 
   Allen::error run(const unsigned buf_idx, RuntimeOptions const& runtime_options);
 
-  void configure_algorithms(const std::map<std::string, std::map<std::string, std::string>>& config);
+  void configure_algorithms(const std::map<std::string, std::map<std::string, nlohmann::json>>& config);
 
   void print_configured_sequence();
 
-  std::map<std::string, std::map<std::string, std::string>> get_algorithm_configuration() const;
+  std::map<std::string, std::map<std::string, nlohmann::json>> get_algorithm_configuration() const;
 
   bool contains_validation_algorithms() const;
 };
diff --git a/stream/sequence/src/Stream.cpp b/stream/sequence/src/Stream.cpp
index bc6f55accc64b20ecfc484075199cf132fa0ae92..8b209d57e1f00401adfad09b098a8230044cc986 100644
--- a/stream/sequence/src/Stream.cpp
+++ b/stream/sequence/src/Stream.cpp
@@ -93,12 +93,12 @@ Allen::error Stream::run(const unsigned buf_idx, const RuntimeOptions& runtime_o
  */
 void Stream::print_configured_sequence() { scheduler->print_sequence(); }
 
-void Stream::configure_algorithms(const std::map<std::string, std::map<std::string, std::string>>& config)
+void Stream::configure_algorithms(const std::map<std::string, std::map<std::string, nlohmann::json>>& config)
 {
   scheduler->configure_algorithms(config);
 }
 
-std::map<std::string, std::map<std::string, std::string>> Stream::get_algorithm_configuration() const
+std::map<std::string, std::map<std::string, nlohmann::json>> Stream::get_algorithm_configuration() const
 {
   return scheduler->get_algorithm_configuration();
 }