From klayoutclaw
Orchestrates end-to-end nanodevice design from user query through flake detection, material analysis, geometry creation, routing, evaluation, and save. Device-agnostic methodology derives physics rules from device type and materials.
How this skill is triggered — by the user, by Claude, or both
Slash command
/klayoutclaw:nanodevice_e2e_designThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
A device-agnostic methodology for designing nanodevices on material regions in KLayout. The agent follows 7 reasoning steps, deriving device-specific physics rules from context and user input. No device type is hardcoded.
A device-agnostic methodology for designing nanodevices on material regions in KLayout. The agent follows 7 reasoning steps, deriving device-specific physics rules from context and user input. No device type is hardcoded.
This is a pure-text orchestrator skill. No scripts directory. The agent uses MCP tools and sub-skills at each step.
| # | Step | What the agent does | Skip when |
|---|---|---|---|
| 1 | QUERY | Check if required info is missing; ask only if needed | User provided everything in initial prompt |
| 2 | PREPARE | Run flake detection + GDS alignment if microscope images provided; otherwise verify existing layout | No images provided / layout already prepared |
| 3 | ANALYZE | Study material regions, compute overlaps/exclusions, identify design-relevant zones | Never |
| 4 | DESIGN | Create device geometry via execute_script | Never |
| 5 | ROUTE | Use auto_route tool to connect device contacts to bonding pads | Device has no external contacts |
| 6 | EVALUATE | Run nanodevice DRC + metric evaluator, visually inspect failures, iterate | Never |
| 7 | SAVE | Export GDS + write result.json summary | Never |
Each step has a gate condition. Maximum 2 retries per step. If a step fails after retries, report to the user.
Check the user's initial prompt against this checklist. Only ask about missing items -- skip this step entirely if all required info is provided.
| Parameter | Required? | Notes |
|---|---|---|
| Device type | Yes | What to build (Hall bar, FET, QD, etc.) |
| Material regions | Yes | Which layers have which materials, or microscope images to detect them |
| Layer assignments | Yes | Which layers to use for each design component |
| pixel_size | If images provided | Microns per pixel, needed for detection/alignment |
| Device-specific constraints | If any | Gates, contacts, pin count, dimensions |
| Output path | No | Defaults to source directory |
Gate: All required parameters are known. Proceed.
Conditional step -- only runs if microscope images are provided.
If microscope images are provided:
validate_pixel_size toolnanodevice_flakedetect pipeline (align, detect, combine)nanodevice_gdsalign if a GDS template is providednanodevice_flakedetect_commit to insert material polygons into KLayoutIf starting from an existing layout:
get_layout_infoGate: Material regions exist as polygons on their designated layers in KLayout.
Prerequisite: Material contours must exist as polygons in KLayout, and any reference images must be loaded as background overlays. If they are not present, go back to PREPARE or ask the user.
The agent studies available geometry to inform design decisions:
get_layout_info to identify which layers have material regionsexecute_script with pya.Region to compute overlaps, exclusions, bounding boxesscreenshot to visually inspect material regions and plan device placementThe agent derives material analysis logic from its physics knowledge of the device type. For example:
⚠️ Coordinate-frame contract (read before touching any flake coords)
If
nanodevice_gdsalignhas run, the flake polygons already committed in KLayout (the flake layers — L10-L13 by default, but confirm the mapping from your own commit) are in the GDS reference frame and are the single source of truth. Build the device against THOSE — read them back withpya.Regionin absolute coordinates; do not re-derive flake geometry from raw JSON, and treat the committed flake layers as read-only reference (do not clear and re-insert flakes from an image-frame source).
- The ONLY valid JSON flake source after gdsalign is
traces_gds.json→ per-entrycontour_gds. NEVER readcontour_um(the un-warped image frame): it places the device hundreds of um off the GDS template and scores ~0 (the QH07 failure). Do not invent adevice_geom.jsonwith a hand-labeledframe.- On session recovery (live layout empty /
result.gdsmissing), rebuild flakes fromtraces_gds.json::contour_gdsONLY — never fromcontour_um.- If the markers/flakes look off-frame, that is an alignment failure: re-run gdsalign (see its validated-commit contract), do not patch coordinates by hand.
Gate: The agent has identified where the device should be placed and what material constraints apply, working in the GDS reference frame (the committed L10-L13 flakes).
Create device geometry using execute_script. What to create depends on the device type -- the agent applies its physics knowledge:
The skill does NOT prescribe dimensions, shapes, or layer numbers. The agent derives these from:
Use screenshot after each major geometry addition to visually verify placement.
Gate: Device geometry is present on designated layers. Visual inspection via screenshot confirms correct placement.
Frame guard (mandatory): before passing this gate, assert with pya.Region that the active region (mesa/channel) overlaps the material region the device physics requires — the SAME region you identified in ANALYZE (for a Hall bar that is the graphene∩graphite overlap; for a single-material device it is that one flake region; for a JJ/QD it is whatever its stack needs). Read those regions from the committed flake layers using the layer numbers YOU assigned (do not hard-code L11/L13 — confirm the mapping from your own commit). Procedure: (1) confirm the target flake layer(s) are non-empty — an absent material is a detection/commit problem, not a frame error, so skip the guard for it; (2) if the target region is non-empty but its overlap with the active region is empty, the device is in the wrong frame — STOP, fix the coordinate source (see the frame contract in ANALYZE) or re-run gdsalign, and do not proceed to ROUTE.
⚠️ Material-containment guard — contacts/arm-tips must land ON the flake (not just the mesa body)
The frame guard above only checks that the mesa body overlaps the flake. It does not catch a mesa whose probe arms / contact patches extend PAST the flake boundary — the central body still overlaps, so the frame guard passes, yet the arm-tip ohmic contacts sit in void and every material-keyed metric (
contacts_in_regions,connectivity,mesa_probes,mesa_on_overlap) silently collapses. This is a distinct, common failure (it caps a structurally clean, correctly-framed device well below where it should score).Principle — material-correctness outranks cosmetic shape. A device's contacts and the arm tips that carry them MUST sit inside the required flake region. Never lengthen a probe arm past the flake edge to satisfy a shape target (e.g. a low-
solidity/ "make the mesa concave" goal). Solidity, aspect ratio, and similar shape metrics are cosmetic and rank below keeping every contact on material. If the two conflict, shorten the arm and keep the contact on the flake.Check before passing this gate (in addition to the frame guard): with
pya.Region, intersect the contact-patch shapes (and the probe-arm tips, if separate) with the required flake region. If any contact patch's in-flake area fraction is below ~0.9, that arm is over-extended — pull it back so the patch is fully on the flake, then re-check. (Equivalently, once you have committed flakes you can runevaluate_designwitharm_material_class/component_containmenton the contact component and require a high fraction — the same measurement the official scorer makes.) Do not proceed to ROUTE while contacts hang off the flake.
If the device has contacts that need fan-out to bonding pads:
execute_script (on a temporary layer)execute_script)auto_route MCP tool with appropriate parameters:
pin_layer_a: contact pin layerpin_layer_b: pad pin layeroutput_layer: route layerobstacle_layers: device geometry layers to avoiddry_run=true first to inspect the ordered-loop assignment, then use pin_pairs_override if the required device topology differs.execute_scriptThe agent decides routing topology, line widths, and obstacle avoidance based on device layout. The nanodevice_routing skill is available as a reference for multi-window EBL routing patterns, but is not required.
Gate: All contacts connected to bonding pads. No route crossings.
Run the evaluate_design MCP tool as a nanodevice DRC + metric pass, with a check configuration composed by the agent based on what it designed.
Available check primitives:
| Primitive | Args | Measures |
|---|---|---|
component_overlap | component, region, region_op | Fraction of component area overlapping with region |
component_containment | component, region, region_op | Fraction of component area contained within region |
bulk_containment | component, bulk_region/materials, region_op, core_bbox | Fraction of a device body/core inside a caller-declared bulk region |
arm_material_class | component, classes, containment_threshold | Fraction of shapes landing in exactly one material class |
material_overlap_report | materials | Pairwise and multi-way material-region report |
contact_isolation | component | Fraction of route pairs that don't cross (promotes crossing_pairs) |
connectivity | contact_component, pad_component, route_component, tolerance | Fraction of contacts reaching pads |
route_endpoints | route_component, target_components, tolerance | Fraction of route endpoints on valid targets |
route_material_compat | (optional graphene/graphite keys) | Fraction of ohmic routes that stay OFF the opposing flake material (promotes violating_routes) |
adjacency | component_a, component_b, tolerance | Fraction of A shapes within tolerance of B |
solidity | component, threshold, direction | Shape solidity above/below threshold |
spacing | component_a, component_b, min_distance | Fraction of pairs meeting min distance |
The region arg can be a single layer_map key or a list of keys combined via region_op (union, intersection, difference).
Always include
route_material_compatonce routes exist (for devices with distinct ohmic materials, e.g. a Hall bar's graphene vs graphite contacts). A route that crosses the opposing flake material is an electrical short and is a common, easily-missed cause of a low score. The check returnsviolating_routes[{route_id, contact_kind, crossed_material, area_um2}] — reroute each violator (e.g. fan it out away from the opposing flake) and re-check, exactly as you usecontact_isolation'scrossing_pairsto fix route-route crossings.
Example check list for a Hall bar:
{
"checks": [
{"name": "component_containment", "args": {"component": "mesa", "region": ["graphene", "graphite"], "region_op": "intersection"}, "weight": 0.2},
{"name": "adjacency", "args": {"component_a": "contact_patch", "component_b": "mesa", "tolerance": 2.0}, "weight": 0.15},
{"name": "solidity", "args": {"component": "mesa", "threshold": 0.5, "direction": "below"}, "weight": 0.15},
{"name": "contact_isolation", "args": {"component": "contact_route"}, "weight": 0.15},
{"name": "connectivity", "args": {"contact_component": "contact_patch", "pad_component": "bonding_pad", "route_component": "contact_route"}, "weight": 0.15},
{"name": "route_endpoints", "args": {"route_component": "contact_route", "target_components": ["contact_patch", "mesa", "bonding_pad"]}, "weight": 0.1},
{"name": "spacing", "args": {"component_a": "contact_patch", "min_distance": 1.0}, "weight": 0.1}
]
}
Also take a screenshot for visual inspection.
Gate: Evaluation score >= 0.80 and visual inspection passes.
BENCHMARK FORMAT WARNING: If this task is a benchmark run, the required
result.jsonschema is defined in the task prompt itself. Re-read the task prompt and use the exact schema it specifies. Do NOT fall back to the nested general-purpose format below — a schema mismatch makes the evaluator score 0.0.
Save often — and make sure your BEST result is the one on disk
Follow the benchmark's own rule: save early, save often. A partial result always scores higher than no result; an agent that finishes a good device but times out before saving scores 0.0. So:
- Save as soon as you have a complete, routed device, then re-save whenever you reach a higher EVALUATE score. Overwriting
output/result.gdsis free —save_layoutwrites it atomically (temp + rename), so a verifier never observes a half-written GDS; you do not need staging files.- Write
result.jsonin the exact schema the task prompt specifies (it is usually a flat object with noscorefield — do not add one). Keep it in sync with the saved GDS.- Don't let a later, worse iteration become the final artifact. Only re-save when EVALUATE confirms the new design is at least as good; if an experiment makes things worse, revert the geometry before the next save.
- Confirm the save landed. Read back
output/result.gdssize /get_layout_info. If a tool returns a suspicious, stale, or repeated result (a wedged bridge), callpingto check the server is alive, then re-save.
.new, promote both with one mv).result.json — check if the task or benchmark specifies a required format first and use that exactly. If no format is specified, use this general-purpose default:General format (non-benchmark):
device_type: from QUERYlayer_map: all layer assignments used (e.g. {"mesa": [{"layer": 20, "datatype": 0}], ...})score: final evaluation score from EVALUATEpixel_size: if applicablepipeline_status: per-step pass/fail/retry countschecks: the evaluation check configuration usedfeedback: design notes and any user interventionsGate: GDS file written and result.json contains all required fields.
Maximum 2 retries per step. When a gate fails:
| Failed Step | Retry Action |
|---|---|
| PREPARE | Re-run detection with adjusted parameters |
| ANALYZE | Re-inspect with different region computations |
| DESIGN | Redesign failing component based on gate feedback |
| ROUTE | Re-route with adjusted parameters or manual fallback |
| EVALUATE | Re-run failing design sub-step per lowest-scoring check |
If any step exhausts retries, stop and report to the user.
MCP is the only path by design -- there is no standalone subprocess fallback. If an MCP call hangs, times out, or stops responding partway through the pipeline, the recovery is to restart KLayout, not to route around it.
Don't stand and wait. Restart KLayout:
pkill -f klayout -- kill any running KLayout processes.open /Applications/klayout.app -- relaunch (standalone command; do not chain with &&).http://127.0.0.1:8765/mcp until the server responds (typically 5-10 s after launch).Keeping MCP as the single canonical path forces real bugs to surface instead of being masked by a fallback. After the restart, resume the pipeline from the step that was in flight when the call wedged -- earlier completed steps remain valid in the saved layout if the layout was checkpointed; otherwise, restart from the last gate that was satisfied.
execute_script, auto_route, evaluate_design, screenshot, get_layout_info, save_layout, validate_pixel_sizeinstrMCPdev (has opencv, numpy, scipy, sklearn, shapely, gdstk)layer/datatype (e.g., 11/0)npx claudepluginhub caidish/klayoutclaw --plugin klayoutclawPlace bonding pads and route nanodevice contacts to pads with multi-window EBL support, different line widths per window, and boundary connection patches between EBL write fields.
Drives an open-source EDA flow from RTL to GDS with signoff checks (DRC, LVS, RCX) using OpenROAD-flow-scripts, Yosys, KLayout, and OpenRCX. Use for synthesis, place-and-route, GDS output, signoff verification, PPA iteration, or flow diagnosis.
Routes 17 KiCad MCP tools for schematic creation, PCB layout, autorouting, DRC, and Gerber export. Enforces serialized PCB ops and library-first lookup.