pi-omarchy-cu
Semantic desktop observation and goal-driven interaction for Linux applications from the Pi coding agent, over AT-SPI, with in-process TypeSafe Jev System One decisions
Package details
Install pi-omarchy-cu from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-omarchy-cu- Package
pi-omarchy-cu- Version
0.1.0- Published
- Nov 1, 2026
- Downloads
- 346/mo · 346/wk
- Author
- paulcynic
- License
- MIT
- Types
- extension, skill
- Size
- 238.3 KB
- Dependencies
- 3 dependencies · 2 peers
Pi manifest JSON
{
"skills": [
"./skills"
],
"extensions": [
"./extensions/index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-omarchy-cu
Computer use for the Pi coding agent on Linux, built for Omarchy (Hyprland Wayland).
pi-omarchy-cu lets Pi drive real desktop applications through the AT-SPI
accessibility tree, while a calibrated decision model picks the target and the
action. The accessibility tree never enters Pi's context: a tool call reads the
live Window or Overlay Surface, filters nodes by their Advertised
Actions, asks Jev System One for the target Ref and Operation,
enforces deterministic confidence and risk thresholds, and returns compact
evidence about what happened.
"switch to list view" → cu_act (one step, dry-run by default)
"open Preferences, then enable Dark Mode" → cu_run (multi-step Goal, verifies as it goes)
"click @s8f3k2p9:e12" → cu_ref (you already know the Ref)
"what is on the screen?" → cu_observe
"why is Chromium invisible?" → cu_status
What it can do
| Capability | Tool |
|---|---|
| Readiness report — agent-desktop binary, private state root, AT-SPI bus, display, Jev config, apps, windows, blind spots | cu_status, /cu status |
Inspect a Window, a Region, or the active dialog/menu — skeleton overview, drill into a Region, find/get/is/list-surfaces |
cu_observe |
Act deterministically on a known Ref — click, right-click, check, uncheck, toggle, expand, collapse, select, set-value, clear, scroll-to — plus wait, clipboard, and accessibility-enabled launch |
cu_ref |
| One natural-language Intent — resolve the target and Operation without reading the tree, optionally execute | cu_act |
| A multi-step Goal — observe → decide → confirm → act → verify, with budgets and stop conditions | cu_run |
| Dialogs and menus first — an open sheet, alert, menu, or popover is observed instead of the window it covers | all read paths |
| Human-in-the-loop — risky or ambiguous steps prompt with the window, operation, target, confidence, and destructive probability | cu_act, cu_run |
Text entry without a keyboard — semantic set-value on nodes that advertise it, with scoped redaction |
cu_act, cu_run, cu_ref |
Diagnostics at zero token cost — /cu apps, /cu windows |
/cu |
It is deliberately conservative: only the 11 Wayland-safe AT-SPI Operations are
offered, text entry is reconciled to set-value (never synthetic keystrokes),
and confidence thresholds (0.55 floor, 0.70 action bar, 0.90 destructive
bar) gate every mutation. See ADR-0002.
What it cannot do (yet)
- Terminal/TUI apps (cliamp, nvim, btop): their content never joins the AT-SPI bus, and Hyprland Wayland blocks synthetic keystrokes. The extension says so and stops; drive these through their own CLI/IPC (the bundled skill shows the cliamp recipe).
- Apps that are not running:
cu_refcan launch them with the accessibility environment injected, butcu_act/cu_rundo not auto-launch today. - Canvas/GPU-drawn UIs with no accessible nodes:
cu_actabstains instead of guessing coordinates. - Compositor-level input: no
wtype,ydotool,hyprctlinput, orgrimscreenshots (ADR-0002). For Chromium-only work, use surf. - Other users' sessions, containers, or sandboxes that don't share the bus.
Install
Requires Linux with a running AT-SPI bus (at-spi2-core), a graphical session,
and Pi. agent-desktop ships as a dependency, so you do not install it
separately.
# from npm (once published)
pi install npm:pi-omarchy-cu
# from GitHub
pi install git:github.com/Paul-Yuchao-Dong/pi-omarchy-cu
# from a local checkout
npm install
pi install .
pi install reads the package manifest ("pi": { "extensions": ["./extensions/index.ts"], "skills": ["./skills"] }) and loads both the tools
and the omarchy-cu skill. A local checkout is not installed by Pi, which is why
it needs its own npm install first.
To try it without touching your settings:
pi -e /path/to/pi-omarchy-cu
Jev credentials
cu_act and cu_run need a TypeSafe Jev endpoint. Resolution matches
pi-jev, so an existing setup works
as-is:
- Endpoint:
PI_JEV_BASE_URL→TYPESAFE_BASE_URL→ OpenRouter (https://openrouter.ai/api, when an OpenRouter key is used) → TypeSafe (https://api.typesafe.ai/v1/systemone). - Key:
$TYPESAFE_API_KEY→~/.pi/agent/secrets/typesafe_api_key→$OPENROUTER_API_KEY→~/.pi/agent/secrets/openrouter_api_key. A custom loopback endpoint may run keyless. - Model: explicit →
PI_JEV_MODEL→TYPESAFE_MODEL→TYPESAFE_DEFAULT_MODEL→~typesafe/jev-lateston OpenRouter,jev-lateston TypeSafe.
HTTPS is required for remote endpoints; plain HTTP is accepted only on loopback,
and URLs with embedded credentials are rejected. cu_status reports the
resolved endpoint and key origin, never the key.
First run
/cu status # binary, state root, bus, display, Jev, apps, blind spots
/cu apps # what is on the accessibility bus
Then, from the Pi prompt:
Call cu_status. If a running Chromium, Electron, or Qt app is missing from the
accessibility bus, show me the exact flags to relaunch it.
Usage
cu_act — one Intent
Call cu_act with intent "press the List View button" and execute: false.
Show the chosen Ref, Operation, confidence, destructive risk, and why.
Dry run is the default. Pass execute: true to land the step. When the Intent
needs text, pass text — the extension never invents strings. When several
foreground apps exist, name the app (app: "Notes"); loose names and casing are
resolved against list-apps.
cu_run — one Goal
Use cu_run with the goal "open Preferences, switch to Appearance, and enable
Dark Mode" and confirmDestructive: true.
Every turn streams as a progress update. The loop stops on done, blocked, a
declined confirmation, action_failed, window_closed, a window/surface
ownership violation, 40 operations, 80 decision calls, or 3 consecutive non-WAIT
turns with an unchanged SHA-1 screen fingerprint.
cu_observe and cu_ref
Use these when you want explicit control: cu_observe to read a Window, Region,
or the active dialog; cu_ref to run one deterministic operation, wait for a UI
transition, read or write the Wayland clipboard, or launch an app with
accessibility enabled.
Tools
| Tool | What it does |
|---|---|
cu_status |
Readiness: binary, private state root (0700), AT-SPI bus, display, Jev configuration, running apps and windows, AT-SPI blind spots with exact relaunch flags, and the Electron single-client bridge warning. |
cu_observe |
snapshot (interactive-only, compact, bounds-included, shallow skeleton, auto-switching to an open Overlay Surface), find, get, is, list-surfaces. A root Ref or maxDepth narrows or deepens a Region read; a windowId pins every read to one Window and rejects leaked nodes. |
cu_ref |
The 11 Wayland-safe Ref Operations, wait, clipboard-get/clipboard-set/clipboard-clear (via wl-clipboard), and launch with ACCESSIBILITY_ENABLED=1 and QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1. |
cu_act |
One Intent: snapshot, candidate filtering, a five-question System One request, top-5 rerank below 0.70, Operation reconciliation, Route Decision, confirmation, execution. |
cu_run |
One Goal: the observe-decide-act-verify loop with DRILL/WIDEN Region navigation, streaming turns, and hard budgets. |
/cu status, /cu apps, and /cu windows give the same diagnostics in the
terminal, outside the model's context.
Omarchy AT-SPI flags
An app that starts without its toolkit's accessibility switch never joins the
bus, and every observation then looks like a missing window. cu_status names
the offending processes; this is what puts each toolkit on the bus:
| Toolkit | Launch with |
|---|---|
| Chromium | ACCESSIBILITY_ENABLED=1 chromium --force-renderer-accessibility (ACCESSIBILITY_ENABLED=1 alone registers the browser with no windows) |
| Qt | QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1 <app> (equivalently QT_ACCESSIBILITY=1) |
| Electron | no accessibility flag; add --no-sandbox only where chrome-sandbox is not setuid |
Electron single-client hazard: when agent-desktop is the only AT-SPI client,
its disconnect can crash the Electron accessibility bridge (VS Code exits with
SIGSEGV). A GNOME desktop keeps the shell connected; on Hyprland keep another
AT-SPI client connected.
Environment variables
| Variable | Effect |
|---|---|
AGENT_DESKTOP_BIN |
Explicit agent-desktop executable; overrides the bundled dependency. |
AGENT_DESKTOP_HOME |
State directory; created and enforced at 0700. |
WAYLAND_DISPLAY, DISPLAY |
Passed through to agent-desktop. When unset (Herdr server, systemd, SSH, or container pane), they are derived from the newest /run/user/<uid>/wayland-* socket and the lowest /tmp/.X11-unix/X<n>; explicit values always win. |
PI_JEV_BASE_URL, TYPESAFE_BASE_URL |
Jev endpoint, as an API root (https://api.typesafe.ai) or the full .../v1/systemone endpoint; both resolve to the same request URL. |
PI_JEV_MODEL, TYPESAFE_MODEL, TYPESAFE_DEFAULT_MODEL |
Decision model, resolved in that order. |
TYPESAFE_API_KEY, OPENROUTER_API_KEY |
API keys; the pi secret files are read when the variables are unset. |
Architecture
- Observation and execution go through
agent-desktopas an async subprocess (never blocking the event loop), with a private state root and fullAbortSignalpropagation. - Decisions are in-process via
@typesafe-ai/sdk, with bounded retry on429/503/529(ADR-0001). Extensions cannot call another extension's tool mid-execution, so the Jev client is embedded rather than delegated. - Policy is deterministic: candidate filtering, Operation reconciliation,
Route Decisions, risk gating, text-queue and redaction rules, and the loop
budgets live in
src/policy/,src/decide/, andsrc/desktop/. - One test seam: every tool is exercised through
execute(toolCallId, params, signal, onUpdate, ctx)with an injectable CLI runner and decision client; one live test drives the real binary.
See docs/adr/, GLOSSARY.md, and skills/omarchy-cu/SKILL.md for the design
record, vocabulary, and the agent-facing usage guide.
Development
npm test # node --test --import tsx test/*.test.ts
npx tsc --noEmit # typecheck
npm run smoke # load the extension in Pi and list its tools
Credits
This package stands on several prior works:
- agent-desktop by Vercel Labs (Apache-2.0) — the AT-SPI observation and Ref-execution CLI that does the actual desktop work. It ships as a dependency, and its Linux skill documents the Chromium/Electron/Qt flags and the Electron bridge hazard reused here.
- TypeSafe Jev System One and
@typesafe-ai/sdk(MIT) — the calibrated choice/probability decisions behindcu_actandcu_run. - pi-jev by Theophilo Damiao (MIT) —
prior art for Jev credential/endpoint resolution, retry, and key-origin
reporting;
src/jev/mirrors its resolution order deliberately. - Pi by Earendil Works — the extension
runtime, tool API, and the
ctx.ui.confirminteraction used for risky steps. - Omarchy and Hyprland — the target desktop; ADR-0002 exists because of their Wayland constraints.
- AT-SPI / at-spi2-core (GNOME) — the accessibility bus everything reads.
- wl-clipboard — the Wayland clipboard backend behind
cu_refclipboard commands.
License
MIT. See LICENSE.