AgentStack
SKILL verified Apache-2.0 Self-run

Gui

skill-svd-ai-lab-sim-cli-gui · by svd-ai-lab

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`.

No reviews yet
0 installs
12 views
0.0% view→install

Install

$ agentstack add skill-svd-ai-lab-sim-cli-gui

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution Used
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README — it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-svd-ai-lab-sim-cli-gui)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming — see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps — measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Gui? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

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:

  1. 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.

  1. 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.

  1. 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"](../SKILL.md). 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"](../SKILL.md) for the full driver-by-driver matrix.

Related skills

  • 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.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.