← Back

Epson ScanSmart CLI

Live

Signature capability

It gives a headless CLI to an app Epson never shipped a CLI for, by driving the live macOS accessibility UI tree with cliclick and AppleScript, hardened against AppleScript injection through user-supplied printer and path strings.

What it is

ScanSmart has no command-line interface, so the tool automates the real GUI: it launches the app, walks the scan → photo-edit → Next → Save flow by inspecting the live accessibility window tree and issuing real CGEvent clicks via cliclick (System Events' synthetic clicks don't activate ScanSmart's image tiles). Once a file lands on disk it hands printing off to CUPS via `lp -d <queue> -n <copies>`, sidestepping ScanSmart's fragile in-app Print Settings UI entirely. Every user-controlled string interpolated into AppleScript is escaped first to block shell/AppleScript injection, and a Preflight/`doctor` command checks cliclick, the app install, and Accessibility permission in one shot. It ships with a `--json` mode so an agent or cron job can drive it. The README is refreshingly honest that this is GUI automation, English-locale-only, and can break when Epson reships the app.

Highlights

  • 841-line automation backend plus a 346-line Click CLI, covered by 61 tests (46 backend, 15 CLI)
  • Hardened against AppleScript injection: all user strings (printer labels, file paths) pass through an escape_as() guard, added after a Codex adversarial review pass
  • Detects the scan Progress window via Quartz and retries on System Events -1728 process drops, the flaky failure modes of real UI automation
  • doctor/Preflight command fails fast with actionable hints if cliclick, ScanSmart, or Accessibility permission are missing
  • Packaged for PyPI as epson-scansmart-cli v0.1.0 with GitHub Actions CI, only one runtime dependency (click)
  • --json output mode makes it consumable by AI agents, cron jobs, and scripts, not just humans

Tech · Python 3.10+, Click, AppleScript/osascript, cliclick, macOS Accessibility API, Quartz, CUPS/lp, pytest, GitHub Actions