Skip to main content

A framework for automating HarmonyOS / OpenHarmony devices through LLM agents

Project description

HarmonyRun 命令行使用说明

HarmonyRun 是一款通过自然语言驱动真机或模拟器完成自动化任务的命令行工具,面向 HarmonyOS(鸿蒙) 平台。

pip install harmonyrun

源码、问题反馈与完整文档:GitHub - HarmonyOS-AI/HarmonyRun

下文示例统一使用 python3 -m harmonyrun 的写法;若已激活虚拟环境或通过 pipx / uv tool 将命令加入 PATH,可直接使用 harmonyrun,两者等价。


1. 环境要求

项目 说明
操作系统 macOS / Linux / Windows 均可
Python 3.11 ~ 3.13
鸿蒙设备 已安装 hdc(DevEco Studio 自带,需加入系统 PATH);hdc list targets 能看到设备
LLM 访问 使用 run / test 需要可访问的 LLM 服务及对应 API Key(详见 第 4 节

2. 安装

2.1 推荐:从 PyPI 安装

python3 -m venv .venv
.venv/bin/python3 -m pip install -U pip
.venv/bin/python3 -m pip install harmonyrun

验证安装:

.venv/bin/python3 -m harmonyrun --version
.venv/bin/python3 -m harmonyrun --help

默认已包含 OpenAI / Anthropic 两家 LLM 适配器。需要 Gemini 或 Ollama 时按需追加:

pip install "harmonyrun[google]"   # Gemini
pip install "harmonyrun[ollama]"   # Ollama
pip install "harmonyrun[all]"      # 全部可选 provider

2.2 离线:从 wheel 包安装

拿到离线交付包(内含 dist/ 目录与本说明)时,解压到任意目录。以下命令中的版本号、路径请按本机实际情况替换。

cd /你的解压目录

python3 -m venv .venv
.venv/bin/python3 -m pip install -U pip

# 若 dist/ 内只有一个 wheel,可以用通配符(不要加引号)
.venv/bin/python3 -m pip install dist/harmonyrun-*-py3-none-any.whl

2.3 可选:pipx / uv tool

把命令直接装进 PATH,无需手动激活虚拟环境:

pipx install harmonyrun
# 或
uv tool install harmonyrun

# 离线包同理,把包名换成 wheel 路径
pipx install /你的解压目录/harmonyrun-<版本>-py3-none-any.whl

3. 快速上手

  1. 确保 hdc list targets 能看到设备。
  2. 首次运行任意命令会自动在用户目录生成 config.yaml
 python3 -m harmonyrun --help
  1. 第 4 节 编辑 config.yaml.env,至少配置一个可用的 API Key。
  2. 运行一个任务:
 python3 -m harmonyrun run "打开设置"

4. 配置文件与环境变量

HarmonyRun 的运行时偏好分布在三个地方,职责定位如下:

用途 优先级 典型字段
CLI 参数(如 --steps 20 / --perception-mode a11y 单次运行的临时覆盖 最高 §5 run 选项表
config.yaml~/.config/harmonyrun/config.yaml 持久化的用户偏好 全部 schema 字段
环境变量 仅限 secrets / 部署级路径 / 运行时调试开关;不承担业务字段覆盖 视用途分两类 §4.3 白名单

业务字段(steps / perception_mode / model / temperature 等)通过 CLI 或 config.yaml 改 —— 不要试图用环境变量绕过。

4.1 配置读取优先级(从高到低)

  1. 命令行 -c / --config 指定的 YAML 文件
  2. 环境变量 HARMONYRUN_CONFIG 指向的 YAML 文件
  3. 用户配置目录下的 config.yaml
  4. 若上述文件不存在,首次运行时会把仓库内置的 config_example.yaml 拷贝到该位置

4.2 用户配置目录

config.yaml.env 始终位于 ~/.config/harmonyrun/

系统 用户配置目录
macOS / Linux / Windows ~/.config/harmonyrun/(受 XDG_CONFIG_HOME 影响)

历史上 macOS / Windows 走的是各自系统约定(~/Library/Application Support/harmonyrun/%APPDATA%/harmonyrun/),统一到 ~/.config/harmonyrun/ 是为了和 gh / starship / ripgrep 等工具保持一致。老用户首次运行 HarmonyRun 时会自动把旧路径下的 config.yaml 拷贝到新位置(原文件保留不动,确认无误后可手动删除)。

4.3 .env 与环境变量

HarmonyRun 在 run / test / farm run 入口启动时会自动读取两处 .env,两次读取都不会覆盖已经存在的环境变量:

  1. 当前工作目录及父目录:以 python-dotenv 默认规则向上查找 .env。适合把密钥跟工程放在一起。
  2. 用户配置目录(见 4.2)下的 .env:作为全局兜底。

4.3.1 LLM API Key

把密钥放到 .env 而不是 config.yaml,更适合团队共享配置模板而密钥各自保管。

可以把下面这样的文件放在工程当前目录(推荐)或用户配置目录下:

# 百炼(Anthropic 协议)
ANTHROPIC_API_KEY=sk-sp-xxxxxxxxxxxxxxxx

# 其它提供商(按需)
# GOOGLE_API_KEY=...
# GEMINI_API_KEY=...
# OPENAI_API_KEY=...

同时,从 .env 里去掉 config.yaml 中各角色下的 kwargs.api_key,只保留 base_url

llm_profiles:
  fast_agent:
    provider: Anthropic
    model: qwen3-vl-plus
    temperature: 0.2
    base_url: https://coding.dashscope.aliyuncs.com/apps/anthropic

4.3.2 API Key 的最终优先级(从高到低)

  1. config.yamlllm_profiles.<角色>.kwargs.api_key(如果填了就直接传给底层 SDK)
  2. 系统 / shell 环境变量(export ANTHROPIC_API_KEY=...,进程已有的值永远不被 .env 覆盖)
  3. 当前工作目录及父目录 下的 .env(先于用户配置目录加载)
  4. 用户配置目录下.env(最后一层兜底)

直白点说:进程一旦持有了某个 *_API_KEY,两个 .env 都不会覆盖;用户配置目录的 .env 仅在 shell env 和 cwd .env 都没设置时才生效。

4.3.3 HarmonyRun 系统级环境变量白名单

变量 用途 何时直读
HARMONYRUN_CONFIG 指定一个 config.yaml 路径,覆盖默认 加载配置之前
XDG_CONFIG_HOME 覆盖 ~/.config 基址 解析用户配置目录
HARMONYRUN_HDC_PATH / HDCUTILS_HDC_PATH 指定 hdc 可执行路径 hdcutils 启动
HARMONYRUN_TELEMETRY / HARMONYRUN_TELEMETRY_ENABLED 遥测开关 telemetry 初始化
HARMONYRUN_STREAM_SCREENSHOTS 调试用:流式发送截图(等价于 logging.stream_screenshots: true 配置加载时
HARMONYRUN_GITHUB_REPO / HARMONYRUN_FEEDBACK_STORAGE_REPO feedback 子命令:issue 落点仓 / trajectory zip 落点 drop-repo(见 §10.2 feedback 运行时

这些是唯一允许通过环境变量影响行为的字段。其他需要持久化的偏好请改 config.yaml;需要单次调整的请用 CLI。

4.3.4 设备解锁口令

运行任务时 HarmonyRun 会先检查设备电源状态,若处于 SLEEP 会自动唤醒并滑开锁屏;若设备设置了 PIN / 密码锁,需要通过环境变量提供解锁口令,否则只能滑开但无法通过密码屏。

变量名 用途
HARMONYRUN_DEVICE_UNLOCK_PASSWORD 全局回退口令,所有设备共用
HARMONYRUN_DEVICE_UNLOCK_PASSWORD_<SERIAL> 指定设备专用口令;优先级高于全局回退。<SERIAL> 中非字母数字字符替换为下划线,并整体大写

示例:设备序列号为 22M0224104000249,对应变量名为 HARMONYRUN_DEVICE_UNLOCK_PASSWORD_22M0224104000249

# 全局回退
HARMONYRUN_DEVICE_UNLOCK_PASSWORD=123456

# 指定设备(带连字符或其它符号的序列号,非字母数字都转成 _)
HARMONYRUN_DEVICE_UNLOCK_PASSWORD_22M0224104000249=123456

口令会在唤醒后自动输入;如果不配置,运行时会在日志中提示 "no HARMONYRUN_DEVICE_UNLOCK_PASSWORD",此时请确保设备未设置密码锁。

4.4 config.yaml 精简模板

首次运行会在 ~/.config/harmonyrun/config.yaml 生成下面的精简模板,可直接在其上修改。完整 schema 见 src/harmonyrun/config/schema/,下表只列常改字段

# === Agent ===
agent:
  max_steps: 15                  # 单任务最大步数
  reasoning: false               # true=Manager+Executor 两阶段;false=FastAgent 单轮
  streaming: true                # 流式打印 LLM 响应

  # UI 感知模式 —— 决定 LLM 每步看到什么:
  #   a11y       : 仅 a11y 文本(index-based 点击,token 最省)
  #   screenshot : 仅截图(坐标点击,与 use_normalized_coordinates 互斥)
  #   both       : a11y 文本 + 截图(默认)
  perception_mode: both

  # 内置 system / user prompt 的自然语言:
  #   en : 英文(默认,与历史行为一致)
  #   zh : 中文
  # 切换只影响"叙述语言"——工具名 / XML 标签 / 字段名 / 参数名都仍保持
  # 英文(如 click_at、<device_state>、dismiss_after),以保证 LLM 的
  # 解析协议不变。自定义 prompt(HarmonyAgent(prompts=...))不受影响。
  prompt_language: en

  app_cards:                     # 详见 ./应用卡片.md
    enabled: true
    mode: local                  # local | server | composite

# === LLM Profiles ===
# 每个 agent 角色用哪个 LLM。CLI 的 --provider/--model/--temperature/--base_url
# 会一次覆盖所有 profile;要分别配置请直接改这里。
# kwargs 里可以放 API key(如果不想用环境变量),如 kwargs: { api_key: sk-... }
llm_profiles:
  manager:
    provider: GoogleGenAI
    model: gemini-3.1-flash-lite-preview
    temperature: 0.2
  executor:
    provider: GoogleGenAI
    model: gemini-3.1-flash-lite-preview
    temperature: 0.1
  fast_agent:
    provider: GoogleGenAI
    model: gemini-3.1-flash-lite-preview
    temperature: 0.2
  app_opener:
    provider: GoogleGenAI
    model: gemini-3.1-flash-lite-preview
    temperature: 0.0
  structured_output:
    provider: GoogleGenAI
    model: gemini-3.1-flash-lite-preview
    temperature: 0.0

# === Device ===
device:
  serial: null                   # null = 自动选第一台已连接的设备
  # 仅 `harmonyrun test`:每个 case 启动应用前,先把设备切到目标姿态。
  # 失败采 best-effort(warn + 继续),不会让用例直接 fail。
  orientation: null              # portrait | landscape | portrait_inverted | landscape_inverted | null=不强制
  fold_display: null             # expanded | folded | null=不强制;非折叠屏配 expanded/folded 会被自动跳过
  harmony_sdk_path: null         # HarmonyOS SDK / 命令行工具根:仅模拟器折叠/旋转用(定位 host Emulator 二进制);null=自动发现;真机无需配

# === Logging ===
logging:
  debug: false                   # 详细日志(也会激活 per-LLM JSON 日志写到 trajectory log/)
  save_trajectory: none          # none | step | action
  trajectory_path: trajectories  # 轨迹根目录
  screen_recording: false        # 屏幕录制(save_trajectory != none 时才生效)

# === Tools ===
tools:
  # 坐标类工具(click_at / click_area / long_press_at)默认启用,作为逃逸手段。
  # a11y 模式下优先用 index 点击(工具描述已写明),index 点不到的目标用坐标兜底。
  # 如需关掉,在这里按名字列出(默认空)。
  disabled_tools: []

# === Telemetry ===
telemetry:
  enabled: false                 # 也可通过 HARMONYRUN_TELEMETRY_ENABLED=false 关闭

4.4.1 不在精简模板里、但仍可写的高级字段

下列字段都有合理默认值,专家场景下可写进 config.yaml

  • agentnameafter_sleep_actionuse_normalized_coordinatesfilter_a11y_tree
  • agent.app_cardsserver_urlserver_timeoutserver_max_retries(仅 mode=server/composite 用)
  • devicesimplify_treeannotation_max_depthannotation_min_sizeauto_wakekeep_awakekeep_awake_interval
  • toolsstealthswipe_fast_default
  • llm_profiles.<role>base_urlkwargs

字段定义全部在 src/harmonyrun/config/schema/*.py 里,是 Python dataclass。

4.5 LLM 模型切换要点

  • 推荐使用支持视觉的模型(百炼上的 qwen3.6-plus 或 Claude Sonnet 4.x 等)并把 agent.perception_mode 设为 both(默认)—— LLM 同时看到 a11y 树和截图,能显著提高对复杂界面的理解与点击准确率。
  • 如果用的是纯文本模型或希望节省 token,把 agent.perception_mode 设为 a11y:只发文本树,优先用 click(index=N) 类工具点击。坐标工具(click_at 等)默认仍启用,作为 index 点不到时(如 WebView 内部图标)的逃逸手段;如确实想关掉,写进 tools.disabled_tools
  • 极少数场景(如全屏 Canvas 应用)a11y 树价值很低,可以试 agent.perception_mode: screenshot,让 LLM 主要用坐标点击(坐标工具默认已启用,无需额外配置)。

5. run:执行单个自然语言任务

python3 -m harmonyrun run "你的任务描述"

常用选项:

选项 含义
-c, --config 指定配置文件
-d, --device 设备序列号或 IP
-p / -m LLM 提供商与模型,必须同时指定
--temperature 采样温度
--steps 单任务最大步数
-u, --base_url 自定义 API 地址(OpenRouter / Ollama / OpenAI-Like)
--perception-mode a11y / screenshot / both
--reasoning / --no-reasoning 切换规划推理模式
--stream / --no-stream 流式输出
--save-trajectory none / step / action
--save-uitest-raw / --no-save-uitest-raw 在 trajectory 目录额外落 uitest_raw/{idx:04d}.{json,png}(原始 uitest 树 + 无标注截图)。默认关闭。
--debug 开启调试日志

退出码:成功 0,失败 1

5.1 run 的输出件

save_trajectorynone 时,在 logging.trajectory_path(默认 trajectories/,相对当前工作目录)下生成:

trajectories/
└── <YYYYMMDD_HHMMSS>_<uuid8>/
    ├── trace.jsonl              # 完整轨迹事件流(含设备 I/O,按行 JSON)
    ├── meta.json                # 本次运行摘要:目标、耗时、token 统计、环境信息
    ├── device_state/            # 每步模型看到的设备状态文本(0000.txt …)
    ├── screenshots/
    │   ├── 0000.jpeg            # 截图帧(每步一张)
    │   └── recording.mp4        # 屏幕录像(screen_recording=true 时)
    ├── log/                     # 每次 LLM 调用的 JSON 日志(logging.debug=true 时)
    └── report.html              # 自包含 HTML 查看器;浏览器直接打开即可回放

推荐用 harmonyrun view <轨迹目录> 打开报告;也可直接在文件管理器双击 report.html(本地 file:// 即可,无需起 server)。


6. test:批量执行测试套件

python3 -m harmonyrun test /路径/套件.json
python3 -m harmonyrun test --help
  • 套件为 JSON 格式,需符合 HarmonyRun 测试套件约定(schema 见 src/harmonyrun/batch/schemas/test_suite.schema.json)。
  • --case <ID>:只执行指定用例。
  • --level L0|L1|L2:按优先级筛选(L0 仅最高优先级;L1 = L0+L1L2 = 全部)。
  • -d <设备> 可重复:多台设备组成池,用例自动分配到空闲设备。
  • --save-trajectory none|step|action:覆盖 config.yamllogging.save_trajectory;不传时默认 step(即便 config.yaml 写的是 nonetest 也会自动开到 step,否则没法出报告)。
  • -c, --config <路径>:指定配置文件。

Suite 级覆盖默认显示姿态

要让某个套件里所有 case 都在固定的横竖屏 / 内外屏下启动,在 suite JSON 顶层加一个 defaults.config_overrides 即可。每个 case setup 阶段会在 stop_app 之后、start_app 之前自动切到目标姿态,失败采 best-effort(warn + 继续):

{
  "suite": { "id": "video_landscape", "name": "Video landscape suite", "app_package": "com.example.video" },
  "defaults": {
    "config_overrides": {
      "orientation": "landscape",
      "fold_display": "expanded"
    }
  },
  "test_cases": [ /* ... */ ]
}
  • orientationportrait / landscape / portrait_inverted / landscape_inverted
  • fold_displayexpanded(内屏 / 展开) / folded(外屏 / 折叠);非折叠屏设备会自动跳过并 warn
  • 不写 = 不强制(保持设备当前姿态);同名字段在 config.yamldevice 节也可写作全局兜底

6.1 test 的输出件

每次运行会在 logging.trajectory_path 下生成一个两层的套件目录:先按 suite_id 分目录,再每次跑出一个带时间戳的子目录:

trajectories/
└── <suite_id>/
    └── test_YYYYMMDD_HHMMSS_<uuid8>/
        ├── meta.json                 # 套件 meta(schema_version / status / 设备 / 用例计划),运行中持续刷新
        ├── report.json               # 机器可读总报告(符合 report.schema.json)
        ├── report.html               # 自包含 HTML 查看器(双击即可看,无需起 server)
        └── cases/
            └── <case_id>/            # 注意:case 子目录**不带时间戳**(与单跑 run 不同)
                ├── trace.jsonl
                ├── meta.json
                ├── device_state/
                ├── log/              # 每次 LLM 调用的 JSON 日志(logging.debug=true 时)
                ├── screenshots/
                │   ├── 0000.jpeg
                │   └── recording.mp4 # screen_recording=true 时
                └── report.html       # 单个 case 的 HTML 查看器

旧版本曾产出 report.md,已下线 —— HTML 是唯一可视化入口。HTML 在 case 跑完后即时刷新,可以一边跑一边看进度。 推荐用 harmonyrun view <套件目录> 打开报告(详见 §11)。


7. doctor:环境与设备健康检查

python3 -m harmonyrun doctor              # 检查当前环境 + 自动选第一台设备
python3 -m harmonyrun doctor -d <serial>  # 指定设备
python3 -m harmonyrun doctor --debug      # 打印每项检查的 detail 行

参数:

选项 含义
-d, --device <serial> 指定要诊断的设备;省略时使用 config.yaml 里的 device.serial,再不行就 hdc 第一台
--debug / --no-debug 每项检查额外打印一行 detail(hdc 路径、版本、SDK env 命中、socket 端口等)

7.1 检查项一览

doctor 按顺序跑下面这些检查,前一项致命失败时跳过后续步骤,并在最后汇总 fail / warn 数量。

检查内容 失败影响
SDK Version 当前 harmonyrun 版本 vs GitHub release latest warn 提示升级
Config 读取 ~/.config/harmonyrun/config.yaml,缺则按默认模板创建 fail 阻断后续
Platform 报告 device.platform(HarmonyOS 是唯一允许值)及 serial(auto / 显式) fail 阻断
Harmony Env 探测 HARMONYRUN_HDC_PATH / HDCUTILS_HDC_PATH / OHOS_SDK_HOME / HARMONYOS_SDK_HOME / DEVECO_SDK_HOME / HARMONY_HOME~/Library/Huawei/Sdk / ~/Library/OpenHarmony/Sdk 等常见路径;任一命中则 pass warn 提示 SDK env 缺失
HDC hdc 可执行 + 能 list targets fail 时跳过所有设备相关检查
Device 通过 hdc 连上目标设备并拿到 state=device fail 时跳过其后
Shell 设备 shell 通:date 命令能回数据 fail 表示 hdc 转发坏掉
Device Env 设备 const.product.os.dist.version / apiversion / software.version / hardwareversion / getenforce / 时间 任一缺值 warn
uitest 设备上的 uitest 版本号能读出来 fail 阻断后续 UI 类检查
uitest agent 比对设备已装的 agent.so 与本机 SDK 期望版本(按 uitest version + arch 选):缺则 warn(socket 时会自动装),版本低于期望也 warn warn
Socket 端到端跑通 socket 链路:agent.so → daemon → hdc fport → TCP → Hypium RPC,并打印 tcp:<local>->{remote_spec} 与当前 rotation。失败采 warn(运行时第一次 dump_layout 失败会粘性熔断 socket 并回退到 shell uitest dumpLayout) warn 时附上 scripts/diagnose_uitest_socket.py 的诊断命令
Screenshot 通过当前 backend 截一张 PNG,输出文件大小 fail 表示截图链路异常
UI Tree uitest dumpLayout 拿到 JSON,统计节点数 fail 表示布局抓取异常

7.2 输出示例

HarmonyRun Doctor (HarmonyOS)

  SDK Version            0.5.3 (up to date)                         ✓
  Config                 ~/.config/harmonyrun/config.yaml           ✓
  Platform               harmony                                     ✓
  Harmony Env            SDK env detected                            ✓
  HDC                    found, 1 device(s)                          ✓
  Device                 22M0224104000249 (state=device)             ✓
  Shell                  Sat May 17 10:23:11 CST 2026                ✓
  Device Env             os=5.1.0, api=18, selinux=Enforcing         ✓
  uitest                 v5.0.7.200                                  ✓
  uitest agent           v5.0.7.200                                  ✓
  Socket                 tcp:48721 -> localabstract:uitest_socket, rotation=0  ✓
  Screenshot             ok (482 KB)                                 ✓
  UI Tree                312 nodes                                   ✓

  All checks passed.

任何 fail / warn 会在结尾按状态分组汇总,并附上 detail 字段(如 pip install --upgrade harmonyrun / scripts/diagnose_uitest_socket.py 等可直接复制粘贴的下一步)。


8. mcp:把原子能力开放给外部 Agent

mcp 子命令以 Model Context Protocol 暴露 HarmonyRun 的原子能力(设备发现、UI 感知、点击/滑动等),任意 MCP-aware 客户端(Claude Code / Cursor / Cline / 自研业务 Agent)都能驱动一台 HarmonyOS 真机。

核心承诺:atomic 模式——MCP server 自身不加载任何 LLM、不消费 llm_profiles、缺 OPENAI_API_KEY 也能起。每一步动作由外层 Agent 决策;HarmonyRun 只负责把原子能力封装好。"一句话甩任务"的黑盒用法继续走 harmonyrun run CLI。

8.1 启动 server

python3 -m harmonyrun mcp serve                          # stdio(IDE 集成默认)
python3 -m harmonyrun mcp serve --transport sse          # SSE(本地 HTTP)
python3 -m harmonyrun mcp serve --transport streamable-http
python3 -m harmonyrun mcp serve -c /path/to/config.yaml  # 指定配置(可选)
python3 -m harmonyrun mcp serve --debug                  # 详细日志(stdio 模式日志走 stderr)

参数:

选项 含义
--transport <stdio|sse|streamable-http> 传输层;默认 stdio,本地 IDE 集成用它即可
-c, --config <路径> 指定 config.yaml;缺省时用 ~/.config/harmonyrun/config.yaml配置不存在也能正常起(atomic 模式无 LLM 依赖)
--debug / --no-debug 详细日志

8.2 IDE 集成示例(Claude Code / Cursor / Cline)

// ~/.claude.json 或对应 IDE 的 MCP 配置
{
  "mcpServers": {
    "harmony": {
      "command": "harmonyrun",
      "args": ["mcp", "serve"]
    }
  }
}

加完之后,IDE 里的编码 Agent 就能直接调用 list_devices / connect_device / get_ui_state / tap_element 等工具。

8.3 暴露的 Tools

每个 session 内只能持有一台活跃设备;切设备就先 disconnect 再 connect。

连接(connection)

Tool 作用
list_devices() 列出 hdc 看得到的所有设备(serial + state)
connect_device(serial?) 连接到指定设备;省略 serial 时自动选第一台在线设备。会替换本 session 已有的活跃设备
disconnect_device() 释放活跃设备的所有资源(uitest daemon / hilog monitor / fport 转发)

感知(perception)

Tool 作用
get_ui_state() 一次取回带索引的元素列表、a11y 文本、前台 app 元信息(bundle / ability / page)、屏幕尺寸、page_signature(页面指纹,可用于判跳转)
get_screenshot(annotated=true) PNG 截图;annotated=true(默认值跟 mcp.screenshot_default_annotated 一致)会在交互元素上画 SoM 索引标签,配合 tap_element(index)
get_recent_events() 拉取上次调用以来产生的 toast / dialog / popup 出现-消失事件,用来判断动作的副作用。环形缓冲上限由 mcp.event_buffer_size 控制

动作(actions)

Tool 作用
tap(x, y) 设备坐标点击
tap_element(index) get_ui_state() 给出的索引点击(推荐,跨分辨率稳)
swipe(x1, y1, x2, y2, duration_ms=1000, fast=false) 滑动;fast=true 走 fling 路径(滚动惯性)
long_press(x, y) 长按
input_text(text, element_index?, clear=false) 文本输入;可选先 tap 一个 element 聚焦,可选清空旧内容
press_key(keycode) 发原始 keycode(对应 @ohos.multimodalInput.keyCode
back() / home() 系统返回 / Home
system_button(button) back / home / menu / power / volume_up / volume_down 命名按键
set_rotation(orientation) portrait / landscape / portrait_inverted / landscape_inverted
set_fold_display(expanded) 折叠屏切换;非折叠设备调用会 ok=false 并返回原因,不会假装成功
open_app(bundle) 按 bundleName 启动 app;仅当 mcp.expose_open_app=true(默认)时注册

8.4 暴露的 Resources

get_ui_state / get_screenshot / get_recent_events 同时以 MCP resource 形式暴露,方便客户端用 resource 订阅而不是每次主动调 tool:

URI MIME 内容
harmony://device/state application/json 当前 UIState 的 JSON 表示(与 get_ui_state 同结构)
harmony://device/screenshot image/jpeg 原始 JPEG 截图(无标注)
harmony://device/screenshot-annotated image/jpeg 带元素索引标注的 JPEG 截图
harmony://device/events application/json 最近 drain 的事件 JSON 数组

8.5 配置项(config.yamlmcp.*

字段 默认 含义
mcp.event_buffer_size 50 get_recent_events 一次最多返回多少条事件
mcp.screenshot_default_annotated true get_screenshot 默认是否带标注
mcp.expose_open_app true 是否注册 open_app 工具(关掉可避免给外层 Agent 直接拉应用的能力)

8.6 mcp doctor:上线前体检

把 server 暴露给 IDE 之前先跑一次:

python3 -m harmonyrun mcp doctor

按顺序检查:

  1. hdc 是否在 PATH / HARMONYRUN_HDC_PATH
  2. 至少一台 HarmonyOS 设备在线
  3. MCP server 能在 atomic 模式下构建出来(捕获 LLM 配置陷阱、依赖缺失等)

任一不过返回退出码 1;通过会提示 harmonyrun mcp serve 可以起了。


9. farm:远程群控(让无真机的 CI 也能跑)

服务端编译流水线(Linux CI、Docker、远程 K8s)通常无法连接真机。farm 子命令组让一台有真机的机器(本地电脑或机房)启动一个 HTTPS 服务端,把连着的真机当成"远程驱动池"——任意可以访问该 endpoint 的客户端都能用 harmonyrun farm run 像本地一样跑 LLM agent。

v1 设计取舍:1 人 1 farm(单 token);不带视频流(agent 只要截图 + a11y);网络可达性用户自备(Tailscale / FRP / Cloudflare Tunnel);保持独立模块,不耦合现有 run / test 命令。

9.1 host 端(接真机的那台)

# 启动 farm server,监听局域网 8080
harmonyrun farm serve --bind 0.0.0.0:8080 --token <YOUR_TOKEN>

# 限定只把指定设备纳入设备池
harmonyrun farm serve --bind 0.0.0.0:8080 --token <T> -d SERIAL1 -d SERIAL2

# 调整 lease TTL(默认 1800s)
harmonyrun farm serve --token <T> --lease-ttl 600

参数:

参数 含义
--bind HOST:PORT 监听地址,默认 127.0.0.1:8080;要给远端访问就改 0.0.0.0:8080
--token T Bearer token,客户端必须带 Authorization: Bearer T
--max-devices N 限制设备池最多收 N 台(按 hdc list 顺序截取)
-d / --device SERIAL 显式指定要纳入设备池的设备 serial(可重复)
--lease-ttl SEC 默认租约 TTL(秒),客户端心跳掉线后会被回收
--archive-raw 服务端逐 session 归档 raw uitest 树 + 无标注截图<archive-dir>/<sid>/uitest_raw/(离线复现用)。留在 server 侧,不回传 client;client 的 --save-uitest-raw 在 farm 模式下被强制关闭并改由本开关承担
--record-screen 服务端逐 session 录 MP4<archive-dir>/<sid>/recording.mp4(设备→server 本地 pull,不过网)
--archive-dir DIR 上述归档根目录,默认 farm_trajectories
--debug 开 uvicorn debug 日志

启动后:

trace 分侧:farm 下 agent trajectory(trace.jsonl / 截图 / device_state / LLM 日志)落在 client 本地 trajectories/<id>/;重原始产物(raw uitest / 录屏 MP4)由 --archive-raw / --record-screen 落在 serverfarm_trajectories/<sid>/不过网。设备侧 hilog 事件(toast/dialog)由 server 自动起 monitor、搭车感知响应回传 client。

9.2 client 端(CI / 无真机机器)

# 单次 NL 命令
harmonyrun farm run "打开设置并点击 wifi" \
  --remote https://farm.lan:8080 --token <YOUR_TOKEN>

# 指定要租的设备
harmonyrun farm run "..." --remote ... --token ... --device SERIAL1

# 通过环境变量配置(写到 .env 也行)
export HARMONYRUN_FARM_URL=https://farm.lan:8080
export HARMONYRUN_FARM_TOKEN=<T>
harmonyrun farm run "打开设置"

farm run 与本地 harmonyrun run 行为对齐:跑完整 HarmonyAgent loop,agent trajectory 写在 CI 本地 trajectories/<id>/,区别仅在于底层 driver 是 RemoteDriver(每次原子动作走一次 HTTPS)。感知每步只走 1 次 GET /state 往返(树+截图+hilog 事件一次拿全),不是分开的 screenshot+ui_tree 两次。

辅助子命令:

harmonyrun farm devices --remote URL --token T                    # 列远端设备池
harmonyrun farm doctor  --remote URL --token T [--device SERIAL]  # 端到端 ping(lease + screenshot + ui_tree 延迟,可指定 serial)

9.3 网络方案建议

HarmonyRun 故意不内置反向隧道。建议:

  • 同一办公网:farm 直接 --bind 0.0.0.0:8080,CI 用内网 IP
  • 跨网络:Tailscale / Cloudflare Tunnel / FRP 把 farm 的 HTTPS 暴露为可达 endpoint
  • 生产环境:在 farm 前挡一层 nginx/Caddy,由它做 TLS 证书 + IP 白名单

token 单值,日志里 Bearer ... 自动 mask 成 ***。不要把 token 提交到 git。

9.4 不在 v1 范围

  • 多租户 / 配额 / 计费
  • 视频流 / WebRTC / 浏览器接管(LLM agent 不需要)
  • 内置反向隧道(用户自备)
  • harmonyrun farm test <suite>(套件运行需要复用 batch 流水线,留作 v1.1)
  • hilog 事件流实时透传(v1 客户端 drain_device_events() 返回 [],v1.1 走 WebSocket)

9.5 环境变量

变量 作用
HARMONYRUN_FARM_URL 远端 farm endpoint,CLI --remote 的兜底
HARMONYRUN_FARM_TOKEN Bearer token,CLI --token 的兜底
HARMONYRUN_FARM_DEVICE 默认 lease 的设备 serial(可选)

10. feedback:一键提交测试反馈到 GitHub issue

测试人员跑用例发现问题后,harmonyrun feedback 一条命令完成:

  • 找到本次(或指定的)trajectory 目录
  • meta.json 预填 issue 正文(任务目标、设备、模型、设备操作统计)
  • 自动把 console.log 末尾 200 行贴进正文(测试通常先在终端看到异常)
  • 把 trajectory 打成 zip 上传到专用 drop-repo 的 release(默认 HarmonyOS-AI/HarmonyRun-Feedback,剔除录屏 mp4;见 §10.2
  • 通过 gh CLI 创建 issue 并打 label test-feedback bug severity:<level> (这些 label 只是元数据;当前账号若无权限打 label,会自动降级为无 label 重试,保证 issue 仍能建出来)。.github/workflows/claude-on-feedback.yml任何新建 issue 都触发 Claude Code 自动分析——不再依赖任何 label (私有仓,能开 issue 的都是内部人员,刻意降低门槛)
  • 自动打开浏览器跳到 issue 页让测试人员补充
# 自动用 trajectories/ 下最新一个
harmonyrun feedback

# 指定 trajectory 目录
harmonyrun feedback ./trajectories/20260526_142319_a8f4b2c1

# 不带 trajectory 附件,只创建 issue
harmonyrun feedback --no-attach

# 把 screen recording mp4 也带上
harmonyrun feedback --include-recording

# 演练模式:打印将执行的 gh 命令,但不真发
harmonyrun feedback --dry-run

# 显式调严重程度(low / medium / high;默认 medium)
harmonyrun feedback --severity high

10.1 前置条件

  1. 安装 ghhttps://cli.github.com/,然后 gh auth login

    • 没装 gh 时命令仍可跑,但会回退到"浏览器打开预填表单",trajectory zip 留在 CWD,需要手动拖到 issue 评论里。
  2. 仓库管理员把 OAuth token 配进 GitHub Secrets:

    # 本地一次性生成
    claude setup-token
    # 把输出粘到 repo Settings → Secrets → Actions:
    #   CLAUDE_CODE_OAUTH_TOKEN = <token>
    

    之后每次 Action 触发都从 Pro/Max 订阅扣额度,不走 Anthropic API key

10.2 仓库落点与 drop-repo 模型

issue 和 trajectory zip 落在两个不同的仓

内容 落点 默认值 env 覆盖
issue(正文 + label + Claude 评论) 主代码仓 HarmonyOS-AI/HarmonyRun HARMONYRUN_GITHUB_REPO
trajectory zip(release asset) 专用 drop-repo HarmonyOS-AI/HarmonyRun-Feedback HARMONYRUN_FEEDBACK_STORAGE_REPO

issue 仓 CLI 优先级:HARMONYRUN_GITHUB_REPO > gh repo view > git remote get-url origin > 默认值。zip 仓优先级:HARMONYRUN_FEEDBACK_STORAGE_REPO > 默认值。

为什么分两个仓:主仓是 private,测试人员通常只有最基本权限 —— 但「创建 release」需要 Write、「打 label」需要 Triage。把 zip 落到一个专用 drop-repo,就能给测试人员只对 drop-repo 授 Write、对主仓授 Triage:既能传 trajectory、又能触发 Claude,却碰不到主仓代码。数据全程留在 GitHub private,不外泄第三方。

release 用 published(非 draft):drop-repo 本身 private,published 不会对外公开;但 workflow 用的跨仓只读 token 看不到 draft,所以必须 published。

一次性配置(仓库管理员)

  1. 建 private drop-repo HarmonyOS-AI/HarmonyRun-Feedback(带 README,保证有初始 commit,否则建不出 release tag)。
  2. 建 team,对主仓授 Triage、对 drop-repo 授 Write,把测试人员加进去。
  3. 建 fine-grained PAT(只勾 drop-repo 的 Contents: Read-only),存进主仓 secret FEEDBACK_REPO_TOKEN —— claude-on-feedback.yml 用它跨仓下载 zip。
  4. 主仓另需 CLAUDE_CODE_OAUTH_TOKEN(见 §10.1)。

fork 用户:把上面两个 env 一起改成自己的仓即可。

10.3 HTML 报告里的"📮 提交反馈"按钮

每个 case 的 report.html(CLI 跑完后写在 trajectory 目录下)右上角带这个 按钮。点击会弹出 modal 给出两条路径:

  • 复制 harmonyrun feedback <path> 命令(推荐——完整 trace 上传 + 触发 Claude)
  • 直接打开 GitHub 预填表单(兜底——没装 gh / 不在跑测试的机器上)

URL 预填使用 GitHub form 的 query param 协议,没有 trajectory 附件; 测试人员可在浏览器手工拖入 zip。


11. memory:跨执行记忆与 app 卡片学习

当前状态:L0 自动记忆(写入/召回)已可用;harmonyrun memory 子命令(L1 候选生成/审阅/promote)的 CLI 入口暂未开放,代码已就位,后续合入时放开。

HarmonyRun 可以把一次执行学到的经验沉淀下来,下次跑同一任务时召回,注入到 system prompt 帮助模型少走弯路。能力分两层:

  • L0(per-case 记忆,自动):任务结束时把本次执行(指令 + 成败 + 失败信号 + 探索轨迹)蒸馏成一条「带结果标签的证据」笔记,按任务 key 存到 ~/.config/harmonyrun/memory/cases/。batch 用例用 test_case.id 作 key(仅 test_execution 阶段写,precondition/postcondition 不写);单跑用指令的归一化哈希作 key。下次同任务开局自动召回 top-N 注入。
  • L1(per-app 卡片,人工 review):把多个用例的 L0 记忆按 app 聚合,蒸馏成「候选 app 卡片知识」,经人工 review 后 promote 进 app_cards,走现有 app 卡片召回路径。

默认关闭,opt-in:在 config.yamlagent.memory.enabled: true(CLI override key 为 memory_enabled)才启用;agent.memory.top_n(override key memory_top_n,默认 5)控制召回条数。关闭时 system prompt 与改动前字节一致,不影响 prompt-cache。记忆始终以「历史证据,当前屏幕才是 ground truth」的口径注入,不会被当成指令盲从。蒸馏走可选的 summarizer LLM profile,缺失时回退到已加载的 agent LLM。

子命令 作用
harmonyrun memory generate-candidates [--app PKG] [--min-cases N] 聚合 L0 记忆,按 app 蒸馏候选卡片。--app 只处理指定包名;--min-cases 跳过记录数不足 N 的 app(默认 1)。
harmonyrun memory list 列出待 review 的候选卡片(app + 来源用例数 + 预览)。
harmonyrun memory promote <PKG> [--overwrite] 把候选卡片写入 app_cards。默认拒绝覆盖人工已有卡片;--overwrite 显式替换。
harmonyrun memory forget <KEY> 删除某任务累积的记忆(清理已知带毒的 key)。

所有子命令支持 --config <path> 指定 config.yaml


12. view:查看测试报告

harmonyrun view 接受任意层级的 trajectory 目录,自动识别类型(单 case / 套件),用当前包内最新模板重新渲染 HTML 后在系统默认浏览器中打开。

# 自动找 ./trajectories/ 下最近一次运行
harmonyrun view

# 直接打开某次 run 的单 case 报告
harmonyrun view trajectories/20260528_142319_a8f4b2c1/

# 打开某次 test 的套件报告
harmonyrun view trajectories/MySuite/test_20260528_a8f4b2c1/

# 传 suite 根目录,自动选最近一次运行
harmonyrun view trajectories/MySuite/

# 传根目录,自动选最近一次(run 或 test 均可)
harmonyrun view trajectories/

目录类型自动识别规则:

目录内容 识别结果
trace.jsonl 单 case 轨迹 → 渲染 case 报告
report.json(无 trace.jsonl 套件运行目录 → 渲染套件报告
两者均无 向下最多两层搜索,取最近修改的轨迹

设计说明:

  • HTML 模板只存在于包内,不随 trajectory 数据一起分发。每次 view 都用当前安装版本的模板重新渲染,升级工具后旧 trajectory 也能得到新版查看器。
  • trajectory 格式当前为 1.0(定义在 src/harmonyrun/traces/format.py),后续出现不兼容变更时会 bump 版本号并在 view 输出中提示。
  • case 详情页与套件报告右上角均有「📁 打开目录」按钮:点击在系统文件管理器(Finder / 资源管理器 / xdg-open)中打开对应的本地目录(case 详情页打开该轨迹目录,套件报告打开套件根目录),快速查看原始文件(trace.jsonl / meta.json / log/*.json / 截图 / report.json)。走本地服务的 /__open__ 端点(前端发页面自身相对目录、服务端经 _resolve_open_target 校验在目录内后调系统命令打开),仅在 view 服务下显示;直接 file:// 双击离线打开时自动隐藏。

13. hypium:把跑通的用例转成 Hypium 回归脚本

harmonyrun hypium generate 读取一次 test 套件运行的 trajectory,把成功的用例转换成可独立执行的 Hypium(HarmonyOS 官方 UI 测试框架)Python 工程——录制一次,之后回放零模型成本,用于版本间的质量看护;版本更新导致回放失败时,再回到 agent 重新录制。

# 从套件运行目录生成 Hypium 工程(默认输出到 <目录>/hypium_project/)
harmonyrun hypium generate trajectories/MySuite/test_20260705_130321_d9aea6b3/

# 只转换指定用例(显式点名可覆盖"跳过失败用例"的默认行为)
harmonyrun hypium generate <套件目录> --case tc_001

# 指定输出目录 / 不生成 TestSuite 汇总文件
harmonyrun hypium generate <套件目录> -o ./my_hypium --no-suite

# 执行生成的工程(需要 pip install hypium)
harmonyrun hypium run <工程目录> [--case tc_001] [-d <serial>]

转换规则:

环节 机制 是否用 LLM
元素定位 记录时每步落盘 ui_states/*.json 结构化快照,坐标反解为稳定选择器,优先级 BY.key(resourceId) > BY.text(text) > BY.type(...).isAfter(BY.text(锚点)) > 比例坐标兜底
动作映射 trace.jsonlDeviceActionEvent(tap/swipe/input_text/press_key/start_app/…)→ Hypium API;batch 的 setup+preconditions → setup(),test_execution → process(),postconditions+teardown → teardown()
断言生成 expected_result + 执行段前后 UI diff 生成 check_component_exist 等断言 可选(生成时一次;无 LLM 时走规则)
代码润色 Step 注释、合并冗余滑动、断言归位 可选(生成时一次)
回放 官方 hypium runner 独立执行

注意:

  • 默认只转换 success=true 的用例——失败运行的动作序列不构成值得回放的质量基线;--case 显式点名可强制转换(用于排查)。
  • 旧版 trajectory(无 ui_states/ 目录)自动降级为比例坐标回放,仍可执行但选择器稳定性差;用当前版本重跑一次套件即可获得语义选择器。
  • LLM 断言/润色使用 llm_profiles 里的 hypium profile(缺省回落 fast_agent);两者都是生成时一次性调用,生成产物的回放不消耗任何模型资源。
  • 回放失败有两种含义:UI 合法变化(选择器/断言过时,应重新录制)或真实回归(App bug)。不要把失败无脑自动重录,先人工确认属于哪一种。

14. 常见问题

  1. harmonyrun / python3 -m harmonyrun 找不到 请确认使用的是安装了 wheel 的那个 Python。未激活虚拟环境时,使用 .venv/bin/python3 -m harmonyrun
  2. ModuleNotFoundError: langchain_google_genai 等可选 provider 依赖 Google Gemini / Ollama 等 provider 需要额外安装:pip install 'harmonyrun[google]' / 'harmonyrun[ollama]' / 'harmonyrun[all]';OpenAI / Anthropic 内置,无需额外装。
  3. 401 / 403 / 模型不可用 检查用户配置目录下的 .env(路径见 4.2)中密钥是否有效;并确认 llm_profilesprovidermodel 与该密钥匹配。
  4. 找不到设备 先执行 hdc list targets 确认设备可见,再 harmonyrun devices;必要时 harmonyrun doctor 进一步诊断。
  5. 运行时报 uitest 相关错误 Layout 取数路径已无 ui_backend 开关:socket 优先,失败一次就粘性熔断回 shell uitest dumpLayout。先跑 harmonyrun doctor 诊断;socket 失败可参考其建议执行 scripts/diagnose_uitest_socket.py
  6. hypium run 失败 单独安装 Hypium 相关依赖与 CLI,确保 python -m hypium 等命令可用。

Download files

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

Source Distribution

harmonyrun-0.4.10.tar.gz (4.2 MB view details)

Uploaded Source

Built Distribution

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

harmonyrun-0.4.10-py3-none-any.whl (1.8 MB view details)

Uploaded Python 3

File details

Details for the file harmonyrun-0.4.10.tar.gz.

File metadata

  • Download URL: harmonyrun-0.4.10.tar.gz
  • Upload date:
  • Size: 4.2 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.11.15

File hashes

Hashes for harmonyrun-0.4.10.tar.gz
Algorithm Hash digest
SHA256 c5ce9fe8210a5bdad2fa65d76d81238fca50905074b500e7a4e018f20bc76a12
MD5 64b04c8b7ec99bd00e3d1616d4a2dec4
BLAKE2b-256 cd70c2625e1d979b6c9e3ee83ec99f4cfc8ec2cfced1ee19649b24061acc29d1

See more details on using hashes here.

File details

Details for the file harmonyrun-0.4.10-py3-none-any.whl.

File metadata

  • Download URL: harmonyrun-0.4.10-py3-none-any.whl
  • Upload date:
  • Size: 1.8 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.11.15

File hashes

Hashes for harmonyrun-0.4.10-py3-none-any.whl
Algorithm Hash digest
SHA256 1ec3c053939b9f16d17cce23dec251ea890ce0e2e6009fe32f2d8c7923c254e2
MD5 2f06d40ae46f55895019ab796af9c3b3
BLAKE2b-256 e00e859fd3744a59a80b57169f1d91ee279247f1399ec4b9a29a724cc523d685

See more details on using hashes here.

Supported by

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