GlassPane
English · 简体中文
Power your agent
คำสั่งของผู้เผยแพร่เอง ไม่ใช่เอนด์พอยต์ของ PlugMCP
Host a copy with our keys and logs.
npx -y [email protected]Claude Code ไม่มีลิงก์ติดตั้งสำหรับคำสั่งแบบโลคัล ให้คัดลอกคำสั่งด้านล่างแล้วรันในเทอร์มินัล
claude mcp add glasspane-mcp -- npx -y glasspane-mcp@1.31.6รันในเทอร์มินัล
{ "mcpServers": { "glasspane-mcp": { "command": "npx", "args": [ "-y", "[email protected]" ] } }}claude_desktop_config.json
URL แบบรีโมตหรือคำสั่งบนเครื่องของคุณ? การติดตั้งสองแบบต่างกันอย่างไร
รันบน PlugMCP
A new server you create. It is not this listing's official endpoint. Use the publisher install when you want their URL and their credentials.
เปิดจากผู้เผยแพร่
English · 简体中文
GlassPane MCP stdio shell: JSON-RPC 2.0 over stdio bridging an AI agent to the glasspane engine daemon
GlassPane is a macOS runtime-verification layer for AI coding agents. Your agent can write the code, run the linter, and pass the unit tests. It cannot tell you whether the settings toggle it clicked actually flipped — because for a GUI app, the agent has no way to observe the interface. So either it declares success unverified, or it grabs a screenshot and guesses at pixel coordinates.
GlassPane supplies that missing half of the loop. It exposes a macOS app's interface as a structured, scriptable test surface over MCP: your agent performs an accessibility action and gets back the change it caused — an element-identified tree diff and a numeric pixel measurement — not an image it has to squint at. It can assert element state, roll the app back to a checkpoint, and export evidence a human can audit. Build → reach a state → operate → observe → diagnose → fix → re-verify, without a human in the middle of every round.
The operating mechanism is a closed loop:
attach → observe → act → measure the change → assert → diagnose if nothing moved
→ roll back to the checkpoint → export the evidence pack
GlassPane is one half of a pair. The other half is GlassPane Harness, a coding agent for the terminal that carries the same gp_* surface natively. The two projects are installable and usable separately, but they are designed around one contract:
glasspane-mcp exposes the measurement over MCP to Claude Desktop, Cursor, or any other MCP host. Install with the one-command installer below.gp_* tools, appends verified calls to a hash-chained decision log, and re-injects those evidence anchors when a long session is compacted. Install it from npm; it expects the engine to be running with Accessibility granted and prints the exact remedy when it is not.The division of labour is the same as the one described above: the engine decides what the application did, and the harness transcribes; it never invents a verdict. Neither product is a client of the other's private API — both consume the same published contract layer, so the formats that cross the boundary are one definition rather than two files evolving apart. The harness is installable on its own:
# The agent side. Requires the engine below to be installed and running with Accessibility granted.
npm install -g glasspane-harness
The rest of this document describes this repository: the engine, the MCP shell and the installer. The harness has its own README — GlassPane Harness (source
harness/glasspane-harness/README.md).
On macOS, an agent's toolchain covers the static half of development well: compile, type-check, review, run tests that live in the terminal. The runtime half of a GUI app is where it falls off a cliff:
Without the second row you don't have an autonomous macOS developer, you have a code typist that reports optimistically. The consequences are concrete: "the checkbox is wired up" turns out to mean the action handler never fired; a layout regression ships because nobody looked; a fix is applied three times because the agent can't see that the first two didn't take.
GlassPane gives the agent eyes and hands with an accountability trail:
gp_act performs an accessibility action on an element it identified by role/title/hierarchy, and reports whether the UI responded;gp_observe returns the accessibility tree; gp_assert_element checks one of the five element properties (title / value / role / enabled / focused) as a pass-fail result; the affected window region is measured for pixel change;gp_diagnose classifies a non-effecting operation: nothing changed, it changed late, or a concurrent human hand contaminated the measurement;gp_snapshot / gp_restore take the app back to a prior state, so the agent can re-run a test instead of leaving your machine in a half-configured mess;gp_export_evidence / gp_recent_reports render the whole thing as an HTML or Markdown report that comes back as text in the session — they take no path and write no file, so saving it for a browser or beside a commit is your step; the settings panel's report button is the only writer of a report file.Taking a screenshot and asking a vision model about it is a real option, and it is what most agent setups fall back to. It is the wrong tool for a verification loop, for reasons that have nothing to do with model quality:
The important line is the last two. A screenshot workflow cannot answer "put it back", and it cannot answer "show me" without re-opening the conversation.
To be fair about the trade-off: a vision model can still judge things GlassPane does not — visual taste, whether a design looks right, or content in a view that exposes no accessibility tree at all. GlassPane measures; it does not have taste. Use both for what they are good at.
The shared schema contract layer is the author's iterate ecosystem kernel, published as iterate-kernel: the same JSON Schema definitions are consumed by iterate's multi-round review loop and by the GlassPane daemon and MCP shell, with dual-language bindings checked against shared fixtures. The two halves are complementary — iterate reviews whether the code is right; GlassPane verifies whether the running app actually does what the agent claims it made it do. Each TypeScript consumer installs that package: mcp-shell bundles it into glasspane-mcp (so the published artifact carries no file: dependency back to this repository), and the fork resolves it through its own lockfile with provenance in harness/glasspane-harness/contracts/kernel-pin.json. kernel/ therefore holds only the pinned copy of that package's corpus — fixtures/ and schemas/ — because the Swift C35 leg and the release archive's requirement list read those bytes and cannot import TypeScript.
This repository also dogfoods that ecosystem: ITERATE.md and iterate.config.yaml are its own onboarding artifacts, so an /iterate run here reviews code against the same validation commands CI enforces. Verified 2026-09-22: iterate doctor 18 checks ok, iterate fingerprint no drift.
tools/list is the authoritative surface.title / value / role / enabled / focused, as booleans with the selector that was resolved.gp_audit_ui walks element geometry and applies deterministic rules: zero-sized or out-of-window controls are blocking; undersized hit targets, clipped elements and overlapping targets are advisory. Geometry it could not read never counts toward a pass, and a truncated or budget-stopped scan says so. On large interfaces the walk can stop early by design; it then reports what it measured plus complete: false rather than nothing.soft by default; strong when the app under test embeds the probe SDK and confirms its own handler ran; weak only when contamination dominates.gp_capture_view hands one PNG of the window to your model when the question is genuinely visual (does this look right). It is a pass-through: the engine encodes and writes nothing, the image travels into the conversation and stops there.gp_project_*.macOS 14+. npm first — one command, and it is also what leaves glasspane doctor / glasspane update
behind for later:
npx glasspane-install
The same install over the script channel (fetch, then run — two steps on purpose: piped into sh, a
failed curl leaves stdin empty, sh reaches EOF and exits 0, so an install that did nothing reports
success):
curl -fsSL https://raw.githubusercontent.com/jingzhao-l/GlassPane/main/install.sh -o /tmp/gp-install.sh && sh /tmp/gp-install.sh
Either way it fetches the pinned release tag, so the build is reproducible; see Channels for the third path and what each one costs.
When the panel opens, grant Accessibility, Input Monitoring and Screen Recording for GlassPane Daemon. macOS forbids programmatic granting, so this is the one manual step; the panel walks you card by card and re-measures after each tick.
The installer prints a ready-to-paste block with your real paths:
{
"mcpServers": {
"glasspane": {
"command": "node",
"args": ["<your checkout>/mcp-shell/dist/index.js"],
"env": { "GLASSPANE_ENGINE_SOCK": "/Users/you/.glasspane/engine.sock" }
}
}
}
The shape that works:
Build and launch the app, open Settings, toggle Dark Mode with
gp_act, assert the checkbox is now checked withgp_assert_element, and if anything didn't take,gp_diagnoseit. Roll it back afterwards and show me the evidence.
You get a verdict with a before/after delta attached, and a report gp_export_evidence returns as HTML/Markdown text in the session (it writes no file — only the panel's report button does).
If you want the agent side of the loop instead of wiring your own host, install GlassPane Harness after step 2.
The installer's preflight probes the rows of this table that name something it can actually ask the host for — the Swift toolchain (swift), Node.js ≥ 18 (node) and git — plus npm and open, which the table does not list because they are not requirements a person chose to satisfy but parts of what those rows install. In total it checks five commands, and installer/cli.js:PREFLIGHT_PROBED_COMMANDS is where that count is read from; a missing one stops the install with a per-item report. The macOS 14+ and Python 3.11 rows are not probed at install time and the table says how to check them yourself: the macOS major version is enforced when LaunchServices opens the bundle (LSMinimumSystemVersion = 14.0), and python3 is needed only by the LLDB bridge test suite, so a missing one surfaces as that suite failing rather than as an install refusal. For the commands it does probe there is no "assume present" path, and nothing silently stands in for the rows it does not probe — each of those says who checks it.
All three reach the same code. The two one-command channels clone the same pinned release tag rather than a moving branch, so two installs on the same day get the same source. npm first: it is the shortest path, it is the one that also leaves the glasspane command on your PATH, and it is the same channel the updater's own remedy hands out when a machine cannot refresh its global layer.
# 1) Through npm (bootstraps its own clone of the pinned tag, then builds and installs).
# Add `-g` if you want the `glasspane` command to stay: `npm install -g glasspane-install`,
# then `glasspane-install`, and afterwards `glasspane doctor` / `glasspane update`.
npx glasspane-install
# 2) Fetch then run. Kept in two steps: with `curl … | sh`, a curl that fails leaves `sh` reading
# an empty stdin, and the pipeline exits 0 — the exit code is exactly what an absent-minded
# agent or CI reads, so it has to be the real one.
curl -fsSL https://raw.githubusercontent.com/jingzhao-l/GlassPane/main/install.sh -o /tmp/gp-install.sh && sh /tmp/gp-install.sh
# 3) From a checkout you manage. `install.sh` pins one release tag (its `GLASSPANE_RELEASE` default,
# rewritten by `scripts/set-version.mjs` on every release) — clone that tag, not `main`, unless you
# mean to install an unreleased tree. The tag below is not verified by eye: it is a derived site
# owned by `scripts/version-sites.mjs`, and `scripts/check-doc-links.mjs` reddens when it stops
# matching install.sh.
git clone --branch v1.25.2 https://github.com/jingzhao-l/GlassPane.git && cd GlassPane && node installer/cli.js
What npm does not deliver: the Swift engine. Every channel above ends in the same swift build
against your Command Line Tools, because glasspane-mcp on npm is the transport and
glasspane-install is the installer, not a prebuilt app bundle. Saying it the other way round would
send someone to install the requirements table above and then wait for a binary that never arrives.
glasspane-install puts a second command on your PATH, and that command is the answer to "the panel's
button failed and I do not know where my install went":
glasspane doctor # reads the machine: install pointer, updater state, the loaded daemon job, the
# socket, and the two global npm packages. One line each, and a line that cannot
# be read says so — "absent" and "I could not look" are different answers
glasspane update # check, then install what passed; exits with the updater's own code
glasspane status # the updater's one-line summary, verbatim
It resolves everything through ~/.glasspane/update-install.json, which is the file the installer
writes and the panel reads, so it cannot start guessing at a checkout. It runs no sudo, deletes
nothing, and where a repair needs a person it names the tool and the directories instead of handing
out a command that escalates.
GLASSPANE_REF=<tag> selects another release; GLASSPANE_REF=main tracks the trunk, which is not a fixed artifact. --no-prompt --no-gui is a silent install; --help lists every flag.
GlassPane Daemon) — not your terminal, not the settings window.Before installing on anyone else's machine: builds are ad-hoc signed (codesign --sign -), not Developer ID, and not notarized. On your own Mac that is invisible; for outside users Gatekeeper refuses the first launch until they allow it under System Settings → Privacy & Security. Notarization removes that step and is a deferred, cost-gated decision (Apple Developer Program membership) — recorded in the P6 publish record. A "one-command install" that has a known manual step in it should say so.
launchctl bootout "gui/$(id -u)/com.glasspane.daemon" 2>/dev/null
launchctl bootout "gui/$(id -u)/com.glasspane.update" 2>/dev/null
rm -f ~/Library/LaunchAgents/com.glasspane.daemon.plist
rm -f ~/Library/LaunchAgents/com.glasspane.update.plist
rm -rf ~/Applications/GlassPane.app ~/Applications/"GlassPane Daemon.app"
rm -rf ~/.glasspane
Then delete the GlassPane Daemon rows from the privacy lists in System Settings. If only the launchd job was lost (common while waiting for a permission tick), recover it without retyping launchctl:
node installer/cli.js --restore-launchd
The installer registers a per-user job that asks the release page once a day and, when it is allowed to, swaps in the new version. The page that drives it is the 更新 (Updates) section of GlassPane.app — the panel's labels are Chinese-only today, so they are quoted as they appear.
What gets updated: the two bundles in ~/Applications (settings panel and daemon; the daemon is restarted as part of the swap) and the two global npm packages, glasspane-mcp and glasspane-install. All of it comes out of one release archive whose checksum was verified — the npm packages are packed from that same verified tree instead of being fetched from the registry, so the code that was checked and the code that lands cannot be two different things.
When: one run a day at a fixed local time, 12:00 by default (enable --hour 3 --minute 45 moves it). A swap only happens while the daemon is idle, so an update never starts in the middle of a run your agent is performing on screen; a busy daemon defers that round and the next slot retries.
Do it right now, by hand: press 「立即检查」 (check now) to fetch and verify, then 「安装更新」 (install update) to apply what passed. The card above the buttons shows current version, newest version, when it last checked, the version waiting, and its full sha256 — copy it and compare against the release page if you want to be sure of what you are installing. gp_diagnose answers the same question for an agent: whether this machine is behind, and as what. Or from a terminal, without hunting for where the install went: glasspane update (and glasspane doctor when something did not take).
One half failing does not cancel the other. The update has two layers — the two .app bundles, and the two global npm packages. If this run cannot reach npm, or cannot write where npm puts a global package, the bundles still install, the daemon still restarts and is read back, and the verdict is applied carrying npm-not-refreshed: the same sentence then names the one command that finishes the rest (npm install -g glasspane-mcp@<version> glasspane-install@<version>), and it keeps being shown on the page and in gp_diagnose until that line has been run. This replaced a whole-update refusal that had been leaving machines on an old version for days, over a global layer they had never had anyway.
A button that has nothing to do stays visible and disabled, with a reason line under it — the panel never hides a control to avoid explaining it, and never shows a failure as a success.
A major version is never applied on a schedule. It waits as an offer, with the reason on the page (跨大版本升级,可能改变对外行为), and pressing 「安装更新」 is what confirms it. Nothing is skipped silently: --consent major is that button's effect, and the scheduled run does not have it.
A release nobody signed is not installed by the schedule either. Every release from v1.5.0 onward publishes a detached GPG signature over its checksum file, and signing is a step the release workflow cannot skip: if the signature is not produced and is not non-empty on disk, the Release is never created. Verified against the key shipped with this program, that is what turns "who published this" from an assumption into a checked claim (and it means exactly matches the key we ship). The older tags are the ones with nothing to check — v1.4.0 shipped without its .asc (the signing step was silently skipped and the two files were back-signed by hand afterwards), and v1.3.1 predates the signing job. So: if there is nothing to check — no signature published, or no gpg on the machine — the daily run stops and says so on the page; you may proceed once by hand with updater check --consent unsigned-release, and the state file and gp_diagnose keep reporting that release as installed without authorship proof. A signature that is published and does not check is refused outright: no consent overrides it. The 「安装更新」 button does not grant this one — it only ever carries --consent major — but you do not need a terminal for it: when that gate is the reason the check stopped, the same page offers 「信任这个发布并重新检查」, and pressing it is updater check --consent unsigned-release. The terminal form remains the fallback for a headless machine.
Turn automatic update off for good — any one of these, and the last is the strongest:
node installer/cli.js --no-auto-update # at install time: the job is never registered
node "<updater>" disable # any time later; `enable` reverses it
GLASSPANE_UPDATE_DISABLE=1 # also refuses a later enable, so it survives re-installs
<updater> is the program path the page itself lists under 更新器 → 程序. Off is not mute: the page keeps reporting 自动更新已关闭 with the time of the last check, and check/install still work by hand — the switch governs the schedule, not your ability to update.
Machine was asleep or switched off at the fixed time: macOS replays a run missed while asleep, but not one missed while powered off. So nothing depends on that: unless the page has something more specific to tell you (a version waiting, or a refusal and why), a check older than 36 hours is reported as 检查已过期, with how long ago it actually looked and the check button live.
"The rollback needed a human" means exit code 5 — the new version went in, failed the read-back check after restart, and putting the old version back did not verify either. The tool stops guessing from there: 「安装更新」 is disabled and its reason line tells you to reinstall by hand (自动退回没成功,请先人工重新安装) — that is, re-run the installer so ~/Applications is rebuilt from source, then reopen this page. When the restore does verify (exit code 4) you are back on the previous version and the page says so plainly.
A test job is a sequence the agent can execute and verify, not a question it has to interpret. The four verbs map directly onto the tool surface:
Two rules of thumb make the difference between a verification and a guess:
gp_restore, so a failed attempt does not accumulate on your machine.The terminal is for installation, service liveness and the update line — not for driving the app. Driving an app goes through MCP from the host.
# Install / repair / re-register the launchd job
node installer/cli.js
node installer/cli.js --restore-launchd
# Ask the daemon itself whether it is alive (the panel is not the service)
printf '{"id":0,"method":"hello"}\n' | nc -U ~/.glasspane/engine.sock
# Check the updater and the version line
node "<updater>" check
node scripts/check-version.mjs
Two equivalent forms for an MCP client (the package installs a third command, described below):
// from a checkout — exactly what the installer prints
{ "mcpServers": { "glasspane": { "command": "node", "args": ["/path/to/GlassPane/mcp-shell/dist/index.js"] } } }
// from npm — same tools, global command
{ "mcpServers": { "glasspane": { "command": "glasspane-mcp" } } }
npm i -g glasspane-mcp installs the transport layer only; the daemon still comes from the installer above. With the daemon unreachable or a permission missing, tool calls return a structured error containing the exact remedy command — you should not need a document to get unstuck.
The same package installs a second command, glasspane-http (and publishes it as the ./http-gateway export — measured from mcp-shell/package.json's bin and exports). It is not a third MCP form: it bridges HTTP/REST callers onto the same daemon socket, it is started by nobody except you, and its trust boundary — loopback-only bind, a bearer token you must supply, and the fact that it exposes act, attach, restore and snapshot — is spelled out in SECURITY.md §2.3.
Stated plainly, because these determine whether it fits your workflow:
.onDrag session (measured, not assumed). Button/menu/value-stepper flows are covered; a drag-and-drop-only feature is not drivable yet.gp_act performs press, increment, decrement, showMenu, confirm, cancel, pick. It does not write element values directly and does not post synthetic HID events, so free-text typing into a field is out of scope.gp_capture_view plus a vision model — earns its place.gp_capture_view exists for taste and gestalt, which no rule can judge. But it does not repeat, it cannot be asserted, and it is bounded by the daemon's frame budget (a large window is refused with a suggested scale rather than quietly downsampled). Ask it "does this look wrong"; do not ask it "did the checkbox change", because that is what gp_assert_element is for.strong attribution requires a cooperating app. It means the app's own embedded probe confirmed the handler ran — see SECURITY.md for what that does and does not prove.tools/list at runtime is authoritative; this is a map.
gp_audit_ui records no operation and writes no evidence pack: it measures the interface as it currently stands, which is why its verdict is allowed to answer insufficient instead of confidently clean. Geometry is deliberately kept out of the tree digest — a hover, an animation or a moving cursor must not be able to make "did this action change this screen?" answer yes.
Each operation produces a versioned glasspane.evidence pack (JSON; schema in kernel/schemas) holding:
changedPixelRatio and bounds; raw screenshots are not persisted);soft by default, strong only when a live GlassPaneProbe in the target app confirms the handler executed, and weak only when contamination is measured for that window;gp_restore replays.GlassPane is one half of a pair. The other half is iterate-harness, the loop that reviews and fixes the code an agent changed here. The two do not talk through a chat log: everything that crosses the boundary is written by one side as a verifiable record and read by the other.
gp_last_evidence is the call that answers with an evidence pack — the other four accept a dimension and return no pack, which is why a dimension declared on them is reported as unverified — and the harness appends a hash-chained entry for every decision recorded from a pack: ~/.local/share/glasspane-harness/decisions.jsonl, or wherever GLASSPANE_DECISION_LOG points. The review loop writes its own decisions to .iterate/decision-log.jsonl in the project under review, in the same chain format, so a claim quoted from the other side's file is verified before it is used: a rewritten line is refused with the number of the line where the chain stops, and the answer is never "let me read it leniently instead". The reader that runs in production today is the loop's — fix_proof verifies GlassPane's ledger before citing it. The fork carries the same verifier, and a fixed-point test pins that a chain written by the loop verifies there; its own production path writes its ledger rather than reading the loop's. A project can name the other harness's ledger as its source of fix evidence once, with ih iterate glasspane-ledger <absolute path>: the link is written only after the whole chain verifies, and it pins the chain's first entry — a ledger that was replaced rather than extended stops qualifying.gp_* tools take an optional dimension argument on each surface, and they are the same five: gp_act, gp_observe, gp_diagnose, gp_last_evidence, gp_attach. gp_probe_status takes none on either surface, on purpose: a self-report produces no evidence frame, so a declaration on it could never be counted against a decision. What echoes the declaration back is the surface you called — the MCP shell or the fork — not the engine: dimension is stripped before a request leaves, the engine never sees the word, and the echo line is written by that surface. The loop witnesses the echo, and a decision that contradicts what was already witnessed for that operation id is refused (KERNEL_E_DIMENSION_CONTEST) instead of quietly becoming a second record.gp_last_evidence plus one gp_diagnose per recorded operation; the allow-list that decides what may be asked at all is the five read-only tools (gp_probe_status / gp_observe / gp_diagnose / gp_last_evidence / gp_recent_reports). A call that would mutate the app is refused by name; nothing in this channel can click for you..iterate/run-plan.json, or GLASSPANE_RUN_PLAN) decides what goes first: history of dimensions this run never planned is dropped before history of the dimensions it did, and the injected block says which rule it used. Where a declared dimension could not reach an anchor — the engine attaches an evidence pack to gp_last_evidence alone — the block prints how many declarations were lost, so that gap is a reading rather than a paragraph someone hopes is still true.recipeConfigPath, or GLASSPANE_RECIPE), and a chain-verified ledger line recording a passing outcome against an operation id. Anything absent or unmeasured is refused by name (RECIPE_GATE_E_*). The answer is recorded in the project's ledger — on the round that sends, and on a round that passed and therefore sent nothing (from iterate-harness 2.11.1) — while a contract refusal writes no ledger bytes, because a decision that was never made must not become an audit entry. Both doors read it back: /iterate gate in a session, ih iterate gate in a terminal.What stays where it belongs: the engine decides what the application did, and neither harness judges an interface on its own. The gate reports and withholds; it does not run the recipe, because neither product ships a recipe executor — the progress pointer is written by whoever performs the fix. Both halves consume the same published contract layer, iterate-kernel, so the formats above are not two files evolving on their own: there is one source for each format, the Python side pins the corpus it codes against by sha256, and a change to the published contract reddens a hash check before it can become a silent re-generation. The boundary is worth naming: whether the two implementations still agree on a case the corpus never wrote down is answered by another command — scripts/diff_kernel_implementations.py, which drives the same corpus through both and compares verdict by verdict. It is an operator command, not a CI step, so it counts when someone runs it.
GlassPane has one configuration surface for the engine and one for each consumer. None of it is a config file you edit by hand: the installer writes the service paths, the MCP host owns its own JSON block, and the harness reads its own run plan and recipe.
Application-specific settings live with the app, not in a global file. gp_project_set registers an app by bundle id; gp_project_get reports the resolved storage paths, recipe and calibration roots; gp_project_list shows what is registered. The records are what the evidence packs and the review-loop gate read, so changing them changes what "verified" means for that app.
The daily check is a launchd job; its time and consent level are the updater's, not the panel's. enable --hour 3 --minute 45 moves the slot; the panel's buttons are the same commands with the same consent semantics described under Keeping GlassPane up to date.
Gatekeeper blocks the app / "unidentified developer". Expected — builds are ad-hoc signed and notarization is a pending decision (see Installation). Allow it under System Settings → Privacy & Security, then reopen.
I ticked the permission and the card is still red. It was probably ticked for the wrong subject: the entry must be GlassPane Daemon, not your terminal and not GlassPane.app. The card shows the subject it measured; run node installer/cli.js --restore-launchd to move the service under launchd and re-verify.
Panel is open but tools error. The panel is not the service. Ask the socket itself: printf '{"id":0,"method":"hello"}\n' | nc -U ~/.glasspane/engine.sock returns the running daemon's hello — its version, capabilities and state root — and that is the liveness read. Do not substitute glasspaned --permissions: that flag measures the TCC seats of whichever process runs it and opens no socket at all (its own --help says so), so a green JSON there says nothing about the service. If an older build holds the socket, re-run the installer with --replace-daemon — otherwise the app you granted permission to is not the app doing the work.
The agent says the change happened but the UI did not move. That is the case gp_diagnose exists for; it separates "no structural change", "change arrived late", and "input contamination". If your feature is drag-only, check What it cannot do first.
Which macOS versions are supported? 14 and later; that is what the accessibility, event-tap and screen-capture behaviour is measured against.
Does anything leave my machine? No. Local unix socket, local stdio process, evidence under ~/.glasspane/. But gp_observe returns accessibility trees into the agent conversation, so whatever your model provider logs, it logs that tree — treat transcripts as sensitive.
Which version am I running? The daemon prints its own version on glasspaned --version — --permissions does not carry a version key, it only measures the TCC seats — the panel shows the same value, the MCP initialize response echoes it, and node scripts/check-version.mjs prints every place the version appears. All of it comes from one number (CHANGELOG.md).
GlassPane holds Accessibility, Input Monitoring and Screen Recording, registers a launchd job, reads the event stream and can attach a debugger. It is powerful and it is attack surface. How to report a vulnerability, and the threat model in detail, are in SECURITY.md (简体中文). Please don't open a public issue containing logs or evidence packs.
GlassPane/
├── install.sh one-command entry: locates/fetches source, delegates to installer
├── installer/ zero-dependency Node installer → npm `glasspane-install`
├── engine/ Swift package: glasspaned daemon, settings GUI, accessibility channel
│ ├── probe/ GlassPaneProbe SPM package (embed it for strong attribution)
│ └── scripts/ make-app.sh — bundle + ad-hoc sign the two .app products
├── mcp-shell/ TypeScript MCP stdio server → npm `glasspane-mcp`
├── kernel/ pinned corpus (schemas + fixtures) of the published iterate-kernel
├── bridge/ Python LLDB bridge (crash / runtime capture)
├── updater/ the daily update job and its consent gates
├── harness/ GlassPane Harness fork (own repo, own release line; excluded from this product's archive)
├── spike/ feasibility experiments and recorded results
├── scripts/ set-version / check-version — the single version line
├── specs/ implementation specs + acceptance records (PRD, P0–P6, audits)
├── ITERATE.md this repo's own iterate onboarding knowledge base
└── .github/workflows/ ci.yml (10 lanes; the publish-shape guard is a step in one of them), release.yml
Setup, the per-layer test commands, the commit and PR conventions, and the rules for writing tests that must not touch a developer's real ~/.glasspane are in CONTRIBUTING.md (简体中文). The short version:
npm ci && npm run build && npm test --workspaces --if-present # TS workspaces: mcp-shell, installer, updater (kernel/ has no package.json)
swift build --package-path engine && swift test --package-path engine # Swift engine
swift test --package-path engine/probe # probe SDK
python3 -m pytest -q bridge # LLDB bridge
node scripts/check-version.mjs # version-line drift guard
CI also runs a publish-shape guard: it bundles glasspane-mcp, packs it, installs the tarball into a clean directory and completes an MCP initialize handshake — because packaging faults (a dangling file: dependency, a missing schema) only ever appear in the published artifact.
Acceptance steps that need a real GUI session cannot run in CI by design; they are recorded as hardware smoke runs in engine/smoke.md instead of being silently skipped.
Releases: node scripts/set-version.mjs <semver> writes the whole version line; pushing a tag produces a GitHub Release whose archive is the tagged tree — less harness/, the vendored fork no install step reads and which is 86.9% of the repository's tracked bytes (64,535,347 of 74,253,356, measured 2026-10-20 — recompute it with git ls-tree -r -l HEAD, summing blob sizes per path) — plus the built JavaScript the updater cannot produce on the target (mcp-shell/dist, mcp-shell/schemas — scripts/make-release-archive.mjs), together with SHA256SUMS-<version>.txt (the version is part of the file name — the updater asks for that name); npm publishing goes through release.yml with provenance.
specs/ is the design-of-record and the acceptance ledger (Chinese). It is where claims get specified and marked verified or not, so it is the closest thing to a reference manual:
The sibling product's documents live with it: GlassPane Harness documentation covers install, the tool surface, the evidence discipline and the release line.
GlassPane drives real applications on a real desktop with permissions that let it read the screen and act on other apps' interfaces. Point it at apps you intend to control, keep the evidence directory out of shared locations, and treat exported reports as containing whatever was on screen. Attribution verdicts are measurements and inferences, not guarantees about a program's internals — an app that misreports its own accessibility tree can still mislead any observer, which is why the probe path exists.
MIT — see LICENSE.
GlassPane MCP stdio shell: JSON-RPC 2.0 over stdio bridging an AI agent to the glasspane engine daemon
{ "mcpServers": { "glasspane-mcp": { "command": "npx", "args": [ "-y", "[email protected]" ] } }}เครื่องมือ
ยังไม่มีรายการเครื่องมือ เซิร์ฟเวอร์แบบรีโมตจะได้รายการหลังการตรวจสอบสถานะครั้งแรก
FAQ
คัดลอกคอนฟิก stdio สำหรับ Cursor, Claude Desktop, Claude Code หรือ VS Code ได้ในหน้านี้ คอนฟิกนี้ใช้การติดตั้งของผู้เผยแพร่ ไม่ใช่พร็อกซีของ PlugMCP
ระเบียนนี้ไม่ได้ระบุตัวแปรสภาพแวดล้อมที่จำเป็น
Glasspane ทำงานแบบโลคัลผ่าน stdio
ตรวจสอบล่าสุดเมื่อ 2026-11-15 GlassPane MCP stdio shell: JSON-RPC 2.0 over stdio bridging an AI agent to the glasspane engine daemon