diff --git a/net/cpp/include/ftl/net/universe.hpp b/net/cpp/include/ftl/net/universe.hpp
index a60785654c4f1caa8a7a734cb769992e91db1158..5e2584f94dcec4559a181411d11da2efbdbf979e 100644
--- a/net/cpp/include/ftl/net/universe.hpp
+++ b/net/cpp/include/ftl/net/universe.hpp
@@ -58,6 +58,14 @@ class Universe {
 	template <typename F>
 	void bind(const std::string &name, F func);
 	
+	/**
+	 * Subscribe a function to a resource. The subscribed function is
+	 * triggered whenever that resource is published to. It is akin to
+	 * RPC broadcast (no return value) to a subgroup of peers.
+	 */
+	template <typename F>
+	bool subscribe(const std::string &res, F func);
+	
 	/**
 	 * Send a non-blocking RPC call with no return value to all connected
 	 * peers.
@@ -65,6 +73,15 @@ class Universe {
 	template <typename... ARGS>
 	void broadcast(const std::string &name, ARGS... args);
 	
+	/**
+	 * Send a non-blocking RPC call with no return value to all subscribers
+	 * of a resource. There may be no subscribers.
+	 */
+	template <typename... ARGS>
+	void publish(const std::string &res, ARGS... args);
+	
+	// TODO(nick) Add find_one, find_all, call_any ...
+	
 	private:
 	void _run();
 	int _setDescriptors();
@@ -82,8 +99,26 @@ class Universe {
 	std::vector<ftl::net::Peer*> peers_;
 	ftl::UUID id_;
 	ftl::net::Dispatcher disp_;
+	
+	// std::map<std::string, std::vector<ftl::net::Peer*>> subscriptions_;
 };
 
+//------------------------------------------------------------------------------
+
+template <typename F>
+void Universe::bind(const std::string &name, F func) {
+	disp_.bind(name, func,
+		typename ftl::internal::func_kind_info<F>::result_kind(),
+	    typename ftl::internal::func_kind_info<F>::args_kind());
+}
+
+template <typename... ARGS>
+void Universe::broadcast(const std::string &name, ARGS... args) {
+	for (auto p : peers_) {
+		p->send(name, args...);
+	}
+}
+
 };  // namespace net
 };  // namespace ftl