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>.jsondelta 对树做多重集 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.tomlversion。 正式发布前可先试水 Test PyPI: uv publish --publish-url https://test.pypi.org/legacy/ --check-url https://test.pypi.org/simple/ (需要 test.pypi.org 的 token,写到 ~/.pypirc[testpypi] 段)。

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

uictl-0.1.4.tar.gz (45.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

uictl-0.1.4-py3-none-any.whl (48.5 kB view details)

Uploaded Python 3

File details

Details for the file uictl-0.1.4.tar.gz.

File metadata

  • Download URL: uictl-0.1.4.tar.gz
  • Upload date:
  • Size: 45.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.6.6

File hashes

Hashes for uictl-0.1.4.tar.gz
Algorithm Hash digest
SHA256 b9a2414c422f2a792042fef385af88ecd1c870b17970944935a838c7eb8ce80c
MD5 fd0a86c40fdedf060c2d7cbf5affd613
BLAKE2b-256 b888a4856e1316f8f7740feb80aa67a2cc69197f744524b3fe7f0b6606537edf

See more details on using hashes here.

File details

Details for the file uictl-0.1.4-py3-none-any.whl.

File metadata

  • Download URL: uictl-0.1.4-py3-none-any.whl
  • Upload date:
  • Size: 48.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.6.6

File hashes

Hashes for uictl-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 de41d97d0d3b81027d3570c851a43c87343c1a9c4712603ecc671735235d8755
MD5 f97432a68be91a987f316af229926357
BLAKE2b-256 073a18b2b319ec2e7247850980876cf6bd63ec8d17e8c25d3d363c47b0753b4d

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.4 This release

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page