Skip to main content

Smithy

Free Python RPA engine — create automation bots with simple async API.

Quick Start

import asyncio
from smithy import Smithy
from smithy.windows.tools.process import ProcessTool
from smithy.windows.tools.click import ClickTool
from smithy.windows.tools.wait import WaitTool
from smithy.windows.tools.delay import DelayTool
from smithy.windows.tools.screenshot import ScreenshotTool
from smithy.windows.tools.input_text import InputTextTool
from smithy.windows.tools.keyboard import KeyboardTool
from smithy.windows.tools.set_text import SetTextTool
from smithy.windows.tools.get_element import GetElementTool

bot = Smithy(
    tools=[
        ProcessTool(),
        ClickTool(),
        WaitTool(),
        DelayTool(),
        ScreenshotTool(),
        InputTextTool(),
        KeyboardTool(),
        SetTextTool(),
        GetElementTool(),
    ]
)


async def main() -> None:
    app = await bot.process_run("notepad.exe")
    await bot.wait(app, class_name="Notepad", name="*Notepad")
    await bot.click(app, name="File")
    await bot.delay(duration_ms=300)
    await bot.click(app, name="Save As...")
    await bot.input_text(app, text="hello world")
    await bot.keyboard(keys="[CTRL]S")
    await bot.screenshot("notepad.png")
    await bot.process_stop(app)


asyncio.run(main())

Built-in Tools

  • ProcessTool (windows.process) — launch and stop Windows processes by name
  • ClickTool (windows.click) — click a UI element by selector or context key
  • WaitTool (windows.wait) — poll until a UI element appears (with timeout)
  • DelayTool (windows.delay) — pause execution for a fixed duration
  • ScreenshotTool (windows.screenshot) — capture the screen or a window to a file
  • InputTextTool (windows.input_text) — type plain text into a UI element
  • KeyboardTool (windows.keyboard) — send key combos and presses (e.g. "[CTRL]S", "[CTRL!]", "[ENTER]")
  • SetTextTool (windows.set_text) — replace a UI element's text programmatically (ValuePattern / WM_SETTEXT)
  • GetElementTool (windows.get_element) — read a UI element's attributes as a dict

All UI tools accept optional pid (or a ProcessHandle) to scope element search to a specific window.

Custom Tools

Create tools from simple async functions:

from smithy import Smithy, tool


@tool("greet", description="Greet a person")
async def greet(config: dict) -> dict:
    name = config.get("name", "World")
    return {"message": f"Hello, {name}!"}


bot = Smithy(tools=[greet])


async def main() -> None:
    result = await bot.call("greet", name="Alice")
    print(result["message"])  # Hello, Alice!


asyncio.run(main())

Error Handling

from smithy.core.errors import InvalidInput, ElementNotFound, PlatformError

try:
    await bot.click(app, name="Nonexistent")
except ElementNotFound:
    print("Element not found")
except PlatformError as e:
    print(f"Platform error: {e}")

Selector Capture

A dev utility for inspecting UI elements at screen coordinates and generating tool configs:

pip install smithy[capture]

# Single capture mode
python -m smithy.windows.tools.selector_capture single -o selectors.json

# Series mode — auto-record clicks and typing
python -m smithy.windows.tools.selector_capture series -o recording.json

# Interactive record mode
python -m smithy.windows.tools.selector_capture record -o flow.json

Install

pip install smithy               # core (no deps)
pip install smithy[windows]     # Windows UIA tools
pip install smithy[capture]      # selector capture (pynput + pyperclip)
pip install smithy[all]          # everything
pip install -e ".[dev]"          # development

Development

# Using uv (recommended)
uv venv .venv
.venv\Scripts\activate
uv pip install -e ".[dev,windows,capture]"

# Or with pip
python -m venv .venv
.venv\Scripts\activate
pip install -e ".[dev,windows,capture]"

pytest                    # run tests
ruff check src/ tests/    # linter
mypy src/smithy --strict  # type check

Project Structure

src/smithy/
├── __init__.py          — Public API: Smithy, ProcessHandle, Tool, errors
├── facade.py            — Smithy facade (async tool dispatch)
├── core/
│   ├── tool.py          — Tool protocol, AbstractTool, @tool decorator
│   ├── registry.py      — ToolRegistry (name → tool dispatch)
│   ├── events.py        — EventBus, ToolEvent, Middleware
│   └── errors.py        — Error hierarchy (ToolError, ElementNotFound, etc.)
└── windows/
    ├── element.py       — SafeUIElement (thread-safe COM wrapper)
    ├── selector.py      — ElementSelector (UIA tree search)
    └── tools/
        ├── process.py          — ProcessTool
        ├── click.py            — ClickTool
        ├── wait.py             — WaitTool
        ├── delay.py            — DelayTool
        ├── screenshot.py       — ScreenshotTool
        ├── input_text.py       — InputTextTool
        ├── set_text.py         — SetTextTool
        ├── get_element.py      — GetElementTool
        ├── _resolve.py         — Shared element resolution helper
        └── selector_capture/   — Dev tool for UI inspection

Examples

License

MIT

Metadata

Release files for smithy-py 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for smithy-py 0.1.0
File Size Uploaded
smithy_py-0.1.0.tar.gz 83.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for smithy-py 0.1.0
File Interpreter ABI Platform
smithy_py-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 124.5 kB

Release files / smithy_py-0.1.0.tar.gz

Download URL smithy_py-0.1.0.tar.gz
Size 83.4 kB
Tags Source
SHA-256 checksum
How to use checksums
face361be487799549e023e7d1214f59e6afeaf30f11a3f2561526d4b4fd0ddf
BLAKE2b-256 checksum
How to use checksums
7271ed95816fefa68c19cd34c0521a948227d22eaa73e6987ace13b8df5778c1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.13

Release files / smithy_py-0.1.0-py3-none-any.whl

Download URL smithy_py-0.1.0-py3-none-any.whl
Size 41.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
eb9aef02b4ea2659f362afa64f5a0a00e8498af6a5f2419043915558c5b75672
BLAKE2b-256 checksum
How to use checksums
d6e2c015ce83ed0c4cba2a6235f90415d8ecb3091359e2b609fe9d4c294a344c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.13

Release history Release notifications | RSS feed

0.1.1

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page