ghost-hands 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ghost_hands-0.3.0/.github/workflows/pages.yml +40 -0
- ghost_hands-0.3.0/.github/workflows/publish.yml +34 -0
- ghost_hands-0.3.0/LAUNCH.md +307 -0
- ghost_hands-0.3.0/LICENSE +21 -0
- ghost_hands-0.3.0/PKG-INFO +251 -0
- ghost_hands-0.3.0/PLAN.md +156 -0
- ghost_hands-0.3.0/README.md +229 -0
- ghost_hands-0.3.0/examples/policy.json +1 -0
- ghost_hands-0.3.0/examples/steps.json +1 -0
- ghost_hands-0.3.0/pyproject.toml +40 -0
- ghost_hands-0.3.0/site/assets/ghost-developer-studio-logo.png +0 -0
- ghost_hands-0.3.0/site/index.html +308 -0
- ghost_hands-0.3.0/src/ghost_hands/__init__.py +41 -0
- ghost_hands-0.3.0/src/ghost_hands/actions.py +253 -0
- ghost_hands-0.3.0/src/ghost_hands/bench.py +1919 -0
- ghost_hands-0.3.0/src/ghost_hands/cli.py +189 -0
- ghost_hands-0.3.0/src/ghost_hands/deciders.py +272 -0
- ghost_hands-0.3.0/src/ghost_hands/drivers.py +2353 -0
- ghost_hands-0.3.0/src/ghost_hands/errors.py +10 -0
- ghost_hands-0.3.0/src/ghost_hands/export.py +140 -0
- ghost_hands-0.3.0/src/ghost_hands/eyes.py +477 -0
- ghost_hands-0.3.0/src/ghost_hands/governor.py +245 -0
- ghost_hands-0.3.0/src/ghost_hands/mcp_server.py +295 -0
- ghost_hands-0.3.0/src/ghost_hands/runner.py +322 -0
- ghost_hands-0.3.0/src/ghost_hands/trail.py +95 -0
- ghost_hands-0.3.0/tests/conftest.py +25 -0
- ghost_hands-0.3.0/tests/pages_fixtures.py +27 -0
- ghost_hands-0.3.0/tests/test_chromium.py +71 -0
- ghost_hands-0.3.0/tests/test_chromium_state.py +146 -0
- ghost_hands-0.3.0/tests/test_chromium_v3.py +625 -0
- ghost_hands-0.3.0/tests/test_deciders.py +68 -0
- ghost_hands-0.3.0/tests/test_drivers_fake.py +110 -0
- ghost_hands-0.3.0/tests/test_export_v2.py +64 -0
- ghost_hands-0.3.0/tests/test_eyes.py +116 -0
- ghost_hands-0.3.0/tests/test_governor.py +141 -0
- ghost_hands-0.3.0/tests/test_heal.py +135 -0
- ghost_hands-0.3.0/tests/test_mcp.py +102 -0
- ghost_hands-0.3.0/tests/test_proxy_relay.py +152 -0
- ghost_hands-0.3.0/tests/test_runner.py +122 -0
- ghost_hands-0.3.0/tests/test_stub_decider.py +125 -0
- ghost_hands-0.3.0/tests/test_trail_export.py +80 -0
- ghost_hands-0.3.0/tests/test_v3_actions.py +368 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
name: Deploy site to Pages
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
paths:
|
|
7
|
+
- "site/**"
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
pages: write
|
|
13
|
+
id-token: write
|
|
14
|
+
|
|
15
|
+
concurrency:
|
|
16
|
+
group: pages
|
|
17
|
+
cancel-in-progress: false
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
deploy:
|
|
21
|
+
name: Deploy site to GitHub Pages
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
environment:
|
|
24
|
+
name: github-pages
|
|
25
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
26
|
+
steps:
|
|
27
|
+
- name: Check out the repo
|
|
28
|
+
uses: actions/checkout@v4
|
|
29
|
+
|
|
30
|
+
- name: Configure Pages
|
|
31
|
+
uses: actions/configure-pages@v5
|
|
32
|
+
|
|
33
|
+
- name: Upload site artifact
|
|
34
|
+
uses: actions/upload-pages-artifact@v3
|
|
35
|
+
with:
|
|
36
|
+
path: site
|
|
37
|
+
|
|
38
|
+
- name: Deploy to GitHub Pages
|
|
39
|
+
id: deployment
|
|
40
|
+
uses: actions/deploy-pages@v4
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
publish:
|
|
10
|
+
name: Build and publish to PyPI
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
environment: pypi
|
|
13
|
+
permissions:
|
|
14
|
+
id-token: write
|
|
15
|
+
steps:
|
|
16
|
+
- name: Check out the repo
|
|
17
|
+
uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Set up Python
|
|
20
|
+
uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: "3.12"
|
|
23
|
+
|
|
24
|
+
- name: Install build tooling
|
|
25
|
+
run: python -m pip install --upgrade build twine
|
|
26
|
+
|
|
27
|
+
- name: Build sdist and wheel
|
|
28
|
+
run: python -m build
|
|
29
|
+
|
|
30
|
+
- name: Check the distributions
|
|
31
|
+
run: twine check dist/*
|
|
32
|
+
|
|
33
|
+
- name: Publish to PyPI (trusted publishing)
|
|
34
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
# Ghost Hands — Launch Package
|
|
2
|
+
|
|
3
|
+
> **STATUS: DRAFT — STAGED LOCALLY ONLY.**
|
|
4
|
+
> Nothing in this file has been published, posted, pushed, or deployed.
|
|
5
|
+
> Every step below runs only on Ryan's explicit go. All copy is DRAFT.
|
|
6
|
+
> Numbers cited are the verified v0.3.0 numbers (see "Honest-claims
|
|
7
|
+
> checklist" at the bottom) — do not inflate them anywhere.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Positioning
|
|
12
|
+
|
|
13
|
+
**Ghost Hands is the governed agent-hands layer for the web: every action
|
|
14
|
+
an agent takes is classified, judged against policy, recorded before it
|
|
15
|
+
runs, and — when it matters — gated on a human approval. And the browser
|
|
16
|
+
stack underneath is our own: a zero-dependency CDP client driving Chromium
|
|
17
|
+
directly. No Playwright. No Selenium. Nobody else's automation stack.**
|
|
18
|
+
|
|
19
|
+
One-liner (primary): *Playwright drives. Stagehand thinks. Browser Use
|
|
20
|
+
wanders. Ghost Hands answers for every move.*
|
|
21
|
+
|
|
22
|
+
### Tagline options (pick one at launch)
|
|
23
|
+
1. "Agent hands with a conscience — classified, approved, and on the record."
|
|
24
|
+
2. "Your agent's hands, on a leash you hold: policy gates, approval prompts, and a replayable trail."
|
|
25
|
+
3. "We didn't wrap Playwright. We built the hands — governor included."
|
|
26
|
+
|
|
27
|
+
### The wedge (why this exists)
|
|
28
|
+
- Every tool in the field will click "Pay", "Send", or "Delete" the moment
|
|
29
|
+
a model tells it to. Ghost Hands classifies first (`readonly` / `write` /
|
|
30
|
+
`consequential`), applies a policy, and stops for a human on the
|
|
31
|
+
consequential ones. No approver present = denied. Silence is never consent.
|
|
32
|
+
- Every run writes a provenance trail *before* actions execute — audit it,
|
|
33
|
+
diff it, replay it.
|
|
34
|
+
- Finished runs graduate into deterministic, model-free scripts (Chromium
|
|
35
|
+
or fake body): explore with a model once, re-run forever for free.
|
|
36
|
+
- Perception is cheap on purpose: numbered element maps, ~174 tokens for
|
|
37
|
+
the demo page — not screenshot firehoses.
|
|
38
|
+
- Self-healing targets: if the page mutates between seeing and acting, the
|
|
39
|
+
hands re-find the element by what it *is*, retry once, and log the heal.
|
|
40
|
+
- Local-first: your Chromium, your keys (env only, never stored), zero
|
|
41
|
+
runtime dependencies, no cloud-browser upsell.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Show HN (DRAFT)
|
|
46
|
+
|
|
47
|
+
**Title:** Show HN: Ghost Hands – governed agent hands for the web (own CDP stack, zero deps)
|
|
48
|
+
|
|
49
|
+
**Body:**
|
|
50
|
+
|
|
51
|
+
> Hi HN — I run a one-person studio in Tennessee and kept running into the
|
|
52
|
+
> same problem with browser agents: every tool I tried (Playwright MCP,
|
|
53
|
+
> Stagehand, Browser Use) hands an LLM raw browser power with no judgment
|
|
54
|
+
> attached. Ask for the wrong thing, or let a page prompt-inject the model,
|
|
55
|
+
> and it will cheerfully click submit/pay/delete.
|
|
56
|
+
>
|
|
57
|
+
> Ghost Hands is the layer I wanted instead. It's a zero-dependency Python
|
|
58
|
+
> package that gives an agent hands on the web — and a governor:
|
|
59
|
+
>
|
|
60
|
+
> - Every action is classified before it runs: readonly / write /
|
|
61
|
+
> consequential. Consequential actions (form submits, anything that
|
|
62
|
+
> smells like pay/send/delete/publish) hit a policy: allow, ask a human,
|
|
63
|
+
> or deny. With no approver attached, "ask" means deny.
|
|
64
|
+
> - Record-before-execute: the decision and the action hit a JSONL
|
|
65
|
+
> provenance trail before the driver moves, so a run can be audited or
|
|
66
|
+
> replayed even if it crashes mid-step.
|
|
67
|
+
> - Trails graduate into deterministic, model-free scripts — explore with
|
|
68
|
+
> a model once, then re-run the same steps with no model in the loop.
|
|
69
|
+
> - The browser body is our own stdlib CDP client over
|
|
70
|
+
> --remote-debugging-pipe. No Playwright, no Selenium — the maintainer of
|
|
71
|
+
> our stack is us. (We drive Chromium, the browser; we didn't write a
|
|
72
|
+
> browser engine.)
|
|
73
|
+
> - Perception is a numbered element map (Jev-style): the demo run reads a
|
|
74
|
+
> page in ~174 estimated tokens. Stuck detection stops and reports
|
|
75
|
+
> instead of wandering.
|
|
76
|
+
>
|
|
77
|
+
> v0.2.0 adds tabs, session save/load (cookies + localStorage),
|
|
78
|
+
> self-healing targets (page mutates between perception and action → the
|
|
79
|
+
> element is re-found by descriptor, retried once, heal logged), real
|
|
80
|
+
> screenshots to disk, and an OpenAI-compatible decider whose wire protocol
|
|
81
|
+
> is proven against a local stub. v0.3.0 adds a second pair of eyes
|
|
82
|
+
> (Accessibility-tree maps alongside the shadow-piercing DOM walk),
|
|
83
|
+
> one-action form filling, downloads/uploads, network capture on the
|
|
84
|
+
> trail, structured extract, dialog policy, PDF, viewport presets,
|
|
85
|
+
> richer input (hover/drag/chords/raw coordinates), and wait-for
|
|
86
|
+
> conditions — every one classified and trailed like the rest.
|
|
87
|
+
> It's verified by a 170-test pytest suite and an 82-case bench,
|
|
88
|
+
> including live runs against example.com and a real Wikipedia search
|
|
89
|
+
> driven end-to-end by the deterministic decider.
|
|
90
|
+
>
|
|
91
|
+
> The honest limits: the LLM decider's protocol is proven against a stub;
|
|
92
|
+
> how well any given live model drives it is that model's business.
|
|
93
|
+
> Chromium only, for now — the same action protocol is designed to gain an
|
|
94
|
+
> Android body from our phone agent (MrGhosty) later.
|
|
95
|
+
>
|
|
96
|
+
> MIT. I'd love feedback on the governance model in particular — is
|
|
97
|
+
> classify-and-approve the right default, or should read/write/consequential
|
|
98
|
+
> be split differently?
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## r/Python post (DRAFT)
|
|
103
|
+
|
|
104
|
+
**Title:** Ghost Hands 0.2 — zero-dependency, governed browser automation for agents (own CDP client, approval gates, replayable trails)
|
|
105
|
+
|
|
106
|
+
**Body:**
|
|
107
|
+
|
|
108
|
+
> I built Ghost Hands because every agent-browser tool I tried would
|
|
109
|
+
> execute whatever the model said — including "submit", "pay", and
|
|
110
|
+
> "delete". Ghost Hands puts a governor between the brain and the hands:
|
|
111
|
+
>
|
|
112
|
+
> - **Classify → policy → record → act.** Every action is readonly, write,
|
|
113
|
+
> or consequential. Consequential actions need policy approval (or a
|
|
114
|
+
> human's). Everything is written to a JSONL trail *before* it executes.
|
|
115
|
+
> - **Own CDP stack.** The Chromium driver is a stdlib Chrome DevTools
|
|
116
|
+
> Protocol client over `--remote-debugging-pipe` — no Playwright, no
|
|
117
|
+
> Selenium, `dependencies = []` in pyproject. Driving a real tab,
|
|
118
|
+
> session save/load (cookies + localStorage), and screenshots included.
|
|
119
|
+
> - **Cheap eyes.** Numbered element maps parsed from HTML — the bundled
|
|
120
|
+
> demo reads a page in ~174 estimated tokens.
|
|
121
|
+
> - **Runs graduate.** Any trail exports into a deterministic Ghost Hands
|
|
122
|
+
> script (no model) — the bench actually executes a graduated script on
|
|
123
|
+
> real Chromium to prove it.
|
|
124
|
+
> - **Self-healing targets** (new in 0.2): if the page mutates between
|
|
125
|
+
> perception and action, the target is re-found by descriptor and
|
|
126
|
+
> retried once; the heal is a trail event.
|
|
127
|
+
> - **Deciders are pluggable:** scripted, deterministic rules (offline),
|
|
128
|
+
> or any OpenAI-compatible endpoint (key from env only; wire protocol
|
|
129
|
+
> tested against a local stub server).
|
|
130
|
+
> - Plus a stdlib MCP server (`hands_perceive` / `hands_act` / `hands_run`
|
|
131
|
+
> / `hands_trail`) — Playwright MCP's surface, with the governor attached.
|
|
132
|
+
>
|
|
133
|
+
> Verified locally: 170 pytest tests, 82 bench cases, plus live cases
|
|
134
|
+
> (example.com link-follow; a real Wikipedia search for "Oakdale,
|
|
135
|
+
> Tennessee" driven end-to-end by the rules decider). MIT licensed.
|
|
136
|
+
> Feedback on the classification model especially welcome.
|
|
137
|
+
|
|
138
|
+
## r/opensource post (DRAFT)
|
|
139
|
+
|
|
140
|
+
**Title:** Ghost Hands — open-source agent hands that ask before they pay (zero-dep Python, own CDP stack)
|
|
141
|
+
|
|
142
|
+
**Body:**
|
|
143
|
+
|
|
144
|
+
> Open-sourcing the browser-hands layer from our studio's agent stack.
|
|
145
|
+
> The idea: agents shouldn't get raw browser power. Ghost Hands classifies
|
|
146
|
+
> every action (readonly / write / consequential), enforces a policy with
|
|
147
|
+
> human approval for the consequential ones, records everything to a
|
|
148
|
+
> provenance trail before it runs, and can graduate a finished run into a
|
|
149
|
+
> deterministic script that needs no model. The browser automation layer
|
|
150
|
+
> is our own — a zero-dependency stdlib CDP client — because we didn't
|
|
151
|
+
> want to ship someone else's stack as our product. MIT. Links + a
|
|
152
|
+
> 82-case bench and 170 tests in the repo; live example (real Wikipedia
|
|
153
|
+
> search, governed) in the README.
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## X / TikTok short copy (DRAFT)
|
|
158
|
+
|
|
159
|
+
**X (post):**
|
|
160
|
+
> Playwright drives. Stagehand thinks. Browser Use wanders.
|
|
161
|
+
> Ghost Hands answers for every move.
|
|
162
|
+
>
|
|
163
|
+
> Governed agent hands for the web: every action classified, consequential
|
|
164
|
+
> ones gated on YOUR approval, everything recorded before it runs — on our
|
|
165
|
+
> own zero-dependency CDP stack. No Playwright under the hood. 👻🖐️
|
|
166
|
+
> #buildinpublic #python #aiagents
|
|
167
|
+
|
|
168
|
+
**X (follow-up):**
|
|
169
|
+
> The demo reads a whole page in ~174 tokens.
|
|
170
|
+
> A checkout click with no approver attached? Denied — and the trail shows
|
|
171
|
+
> exactly why. That's the whole product: hands you can audit.
|
|
172
|
+
|
|
173
|
+
**TikTok caption:**
|
|
174
|
+
> I built my AI agent a pair of hands — then I built it a conscience.
|
|
175
|
+
> Ghost Hands: it classifies every click before it clicks, asks me before
|
|
176
|
+
> anything that costs money, and writes down everything it did. Oh — and
|
|
177
|
+
> we didn't wrap Playwright. We wrote our own browser stack. 👻
|
|
178
|
+
> #buildinpublic #devtools #aiagent #python #ghostdevstudio
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Build in Public episode outline (DRAFT)
|
|
183
|
+
|
|
184
|
+
**Working title:** "We Built Our Own Playwright — With a Conscience"
|
|
185
|
+
**Format:** vertical, studio standard; show artifacts, not gaps.
|
|
186
|
+
|
|
187
|
+
1. **Cold open (the problem):** on camera — an ungoverned agent (any
|
|
188
|
+
competitor) one prompt away from clicking "Place order". Freeze frame:
|
|
189
|
+
"Would you let your agent do that unsupervised?"
|
|
190
|
+
2. **The bench moment:** run `ghost-hands bench` live on screen — 82/82,
|
|
191
|
+
call out the money case: "checkout blocked without approval."
|
|
192
|
+
3. **Show the trail:** open a trail file; walk one step: perceive →
|
|
193
|
+
decide → govern → execute → result. "Receipts for every move."
|
|
194
|
+
4. **Show the hands are ours:** the CDP pipe client, zero dependencies —
|
|
195
|
+
print the import audit. "No Playwright. No Selenium. Ours."
|
|
196
|
+
5. **Live proof:** the Wikipedia run — RuleDecider types "Oakdale,
|
|
197
|
+
Tennessee", the Search click classifies *consequential*, approval
|
|
198
|
+
granted, lands on the Oakdale article. Real browser, real site.
|
|
199
|
+
6. **The heal:** mutation demo — banner appears mid-run, target shifts,
|
|
200
|
+
`heal` event in the trail, action still lands.
|
|
201
|
+
7. **Graduation:** export a trail → run the graduated script with no
|
|
202
|
+
model. "Explore once with AI. Replay forever free."
|
|
203
|
+
8. **Close:** what's next (Android body — the same hands on a phone),
|
|
204
|
+
launch ask: star/feedback; no mention of anything unfinished as a lack
|
|
205
|
+
— frame purely as what's coming.
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Product Hunt draft (DRAFT)
|
|
210
|
+
|
|
211
|
+
**Name:** Ghost Hands
|
|
212
|
+
**Tagline:** Governed agent hands for the web — approval gates, provenance trails, zero dependencies
|
|
213
|
+
**Description:**
|
|
214
|
+
> Ghost Hands gives AI agents hands on the web — with a governor attached.
|
|
215
|
+
> Every action is classified (readonly / write / consequential), judged
|
|
216
|
+
> against a policy, written to a replayable provenance trail before it
|
|
217
|
+
> executes, and gated on human approval when it matters. Finished runs
|
|
218
|
+
> graduate into deterministic scripts that re-run with no model. Under the
|
|
219
|
+
> hood is our own zero-dependency CDP client driving Chromium — no
|
|
220
|
+
> Playwright, no Selenium — plus cheap numbered element maps (~174 tokens
|
|
221
|
+
> for the demo page), tabs, session save/load, self-healing targets, and
|
|
222
|
+
> an MCP server. MIT, from Ghost Developer Studio.
|
|
223
|
+
**Makers:** Ryan Cotten (Ghost Developer Studio)
|
|
224
|
+
**Topics:** Developer Tools, Artificial Intelligence, Open Source, Automation
|
|
225
|
+
**First comment (draft):** the Show HN body, lightly trimmed.
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Publish steps (run ONLY on Ryan's explicit go, in order)
|
|
230
|
+
|
|
231
|
+
1. **Final local verification:** `pytest -q` (expect 170 passed),
|
|
232
|
+
`ghost-hands bench` (expect 82/82), `ghost-hands bench --live`
|
|
233
|
+
(expect 2/2), `python -m build` (0.3.0 wheel + sdist), clean-venv
|
|
234
|
+
install + `ghost-hands demo` + MCP smoke. Record the numbers; update
|
|
235
|
+
README/this file if they moved.
|
|
236
|
+
2. **Create the GitHub repo** `littlestjames82-sys/ghost-hands` (public,
|
|
237
|
+
MIT) via the GitHub API with the stored connector (same route used for
|
|
238
|
+
agent-seatbelt / ghostbus): push the tree at `~/workspace/ghost-hands/`
|
|
239
|
+
(src layout, tests, examples, README, LICENSE, PLAN.md, LAUNCH.md,
|
|
240
|
+
site/) as the initial commit.
|
|
241
|
+
3. **Tag `v0.3.0`** on that commit and cut a GitHub release with the notes
|
|
242
|
+
from the README changelog; attach the built wheel + sdist from `dist/`.
|
|
243
|
+
4. **PyPI trusted publishing** (mirror the ghost-seatbelt flow exactly):
|
|
244
|
+
a. On PyPI: "Publishing → Add a new pending publisher" — project name
|
|
245
|
+
`ghost-hands`, owner `littlestjames82-sys`, repository `ghost-hands`,
|
|
246
|
+
workflow `release.yaml`, environment `pypi`.
|
|
247
|
+
(Name availability re-verify immediately before: `ghost-hands`
|
|
248
|
+
returned 404 on Oct 8, 2026.)
|
|
249
|
+
b. Commit `.github/workflows/release.yaml` (build + `pypa/gh-action-pypi-publish`
|
|
250
|
+
with OIDC, environment `pypi`) — same shape as agent-seatbelt's.
|
|
251
|
+
c. Trigger the workflow from the v0.3.0 release; verify
|
|
252
|
+
`pip install ghost-hands` in a clean venv + `ghost-hands demo`.
|
|
253
|
+
d. After the first successful publish, delete the "pending" nature by
|
|
254
|
+
confirming the project page lists 0.3.0 files (wheel + sdist).
|
|
255
|
+
5. **Enable GitHub Pages** for the repo: the landing page lives at
|
|
256
|
+
`site/` in the repo root, so publish that directory — either add the
|
|
257
|
+
standard static-pages workflow (`actions/upload-pages-artifact` with
|
|
258
|
+
`path: site`, Pages source = GitHub Actions) or serve a `gh-pages`
|
|
259
|
+
branch containing the contents of `site/`. Verify the logo path
|
|
260
|
+
(`assets/ghost-developer-studio-logo.png`, relative to `site/index.html`)
|
|
261
|
+
resolves on the live URL before announcing it.
|
|
262
|
+
6. **Announce** (each is its own approval): Show HN (weekday 8–9am ET),
|
|
263
|
+
r/Python + r/opensource posts, X/TikTok copy, Product Hunt submission,
|
|
264
|
+
Build in Public episode. Re-check every number in the copy against the
|
|
265
|
+
honest-claims checklist below on the day.
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## Honest-claims checklist (verified Oct 8, 2026 — re-verify on launch day)
|
|
270
|
+
|
|
271
|
+
- [x] pytest: **170 passed** (v0.3.0 tree).
|
|
272
|
+
- [x] Bench (offline): **82/82 passed**, including live-Chrome fixture
|
|
273
|
+
cases (perceive/type/click, session roundtrip, tabs, screenshot,
|
|
274
|
+
graduated-script execution) and the full v0.3 capability set on
|
|
275
|
+
real Chromium (AX eyes, shadow DOM, frames, dialogs, downloads,
|
|
276
|
+
uploads, network capture, fill_form, structured extract, hover,
|
|
277
|
+
drag, chords, PDF, viewport, wait_for, click_at).
|
|
278
|
+
- [x] Bench (live): **2/2 passed** — example.com (title "Example Domain",
|
|
279
|
+
IANA link followed to https://www.iana.org/help/example-domains,
|
|
280
|
+
landed title "Example Domains") and Wikipedia (RuleDecider searched
|
|
281
|
+
"Oakdale, Tennessee", 3 executed steps, landed on
|
|
282
|
+
https://en.wikipedia.org/wiki/Oakdale,_Tennessee, title
|
|
283
|
+
"Oakdale, Tennessee - Wikipedia"). Note: one transient failure was
|
|
284
|
+
observed during the v0.3 round (the sandbox egress proxy closing
|
|
285
|
+
connections across several hosts, `net::ERR_CONNECTION_CLOSED`);
|
|
286
|
+
the re-run passed 2/2 and adjacent probes loaded Wikipedia with
|
|
287
|
+
the same code — environmental, not a regression.
|
|
288
|
+
- [x] Dist sizes (0.3.0): wheel **76,665 B**, sdist **366,151 B** (the
|
|
289
|
+
sdist ships the full test suite + bench fixtures).
|
|
290
|
+
- [x] Demo perception: **696 map chars ≈ 174 tokens (chars/4)** for the
|
|
291
|
+
bundled demo run; demo completes in 8 steps.
|
|
292
|
+
- [x] Zero runtime dependencies: pyproject `dependencies = []`; import
|
|
293
|
+
audit = stdlib only.
|
|
294
|
+
- [x] No Playwright / Selenium code: grep shows only negative assertions
|
|
295
|
+
and comparison copy (tests assert exports do NOT contain them).
|
|
296
|
+
- [x] example.com link label: as served Oct 2026 it reads **"Learn more"**
|
|
297
|
+
(href https://iana.org/help/example-domains) — do not claim a
|
|
298
|
+
"More information" label in copy.
|
|
299
|
+
- [ ] LLM decider: protocol proven vs a **local stub** only. Never claim
|
|
300
|
+
live-model performance, success rates, or benchmarks.
|
|
301
|
+
- [ ] ChromiumDriver vs arbitrary third-party sites: proven on
|
|
302
|
+
example.com + Wikipedia only. No broad compatibility claims.
|
|
303
|
+
- [ ] No speed claims vs Playwright/Stagehand/Browser Use — we have not
|
|
304
|
+
benchmarked head-to-head; the comparison table describes features,
|
|
305
|
+
not performance.
|
|
306
|
+
- [ ] PyPI/GitHub: NOT live until step 2–4 above are done. All install
|
|
307
|
+
commands in copy are future tense until then.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ghost Developer Studio
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: ghost-hands
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Governed agent hands for the web: numbered element maps, classified actions, an approval governor, and a replayable provenance trail.
|
|
5
|
+
Project-URL: Homepage, https://github.com/littlestjames82-sys/ghost-hands
|
|
6
|
+
Project-URL: Repository, https://github.com/littlestjames82-sys/ghost-hands
|
|
7
|
+
Author: Ghost Developer Studio
|
|
8
|
+
License: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: agent,browser-automation,cdp,governance,mcp
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Browsers
|
|
19
|
+
Classifier: Topic :: Software Development :: Testing
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# Ghost Hands
|
|
24
|
+
|
|
25
|
+
**Playwright drives. Stagehand thinks. Browser Use wanders. Ghost Hands answers for every move.**
|
|
26
|
+
|
|
27
|
+
Ghost Hands is a standalone, zero-dependency Python package that gives an
|
|
28
|
+
agent *hands* on the web — and a conscience to go with them. Every action an
|
|
29
|
+
agent takes is classified before it runs (`readonly` / `write` /
|
|
30
|
+
`consequential`), judged against a policy, written to a provenance trail
|
|
31
|
+
*before* it executes, and — when it matters — gated on a human approval.
|
|
32
|
+
Finished runs graduate into deterministic, model-free Ghost Hands scripts
|
|
33
|
+
you can re-run for free.
|
|
34
|
+
|
|
35
|
+
The browser body is **our own**: a stdlib Chrome DevTools Protocol client
|
|
36
|
+
drives Chromium directly over the `--remote-debugging-pipe` transport.
|
|
37
|
+
There is no Playwright, no Selenium, and no other automation library under
|
|
38
|
+
the hood — the automation layer is 100% ours. (We drive Chromium, the
|
|
39
|
+
browser; we did not write a browser engine and don't claim to have.)
|
|
40
|
+
|
|
41
|
+
From [Ghost Developer Studio](https://github.com/littlestjames82-sys).
|
|
42
|
+
MIT licensed.
|
|
43
|
+
|
|
44
|
+
> Status: v0.3.0 — **live on GitHub**:
|
|
45
|
+
> [github.com/littlestjames82-sys/ghost-hands](https://github.com/littlestjames82-sys/ghost-hands),
|
|
46
|
+
> site at [littlestjames82-sys.github.io/ghost-hands](https://littlestjames82-sys.github.io/ghost-hands/).
|
|
47
|
+
> The PyPI listing (`ghost-hands`) is being registered and lands at launch.
|
|
48
|
+
|
|
49
|
+
## What's new in 0.3.0
|
|
50
|
+
|
|
51
|
+
- **Two kinds of eyes.** DOM eyes now walk the composed tree — open
|
|
52
|
+
shadow roots pierced, same-page iframes included and tagged — so web
|
|
53
|
+
components and framed controls are numbered like everything else.
|
|
54
|
+
Or switch to **AX eyes** (`eyes="ax"`): the map is built from the CDP
|
|
55
|
+
Accessibility tree (role + name + states) and actions resolve back
|
|
56
|
+
through `backendNodeId`.
|
|
57
|
+
- **Forms in one move.** `fill_form` fills a whole form from
|
|
58
|
+
`{label: value}` pairs, resolving each field by label, name,
|
|
59
|
+
placeholder, or aria-label, and reports per-field results — failures
|
|
60
|
+
named, never silent. With `submit: true` it is classified
|
|
61
|
+
consequential and takes the normal approval path.
|
|
62
|
+
- **Files both ways.** `download` clicks through and waits for the file
|
|
63
|
+
to complete on disk (filename + byte size reported, completion on the
|
|
64
|
+
trail); `set_file` uploads a local file into a file input
|
|
65
|
+
(`DOM.setFileInputFiles`), refusing missing paths and directories.
|
|
66
|
+
- **Network on the record.** The Network domain is captured during
|
|
67
|
+
runs (method, URL, status, type) into `net` trail events, capped at
|
|
68
|
+
200 per run with truncation noted; `extract` mode `network` returns
|
|
69
|
+
the captured list.
|
|
70
|
+
- **Structured extract.** `extract` modes: `text` (default), `list`
|
|
71
|
+
(links → `[{text, href}]`), `table` (→ list of row dicts), `network`.
|
|
72
|
+
- **Dialogs handled, on the record.** `confirm`/`alert`/`prompt` are
|
|
73
|
+
answered per the driver policy (`dialog_policy="dismiss"|"accept"`,
|
|
74
|
+
default dismiss) and every dialog + decision lands on the trail.
|
|
75
|
+
- **Richer input.** `hover`, `double_click`, `right_click`, `drag`
|
|
76
|
+
(target → target), key chords in `press` (`"Control+a"`), and
|
|
77
|
+
`click_at(x, y)` — the raw-coordinate fallback, classified `write`
|
|
78
|
+
and marked `raw: true` on the trail.
|
|
79
|
+
- **PDF + viewport.** `pdf` prints the page to a real PDF file
|
|
80
|
+
(`Page.printToPDF`); `set_viewport` switches named presets
|
|
81
|
+
(desktop 1280×800, mobile 390×844 + touch) and perception reflects
|
|
82
|
+
the emulated layout, media queries included.
|
|
83
|
+
- **Wait-for conditions.** `wait_for` waits for text to appear, an
|
|
84
|
+
element matching a descriptor, or a URL substring — with a timeout
|
|
85
|
+
that fails honestly, on the record.
|
|
86
|
+
- All new actions work through the CLI runner and MCP `hands_act`
|
|
87
|
+
unchanged, and every one of them is still classified by the governor
|
|
88
|
+
and written to the trail. (HTML-snapshot eyes do not pierce shadow
|
|
89
|
+
roots or frames — that is what the live-element map is for.)
|
|
90
|
+
|
|
91
|
+
## What's new in 0.2.0
|
|
92
|
+
|
|
93
|
+
- **Live-web proven.** The Chromium driver has now driven real sites end
|
|
94
|
+
to end: example.com (followed the IANA link to the Example Domains
|
|
95
|
+
page) and a real Wikipedia search — the deterministic RuleDecider typed
|
|
96
|
+
"Oakdale, Tennessee", submitted, and landed on the Oakdale article.
|
|
97
|
+
Reproduce with `ghost-hands bench --live` (2 cases, verified Oct 8,
|
|
98
|
+
2026 from the studio sandbox).
|
|
99
|
+
- **Self-healing targets.** If the page mutates between perception and
|
|
100
|
+
action, the stale target is detected, re-found by its recorded
|
|
101
|
+
descriptor, retried exactly once, and the heal is written to the trail
|
|
102
|
+
as its own event.
|
|
103
|
+
- **Tabs.** `open_tab` / `switch_tab` / `list_tabs` — each tab is its own
|
|
104
|
+
CDP target; perception and actions apply to the active tab.
|
|
105
|
+
- **Session state.** `save_session` / `load_session`: cookies
|
|
106
|
+
(Network.getAllCookies / setCookie) plus the current origin's
|
|
107
|
+
localStorage, in a small versioned JSON format.
|
|
108
|
+
- **Screenshots to disk.** The screenshot action now writes a real PNG
|
|
109
|
+
(`Page.captureScreenshot`) to the action's `path`.
|
|
110
|
+
- **Proxy support.** The driver honors `HTTPS_PROXY` / `https_proxy`
|
|
111
|
+
(opt out with `proxy=""`). Authenticated proxies work via a built-in
|
|
112
|
+
local relay that injects the credentials Chrome itself can't accept;
|
|
113
|
+
`ignore_cert_errors=True` is available for TLS-intercepting proxies.
|
|
114
|
+
- **Decider wire proof.** The OpenAI-compatible decider's protocol —
|
|
115
|
+
request shape, env gating, reply parsing, the full Runner loop — is
|
|
116
|
+
covered by tests and a bench case against a local stub
|
|
117
|
+
`/chat/completions` server. Live-model driving quality remains
|
|
118
|
+
unproven (see "Honest status").
|
|
119
|
+
- **Graduated scripts, executed.** Replay export now takes `driver=`
|
|
120
|
+
(chromium or fake-with-embedded-pages) and `start_url=`; the bench
|
|
121
|
+
actually *executes* a graduated script against fixture pages on real
|
|
122
|
+
Chromium and checks its completion marker.
|
|
123
|
+
|
|
124
|
+
## Quickstart
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
pip install ghost-hands # (once published; for now: pip install . from a checkout)
|
|
128
|
+
ghost-hands demo # scripted run over a built-in fake mini-web — no browser needed
|
|
129
|
+
ghost-hands bench # the verification suite
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Drive a real page:
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
from ghost_hands import ChromiumDriver, Runner, ScriptedDecider
|
|
136
|
+
|
|
137
|
+
driver = ChromiumDriver() # finds Chromium/Chrome; $GHOST_HANDS_CHROME overrides
|
|
138
|
+
runner = Runner(driver, ScriptedDecider([
|
|
139
|
+
{"kind": "navigate", "url": "https://example.com"},
|
|
140
|
+
{"kind": "extract"},
|
|
141
|
+
{"kind": "done", "summary": "looked at the page"},
|
|
142
|
+
]))
|
|
143
|
+
report = runner.run("look at example.com")
|
|
144
|
+
print(report.stop_reason, report.summary)
|
|
145
|
+
driver.close()
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## How it works
|
|
149
|
+
|
|
150
|
+
| Layer | What it does |
|
|
151
|
+
|---|---|
|
|
152
|
+
| **Eyes** (`eyes.py`) | Numbered **ElementMap** — `[3] <button> "Sign in"` — compact text with a character budget. No screenshots, no vision model. Two sources: an HTML snapshot parse (offline body), or the live browser — a composed-tree DOM walk (shadow roots + iframes) or the CDP Accessibility tree. |
|
|
153
|
+
| **Hands** (`actions.py`) | Typed, JSON-serializable actions: navigate, click, type, press (with key chords), select, scroll, hover, double/right click, drag, click_at (raw coordinates), fill_form, set_file, download, extract (text/list/table/network), screenshot (to a real PNG file), pdf, set_viewport, wait / wait_for, tabs, session save/load, done. Targets are element numbers, never raw selectors. |
|
|
154
|
+
| **Governor** (`governor.py`) | Classifies every action *before* execution and applies a policy: allow / ask / deny per class, a domain allowlist, blocked domains. Form submits and anything smelling like pay / send / delete / publish / transfer is **consequential**. |
|
|
155
|
+
| **Trail** (`trail.py`) | JSONL provenance: perceive → decide → govern → execute → result → stop (plus `heal`, `dialog`, `net`, and `download` events), with per-run accounting (steps, perception chars, ~tokens at chars/4, actions by class). Govern + execute are recorded **before** the action runs. |
|
|
156
|
+
| **Bodies** (`drivers.py`) | `FakeDriver` (in-memory mini-web for tests/demos) and `ChromiumDriver` (real Chromium via our own CDP client: auto-wait, tabs, session save/load, screenshots to disk, downloads/uploads, network capture, dialog policy, viewport emulation, PDF, env-proxy support with a credential-injecting local relay, stale-target detection). |
|
|
157
|
+
| **Brains** (`deciders.py`) | `ScriptedDecider` (explicit steps), `RuleDecider` (deterministic offline rules — "go to…", "click…", "type… into…", "search for…"), `OpenAICompatibleDecider` (any OpenAI-compatible endpoint; key from env only, never stored; wire protocol proven against a local stub server). |
|
|
158
|
+
| **Runner** (`runner.py`) | The loop, with a step budget, stuck detection (same action 3×, or an unchanged map for 3 steps), and self-healing: a target that moved mid-flight is re-found by descriptor and retried once, heal logged. Honest stop reasons: `done` / `budget` / `denied` / `stuck` / `error`. Silence is never consent: an "ask" with no approver is a denial. |
|
|
159
|
+
| **Replay export** (`export.py`) | Graduate a trail into a standalone Ghost Hands script that replays the executed steps deterministically — no model, still governed. Chromium body, or a fake body with the mini-web embedded. |
|
|
160
|
+
| **MCP server** (`mcp_server.py`) | Stdlib-only stdio MCP: `hands_perceive`, `hands_act`, `hands_run`, `hands_trail`. Consequential actions are denied on this channel (no approver) with an explanation. |
|
|
161
|
+
|
|
162
|
+
## CLI
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
ghost-hands demo # built-in fake-web demo
|
|
166
|
+
ghost-hands bench # 82-case verification suite
|
|
167
|
+
ghost-hands bench --live # + live cases: example.com, Wikipedia
|
|
168
|
+
ghost-hands run --script steps.json --driver fake # or --driver chromium
|
|
169
|
+
ghost-hands run --script steps.json --policy policy.json --approve-all
|
|
170
|
+
ghost-hands export trail.jsonl -o replay.py # graduate a trail into a script
|
|
171
|
+
ghost-hands export trail.jsonl --driver fake --pages pages.json -o replay.py
|
|
172
|
+
ghost-hands mcp # MCP server on stdio
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
See `examples/steps.json` and `examples/policy.json` for the file formats.
|
|
176
|
+
|
|
177
|
+
## How it compares
|
|
178
|
+
|
|
179
|
+
| | Driver stack | Intent layer | Governance / approval gate | Provenance trail | Run → script replay | Bodies |
|
|
180
|
+
|---|---|---|---|---|---|---|
|
|
181
|
+
| **Playwright** | Own protocol drivers for Chromium/Firefox/WebKit | None — deterministic scripts | None | Trace viewer for tests | Codegen records scripts | Web |
|
|
182
|
+
| **Playwright MCP** | Playwright via MCP (23+ raw tools) | The calling model, unmediated | None | None built in | No | Web |
|
|
183
|
+
| **Stagehand** | Playwright + AI primitives (act/observe/extract/agent) | Per-step LLM calls | None | Session logs | Action caching | Web (cloud browsers upsell) |
|
|
184
|
+
| **Browser Use** | Own browser agent loop | Full autonomous LLM loop | None | Run history | No | Web |
|
|
185
|
+
| **Jev** | Numbered control list, cheap decision pass | Single cheap pass per step | None (we built Agent Seatbelt for it) | Minimal | No | Web |
|
|
186
|
+
| **Ghost Hands** | **Own CDP stack, zero dependencies — no Playwright, no Selenium under the hood** | Pluggable: scripted, deterministic rules, or any OpenAI-compatible model | **Classify + policy + approval before every action; record-before-execute** | **Full JSONL trail with per-run accounting** | **Yes — trails graduate into Ghost Hands scripts** | Web today; phone (Android via MrGhosty) on the roadmap |
|
|
187
|
+
|
|
188
|
+
### Capabilities, feature by feature
|
|
189
|
+
|
|
190
|
+
Surveyed from each project's public docs (Oct 2026); "—" means not a
|
|
191
|
+
built-in of the tool as documented. Every Ghost Hands row is proven by
|
|
192
|
+
a named bench case on real Chromium unless marked (fake) — the bench
|
|
193
|
+
says which body each case ran on.
|
|
194
|
+
|
|
195
|
+
| Capability | Playwright | Stagehand | Browser Use | Ghost Hands |
|
|
196
|
+
|---|---|---|---|---|
|
|
197
|
+
| Numbered element map for a model | Via MCP / snapshots | observe | Yes (own format) | **Yes — DOM or Accessibility-tree eyes** |
|
|
198
|
+
| Shadow DOM controls | Yes | Yes | Partial | **Yes — open roots pierced (live map)** |
|
|
199
|
+
| Iframe controls | Yes | Yes | Partial | **Yes — same-page frames, tagged** |
|
|
200
|
+
| JS dialogs (confirm/alert) | Yes | Yes | Yes | **Yes — policy-driven, decision on the trail** |
|
|
201
|
+
| Downloads | Yes | Yes | Yes | **Yes — completion + size on the trail** |
|
|
202
|
+
| File upload | Yes | Yes | Yes | **Yes — `set_file`** |
|
|
203
|
+
| Network capture | Yes (HAR/request APIs) | Via Playwright | Limited | **Yes — `net` trail events + extract mode** |
|
|
204
|
+
| Fill a whole form in one step | No (per-field API) | act per field | Agent loop | **Yes — `fill_form`, per-field results** |
|
|
205
|
+
| Structured extract (list/table) | Manual locators | extract (LLM schema) | Agent loop | **Yes — deterministic, no model call** |
|
|
206
|
+
| Hover / double / right click / drag | Yes | Via act | Yes | **Yes** |
|
|
207
|
+
| Key chords (Control+a) | Yes | Via act | Yes | **Yes** |
|
|
208
|
+
| Raw coordinate clicks | Yes | — | Yes | **Yes — classified `write`, marked raw** |
|
|
209
|
+
| PDF export | Yes (Chromium) | Via Playwright | — | **Yes** |
|
|
210
|
+
| Device/viewport emulation | Yes | Via Playwright | Viewport opts | **Yes — named presets, perception follows** |
|
|
211
|
+
| Wait for text/element/URL | Yes | Via act | Agent loop | **Yes — honest timeout on the record** |
|
|
212
|
+
| **Every action classified + approval-gated** | **No** | **No** | **No** | **Yes — the whole point** |
|
|
213
|
+
| **Run graduates into a replayable script** | Codegen (records new) | Action cache | No | **Yes — from the trail** |
|
|
214
|
+
|
|
215
|
+
## Honest status
|
|
216
|
+
|
|
217
|
+
What is proven, and what is not — as of v0.3.0 (Oct 8, 2026):
|
|
218
|
+
|
|
219
|
+
- **Proven:** the full offline suite (170 pytest tests, 82 bench cases);
|
|
220
|
+
the Chromium driver on fixture pages (perceive / type / click / tabs /
|
|
221
|
+
session roundtrip / screenshots / graduated-script execution) and the
|
|
222
|
+
full v0.3 capability set on real Chromium (see the matrix note);
|
|
223
|
+
live runs on example.com and Wikipedia (`ghost-hands bench --live`,
|
|
224
|
+
2/2); the LLM decider's wire protocol against a local stub endpoint.
|
|
225
|
+
- **Unproven:** live-model driving quality (bring your own model; how
|
|
226
|
+
well it drives is the model's business, and no benchmark is claimed);
|
|
227
|
+
the Chromium driver against arbitrary third-party websites beyond the
|
|
228
|
+
two live cases above; head-to-head speed vs any other tool (never
|
|
229
|
+
measured, never claimed).
|
|
230
|
+
|
|
231
|
+
## Safety posture
|
|
232
|
+
|
|
233
|
+
- **No stealth.** Ghost Hands identifies honestly and never disguises
|
|
234
|
+
automation. Governance is the product; evasion is not a feature.
|
|
235
|
+
- **No stored keys.** The OpenAI-compatible decider reads
|
|
236
|
+
`GHOST_HANDS_API_KEY` / `GHOST_HANDS_BASE_URL` / `GHOST_HANDS_MODEL` from
|
|
237
|
+
the environment only.
|
|
238
|
+
- **Denied means denied.** A blocked, denied, or unapproved action never
|
|
239
|
+
executes — and the trail shows the verdict and the reason.
|
|
240
|
+
|
|
241
|
+
## Roadmap
|
|
242
|
+
|
|
243
|
+
- **Android body** — MrGhosty's accessibility service speaking the same
|
|
244
|
+
action protocol: one hands, phone + web.
|
|
245
|
+
- **GhostBus transport** — hands as a bus agent other agents can task.
|
|
246
|
+
- **Policy packs** — Seatbelt/GhostGuard policy bundles; approvals routed
|
|
247
|
+
over GhostBus or phone push.
|
|
248
|
+
|
|
249
|
+
## License
|
|
250
|
+
|
|
251
|
+
MIT — see `LICENSE`. © 2026 Ghost Developer Studio.
|