Skip to main content
Glama

Digitomancy

Divination by fingers. Android automation for people and agents: read the screen, tap and type, remember buttons as named anchors, check where you are with checkpoints, and run multi-step routines that resume after a failure. Works with a USB phone, an emulator or BlueStacks, from a CLI, from Python, or from Claude as an MCP server and plugin.

Status: early but working. Tested on a Pixel 9 (Android 16) plus unit tests against a fake device. The Tasker bridge has unit tests but hasn't yet been verified end to end on a device.

Why not just use X

Tool

Good for

Why it isn't the whole answer

mobile-mcp

Ad-hoc agent poking via the accessibility tree

No memory: every session finds the same buttons again

droidrun

A full LLM agent framework

Heavy and opinionated if you already have agents

uiautomator2

Fast Android-only driver, no Appium server

Digitomancy builds on this

Appium

Cross-platform QA

Needs a server; overkill for Android-only

scrcpy

Mirroring the screen

Use dgm mirror to watch automation live

What Digitomancy adds: named devices, anchor maps (selector first, normalized coordinates as fallback), checkpoints with failure snapshots, resumable routines, and a Tasker bridge. What an agent finds once gets written down; the next run looks it up.

Related MCP server: duet

Install

As a Claude plugin: build it with scripts/build_plugin.sh and install dist/digitomancy.plugin. You need adb and uv on your PATH. See plugin/README.md.

As a CLI or library:

git clone https://github.com/MadnessEngineering/digitomancy-plugin && cd digitomancy-plugin
uv sync --group dev             # add --extra vision for image-template checkpoints
uv run dgm doctor               # tools, workspace, which devices are online

As an MCP server in any MCP client:

{"mcpServers": {"digitomancy": {"command": "uv", "args": ["run", "--project", "/path/to/digitomancy-plugin", "digitomancy-mcp"]}}}

Connect a device

  • Phone: enable Developer options (tap Build number 7 times), turn on USB debugging, plug in, and accept the prompt. On first connect uiautomator2 installs its helper on the device.

  • BlueStacks: go to Settings → Advanced and enable ADB, then uv run dgm -d bluestacks connect. Check the port it shows; edit devices.yaml to match.

Workspace

Your devices, maps and routines live in a workspace: $DGM_HOME, or ~/.digitomancy by default, created on first run with starter maps and routines. Existing files are never overwritten.

  • devices.yaml: names → serials. Pick one with -d NAME, $DGM_DEVICE or default:. Unknown names are used as raw serials.

  • maps/<app>.yaml: anchors (things to tap), screens (checkpoint specs) and hazards (things never to tap). Refer to them as map:name.

  • routines/*.py: routines built from stages. A stage can require a screen, and a failed run can resume_from that stage.

  • .runs/: evidence from failed checkpoints (screenshot, UI dump, foreground activities).

  • catalog/ (optional, from dgm catalog): a redacted index of your Tasker projects and tasks. hazards_manual.txt and hazard_patterns.txt there tell the Tasker bridge which tasks it must never fire.

Concepts

  • Coordinates: a float in [0,1] is a fraction of the screen, and an int is a pixel. Maps store fractions so they work at any resolution. They still depend on orientation.

  • Checkpoints: a screen spec combines conditions with all or any: selector, gone, app, activity, anchor, image. A failed expect saves a snapshot to .runs/.

  • Tasker: dgm tasker "Task Name" -p par1=x fires a task through am broadcast. It needs a one-time profile on the phone; see docs/TASKER.md.

CLI

dgm doctor | connect | look [--all] | tap map:anchor|x,y | check map:screen
dgm routines | run NAME [-p k=v] [--resume-from STAGE]
dgm tasker TASK [-p k=v] [-w SEC] | catalog [SOURCES…]
dgm mirror [-- scrcpy args] | mcp

Known conflicts

  • Accessibility suppression. While uiautomator2's on-device server runs, Android suppresses every accessibility service: Tasker, AutoInput, Join, screen readers. The CLI stops the server when each command exits; the MCP server stops it after 60s idle or on release.

  • scrcpy --new-display. Apps on virtual displays don't count as foreground. Detection reads Display #0 only.

  • Launching apps. Device.launch() resolves the default launcher activity. uiautomator2's app_start can pick a random one, and some apps (Tasker) run a task from their second launcher activity.

Development

uv run pytest -q                 # no device needed: tests use a fake device
./scripts/build_plugin.sh        # dist/digitomancy/ and dist/digitomancy.plugin
claude plugin validate dist/digitomancy

License

MIT. Copyright (c) 2026 Madness Engineering. The Tasker action code table in the plugin comes from Taskomater/Tasker-XML-Info (MIT).

Available Tools

20 tools
checkCheckC

Evaluate a mapped screen 'map:screen' (optionally waiting). Returns ok + per-condition detail.

Inputs: screen (required), device, timeout. Returns: object

devicesDevicesB

Registered devices (devices.yaml), the default, and which serials adb sees right now.

Inputs: no named parameters. Returns: object

keyKeyB

Press a key: home, back, enter, recent, power, volume_up, volume_down, delete…

Inputs: name (required), device. Returns: result

launchLaunchC

Start an app by package name.

Inputs: package (required), device, stop_first. Returns: result

list_mapsList MapsC

All maps with their anchors and screens.

Inputs: no named parameters. Returns: object

list_routinesList RoutinesC

Known routines with params and stage names (stages are resume points).

Inputs: no named parameters. Returns: result

lookLookC

Current app + compact UI node list. Lines: #idx class 'text' id=res @(x,y normalized) [tap].

Inputs: limit, device, everything. Returns: result

releaseReleaseC

Stop uiautomator on the device so Tasker/AutoInput accessibility comes back.

Inputs: device. Returns: result

run_routineRun RoutineC

Run a routine. On failure returns the failed stage, snapshot dir, and a resume hint.

Inputs: name (required), device, params, resume_from. Returns: object

save_anchorSave AnchorC

Remember a tap target. From a look node (stores selector + point) or raw normalized x,y.

Inputs: name (required), map_name (required), x, y, +3 more. Returns: result

screenshotScreenshotA

PNG of the screen (downscaled to save tokens). Use when look can't see it (games, canvases).

Inputs: scale, device.

shellShellC

Raw adb shell escape hatch.

Inputs: cmd (required), device. Returns: result

swipeSwipeB

Swipe between two points (fractions or pixels). Scroll down = swipe(0.5,0.75,0.5,0.25).

Inputs: x1 (required), x2 (required), y1 (required), y2 (required), +2 more. Returns: result

tapTapC

Tap. Floats in [0,1] are screen fractions (preferred); otherwise pixels.

Inputs: x (required), y (required), device. Returns: result

tap_anchorTap AnchorC

Tap a mapped anchor 'map:name' (selector first, saved point as fallback).

Inputs: ref (required), device, timeout. Returns: result

tap_nodeTap NodeC

Tap node #index from the last look on this device.

Inputs: index (required), device. Returns: result

tasker_lookupTasker LookupA

Search the Tasker catalog (built by dgm catalog) by task/profile name substring.

Returns matching tasks with their actions and calls, plus hazard flags. Never fire a task marked hazard; tasker_run refuses them anyway.

Inputs: limit, query, project. Returns: object

tasker_runTasker RunB

Fire a Tasker task via broadcast (needs the DGM Dispatch profile, docs/TASKER.md).

Inputs: task (required), device, params, wait_result. Returns: object

type_textType TextC

Type into the focused field.

Inputs: text (required), clear, device. Returns: result

workspaceWorkspaceB

Where devices.yaml, maps/ and routines/ live (created and seeded if missing). Edit devices.yaml there.

Inputs: no named parameters. Returns: object

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

    TDQS

    C2.9/5.0

    Scored across 20 tools

    Disambiguation4/5

    Most tools have clearly distinct purposes, but tap, tap_node, and tap_anchor overlap as three tap variants, and tasker_run versus run_routine could be confused without careful reading. The descriptions generally clarify when to use each tool, so ambiguity is limited.

    Naming Consistency3/5

    There is a mix of snake_case multiword names and bare nouns/single verbs such as shell, workspace, look, tap, and swipe. The convention is readable but not consistent across the set.

    Tool Count3/5

    20 tools is on the heavy side for a device-automation server, though most correspond to real primitives rather than duplicates. It sits in the borderline-heavy 16–25 range.

    Completeness4/5

    The set covers device inspection, interaction, maps/anchors, routines, Tasker, and raw adb shell. It lacks structured CRUD for maps and routines and some UI actions like long-press, but the shell escape hatch prevents hard dead ends.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      C
      quality
      B
      maintenance
      Enables AI agents to control Android phones, emulators, redroid containers, iOS devices, and cloud-hosted devices through a perceive-act-verify loop of screen reading, taps, gestures, typing, and app launching. Exposes 138 tools for driving screens, elements, and files over adb, Portal APIs, and ios-portal without running ARM-only code on the device.
      94
      15 npm
      1
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables an AI coding agent to drive a real Android phone over adb and one or more visible Chrome windows in the same test run, with safe guarded commands, screenshots returned as images, per-step logs, reports, and recordings. It lets agents act, inspect the screen and device log, fix code, and rerun a scenario until the feature passes.
      21 npm
      3
      MIT
    • A
      license
      A
      quality
      B
      maintenance
      Enables AI agents to see and drive a real Android phone over plain ADB: screenshots and numbered UI trees, gestures, typing with accents and emoji, SMS/RCS reading and prepared replies, notifications, files, and settings, with no root and no app installed on the phone. Safeguards mask security codes and require explicit confirmation before sending, paying, deleting or confirming anything.
      18
      2
      MIT
    • A
      license
      A
      quality
      A
      maintenance
      Lets AI agents use an Android phone: read the screen, tap, type, scroll, open apps, take screenshots and reply to notifications, with approval cards before anything is sent, posted, bought or deleted. Runs inside the Buddy app on the phone; no root, adb or PC.
      10
      48
      207
      Apache 2.0