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

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.1
File Size Uploaded
smithy_py-0.1.1.tar.gz 41.7 kB Details

Built distribution (wheel)

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

Total release size: 84.5 kB

Release files / smithy_py-0.1.1.tar.gz

Download URL smithy_py-0.1.1.tar.gz
Size 41.7 kB
Tags Source
SHA-256 checksum
How to use checksums
6f9090f592071f334a0bcd14167d49f63a65e06034f4c1607cad0a2d74851109
BLAKE2b-256 checksum
How to use checksums
9b9d43ce29d37a1d467ccda726b36381d7a4a218f0ae841c2567ef91a0d69d4b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.2

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

Download URL smithy_py-0.1.1-py3-none-any.whl
Size 42.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d5e6535ea4db6a28267f4db7231d60e3aac41074c1e9302cc7700be44c3f8c37
BLAKE2b-256 checksum
How to use checksums
a7b8fa6d63c259d74ef44709ece360186b46d78fbc9c69c79369f22e0b0fd186
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.2

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

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