Skip to main content

uictl

Linux 桌面 UI 自动化控制 CLI,基于 dogtail / AT-SPI 无障碍树。搜索窗口、浏览控件树、点击控件、输入文本、等待/断言,一条命令搞定。

uictl apps                              # 列出所有应用
uictl windows gnome-text-editor         # 列出应用的窗口
uictl tree gnome-text-editor --depth 4  # 打印窗口控件树
uictl find gnome-text-editor "role=button"
uictl inspect gnome-text-editor "name=保存"
uictl read Chromium                        # 提取页面干净文本(自动定位 document)
uictl read Chromium 'role=paragraph'       # 只读 selector 子树下所有文本
uictl click gnome-text-editor "role=button[name=保存]"
uictl type gnome-text-editor "role=text" --text "hello"
uictl wait  gnome-text-editor "name=保存" --visible
uictl expect gnome-text-editor "name=保存" --visible --sensitive

安装

# 轻量命令(不碰无障碍树):直接跑
uvx uictl --version
uvx uictl install-skill        # 注入 agent 技能到 ~/.agents/skills/uictl/

# 完整 UI 命令:用系统 Python 跑(gi 无 PyPI wheel,只能来自系统包;
# uictl 在 gi 缺失时自动注入系统 site-packages 到 sys.path,无需 PYTHONPATH)
uvx --python /usr/bin/python3 uictl apps

# 或持久安装
uv tool install uictl --python /usr/bin/python3

依赖系统包(AT-SPI typelib,无法 pip 安装): gir1.2-atspi-2.0 python3-gi python3-pyatspi (Wayland 下如需输入注入:gnome-ponytail-daemon,GNOME 46+ 已封禁注入,见下)。

本地开发(本仓库):

cd ~/projects/uictl
uv venv .venv --python $(which python3) --system-site-packages
uv pip install -e .

子命令

子命令 作用 Wayland 可用
apps 列出应用(--json) ✅
windows [APP] 列出窗口 ✅
tree APP 控件树(--depth --path --json) ✅
find APP SEL [--context N] 搜索控件,输出 path;--context N 打印目标周边局部树 ✅
inspect APP SEL 控件详情(状态/文本/坐标/Action 列表) ✅
click APP SEL 点击:AT-SPI Action 自动链(click→press→activate→toggle→check/uncheck),全无才回退注入(--action NAME) ✅ Action / ⚠️ 注入
dblclick APP SEL 双击 ⚠️ 需注入
hover APP SEL 悬停 ⚠️ 需注入
type APP SEL --text X 输入:fill 后自动验证,失败自动降级 insert_text,仍失败清晰报错(--keystrokes 逐键 ⚠️ 需注入) ✅ / ⚠️
key COMBO 组合键,如 "<Control>a" ⚠️ 需注入
read APP [SEL] [--win] [--min-length N] [--skip-role a,b] [--max-depth N] 提取干净文本:默认读窗口内所有 document 节点,无则整窗;传 SEL 则读其子树 ✅
search [APP] KEYWORD [--win] [--scope] [--name-only] [--context N] [--limit N] 全文发现(name/text/desc 子串,不区分大小写);APP 省略搜所有应用 ✅
snapshot APP [--win] 捕获 tree-json 精度基线,打印短 id,存 /tmp/uictl-UID/<id>.json ✅
delta ID [--keep] [--json] 对比快照,输出 +/-/~(树节点级差异),默认 diff 后删除 ✅
snapshots [--clear] 列出/清理存活快照 ✅
wait APP SEL [--visible] [--sensitive] [--focused] [--gone] 轮询等待条件成立 ✅
expect APP SEL [--text S] [--role R] ... 断言,失败 exit 1 ✅
install-skill [--dir DIR] [--force] 注入 agent 技能到 ~/.agents/skills/uictl/ ✅

⚠️ 需注入 = 需要原始输入注入(X11 会话原生支持;Wayland 需 RemoteDesktop 后端)。在只读环境(GNOME 46+ Wayland)下这些命令会报清晰错误而不是 抛 traceback。

选择器语法(Playwright 风格)

role=button[name=保存]         # 引擎 + [属性...]
name=保存                      # 单属性
text=请输入                    # 匹配 node.text 子串
path=0:2:3                     # 从应用根开始的索引路径(find 输出的 path 可直接用)
保存                           # 裸字符串 = name

支持属性:name role(role_name) desc(description) label id(accessible_id) text。 值含空格需加引号:name="保存 文档"。

strict 模式:inspect/click 等要求唯一匹配,命中多个会报错并列出全部匹配, 用 --index N 指定;--scope 限定在父节点内搜索;--win 指定多窗口应用的窗口。

read:提取干净的页面文本

uictl read APP 把页面内容抽成干净的纯文本行(每段/每标题一行),适合让 agent 直接"读网页"。行为:

  • 默认根:在窗口里递归找所有 document 类角色(document / document web / document frame / document picture / web area),逐个读取拼接;一个都没有 (如 GTK 文本编辑器)就回退读整个窗口子树。
  • 去重:容器节点(heading/paragraph/link)的 node.text 已聚合子孙文本, 重复的 static 子节点会被自动丢弃,标题/链接不会出现两遍。
  • 内联替换:Chromium 用 \ufffc(U+FFFC) 占位内联子节点,如 "You can ." 会还原成 "You can index it here."。
  • image 无文本时用其 name(alt 文本)兜底。

常用参数:--min-length N 丢弃过短行、--skip-role button,panel 整类跳过、 --max-depth N 限深、--win 指定窗口。传 SEL 时改为 strict 解析单个节点、只读 该子树(如 uictl read Chromium 'role=paragraph')。

search / snapshot / delta:给 LLM Agent 的"发现 + 验证"配套

uictl 面向 LLM Agent 使用做了几处容错设计:

  • type 不再静默撒谎:fill(set_text_contents)后自动读回验证,失败自动降级 delete_text + insert_text(Chromium 网页输入框吃这一套),仍失败才报清晰错误。

  • click 自动选 Action:按 click → press → activate → toggle → check/uncheck 依次尝试,Wayland 下 radio/checkbox 无需手动 --action。

  • search 代替 tree | head:禁止对 tree 全量输出用 head 截断(会漏掉 document 里的内容)。发现用 search APP "关键词"(覆盖整页、一次拿全),看结构用 find APP SEL --context N(目标周边局部树,命中行标 ◀ target)。

  • snapshot + delta 验证操作生效:

    $ uictl snapshot Chromium
    snap: e3f2a91
    $ uictl type Chromium "name=令牌名称" --text tea-cli
    $ uictl delta e3f2a91
    ~ [entry] 令牌名称: text '' → 'tea-cli'      # 填进去了
    [snapshot e3f2a91 removed]
    
    • snapshot 捕获与 tree --json 同精度的树(role/name/text/path/children), 存 /tmp/uictl-<uid>/<id8>.json;delta 对树做多重集 diff(稳定键 role+name+text,忽略 path/坐标 churn),输出 + 新增 / - 消失 / ~ 文本编辑。
    • 默认 diff 完即删,强制"基线→操作→验证"原子化,防止拿过期基线对比;--keep 保留、snapshots 列出、--clear 清空。
    • 性能说明:tree/snapshot/delta 都是整树遍历,AT-SPI 每节点一次 DBus(无缓存), 重页面约 5–15s,属正常范围(tree --json 用增量 path,比旧版快约 5 倍)。

平台限制说明(为什么有的命令报错)

  • 读(apps/windows/tree/find/inspect/read/search/snapshot/delta/wait/expect)走 AT-SPI 总线,Wayland 全可用。
  • 控(click/type-fill)走 AT-SPI 接口(Action/EditableText/Component), 应用自己实现,Wayland 全可用——这是 GNOME 给无障碍"控制"设计的官方通道。
  • 原始输入注入(key/hover/dblclick/type-keystrokes)在 X11 走 XTEST; 在 Wayland 被设计成受控特权(需 RemoteDesktop portal 授权)。 另外 GNOME 46+ 移除了 org.gnome.Shell.Introspect.GetWindows, gnome-ponytail-daemon 依赖它做坐标换算,因此 dogtail 的注入在 GNOME 46+ Wayland 上整体不可用 → uictl 会报清晰错误。

退出码

  • 0 成功
  • 1 未找到 / 断言失败 / strict 多匹配 / 平台不支持
  • 130 用户中断

Roadmap

  • screenshot(GNOME 50 需走 XDG Desktop Portal,core.take_screenshot 已预留)
  • RemoteDesktop portal 输入后端(Wayland 注入的官方通道,需用户授权)

发布到 PyPI

cd ~/projects/uictl
uv build                                    # 构建 sdist + wheel(产出 dist/)
uv publish                                 # 需要 PyPI API token 凭据

凭据(三选一):

  • ~/.pypirc([pypi] username=__token__ password=pypi-xxx)——本机已配置
  • 环境变量:UV_PUBLISH_TOKEN=pypi-xxx uv publish
  • 交互输入:uv publish --username __token__(会提示输入密码)

⚠️ 版本一旦发布不可覆盖,改代码后记得 bump pyproject.toml 的 version。 正式发布前可先试水 Test PyPI: uv publish --publish-url https://test.pypi.org/legacy/ --check-url https://test.pypi.org/simple/ (需要 test.pypi.org 的 token,写到 ~/.pypirc 的 [testpypi] 段)。

Metadata

Release files for uictl 0.1.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for uictl 0.1.4
File Size Uploaded
uictl-0.1.4.tar.gz 45.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for uictl 0.1.4
File Interpreter ABI Platform
uictl-0.1.4-py3-none-any.whl Python 3 none any Details

Total release size: 94.3 kB

Release files / uictl-0.1.4.tar.gz

Download URL uictl-0.1.4.tar.gz
Size 45.7 kB
Tags Source
SHA-256 checksum
How to use checksums
b9a2414c422f2a792042fef385af88ecd1c870b17970944935a838c7eb8ce80c
BLAKE2b-256 checksum
How to use checksums
b888a4856e1316f8f7740feb80aa67a2cc69197f744524b3fe7f0b6606537edf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.6.6

Release files / uictl-0.1.4-py3-none-any.whl

Download URL uictl-0.1.4-py3-none-any.whl
Size 48.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
de41d97d0d3b81027d3570c851a43c87343c1a9c4712603ecc671735235d8755
BLAKE2b-256 checksum
How to use checksums
073a18b2b319ec2e7247850980876cf6bd63ec8d17e8c25d3d363c47b0753b4d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.6.6

Release history Release notifications | RSS feed

This release

0.1.4 This release

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page