@harnessgg/electron
Published v0.1.0CLI harness for AI agents to interact with Electron apps via Chrome DevTools Protocol. Connect to any Electron app via CDP. Query elements, click, type, assert, screenshot, and evaluate JavaScript. Session is implicit — one JSON object per command.
npm install -D @harnessgg/electron Agents can file bugs or feature requests with curl -X POST https://harness.gg/api/submit using "package":"electron" in the JSON payload.
Prerequisite
Launch your Electron app with the CDP debugging port exposed:
$ electron . --remote-debugging-port=9222 Node.js ≥ 20 required.
Quick flow
# 0. Start app with CDP enabled $ electron . --remote-debugging-port=9222 # 1. Discover contract $ harness-electron schema # 2. Connect $ harness-electron connect --port 9222 {"ok":true,"session":"default","data":{"target":"My App"}} # 3. Inspect DOM $ harness-electron dom --format summary {"ok":true,"session":"default","data":{"interactive":[{"role":"button","name":"Sign in"}]}} # 4. Query a stable target $ harness-electron query --role button --name "Sign in" {"ok":true,"session":"default","data":{"elements":[{"elementId":"e1","role":"button","name":"Sign in"}]}} # 5. Interact $ harness-electron type --css "input[type=email]" --value "user@example.com" $ harness-electron click --element-id e1 # 6. Verify $ harness-electron assert --kind url --expected "/dashboard" {"ok":true,"session":"default","data":{"actual":"/dashboard"}} # 7. Screenshot $ harness-electron screenshot --path ./artifacts/dashboard.png # 8. Cleanup $ harness-electron disconnect
Schema examples
Each command returns one JSON object. Parse ok, then use data or error.
{"ok":true,"protocolVersion":"1.0","command":"click","session":"default","data":{"clicked":true,"target":{"elementId":"e1"}}} {"ok":false,"protocolVersion":"1.0","command":"click","session":"default","error":{"code":"TARGET_NOT_FOUND","message":"No element matched selector","retryable":true,"suggestedNext":["dom --format summary"]}} Command reference
connect harness-electron connect --port <n> [--host <h>] [--window-title <t>] [--url-contains <s>]
Connect to an Electron app via CDP. Session is implicit — do not pass --session unless running multi-session flows.
| Flag | Required | Description |
|---|---|---|
--port | yes | CDP port (e.g. 9222) |
--host | no | Host (default: localhost) |
--window-title | no | Filter targets by window title |
--url-contains | no | Filter targets by URL substring |
dom harness-electron dom [--format summary|tree|html] [--max-nodes <n>]
Inspect the DOM. Start with summary to discover interactive elements before targeting.
| Flag | Required | Description |
|---|---|---|
--format | no | summary | tree | html (default: summary) |
--max-nodes | no | Cap node count in output |
query harness-electron query <selector> [--limit <n>] [--visible-only]
Resolve elements and return persistent elementIds for reuse in later commands. Prefer over inline selectors for stability.
| Flag | Required | Description |
|---|---|---|
--css / --xpath / --text / --role / --testid | no | Selector strategy (one required) |
--name | no | Accessible name (use with --role) |
--limit | no | Max results |
--visible-only | no | Exclude hidden elements |
click harness-electron click <target> [--timeout <ms>]
Click an element. Use --element-id from query for stable targeting, or a selector flag.
| Flag | Required | Description |
|---|---|---|
--element-id | no | ID returned by query (preferred) |
--css / --xpath / --text / --role / --testid | no | Inline selector (one required if no --element-id) |
--name | no | Accessible name (use with --role) |
--index | no | Pick nth match (0-based, default 0) |
--timeout | no | Max wait ms |
type harness-electron type <target> --value <text> [--clear] [--timeout <ms>]
Type text into an input field.
| Flag | Required | Description |
|---|---|---|
--value | yes | Text to type |
--element-id | no | ID returned by query |
--css / --xpath / --role / --testid | no | Inline selector |
--clear | no | Clear existing content first |
--timeout | no | Max wait ms |
wait harness-electron wait --for visible|hidden|url|text [<target>] [--value <v>] [--timeout <ms>]
Wait for a condition. Rules: url requires --value and no target; text requires target + --value; visible/hidden require target.
| Flag | Required | Description |
|---|---|---|
--for | yes | visible | hidden | url | text |
--value | no | Expected value (required for url and text) |
--timeout | no | Max wait ms |
screenshot harness-electron screenshot --path <file> [--full-page] [<target>] [--timeout <ms>]
Capture a screenshot. No target = viewport. With target = element. --full-page cannot be combined with a target.
| Flag | Required | Description |
|---|---|---|
--path | yes | Output .png path |
--full-page | no | Full-page screenshot (no target allowed) |
--element-id / --css | no | Element screenshot |
--timeout | no | Max wait ms |
assert harness-electron assert --kind exists|visible|text|url [<target>] [--expected <v>] [--timeout <ms>]
Assert a condition. Returns ok:false with ASSERT_FAIL on failure — treat as test failure, not infrastructure failure.
| Flag | Required | Description |
|---|---|---|
--kind | yes | exists | visible | text | url |
--expected | no | Expected value (required for text and url) |
--element-id / --css / --xpath | no | Target (required for exists, visible, text) |
--timeout | no | Max wait ms |
evaluate harness-electron evaluate --script <js>
Execute a JavaScript expression in the page context and return the result as JSON.
| Flag | Required | Description |
|---|---|---|
--script | yes | JavaScript expression |
disconnect harness-electron disconnect
Close the default CDP session.
sessions harness-electron sessions list | prune
List persisted sessions or prune stale ones.
schema harness-electron schema
Emit machine-readable command and flag schema. Run this first for dynamic discovery.
capabilities harness-electron capabilities
Show a human-readable summary of what this harness can do.
Response shape
Every command writes a single JSON object to stdout. Check ok first.
Success
{
"ok": true,
"protocolVersion": "1.0",
"command": "click",
"session": "ses_a1b2c3",
"data": { "selector": "[role=button]" }
} Error
{
"ok": false,
"protocolVersion": "1.0",
"command": "click",
"session": "ses_a1b2c3",
"error": {
"code": "TARGET_NOT_FOUND",
"message": "No element matched",
"retryable": true,
"suggestedNext": ["dom --format summary"]
}
} | Field | Type | Description |
|---|---|---|
ok | boolean | true on success, false on error |
protocolVersion | string | Always "1.0" |
command | string | The command that was run |
session | string | Session ID (ses_xxx) |
data | object | Command-specific payload (success only) |
error | object | code, message, retryable, suggestedNext (error only) |
Error codes
| Code | Exit | Retryable | Action |
|---|---|---|---|
INVALID_INPUT | 10 | no | Bad or missing arguments. Fix the command before retrying. |
CONNECT_FAILED | 20 | yes | Could not reach CDP port. Verify the app is running with --remote-debugging-port. |
TARGET_NOT_FOUND | 20 | yes | No element matched the selector. Run dom --format summary and retry with a different target. |
INVALID_SELECTOR | 30 | no | Malformed selector. Run dom --format tree to rediscover structure. |
ACTION_FAILED | 30 | yes | Action executed but failed (e.g. element not interactable). Retry once. |
TIMEOUT | 40 | yes | Condition did not occur in time. Retry with a larger --timeout. |
ASSERT_FAIL | 50 | no | Assertion did not pass. Treat as test failure — inspect actual value in error.message. |
INTERNAL_ERROR | 70 | yes | Unexpected error. Retry once; if it persists, file a bug. |
Submit feedback
Agents can file bug reports and feature requests via POST /api/submit.
Issues land on harnessgg/Harness-electron.
| Field | Required | Values |
|---|---|---|
type | yes | "bug" | "feature" | "question" |
package | yes | "electron" |
title | yes | Short summary |
body | yes | Full description |
context | no | Session ID, OS, version… |
$ curl -X POST https://harness.gg/api/submit \
-H "Content-Type: application/json" \
-d '{"type":"bug","package":"electron","title":"connect fails","body":"Steps..."}'