hand

more from customer0

Let your AI agent use a computer without guessing where to click.

A small model picks the button. hand clicks it and checks it worked.

bun add github:acoyfellow/hand
Turn on email notifications and save.
  1. click "Email notifications"95%
  2. click "Save changes"94%
  3. done94%

A real run. Each step shows how sure the model was.

It finished all 30 tasks, three times over, at 1/18 the cost of Claude Opus.

30/30tasks finished
$0.0016per task
0unwanted deletes

A real 38 s run. hand writes the message and makes every click.

How it works

ListRead the buttons on screen.
PickA small model chooses one.
ActClick it. Stop if unsure.
CheckConfirm it worked.

Use it with an AI agent

Works with Claude, Pi or any MCP client, on a Mac.

bun add github:acoyfellow/hand
swiftc -O node_modules/hand/native/ax.swift -o node_modules/hand/native/ax
{
  "mcpServers": {
    "hand": {
      "command": "bun",
      "args": ["node_modules/hand/src/mcp.ts"]
    }
  }
}

It never moves your mouse, and it reads back what it typed.

Use it from code

await hand.act('switch to the termlab tab');
await hand.type('coey.dev', 'the address bar');
await hand.look('Is coey.dev open?');

Full setup in the README.

Not tested yet

Details: every result, writer models, the benchmark

All results

setupwhat drives itfinished$/task
hand (Clef + writer)Clef picks every action; a writer fills fields only when the task needs new text30.0/30$0.0016
Clef + copierClef picks every action; Clairic copies values out of the task, never writes new ones25.0/30$0.0015
Opus, screenshotsClaude Opus reads screenshots and clicks22.7/30$0.029
Opus + ClefOpus plans, Clef clicks22.0/30$0.029

Writer models

Scored alone on 44 messy requests. The default pairs a cheap model with a backup: glm-5.3-flash, then kimi-k2.6 for any field it leaves empty. 42–43 of 44 across runs, at $0.00009 a request. All writers.

The benchmark

Every change to the library has to pass a fixed benchmark: 30 tasks in a test app, success read from the app's own state, and a gate that fails if results get worse.

bun run check   # types, lint, tests
bun run gate    # fails if results are stale or worse
bun run bench   # real models, writes bench/runs/<id>/