Cross-layer action verification
One sense lies. A screenshot can't tell a spinner from a frozen app; systemd can't
see a dialog. Fuse both and you can tell a real success from a no-op — the thing that
makes long-horizon work survivable. This skill encodes the loop:
begin → act → read both senses → end → reconcile.
The loop
os_verify action=begin — snapshot the baseline. Pass the units the action
should affect (e.g. ["nginx.service"]), optionally expect (unit → wanted state,
e.g. {"nginx.service": "active"}), and scope (system|user). Keep the returned
token.
- Perform the action with whatever tool does it — a
screen_click on the GUI
button, an os_service restart, a manual step.
- Read the pixel signal (only if a GUI was involved). Two options:
screen_verify — preferred. It polls until the screen settles or a timeout,
grades the GUI itself (CONFIRMED/PARTIAL/NO_OP/DIVERGED), and returns a
pixel block ready to hand straight to step 4. Takes expect_text / expect_gone
/ expect_change, so you can assert the button's effect rather than just "something
moved". Use this when the GUI effect may take a moment to appear.
screen_sense — passive. Returns {"pixel": {changed, opened, modal, no_op, activity}} for whatever the last action already left behind, with no waiting. Use
it when the action is known to be instantaneous, or when you have already screenshotted.
os_verify action=end — pass the token and, if you have one, pixel=<the pixel object from screen_verify or screen_sense>. It re-reads systemd + journald
and returns the verdict.
Both emit the same {"changed": bool, ...} contract; os_verify reads changed and
ignores the rest, so either is safe to pass.
Worked example (verified live)
os_verify action=begin units=["dbus.service"] -> token
screen_click / os_service / manual step
screen_verify expect_change=true region=[...] -> {"verdict":"CONFIRMED","pixel":{"changed":true}}
os_verify action=end token=<token> pixel={"changed":true}
A GUI-only action (a hover) against an untouched unit returns
status: DIVERGED, cross_layer: "pixel-changed-os-static", reconciled: false.
An inert action on both layers returns status: NO_OP, reconciled: true,
cross_layer: null. Both quadrants were exercised end-to-end against a live desktop.
Reading the verdict
| status |
meaning |
do |
| CONFIRMED |
expectation met (or a plausible OS effect happened), no journal errors, layers agree |
proceed |
| PARTIAL |
some expected units met, others not |
inspect the per-unit block; finish the rest |
| NO_OP |
nothing changed at the OS layer and (if given) the screen was static |
the action did nothing — re-ground and retry, don't build on it |
| DIVERGED |
a unit failed, journald logged errors, OR the layers disagree |
STOP. Read cross_layer + journal.sample. Do not assume success. |
cross_layer: "pixel-changed-os-static" is the signal to care about most: the GUI moved
but the service never did — the button "worked" visually and did nothing real. That is
exactly the silent failure that compounds over a long task.
When to reach for it
- After clicking a control in a GUI that is supposed to drive a service (restart, apply,
enable) — the click succeeding on screen is not proof the service restarted.
- On any high-stakes or irreversible-adjacent step where a confident wrong belief is worse
than a slow check.
- Over long tasks (many steps), to stop drift: verify the load-bearing actions so a no-op
never becomes a false premise for the next twenty steps.
Notes
os_verify is read-only — it never mutates; it only observes and reconciles. Safe
to call freely.
- The
token is stateless (it carries the baseline), so begin and end need not be
adjacent — do arbitrary work in between.
- No screen-mcp installed? Skip step 3 and omit
pixel; you still get OS-layer
verification (unit state + journald), just without the GUI cross-check.
expect is optional. With it you assert the intended end-state and get CONFIRMED/
PARTIAL grading; without it, os_verify reports whether anything changed and flags
failures/errors.
1---2name: cross-layer-verify3description: Verify that an action actually worked by fusing TWO independent senses onto the machine — the GUI (screen-mcp's pixel-change signal) and the OS (os-control-mcp's os_verify: systemd unit state + journald). Use whenever an action is supposed to have a system effect you must confirm across a long or high-stakes task: clicking a Restart/Apply/Start button in a GUI, toggling a service from a settings panel, or any step where "it looked like it worked" is not good enough. The loop catches the failure a single-layer agent cannot see — a GUI that changed while the service never did (or a service that changed while the UI froze). Requires os-control-mcp; the pixel half additionally needs screen-mcp (without it, verification degrades cleanly to OS-only).4---56# Cross-layer action verification78One sense lies. A screenshot can't tell a spinner from a frozen app; systemd can't9see a dialog. Fuse both and you can tell a real success from a no-op — the thing that10makes long-horizon work survivable. This skill encodes the loop:1112**`begin` → act → read both senses → `end` → reconcile.**1314## The loop15161. **`os_verify` `action=begin`** — snapshot the baseline. Pass the `units` the action17 should affect (e.g. `["nginx.service"]`), optionally `expect` (unit → wanted state,18 e.g. `{"nginx.service": "active"}`), and `scope` (`system`|`user`). Keep the returned19 `token`.202. **Perform the action** with whatever tool does it — a `screen_click` on the GUI21 button, an `os_service` restart, a manual step.223. **Read the pixel signal** (only if a GUI was involved). Two options:23 - **`screen_verify`** — preferred. It *polls* until the screen settles or a timeout,24 grades the GUI itself (`CONFIRMED`/`PARTIAL`/`NO_OP`/`DIVERGED`), and returns a25 `pixel` block ready to hand straight to step 4. Takes `expect_text` / `expect_gone`26 / `expect_change`, so you can assert the button's effect rather than just "something27 moved". Use this when the GUI effect may take a moment to appear.28 - **`screen_sense`** — passive. Returns `{"pixel": {changed, opened, modal, no_op,29 activity}}` for whatever the *last* action already left behind, with no waiting. Use30 it when the action is known to be instantaneous, or when you have already screenshotted.314. **`os_verify` `action=end`** — pass the `token` and, if you have one, `pixel=<the32 `pixel` object from screen_verify or screen_sense>`. It re-reads systemd + journald33 and returns the verdict.3435Both emit the same `{"changed": bool, ...}` contract; `os_verify` reads `changed` and36ignores the rest, so either is safe to pass.3738### Worked example (verified live)3940```41os_verify action=begin units=["dbus.service"] -> token42screen_click / os_service / manual step43screen_verify expect_change=true region=[...] -> {"verdict":"CONFIRMED","pixel":{"changed":true}}44os_verify action=end token=<token> pixel={"changed":true}45```4647A GUI-only action (a hover) against an untouched unit returns48`status: DIVERGED`, `cross_layer: "pixel-changed-os-static"`, `reconciled: false`.49An inert action on both layers returns `status: NO_OP`, `reconciled: true`,50`cross_layer: null`. Both quadrants were exercised end-to-end against a live desktop.5152## Reading the verdict5354| status | meaning | do |55|---|---|---|56| **CONFIRMED** | expectation met (or a plausible OS effect happened), no journal errors, layers agree | proceed |57| **PARTIAL** | some expected units met, others not | inspect the per-unit block; finish the rest |58| **NO_OP** | nothing changed at the OS layer and (if given) the screen was static | the action did nothing — re-ground and retry, don't build on it |59| **DIVERGED** | a unit failed, journald logged errors, OR the layers disagree | STOP. Read `cross_layer` + `journal.sample`. Do not assume success. |6061`cross_layer: "pixel-changed-os-static"` is the signal to care about most: the GUI moved62but the service never did — the button "worked" visually and did nothing real. That is63exactly the silent failure that compounds over a long task.6465## When to reach for it6667- After clicking a control in a GUI that is supposed to drive a service (restart, apply,68 enable) — the click succeeding on screen is not proof the service restarted.69- On any high-stakes or irreversible-adjacent step where a confident wrong belief is worse70 than a slow check.71- Over long tasks (many steps), to stop drift: verify the load-bearing actions so a no-op72 never becomes a false premise for the next twenty steps.7374## Notes7576- `os_verify` is **read-only** — it never mutates; it only observes and reconciles. Safe77 to call freely.78- The `token` is stateless (it carries the baseline), so `begin` and `end` need not be79 adjacent — do arbitrary work in between.80- No screen-mcp installed? Skip step 3 and omit `pixel`; you still get OS-layer81 verification (unit state + journald), just without the GUI cross-check.82- `expect` is optional. With it you assert the intended end-state and get CONFIRMED/83 PARTIAL grading; without it, os_verify reports whether *anything* changed and flags84 failures/errors.