MCP / RPC reference

MCP 工具完整参考

klink 的控制面只有一份工具目录,两张脸:typed Python client(KLinkClient)和暴露给 agent 的 MCP 工具。二者都由 live plugin 的 method registry 生成,不存在会漂移的手写清单。本页把 83 个 plugin RPC + 39 个 MCP 本地工具(共 122 个)按 11 个领域逐一列出:功能、参数、示例。

总览与约定

MCP 工具名是稳定的 namespace.verb。每个工具都归属唯一一个领域,同一个领域 token 既是 klink.find_tools domain=<token> 的导航键,也是 --profile <token> 的过滤器。

阅读约定

  • 参数表里 name* 表示必填,其余为可选。
  • 坐标:带 _um 后缀是微米(最自然);带 _dbu 是整数数据库单位。micron = dbu × layout.dbudbu 来自 layout.info
  • 图层写法三选一:图层索引 int"L/D" 字符串(如 "1/0")、或 {layer, datatype} 对象。
  • 徽章含义: read 只读 · write 写入 · verify 验证 · escape 逃生舱 · mutates 会改动版图(可 Ctrl+Z 撤销)· long 长耗时(走独立超时)。
批量优先。 生成式版图永远不要一次 RPC 画一个对象——循环里每次调用都要付 TCP + JSON + 事务 + GUI 记账,常慢上百倍。用批量方法:shape.insert_boxes / shape.insert_many / instance.insert_many / instance.insert_pcell_many。单件插入只用于调试单个对象。

动态发现工具

目录是实时查询的,不要死记。Python 侧:

from klink import KLinkClient
with KLinkClient() as c:
    print([m["name"] for m in c.methods()["methods"]])   # meta.methods

MCP 侧,tools/list 会公布每一个工具,而 klink.find_tools 负责导航:

klink.find_tools                          # 无参 → 领域索引(每个领域一行)
klink.find_tools domain="routing_backends"  # 该领域的工具 + 详细用法
klink.find_tools query="lvs route"          # 跨全部工具的关键词排序匹配

不确定用哪个工具时,klink.guide 会报告当前打开了什么、磁盘上已有哪些意图状态(declared nets / LVS 报告 / spec),并给出每个可用意图的字面调用。

Profiles 过滤

--profile 沿两条正交轴过滤 MCP 暴露的工具——意图领域。默认是 read,write,verify,escape

意图 Profile暴露什么
read只读探查:layout.infocell.listshape.queryview.*pcell.*、recorder。
write版图编辑:shape.insert_*cell.createlayer.ensureinstance.insert*edit.undo
verify运行检查:drc.runlvs.run
escape逃生舱:exec.pythonexec.resetevents.*
all全部,不过滤。
python -m klink.mcp --profile read,write,verify,escape      # 默认
python -m klink.mcp --profile read,device_photonics         # 混合两轴
python -m klink.mcp --profile routing_backends              # 只暴露一个领域

所有本地工具在任意意图 profile 下都始终包含;核心导航工具 klink.find_tools / klink.status / klink.reconnect 永远在。旧别名仍有效:basic→readdraw→writeadvanced→escapedrc→verify

1 · 连接、自检、发现与视图 connection_and_view · 15 tools

klink.find_tools domain="connection_and_view"

不确定时从这里开始。 klink.status 报告连接、当前 session、解释器和可选能力(gdsfactory、klayout.db);klink.guide 报告打开了什么 + 磁盘意图状态 + 下一步字面调用;klink.find_tools 按领域/关键词导航其余工具;klink.reconnect 恢复断掉的连接。View 工具是读为主的画布导航——注意新建的 cell 在 view.show_cell 之前是不可见的。截图(view.screenshot)只是用户要的产物,绝不是 agent 的验证步骤,优先用几何查询。

工具参数功能
klink.statusMCP 桥连接状态、当前 session、解释器与上次连接错误。排障第一步
klink.reconnect关掉过期 client 并尝试重连 KLayout。
klink.guide报告已打开内容、磁盘上的意图状态,以及每个可用意图的字面调用和建议下一步。不知道该干嘛就调它。
klink.find_toolsdomain, query按领域或关键词发现工具。无参→领域索引;domain→该域工具+用法;query→排序匹配。
helloclient, protocol介绍 client,拿到 server 信息+能力列表。推荐每条新连接的第一次调用。
meta.ping存活探针,回显 params + trace id,用于测往返延迟。
meta.methods返回完整 RPC 方法目录(描述 + JSON schema),可直接喂给 LLM function-calling。
meta.debug_signalsfireSignalHub 诊断日志;fire="selection_changed" 可触发合成事件测投递链路。
view.list_tabs列出该窗口所有 layout tab(索引、标题、文件、active cell、当前 tab)。
view.activate_tab mutatesindex*按索引切换当前 tab;之后所有单 layout RPC 都作用于该 tab。
view.show_cellcell*, zoom_fit把当前 cellview 显示的 top cell 切成指定 cell(新建 cell 靠它才可见),默认 zoom-fit。
view.screenshotmode, width_px, height_px, bbox_dbu, path渲染 PNG。mode=base64 内嵌 data URL(给有视觉的 LLM);mode=path 存盘返回绝对路径。仅用户请求时用。
view.zoom_fit mutates整幅版图适配视口(等价 GUI 的 Zoom Fit)。
view.zoom_box mutatesbbox_dbu*缩放到恰好显示给定 bbox(dbu)。
view.viewport报告当前视口:可见 bbox(dbu)、视图像素尺寸、cellview 索引。
view.show_lvsdbpath*, kind把存盘的 LVS/netlist 数据库载入 Netlist Browser 并显示,交互 cross-probe。kind=lvs.lvsdbkind=l2n.l2n

示例:连接自检 + 查看当前状态。

# MCP(agent 视角)
klink.status
klink.guide
view.list_tabs

# Python client 等价
from klink import KLinkClient
with KLinkClient() as c:
    print(c.hello(client="my-script"))
    print(c.layout_info(verbosity="summary"))
    print(c.ping(nonce=42))

2 · 多会话注册表与跨会话搬运 multi_session_transfer · 15 tools

klink.find_tools domain="multi_session_transfer"

klink 用一个 MCP 桥驱动多个 KLayout session(每个是本地注册表里的一个端口,通常 8765、8766……)。所有 session 是平等 peer,没有特权端口——显式传你要的那个。搬运是两阶段、确认安全的:transfer_prepare 构建包并在目标 dry-run 后挂起,transfer_commit 才写入。

工具参数功能
klink.session_listinclude_stale从本地注册表枚举可发现的 KLayout/klink session。
klink.session_statussession_id, include_stale返回一条 session 记录,默认当前 MCP session。
klink.session_labelsession_id*, label*, aliases, description给注册的 session 附人类 label 和别名。
klink.session_resolvequery*把 id / label / 别名 / active cell / top cell 解析成一个 session。
klink.session_usesession_id*把 MCP 桥的主 RPC 目标切到指定 session。
klink.session_set_klive_targetsession_id*指定 klive 兼容 8082 入口用的 session(gdsfactory c.show() 落点)。
klink.transfer_preparesource_session*, target_session*, target_cell, copy_mode, layer_map, translate_um构建两 session 间的 flat-selection 搬运包并在目标 dry-run。
klink.transfer_commitpackage_id*, dry_run提交 transfer_prepare 生成的包。
session.mark_klive_target(plugin 侧)把本窗口标记为 klive/gdsfactory 兼容的 8082 目标。
session.label_setsession_id*, label*, aliases, description(plugin 侧)在共享注册表里设 label 和别名。
transfer.pending_setpackage*把已审阅的 flat-selection 包存进本窗口。
transfer.pending_status本窗口挂起搬运包的状态。
transfer.pending_clear清掉挂起包(不写几何)。
transfer.paste_pending mutatesdry_run, clear_after把挂起的 flat-selection 包粘入本窗口(包内已含最终目标层与坐标)。
transfer.import_cell_tree_package mutates longpath*, source_cell*, dry_run用 KLayout 原生 Cell.copy_tree 从 GDS/OAS 包导入一棵 cell 树;重名以 $N 解决。

示例:给窗口打标签,再把选中几何从一个窗口搬到另一个。

klink.session_list
klink.session_label session_id="klayout-8766" label="scratch" aliases=["test"]
klink.session_resolve query="scratch"

# 两阶段搬运:先 prepare + dry-run,看清目标/cell/layer/统计再 commit
klink.transfer_prepare source_session="klayout-8765" target_session="klayout-8766" copy_mode="flat_selection"
klink.transfer_commit package_id="pkg_0001"

3 · 几何与单元结构 geometry_authoring · 28 tools

klink.find_tools domain="geometry_authoring"

核心绘图面。先读layout.infocell.list/cell.treelayer.listshape.queryinstance.querypcell.*再用批量 RPC 写。画之前先 layer.ensure。编辑都包在事务里,edit.undo/redo/status 操作它们。破坏性的 layout.clear/cell.delete 只对一次性测试 cell 用,除非用户明确要求,别碰用户的工作 tab。

读取(geometry, not pixels)

工具参数功能
layout.infoverbosity当前 layout 快照:视图数、active cellview、top cell、源文件、dbu、top-cell 列表、已注册 layer/datatype。想快速了解当前状态就用它。
cell.listname_prefix, top_only, with_bbox, offset, limit扁平分页列出 cell。发现有哪些 cell 用它,层级用 cell.tree
cell.treeroot, max_depth, max_nodes从某 cell 起的层级树(受 depth/nodes 限);每个节点的 instances 数说明它被父实例化几次。
layer.list列出所有已定义图层:layer_index(其他 RPC 用的句柄)、layer/datatype、可选 name,附 dbu_um
shape.query longcell*, layers, bbox_dbu, kinds, limit一个 cell 的形状(不递归)为 JSON。强烈建议用 layers+bbox_dbu 缩小范围并分页(默认 500,最大 5000)。truncated=true 表示还有更多。
instance.queryparent*, child, bbox_dbu, bbox_um, limit列父 cell 的直接子实例:child 名、bbox、变换、array、PCell 元数据、子 cell 各层形状计数。
pcell.libraries列可用 PCell 库(Basic 恒在;PDK 注册自己的)。
pcell.listlibrary列某库(默认 Basic)里全部 PCell 名。
pcell.infolibrary, pcell*描述一个 PCell 的参数(name/type/default/description/choices),据此构造 instance.insert_pcell 的 params。

写入 · 单元与图层

工具参数功能
cell.create mutatesname新建 cell;重名时 KLayout 追加 $1…(返回生效名)。不保证幂等,每次调用建新 cell。
cell.rename mutatescell*, new_name*, allow_suffix重命名;重名默认报错(allow_suffix=true 才自动加后缀)。
cell.delete mutatescell*, recursive删 cell。recursive=true 连带删孤儿子 cell;默认残留 ghost 引用。破坏性
layer.ensure mutateslayer*, datatype, name确保 GDS 层存在(缺则在事务里建),返回 layer_index。纯 upsert,可反复调。

写入 · 形状(批量优先)

工具参数功能
shape.insert_boxes mutatescell, layer, boxes_um / boxes_dbu批量:一次 RPC、一个事务插入很多矩形到同一 cell/层。生成式版图首选。
shape.insert_many mutatescell*, items*, dry_run批量:一次插入混合形状(box/polygon/path/text),每项带自己的层选择器和几何字段。
shape.insert_box mutatescell, layer, bbox_um / bbox_dbu单个轴对齐矩形。调试单对象用。
shape.insert_polygon mutatescell, layer, points_um / points_dbu单个多边形(仅外壳,暂不支持洞),≥3 点,自动闭合。
shape.insert_path mutatescell, layer, points, width, begin_ext, end_ext, round_ends单条 path(中心线+宽度),可选端延伸与圆头。
shape.insert_text mutatescell, layer, position, size_um单个文本标签(非几何注记,不产生掩模)。
shape.delete mutatescell, layer(s), bbox, kinds, dry_run按声明式选择器删形状(层 + 可选 bbox + 可选 kinds)。dry_run=true 先看计数。整批一个事务,可一次 undo。

写入 · 实例与 PCell(批量优先)

工具参数功能
instance.insert_many mutatesparent*, items*, dry_run批量:一次插入很多已存在子 cell 实例。每项含 child + 变换/array 字段。
instance.insert_pcell_many mutatesparent*, items*, dry_run批量:一次插入很多 PCell 实例(library/pcell/params/变换/array)。
instance.insert mutatesparent*, child*, position, rotation, mirror, magnification, array把 child 放进 parent。位置微米/dbu,旋转度数,可选 array 建网格。
instance.insert_pcell mutatesparent*, library, pcell*, params, position, rotation, …从库构建一个 PCell 变体 cell(如 Basic.CIRCLE/TEXT)再插一个实例。先 pcell.info 查参数。相同 params 复用同一变体。
instance.queryparent*, child, bbox, limit(见上)读父 cell 的子实例。
instance.delete mutatesparent*, child, bbox, all, limit, dry_run按声明式选择器删实例(对子 cell 本身非破坏,只去引用)。一个事务。
pcell.register_fittedname*, fit_table*运行期从 fit table 注册一个拟合器件 PCell(klink_transistor_pcell_fit_v1),落到 klink_structdevice 库,无需重载插件。新器件族零插件改动。

写入 · Layout 级与编辑历史

工具参数功能
layout.show_file mutates longpath*, mode, keep_position, technology载入 GDS/OAS(已开则 reload)。mode=replace 当前视图 / new 新 tab。录制时合并为一行。
layout.save_file mutatespath*, cellview_index存盘。扩展名决定格式:.gds/.gds2 GDSII,.oas/.oasis OASIS。
layout.clear mutatescellview_index破坏性:清空整幅 layout(所有 cell/形状/层级)。
edit.undo mutates撤销最近一次可撤销操作(klink RPC、Macro IDE 编辑或 GUI 编辑)。返回前后栈快照。
edit.redo mutates重做,与 edit.undo 配对。
edit.statusdebug报告当前 undo/redo 可用性;debug=true 暴露 Manager 内省字段。

示例:先读当前状态 → 建 cell 与层 → 批量画 → 显示。

# 1) 读
layout.info verbosity="summary"
cell.list top_only=true

# 2) 建 cell + 确保层
cell.create name="MYBLOCK"
layer.ensure layer=1 datatype=0 name="M1"

# 3) 批量画一排矩形(微米)——不要循环单插!
shape.insert_boxes cell="MYBLOCK" layer="1/0" boxes_um=[[0,0,10,4],[20,0,30,4],[40,0,50,4]]

# 4) 混合形状一次插入
shape.insert_many cell="MYBLOCK" items=[
  {"kind":"box","layer":"1/0","bbox_um":[0,10,50,14]},
  {"kind":"path","layer":"2/0","points_um":[[0,20],[50,20]],"width_um":2},
  {"kind":"text","layer":"63/0","position_um":[0,26],"text":"MYBLOCK","size_um":4}
]

# 5) 让它可见(新 cell 在 show_cell 前不可见)
view.show_cell cell="MYBLOCK"

示例:放置 Basic.CIRCLE PCell(先查参数)。

pcell.info library="Basic" pcell="CIRCLE"
instance.insert_pcell parent="MYBLOCK" library="Basic" pcell="CIRCLE" \
    params={"l":"1/0","r":5.0,"n":64} position_um=[100,0]

# 一次放一个 8×8 网格
instance.insert parent="TOP" child="MYBLOCK" position_um=[0,0] \
    array={"rows":8,"cols":8,"pitch_x_um":60,"pitch_y_um":40}

4 · 选择与 SEND 交互记忆 selection_and_send_memory · 11 tools

klink.find_tools domain="selection_and_send_memory"

两件不同的事。selection.* 是 KLayout 里当前的实时选择interaction.* 是用户明确 SEND 过(工具栏 SEND,记成 sel_0006 这样的 id)的持久 session 记忆。当用户说“刚发的”“这块区域”“这里”“那一个”时用它们——按顺序/数量解析,不是按时间;把用户措辞绑到这些 id/查询,而不是绑到截图。

工具参数功能
selection.getlimit当前视图的选择,每项是 shape(层+bbox)或 instance(目标 cell+bbox)。空选择返回空列表,不是错误。
selection.set_box mutatescell*, bbox_dbu*, layers, limit选中 cell 内 bbox 与给定框相交的所有形状(默认全层),替换当前选择,返回选中数。
selection.clear mutates清空当前选择。
selection.send_contextsource, max_items把当前非空选择作为 selection_sent 事件显式发出(agent 侧 SEND)。不在 plugin 存记忆。
interaction.selection.latest本 MCP session 记忆里最新一次 SEND。
interaction.selection.recentlimit最近若干次 SEND(默认最新 5,按顺序不按时间裁剪)。
interaction.selection.getid*按稳定 id 读一条存储选择。
interaction.selection.labelid*, label, description给某条存储选择加/改 label 和描述。
interaction.selection.clear_sessionconfirm*确认后清掉本 MCP session 的持久交互上下文。
interaction.contextinclude_current_selection同时返回当前 KLayout 选择 + 最近持久 SEND 记忆。

示例:解析“把我刚发的两块连起来”。

# 用户在 KLayout 里选中 A,点 SEND;再选中 B,点 SEND
interaction.selection.recent limit=2       # → [sel_0007(B), sel_0006(A)]
interaction.selection.label id="sel_0006" label="probe pad"
# 现在按 id 去 mark port / 声明 net,而不是靠截图猜位置

5 · Port 与 Anchor(路由标记) ports_and_anchors · 16 tools

klink.find_tools domain="ports_and_anchors"

Port 是网络端点(klink_Port PCell:带 net + 朝向 + 宽度)。Anchor 是路由约束(klink_Anchor PCell),kindwaypoint_region / bend_region / corridor(普通 corridor 是必经通道;给它 choice_group=BUS 才变成可选通道)。路由工具默认 port_layer=999/99anchor_layer=999/1Keepout 不是 anchor 类型——它是你传给路由工具的 obstacle_layers(你自己设计里的层);klink 不带默认 keepout 层。这些是路由后端的输入:先 mark Port+Anchor,再调 routing.*

工具参数功能
port.set_layer mutateslayer*配置本 layout 的默认 Port 标记层。
port.mark mutatescell*, name, center, orientation, width_um, port_type, net, target_layer, …在 cell 里建一个 klink_Port PCell 实例(一个端点)。
port.listcell*, layer, sort列 cell 里的 Port(给 layer 则只列该标记层的)。
port.update mutatescell*, name*, orientation, width_um, net, …按不可变 name 更新单个 Port。
port.transform mutatescell*, names / selection, rotate_delta, net, …按 names 或 GUI 选择批量更新 Port 参数。
port.repair_names mutatescell*, layer, prefix修复重复/空 Port 名(主要给经 GUI PCell 面板手插、绕过唯一性检查的)。
port.unmark mutatescell*, name*按 name 删一个 Port。
port.delete_all mutatescell*, layer删 cell 里全部 Port。
anchor.set_layer mutateslayer*配置默认 Anchor 标记层。
anchor.mark mutatescell*, kind, center, net, radius_um, width_um, height_um, path_points, …建一个 klink_Anchor PCell 实例(路由约束)。
anchor.listcell*, layer, sort列 cell 里的 Anchor。
anchor.update mutatescell*, id*, new_id, kind, net, …按不可变 id 更新单个 Anchor。
anchor.transform mutatescell*, ids / names / selection, kind, …按 ids 或选择批量更新 Anchor。
anchor.repair_ids mutatescell*, layer, prefix修复重复/空 Anchor id(GUI 手插的)。
anchor.unmark mutatescell*, id*按 id 删一个 Anchor。
anchor.delete_all mutatescell*, layer删 cell 里全部 Anchor。

示例:标两个对着的 Port,加一个必经 waypoint,然后路由。

port.mark cell="NET1" name="A" center_um=[0,0]   orientation="E" width_um=2 net="sig"
port.mark cell="NET1" name="B" center_um=[80,20] orientation="W" width_um=2 net="sig"
anchor.mark cell="NET1" kind="waypoint_region" center_um=[40,40] radius_um=6 net="sig"
port.list cell="NET1"

routing.tapered_hybrid_cell cell="NET1" angle_mode="manhattan" obstacle_layers=["10/0"]

6 · 路由后端 routing_backends · 9 tools

klink.find_tools domain="routing_backends"

都读一个 cell 里的 Port/Anchor PCell 并写出路由几何。按拓扑/质量选后端。永远检查结构化结果ok=falseobstacle_hit_count>0、sibling 重叠、route_count 偏少都算失败。诚实报告 router 局限。障碍处理要传你自己设计的 obstacle_layers(无默认)。

工具参数功能
routing.tapered_hybrid_cellcell*, spacing_um, angle_mode, clear, port_layer, anchor_layer, obstacle_layers主要的 path+patch 后端。angle_mode:any / manhattan / fortyfive。
routing.tapered_polygon_cellcell*, …, route_layer, corner_style, obstacle_layers连续 taper 多边形(正式后端,不是备选),corner_style miter/bevel/round。
routing.steiner_cellcell*, route_layer, root_ports, clear, obstacle_layers多端网络(>2 port)的直角 Steiner/总线树。星形网否则要拆成 2-port。
routing.damped_segment_cellcell, damping_distance_um, obstacle_layers, …显式远离障碍的 damped 段后端(用 hybrid 输出 + 额外软间距)。
routing.damped_polygon_cellcell, damping_distance_um, corner_style, …damped 连续 taper 多边形版。
routing.damped_steiner_cellcell, damping_distance_um, root_ports, …damped 多端 trunk/branch 版。
routing.global_channel_cellcell*, spacing_um, angle_mode, safe_distance_um, obstacle_layers更强的全局决策路由:障碍感知候选 sink 分配 + corridor 容量负载均衡,再复用 hybrid 几何。非完整 rip-up/reroute。
routing.multilayer_escape_cellcell*, route_layer*, bridge_layer*, via_layer*, spacing_um, obstacle_layers用主层 + bridge 层 + via 盒子给被墙挡住的成对网络逃逸(窄;不建模 via enclosure)。
routing.gdsfactory_portscell*, route_layer*, router, cross_section, separation_um, radius_um, waypoints_um, path_length_match, obstacle_bboxes_um, …读 cell 的 Port 标记,用一种命名 gdsfactory 策略路由再写回。需 MCP 解释器里有 gdsfactory。

routing.gdsfactory_portsrouter 策略(选错参数会报错并指出哪些 router 支持它,绝不静默忽略):

router用途
bundle(默认)带间距的 Manhattan river 路由;也支持 waypoints/steps、radius_um、start/end_straight_um、path_length_match 等长、collision_check_layers。
electricalbundle + 金属默认 + 直角尖角 + 电学端口类型。
sbend横向偏移、面对面端口的平滑 S 过渡。
all_angle非 Manhattan bundle(可选 backbone_um 脊线)。
single每对独立 Manhattan 路由。
dubins每对基于圆弧的任意朝向路由。
astar(实验)obstacle_bboxes_um 的网格 A*;gf 的 astar 脆弱,klink 会校验结果,穿墙则报错而不是返回坏路由。可靠避障请用 klink 自己的 tapered_hybrid/damped + obstacle_layers

示例:主路由 + 更强避障 + gdsfactory bundle。

# klink 自带的主路由,Manhattan,避开你的 keepout 层
routing.tapered_hybrid_cell cell="BLOCK" angle_mode="manhattan" spacing_um=20 obstacle_layers=["900/0"]

# 需要更大障碍间距时
routing.damped_segment_cell cell="BLOCK" damping_distance_um=15 obstacle_layers=["900/0"]

# 多端网络(>2 port)
routing.steiner_cell cell="BLOCK" route_layer="1/0"

# gdsfactory river bundle,等长匹配
routing.gdsfactory_ports cell="BLOCK" route_layer="1/0" router="bundle" \
    separation_um=5 radius_um=10 path_length_match=true
路由完成的判据是结构化报告,不是“看起来连上了”。检查 okobstacle_hit_count、sibling overlap 和 route_count。真正的“完成”只有 live LVS match=True

7 · DRC 与 LVS 验证 drc_and_lvs_verification · 2 tools

klink.find_tools domain="drc_and_lvs_verification"

两个都是长耗时、纯 pya、领域无关的逃生舱式检查。drc.run 跑你提供的任意 DRC DSL(Ruby)脚本——脚本内异常作为结果返回,不会让 RPC 失败。lvs.run 是连通性对应物:把 live 版图抽成器件网表,和你提供的参考网表比对,写 .lvsdb 并(默认 show=true)在 Netlist/LVS 浏览器打开做 cross-probe。一个 P&R/器件阶段只有在真实 live LVS match=True 时才算 DONE——离线 fixture 和 marker 计数都不能替代。structdevice 流程优先用 structdevice.lvs_check

工具参数功能
drc.run mutates long(DRC DSL 源码 + 可选 output_rdb / 输入变量)在 KLayout 集成 Ruby DRC 引擎跑任意 DRC DSL。含 source() 则 standalone,否则对当前 layout 交互式跑。
lvs.run longcell*, conductors*, vias, devices*, reference*, out_lvsdb, show抽取(按 devices 配置的 per-cell 器件抽取器 + 你传的导体层)→ 与参考网表(reference.spice 或结构化 reference.netlist)比对 → 写 .lvsdb 并显示。

示例:最小 DRC(间距检查)与 LVS 调用骨架。

# DRC:M1 最小间距 0.2um(交互模式,对当前 layout)
drc.run script="""
m1 = input(1, 0)
m1.space(0.2.um).output("M1_space", "M1 spacing < 0.2um")
"""

# LVS:抽取导体层,和参考 SPICE 比对,打开浏览器
lvs.run cell="BLOCK" conductors=["1/0","3/0"] vias=["2/0"] \
    devices={...} reference={"spice":"ref.spice"} out_lvsdb="block.lvsdb" show=true

8 · 自定义器件网表 → 自动 P&R → LVS device_structdevice · 7 tools

klink.find_tools domain="device_structdevice"

这是器件无关的自定义器件 P&R 流。“器件”=任何带任意参数集 + 端子的 cell;klink 不假设参数名/数量,也没有器件词汇表。器件库、工艺 profile、端子来源都是示例/PDK 数据显式传入——MCP 工具不带任何工艺,缺工艺时返回有指导性的错误(“写/跑一个 example”),绝不猜。物理模型很紧凑:器件自己的金属层同时当路由层用;mode 2L/3L 选用其中 2 或 3 层。

工具参数功能
structdevice.build_from_netlistcell*, netlist*, confirm, mode, rows, cols, session一次调用的主流程:给器件级网表({instances, nets, groups}),派生 floorplan → 单趟多层路由 → 绘制 → 器件 LVS 验证一个全新 cell。确认门控:先不带 confirm → 返回 proposal;带 confirm token 再调 → 真正 build。
structdevice.declare_netsrecent_sends*, cell*, conductors, vias从 SEND 声明电学网络:一次 SEND 框住 ≥2 个端子 = 一个声明网络(持久化到 <cell>.elec_nets.json)。示例驱动,缺 recipe 报指导性错误。
structdevice.connect_netscell*, session, route_layer, route_width_um, via_cell, min_spacing_um, min_width_um, conductors, vias把每个已声明但未连接的网络布线并验证:recipe 派生 attach point、自动 via、自动 keepout、damped 路由,然后 LVS——任何 mismatch 全部撤销。在 declare 之后、spec_write 之前。
structdevice.lvs_checkcell*, session, mode, conductors, vias一次调用 LVS:派生器件端子(recipe)→ 抽取实际布线做出的网络 → 和 declared 网络对账。mode=net(默认)net 级;device/both 另跑器件级 NetlistComparer → device_lvs
structdevice.spec_writecell*, layer_roles*, session, device_class, conductors, vias把 live cell 投影成 klink.spec.json v1 事实文件:器件、实例、declared/derived 网络及对账。layer_rolesL/D 映射到角色名。
structdevice.register_pcellname*, fit_table*, session运行期从 fit table 注册拟合器件 PCell(fitter 产出后调)。落到 klink_structdevice 库,零插件改动零重载,GUI 与 instance.insert_pcell 立即可用。
pcell.register_fittedname*, fit_table*上面 register_pcell 背后的底层 plugin RPC。

示例:从器件级网表两步 build。

# 第 1 步:不带 confirm → 拿 proposal(网格 rows×cols、行距、路由层、器件混合)
structdevice.build_from_netlist cell="RINGOSC" netlist={
  "instances":[{"name":"INV0","device":"inv_x1"}, ...],
  "nets":[{"name":"a","terminals":["INV0/in","INV2/out"]}, ...],
  "groups":[]
} mode="3L"
# → needs_confirmation + proposal + next_action(confirm=...)

# 第 2 步:同样参数 + confirm token → 真正 place/route/draw/LVS
structdevice.build_from_netlist cell="RINGOSC" netlist={...} mode="3L" confirm="CONFIRM-xyz"

示例:SEND 驱动的交互连线。

# 用户为每个网络 SEND 一次(框住该网络的所有端子)
structdevice.declare_nets recent_sends=3 cell="BLOCK" conductors=["1/0","3/0"] vias=["2/0"]
structdevice.connect_nets cell="BLOCK" route_layer="3/0" route_width_um=0.5
structdevice.lvs_check cell="BLOCK" mode="both"
structdevice.spec_write cell="BLOCK" layer_roles={"1/0":"gate","3/0":"metal1"}

9 · 纳米器件(Hall bar / EBL / flake) device_nanodevice · 2 tools

klink.find_tools domain="device_nanodevice"

nanodevice.hallbar 用一次调用完成整个流程:它在通用 port 标记 + 路由之上,额外提供参数化的 Hall bar 器件几何——从 HallBarSpec(bar 长宽、contact 数、contact/pad 尺寸、pitch、gap)算并画整个器件(bar + N 对称接触臂 + pad + Port 标记 + label),然后把实际路由交给通用 router 把 contact 接到 pad(开启重叠校验,可选 EBL writefield 墙当 keepout),提交到一次性 cell(支持 dry_run)。失败返回 problems/next_action,什么都不改。

工具参数功能
nanodevice.hallbarcell, spec, writefield, route_layer, spacing_um, dry_run, session一次调用生成 + 路由 + 校验 + 提交一个 Hall bar:从 spec 生成几何 + Port/Anchor,用 klink router 把 contact 接 pad(重叠校验 ON,可选 writefield 墙),写入一次性 cell。
nanodevice.detect_commitcell, traces_path, image, pixel_size_um, coordinate, dry_run, session加载(或检测)纳米器件 flake trace 并作为多边形提交进 live cell。traces_path 走预算 traces.json(无额外依赖);image+pixel_size_um 走实时检测(需本解释器有 cv2 + numpy)。

示例:生成并路由一个 Hall bar;再从预算 traces 提交 flake。

nanodevice.hallbar cell="HB1" spec={
  "bar_length_um":60, "bar_width_um":8, "contact_count":6,
  "contact_width_um":4, "pad_size_um":40, "pitch_um":24, "gap_um":6
} route_layer="1/0" dry_run=true

nanodevice.detect_commit cell="FLAKE" traces_path="out/traces.json"

10 · 硅光(gdsfactory 导入 / 连接 / 重路由) device_photonics · 4 tools

klink.find_tools domain="device_photonics"

光子电路流,需 MCP 解释器里有 gdsfactory。两个端口来源、一个交互循环:photonics.import_gf 一次把成品 gdsfactory 脚本接管进循环(器件实例→真实 KLayout cell+实例,routed/snapped 连接坍缩成器件级网络,per-device port 模板持久化进 spec,网络由 klink 路由);port.harvest_blackbox 从 live blackbox 实例位置按 foundry stub 约定派生 Port。接管后,在 GUI 里拖动组件 → 一次 photonics.reroute 把光学和金属一起重画。这个“拖动→reroute”循环就是重点:版图保持 live 可编辑,不是一次性冻结。

工具参数功能
photonics.import_gfscript_path*, component, cell, route_layer, port_layer, route, session一次接管成品 gdsfactory 脚本:跑用户 .py,取它 build 的 Component,把器件实例导入为真实 KLayout cell+实例(批量 RPC),把 routed 连接坍缩成器件级网络,持久化 port 模板 + net 表,并用 klink 路由(脚本自己的路由被替换)。
port.harvest_blackboxcell*, tags*, nets, wg_layer*, stub_size_um*, port_layer, clear按 waveguide stub 约定(波导层上的小 stub 盒)从 PDK blackbox 实例派生 Port。Port 由 live 实例位置得来——移动实例后重跑刷新,再路由。
photonics.connectrecent_sends*, cell, width_um, radius_um, separation_um, wg_layer, stub_size_um, route_layer连接用户刚 SEND 的端口:读最近 N 次 SEND → 变成端口对(一次 SEND 框两个 Port 标记 = 一对)→ 自动命名网络 → 持久化 → 重新 harvest → gdsfactory 路由。session 从 SEND 自动推得。
photonics.reroutecell*, session, wg_layer, stub_size_um, route_layer用户移动组件后重路由:读持久 net 表 → 从 live 实例位置重新 harvest → 路由 → 写回。只需 cell 名。多端光学网络需先放 splitter/MMI。

示例:接管一个 gdsfactory 脚本,然后拖动后重路由。

# 1) 一次接管成品脚本(脚本里 c = build_mzi(); 供 klink 取用)
photonics.import_gf script_path="my_mzi.py" cell="MZI" route_layer="1/0"

# 2) 在 KLayout GUI 里拖动某个 phase shifter……然后:
photonics.reroute cell="MZI"     # 光学 + 金属一起重画,保住你的拖动

# 也可从 blackbox stub 约定派生端口后再连
port.harvest_blackbox cell="MZI" tags=["gc","mmi"] wg_layer="1/0" stub_size_um=0.5
photonics.connect recent_sends=4 cell="MZI" radius_um=10 separation_um=5

11 · Escape hatch(pya exec、事件、recorder) escape_hatch · 8 tools

klink.find_tools domain="escape_hatch"

优先用 typed RPC。 exec.python 跑原始 pya,仅用于没有 typed RPC 覆盖的操作 / 调试 / 紧凑一次性——它仍会触发 recorder + layout-diff 检测。events.* 是桥为 SEND 记忆订阅的 live 事件流(通常你改读 interaction.*)。recorder.* 生成回放脚本(不是字面 RPC 日志);测试前先看 recorder.status,别覆盖用户正在录的东西。

工具参数功能
exec.python mutates(code + 可选 reset)在 KLayout Qt 主线程跑任意 Python。全 pya + 文件系统访问。预绑定 pya, mw, view, layout。同一连接内状态保留(reset=true 清空)。stdout/stderr 捕获返回。
exec.reset mutates清空 exec.python 的 per-connection 命名空间(要个干净沙箱)。
events.channels列 server 能推的事件通道。事件以 NDJSON 帧 {"event":…,"data":…} 投递。
events.status本连接的订阅 + SignalHub 诊断。调试 selection_changed 是否绑定/订阅。
events.subscribechannels*订阅一或多个通道(未知通道静默忽略,看返回的 accepted)。
events.unsubscribechannels退订;传 * 退全部,空/省略则不变。
recorder.startoutput_path开始把所有改动版图的事件翻译成可回放 Python 脚本。幂等。默认落 ~/Documents/klink_recordings/…
recorder.stopoutput_path停止并写脚本;返回统计 + wrote。幂等。
recorder.status当前 recorder 状态(是否在录、事件/动作数、输出路径)。随时可调。

示例:录制一段会话,用 pya 做一次性操作。

recorder.status                 # 先确认没在录别人的
recorder.start
# …做一些 typed RPC 编辑 + 手工 GUI 编辑…
recorder.stop                   # 产出 <name>.py 和可独立跑的 <name>_pya.py

# 没有 typed RPC 覆盖时才用逃生舱
exec.python code="print(layout.top_cell().name); print(len(list(layout.each_cell())))"

recorder 产出两个文件:<name>.py(基于 KLinkClient 的回放)和 <name>_pya.py(可在 KLayout 内独立运行的 pya 版)。

想看这些工具在真实流程里怎么配合?去 示例 看 8 个公开 demo 的逐个详解,或 教程 看按领域的上手路径。