Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@
"source": "./plugins/glm-plan-bug",
"category": "development",
"description": "Submit case feedback and bug reports for GLM Coding Plan service."
},
{
"name": "ghostlight",
"source": "./plugins/ghostlight",
"category": "development",
"description": "Governed, semantic browser control for coding agents."
}
]
}
}
17 changes: 17 additions & 0 deletions plugins/ghostlight/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "ghostlight",
"version": "1.0.0",
"description": "Governed, semantic tools for driving the user's real browser: navigate, inspect, find, click, fill, type, screenshot, record. Local by construction, with optional policy and audit.",
"author": {
"name": "sylin-org",
"url": "https://github.com/sylin-org"
},
"homepage": "https://sylin.org/ghostlight/",
"mcpServers": {
"ghostlight": {
"command": "npx",
"args": ["-y", "ghostlight"],
"env": {}
}
}
}
30 changes: 30 additions & 0 deletions plugins/ghostlight/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Ghostlight

Governed, semantic browser control for coding agents. Ghostlight's MCP server drives the
user's real, signed-in Chromium browser through 24 governed tools -- navigate, inspect, find,
click, fill, type, screenshot, record -- with per-action capability classification
(read / action / write / execute) and structured audit. Local by construction: no telemetry
and no update pings; the only network traffic is the checksum-pinned binary download from the
project's GitHub releases.

## MCP server

`npx -y ghostlight` -- the project's npm launcher. It verifies sha256-pinned binaries from
the official GitHub release into `~/.ghostlight/bin/v<version>/`, then hands its inherited
stdio to `ghostlight-mcp-connector`, which demand-starts the sibling local authority.
Requires Node.js 18 or newer.

The first real browser call walks the user through connecting the browser adapter (a
Chrome Web Store reviewed extension) if none is connected yet.

## Skill

`control-browser` teaches agents the observe-then-act handle model (target, view, and
snapshot handles), screenshot-bound coordinates, composition via `browser_sequence` and
`browser_flow`, dialog handling, and the effect-truth rules (never replay a call that is not
repeat-safe).

## Links

- Repository: https://github.com/sylin-org/ghostlight
- License: Apache-2.0 OR MIT
89 changes: 89 additions & 0 deletions plugins/ghostlight/skills/control-browser/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
---
name: control-browser
description: "Drive the user's real, signed-in browser through Ghostlight's governed tools. Use to open, navigate, inspect, find, click, type, fill forms, screenshot, upload, record, or verify web pages from an agent session, including web-UI testing, rendered-page reading, and form journeys. Prefer these tools over guessing at page structure or replaying raw browser commands."
---

# Controlling the browser with Ghostlight

These tools drive the user's visible Chromium browser through one governed path. Every call
returns one envelope: `status`, `effect`, `readiness`, `repeat_safe`, a Ghostlight-authored
`summary`, tool-specific `facts`, and up to two safe `next_steps`. Read the summary and
`next_steps` before deciding what to do next; they are written to be followed.

## Observe, then act

Perception handles are cheap and deliberate. Do not guess at page structure.

- `browser_inspect` lists semantic controls (role, accessible name, state) and returns
`target_` handles. `scope: "document"` returns a bounded structure tree under a `snapshot_`
handle and diffs it against the prior snapshot, so one extra inspect proves whether your
edit landed.
- `browser_find` ranks controls by visible or accessible text. Use it when you know the label:
the fastest route to a control is its name.
- Acting on a stale `target_` handle is refused on purpose: a navigation made the page unseen,
so observe again. `tab_` handles are different -- they are durable slots, and navigating
through a closed one recreates the tab under the same handle and says so.
- Typed selectors (`name`, optional `role`, optional `exact`) are accepted wherever target
handles are, including waits. Prefer a selector when stashing a handle adds nothing.

## Coordinates come from a view

Never invent pixel coordinates. `browser_screenshot` returns a `view_` handle that binds
coordinates to one tab, document generation, viewport, scale, and zoom. Click, hover, drag,
and wheel-scroll at `view_` pixels from the returned image; a bounded region capture returns a
new, magnified view for precision. Coordinate input on a stale view is rejected -- take a
fresh screenshot.

## Acting

- `browser_fill_form` fills 1 to 30 fields in one call and proves a contained submit before
clicking `submit_target`; it never submits without one. Use it over repeated typing.
- `browser_type_text` sends real per-character events, with `focused: true` to type into
whatever is focused and `clear_first` to replace. Use it when keystroke events matter.
- `browser_click` takes a target or a view point; `click_count` covers double and triple.
`browser_press_key` takes one key or a stroke sequence with repeat and modifiers.
- Credential-class fields (passwords, card numbers) stop before dispatch and ask for visible
user handoff. That refusal is a feature; do not route around it.
- `browser_upload` attaches local paths, inline base64 files (1 to 5, each and combined under
5,000,000 bytes), or a captured image, to a file input or dropped at a view point.
- `browser_execute` runs page JavaScript and can mutate or navigate anything. Use a semantic
tool whenever one fits; reach for execute only for what no other tool expresses.

## Composing steps

- `browser_sequence` runs 2 to 8 fixed steps (click, fill, type_text, press_key, scroll,
hover, wait) on one tab, stopping at the first failure. Use it for a known, stable journey.
- `browser_flow` runs 1 to 20 steps of any non-composite tool and lets later steps reference
earlier envelopes with `{"flow_ref": {"step": "id", "pointer": "/facts/..."}}`. Use
`dry_run: true` to decode and classify the whole plan before anything dispatches.
Compose journeys here when step outputs feed later inputs (open, then reuse the found
handle, then wait for its text).
- Every step is classified and audited independently under the invocation's authority;
composite wrappers add no power of their own.

## Waiting and dialogs

- `browser_wait` on `load_ready`, `url_contains`, `text_present` or `text_absent`,
`target_present` or `target_absent`, or `selector_present`. Bounded executor-side sleeps use
`duration` (0 to 10000 ms). A false condition is a decisive failed answer, not "unknown" --
do not retry blindly; observe instead.
- Per-call `timeout_ms` runs 100 to 30000, defaulting to 8000.
- A JavaScript dialog blocks its tab until handled. Check and resolve it with `browser_dialog`
(`status`, `accept`, `dismiss`, `respond`); deal with it before other work on that tab.

## Telling the truth about effects

- `repeat_safe: false` means the same call is known unsafe or of unknown safety to repeat.
Do not replay it; observe and decide.
- `effect` of `partial` or `unknown` means some work may have happened. Say so in anything you
report; never claim completion the envelope does not claim.
- Refusals name the deciding reason and the remedy. When a refusal surprises you, ask
`policy_explain` first: it compiles the authority in force, one line per capability, and is
always available.

## Recording evidence

`browser_record` makes a short, memory-only GIF: `start`, ordinary work, then `save` (to a
file input, a download, or back to you) or `discard`. Frames never leave the browser except
by your explicit save. A replay is a human-scale artifact: report what it shows and how long
it plays, and let the facts carry the byte counts.
Loading