mcpbeat Sign in

Gui Agent Skill

Cross-driver GUI actuation for CAE solvers running under sim-cli. Use to click buttons, fill fields, dismiss dialogs, and capture window screenshots against GUI-capable driver windows through `sim exec`.

2k tokens
context cost
the whole folder, loaded on every use
2
files
ships runnable scripts
0
copies elsewhere
how many repositories repackaged it
193
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/svd-ai-lab/sim-cli --skill gui

The instruction itself

17 sections, as written by the author

gui — cross-driver GUI actuation

Whenever the active driver runs with ui_mode=gui (or desktop),

sim serve injects a gui object into your sim exec namespace

alongside session / solver / meshing / model. The object is the

same shape across solvers — only the process filter differs — so one

skill serves every GUI-capable driver.

/connect advertises it:

{
  "ok": true,
  "data": {
    "...": "...",
    "tools": ["gui"],
    "tool_refs": {"gui": "sim-cli/_skills/sim-cli/gui/SKILL.md"}
  }
}

If tools doesn't contain "gui", the driver launched headless and

the object is absent — don't call it.

When to reach for gui

Three scenarios dominate:

  • A blocking dialog is wedging the workflow. A login prompt,

overwrite confirmation, or script-error dialog can pause agent work

until someone clicks a button — that someone is you, via gui.

  • You need to drive the GUI where the SDK can't. Some workflows

expose a UI-only surface that the driver API does not cover.

  • You need a per-window screenshot. sim screenshot captures the

whole desktop. SimWindow.screenshot() captures just the window you

care about — cheaper to read, less visual clutter for the LLM.

If the SDK has a programmatic path (session.tui.*, model.solve(),

ModelUtil.loadCopy()), prefer that. gui is for the UI-only surface

that the SDK doesn't cover.

Remote equivalence

gui is in the session namespace on the sim serve side. You talk to

it via the existing /exec HTTP channel:

# local Windows box
sim exec "dlg = gui.find('Login'); dlg.click('OK')"

# Windows box on the LAN / Tailscale
sim --host 10.0.x.y exec "dlg = gui.find('Login'); dlg.click('OK')"

No new endpoint, no new protocol — the same API shape from anywhere

the agent runs.

Requirement on the server host: sim serve must run in a **real

interactive desktop session** (normal login or RDP). Windows

service / SSH session 0 has no desktop, so pywinauto can't enumerate

any windows even though the solver processes are running. This is the

same constraint GUI-capable drivers document.

API

Discover what the controller is looking at

gui.available          # True iff pywinauto can run — check before driving anything
gui.process_filter     # tuple of process-name substrings this gui will target
gui.list_windows()     # {ok, windows: [{hwnd, pid, proc, title, rect}, ...]}

Find a window (polled until timeout)

dlg = gui.find(title_contains="Login", timeout_s=5)
# returns a SimWindow, or None on timeout

title_contains is a plain substring match (case-sensitive, any language).

Returns None if nothing matched — always check before calling

methods on it:

dlg = gui.find("连接到")
if dlg is None:
    _result = {"ok": False, "error": "login dialog not visible"}
else:
    dlg.click("确定")

Act on a window

Every action returns {ok: bool, ...}. No exceptions unless you pass

invalid Python types — surface ok=False + error to the agent.

dlg.click("OK", timeout_s=5)             # click a button by accessible name
dlg.send_text("alice", into="Username")  # type into a named Edit field
dlg.send_text("/tmp/out.cas.h5")         # without `into` → first editable
dlg.close()                              # WM_CLOSE (Alt+F4 equivalent)
dlg.activate()                           # bring to foreground
dlg.screenshot(label="after_login")      # window-only PNG under workdir

Each action method tries the most natural pywinauto strategy first

(button_by_title) and falls back to a broader match

(any_control_by_title) before giving up — the response tells you

which path worked via the strategy field.

Full UIA dump

Expensive but sometimes necessary for reasoning about an unfamiliar GUI:

state = gui.snapshot(max_depth=3)
# {ok, windows: [{hwnd, pid, proc, title,
#                  controls: [{name, control_type, handle, children?}, ...]}]}

Use this when find(title) misses and you need to see what the GUI

actually exposes.

Handle metadata

SimWindow fields you can read without another round-trip:

dlg.hwnd     # int
dlg.pid      # int
dlg.proc     # str, process name
dlg.title    # current window title
dlg.as_dict() # {hwnd, pid, proc, title, rect}

Typical patterns

Pattern 1 — dismiss a blocking login dialog

dlg = gui.find(title_contains="Login", timeout_s=5)
if dlg:
    dlg.send_text("alice", into="Username")
    dlg.send_text("secret", into="Password")
    dlg.click("OK")
_result = {"dismissed": dlg is not None}

Pattern 2 — confirm a "file exists, overwrite?" dialog

dlg = gui.find(title_contains="Question", timeout_s=3)
if dlg is None:
    dlg = gui.find(title_contains="overwrite", timeout_s=3)  # other
if dlg:
    dlg.click("OK")
_result = {"confirmed": dlg is not None, "title": dlg.title if dlg else None}

Pattern 3 — walk the solver UI tree to find an unexpected control

state = gui.snapshot(max_depth=4)
names = []
def walk(items):
    for c in items:
        if c.get("name"):
            names.append((c["control_type"], c["name"]))
        walk(c.get("children") or [])
for w in state["windows"]:
    walk(w.get("controls") or [])
_result = {"control_names": names[:50]}

Pattern 4 — capture only the solver window for the agent to read

dlg = gui.find(title_contains="Main", timeout_s=3)
if dlg:
    shot = dlg.screenshot(label="after_solve")
    _result = shot  # contains {ok, path, width, height}
else:
    _result = {"ok": False, "error": "main window not found"}

Error handling

Every call returns a dict; failures look like

{"ok": False, "error": "connect(handle=...) failed: ..."}. The UIA

machinery runs in an isolated subprocess so a COM glitch in one call

never poisons the next.

Things that commonly make ok false:

| Symptom | Likely cause | What to do |

|---|---|---|

| find returns None | title didn't match / process filter too strict | print gui.list_windows() to see what is live |

| click says no control titled ... in hwnd=... | the button label in the UI is not what you think | snapshot the window, read controls[*].name |

| screenshot returns minimal PNG | window is minimized (pywinauto captures the window rect; min'd windows live at (-32000, -32000, …)) | dlg.activate() first, then screenshot |

| gui.available is False | off-Windows host, or pywinauto not installed | don't use gui — fall back to SDK-only path |

| list_windows() returns ] even though the solver clearly launched | sim serve was started from an SSH / non-interactive Windows session — the GUI exists in a session with no display surface and pywinauto can't see it | ask the operator to restart sim serve from a desktop session (RDP, Windows Terminal, or Task Scheduler with "run only when user is logged on" + interactive). See [../SKILL.md → "Where sim serve runs". Do not retry. |

| screenshot returns a uniformly black PNG | same as above — non-interactive session has no compositor | same fix |

Pitfalls

  • Don't guess button labels. Windows localisation is real. Use

gui.snapshot() to confirm the actual accessible name before calling

click(name).

  • Don't assume single window. Some solvers open extra floating

panels. find(title) returns the first match; if the workflow is

ambiguous, use list_windows() and pick by pid.

  • Don't rely on gui for SDK-shaped work. Solver objects (session,

model) are always faster and more reliable than UI clicks. gui is

the fallback for the UI-only surface.

  • Remote servers need a real desktop. If sim serve runs from an

SSH session, a Windows service, or any non-interactive context, the

spawned solver process inherits a session with no display surface.

pywinauto then finds zero windows, screenshots come back uniformly

black, and find(...) silently times out — the server itself is up

and reachable, only the GUI half is dead. Restart sim serve from a

desktop session (Windows Terminal on the console, RDP, or Task

Scheduler with "run only when user is logged on" + interactive). See

../SKILL.md → "Where sim serve runs" for the full

driver-by-driver matrix.

  • Plugin-specific skills list the dialogs that a given driver is known

to pop. Check those for recipes before inventing your own.

  • sim.inspect probes (issue #8a window_observed, #8b screenshots)

tell you what is on screen — read them first, then reach for

gui to act.

Other skills for the same job

different authors, same section of the catalogue
Python Executor
by ComeOnOliver
×1

Execute Python code in a safe sandboxed environment via [inference.sh](https://inference.sh). Pre-installed: NumPy, Pandas, Matplotlib, requests, BeautifulSoup, Selenium, Playwright, MoviePy, Pillow, OpenCV, trimesh, and 100+ more libraries. Use for: data processing, web scraping, image manipulation, video creation, 3D model processing, PDF generation, API calls, automation scripts. Triggers: python, execute code, run script, web scraping, data analysis, image processing, video editing, 3D models, automation, pandas, matplotlib

4k tokens
Python Executor
by ComeOnOliver
×1

Execute Python code in a safe sandboxed environment via [inference.sh](https://inference.sh). Pre-installed: NumPy, Pandas, Matplotlib, requests, BeautifulSoup, Selenium, Playwright, MoviePy, Pillow, OpenCV, trimesh, and 100+ more libraries. Use for: data processing, web scraping, image manipulation, video creation, 3D model processing, PDF generation, API calls, automation scripts. Triggers: python, execute code, run script, web scraping, data analysis, image processing, video editing, 3D models, automation, pandas, matplotlib

5k tokens
Upgrade Browser
by flutter
vendor

Upgrade browser versions (Chrome or Firefox) in the Flutter Web Engine and/or Framework tests. Use when asked to roll or upgrade Chrome or Firefox to a newer version.

2k tokens scripts
UI Tests Migration
by microsoft
vendor

Migrate PowerToys module UI tests from the legacy WinAppDriver/Selenium harness (Microsoft.PowerToys.UITest) to the new winappcli-based harness (Microsoft.PowerToys.UITest.Next). Use when asked to port/convert/rewrite/modernize a module's UI tests to the .Next framework, create a new [Module].UITests.Next project alongside existing legacy tests, or stand up brand-new winappcli UI tests for a module that has none by reading its human test sign-off markdown. Covers the API mapping (By/Element/Session/UITestBase, KeyboardHelper/MouseHelper/ClipboardHelper), project/csproj scaffolding, naming rules, common PowerToys test recipes (toggle a module, read an activation shortcut, fire a global hotkey, inspect the clipboard, discover overlay/editor windows), build/run validation, and CI-stability hardening for fewer CI iterations. Keywords: UI test, UITests, UITestAutomation.Next, winappcli, WinAppDriver, Selenium, migrate, port, modernize, .Next, MSTest, CI stability, flaky test, stabilize on CI.

32k tokens
Open Source
by browser-use

> Documentation reference for writing Python code using the browser-use open-source library. Use this skill whenever the user needs help with Agent, Browser, or Tools configuration, is writing code that imports from browser_use, asks about @sandbox deployment, supported LLM models, Actor API, custom tools, lifecycle hooks, MCP server setup, or monitoring/observability with Laminar or OpenLIT. Also trigger for questions about browser-use installation, prompting strategies, or sensitive data handling. Do NOT use this for Cloud API/SDK usage or pricing — use the cloud skill instead. Do NOT use this for directly automating a browser via CLI commands — use the browser-use skill instead.

14k tokens
Vercel Sandbox
by vercel-labs
vendor

Run agent-browser + Chrome inside Vercel Sandbox microVMs for browser automation from any Vercel-deployed app. Use when the user needs browser automation in a Vercel app (Next.js, SvelteKit, Nuxt, Remix, Astro, etc.), wants to run headless Chrome without binary size limits, needs persistent browser sessions across commands, or wants ephemeral isolated browser environments. Triggers include "Vercel Sandbox browser", "microVM Chrome", "agent-browser in sandbox", "browser automation on Vercel", or any task requiring Chrome in a Vercel Sandbox.

2k tokens
Browse
by browserbase
vendor

Use the browse CLI for Browserbase browser automation, Browserbase cloud APIs, Browserbase Functions, templates, web fetch/search, diagnostics, and Browse.sh skill discovery/installation. Use when the user asks to navigate pages, inspect browser state, run local or remote browser sessions, manage Browserbase resources, call Browserbase Functions, browse or scaffold Browserbase templates, fetch or search web content, diagnose browse setup, find or install a skill for a website task, discover site-specific Browse.sh skills, or install/refresh this browse skill.

5k tokens
Dev
by microsoft
vendor

Development workflows for the playwright-cli repository. Use when the user asks about rolling dependencies, releasing, or other repo maintenance tasks.

2k tokens

How to use it

Copy the folder

Take svd-ai-lab/gui from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.