diff --git a/hal/cluster.go b/hal/cluster.go
index b5a5c37..0edbe05 100644
--- a/hal/cluster.go
+++ b/hal/cluster.go
@@ -19,18 +19,54 @@ func (c *Cluster) Run(ctx context.Context) error {
 
 type ModuleMapping map[MultiThreadedIOPort]MultiThreadedIOPort
 
-func (mapping ModuleMapping) BuildCluster() *Cluster {
-	modules := make(map[*Module]struct{})
-	for host, client := range mapping {
-		modules[host.Module] = struct{}{}
-		modules[client.Module] = struct{}{}
-		host.Module.IO[host.IOPort] = NewMultiThreadedIO(&client)
+func (config *ClusterConfig) BuildCluster(modules map[string]*Module) (*Cluster, error) {
+	// We assume all modules in the connection config exist
+	for _, c := range config.Connections {
+
+		// For a connection like a -> b we need two channels:
+		// One which is the IN channel on a and the OUT channel on b
+		// One which is the OUT channel on a and the IN channel on b
+		// That means we need to create two IOs, one for each node and two channels
+		// The two channels then need to be passed around
+		// hmmmmmmm...
+
+		outConn := &MultiThreadedIOPort{
+			Module: modules[c.DestNode],
+			IOPort: c.DestPort,
+		}
+		conn := NewMultiThreadedIO(outConn)
+		modules[c.SourceNode].IO[c.SourcePort] = conn
 	}
+
+	//	for host, client := range mapping {
+	//		modules[host.Module] = struct{}{}
+	//		modules[client.Module] = struct{}{}
+	//		host.Module.IO[host.IOPort] = NewMultiThreadedIO(&client)
+	//	}
+
 	cluster := &Cluster{modules: make([]*Module, len(modules), len(modules))}
 	var index int64
-	for module := range modules {
+	for _, module := range modules {
 		cluster.modules[index] = module
 		index++
 	}
-	return cluster
+	return cluster, nil
+}
+
+type ClusterConnection struct {
+	SourcePort int64  `yaml:"source_port"`
+	SourceNode string `yaml:"source_node"`
+	DestPort   int64  `yaml:"dest_port"`
+	DestNode   string `yaml:"dest_node"`
+}
+
+type ClusterNode struct {
+	Name string `yaml:"name"`
+	// Path to the hal program
+	Program string `yaml:"program"`
+}
+
+type ClusterConfig struct {
+	Nodes       []*ClusterNode       `yaml:"nodes"`
+	Connections []*ClusterConnection `yaml:"connections"`
 }
diff --git a/hal/cluster_test.go b/hal/cluster_test.go
index aca165f..5b3b59f 100644
--- a/hal/cluster_test.go
+++ b/hal/cluster_test.go
@@ -1,41 +1,125 @@
 package hal
 
 import (
-	"context"
 	"github.com/stretchr/testify/assert"
 	"testing"
 )
 
-func TestCluster_Run(t *testing.T) {
-	var mapping ModuleMapping
+// func TestCluster_Run(t *testing.T) {
+// 	var mapping ModuleMapping
+//
+// 	firstModule := &Module{
+// 		programStorage: map[int64]*ProgrammedInstruction{
+// 			1: {
+// 				Instruction: InstructionStart,
+// 			},
+// 		},
+// 		register: []float64{0},
+// 		IO:       map[int64]IO{},
+// 	}
+// 	secondModule := &Module{
+// 		programStorage: map[int64]*ProgrammedInstruction{
+// 			1: {
+// 				Instruction: InstructionStop,
+// 			},
+// 		},
+// 		register: []float64{0},
+// 		IO:       map[int64]IO{},
+// 	}
+//
+// 	mapping = map[MultiThreadedIOPort]MultiThreadedIOPort{
+// 		{
+// 			Module: firstModule,
+// 			IOPort: 0,
+// 		}: {
+// 			Module: secondModule,
+// 			IOPort: 0,
+// 		},
+// 	}
+// 	assert.NoError(t, mapping.BuildCluster().Run(context.Background()))
+// }
 
-	firstModule := &Module{
-		programStorage: map[int64]*ProgrammedInstruction{
-			1: {
-				Instruction: InstructionStart,
+func TestModuleMapping_BuildCluster(t *testing.T) {
+	config := &ClusterConfig{
+		Nodes: []*ClusterNode{
+			{
+				Name: "node1",
+			},
+			{
+				Name: "node2",
+			},
+			{
+				Name: "node3",
 			},
 		},
-		register: []float64{0},
-		IO:       map[int64]IO{},
-	}
-	secondModule := &Module{
-		programStorage: map[int64]*ProgrammedInstruction{
-			1: {
-				Instruction: InstructionStop,
+		Connections: []*ClusterConnection{
+			{
+				SourceNode: "node1",
+				SourcePort: 1,
+				DestNode:   "node2",
+				DestPort:   1,
+			},
+			{
+				SourceNode: "node1",
+				SourcePort: 2,
+				DestNode:   "node2",
+				DestPort:   2,
+			},
+			{
+				SourceNode: "node2",
+				SourcePort: 3,
+				DestNode:   "node3",
+				DestPort:   2,
+			},
+			{
+				SourceNode: "node1",
+				SourcePort: 3,
+				DestNode:   "node3",
+				DestPort:   3,
 			},
 		},
-		register: []float64{0},
-		IO:       map[int64]IO{},
 	}
 
-	mapping = map[MultiThreadedIOPort]MultiThreadedIOPort{
-		{
-			Module: firstModule,
-			IOPort: 0,
-		}: {
-			Module: secondModule,
-			IOPort: 0,
+	modules := make(map[string]*Module)
+	modules = map[string]*Module{
+		"node1": {
+			programStorage: map[int64]*ProgrammedInstruction{
+				1: {Instruction: InstructionStart},
+				2: {Instruction: InstructionStop},
+			},
+			register: []float64{0},
+			IO:       map[int64]IO{},
+		},
+		"node2": {
+			programStorage: map[int64]*ProgrammedInstruction{
+				1: {Instruction: InstructionStart},
+				2: {Instruction: InstructionStop},
+			},
+			register: []float64{0},
+			IO:       map[int64]IO{},
+		},
+		"node3": {
+			programStorage: map[int64]*ProgrammedInstruction{
+				1: {Instruction: InstructionStart},
+				2: {Instruction: InstructionStop},
+			},
+			register: []float64{0},
+			IO:       map[int64]IO{},
 		},
 	}
-	assert.NoError(t, mapping.BuildCluster().Run(context.Background()))
+
+	cluster, err := config.BuildCluster(modules)
+	assert.NoError(t, err)
+	// First connection config
+	assert.NotNil(t, cluster.modules[0].IO[1])
+	assert.NotNil(t, cluster.modules[1].IO[1])
+	// Second
+	assert.NotNil(t, cluster.modules[0].IO[2])
+	assert.NotNil(t, cluster.modules[1].IO[2])
+	// Third
+	assert.NotNil(t, cluster.modules[1].IO[3])
+	assert.NotNil(t, cluster.modules[2].IO[2])
+	// Fourth
+	assert.NotNil(t, cluster.modules[0].IO[3])
+	assert.NotNil(t, cluster.modules[2].IO[3])
 }