diff --git a/components/common/cpp/CMakeLists.txt b/components/common/cpp/CMakeLists.txt
index 2b99f94b23d2eb130b66a6af9134661b1e9bded9..f85d96d2ce3ba9129b38a0510c7e3495a5893bdb 100644
--- a/components/common/cpp/CMakeLists.txt
+++ b/components/common/cpp/CMakeLists.txt
@@ -1,6 +1,7 @@
 set(COMMONSRC
 	src/config.cpp
 	src/configuration.cpp
+	src/configurable.cpp
 	src/opencv_to_pcl.cpp
 )
 
diff --git a/components/common/cpp/include/ftl/configurable.hpp b/components/common/cpp/include/ftl/configurable.hpp
index 71c8a556401fd568e0808e762fe5d851b9fb522a..d14585dc8ceb4894fded0f2269c8583fc4df5ccd 100644
--- a/components/common/cpp/include/ftl/configurable.hpp
+++ b/components/common/cpp/include/ftl/configurable.hpp
@@ -6,18 +6,35 @@
 #include <nlohmann/json.hpp>
 #include <string>
 #include <tuple>
+#include <map>
+#include <list>
+#include <functional>
 
 #define REQUIRED(...) required(__func__, __VA_ARGS__)
 
 namespace ftl {
 
+/**
+ * The Configurable class should be inherited by any entity that is to be
+ * configured using json objects. Additionally, any such object can then be
+ * reconfigured through changes to that underlying json object with event
+ * callbacks being triggered when specific changes occur.
+ * 
+ * Configurables may also optionally have a URI that enables static methods
+ * of getting and setting configuration options. These static methods are used
+ * by network RPCs to enable remote reconfiguration.
+ */
 class Configurable {
 	public:
 	Configurable() {}
 	explicit Configurable(nlohmann::json &config) : config_(config) {
-
+		if (config["uri"].is_string()) __changeURI(config["uri"].get<std::string>(), this);
 	}
 
+	/**
+	 * Force the JSON object to have specific properties with a specific type.
+	 * If not, emit errors and terminate the application.
+	 */
 	void required(const char *f, const std::vector<std::tuple<std::string, std::string, std::string>> &r) {
 		bool diderror = false;
 		for (auto i : r) {
@@ -33,10 +50,55 @@ class Configurable {
 
 	nlohmann::json &getConfig() { return config_; }
 
+	/**
+	 * Get a configuration property from the json object. Returns an optional
+	 * result which will be empty if the property does not exist or is not of
+	 * the requested type.
+	 */
+	template <typename T>
+	std::optional<T> get(const std::string &name) {
+		try {
+			return config_[name].get<T>();
+		} catch (...) {
+			return {};
+		}
+	}
+
+	/**
+	 * Change a configuration property and trigger any listening event handlers
+	 * for that property. Also triggers the global listeners.
+	 */
+	template <typename T>
+	void set(const std::string &name, T value) {
+		config_[name] = value;
+		_trigger(name);
+	}
+
+	/**
+	 * Add callback for whenever a specified property changes value.
+	 * @param prop Name of property to watch
+	 * @param callback A function object that will be called on change.
+	 */
+	void on(const std::string &prop, std::function<void(Configurable*, const std::string&)>);
+
 	protected:
 	nlohmann::json config_;
+
+	private:
+	std::map<std::string, std::list<std::function<void(Configurable*, const std::string&)>>> observers_; 
+
+	void _trigger(const std::string &name);
+
+	static void __changeURI(const std::string &uri, Configurable *cfg);
 };
 
+/*template <>
+void Configurable::set<const std::string&>(const std::string &name, const std::string &value) {
+	config_[name] = value;
+	if (name == "uri") __changeURI(value, this);
+	_trigger(name);
+}*/
+
 }
 
 #endif  // _FTL_CONFIGURABLE_HPP_
diff --git a/components/common/cpp/src/configurable.cpp b/components/common/cpp/src/configurable.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cea4d74e6b3ef45d3485443e96458ce1e87f814a
--- /dev/null
+++ b/components/common/cpp/src/configurable.cpp
@@ -0,0 +1,24 @@
+#include <ftl/configurable.hpp>
+
+using ftl::Configurable;
+using std::string;
+using std::map;
+using std::list;
+using std::function;
+
+void Configurable::_trigger(const string &name) {
+	auto ix = observers_.find(name);
+	if (ix != observers_.end()) {
+		for (auto &f : (*ix).second) {
+			try {
+				f(this, name);
+			} catch(...) {
+				LOG(ERROR) << "Exception in event handler for '" << name << "'";
+			}
+		}
+	}
+}
+
+void Configurable::__changeURI(const string &uri, Configurable *cfg) {
+
+}
\ No newline at end of file