gdsfactory can build a full layout from a YAML netlist that describes instances, placements, and routing links. To use a DoRoutes router as the link strategy, register it under a name on the active PDK:

PDK.routing_strategies["doroute_astar"] = add_bundle_astar

After that, any route in the YAML with routing_strategy: doroute_astar will be routed by add_bundle_astar with the arguments under settings:. This lets you describe an entire circuit declaratively and rebuild it from text.

This is optical routing: bends are bend_euler at the PDK minimum radius, and the obstacle layer is WG.

Imports

import gdsfactory as gf
from cspdk.si220.cband import PDK
from doroutes import add_bundle_astar, util

PDK.activate()
PDK.routing_strategies["doroute_astar"] = add_bundle_astar

Two MZIs Linked by a Single-Wire Bundle

The simplest case: two MZIs and one routing link, mzi1.o3 → mzi2.o1. The same add_bundle_astar call applies — a one-wire "bundle" is a fine starting point to confirm the strategy is registered and the YAML wiring is what you expect, before scaling up to a real bundle.

yaml = """
instances:
  mzi1:
    component: mzi
    settings: {}
  mzi2:
    component: mzi
    settings:
      delta_length: 20
connections: {}
routes:
  bundle:
    links:
      mzi1,o3: mzi2,o1
    routing_strategy: doroute_astar
    settings:
        spacing: 1.0
        bend:
            component: bend_euler
            settings:
                radius: 5
        straight: straight
        layers:
            - WG
nets: []
ports:
  o1: mzi1,o1
  o2: mzi2,o2
  o3: mzi2,o3
placements:
  mzi1:
    mirror: 0
    rotation: 0
    x: 0
    y: 0
  mzi2:
    dx: 100
    dy: 100
    mirror: 0
    rotation: 0
    x: mzi1,o2
    y: 0
"""

Build the Layout

c = gf.read.from_yaml(yaml)
util.show_cell(c)
API key for organization 'DoPlayDo' found.

Two-Wire Bundle Across a Crossing

This second netlist places four straight stubs on a 2×2 grid and asks DoRoutes to bundle-route s3-4.o1 → s1-2.o2. The s3-4 / s1-2 notation is gdsfactory shorthand for a port range — handy when you don't want to enumerate every port name. The bundle has to cross the layout from right to left while the obstacle straights sit in the middle, so A* finds a route that clears them.

yaml2 = """
instances:
  s1:
    component: straight
    settings: {}
  s2:
    component: straight
    settings: {}
  s3:
    component: straight
    settings: {}
  s4:
    component: straight
    settings: {}
connections: {}
routes:
  my_bundle:
    links:
      s3-4,o1: s1-2,o2
    routing_strategy: 'doroute_astar'
    settings:
        spacing: 1.0
        bend:
            component: bend_euler
            settings:
                radius: 5
        straight: straight
        layers:
            - WG
nets: []
ports: {}
placements:
  s1:
    y: 100
  s2:
    y: -100
  s3:
    x: 200
    y: 100
  s4:
    x: 200
    y: -100
"""
c = gf.read.from_yaml(yaml2)
c.show()
util.show_cell(c)
API key for organization 'DoPlayDo' found.


2026-04-30 06:17:56.642 | WARNING  | kfactory.kcell:show:3981 - Could not connect to klive server

Next steps