MCP / RPC reference

MCP 工具完整参考

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

总览与约定

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

阅读约定

  • 参数表里 name* 表示必填,其余为可选。
  • 坐标:带 _um 后缀是微米(最自然);带 _dbu 是整数数据库单位。micron = dbu × layout.dbu,dbu 来自 layout.info。
  • 图层写法三选一:图层索引 int、"L/D" 字符串(如 "1/0"),或 {layer, datatype} 对象。
  • 类型列说明工具跑在哪:rpc 在 KLayout 插件内执行;local 在 MCP 进程内执行。其余徽章: 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。单件插入只用于调试单个对象。

动态发现工具

目录是实时查询的,不要死记——它由 live plugin 的 method registry 生成,不存在会漂移的手写清单。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.info、cell.list、shape.query、view.*、pcell.*、recorder。
write版图编辑:shape.insert_*、cell.create、layer.ensure、instance.insert*、edit.undo。
verify运行检查:drc.run、lvs.run。
escape逃生舱:exec.python、exec.reset、events.*。
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→read、draw→write、advanced→escape、drc→verify。

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

klink.find_tools domain="connection_and_view"

不确定时从这里开始。 klink.status 报告连接、当前 session、解释器和可选能力;klink.guide 报告打开了什么 + 磁盘意图状态 + 下一步字面调用;klink.find_tools 按领域/关键词导航其余工具;klink.reconnect 恢复断掉的连接。本域还带着 MCP 侧的 session 注册辅助工具(klink.session_*、klink.transfer_*)——klink 用一个 MCP 桥驱动多个 KLayout session,session 是平等 peer,显式传你要的那个。View 工具是读为主的画布导航:新建的 cell 在 view.show_cell 之前不可见;view.new_tab 打开一次性 scratch tab;view.show_25d 从显示列表打开原生 2.5D 视图;子实例显示成名字方框时用 view.hier_levels 调大层级深度。截图(view.screenshot)只是用户要的产物,绝不是 agent 的验证步骤,优先用几何查询。破坏性:view.close_tab——只对一次性测试 tab 用。

工具类型参数功能
hellorpcclient, protocol介绍 client 并获取 server 信息 + 能力列表。建议作为每条新连接的第一次调用;不是必须的(不调用 server 也能正常工作),但对基于版本控制的功能启用很有用。
klink.find_toolslocaldomain, query按领域或关键词发现 klink 工具。不带参数调用会返回领域索引;domain=<token> 返回该领域的工具列表及详细用法;query=<keywords> 按匹配度排序工具(可限定在一个领域内)。tools/list 本身已包含全部工具且都可直接调用——这个工具只是用来导航、按需查看详细用法,不是准入门槛。拿不准该用哪个工具时就调它。
klink.guidelocal如果你还不熟悉这套体系,从这里开始:报告当前打开了什么、磁盘上已存在的 intent 状态(已声明的 net、LVS 报告、spec 文件)、每个可用用户意图对应的具体调用方式,以及建议的下一步。拿不准接下来该做什么时就调用它——工作流程活在工具返回结果里,而不是活在你的记忆里。
klink.reconnectlocal关闭任何过期的 klink client 并尝试重新连接 KLayout。
klink.session_labellocalaliases, description, label*, session_id*为一个已注册的 KLayout session 附加人类可读的 label 和别名。
klink.session_listlocalinclude_stale从本地 session 注册表中列出可发现的 KLayout/klink session。
klink.session_resolvelocalquery*把一个 session id、人类 label、别名、active cell 或 top cell 解析成一个 KLayout session。
klink.session_set_klive_targetlocalsession_id*设置 klive 兼容的 8082 入口所使用的已注册 KLayout session。
klink.session_statuslocalinclude_stale, session_id返回一条已注册的 KLayout session 记录,默认是当前活动的 MCP session。
klink.session_uselocalsession_id*把本 MCP 桥的活动 KLayout RPC 目标切换到一个已注册的 session。
klink.statuslocal返回 MCP 桥的连接状态和最近一次 klink 连接错误。
klink.transfer_commitlocaldry_run, package_id*提交一个先前由 klink.transfer_prepare 创建的包。
klink.transfer_preparelocalcopy_mode, layer_map, source_session*, target_cell, target_session*, translate_um在两个已注册的 KLayout session 之间准备一个 flat-selection 搬运包,并在目标端进行干跑。
meta.debug_signalsrpcfire返回 SignalHub 诊断日志,并可对某个 channel 触发一次合成事件以验证 subscribe→emit→deliver 链路。传 fire="selection_changed" 即可测试事件投递。
meta.methodsrpc返回完整的 RPC 方法目录(描述 + JSON schema),设计成可直接被 LLM function-calling 层消费(工具定义、MCP、OpenAI/Anthropic 的 tools 等)。
meta.pingrpc存活探针。回显传入的 params 并附带服务端的 trace id,用来测量往返延迟或检查连接是否健康。
view.activate_tabrpcindex*按 view.list_tabs 给出的索引切换当前 KLayout tab(视图)。切换后,所有单 layout RPC(layout.info、cell.list、shape.query 等)都作用于该 tab 的版图。
view.close_tabrpcview_index按索引关闭一个 layout 视图 tab。若不指定索引,则关闭当前活动 tab。
view.hier_levelsrpcmax, min读取或设置视图显示的层级深度(pya 的 min_hier_levels/max_hier_levels)。不带参数时报告当前层级。传入 min 和/或 max 可修改层级;视图会通过 update_content() 刷新,因此之后的截图能看到变化。如果密集的子 cell 实例渲染成名字标签方框而不是几何图形,说明 max 设得太浅——调大它(KLayout 默认值为 1)。
view.highlightrpcboxes_um, circles_um, clear, color, expire_s, halo, line_width, polygons_um在当前视图上绘制临时高亮标记,用于向用户指出位置——这是视图层的叠加渲染,不会触碰版图、选择或 undo。传入 boxes_um、polygons_um 和/或 circles_um(微米,top cell 坐标;circles_um 采用与 cell.fill_region 相同的 {center, radius, start/end_angle_deg} 规格,因此高亮出的圆/扇形与可 fill 的完全一致——切勿手工近似圆弧)。样式参数:color(#RRGGBB,默认红色)、line_width(像素)、halo。默认会替换之前的高亮(clear: false 则累加,例如给不同类别用不同颜色)。expire_s 会在 N 秒后自动移除这批标记。当你只是想“指出位置”时应使用此工具而不是 selection.set_box——后者会破坏用户真正的选择。view.highlight_clear 可移除全部高亮。
view.highlight_clearrpc立即移除全部 klink 高亮标记(来自 view.highlight)。绝不会触碰版图、选择或 undo。
view.list_tabsrpc列出本 KLayout 窗口内所有 layout tab(视图):索引、标题、文件路径、活动 cell,以及当前是哪个 tab。配合 view.activate_tab 使用,可以通过普通的单 layout RPC 检视非活动的版图。
view.new_tabrpccell_name, dbu打开一个带全新 top cell 的空 layout tab,并将其设为当前 tab(对应 pya MainWindow.create_layout 的 mode 1)。返回 index(新 tab)和 previous_current_index,以便临时 tab 工作流之后可通过 view.activate_tab 恢复用户原来的 tab。若调用前根本没有打开任何 tab,previous_current_index 为 -1——此时无需恢复,跳过 view.activate_tab 恢复步骤即可。应使用此工具而不是 exec.python。
view.screenshotrpcbbox_dbu, bbox_um, height_px, mode, path, width_px渲染当前活动 layout 视图的 PNG 截图。两种模式:base64 把 PNG 以 data URL 形式内嵌在响应中(适合支持视觉的 LLM);path 存盘并返回绝对路径(用于大图)。宽/高以像素为单位;默认值匹配用户在屏幕上看到的效果。也可以通过 bbox_um=[x1,y1,x2,y2](微米,推荐)或 bbox_dbu(整数 database units)裁剪到某个区域;裁剪框会被精确渲染(不做视口宽高比扩展),因此要让 width_px/height_px 匹配其宽高比,以获得线性的微米到像素映射。
view.show_25drpccell, displays*, generator打开 KLayout 原生的 2.5D(挤出式 3D)查看器,并向其提供一份显示列表:每种材料一条记录,包含图层、以微米计的 z 范围,以及可选的名称/颜色。图层从活动版图的某个 cell 中读取(默认为当前 cell)。klink 不自带 z 高度——厚度/标高是工艺事实,由调用方自行提供(可用 klink.stack25d.stack_displays 结合你的 StackSpec 和 z 表来派生该列表)。需要带 OpenGL 的 KLayout 构建版本。
view.show_cellrpccell*, zoom_fit设置活动 cellview 显示的(top)cell。KLayout 每个视图一次只显示一个 cell;如果你刚用 cell.create 创建了一个 cell 并想真正看到它的内容,必须调用此工具(或把它的一个实例插入到当前 top 中)。默认还会执行 zoom-fit。返回当前正在显示的 cell。
view.show_lvsdbrpckind, path*从磁盘加载一个已保存的 KLayout LVS/网表数据库到当前视图的 Netlist Browser 并显示,以便交互式地在版图与网表之间交叉探查(点击一个 net/器件 -> 在版图中高亮)。类似 DRC 的 marker browser,但用于 LVS/连通性。kind='lvs'(默认)读取 .lvsdb(LayoutVsSchematic,含匹配/不匹配的交叉引用);kind='l2n' 读取 .l2n(仅提取结果)。可与 structdevice.lvs_check 的 mode='lvsdb' 配合使用,后者会写出 .lvsdb 并返回其路径。只读(加载文件,不修改版图)。
view.viewportrpc报告当前视口:以微米为单位的可见 bbox(bbox_um,klink 的标准单位)以及以整数 database units 为单位的可见 bbox(bbox_dbu,通过活动版图的 dbu 换算得到)、视图控件的像素尺寸,以及 cellview 索引。调用此工具可将外部坐标与用户实际看到的画面对齐。
view.zoom_boxrpcbbox_dbu, bbox_um缩放视口以精确显示给定的 bbox。提供 bbox_um=[x1,y1,x2,y2](微米,推荐——是 klink 面向用户的标准单位,与其他地方用的 boxes_um/points_um/center_um 一致)或 bbox_dbu=[x1,y1,x2,y2](整数 database units,用活动版图的 dbu 换算)。两者中恰好提供一个即可。
view.zoom_fitrpc将整个版图适配到视口中(等价于 GUI 的 "Zoom Fit")。

示例。

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))

# session 注册表 + 两阶段搬运(先 prepare + dry-run,看清目标/cell/layer/统计再 commit)
klink.session_list
klink.session_label session_id="klayout-8766" label="scratch" aliases=["test"]
klink.session_resolve query="scratch"
klink.transfer_prepare source_session="klayout-8765" target_session="klayout-8766" copy_mode="flat_selection"
klink.transfer_commit package_id="pkg_0001"

2 · 多会话注册表与跨会话搬运(plugin 侧) multi_session_transfer · 7 tools

klink.find_tools domain="multi_session_transfer"

session/transfer 的 plugin 侧一半:session.label_set 和 session.mark_klive_target 直接在某个 KLayout 窗口里操作共享注册表;transfer.pending_set/status/clear 和 transfer.paste_pending 在本窗口持有并应用一个已审阅的 flat-selection 包;transfer.import_cell_tree_package 用原生 Cell.copy_tree 从 GDS/OAS 包导入一棵 cell 树。MCP 侧编排(klink.session_*、klink.transfer_prepare/commit)在 connection_and_view 域——两阶段、确认安全的搬运流程从那里开始。

工具类型参数功能
session.label_setrpcaliases, description, label*, session_id*在共享注册表中为一个已注册的 KLayout 会话设置人类可读的 label 和别名。
session.mark_klive_targetrpc把本 KLayout 窗口标记为兼容 klive/gdsfactory 的 8082 目标。
transfer.import_cell_tree_packagerpcdry_run, path*, source_cell*使用 KLayout 原生的 Cell.copy_tree 行为,把一个 GDS/OAS 包中的一棵 cell 树导入本 KLayout 窗口。命名冲突由 KLayout 用 $N 后缀解决。
transfer.paste_pendingrpcclear_after, dry_run把当前挂起的 flat-selection 搬运包粘贴到本 KLayout 窗口。该包必须已经包含最终的目标图层与坐标。
transfer.pending_clearrpc清除本 KLayout 窗口的挂起搬运包,且不写入任何版图几何。
transfer.pending_setrpcpackage*把一个已审阅过的 flat-selection 搬运包存入本 KLayout 窗口。
transfer.pending_statusrpc返回本 KLayout 窗口的挂起搬运包状态。

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

klink.find_tools domain="geometry_authoring"

核心绘图面。先读:layout.info、cell.list/cell.tree、layer.list/layer.display_list、shape.query、instance.query、pcell.*、library.list。生成式版图永远不要一次 RPC 画一个对象,用批量 RPC。画之前先 layer.ensure。编辑都包在事务里,edit.undo/redo/status 操作它们。本域除基础绘图外还带:geometry.boolean/cell_xor/density(几何差异与覆盖率检查)、cell.fill_region(dummy fill/测试结构平铺)、cell.flatten、layer.load_lyp/save_lyp/set_style/set_visible(视图样式)、library.list/refresh/register_file、pcell.convert_to_static、shape.change_layer/transform、instance.transform。破坏性的 layout.clear、cell.delete 只对一次性测试 cell 用,除非用户明确要求,别碰用户的工作 tab。

读取(geometry, not pixels)

工具类型参数功能
layout.inforpcverbosity当前活动版图视图的快照:打开的视图数、active cellview 索引、top cell 名字、源文件路径、数据库单位、完整的顶层单元列表,以及已注册的 layer/datatype 组合。可以放心频繁调用——这是 LLM agent 用来刷新自己对当前状态认知的方法。
cell.listrpclimit, name_prefix, offset, top_only, with_bbox扁平、分页地列出当前 layout 中的 cell。用它来发现有哪些 cell 存在;查看层级请改用 cell.tree。过滤:name_prefix 是区分大小写的前缀匹配;top_only 限制为顶层 cell。分页:offset + limit。
cell.treerpcmax_depth, max_nodes, root以某个 cell 为根的层级树(默认:第一个顶层 cell)。受 max_depth 和 max_nodes 限制。用它来理解一个 layout 的组成方式;每个节点的 instances 计数说明它被父 cell 实例化了多少次。
layer.listrpc列出当前活动版图中已定义的所有图层。每一项包含 layer_index(其他 RPC 使用的运行时句柄)、layer/datatype(GDS 编号)和可选的 name。同时返回 dbu_um,便于客户端在微米和数据库单位之间换算。
layer.display_listrpc列出当前视图的图层显示项:layer/datatype、visible、fill_color/frame_color(#RRGGBB)、dither_pattern 索引和 name。这是 layer.list(列出数据图层)在视图侧的对应物。
shape.queryrpcbbox_dbu, cell*, kinds, layers, limit以 JSON 形式读取一个 cell 内的形状(不递归)。强烈建议用 layers 和 bbox_dbu 缩小范围,并遵守 limit 分页(默认 500,最大 5000)。坐标以 database units(dbu)给出;乘以版图 dbu(来自 layout.info)即得微米值。truncated 标志表示匹配的形状数超过了 limit——用更小的 bbox 再次调用。
instance.queryrpcbbox_dbu, bbox_um, child, limit, parent*列出一个父 cell 中的直接子实例。返回 child 名称、bbox、变换、可选的 array、PCell 元数据,以及该子 cell 按图层统计的直接形状计数。这是一个只读原语,供需要检查或清理实例/PCell 几何、又不想用 exec.python 的客户端使用。
pcell.librariesrpc列出可用的 KLayout PCell 库(Basic 恒在;各 PDK 会注册自己的库)。接下来用 pcell.list 枚举某个库里的 PCell。
pcell.listrpclibrary列出 library(默认 Basic)里的全部 PCell。返回的只是名字列表——要看某个 PCell 的参数细节,调用 pcell.info。
pcell.inforpclibrary, pcell*描述一个 PCell 的参数,供调用方为 instance.insert_pcell 构造合法的 params 字典。每条记录包含 {name, type, default, description, choices?};type 取值为 int、double、string、boolean、layer、list、shape、none 之一。
library.listrpc列出本 KLayout 进程中注册的全部库(Basic、salt/PDK 库、运行期注册的器件或文件库)。每条记录含 name、id、description、technologies、cell_count、pcell_count 以及最多 20 个 top_cells(像 Basic 这类纯 PCell 库 cell_count 为 0 属正常);由 library.register_file 创建的库还带 source_file。要查看某个库里的 PCell,用 pcell.list/pcell.info。

写入 · 单元与图层

工具类型参数功能
cell.createrpcname在当前 layout 中新建一个 cell。若给定 name 且已被占用,KLayout 会追加 $1、$2……以保证名字唯一(返回生效名);若省略则创建一个匿名的自动命名 cell($N)。不保证幂等——每次调用都会新建一个 cell。
cell.renamerpcallow_suffix, cell*, new_name*重命名一个 cell。若 new_name 已被占用则失败(否则 KLayout 会默默追加 $1;这里把它变成一个错误,交给调用方决定)。传 allow_suffix=true 可选择使用 KLayout 的自动加后缀行为。
cell.deleterpccell*, recursive从当前 layout 删除一个 cell。recursive=true 时会连带删除因此变成孤儿(不再被任何其它 cell 引用)的子 cell;默认只删除这一个 cell,遗留的实例会变成“ghost”引用。
cell.flattenrpccell*, dry_run, levels, prune拍平一个 cell 的层级:子实例被溶解为该 cell 内的普通形状。levels(默认 -1,即全部层级)、prune(默认 true:删除因此变成孤儿的子 cell)、dry_run(默认 false:只报告将发生什么)。对该 cell 的层级结构是破坏性操作——拍平本身算一个撤销步骤;不确定时先用 dry_run。
cell.fill_regionrpcboxes_um, cell*, circles_um, column_step_um, exclude_layers, exclude_margin_um, fc_bbox_um, fill_cell*, origin_um, polygons_um, region_layers, row_step_um在一个区域内平铺一个 fill cell(KLayout 内置的 Fill Utility,pya.Cell#fill_region):用于 dummy fill、器件阵列、测试结构平铺。区域 = boxes_um、polygons_um、circles_um(整圆或扇形)与 region_layers(在目标 cell 这些图层有几何的地方填充,例如 scratch 图层上手绘的一块形状)的并集,再减去 exclude_layers 的几何(按 exclude_margin_um 外扩)。只有完全落在区域内部的瓦片才会被放置,因此弯曲边界会留下一圈未填充的边——在 remaining_area_um2 中报告。填充足迹默认取 fill cell 的 bbox(fc_bbox_um 可覆盖);栅格步进默认等于该足迹(row_step_um/column_step_um 可覆盖,例如用于在瓦片间留缝隙)。单趟单次栅格化——结果中的 remaining_area_um2 用于检查未覆盖的剩余部分。放置的实例算一个撤销步骤(Ctrl+Z 可撤销整次填充)。
layer.ensurerpcdatatype, layer*, name确保一个 GDS 图层(layer/datatype)存在于当前活动版图中;若缺失,会在一次可撤销的事务中创建。返回 layer_index 句柄,以及该图层是否是刚刚创建的。可放心反复调用——这是一个纯粹的 upsert。
layer.set_stylerpccolor, dither_pattern, fill_color, frame_color, layer*, line_width设置某个图层在当前视图中的显示样式:color 同时设置填充和边框颜色(#RRGGBB);也可以分别设置 fill_color/frame_color;dither_pattern(KLayout 抖动图案索引,从 0 开始)和 line_width 为可选项。只改显示,不动版图数据。
layer.set_visiblerpcexclusive, layers*, visible在当前视图中显示或隐藏图层(只影响显示,不触碰版图数据,也不涉及撤销)。layers 为 [L/D, ...] 形式;visible 默认为 true;exclusive=true 表示只显示列出的这些图层、隐藏其余所有图层(即“只看 1/0 和 3/0”这类调试场景)。未知图层会被如实报告,不会被静默忽略。
layer.load_lyprpcpath*把一个 KLayout .lyp 图层属性文件载入当前视图(一次调用设置整套图层栈的颜色/填充/可见性)。
layer.save_lyprpcpath*把当前视图的图层属性(颜色/填充/可见性)保存为一个 KLayout .lyp 文件。
library.refreshrpclibrary在所有使用该库的版图里重新求值库内容(即官方 pya.Library 的 refresh)。传 library 按名字刷新单个库,省略则刷新全部已注册库。在库发生变化后(例如某 PCell 被重新注册、或某个 salt 库被更新)调用它,而不是让用户去按 GUI 的刷新按钮。只读版图会被 KLayout 自身保持不变。
library.register_filerpcdescription, name, path*, technology把一个版图文件(GDS/OASIS/任何 KLayout 能读的格式)注册成运行期库,使其 cell 可以通过 instance.insert / instance.insert_many(设置 library)按名字放置。name 默认取文件主名。该库只在本次 KLayout 会话内存在(重启后需重新注册)。若名字已被注册则拒绝——请换一个新名字,会话内不支持替换。

写入 · 形状(批量优先)

工具类型参数功能
shape.insert_boxesrpcboxes_dbu, boxes_um, cell*, datatype, dry_run, layer, layer_index用一次 RPC 调用和一个 undo 事务向同一个 cell/图层批量插入多个轴对齐矩形。用 boxes_um 或 boxes_dbu 提供一个 [x1,y1,x2,y2] 矩形列表。对于大型生成式版图,应使用此工具而不是多次调用 shape.insert_box。
shape.insert_manyrpccell*, dry_run, items*用一次 RPC 调用和一个 undo 事务向同一个 cell 插入一组混合类型的形状。每一项都有 kind/type(box、polygon、path 或 text)、各自的图层选择器,以及对应单形状 RPC 所用的相同几何字段。
shape.insert_boxrpcbbox_dbu, bbox_um, cell*, datatype, layer, layer_index在给定图层上向 cell 插入一个轴对齐矩形。用 bbox_um=[x1,y1,x2,y2](微米,最自然)或 bbox_dbu(整数 database units)提供矩形范围。此编辑封装为单步事务,Ctrl+Z 可撤销。
shape.insert_polygonrpccell*, datatype, layer, layer_index, points_dbu, points_um向 cell 插入一个多边形(仅外壳,暂不支持洞)。点通过 points_um=[[x,y],...](微米)或 points_dbu(dbu)给出,至少需要 3 个点,多边形会自动闭合。
shape.insert_pathrpcbegin_ext_dbu, begin_ext_um, cell*, datatype, end_ext_dbu, end_ext_um, layer, layer_index, points_dbu, points_um, round_ends, width_dbu, width_um向 cell 插入一条 path(带宽度的中心线)。点通过 points_um/points_dbu 给出,宽度通过 width_um/width_dbu 给出。可选 begin_ext/end_ext 端部延伸(默认值为 width/2,即端面齐平),以及 round_ends 用于圆形端帽。
shape.insert_textrpccell*, datatype, layer, layer_index, position_dbu, position_um, size_dbu, size_um, string*向 cell 插入一个文本标签。位置通过 position_um/position_dbu 给出。可选 size_um 对应 KLayout 的文本大小(pya.Text.size)。标签是非几何性的注记——会对齐到整数坐标,但不产生掩模几何。
shape.deleterpcall_layers, bbox_dbu, bbox_um, cell*, datatype, dry_run, kinds, layer, layer_index, layers, limit按声明式选择器删除一个 cell 内匹配的形状。按图层选择(layer_index / layer+datatype / layers=[...] / all_layers=true),可选 bbox_dbu|bbox_um(相接触即选中),可选 kinds=['boxes','polygons','paths','texts']。用 dry_run=true 可在真正删除前预览计数。整个删除操作运行在同一个事务内,因此 Ctrl+Z / edit.undo 可一次性全部撤销。返回 {deleted, per_layer, truncated}。若没有匹配项,deleted=0 且调用成功、不报错。
shape.change_layerrpcbbox_um, cell*, from_layer*, to_layer*在一个 cell 内把形状从一个图层搬到另一个图层(可选只搬与 bbox_um 相接触的部分)。这是“把它画到正确图层上”这一意图的一步式实现。作为一个 undo 步骤;零匹配视为错误。
shape.transformrpcbbox_um, cell*, layers, limit, mirror, move_um, rotation原地移动/旋转/镜像已有形状(不是删除后重画)。过滤条件:layers(如 ['L/D', ...])和/或 bbox_um(相接触即匹配)——两者至少要给一个,防止裸调用悄悄重写整个 cell。动作:move_um [dx, dy]、rotation(逆时针角度)、mirror。旋转/镜像围绕匹配集合的联合 bbox 中心进行(与 GUI 行为一致),然后再应用移动。作为一个 undo 步骤;零匹配视为错误,而不是静默空操作。

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

工具类型参数功能
instance.insert_manyrpcdry_run, items*, parent*在一次 RPC、一个撤销事务中,把多个已存在的子 cell 实例插入同一个父 cell。每一项都包含 child,以及和 instance.insert 相同的变换/array 字段。
instance.insert_pcell_manyrpcdry_run, items*, parent*在一次 RPC、一个撤销事务中,把多个 PCell 实例插入同一个父 cell。每一项接受 library、pcell、params、变换字段和可选的 array,与 instance.insert_pcell 一致。
instance.insertrpcarray, child*, klink_id, library, magnification, mirror, parent*, position_dbu, position_um, rotation把 child 放进 parent。位置用微米(position_um)或 dbu(position_dbu)指定;旋转用角度(0/90/180/270 保持为整数变换,其它角度会被提升为带放大系数的复合变换)。可选的 array 会创建一个网格,支持两种形状:正交型 {rows, cols, pitch_x_um/dbu, pitch_y_um/dbu} 和通用型 {na, nb, a_dbu|a_um:[x,y], b_dbu|b_um:[x,y]}(通用型对旋转/剪切过的阵列同样适用)。不给 array 就只放一个实例。会拒绝循环层级(即 child 里已经包含 parent)。
instance.insert_pcellrpcarray, klink_id, library, magnification, mirror, params, parent*, pcell*, position_dbu, position_um, rotation用给定的 params 字典,从某个库(例如 Basic.CIRCLE、Basic.TEXT)构建一个 PCell 变体 cell,然后在 parent 中插入它的一个实例。请先调用 pcell.info(library, pcell) 查出确切的参数名和类型。图层参数接受 {'layer': int, 'datatype': int} 或 'L/D' 形式。相同的 params 会复用同一个变体 cell(KLayout 按值一致性合并)。
instance.deleterpcall, bbox_dbu, bbox_um, child, dry_run, limit, parent*从 parent 中删除匹配某个声明式选择器的实例。可选过滤:child(cell 名或 cell_index)、bbox_dbu/bbox_um(相交即算)。删除一个实例对子 cell 本身是非破坏性的——只是这个父 cell 里的引用消失了。整体包在一个事务里,撤销会把整批一起回滚。dry_run=true 时只报告数量。不给任何过滤条件时,必须传 all=true 来确认删除父 cell 中的全部实例。
instance.transformrpcbbox_um, child, mirror, move_um, parent*, rotation移动/旋转/镜像已放置的实例(数组作为一个整体一起移动)。过滤条件:child(cell 名)和/或 bbox_um(相交即算)——至少要给一个。操作:move_um、rotation(逆时针角度)、mirror;旋转/镜像围绕匹配到的整体 bbox 中心进行。算一个撤销步骤;零匹配会报错。
pcell.register_fittedrpcfit_table*, name*从一张 fit table(格式 klink_transistor_pcell_fit_v1,由 klink fitter 根据用户提供的样例器件族生成)在运行期注册一个拟合器件 PCell。插件本身只提供通用机制;器件定义通过本调用从外部传入——新增一个器件族不需要改动插件、也不需要重载。该 PCell 落在库 klink_structdevice 中,可立即通过 instance.insert_pcell 实例化。
pcell.convert_to_staticrpccell*, prune_variant把一个 PCell 变体转换成普通静态 cell(Layout#convert_cell_to_static);由于 KLayout 会让原有的放置仍指向旧变体,本调用会把版图里的每个实例都重定向到新的静态 cell,再删除变成孤儿的旧变体(prune_variant,默认 true)。之后几何就冻结了:参数编辑不再生效。整个过程算一个 undo 步骤。

写入 · Layout 级与编辑历史

工具类型参数功能
layout.file_inforpcdetail, path*回答“这个版图文件里有什么”这个问题,且不触碰当前会话:文件被读入一次性版图后即丢弃,因此打开的 tab 不可能污染答案(这是一个实测过的 agent 失败模式:导入把文件合并进了一个脏的版图,随后会话查询把残留的单元/图层当成了文件自身的内容来报告)。返回 dbu、顶层单元、单元总数、文件自身的图层列表,以及每个顶层单元以 dbu 为单位的 bbox;detail=counts 会额外按类型(boxes/polygons/paths/texts/others + 合计)给出每个图层的已存形状计数(大文件上会更慢)——问“boxes 有多少”指的是 boxes 这一项,而不是 total。检查一个文件请用这个;要在 tab 里打开文件请用 layout.show_file;layout.import_file 会把文件合并进当前活动版图。
layout.show_filerpckeep_position, mode, path*, technology把一个 GDS/OAS 文件载入 KLayout。如果文件已经在某个 tab 中打开,则重新加载它;否则在当前视图中打开(mode=replace)或在新 tab 中打开(mode=new)。返回值中的 file_info 块报告的是文件本身包含的内容(与文件分开单独读取,不受会话状态影响)——关于文件内容的问题应从它那里得到答案,而不是靠会话查询。录制处于激活状态时,文件加载触发的所有形状/单元事件会被合并成一行 layout_show_file()。
layout.save_filerpccellview_index, path*把当前活动版图保存为磁盘上的 GDS 或 OASIS 文件。扩展名决定格式:.gds/.gds2 对应 GDSII,.oas/.oasis 对应 OASIS。
layout.export_cleanrpcallowlist_layers*, cells, cellview_index, path*fail-closed 的交付导出:只把显式声明的一份工艺图层 allowlist 写入一份新的 GDS/OASIS 文件,移除每一个 klink 标记(Port/Anchor/Region PCell 实例)并剥离 PCell 上下文。操作在一份草稿副本上进行——live 版图永远不会被修改。输出文件会被重新读回并校验(无保留图层、无标记单元)后才原子性地提升到位;只要校验失败,临时文件就会被删除并报错。allowlist 中包含保留标记图层会被拒绝。传入 cells 则只导出这些顶层单元(及其层级)——不传的话,整幅版图的所有顶层单元都会写入文件,包括共享 session 中不相关的那些。完整工作存档请用 layout.save_file;掩模版和交付场景请用这个。
layout.import_filerpccreate_other_layers, layer_map, on_conflict, path*把一个版图文件(GDS/OASIS/…)合并进当前活动版图——这是加载期的图层映射工作流(官方 LoadLayoutOptions),不同于在自己的 tab 中打开文件的 layout.show_file。layer_map 在读取时重新映射图层(形如 [{from: L/D, to: L/D}, ...]);create_other_layers(默认 true)控制未列出的图层是否也一并读取;on_conflict 决定同名单元的处理策略:rename(默认,新单元获得 $1 风格的后缀)、add(内容合并进已有单元)、overwrite(旧单元被替换)、skip(丢弃新单元)。整个操作是一次撤销步骤。返回新增的单元/图层、新的顶层单元,以及一个描述文件本身内容的 file_info 块——合并之后,会话查询(cell.list/layer.list)描述的是混合后的版图,而不是文件本身;关于文件内容的问题应从 file_info 或 layout.file_info 得到答案。如果只是想检查一个文件,不要导入它:用 layout.file_info(不触碰会话)或 layout.show_file(自己的 tab)。
layout.clearrpccellview_index清空整幅版图:一次操作移除所有单元、形状和层级,留下一个空的版图供新内容使用。适合在恢复版本控制快照之前调用。
edit.undorpc撤销最近一次可撤销的操作(klink 的写操作 RPC、Macro IDE 编辑或 GUI 编辑)。这是 Edit > Undo 的程序化等价物。返回前后的栈快照,方便调用方检测无效果的撤销。不可撤销的东西(例如视图缩放)会被 KLayout 自动跳过。
edit.redorpc重做最近一次被撤销的操作,与 edit.undo 配对使用。返回前后的栈快照,方便调用方验证栈确实推进了。
edit.statusrpcdebug报告当前 undo/redo 的可用性。用它来判断调用 edit.undo/edit.redo 是否真的会有效果。传 debug=true 暴露 KLayout Manager 的内省字段(在诊断 has_undo/has_redo 缺失的构建时有用)。

几何检查(只读报告)

工具类型参数功能
geometry.booleanrpca*, b*, op*, write_to在两个图层源之间做布尔运算:op 取 and/or/xor/not 之一(not = a 减 b)。a 和 b 都是 {cell, layer}——两者的 cell 可以不同(默认 b.cell = a.cell),会包含层级并合并输入。返回结果的 polygon_count/area_um2/bbox_um;传 write_to({cell?, layer})可以额外把结果多边形写入目标 cell(缺失则自动创建,结果里会标 cell_created;算一个撤销步骤;默认目标 cell 为 a.cell)。典型用法:检查两图层重叠(op=and,area>0 表示短路/接触)、和一个 intent 区域做差异对比(op=xor,area==0 表示完全匹配)。
geometry.cell_xorrpccell_a*, cell_b*, layers, only_differing逐图层对比两个 cell 的几何差异(纯报告,不写入任何东西):对任一 cell 中出现过的每个图层,对合并后的层级几何做 XOR,报告差异的 polygon_count/area_um2。layers 限定对比范围;only_differing(默认 true)会把相同的图层从列表中省略。equal==true 表示每个被比较的图层都做到了字节级几何一致。这正是回答“我的改动是否只改了我想改的东西”的工具——拿一个备份/参照 cell 和编辑后的 cell 对比。
geometry.densityrpccell*, layer*, window_um一个 cell 中某图层的覆盖面积密度:合并后的层级几何面积除以窗口面积。window_um([l,b,r,t])默认取该 cell 在该图层上的 bbox。返回 area_um2、window_area_um2 和 density(0 到 1)。用于 dummy fill 决策前的预检查(与 cell.fill_region 搭配使用)。

示例。

# 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 · 10 tools

klink.find_tools domain="selection_and_send_memory"

两件不同的事。selection.* 是 KLayout 里当前的实时选择:selection.get、selection.set_box(替换当前选择)、selection.clear、selection.send_context(agent 侧显式 SEND)。interaction.* 是用户明确 SEND 过(工具栏 SEND,记成 sel_0006 这样的 id)的持久 session 记忆:interaction.selection.latest/recent(默认最新 5,按顺序不按时间裁剪)/get/label,以及 interaction.context(当前选择+最近记忆一起返回)。当用户说“刚发的”“这块区域”“这里”“那一个”时用它们——按顺序/数量解析,不是按时间;把用户措辞绑到这些 id/查询,而不是绑到截图。

工具类型参数功能
interaction.contextlocalinclude_current_selection返回当前 KLayout 选择,外加最近持久化的交互选择记忆。
interaction.selection.clear_sessionlocalconfirm*在获得明确确认后,清除本 MCP session 的持久交互上下文。
interaction.selection.getlocalid*按稳定的 selection id 读取一条已存储的选择。
interaction.selection.labellocaldescription, id*, label为一条已存储的选择添加或更新 label 与描述。
interaction.selection.latestlocal返回本 MCP session 记忆中最近一次显式 SEND 的选择。
interaction.selection.recentlocallimit按顺序返回最近若干次显式 SEND 的选择,默认最新 5 条。
selection.clearrpc清空当前活动视图中的对象选择。
selection.getrpclimit返回当前活动视图中的对象选择。每项要么是 shape(带图层 + bbox),要么是 instance(带目标 cell + bbox)。选择为空时返回空列表,不是错误。
selection.send_contextrpcmax_items, source把当前非空的 KLayout 选择显式作为 selection_sent 事件发送,供外部 AI 交互上下文使用。选中的标尺(RULER)也会被捕获(事件字段 ruler_count/rulers,id 升序),因此“我刚发的标尺”可通过 interaction.selection.* 解析。此调用不会在 plugin 中存储记忆。
selection.set_boxrpcbbox_dbu, bbox_um, cell*, include_instances, layers, limit选中 cell 中 bbox 与给定框相交、且位于给定 layers(默认全部图层)上的每一个形状(传入 bbox_um,单位微米,推荐;或 bbox_dbu)。设置 include_instances: true 可同时选中与该框重叠的已放置子实例(与 GUI 框选行为一致;阵列实例作为一个对象被选中)。此调用会替换当前选择,并显示 KLayout 原生的选择渲染效果。返回选中的对象数量。

示例。

# 用户在 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 · 标尺(annotation)与画布测量 rulers_and_measurement · 7 tools

klink.find_tools domain="rulers_and_measurement"

标尺是住在视图里的 pya.Annotation——不在版图里:selection.get 看不见它,保存的 GDS 也不带它,annotation.* 是唯一的读写通道。这是用户和 agent 之间"线状"的指点渠道:用户随手拉一条标尺说"沿这条线切个剖面",agent 用 annotation.list 读它;agent 也可以用 annotation.insert 画一条回去提议切线或预演走线,用户拖完再重读。annotation.measure 则是"这条缝多宽"的免坐标测量。SEND 也会捕获选中的标尺(见上一节);把标尺变成 Region 交给 region.claim(下一节)。

工具类型参数功能
annotation.listrpccategory, limit, selected_only列出当前视图里的标尺(annotation),包括用户手画的。标尺住在视图里、不在版图里:selection.get 和保存的 GDS 都看不见它们,这是唯一的读取通道。每条带完整 points_um 列表和段数——多段标尺不能约化成起终点。
annotation.getrpcid*按 id 读一条标尺(id 来自 annotation.list);id 不是当前视图里的活标尺则报错。
annotation.insertrpcangle_constraint, category, fmt, outline, points_um*, snap, style, text在当前视图画一条标尺——agent→用户的“线状”指点通道(view.highlight 指“面”):提议剖面切线、标注间距、预演走线;用户拖完你用 annotation.list 重读。
annotation.updaterpcangle_constraint, category, fmt, id*, outline, points_um, snap, style, text原地修改一条已有标尺(只改你传入的属性)。先 annotation.list 拿 id。
annotation.deleterpccategory, id按 id 或按 category 标签删标尺,两者恰传其一;要全清用 annotation.clear。
annotation.clearrpcconfirm删掉当前视图的所有标尺,用户手画的也在内。破坏性操作:需要 confirm=true;只想清 agent 画的请用 annotation.delete{category:'klink'}。
annotation.measurerpcangle_constraint, category, keep_failed, point_um*在种子点自动测量:KLayout 从该点沿允许方向向外找可见图层上最近的边并在其间拉出标尺——不知道任何坐标也能问“这条缝/这根线多宽”。附近找不到边则测量失败,零长度的退化标尺会被撤掉(measured=false)。

示例。

annotation.list                                    # 列出当前视图里的标尺
annotation.insert points_um=[[0,0],[10,0]] category="klink" text="cut here"
annotation.measure point_um=[5,5]                  # 自动测量最近的缝隙/线宽

6 · Port、Anchor 与 Region(标记 PCell) ports_and_anchors · 26 tools

klink.find_tools domain="ports_and_anchors"

Port 是网络端点(klink_Port PCell:带 net + 朝向 + 宽度)。Anchor 是路由约束(klink_Anchor PCell),kind 为 waypoint_region / bend_region / corridor(普通 corridor 是必经通道;给它 choice_group=BUS 才变成可选通道)。port.mark/list/update/transform/set_layer/unmark/delete_all/repair_names,anchor.*(+ anchor.repair_ids)同名动词对应。port.mark_many 一次 RPC/一个 undo 步在一个 cell 里标很多 port(先校验再写)——生成式 port 阵列用它而不是循环 port.mark。port.harvest_blackbox 按 waveguide stub 约定从 live 的 gdsfactory/PDK blackbox 实例位置派生 Port(这个偏硅光的工具归在本域)。路由工具默认 port_layer=999/99、anchor_layer=999/1。Keepout 不是 anchor 类型——把你自己设计的 obstacle_layers 传给路由工具;klink 不带默认 keepout 层(900/0 是 klink 保留 keepout 层,structdevice 内部用它)。这些是路由后端的输入:先 mark Port+Anchor,再调 routing.*。

Region 是已认领的区域(klink_Region PCell,默认层 999/10):用户拖 box/ellipse 标尺圈一块地方,region.claim 把它们合并成一个 Region PCell 并消耗掉标尺。角色:include=并集、clip=交集、exclude=差集(半圆=椭圆被 box 裁剪;圆环=圆减圆)。结果必须是一个连通分量——不连通的孤岛会被拒绝,分开认领。region.list/get/unclaim/set_layer;region.get 返回合成多边形(hull_um)——喂给 cell.fill_region 铺区域,或把 bbox_um 喂给 view.zoom_box 导航过去。用户也可以点击一个 Region 并 SEND,用 interaction.selection.* 解析。把 Region 变成带唯一编号的可执行阵列,见 layout_intent 域。

工具类型参数功能
port.set_layerrpclayer*为本 layout 配置默认的 Port PCell 标记层。
port.markrpcaccess_mode, cell*, center_dbu, center_um, label, layer, name, net, orientation, port_type, show_label, slide_allowed, slide_edge, target_layer, width_um在 cell 里创建一个 klink_Port PCell 实例。
port.mark_manyrpcaccess_mode, cell*, items*, label, layer, net, orientation, port_type, show_label, slide_allowed, slide_edge, target_layer, width_um在一个 cell 里,用一次 RPC 和一个 undo 事务批量创建多个 klink_Port PCell 实例。items 是一组逐端口对象,字段与 port.mark 的参数相同(name、label、center_um/center_dbu、orientation、width_um、port_type、net、target_layer、show_label、access_mode、slide_allowed、slide_edge);每一项都必须设置 center_um 或 center_dbu。layer、label、orientation、width_um、port_type、net、target_layer、show_label、access_mode、slide_allowed、slide_edge 中的任意一个,也可以只在顶层给一次作为默认值,被每一项继承,除非该项自己覆盖。所有条目会在插入任何 Port 之前先整体校验——只要有一项无效(缺 center、重名等),就不会创建任何 Port,并且错误信息会指明是哪个 items[i] 出的问题。
port.listrpccell*, layer, sort列出 cell 里的 klink_Port PCell 实例。给定 layer 时只返回标记层匹配的 Port(该参数同时决定 repair 所用的层);不给则返回全部 Port。
port.updaterpcaccess_mode, cell*, label, layer, name*, net, orientation, port_type, show_label, slide_allowed, slide_edge, target_layer, width_um按不可变的 name 更新单个 Port PCell 实例。
port.transformrpcaccess_mode, cell*, label, layer, names, net, orientation, port_type, rotate_delta, selection, show_label, slide_allowed, slide_edge, target_layer, width_um按 names 或 GUI 选择批量更新 Port PCell 参数。
port.repair_namesrpccell*, layer, prefix修复 cell 里重复或为空的 Port 名字。这主要是为经由 KLayout PCell GUI 手动插入的 Port 准备的,因为那条路径会绕过 port.mark 的唯一性检查。
port.harvest_blackboxlocalcell*, clear, nets, port_layer, stub_size_um*, tags*, wg_layer*按照 waveguide stub 约定(波导层上的小 stub 盒)从 cell 里的 PDK blackbox 实例中提取光学端口,并把它们标记为 klink Port。Port 是从 live 实例位置派生的:在 GUI 里移动实例后需要重新跑一次以刷新,然后再路由。Net intent 依据的是身份稳定的名字 {tag}{ordinal}_{stubIndex}。
port.unmarkrpccell*, name*按 name 删除一个 Port PCell 实例。
port.delete_allrpccell*, layer删除 cell 里的全部 Port PCell 实例。
anchor.set_layerrpclayer*为当前 layout 配置默认的 Anchor PCell 标记层。
anchor.markrpccell*, center_dbu, center_um, height_um, id, kind, label, layer, mode, name, net, orientation, path_points, priority, radius_um, required, show_label, width_um在一个 cell 里创建一个 klink_Anchor PCell 实例。
anchor.listrpccell*, layer, sort列出一个 cell 里的 klink_Anchor PCell 实例。给定 layer 时,只返回标记层匹配的 anchor(同时也决定 repair 使用的图层);不给则返回全部。
anchor.updaterpccell*, height_um, id*, kind, label, layer, mode, net, new_id, orientation, path_points, priority, radius_um, required, show_label, width_um按不可变 id 更新单个 Anchor PCell 实例。
anchor.transformrpccell*, height_um, ids, kind, label, layer, mode, names, net, orientation, path_points, priority, radius_um, required, selection, show_label, width_um按 ids 或 GUI 选中批量更新 Anchor PCell 参数。
anchor.repair_idsrpccell*, layer, prefix修复一个 cell 里重复或为空的 Anchor id。主要针对通过 KLayout PCell GUI 手动插入的 anchor——这类插入会绕过 anchor.mark 的唯一性校验。
anchor.unmarkrpccell*, id*按 id 删除一个 Anchor PCell 实例。
anchor.delete_allrpccell*, layer删除一个 cell 里全部 Anchor PCell 实例。
region.set_layerrpclayer*为本 layout 配置默认的 Region PCell 标记层(默认 999/10)。
region.claim_previewrpclimit, npoints, rulersregion.claim 的干跑,零改动:把当前视图每条标尺列为候选(newest first,recency_rank 1 = 最后画的),标出 claim 会怎么读它(box | ellipse | 3+ 点=多边形 | line=不可 claim)、点数、bbox_um、标签、以及标签为 'region'/'region:exclude' 快车道令牌时的角色;传 rulers:[{id, role}] 还能预演这组组合的结果(bbox/面积/孔)或提前拿到 claim 会报的同样错误。用它向用户逐条讲述候选、拿到确认再 claim——视图里混着此刻的意图和旧的测量残留。
region.claimrpccell, keep_rulers, layer, name, npoints, rulers*把若干标尺合并成一个 klink_Region PCell(保留层,默认 999/10)并消耗掉这些标尺。标尺种类:两点式 box/ellipse 标尺,以及 3 点及以上的标尺,会被当作精确的闭合多边形读取(首尾自动闭合;有自相交的轮廓会被拒绝,并指出具体是哪几段相交)。角色:include(并集)、clip(交集)、exclude(差集;洞永远不可写)。结果必须是单个连通分量;不连通的孤岛会被拒绝,并各自给出 bbox——请分开认领。椭圆的离散化是安全的:include/clip 用内切,exclude 用外切。挑选标尺是这里的风险点(视图里意图标尺和旧的测量线混在一起):如果用户 SEND 过,就从 interaction.selection.latest.rulers 取 id;否则用 region.claim_preview 加口头确认,取得用户同意;标注为 region 的标尺可以不必确认直接取用。结果会回显每一个被消耗掉的标尺(consumed[])。
region.listrpccell列出全部 klink_Region PCell 实例(name、cell、layer、bbox、area、klink_id)。Region 是持久化的已认领区域;标尺只是草稿。
region.getrpcname*按名字读取一个 Region:合成后的多边形(实例变换 × 局部轮廓),给出目标 cell 的 dbu 和微米坐标、面积、洞。magnification != 1 时拒绝。
region.occupancyrpcexclude_cells, layers, name*, obstacle_cells某个 Region 的递归占用情况:按请求的层 和/或 命名的障碍 cell(该 cell 在区域内每次出现的 bbox,用于自定义器件/blackbox)合并出障碍多边形,裁剪到该区域多边形内,并给出剩余空闲面积。一切都是显式的——klink 不对哪些层或 cell 是障碍做任何假设。truncated: true 表示结果不完整,绝不能用于规划。
region.repair_idsrpckeeper*, name*为通过复制粘贴产生的重复 Region(多个实例共享同一个 name/klink_id)修复身份。由用户指定 keeper(父 cell + 锚点位置);keeper 保留原有的 name、klink_id 以及任何 Intent 绑定不变。其余每一个副本都会得到全新的自动 R### 名字 + klink_id,且不带 intent——之后要绑定请用 intent.rebind 单独处理。本工具绝不猜测哪一个副本是原件;keeper 指定有歧义时直接拒绝。
region.unclaimrpcname*按名字删除一个 klink_Region PCell 实例。只删除区域标记本身——绝不删除生成的输出或用户几何。

示例。

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"]

# Region:拖标尺圈一块地方,认领成一个 Region 标记
region.claim cell="TOP" layer="999/10" rulers=[{"id":12,"role":"include"}]
region.get name="R001"

7 · 可执行版图意图(Region → 确定性阵列) layout_intent · 10 tools

klink.find_tools domain="layout_intent"

Region 驱动的生成闭环(需要一个已认领的 Region——见 ports_and_anchors 的 region.claim)。intent.prepare 对着你声明的障碍物(层、命名的器件/blackbox cell 按每次出现的 bbox 计入、自由多边形,外加可选 clearance_um)分析区域占用,把任意已有的 source cell(支持 rotation_deg/mirror)规划成间距网格,每个副本带唯一的多边形文字编号标签(真实几何,TextGenerator),校验包含关系 + 障碍物 + 重叠,返回预览 + plan_id + plan_hash——不写入任何东西。intent.apply(plan_id + plan_hash + confirm=plan_id)把它作为一次事务提交进一个全新的 KLINK_I_* 容器 cell(一次 Ctrl+Z 撤销;klink_id 打标的根实例)。intent.regenerate 带参数补丁(比如 numbering.start)重新规划,下一次 apply 会原子替换只属于这个 intent 的容器——手改过的输出会被检测到(偏离)并绝不静默覆盖。intent.list/get 显示已存储的 intent + 实时状态;intent.rebind 显式把 intent 重新指向一个 region(region 被删除/修复之后唯一的路径);intent.retire 按 output_policy 决定几何去留(preserve/detach/remove)。层、间距、尺寸全部是必填输入:klink 不带工艺默认值。底层原语 intent.apply_managed_plan/intent.managed_digest/intent.remove_managed_output 是编排工具背后调用的 plugin RPC——正常流程不要直接调它们。

编排(MCP 本地工具)

工具类型参数功能
intent.preparelocalallow_empty_obstacles, clearance_um, extra_obstacles_um, instruction, intent_id, label*, mirror, numbering*, obstacle_cells, obstacle_layers, pitch_um*, project_root, region*, rotation_deg, source_cell*为一个已认领的 Region 规划一个 array_labeled 意图:分析占用情况,把一个已有的 source cell(任意自定义 cell;支持 rotation/mirror)按间距铺成网格,每份副本带唯一的物理编号标签(真实的多边形文字),校验包含关系/障碍物,返回预览 + plan_id + plan_hash。不会写入 layout 的任何内容。障碍物完全由你声明:图层、命名的器件/blackbox cell、自由形式的多边形,外加一个可选的间隙余量——klink 不带任何工艺默认值,什么都不假设。审阅后用 intent.apply 提交。
intent.applylocalconfirm*, plan_hash*, plan_id*, project_root在一次 KLayout 事务里提交一份已预览的计划(新建容器 cell + klink_id 根实例;regenerate 会替换这个容器)。需要 intent.prepare 给出的 plan_id 和 plan_hash,加上 confirm=plan_id。会拒绝过期的计划(layout 自 prepare 后已变化)、有偏差的输出,以及带问题的计划。一次 Ctrl+Z 即可撤销整次 apply。
intent.regeneratelocalintent_id*, parameters_patch, project_root重新规划一个已应用的 intent(可选打补丁修改参数,例如新的编号起点或间距),返回一份新预览;下一次 intent.apply 会原子式地只替换这个 intent 自己的容器。如果输出已被手动改过(偏离),则拒绝——绝不静默覆盖。
intent.listlocalproject_root列出所有已存储的 intent(id、region、executor、revision、输出容器),并带上惰性输出状态:applied | diverged | undone_or_deleted | never_applied。
intent.getlocalintent_id*, project_root完整读取一个已存储的 intent(参数、输出、惰性状态)。
intent.rebindlocalintent_id*, project_root, region*显式把一个 intent 绑定到一个(新的)Region 名字——这是 Region 被删除/修复之后唯一的路径。会校验该 Region 确实存在;绝不猜测。
intent.retirelocalconfirm, intent_id*, output_policy, project_root退休一个 intent。output_policy 决定几何的去向:preserve(默认)把容器保留为普通版图、只关闭该 intent;detach 在此基础上进一步忘记输出绑定(容器保留,但不再被管理);remove 通过带 digest 校验的 plugin 原语删除容器——如果输出已被手动改过(偏离)则拒绝。任何情况下都不会删除用户自己的几何。

底层原语(plugin RPC,编排工具背后调用)

工具类型参数功能
intent.apply_managed_planrpccontainer_cell*, expected_managed_digest, expected_root_klink_id, mode*, parent_cell*, payload*, plan_hash*, root_klink_id*, scope_check机械地在一次事务里提交一份已完全校验过的 managed plan:从类型化 payload 创建一个全新容器 cell,把它的根实例(打上 klink_id 标记)放进父 cell,mode=replace 时替换掉之前的容器。所有业务校验都必须在调用这个接口之前完成;TOCTOU 由 scope_check(重新运行并对比)和 expected_managed_digest 防护。0 个或多个根匹配、digest 不一致、scope 过期都会被拒绝。一个撤销步骤即可撤掉整次 apply。
intent.managed_digestrpccontainer_cell*一个容器 cell 自身内容(规范化后的形状 + 子实例)的 managed digest。用于惰性的 undone/diverged 检查:与上一次 apply 记录的 digest 做对比。
intent.remove_managed_outputrpcexpected_managed_digest*, parent_cell*, root_klink_id*在校验身份和 digest 之后,删除一个 managed 输出(根实例 + 容器单元)。根匹配为 0 个或多个、以及容器已偏离(digest 不一致)的情况都会被拒绝——手动改过的输出绝不会被静默销毁。整个操作是一次事务、一次撤销步骤。

示例。

# 1) 认领区域(见 ports_and_anchors 的 region.claim)
region.claim cell="TOP" rulers=[{"id":12,"role":"include"}]

# 2) 规划:任意已有 cell 铺间距网格,带唯一编号
intent.prepare region="R001" source_cell="SENSOR" pitch_um=[20,20] \
    obstacle_layers=["10/0"] numbering={"prefix":"S","width":3,"start":1} \
    label={"layer":"20/0","slot_region":"R00X"}
# -> preview + plan_id + plan_hash,写入任何东西之前先看这份预览

# 3) 应用:一次事务写入
intent.apply plan_id="..." plan_hash="..." confirm="..."

# 4) 改主意:换个编号起点重新生成,apply 原子替换旧容器
intent.regenerate intent_id="..." parameters_patch={"numbering":{"start":201}}
intent.apply plan_id="..." plan_hash="..." confirm="..."

8 · 路由后端 routing_backends · 9 tools

klink.find_tools domain="routing_backends"

都读一个 cell 里的 Port/Anchor PCell 并写出路由几何。按拓扑/质量选后端:routing.tapered_hybrid_cell 是主要的 path+patch 后端;routing.tapered_polygon_cell 写连续 taper 多边形(正式后端,不是备选);routing.steiner_cell 处理多端网络(>2 port);routing.damped_* 系列显式加额外障碍间距;routing.global_channel_cell 是在 hybrid 几何之上的全局决策路由(候选 sink 分配+corridor 容量负载均衡);routing.multilayer_escape_cell 用 bridge 层+via 给被墙挡住的网络逃逸;routing.gdsfactory_ports 用命名 gdsfactory 策略路由 Port 标记(需解释器里有 gdsfactory)。永远检查结构化结果:ok=false、obstacle_hit_count>0、sibling 重叠、route_count 偏少都算失败。障碍处理要传你自己设计的 obstacle_layers(无默认)。

工具类型参数功能
routing.damped_polygon_celllocalanchor_layer, angle_mode, cell*, clear, corner_style, damping_distance_um, obstacle_layers, port_layer, route_layer, spacing_um用显式的 damped 多边形后端为一个 KLayout cell 布线,使用连续渐变(taper)的多边形,并与障碍物保持额外间距。
routing.damped_segment_celllocalanchor_layer, angle_mode, cell*, clear, damping_distance_um, obstacle_layers, port_layer, spacing_um用显式的 damped 分段后端为一个 KLayout cell 布线,使用 tapered hybrid 输出,并与障碍物保持额外间距。
routing.damped_steiner_celllocalanchor_layer, angle_mode, cell*, clear, damping_distance_um, obstacle_layers, port_layer, root_ports, route_layer, spacing_um用显式的 damped Steiner 后端为一个 KLayout cell 布线,使用多端 trunk/branch 拓扑,并带 damped 式的障碍间距处理。
routing.gdsfactory_portslocalall_two_port_nets, allow_crossing, auto_taper, backbone_um, bundle_gather_um, cell*, clear, collision_check_layers, cross_section, distance_um, end_straight_um, gf_route_layer, min_straight_taper_um, net, obstacle_bboxes_um, output_mode, pair_by, path_length_match, port_layer, radius_um, resolution_um, route_layer*, route_width_um, router, sbend_fallback, separation_um, sort_ports, source, source_orientation, source_prefix, start_straight_um, steps, taper, target, target_orientation, target_prefix, waypoints_um用指定的 gdsfactory 路由策略为 KLayout 的 Port 标记布线。router 可选:bundle=带间距的曼哈顿 river 路由(默认;同时支持 waypoints/steps、radius_um、start/end_straight_um、path_length_match、collision_check_layers);electrical=金属默认值 + 直角拐角的 bundle;sbend=用于朝向偏移端口的平滑 S 形过渡;all_angle=非曼哈顿 bundle(可选 backbone_um 主干);single=每对端口独立的曼哈顿路由;dubins=每对端口基于圆弧、任意朝向的路由;astar=实验性功能,围绕 obstacle_bboxes_um(+ resolution_um/distance_um)为每对端口做网格 A* 搜索——gf 自带的 astar 不太稳定,所以 klink 会校验结果,一旦路由穿墙就直接报错,而不是把它返回给你;要可靠地避障,请优先用 klink 自己的 routing.tapered_hybrid_cell / routing.damped_* 系列并配合 obstacle_layers。如果选定的 router 不支持某个参数,会返回错误并指明哪些 router 支持它。需要 MCP 解释器里装有 gdsfactory。
routing.global_channel_celllocalanchor_layer, angle_mode, cell*, clear, obstacle_layers, port_layer, safe_distance_um, spacing_um用更强的全局 channel 后端为一个 KLayout 单元布线:先做障碍感知的候选分配和容量感知的走廊(corridor)分配,再使用 tapered hybrid 几何。
routing.multilayer_escape_celllocalbridge_layer*, cell*, clear, obstacle_layers, port_layer, route_layer*, spacing_um, via_layer*使用主路由层、bridge 层和 via 盒为被墙阻挡的成对 net 布线逃逸。
routing.steiner_celllocalanchor_layer, cell*, clear, obstacle_layers, port_layer, root_ports, route_layer在一个 KLayout 单元内使用 klink 的直角 Steiner/总线树路由器为多端子 net 布线。用于端口数超过两个的 net。
routing.tapered_hybrid_celllocalanchor_layer, angle_mode, cell*, clear, obstacle_layers, port_layer, spacing_um使用 klink 的 tapered hybrid 单元路由器为一个 KLayout 单元布线:读取 Port/Anchor PCell、规划路由、校验并写入结果。传入 obstacle_layers=[...],填你设计自己的 keepout 图层(无默认值)。
routing.tapered_polygon_celllocalanchor_layer, angle_mode, cell*, clear, corner_style, obstacle_layers, port_layer, route_layer, spacing_um使用 klink 的连续 tapered 多边形后端为一个 KLayout 单元布线,支持与 hybrid 路由相同的 Port/Anchor 语义,但写入的是连续 taper 多边形。

routing.gdsfactory_ports 的 router 策略(选错参数会报错并指出哪些 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。

示例。

# 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
路由完成的判据是结构化报告,不是“看起来连上了”。检查 ok、obstacle_hit_count、sibling overlap 和 route_count。真正的“完成”只有 live LVS match=True。

9 · 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 并(默认显示)在 Netlist/LVS 浏览器打开做 cross-probe。一个 P&R/器件阶段只有在真实 live LVS match=True 时才算 DONE——离线 fixture 和 marker 计数都不能替代。structdevice 流程优先用 structdevice.lvs_check。

工具类型参数功能
drc.runrpccode*, input_layout, output_rdb, result_mode, stderr_limit, stdout_limit, top_cell逃生舱:在 KLayout 集成的 Ruby DRC 引擎里跑任意 DRC DSL 脚本代码。接受 DRC DSL 源码(source()/input()/report() 等 Ruby 风格语法)并执行。report() 需要第二个参数:report("title", $output_rdb)——不给的话 RDB 永远不会被写入,rdb_summary 会空着返回且不报错,看起来“干净”是因为什么都没被记录,而不是因为没发现问题。脚本若包含 source() 则以 standalone 模式运行(针对指定文件);省略 source() 则以交互模式对当前已加载的 layout 运行。可选变量($input_layout、$output_rdb、$topcell)会被注入 Ruby 解释器,脚本可以直接引用它们而不必硬编码路径。stdout/stderr 会被捕获并以字符串形式返回。若指定了 output_rdb 且脚本生成了它,RDB 会被解析并返回违规摘要。DRC 脚本里的异常不会导致该 RPC 失败——它们会出现在 result.exception 中,连同报错前捕获到的 stdout/stderr;只有格式错误的请求(缺 code、过大)才会返回 ok=false。
lvs.runrpccell*, conductors*, devices*, out_lvsdb, reference*, show, vias通用 LVS(相当于连通性方向的 DRC 逃生舱):把 live 版图抽取成器件网表(按 devices 配置里的 per-cell 器件抽取器),再与你传入的参考网表比对——可以是外部 SPICE 文件(reference.spice),也可以是结构化网表(reference.netlist)。会写出原生 .lvsdb,并在 show=true(默认)时在 Netlist/LVS 浏览器中打开,以便版图与网表互相探查。纯 pya 实现,与具体领域无关;端子名字/层全部是参数。只读(会给内存中的版图加临时标记层,不改动已保存的几何)。

示例。

# 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

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

klink.find_tools domain="device_structdevice"

这是器件无关的自定义器件 P&R 流。“器件”=任何带任意参数集 + 端子的 cell;klink 不假设参数名/数量,也没有器件词汇表。器件库、工艺 profile、端子来源都是示例/PDK 数据显式传入——工具不带任何工艺,缺工艺时返回有指导性的错误(“写/跑一个 example”),绝不猜。structdevice.build_from_netlist 是一次调用的主流程(确认门控:先调一次拿 proposal,带 confirm token 再调才真正 build);路由跑在 flexdr 引擎上,物理模型很紧凑:器件自己的金属层同时当路由层用。structdevice.declare_nets/connect_nets/lvs_check/spec_write 是 SEND 驱动的交互路径。structdevice.register_pcell 封装了更底层的 plugin RPC pcell.register_fitted(列在 geometry_authoring 域)。

工具类型参数功能
structdevice.build_from_netlistlocalcell*, cols, confirm, mode, netlist*, rows, session从器件级网表构建一个电路 cell,全程算法化并带确认门控。分两次调用:(1) 不带 confirm 调用 -> 返回 needs_confirmation、一份 proposal(网格行数 x 列数、派生的行间距、路由图层、器件构成)和 next_action;把 proposal 念给用户看。(2) 用户批准后,用相同参数加上 next_action 中的 confirm 令牌再次调用 -> 此时会放置(派生的 floorplan)、单趟多层布线、绘制,并对一个全新 cell 做器件级 LVS 验证。网表格式:{instances: [{instance_id, device_cell}], nets: [{net_id, terminals: ['X1.D', ...]}], groups: [{instances: [...]}]}。没有任何手工调参:图层/via/间距来自工艺 profile,floorplan 由需求派生。不要自己放置/布线/绘制;除非用户要求,不要改动 rows/cols/mode;把 problems 原样转达给用户。每个结果都带 next_action——照做。
structdevice.connect_netslocalcell*, conductors, min_spacing_um, min_width_um, route_layer, route_width_um, session, via_cell, vias一次调用为器件 cell 中每一个已声明但未连接的 net 布线并验证:接入点由 recipe 派生,via 自动放置/复用,keepout 自动生成(net 之外的一切都是障碍),阻尼路由(damped routing),随后做 LVS——一旦不匹配,所有改动全部撤销。须在 structdevice.declare_nets 之后、structdevice.spec_write 之前调用。结果携带 next_action;把 problems 原样转达,切勿自行即兴布线。示例驱动,非开箱即用:接入点需要来自你项目的 recipe(klink 不自带),因此原样调用会返回一个指导性错误。
structdevice.declare_netslocalcell*, conductors, recent_sends*, vias从用户的 SEND 中声明电学 net:一次框住两个或更多器件端子的 SEND = 一个已声明的 net;声明会持久化到 <cell>.elec_nets.json,并供 structdevice.lvs_check / spec_write 使用。示例驱动,非开箱即用:读取器件端子需要从你的项目注入 recipe(klink 不自带),因此原样调用会返回一个点名所需 recipe 的指导性错误——绝不会靠猜测。
structdevice.lvs_checklocalcell*, conductors, mode, session, vias一次调用完成 LVS:派生器件端子(recipe),从保存的快照上用 KLayout 原生提取得到实际布线所形成的 net,并与 structdevice.declare_nets 持久化的已声明 net 做对账。mode='net'(默认)为 net 级 LVS-lite;mode='device'/'both' 还会额外运行器件级 LVS(构建参考网表 + 提取网表,用原生 NetlistComparer 比较)-> 结果放在 device_lvs 下。发现项是带端子级证据的指令;报告持久化到 <cell>.lvs.json。示例驱动,非开箱即用:派生器件端子需要来自你项目的 recipe(klink 不自带),因此原样调用会返回一个指导性错误。
structdevice.register_pcelllocaldiff_report, fit_table*, name*, session在运行期根据 fit table(由 exemplar fitter 生成)注册一个拟合器件 PCell。一次调用,零插件改动,零重载:PCell 落地到库 klink_structdevice 中,立即可在 GUI 中使用,也可通过 instance.insert_pcell 使用。须在 fitter 生成 table 之后调用;该 table 编码了用户几何数据,保留在本地。推荐流程:先针对 ground truth 运行逐字节差分测试工具(klink.domains.structdevice.pcell_diff.verify_differential),再把其结果作为 diff_report 传入,使注册过程带上验收证据。
structdevice.spec_writelocalcell*, conductors, device_class, layer_roles*, session, vias一次调用把一个 live cell 投影成 klink.spec.json v1 事实文件:包含器件(recipe 端子)、实例、已声明 net(来自 structdevice.declare_nets)、派生 net 及其对账结果。layer_roles 把 L/D 映射到角色名,并记录为 user_declared。该 spec 落地到与 net 表同目录的 <cell>.klink.spec.json。

示例。

# 第 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"}

11 · 成像(剖面 / 3D / SEM / Blender) imaging · 4 tools

klink.find_tools domain="imaging"

全部在 klink 侧运行(不涉及插件);重依赖是可选的,缺失时错误会指名确切的 pip install 命令。Recipe/VisualStack 实例是示例自有的——klink 只提供机制。imaging.xsection_run 沿显式切割线,按 .pyxs 工艺配方(引擎 klayout_pyxs)做工艺剖面;steps=true + 配方里的 '# klink-step: <name>' 标记可给每个工艺步骤各出一张剖面。imaging.render3d 生成 GLB + 自包含交互查看器 HTML,把 visual-stack 声明的每一层拉伸成 3D 掩膜(圆保持光滑棱柱);层的 sidewall_deg 声明侧壁倾角,cutaway_um 把建好的整个模型布尔切开露出截面;工艺曲率(LOCOS、CMP)这类真值仍然只在 imaging.xsection_run 的 2D 剖面里。imaging.sem_top 渲染确定性的 SEM 风格俯视图 PNG(灰度+假彩色)。imaging.blender 用无头 bpy 子进程做论文级渲染——mode=die 给 render3d 的 GLB 抛光,mode=figure 按 GDS+stack 以 1:1 版图坐标建器件图(lattice 层变成原子结构图案)。

工具类型参数功能
imaging.blenderlocalbasename, camera, cell, gds, glb, lattice_a_um, mode*, output_dir*, overwrite, samples, session, slabs, stack, style*, timeout_s, transparent, weld_slits_dbu论文级 Blender 渲染(headless bpy,在一个子进程里执行——bpy 从不常驻 server 进程内)。mode='die':导入 imaging.render3d 生成的 GLB,摆平放置,加胶片质感 + 透明片基 + 阴影接收板。mode='figure':按 GDS 驱动、以 1:1 版图坐标绘制器件图——kind='lattice' 的堆叠层渲染为材料的原子结构(石墨烯/MoS2 图案),实体层渲染为精确的版图棱柱,另加显式的衬底/氧化层“slab”。两种模式都会写出 <basename>.png(RGBA)+ <basename>.blend(可在桌面版 Blender 中打开手动调整)+ sidecar 文件。需要 pip install bpy(约 300MB;缺失时给出指导性报错)。渲染结果不是字节级确定的(Cycles 渲染器)。
imaging.render3dlocalbasename, cell, cutaway_um, gds, output_dir*, overwrite, session, stack*, style*, weld_slits_dbu为 layout 构建一个 3D 模型(GLB),外加一个自包含的交互式查看器页面(html:内嵌模型 + 内置查看器 JS + 手动的颜色/金属度/粗糙度面板 + PNG 导出;双击即可离线打开)。按 klink_visual_stack_v1 声明,把每一层在其 z0_um/z1_um 之间拉伸——模型就是这个 layout 本身(圆保持为光滑的棱柱)。若需要工艺真值(刻蚀轮廓、bird's beak、保形薄膜),请改用 2D 剖面工具 imaging.xsection_run;klink 不会伪造 3D 工艺仿真。层可以在 stack 中声明 sidewall_deg 以获得光滑的倾斜侧壁;cutaway_um 会把成型后的模型切到一个区域内。输出是确定性的,并附带 klink_imaging_result_v1 sidecar;除非 overwrite=true,否则绝不覆盖已有文件。
imaging.sem_toplocalbasename, cell, corner_radius_um, gds, layers, output_dir*, overwrite, session, stack*, style*, width_px, window_umlayout 的 SEM 风格俯视图:按 klink_visual_stack_v1 声明生成逐层灰度(sem_grey)+ 明亮的地形边缘高光(edge_glow),并叠加电子束模糊、胶片颗粒、扫描线和暗角(确定性,可设种子)。写出 <basename>_sem.png(灰度图)和 <basename>_sem_color.png(按图层颜色生成的假彩色图)+ klink_imaging_result_v1 sidecar。layers=[...] 可限定为某个子集——例如只画到某个工艺步骤为止已印出的掩膜。需要 numpy/scipy/pillow。
imaging.xsection_runlocalauto_layer_base, axis, basename, below_um, cell, cut_from_ruler, cut_um, delta_dbu, depth_um, exclude, extend_um, gds, height_um, output_dir*, overwrite, recipe*, render, ruler_id, ruler_segment, session, show, stack, steps, style, weld_slits_dbu, z_window_um沿一条显式的切割线,按 .pyxs 配方生成工艺剖面——headless、确定性,引擎固定为 klayout_pyxs(缺失时给出指导性安装报错)。写出 <basename>.gds(若 steps=true,则按配方里的 '# klink-step: <name>' 标记逐步骤各出一个文件)+ klink_imaging_result_v1 sidecar 到 output_dir;除非 overwrite=true,否则绝不覆盖。来源可以是一个 gds 路径,也可以是当前存活的 KLayout 会话(通过 layout.save_file 保存)。show=true 会在新标签页打开剖面。注意:.pyxs 配方是受信任的 Python 代码,会在进程内执行。

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

klink.find_tools domain="device_nanodevice"

nanodevice.hallbar 用一次调用完成整个流程:从 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.detect_commit 从预算 traces.json 提交 flake trace 为多边形,或对显微图像做实时检测(需 cv2 + numpy)。

工具类型参数功能
nanodevice.detect_commitlocalcell, coordinate, dry_run, image, pixel_size_um, session, traces_path一次调用完成加载(或检测)纳米器件 flake trace,并把它们作为多边形提交进 live KLayout cell。传 traces_path 使用预先算好的 traces.json;传 image(+ pixel_size_um)则现场跑检测(需要该解释器里装有 cv2/opencv + numpy)。状态落盘持久化;失败时返回指引,且不改动任何东西。
nanodevice.hallbarlocalcell, dry_run, route_layer, session, spacing_um, spec, writefield一次调用完成一个 Hall bar 器件的生成、路由、校验与提交:按 spec 生成几何 + Port/Anchor,用 klink 现有的 router 把 contact 接到 pad(重叠校验默认开启,可选 writefield 围墙),写入一个一次性 cell 并持久化状态。遇到问题会返回指引(problems/next_action);调用失败时不改动任何东西。

示例。

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"

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

klink.find_tools domain="device_photonics"

光子电路流,需 MCP 解释器里有 gdsfactory。两个端口来源、一个交互循环:photonics.import_gf 一次把成品 gdsfactory 脚本接管进循环——器件实例变成真实 KLayout cell+实例,routed 连接坍缩成器件级网络,per-device port 模板持久化进 spec,网络由 klink 路由。port.harvest_blackbox(列在 ports_and_anchors 域——从 live blackbox 实例位置派生 Port)是另一个端口来源;移动实例后重跑它,再路由。photonics.connect 读最近 N 次 SEND 当端口对,自动命名网络,持久化,重新 harvest,再用 gdsfactory 路由。photonics.reroute 在用户移动组件后重路由一个 cell(读持久 net 表)。多端光学网络不按星形路由——先插入显式 splitter/MMI/Y-branch,再路由拆出来的两端网络。

工具类型参数功能
photonics.connectlocalcell, radius_um, recent_sends*, route_layer, separation_um, stub_size_um, wg_layer, width_um一次调用连接用户刚 SEND 的端口:读取最近 N 次显式 SEND 选择,把它们转换成端口对(一次框住两个 klink Port 标记的 SEND 算一对;只框住单个标记的 SEND 按顺序两两配对),自动命名 net,持久化 net 表,从 live 实例位置重新 harvest 端口,再用 gdsfactory 路由。工作流程:用户为每一对端口按一次 SEND,然后带上 recent_sends 调用本工具;KLayout 会话会从这些 SEND 中自动推断。遇到问题时返回指引,绝不猜测。
photonics.import_gflocalcell, component, port_layer, route, route_layer, script_path*, session一次调用把一个已经写完的 gdsfactory 脚本接管进 klink 的交互循环:在这个(具备 gdsfactory 能力的)解释器里运行用户的 .py 文件,取出它构建的 Component,把其中的 DEVICE 实例导入为真正的 KLayout cell + 实例(批量 RPC),把脚本里已路由/已吸附的连接坍缩成器件级别的 net,把每个器件的 port 模板 + net 表持久化进 spec,再用 klink 给这些 net 布线(脚本自带的路由会被 klink 自己的路由替换掉)。之后用户可以在 KLayout 里拖动组件,再调用 photonics.reroute(只需给 cell 名字)就能按 live 位置重新布线。该脚本会被实际执行——只运行用户明确要求你导入的文件。
photonics.reroutelocalcell*, route_layer, session, stub_size_um, wg_layer在用户移动了组件之后,为一个此前用 photonics.connect 建立过连接的 cell 重新布线:读取持久化的 net 表,从 live 实例位置重新 harvest 端口,布线,再写回。只需要 cell 名字(若不是主会话,还需带上 session)。

示例。

# 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 约定派生端口后再连(这个工具列在 ports_and_anchors 域)
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

14 · L-Edit 桥(文件交换 RPC) bridge_ledit · 18 tools

klink.find_tools domain="bridge_ledit"

前提是用户把 example_template/ledit_bridge/ledit_bridge.cpp 以源码方式装载进 L-Edit(Tools → Macro → Load Macro…,零编译)。传输是 %LOCALAPPDATA%\klink\ledit_bridge\<namespace> 下的 JSON 文件交换,单命名空间——同时只保留一个装宏的 L-Edit。ledit.status 是发现与握手——任何异常先调它,错误信息直接写明下一步。ledit.import_selection 现拉用户当前 L-Edit 选区到新的 KLayout 落地 cell。ledit.push_cell 把 KLayout 平坦 cell 推回 L-Edit(追加式,重新生成用新 target cell)。ledit.import_cell_tree 把一个 cell 连同整棵层级导入 KLayout,children-first、实例照旧建成实例。ledit.push_cell_tree 反方向把整棵子树推回 L-Edit,同样保留层级,摆不出的摆放如实列出、绝不近似。更深的 T-Cell 工作流走 Python API klink.bridges.ledit;详见 《L-Edit 桥》指南。0.5.7 新增 13 个工具,把桥从画图传输扩展成完整的编辑器控制面:六个导航工具(show_cell/set_cell_hidden/list_windows/close_window/layout_view/save_image)、四个带显式目标且会拒绝的破坏性命令(delete_cell/rename_cell/delete_objects/close_design),以及三个验证工具(run_drc/drc_summary/export_gds);配套宏 0.5.6 → 0.5.8,升级后需要在 L-Edit 里重新装载宏。

工具类型参数功能
ledit.statuslocalnamespace发现 L-Edit 桥的可用命名空间,并报告其中一个的存活状态与握手信息:hello 心跳年龄、宏版本/能力、当前 .tdb 文件与 cell。宏支持时,还会列出全部已打开的设计(designs,含 visible/changed 标记)和当前活动设计的 cell 列表(含 T-Cell 标记);宏版本 >= 0.5.6 时,还会列出已打开的窗口(windows[])——一次调用即可回答“L-Edit 里现在有什么”。任何 ledit.* 调用行为异常时都应先叫它;错误信息会直接给出确切的修复办法(加载/重载宏、关闭一个模态对话框……)。
ledit.import_selectionlocalnamespace, session, target_cell把用户当前在 L-Edit 里的选区导入 KLayout 的一个全新落地 cell(每次调用都现拉一次 GET——绝不用陈旧几何)。通用能力匹配转换:box→box、wire→path、circle→Basic.CIRCLE PCell(保持参数化)、其余任意轮廓兜底转 polygon;不可转换的对象会被如实报告,绝不静默丢弃。图层按 name + GDS 号迁移(沿用 L-Edit 自己的层表;未映射的图层会被自动分配编号并报告)。
ledit.push_celllocalcell*, ledit_cell, namespace, session通过桥把一个 KLayout cell 的扁平化(flat)几何推送到 L-Edit cell:box、path(→wire)和 polygon 会被转移;text 和子实例会被计数并报告,不会被静默丢弃。在 L-Edit 中新建图层时,若对应的 KLayout 图层有 name 则使用该 name(否则用 L<gds>D<dt>),并附带 GDS 编号。L-Edit 侧的 draw 是仅追加(append-only)的——重新生成请换一个新的 ledit_cell。
ledit.import_cell_treelocalcell*, namespace, session把 L-Edit 一个 cell 连同它整棵层级导入 KLayout,建成真实的 cell + 实例(ledit.import_selection 读的是当前选区,按设计会丢弃实例)。children-first 重建;层身份连名带 GDS 号一起迁移;每个目标 cell 都会被重新创建,因此重复导入是幂等的。L-Edit 暴露出但没有可转换轮廓的形状列进 not_convertible。
ledit.push_cell_treelocalcell*, clear, expect_file, namespace, session把 KLayout 一个 cell 连同它下面整棵子树推回 L-Edit,保留层级(ledit.push_cell 是平坦版——遇到子实例会拒绝):children-first 建 cell,实例重建成真实实例。默认幂等(每个 cell 在重绘前会先被清空,因为 L-Edit 的 draw 只会追加)。整棵树作为一次有序批量请求整体发送。L-Edit 摆放机制无法精确表达的实例(缩放、非正交旋转、错切阵列)会被列进 unsupported_instances,绝不做近似凑合。要推整个设计而不是一棵子树,走 import_gds 的 GDS 文件更省事。
ledit.show_celllocalcell*, namespace打开(或前置)某个 L-Edit cell 的版图窗口并将其设为可见 cell——对应“在 L-Edit 里给我看 X”/“打开 cell X”。返回 window_opened(是否新建了窗口)和 via。cell 名字来自 ledit.status 的 cells[]。对设计只读:不触碰任何几何。
ledit.set_cell_hiddenlocalcell*, hidden*, namespace把某个 L-Edit cell 从 cell 列表中隐藏(即自动生成的 T-Cell 变体自带的 “Hide In Lists” 标记)或重新显示——对应“隐藏 cell X”/“取消隐藏 X”。通过原生标记 LCell_SetShowInLists 往返读写并回读实际值;若存储属性与标记不一致,两者都会报出(hidden、hidden_property),绝不擅自二选一。ledit.status 的 cells[] 读取的是同一个标记。
ledit.list_windowslocalnamespace列出所有打开的 L-Edit 窗口(版图/文本/日志……),带 index、file、cell 及是否可见;没有设计打开时也能用;index 就是 ledit.close_window 用的句柄。
ledit.close_windowlocalcell, file, index, namespace按 cell 名(同名跨设计用 file 消歧)或 list_windows 给的 index 关闭窗口,返回 matched/closed;无末窗防呆——关掉设计最后一扇窗口可能连设计一起关掉,动手前先确认没打算关自己没开过的窗口。
ledit.layout_viewlocalcell, home, namespace, rect_um一个视图动词——不带 rect_um/home 时读取当前视图;rect_um=[left,bottom,right,top](微米)设置视图(缩放到该区域——即“缩放到器件”/“看这个区域”这类需求);home=true 复位到该 cell 的 home view。总是返回调用之后的实际视图,外加 has_window(没有打开窗口时 rect 没有意义——先调用 ledit.show_cell)。默认 cell 为当前可见 cell。
ledit.save_imagelocalcell*, dpi, height_px, namespace, path*, rect_um, width_px通过 LCell_SaveImageToFile 把一个 L-Edit cell 渲染成图片文件(按扩展名 PNG/BMP/JPG)——默认整个 cell,或用 rect_um 限定区域。仅限用户明确要求的图片/截图产物:只在用户要看 L-Edit cell 的图片/截图时调用,绝不当作验证证据(验证请用 ledit.status/get_cell 几何数据,与 KLayout view.screenshot 同一条规矩)。目标文件夹必须已存在。返回 path 与 bytes。
ledit.delete_celllocalcell*, force, namespace破坏性——按显式名字删除 L-Edit cell;除非 force=true,遇到“是可见 cell”“被其他 cell 实例化”“是 T-Cell 生成器”都拒绝并点名引用者;删除用户画的东西前先确认,klink 自己的 scratch cell(推送目标、探针)可以随便删。
ledit.rename_celllocalcell*, namespace, new_name*重命名 L-Edit cell;new_name 已存在则拒绝(用 ledit.status 的 cells[] 查看现有名字)。
ledit.delete_objectslocalcell*, layer, namespace, rect_um破坏性——按图层和/或区域删除 cell 内的形状;rect_um=[left,bottom,right,top](微米)只删边界框完全落在矩形内的对象(穿过矩形的路由留着不动);layer 限定单个图层,两者至少给一个;实例从不在这里被删(清整个 cell 用 clear_cell);返回 deleted 与 by_layer;除非是 klink 自己的 cell,动手前先确认。
ledit.close_designlocaldiscard, file*, namespace按名字(来自 ledit.status 的 designs[])关闭一个已打开的 L-Edit 设计;有未保存改动时拒绝,除非 discard=true;关掉设计最后一扇窗口不会关闭设计本身——这是关闭它的唯一办法;用来丢弃 klink 建的 scratch 设计(new_design),关别人的设计前先确认。
ledit.run_drclocalcell, namespace, rect_um用设计已加载的规则集,对一个 cell 跑 L-Edit 自带的 DRC(整个 cell,或用 rect_um=[left,bottom,right,top](微米)限定区域);只报告错误数量和 status——L-Edit v16.3 的 UPI 不暴露违例几何;要拿违例几何请改用 export_gds 配合 klink 的 KLayout 侧 DRC 工具。同时报告规则数量。设计没有 DRC 规则时拒绝执行。
ledit.drc_summarylocalcell, namespace不重新跑 DRC,只读某个 cell 上一次的结果:errors 与 status(needed=从未跑过或已过期、passed、failed);首次跑之前 errors 是 null。
ledit.export_gdslocalcell, cell_name_length, include_hierarchy, log_path, namespace, path*用 LFile_ExportGDSII 把整个设计(或指定 cell 连同层级)写成 GDS 文件——这是 L-Edit 到 KLayout 最便宜的回程:KLayout 侧 layout.file_info / layout.import_file 会原样读取,这个方向不需要额外补零。GDS 把 cell 名限制到 cell_name_length(标准值 32;KLayout 接受更长,klink 长命名回程时可调高);目标文件夹必须已存在;导出日志写到 log_path(默认在桥 inbox 旁边)并被扫描错误。

15 · Escape hatch(pya exec、事件、recorder) escape_hatch · 9 tools

klink.find_tools domain="escape_hatch"

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

工具类型参数功能
events.channelsrpc列出 server 可以推送的事件通道。通过 events.subscribe 订阅其中的子集。事件以 NDJSON 帧的形式投递,格式为 {"event": "<name>", "data": {...}}。
events.statusrpc返回调用连接的事件订阅情况和 SignalHub 诊断信息。用它来调试 selection_changed 等交互事件是否已绑定并订阅。
events.subscriberpcchannels*让调用连接订阅一个或多个事件通道。未知通道会被静默忽略(检查响应中的 accepted)。调用 events.channels 获取完整列表。
events.unsubscriberpcchannels让调用连接退订一个或多个通道。传空列表或省略则状态不变;传 * 退订全部。
exec.pythonrpccode*, protect_cellview, reset, result_mode, stderr_limit, stdout_limit逃生舱:在 KLayout 的 Qt 主线程里跑任意 Python 代码,拥有完整 pya 访问和完整文件系统访问权限——等价于从 IDE 里跑一个宏。预绑定的全局变量:pya、mw(主窗口)、view(当前 LayoutView)、layout(当前 Layout)。状态在同一连接的多次调用之间保留;传 reset=true 先清空命名空间。stdout/stderr 会被捕获并以字符串返回。如果最后一条顶层语句是表达式,其值会以 return_value(类似 Jupyter)的形式返回;否则 had_result=false。用户代码中的异常不会导致该 RPC 失败——它们会出现在 result.exception 中,连同报错前捕获到的 stdout/stderr;只有格式错误的请求(缺 code、过大、语法错误)才会返回 ok=false。编写 LLM 反馈循环的调用方应该基于 result.exception 分支处理。
exec.resetrpc清空 exec.python 使用的、按连接隔离的 Python 命名空间。等价于用 reset=true 且不带代码调用 exec.python。适用于客户端只想要一个全新沙箱、不想顺带跑其它东西的场景。
recorder.startrpcoutput_path开始记录所有改动版图的事件,并把它们翻译成一份可回放的 Python 脚本。幂等:已经在录制时再调用只会返回当前状态,不会开启新会话。传 output_path 可覆盖默认输出位置(~/Documents/klink_recordings/klink_record_YYYYMMDD_HHMMSS.py)。
recorder.statusrpc返回当前 recorder 状态(是否正在录制、目前的事件数与已翻译的动作数、配置的输出路径)。任何时候调用都是安全的。
recorder.stoprpcoutput_path停止正在进行的录制,并把可回放脚本写入磁盘。返回最终统计数据,外加 wrote(布尔值)表示文件是否成功写入。幂等:并未在录制时调用会返回 wrote=false 及最后一次已知状态。

示例。

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 版)。

想看这些工具在真实流程里怎么配合?去 教程 看可跑 demo 的逐个详解。