Plain data types for tools that drive Android and iOS devices: an accessibility-tree node, a
screen snapshot, device identity, and the IDeviceIO protocol a device adapter implements.
Pure dataclasses with no I/O and no dependencies, so an MCP server, a test harness and a
quality checker can share one vocabulary and one compact JSON shape.
nerve uses it.
pip install linc-device-kit # or: uv add linc-device-kitPython 3.12+. No runtime dependencies.
import json
from linc_device_kit import (
DeviceInfo, DeviceType, ElementNode, Platform, Rect, ScreenState, SemanticRole,
)
login = ElementNode(
id="login", text="Sign in", role=SemanticRole.BUTTON,
bounds=Rect(x=40, y=900, width=400, height=96), clickable=True,
)
root = ElementNode(role=SemanticRole.CONTAINER, children=[login])
state = ScreenState(
device=DeviceInfo("emulator-5554", Platform.ANDROID, DeviceType.EMULATOR),
timestamp="2026-10-01T12:00:00Z",
elements=root,
foreground_app="com.example.app",
)
payload = state.to_dict() # compact: fields at their defaults are omitted
print(json.dumps(payload["elements"]))
print(payload["element_count"])
assert ScreenState.from_dict(payload) == state$ python example.py
{"role": "container", "children": [{"id": "login", "text": "Sign in", "role": "button", "bounds": {"x": 40, "y": 900, "width": 400, "height": 96}, "clickable": true}]}
2ElementNode.to_dict() leaves out every field that is at its default, which keeps an
accessibility tree small enough to hand to an AI agent. from_dict restores the defaults, so
from_dict(to_dict(x)) == x. ScreenState.to_dict() never includes the screenshot bytes.
| Type | What it holds |
|---|---|
ElementNode |
One accessibility-tree node: id, text, description, value, role, bounds, clickable/enabled/focused/scrollable/checked, children |
ScreenState |
A screen at a point in time: device, ISO 8601 timestamp, element tree, optional screenshot bytes, foreground app, screen name; element_count is computed from the tree |
DeviceInfo |
Serial, platform, device type, model, OS version |
Rect |
Axis-aligned bounds: x, y, width, height |
Platform, DeviceType, SemanticRole |
StrEnums, so they serialise as plain strings |
IDeviceIO |
@runtime_checkable protocol: screenshot, elements, foreground_app, logs, tap, swipe, type_text, press_key, install, launch, kill, clear_app_data, grant_permission, forward_debug_port, list_debug_targets, capabilities |
DeviceKitError |
Base of the exception hierarchy (DeviceNotReachable, DeviceNotConfigured, InstallFailed, BuildFailed, SigningError, WDAStartupFailed, QualityGateFailed) |
uv sync --all-extras
uv run pytestThis is a release mirror of a private LINC repository. The code is built by LINC's AI software factory under human review, and each release lands here as one commit. Issues are welcome; see CONTRIBUTING.md. To report a security problem, see SECURITY.md.
Apache-2.0. See LICENSE and NOTICE.
Built by LINC Innovations. We diagnose flaky device test suites.