Loading: one file, zero compile
After pip install klayout-klink, klink init scaffolds example_template/ledit_bridge/:
ledit_bridge.cpp— the single macro file. In L-Edit: Tools → Macro → Load Macro… and pick the source file itself (L-Edit compiles it in place; the macro uses only the old-version API subset — older installs compatible by design, tested on v16.x; klink ships zero Siemens/Tanner files — the SDK header comes from your own L-Edit installation).driver.py— dependency-free smoke driver:python driver.py pingshows macro version, current design, and the capability list.tcell_workflows.py— the T-Cell loop CLI (below).
Transport is an inbox/outbox JSON file pair under %LOCALAPPDATA%\klink\ledit_bridge\; the macro polls on the UI thread every 200 ms and answers atomically. A hello.json heartbeat provides liveness.
Capability surface
| Area | Commands |
|---|---|
| Design files | new_design (bootstraps a .tdb even with nothing open) · open_design · save_design |
| Layers | ensure_layer (GDS numbers stamped; new layers auto-colored: solid fill, no outline) · set_layer_style · get_layers (fill color, special-layer flags) |
| Drawing | create_cell · draw (box/polygon/wire/circle, batch) · place_instance (incl. nx×ny arrays) · clear_cell |
| Full readout | get_selection · get_cell (shapes + per-object property trees + instances + ports + labels; wires carry cap/join, torus/pie carry exact params) · list_cells |
| Process knowledge | get_drc_rules — the design's whole rule table, machine-readable |
| T-Cells | get_tcell_params · instance_tcell (programmatic, parameterized) · set_tcell_code (write generator code back as a native T-Cell) |
Exchanging with KLayout (one-call MCP tools)
ledit.status— discovery and triage: macro liveness, whether a design is open, heartbeat age. Call it first when anything misbehaves; errors name the fix.ledit.import_selection— you select in L-Edit, the agent imports into a fresh KLayout cell: circles stay parametric (CIRCLE PCells), layers migrate by name and GDS number (conflicts append, never overwrite), non-convertibles are listed, never dropped.ledit.push_cell— flat KLayout cell back into L-Edit (layers created by name there too).
T-Cells: parametric in both directions
A T-Cell's generator source lives in a cell property the bridge can read whole; parameter names parse deterministically from the generated DO-NOT-EDIT section. That opens both directions, with a single acceptance bar: byte-exact (sorted integer-nanometer boxes, element for element, with L-Edit's own generated geometry as ground truth).
python tcell_workflows.py read NFET_Generator # params + defaults
python tcell_workflows.py variants NFET_Generator --paramsets "[...]" --out ex.json
python tcell_workflows.py writeback MyGen --code gen.cpp --params "[...]"
python tcell_workflows.py verify MyGen --reference ref.py:boxes --paramsets "[...]"
python tcell_workflows.py fit MyGen --paramsets "[...]" --check "[...]" --out fit.json --register MY_DEVICE
- T-Cell → KLayout, geometry-only:
fit(v0.2.2) harvests exemplars and fits the v3 repeat-group model — counts, pitch and positions as exact integer laws, byte-verified against fresh L-Edit variants at held-out points, then registered as a live KLayout PCell (placement byte-verified too). What the model cannot express exactly and uniquely it REFUSES, naming the box family — alternating/parity structure stays on the code route below. - T-Cell → KLayout: read the code → the agent ports the logic to a KLayout-side generator/PCell →
verifybyte-exact on a grid that crosses repetition thresholds. - KLayout → T-Cell: the agent emits UPI code →
writeback(also defines the parameter table) → L-Edit compiles it in place → a native parametric T-Cell, indistinguishable from a hand-written one.
Known boundaries & troubleshooting
| Symptom / boundary | Meaning / fix |
|---|---|
Heartbeat stalls (stale hello.json) | A modal dialog is open in L-Edit (often a T-Cell compile error) — close it and the bridge resumes |
| Changed T-Cell code but geometry unchanged | L-Edit caches variants: use fresh parameter values or Tools → Regenerate T-Cells |
| Drawing into an existing cell doubles content | draw is append-only — regenerate via clear_cell or a fresh cell |
| Two L-Edit instances with the macro | single namespace for now; keep one instance |
A layer shows GDS -1 | it will not export correctly — bridge-created layers stamp numbers; written-back code should follow the need_layer pattern |
Scope: parametric intelligence (fitting, porting, verification) runs on the klink/KLayout side; L-Edit receives native results (static cells or real T-Cells). The bridge is an external adapter shipped with klink, not an L-Edit plugin.