diff --git a/applications/rtdt-manager/clab-config/clab-config.go b/applications/rtdt-manager/clab-config/clab-config.go
new file mode 100644
index 0000000000000000000000000000000000000000..97ff714c7cd55045abe44fe40961d713b778f20d
--- /dev/null
+++ b/applications/rtdt-manager/clab-config/clab-config.go
@@ -0,0 +1,187 @@
+package clabconfig
+
+import (
+	"fmt"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"strconv"
+	"strings"
+
+	"gopkg.in/yaml.v3"
+)
+
+// 1st level (Root entry)
+type ClabConfig struct {
+	Name     string   `yaml:"name"`
+	Mgmt     Mgmt     `yaml:"mgmt"`
+	Topology Topology `yaml:"topology"`
+}
+
+// 2nd level
+type Mgmt struct {
+	Network    string `yaml:"network"`
+	IPv4Subnet string `yaml:"ipv4-subnet"`
+	IPv6Subnet string `yaml:"ipv6-subnet"`
+	MTU        int    `yaml:"mtu"`
+}
+
+// 2nd level
+type Topology struct {
+	Nodes map[string]Node `yaml:"nodes"`
+	Links []Link          `yaml:"links"`
+}
+
+// topology.nodes
+type Node struct {
+	Kind         string            `yaml:"kind"`
+	Image        string            `yaml:"image"`
+	Ports        []string          `yaml:"ports,omitempty"`
+	Cmd          string            `yaml:"cmd,omitempty"`
+	MgmtIPv4     string            `yaml:"mgmt-ipv4"`
+	Env          map[string]string `yaml:"env,omitempty"`
+	Binds        []string          `yaml:"binds,omitempty"`
+	StartupDelay int               `yaml:"startup-delay,omitempty"`
+	Group        string            `yaml:"group,omitempty"`
+}
+
+// topology.links
+type Link struct {
+	Endpoints []string `yaml:"endpoints"`
+}
+
+// Read file and parse into ClabConfig struct
+func LoadConfig(filename string) (*ClabConfig, error) {
+	absFilepath, err := filepath.Abs(filename)
+	if err != nil {
+		return nil, fmt.Errorf("Failed to get absolute path: %w", err)
+	}
+	data, err := os.ReadFile(absFilepath)
+	if err != nil {
+		return nil, fmt.Errorf("Failed to read file: %w", err)
+	}
+
+	var clabconfig ClabConfig
+	err = yaml.Unmarshal(data, &clabconfig)
+	if err != nil {
+		return nil, fmt.Errorf("Failed to unmarshal YAML: %w", err)
+	}
+
+	return &clabconfig, nil
+}
+
+// incrementPort takes a port as a string, adds an offset, and returns the new port as a string.
+func incrementPort(port string, offset int) (string, error) {
+	portNum, err := strconv.Atoi(port)
+	if err != nil {
+		return "", fmt.Errorf("invalid port number: %s", port)
+	}
+	return strconv.Itoa(portNum + offset), nil
+}
+func DeriveConfig(clabconfig *ClabConfig, newIPv4Subnet, newIPv6Subnet string, postfix string) (*ClabConfig, error) {
+	// Create deep copy
+	derivedConfig := *clabconfig
+	derivedConfig.Topology.Nodes = make(map[string]Node)
+	derivedConfig.Topology.Links = append([]Link{}, clabconfig.Topology.Links...) // Copy links
+	portOffset := 5
+
+	derivedConfig.Name = fmt.Sprintf("%s_%s", clabconfig.Name, postfix)
+	subnetParts := strings.Split(newIPv4Subnet, ".")
+	derivedConfig.Mgmt.IPv4Subnet = newIPv4Subnet
+	derivedConfig.Mgmt.IPv6Subnet = newIPv6Subnet
+	derivedConfig.Mgmt.Network = fmt.Sprintf("%s-%s", clabconfig.Name, postfix)
+
+	// Adjust all nodes
+	for name, node := range clabconfig.Topology.Nodes {
+		splitIPv4 := strings.Split(node.MgmtIPv4, ".")
+		splitIPv4[0], splitIPv4[1], splitIPv4[2] = subnetParts[0], subnetParts[1], subnetParts[2]
+		node.MgmtIPv4 = strings.Join(splitIPv4, ".")
+
+		// Ports: host side needs to be incremented or there will be conflicts
+		// for now just use 5 as increment
+		for i, portBinding := range node.Ports {
+			parts := strings.Split(portBinding, ":")
+			if len(parts) == 3 {
+				// Format: <host-ip>:<host-port>:<container-port>
+				hostPort := parts[1]
+				newHostPort, err := incrementPort(hostPort, portOffset)
+				if err != nil {
+					return nil, fmt.Errorf("invalid port binding: %s", portBinding)
+				}
+				parts[1] = newHostPort
+			} else if len(parts) == 2 {
+				// Format: <host-port>:<container-port>
+				hostPort := parts[0]
+				newHostPort, err := incrementPort(hostPort, portOffset)
+				if err != nil {
+					return nil, fmt.Errorf("invalid port binding: %s", portBinding)
+				}
+				parts[0] = newHostPort
+			} else {
+				return nil, fmt.Errorf("invalid port binding format: %s", portBinding)
+			}
+			node.Ports[i] = strings.Join(parts, ":")
+		}
+		newName := fmt.Sprintf("%s-%s", name, postfix)
+		derivedConfig.Topology.Nodes[newName] = node
+	}
+
+	// Update Links so they reference the correct nodes
+	for i, link := range clabconfig.Topology.Links {
+		for j, endpoint := range link.Endpoints {
+			parts := strings.Split(endpoint, ":")
+			if len(parts) != 2 {
+				return nil, fmt.Errorf("invalid link endpoint: %s", endpoint)
+			}
+			parts[0] = fmt.Sprintf("%s-%s", parts[0], postfix) // Update the node name
+			clabconfig.Topology.Links[i].Endpoints[j] = strings.Join(parts, ":")
+		}
+	}
+
+	return &derivedConfig, nil
+}
+
+// WriteConfig writes the Config struct to a YAML file
+func WriteConfig(filename string, dirname string, config *ClabConfig) error {
+	data, err := yaml.Marshal(config)
+	if err != nil {
+		return fmt.Errorf("failed to marshal YAML: %w", err)
+	}
+
+	fullPath := filepath.Join(dirname, filename)
+	err = os.WriteFile(fullPath, data, 0644)
+	if err != nil {
+		return fmt.Errorf("failed to write file: %w", err)
+	}
+
+	return nil
+}
+
+func ClabDeploy(filename string, dirname string, stopchan chan os.Signal) error {
+	fullPath := filepath.Join(dirname, filename)
+	cmd := exec.Command("sudo", "containerlab", "deploy", "-t", fullPath, "--reconfigure")
+
+	// Run the command in a Goroutine
+	done := make(chan error, 1)
+	go func() {
+		output, err := cmd.CombinedOutput() // Use CombinedOutput to capture stdout and stderr
+		if err != nil {
+			fmt.Printf("Error during deployment: %s\n", err)
+		} else {
+			fmt.Println(string(output))
+		}
+		done <- err
+		close(done) // Ensure the channel is closed after sending the result
+	}()
+
+	// Wait for the deployment to finish or a signal to stop
+	select {
+	case err := <-done: // Command finished
+		return err
+	case <-stopchan: // Signal received to interrupt
+		if err := cmd.Process.Kill(); err != nil {
+			fmt.Printf("Failed to kill process: %v\n", err)
+		}
+		return fmt.Errorf("deployment interrupted by signal")
+	}
+}
diff --git a/applications/rtdt-manager/data/gosdn_slim.clab.yaml b/applications/rtdt-manager/data/gosdn_slim.clab.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f4d76846cddf22b054f8cee3c4e39d70589cb7ea
--- /dev/null
+++ b/applications/rtdt-manager/data/gosdn_slim.clab.yaml
@@ -0,0 +1,101 @@
+name: gosdn_csbi_arista_base
+
+mgmt:
+  network: gosdn-csbi-arista-base-net
+  ipv4-subnet: 172.100.0.0/16
+  ipv6-subnet: 2001:db8::/64
+  mtu: 1500
+
+topology:
+  nodes:
+    plugin-registry:
+      kind: linux
+      image: plugin-registry
+      mgmt-ipv4: 172.100.0.16
+
+    gosdn:
+      kind: linux
+      image: gosdn
+      ports:
+        - 55055:55055
+        - 8080:8080
+        - 40000:40000
+      cmd: --config /app/configs/containerlab-gosdn.toml
+      mgmt-ipv4: 172.100.0.5
+      env:
+        GOSDN_ADMIN_PASSWORD: TestPassword
+      binds:
+        - ../../artifacts/ssl/gosdn:/app/ssl
+
+    gnmi-target-switch0:
+      kind: linux
+      image: registry.code.fbi.h-da.de/danet/gnmi-target/debian:master
+      #only for local use
+      #image: gnmi-target:latest
+      binds:
+        - ../../artifacts/ssl/gnmi-target:/etc/gnmi-target/ssl
+      ports:
+        - 7030:7030
+      cmd: start --ca_file /etc/gnmi-target/ssl/ca.crt --cert /etc/gnmi-target/ssl/certs/gnmi-target-selfsigned.crt --key /etc/gnmi-target/ssl/private/gnmi-target-selfsigned.key
+      mgmt-ipv4: 172.100.0.11
+      startup-delay: 5
+
+    gnmi-target-switch1:
+      kind: linux
+      image: registry.code.fbi.h-da.de/danet/gnmi-target/debian:master
+      #only for local use
+      #image: gnmi-target:latest
+      binds:
+        - ../../artifacts/ssl/gnmi-target:/etc/gnmi-target/ssl
+      ports:
+        - 7031:7030
+      cmd: start --ca_file /etc/gnmi-target/ssl/ca.crt --cert /etc/gnmi-target/ssl/certs/gnmi-target-selfsigned.crt --key /etc/gnmi-target/ssl/private/gnmi-target-selfsigned.key
+      mgmt-ipv4: 172.100.0.12
+      startup-delay: 5
+
+    centos0:
+      kind: linux
+      image: centos:8
+      mgmt-ipv4: 172.100.0.3
+      group: server
+
+    centos1:
+      kind: linux
+      image: centos:8
+      mgmt-ipv4: 172.100.0.4
+      group: server
+
+    mongodb:
+      kind: linux
+      image: mongo:7
+      ports:
+        - 27017:27017
+      env:
+        MONGO_INITDB_ROOT_USERNAME: root
+        MONGO_INITDB_ROOT_PASSWORD: example
+      mgmt-ipv4: 172.100.0.13
+
+    mongodb-express:
+      kind: linux
+      image: mongo-express:1.0.2
+      ports:
+        - 8081:8081
+      env:
+        ME_CONFIG_MONGODB_AUTH_USERNAME: root
+        ME_CONFIG_MONGODB_AUTH_PASSWORD: example
+        ME_CONFIG_MONGODB_SERVER: mongodb
+        ME_CONFIG_BASICAUTH: "false"
+      mgmt-ipv4: 172.100.0.14
+
+    rabbitmq:
+      kind: linux
+      image: rabbitmq:3-management
+      ports:
+        - 127.0.0.1:5672:5672
+        - 127.0.0.1:15672:15672
+      mgmt-ipv4: 172.100.0.15
+
+  links:
+    - endpoints: ["gnmi-target-switch0:eth1", "gnmi-target-switch1:eth1"]
+    - endpoints: ["gnmi-target-switch0:eth2", "centos0:eth1"]
+    - endpoints: ["gnmi-target-switch1:eth2", "centos1:eth1"]
diff --git a/applications/rtdt-manager/main.go b/applications/rtdt-manager/main.go
index ae0284da71996b51b093e3a08cf01336457361a4..5c58ca8f4a22f5f7eeec0db08c079cf05a09969d 100644
--- a/applications/rtdt-manager/main.go
+++ b/applications/rtdt-manager/main.go
@@ -16,11 +16,14 @@ func main() {
 	var url string
 	var pass string
 	var user string
+	var topology_file string
 	flag.StringVar(&url, "url", "172.100.0.5:55055", "Address of the gosdn controller")
 	flag.StringVar(&pass, "p", "TestPassword", "Password for admin user")
 	flag.StringVar(&user, "u", "admin", "Username")
+	flag.StringVar(&topology_file, "topology", "data/clab.yaml", "Containerlab file on the basis of which to create topo")
 	flag.Parse()
 	fmt.Println("Trying to connect to gosdn controller at ", url)
+	fmt.Println("Topology file path: ", topology_file)
 
 	dialOption := grpc.WithTransportCredentials(insecure.NewCredentials())
 	conn, err := grpc.NewClient(url, dialOption, grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(100*1024*1024)))
@@ -33,11 +36,11 @@ func main() {
 
 	auth := rtdt_auth.NewRtdtAuth(user, url, pass, conn) // logs in and stores token
 	rtdt_app := app.NewApp(conn, auth)
-	rtdtMan := RtdtMan.NewRtdtManager(conn, auth)
-    if rtdtMan == nil {
-        fmt.Println("Couldn't initialize rtdt-manager, quitting!")
-        return
-    }
+	rtdtMan := RtdtMan.NewRtdtManager(conn, auth, topology_file)
+	if rtdtMan == nil {
+		fmt.Println("Couldn't initialize rtdt-manager, quitting!")
+		return
+	}
 	rtdt_app.AddManager(rtdtMan)
 	_ = rtdtMan
 
diff --git a/applications/rtdt-manager/rtdt-manager/rtdt-manager.go b/applications/rtdt-manager/rtdt-manager/rtdt-manager.go
index aa44fd9c0c61fdc74a47efe4e227c18d50a6aa39..bdd440074b754efc92138eccd45734ee16f52235 100644
--- a/applications/rtdt-manager/rtdt-manager/rtdt-manager.go
+++ b/applications/rtdt-manager/rtdt-manager/rtdt-manager.go
@@ -4,8 +4,11 @@ import (
 	"fmt"
 	"os"
 	"os/exec"
+	"os/signal"
 	"path"
 	"path/filepath"
+	"strings"
+	"syscall"
 	"time"
 
 	"code.fbi.h-da.de/danet/gosdn/application-framework/event"
@@ -16,31 +19,96 @@ import (
 	confManPb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/configurationmanagement"
 	pnd "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/pnd"
 	topoPb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/topology"
+	"code.fbi.h-da.de/danet/gosdn/applications/rtdt-manager/clab-config"
 	"code.fbi.h-da.de/danet/gosdn/applications/rtdt-manager/rtdt-auth"
+	"code.fbi.h-da.de/danet/gosdn/applications/rtdt-manager/rtdt-topology"
+	"code.fbi.h-da.de/danet/gosdn/applications/venv-manager/containerlab"
 	"google.golang.org/grpc"
+	"gopkg.in/yaml.v3"
 )
 
+func now() int64 {
+	return int64(time.Now().Nanosecond())
+}
+
+func getGosdnPath() (string, error) {
+	var execPath string
+	var absExecPath string
+	var err error
+	if execPath, err = os.Executable(); err != nil {
+		return "", nil
+	}
+	if absExecPath, err = filepath.Abs(execPath); err != nil {
+		return "", nil
+	}
+	executableDir := filepath.Dir(absExecPath)
+	projectRoot := filepath.Dir(executableDir)
+
+	fmt.Println("Project Root Path:", projectRoot)
+	return projectRoot, nil
+
+}
+
 type RtdtManager struct {
 	auth         *rtdt_auth.RtdtAuth         // auth struct for realnet gosdn
 	conn         *grpc.ClientConn            // connection to twin's gosdn instance
 	Pnd          *pnd.PrincipalNetworkDomain // PND for realnet gosdn
 	topo         *topoPb.Topology            // Topology with which to create clab.yaml
 	sdnConfig    string
+	clabFilename string // Clab file that exemplifies the topology
+	topoData     *containerlab.YamlStruct
+	clabData     *clabconfig.ClabConfig
 	eventService event.ServiceInterface // Receive events from realnet gosdn
-	stopChan     *chan os.Signal
-	// TODO auth and conn for virtual net
+	stopChan     chan os.Signal         // Global stop channel TODO Can I use that like this?
+	// TODO auth and conn for virtual net?
 }
 
-func NewRtdtManager(conn *grpc.ClientConn, auth *rtdt_auth.RtdtAuth) *RtdtManager {
+func NewRtdtManager(conn *grpc.ClientConn, auth *rtdt_auth.RtdtAuth, clabFilename string) *RtdtManager {
+	projectRoot, _ := getGosdnPath()
+
 	rMan := RtdtManager{
-		conn: conn,
-		auth: auth,
+		conn:         conn,
+		auth:         auth,
+		clabFilename: clabFilename,
+		stopChan:     make(chan os.Signal, 1),
 	}
+	signal.Notify(rMan.stopChan, os.Interrupt, syscall.SIGTERM)
+
 	if err := rMan.fetchPndUUID(); err != nil {
 		fmt.Println(err)
 		return nil
 	}
-	if err := rMan.fetchTopology(); err != nil {
+	// The topology of the currently running realnet needs to be parsed. We get this
+	// from the clab.yaml file that was used to create it, that means that --topolog needs to point
+	// to it
+	var err error
+	if rMan.clabData, err = clabconfig.LoadConfig(rMan.clabFilename); err != nil {
+		fmt.Println(err)
+		return nil
+	}
+	var derivedConfig *clabconfig.ClabConfig
+	if derivedConfig, err = clabconfig.DeriveConfig(rMan.clabData, "172.101.0.0/16", "2001:db9::/64", "twin"); err != nil {
+		fmt.Println(err)
+		return nil
+	}
+
+	clabConfigDir := filepath.Join(projectRoot, "dev_env_data/clab")
+	if err := clabconfig.WriteConfig("clab-derived.yaml", clabConfigDir, derivedConfig); err != nil {
+		return nil
+	}
+	if err := clabconfig.ClabDeploy("clab-derived.yaml", clabConfigDir, rMan.stopChan); err != nil {
+		return nil
+	}
+	fmt.Println("Success: RtdtManager created")
+	return &rMan
+	// Now we need to apply the topology to gosdn because it is not done automatically when creating
+	// devices
+	if err := rtdt_topology.ApplyTopology(rMan.topoData); err != nil {
+		fmt.Println(err)
+		return nil
+	}
+	// Write the topology to a file to check
+	if err := rMan.writeModifiedTopologyToFile(rMan.topoData); err != nil {
 		fmt.Println(err)
 		return nil
 	}
@@ -52,14 +120,13 @@ func NewRtdtManager(conn *grpc.ClientConn, auth *rtdt_auth.RtdtAuth) *RtdtManage
 	// 	fmt.Println(err)
 	// 	return nil
 	// }
-	fmt.Println("Success: RtdtManager created")
-	return &rMan
+	return nil
 }
 
 func (rMan *RtdtManager) fetchPndUUID() error {
 	pndService := pnd.NewPndServiceClient(rMan.conn)
 	ctx := rMan.auth.CreateContextWithAuthorization()
-	pndResponse, err := pndService.GetPndList(ctx, &pnd.GetPndListRequest{Timestamp: int64(time.Now().Nanosecond())})
+	pndResponse, err := pndService.GetPndList(ctx, &pnd.GetPndListRequest{Timestamp: now()})
 	if err != nil {
 		return fmt.Errorf("Failed to retrieve PND information: %w", err)
 	}
@@ -72,6 +139,48 @@ func (rMan *RtdtManager) fetchPndUUID() error {
 	}
 }
 
+func (rMan *RtdtManager) applyTopology() error {
+	topoService := topoPb.NewTopologyServiceClient(rMan.conn)
+	ctx := rMan.auth.CreateContextWithAuthorization()
+	topoService.AddLink(ctx, &topoPb.AddLinkRequest{Timestamp: now()})
+
+	return nil
+}
+
+// \cite venv-manager
+// Write a clab.yaml file to launch a different
+func (rMan *RtdtManager) writeModifiedTopologyToFile(clabStruct *containerlab.YamlStruct) error {
+	rMan.topoData.Mgmt.Network = "gosdn-csbi-arist-twin-net"
+
+	splitMainNetwork := strings.Split(rMan.topoData.Mgmt.Ipv4Subnet, ".")
+	splitMainNetwork[1] = "101"
+	rMan.topoData.Mgmt.Ipv4Subnet = strings.Join(splitMainNetwork, ".")
+
+	splitMainNetworkIPv6 := strings.Split(rMan.topoData.Mgmt.Ipv6Subnet, ":")
+	splitMainNetworkIPv6[1] = "db9"
+	rMan.topoData.Mgmt.Ipv6Subnet = strings.Join(splitMainNetworkIPv6, ":")
+
+	// Different network for our twin
+	for i, node := range rMan.topoData.Topology.Nodes {
+		splitIPv4 := strings.Split(node.MgmtIpv4, ".")
+		splitIPv4[1] = "101"
+		node.MgmtIpv4 = strings.Join(splitIPv4, ".")
+		rMan.topoData.Topology.Nodes[i] = node
+	}
+	yaml, err := yaml.Marshal(clabStruct)
+	if err != nil {
+		return err
+	}
+
+	fname := "./topo.clab.tmp.yaml"
+	err = os.WriteFile(fname, yaml, 0600)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
 // This retrieves the topology from the running realnet gosdn instance
 // This is needed to generate the clab file to be used with the virtual net
 // TODO Solve this not returning anything
diff --git a/applications/rtdt-manager/rtdt-topology/rtdt-topology.go b/applications/rtdt-manager/rtdt-topology/rtdt-topology.go
new file mode 100644
index 0000000000000000000000000000000000000000..e7a0b3d94f0d8e41f1e0bed27db8d04accb7dd54
--- /dev/null
+++ b/applications/rtdt-manager/rtdt-topology/rtdt-topology.go
@@ -0,0 +1,78 @@
+package rtdt_topology
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+
+	"code.fbi.h-da.de/danet/gosdn/applications/venv-manager/containerlab"
+	"gopkg.in/yaml.v3"
+)
+
+// Probably don't need a package, just use api inside rtdt-manager.go
+// import (
+// 	"code.fbi.h-da.de/danet/gosdn/api/go/gosdn/topology"
+// 	"code.fbi.h-da.de/danet/gosdn/applications/rtdt-manager/rtdt-auth"
+// 	"google.golang.org/grpc"
+// )
+//
+// type Link struct {
+// 	Id   string
+// 	name string
+// }
+// type Port struct {
+// }
+//
+// type Node struct {
+// }
+//
+// type Topology struct {
+// 	Links *[]Link
+// 	Ports *[]Port
+// 	Nodes *[]Node
+// }
+//
+// func NewTopology() {
+//
+// 	return &Topology{}
+// }
+//
+// func ApplyTopology(conn grpc.ClientConnInterface, auth rtdt_auth.RtdtAuth) {
+// 	ctx := auth.CreateContextWithAuthorization()
+// 	topoService := topology.NewTopologyServiceClient(conn)
+//     addLink := topology.AddLinkRequest{}
+//     topoService.AddLink(ctx, addLink)
+// }
+//
+// func LoadTopologyFromFile()
+
+func ParseTopology(filename string) (*containerlab.YamlStruct, error) {
+	fmt.Println("Parsing file: ", filename)
+	var absFilepath string
+	var err error
+	if absFilepath, err = filepath.Abs(filename); err != nil {
+		return nil, fmt.Errorf("Failed to convert filename %v to absolute path", filename)
+	}
+	fmt.Printf("absolute filepath: %v\n", absFilepath)
+
+	file, err := os.Open(absFilepath)
+	if err != nil {
+		return nil, fmt.Errorf("Encountered error while trying to parse clab file into topology: %v", err)
+	}
+	decoder := yaml.NewDecoder(file)
+	var topoData containerlab.YamlStruct
+	if err := decoder.Decode(&topoData); err != nil {
+		return nil, fmt.Errorf("Failed to decode YAML: %v", err)
+	}
+
+	fmt.Println("Successfully parsed given clab file into topology, nice!")
+
+	return &topoData, nil
+}
+
+
+// Needs to be in rtdt-manager
+func ApplyTopology(topoYaml *containerlab.YamlStruct) error {
+
+	return nil
+}