Skip to content

fix(cua-driver): forward-port Hyprland agent mode to v0.22 - #2

Merged
jacob-vincent-mink merged 125 commits into
jacob-vincent-mink:test/hyprland-integrationfrom
spencerbull:hyprland-agent-mode-v0.22
Aug 26, 2026
Merged

fix(cua-driver): forward-port Hyprland agent mode to v0.22#2
jacob-vincent-mink merged 125 commits into
jacob-vincent-mink:test/hyprland-integrationfrom
spencerbull:hyprland-agent-mode-v0.22

Conversation

@spencerbull

@spencerbull spencerbull commented Aug 25, 2026

Copy link
Copy Markdown

Summary

  • Forward-port the Hyprland integration branch onto exact cua-driver-rs-v0.22.0 (ac9b1643acb61e20d5af078215e7d1b8c414db89).
  • Preserve native Hyprland discovery, identified-window capture, logical/physical coordinate conversion, output-bound synthetic cursors, browser cursor rendering, and Wayland/X11 overlay isolation.
  • Preserve agent-mode non-interference and cancellation-safe held-button teardown across session, runtime, disconnect, and failed-release cleanup paths.
  • Apply the Fable 5 review loop fixes: truthful WebKitGTK pointer refusal, bounded single-element AT-SPI bounds lookup, one shared Hyprland correlation refresh, exact guarded foreground focus leases, and correct persistent-pointer coordinates across offset/negative outputs.

Salvaged from upstream work in trycua#3019, trycua#3031, trycua#3052, and trycua#3152, then continued from Jacob's integration branch.

Candidate

  • Exact reviewed and tested PR head: c8a951c4f3c5750b5c68e0b5d2e8a9ee549df9c8
  • Tree: e532b2ec30fa32df83d4a12d3e585c618f42b11f
  • v0.22 base tag commit: ac9b1643acb61e20d5af078215e7d1b8c414db89
  • Jacob target branch base at PR creation: 1e988d45770ed8bc43128151f095ef28e0bc32c1

Verification

  • git diff --check
  • cargo fmt --all -- --check
  • cargo test -p platform-linux --lib: 341 passed, 0 failed, 5 ignored
  • cargo check -p cua-driver
  • cargo test -p cua-driver --test capture_contract_test --no-run
  • Focused registry/reuse state-machine tests: 5 passed
  • Fable 5 reviewed the functional forward-port in three bounded passes, found F1-F5, then re-reviewed the fixes twice. Final verdict: GO, with no remaining substantive P0-P2 findings.
  • Independent orchestrator inspection confirmed each finding and the follow-up recycled-address state transitions before commit/push.

The earlier bounded installed/MCP smoke applied to pre-review candidate ea707a5737b6606df68cf906d9abb14abfecb9c3. The final review-fix commit above has source/build/unit verification but has not been installed or exercised against this personal desktop.

Attribution and merge method

  • Keep the authored merge topology and use a merge commit for this PR; do not squash or rebase-merge it.
  • That preserves the existing authorship for Jacob Mink, Zane Chee/injaneity, Rodri Mora, Ilyas Khallouki, shuv, Spencer Bull, and the salvaged upstream PR commits.
  • If maintainers intentionally choose a squash despite this note, the squash commit must reproduce all author/co-author trailers with GitHub-resolvable identities and retain the salvaged-source references.

Known gaps / draft gate

  • The complete canonical cross-platform desktop E2E matrix has not run at this exact candidate. Repository guidance prohibits running the representative Hyprland matrix on a personal desktop containing unrelated windows.
  • The active Hyprland host used by the earlier smoke exposed one monitor, so mixed-output and mixed-scale behavior was not exercised live.
  • The new foreground focus lease and held-pointer coordinate fixes are source-tested and independently reviewed, but not live-tested on the final commit.
  • Non-blocking P3s from review remain documented, including the pre-existing explicit mouse_button_up(x,y) overlay/wire-position mismatch and one shared 80 ms refresh for a permanently ambiguous Hyprland topology.

Keep this PR draft until the canonical desktop evidence is complete or maintainers explicitly accept the documented environment limits.

r33drichards and others added 30 commits August 13, 2026 11:22
trycua#3131)

* docs(sandbox): add a how-to for running Minecraft in a Windows sandbox

Walks through booting Image.windows() on the local bare-metal QEMU
runtime, installing Minecraft Java Edition inside it, and handing the
launcher to a computer-use agent.

The page documents the four traps that make this fail otherwise:

- the bare-metal netdev is restrict=on, so the guest has no internet
  until a second NIC is added, and that NIC needs its own subnet or
  both user-mode networks offer the guest the same address
- the default qemu64 CPU model is too thin for a software OpenGL
  driver: the game creates its window and then dies during resource
  loading with no Java exception, which -cpu host fixes
- MSVC builds of both Prism Launcher and Mesa3D need the VC++
  redistributable that Windows Server 2022 does not ship, so the
  MinGW builds are the ones that work
- the launcher downloads its own Java, so the Mesa DLLs have to land
  next to that javaw.exe rather than a separately installed JRE

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(sandbox): drop the obsolete shared-efivars troubleshooting row

EFI variables stopped being shared in trycua#3128: the bare-metal QEMU runtime
now derives one pflash file per VM from its disk name
(Path(disk_path).with_suffix(".efivars.fd"), runtime/qemu.py:345), and
tests/test_docs_regressions.py asserts the old shared path is gone. There
is no ~/.cua/cua-sandbox/images/sessions/efivars.fd to delete anymore, so
the row pointed readers at a file that does not exist.

* docs(sandbox): drive Minecraft through cua-driver's MCP server

Rewrites the agent half of the guide around the MCP server the sandbox
already runs, rather than ComputerAgent: Image.windows().expose(3000)
publishes cua-driver's endpoint on guest :3000, a FastMCP client lists
its tools, and a small loop hands them to a model as ordinary function
tools. The same loop runs against a local sandbox and against Fleet;
only the transport differs.

Presenting MCP tools as ordinary function tools also sidesteps endpoints
that refuse provider-native computer-use tool types.

Documents three things about cua-driver that are otherwise a surprise:
a YAML policy refuses tools that list_tools() still advertises, clicks
are addressed to a pid rather than the screen, and there is no wait tool
so the loop waits by re-screenshotting.

Also adds prerequisites (cua-sandbox 0.3.1+, and that -cpu host needs
KVM or HVF, so an x86_64 guest on Apple Silicon cannot use the local
path), a delivery snippet for the Mesa script, and replaces the stale
Fleet callout now that Windows boots there.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(sandbox): use the public tunnel API and make the sample match the run

Replaces the hand-assembled Fleet service URL with sb.tunnel.forward(3000),
which returns exactly that URL and is already documented in tunneling.mdx.
The local path keeps reading the port off the object Sandbox.create returns,
because tunnel.forward() is not implemented for that transport and the port
is not recoverable after a reconnect — now stated outright rather than left
for a reader to discover.

The agent sample now does what the prose said it did: streams and rebuilds
with stream_chunk_builder, folds the system prompt into the first user turn,
prunes old screenshots, and trims the 55-tool listing to the handful the task
needs.

Also explains why -cpu host is absent on Fleet, attributes the token lifetime
to what was observed rather than asserting it, and drops an unused import.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(sandbox): drop the /docs prefix from the tunneling cross-link

Internal doc links in docs/content are written relative to the docs root
without a /docs segment — every other absolute link in the tree does it
this way (for example ](/how-to-guides/sandbox/images)), and there were
zero occurrences of ](/docs/ before this one. The prefixed form resolves
to /docs/how-to-guides/... at render time and 404s.

* docs(sandbox): record that Minecraft does not yet run on Fleet

The Fleet path is verified as far as the sandbox and the agent: it boots,
.expose(3000) publishes cua-driver, the MCP client lists the same tools,
the setup script installs Prism and Mesa, the Microsoft sign-in completes,
and the agent loop drives the desktop. The game itself exits during
resource loading every time, with no Java exception, no hs_err and nothing
in the event log.

Neither known cause explains it: the Fleet CPU reports full AVX-512, so
the qemu64 instruction theory does not apply, and forcing the heap from
Prism's auto-sized -Xmx2717m down to -Xmx1024m on the 4 GB sandbox changed
nothing. Unlike the local path there are no QEMU arguments to adjust.

Says so plainly rather than implying the game runs there.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(sandbox): pin down the Fleet crash with an exit code and a second version

Adds the evidence that narrows it: the game dies with exitcode -2147024809,
and it is not version-specific — 1.20.1 on Java 17 with LWJGL 3 and 1.12.2
on Java 8 with LWJGL 2 stop at the same point. That exit code is the same
one the local qemu64 CPU model produced, but the Fleet CPU reports AVX,
AVX2 and AVX-512 present, so the local explanation does not carry over.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(sandbox): rule out machine size for the Fleet crash

Records the last elimination so nobody repeats the experiment: the same
local session disk, rebooted with -m 4096 -smp 4 to match the Fleet
sandbox exactly, runs Minecraft fine. Prism warns about low free memory
and the game launches anyway.

So the Fleet failure is not resources. Five things are now ruled out --
CPU feature flags, heap size, Minecraft version, Java/LWJGL generation,
and machine size -- with the same stopping point and the same exitcode
-2147024809 throughout.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(sandbox): restore the tunneling cross-link path

The /docs prefix came back in 2a4c385 when the surrounding Fleet
paragraph was rewritten, undoing 5f19e66. Internal links in docs/content
omit the /docs segment — every other absolute link in the tree is written
](/how-to-guides/...) and this is the only ](/docs/ in it — so the
prefixed form 404s at render time.

* docs(sandbox): stop sending Apple Silicon readers to Fleet for the game

The prerequisites and the -cpu host troubleshooting row both told readers
without KVM or HVF to use the Fleet path instead. Since 93c1cdd the guide
also records that Minecraft does not run on Fleet, so those two lines sent
the one reader who cannot use the local path to the one path where the
game is known not to work. Both now say what Fleet does get you — the
sandbox and the agent loop — and point at the Fleet section for the rest.

* docs(sandbox): Minecraft runs on Fleet with GALLIUM_DRIVER=softpipe

The Fleet crash was Mesa's llvmpipe renderer. Switching to softpipe fixes
it, and an agent drove the same loop from launcher to standing in a new
world on Fleet in 51 steps. The section documents the workaround instead
of the failure, and the Apple Silicon note now sends readers to Fleet for
the game rather than away from it.

Keeps the eliminations as the reason softpipe is needed rather than a
guess: not the Minecraft version, not the Java/LWJGL generation, not the
heap, not the machine size, and not simply wide-vector codegen -- narrowing
llvmpipe with LP_NATIVE_VECTOR_WIDTH=128 did not help. Notes that softpipe
has no JIT and is markedly slower, and that the variable must be set in the
process that launches the launcher, since a machine-level variable does not
reach an already-running process.

Also records that Fleet sizing is account-dependent: cpu/memory_mb route
through a gated path that returned 403 until a card requirement was lifted.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(sandbox): make the resource-loading crash findable for Fleet readers

The troubleshooting table had one row for "game exits during resource
loading", attributing it to the qemu64 CPU model and prescribing -cpu
host. Since b8ab92f the same symptom has a second, unrelated cause on
Fleet — Mesa's llvmpipe renderer — and -cpu host is not available there
at all, because Fleet takes no runtime= and no QEMU arguments. A Fleet
reader looking the symptom up was sent to a fix they cannot apply, while
the one that works had no row.

Scope the existing row to local, add a Fleet row pointing at
GALLIUM_DRIVER=softpipe, and note in the Fleet callout that setup.ps1
has already started Prism without the variable, so the launcher has to
be restarted for it to take effect.

* docs(sandbox): catch up with the exposed-ports and tool-listing fixes

Two changes merged to main after this page was written and left parts of
it describing behaviour that no longer exists.

trycua#3133 added a public Sandbox.exposed_ports property that falls back to the
saved sandbox state, so the page no longer needs to reach into
_runtime_info, and the callout warning that a reconnecting caller cannot
recover the port is simply wrong now. Rewrite it around the property,
keeping the local/Fleet split the property's own docstring draws:
exposed_ports locally, tunnel.forward() on Fleet, where it is empty.

trycua#3132 filters the MCP tools/list roster through the capability policy, so
denied tools are no longer advertised. The page presented "list_tools()
advertises everything, the policy refuses at call time" as the rule; that
holds only for driver builds predating the fix. Attribute the 55-tool
observation to the image used here, say the listing may already be
filtered, and tell readers not to assume the listing and the callable set
match in either direction. The client-side trim is unaffected and still
worth doing, so its rationale is restated without leaning on the count.

* docs(sandbox): state the tool-listing behaviour as fact, not a hedge

Every published cua-driver release advertises the full tool surface and
refuses out-of-policy calls only at call time: tags 0.19.2 (2026-08-07),
0.19.3 (2026-08-10) and the 0.19.4 nightly (2026-08-12) all predate the
change that filters the listing, which merged on 2026-08-13. So for any
reader today this is simply how it behaves, and the previous
"depends on your image / do not assume either direction" wording cost
them a concrete expectation for no gain.

State it plainly, keep the probe-your-own-image advice for the allow list
itself, and note that later drivers make the listing and the callable set
agree. The troubleshooting row is scoped the same way.

* docs(sandbox): raise the version floor to 0.3.2 for sb.exposed_ports

I moved the page onto the public Sandbox.exposed_ports property in
b2bebc1 without revisiting the prerequisite, which still said 0.3.1. The
property arrived with trycua#3133, merged 2026-08-13T17:49Z — after cua-sandbox
0.3.1 went to PyPI at 04:07 that morning and before 0.3.2 at 17:54. So a
reader installing the version the page asked for gets AttributeError on
the page's own first example.

Floor is 0.3.2. The bullet now names what each version is needed for, so
the next person to use a newer API has the mapping in front of them.

---------

Co-authored-by: Robert Wendt <robert@trycua.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(cua-driver): preserve named CLI sessions

* test(cua-driver): cover named CLI session isolation
* feat(cyclops): add browser bash chat

* fix(cyclops): finalize browser bash chat

* test(cyclops): update chat SDK import

* fix(cyclops): harden browser chat previews

* fix(cyclops): bound in-memory chat storage

* fix(cyclops): render previews from PR commits

CloudCyclopsCs-RevId: 40f89a33057b364a71b2a9afb945cb70ef362a02
* docs: specify RDS membership grantor compatibility

* docs: plan RDS membership grantor rollout

* fix(cyclops-cs): classify authoritative role grants

* docs: specify Cyclops serving availability

* docs: correct Cyclops availability spec date

* docs: date Cyclops availability spec correctly

* docs: correct Cyclops availability design date

* docs: plan Cyclops serving availability

* fix(cyclops-cs): preflight static membership repairs

* fix migrator static membership validation

* fix(cyclops-cs): keep backend ready without postgres

* fix(cyclops-cs): decouple state query startup

* fix(cyclops-cs): clear stale database features

* fix(cyclops-cs): bound postgres-backed requests

* fix(cyclops-cs): surface database availability failures

* fix(cyclops-cs): harden serving rollouts

* test(cyclops-cs): make manifest contract offline

* ci(cyclops-cs): pin manifest contract toolchain

* ci(cyclops-cs): pin query contract verifier toolchain

* fix(cyclops-cs): isolate state projector rollout

* test(cyclops-cs): stabilize projector contract

* test(cyclops-cs): update projector isolation contract

* fix(cyclops): resolve backend availability rebase

* fix(database): select RDS static membership grantor

* test(flux): keep cyclops serving migration-independent

* fix(cyclops-cs): classify postgres transport outages

* test(cyclops-cs): align availability contracts

CloudCyclopsCs-RevId: 4ec38af516b181e1799bf8e13e1c1eef11a3c884
Co-authored-by: coding-sub-agent <coding-sub-agent@trycua.com>
CloudCyclopsCs-RevId: dadc4479a482d9c55847bec9fff4cf8d530867cd
CloudCyclopsCs-RevId: 384503987a24e77cbeb0a76bb51c8eedfd436cba
* feat(cyclops): require card or admin for CR creation

* fix(cyclops): evaluate card expiry in policy

* fix(cyclops): snapshot admission clock per request

* feat(cyclops): add card exemption controls

---------

Co-authored-by: coding-sub-agent <coding-sub-agent@trycua.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
CloudCyclopsCs-RevId: 162c0bc1e65d2f6277ca62fd400b988ade122363
* docs: define sidebar route synchronization

* docs(cyclops): use public ECR in Fleets example

CloudCyclopsCs-RevId: 8e973229f8dfc96c425afe4417e30a507b51e2a2
* feat(cyclops): add browser bash chat tools

* feat(cyclops): render sanitized chat markdown

* fix(cyclops): contain chat transcript scrolling

* docs(cyclops): design per-user chat access

* docs(cyclops): plan per-user chat access

* feat(cyclops): add per-user chat access

CloudCyclopsCs-RevId: 0b74fb8918ba31fb3e518190f9221df15a2bac30
CloudCyclopsCs-RevId: d9809fbc1d103613cbe53af6d4b3a30fe5470596
CloudCyclopsCs-RevId: c81eeabec054ff1233c006511b1853ff7f4fe040
* feat(cyclops): grandfather pre-cutoff billing users

* fix(cyclops): resolve chat access rebase

CloudCyclopsCs-RevId: 572dc45fdc375831779f65e0d50e113882710ec4
* docs: design policy denial reasons

* docs: plan policy denial reasons

* feat(cyclops): add policy denial reasons

* test(cyclops): preserve policy denial annotations

* test(cyclops): strengthen denial annotation coverage

* test(cyclops): cover annotated fact sinking

* fix(cyclops): explain billing policy denials

* test(cyclops): pin k8s denial copy

CloudCyclopsCs-RevId: 54e1bf75a6d018c1e2473fcb3fc1a33443851af9
…ua#3155)

Turn the hand-built sandbox into an OCI containerDisk, push it to GHCR, and boot
it locally and on Fleet, so the GUI install never has to be repeated — least of
all on Fleet.

Covers what a containerDisk is, never signing in before exporting and the three
places a credential survives if you do, creating the instance and fetching Java
without a Microsoft account, the sb.stop() trap, qemu-img convert, the two-line
Dockerfile, --provenance=false --sbom=false, GHCR being private on first push,
and the os_type override that keeps a Windows disk off SeaBIOS.

Verified end to end as ghcr.io/trycua/minecraft-agent:1.20.1: export 8m44s for
7,697,072,128 bytes, build and push 6m28s as a plain manifest, anonymous pull
200 with no credentials, local boot with the game files intact, and a Fleet boot
READY in 157 s — the first confirmation that a custom Windows containerDisk on a
public non-ECR registry runs there.

Retrying a BindDeadlineExceeded boot under the same name returns 403 on update
template, because both branches of the gateway image policy are guarded by
input.method != "PATCH": a template can be created but never updated. The retry
needs a new name. tunnel.forward() is also not available on a pool-claim
sandbox, which carries the base FleetTransport.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
from_registry hardcoded os_type="linux" with no way to override it, while
from_file — the adjacent constructor building the same object from a different
source — takes os_type and kind as keyword arguments.

os_type is what selects UEFI, on the local QEMU runtime and in the Fleet
transport alike. A Windows containerDisk pulled from a registry was therefore
handed BIOS and could not boot, and the only escape was reaching past the
constructor with dataclasses.replace(). That is the firmware failure fixed for
Fleet in trycua#3125 arriving through a different door.

The default stays "linux", so existing callers are unaffected.

Also repairs a test double in test_cloud.py: trycua#3133 made Sandbox._create pass
ephemeral= to runtime.start(), and the fake Runtime there does not accept it, so
that test has been failing on main since it merged. It went unnoticed because
cua-sandbox is not in the ci-test-python package matrix and its suite never runs
on pull requests.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
install.ps1 documents itself as an `irm ... | iex` install, and that invocation
failed outright with:

    The attribute cannot be added because variable Channel with value
    would no longer be valid.

Piped into Invoke-Expression, param() is not a parameter block: it becomes a set
of attributed variable declarations. [string]$Channel is initialised to '', and
its own [ValidateSet("stable","nightly")] rejects that default before the body
runs. The parameter has no default in the set, so this happened for every iex
caller whether or not they passed -Channel. Run as a script file the same code
is fine, because an unbound parameter is never assigned and validation never
fires — which is why the asymmetry survived review.

Validate at the point of use instead, keeping the accepted values and the error
wording aligned with the saved-channel check below it.

Reproduced and fixed against the real script under pwsh: the unmodified script
fails at the param block; the patched one proceeds into real work. The guard was
driven directly — stable and nightly return, bogus reports
"invalid -Channel 'bogus'; expected stable or nightly".

This is what breaks the Windows workspace image build at its
"install cua-driver" step, which blocks rebuilding that image at all.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: nested KVM support for KubeVirt VMs (CUA-952)

Adds an opt-in nestedVirtualization flag to OSGymSandbox/OSGymSandboxTemplate
vmTemplate. When set, the pool-operator renders spec.domain.cpu.model:
host-passthrough so the guest exposes vmx/svm and /dev/kvm for a nested
hypervisor (Android emulator, QEMU/KVM). Off by default; omitted templates
render no cpu model (verified on-cluster).

- KubeVirt CR: enable the NestedVirtualization feature gate.
- kubevirt host module: options kvm-intel nested=1 (redundant on 6.12, explicit).
- SDK schema: add nested_virtualization to VmTemplate; regenerate the CRD bundle
  and the python/kotlin/swift/ruby bindings + fixtures/ffi_models.
- pool-operator + kubevirt provider: thread cpu_model through vm_body.

Validated by a disposable nested-virt canary against the PR head: host vmx +
/dev/kvm, a direct host-passthrough VMI booting an L2 cirros VM to userspace,
and the product-path sandbox rendering host-passthrough and reaching Running.

Rebased onto main; drops the stale legacy osgymworkspacepools CRD the branch
carried (removed from main in #6316) by regenerating the bundle from schema.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(sdk): thread nested_virtualization through go/ts bindings and live examples

The mid-struct VmTemplate field shifted positional constructors and changed
the record wire layout. Update the hand-maintained go-uniffi + ts-uniffi
(node) + ts-uniffi-browser record serializers (struct/read/write/allocationSize)
to carry nested_virtualization after firmware, and add the field to the
positional/full-keyword live examples (kotlin/swift/python/ruby). Fixes the
go/node/browser live-example segfaults and the terraform-provider envtest
SIGSEGV, which all decode VmTemplate through the stale go/ts bindings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(nested-kvm): address review — AMD modprobe + cpu_model docstring

Per the code review: also set options kvm-amd nested=1 (harmless on Intel
hosts where kvm-amd never loads, future-proofs an AMD host), and document
the cpu_model param + host-passthrough live-migration trade-off in vm_body.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(nested-kvm): dedicated nested-virt NodePool + operator routing

Splits nested-virt onto its own Karpenter pool instead of sharing the
general kubevirt-worker pool:

- New NodePool kubevirt-worker-nested, tainted cua.ai/nested-virt=true:
  NoSchedule. It reuses the existing kubevirt-worker EC2NodeClass verbatim
  (both pools need the EC2-instance nested-virt CpuOptions just to expose
  /dev/kvm on virtual instances), so the general pool and its EC2NodeClass
  are left completely unchanged.
- Operator routes a sandbox to the nested pool (nodeSelector + matching
  toleration) and renders cpu.model=host-passthrough only when its
  vmTemplate sets nestedVirtualization:true; everything else stays on
  kubevirt-worker with the default CPU model.
- KubeVirt CR: virt-handler now also tolerates cua.ai/nested-virt so the
  DaemonSet runs on the nested nodes and advertises devices.kubevirt.io/kvm.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(authz): gate nested-virt templates to admins (CUA-952)

Only admins may create or update an OSGymSandboxTemplate whose
vmTemplate.nestedVirtualization is true — nested KVM passes the host CPU's
vmx/svm into the guest and reserves the dedicated kubevirt-worker-nested
pool, so it's privileged. Mirrors the existing macOS admin-only gate in
pool_admission.rego: non-admin create/PATCH returns 403 forbidden at the
/api/k8s proxy; non-nested templates are unaffected. Admin identity is the
existing authz.is_admin (JWT sub in the /feature-flags/cyclops-cs/admin-subs
SSM allowlist) — same set that already gates macOS pools and the admin UI.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
CloudCyclopsCs-RevId: 577246da3c6d9d812c2397402ae0f1a1ee87c0f1
…vice (trycua#3156)

cua-sandbox 0.3.3 gives from_registry the os_type and kind keywords that
from_file already had (trycua#3154), so the dataclasses.replace() reach-around is
gone from the snippet and the frozen-dataclass explanation with it. The version
floor moves to 0.3.3, which is also the first release with the pull-secret fix
that lets Fleet boot an image from a registry outside its own allowlist.

Also corrects the retry advice, which was wrong. It said a fresh sandbox name
avoids the 403 on update template. Four boots of the same image say otherwise:

    same name after a failed boot   -> 403 update template
    fresh name (e2e-fleet-cd-1)     -> 403 update template
    fresh name (e2e-fleet-cd-2)     -> READY in 187 s
    fresh name (mc-ghcr-fleet2)     -> READY in 157 s

Two fresh names disagreeing rules out the name as the cause. What holds is the
policy — both branches of the gateway rule are guarded by
input.method != "PATCH", so any update is refused — and that the failure is
intermittent. The page now says retry, rather than prescribing a fix that does
not reliably work.

Re-tested end to end against the released package in a clean venv, using the
page's snippets verbatim: from_registry(..., os_type="windows", kind="vm")
builds correctly on 0.3.3, and the local boot of
ghcr.io/trycua/minecraft-agent:1.20.1 reached READY in 248 s with
sb.exposed_ports returning {3000: 56457}.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ua#3168)

Pool.apply() only exposed a static replicas count, so enabling
claim-demand autoscaling required dropping down to
Pool.reconcile(CreatePoolRequest(...)) even though the Fleet SDK
already models WarmPoolAutoscaling.

Add an autoscaling=WarmPoolAutoscaling(...) argument to the async and
sync Pool.apply() facades, validate the bounds client-side, and thread
the value into the reconciled pool spec. The autoscaling bounds join
the deterministic pool identity hash only when set, so pools applied
before this change keep their names. WarmPoolAutoscaling and its
builder are now re-exported from cua_sandbox.


Claude-Session: https://claude.ai/code/session_01GXGC2B4EsEw9dHBPWbKrBz

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat(cua-driver)!: remove browser approval tokens

* test(cua-driver): cover runtime browser authorization

* fix(cua-driver): update direct MCP permission setup

* docs(cua-driver): regenerate MCP reference
* chore(main): release cua-driver-rs 0.20.0

* chore(cua-driver-rs): synchronize generated release files

---------

Co-authored-by: cua-release-bot[bot] <254316371+cua-release-bot[bot]@users.noreply.github.com>
Co-authored-by: trycua-release[bot] <trycua-release[bot]@users.noreply.github.com>
…6886)

The serving tier deliberately keeps readiness database-independent
(docs/superpowers/plans/2026-08-12-cyclops-serving-availability.md):
initializeDatabaseFeatures logs, continues, and lets the database-backed
routes answer 503 so a PostgreSQL outage cannot take the API down. The
contract tests pin that — TestBackendDeploymentKeepsCoreAPIReadyWithoutDatabaseSchema
requires both probes to stay on /healthz.

The gap is not the behaviour, it is that the behaviour is invisible. A pod
that came up with a broken database is indistinguishable from a healthy one:
CyclopsCSBackendDown reads pod readiness, which is Ready by design here, and
the 503s only appear in the request metrics if somebody happens to call
/api/state/query or the GitHub trust policy routes. Initialization runs once
at startup with no retry, so the pod stays degraded until restarted.

Add a cyclops_cs_database_features_ready gauge, set on every exit path of
initializeDatabaseFeatures, and alert on configured="true" reporting 0 for
10m. configured="false" (DATABASE_URL unset) is a supported configuration
and always reports 1, so the alert cannot fire on a deployment that runs
without a database at all.

client_model moves from indirect to direct in go.mod: the test reads the
gauge through dto.Metric. The alternative, prometheus/testutil, pulls new
modules into the graph for one assertion.

Claude-Session: https://claude.ai/code/session_01BgMLQdA6oMLtXo8mr3Ykxn

Co-authored-by: Claude <noreply@anthropic.com>
CloudCyclopsCs-RevId: 6de9ffc185b90add3c8d31a19d79b914dad65ce2
* feat(cua-driver): project centennial

* fix(cua-driver): preserve authorization across history relaunch

* docs(cua-driver): prepare public history integration RFC

* feat(cua-driver): add Project Centennial agent consultation

* fix(cua-driver): read legacy Project Centennial chunks

* fix(cua-driver): align history relaunch with current authorization

* fix(cua-driver): preserve compatibility contracts for preview

* fix(cua-driver): keep preview portable across targets

* fix(cua-driver): complete portable preview dispatch

* test(cua-driver): cover history enforcement inventory

* fix(cua-driver): confine history storage to owned roots
* Report the state query executor's startup health separately

Addresses the review finding on #6886. cyclops_cs_database_features_ready
does not cover /api/state/query, but the alert annotation shipped in #6886
claimed it did.

The state query executor is initialized before the DATABASE_URL
short-circuit, on its own DSN, and a failure there logs and lets the rest of
initializeDatabaseFeatures continue. So a broken state query alongside a
healthy application database left the gauge reporting 1 while
/api/state/query answered 503 — the exact silent degradation #6886 set out
to expose. (The review read that path as returning early; it does not, which
is what makes the blind spot real rather than incidentally covered.)

Add cyclops_cs_state_query_ready with the same configured="true|false"
shape and a CyclopsCSBackendStateQueryDegraded alert beside the existing
one, and correct the original alert's description to claim only the
application-database routes it actually covers.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BgMLQdA6oMLtXo8mr3Ykxn

* Assert the disabled state-query gauge in the remaining cases

Review follow-up on #6887. The three DATABASE_URL-only cases left
wantStateQuery empty, so the else branch that reports
cyclops_cs_state_query_ready{configured="false"} 1 had no regression guard —
dropping it would have left the gauge unset without failing a test.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BgMLQdA6oMLtXo8mr3Ykxn

---------

Co-authored-by: Claude <noreply@anthropic.com>
CloudCyclopsCs-RevId: 1c1095adf504e27e441889212e5202ac9ff6f852
jacob-vincent-mink and others added 17 commits August 24, 2026 23:19
(cherry picked from commit 2f8b49aedeebd5f9c140708593af17bc33e63a4c)
Fail closed on unsupported WebKitGTK pointer delivery, bound single-element AT-SPI lookups, share Hyprland correlation refreshes, add guarded foreground focus leases, and normalize persistent pointer coordinates.
@spencerbull
spencerbull marked this pull request as ready for review August 25, 2026 12:59
@spencerbull
spencerbull marked this pull request as draft August 25, 2026 12:59
@spencerbull

Copy link
Copy Markdown
Author

History repair gate

I rebuilt this as a clean, attribution-preserving series on current upstream main (cb914ed90168b7b711fe53db07032f3a4724b502). Independent history review returned GO: the functional patch is byte-equivalent, the original merge topology is preserved in the integration base, and the Spencer delta is exactly 5 linear commits / 15 files.

Published recovery refs:

  • clean integration base: spencerbull:hyprland-integration-v0.22-base-clean at 6db95494d7bf0a5a059594505fb61df710d21917
  • pre-repair archive: spencerbull:archive/hyprland-agent-mode-v0.22-pre-history-repair at c8a951c4f3c5750b5c68e0b5d2e8a9ee549df9c8

The Jacob integration branch must be moved, not merged. Merging would reconnect its 23 stale-lineage commits and recreate the malformed topology. From a clone where origin is jacob-vincent-mink/cua, the guarded update is:

git fetch https://github.com/spencerbull/cua.git hyprland-integration-v0.22-base-clean
git push --force-with-lease=refs/heads/test/hyprland-integration:1e988d45770ed8bc43128151f095ef28e0bc32c1 \
  origin FETCH_HEAD:refs/heads/test/hyprland-integration

The explicit lease aborts if the Jacob branch moved since this repair was prepared. I have intentionally not force-pushed the PR head yet: doing that before the base move would temporarily widen this PR. After the base reaches 6db95494d, I will rewrite the head from c8a951c4f to clean head 5eb48cbbea18f9f990ef7b65a1ecfc6ed9b685e5 with its own lease and verify GitHub shows exactly 5 commits / 15 files.

@jacob-vincent-mink

Copy link
Copy Markdown
Owner

Merging this into test/hyprland-integration as the selected v0.22 integration update. This accepts the documented personal-desktop/canonical-E2E limits for the integration branch only; it does not certify the eventual upstream landing candidate. Using a merge commit to preserve the authored topology and contributor attribution.

@jacob-vincent-mink
jacob-vincent-mink marked this pull request as ready for review August 26, 2026 21:00
@jacob-vincent-mink
jacob-vincent-mink merged commit 381c132 into jacob-vincent-mink:test/hyprland-integration Aug 26, 2026
jacob-vincent-mink pushed a commit that referenced this pull request Aug 26, 2026
Continued from Spencer Bull's Wayland cursor contribution and its v0.22
forward-port in #2.

Salvaged from trycua#3151

(cherry picked from commit 2f8b49aedeebd5f9c140708593af17bc33e63a4c)
(cherry picked from commit 71bb9f1)
jacob-vincent-mink pushed a commit that referenced this pull request Aug 26, 2026
Continued from Spencer Bull's Wayland cursor contribution and its v0.22
forward-port in #2.

Salvaged from trycua#3151

(cherry picked from commit 34f2286)
jacob-vincent-mink added a commit that referenced this pull request Aug 26, 2026
Continued from Spencer Bull's Wayland cursor contribution and its v0.22
forward-port in #2.

Salvaged from trycua#3151

(cherry picked from commit 2f8b49aedeebd5f9c140708593af17bc33e63a4c)
(cherry picked from commit 71bb9f1)

Co-authored-by: Spencer Bull <7035687+spencerbull@users.noreply.github.com>
jacob-vincent-mink added a commit that referenced this pull request Aug 26, 2026
Continued from Spencer Bull's Wayland cursor contribution and its v0.22
forward-port in #2.

Salvaged from trycua#3151

(cherry picked from commit 34f2286)

Co-authored-by: Spencer Bull <7035687+spencerbull@users.noreply.github.com>
f-trycua added a commit to trycua/cua that referenced this pull request Aug 27, 2026
* fix(cua-driver): isolate Wayland cursors across outputs

Create one initialized layer-shell surface per enabled output, preserve independent named-session cursor state, and keep explicit lifecycle revival aligned with the current session contract.

Adapted with permission from the focused Wayland overlay commits in spencerbull/cua.

Salvaged from #3151

Co-authored-by: Spencer Bull <7035687+spencerbull@users.noreply.github.com>
(cherry picked from commit d60f71f)

* fix(cua-driver): align Wayland desktop capture and input pixels

Normalize native Wayland captures into the reported desktop action frame and expose the real backing scale so screenshot-grounded input and cursor overlays share one coordinate system. Fail closed instead of distorting nonuniform layouts.\n\nRefs #3061.\n\nCo-authored-by: Pagani <33448453+pagan1e@users.noreply.github.com>

(cherry picked from commit c0b02d0)

* docs(cua-driver): clarify persistent GUI sessions

(cherry picked from commit 3e84ef9)

* fix(cua-driver): verify Wayland window activation

(cherry picked from commit 0bde8d3)

* fix(cua-driver): avoid duplicate X11 overlay on Wayland

(cherry picked from commit 0a908f0)

* fix(cua-driver): suppress X11 overlay on Wayland displays

(cherry picked from commit 9042357)
(cherry picked from commit 4bf5d22)

* fix(cua-driver): keep session cursor visible during Linux input

Continued from Spencer Bull's Wayland cursor contribution and its v0.22
forward-port in jacob-vincent-mink#2.

Salvaged from #3151

(cherry picked from commit 2f8b49aedeebd5f9c140708593af17bc33e63a4c)
(cherry picked from commit 71bb9f1)

Co-authored-by: Spencer Bull <7035687+spencerbull@users.noreply.github.com>

* fix(cua-driver): preserve user pointer in agent mode

Continued from Spencer Bull's Wayland cursor contribution and its v0.22
forward-port in jacob-vincent-mink#2.

Salvaged from #3151

(cherry picked from commit 34f2286)

Co-authored-by: Spencer Bull <7035687+spencerbull@users.noreply.github.com>

* test(cua-driver): align cursor revival with v0.22 state

* fix(cua-driver): centralize Wayland cursor backend routing

Select one Linux Wayland overlay backend, prefer native layer-shell over an outdated shell helper, and retain that helper when layer-shell is unavailable. Port the visible first-glide and transparent repaint corrections from #3403 into the existing keyed session model.

Co-authored-by: Francesco Bonacci <f@trycua.com>

* test(cua-driver): capture composed X11 cursor showcase

---------

Co-authored-by: Spencer Bull <7035687+spencerbull@users.noreply.github.com>
Co-authored-by: Francesco Bonacci <f@trycua.com>
LikelyLucid pushed a commit to LikelyLucid/cua that referenced this pull request Aug 31, 2026
Continued from Spencer Bull's Wayland cursor contribution and its v0.22
forward-port in jacob-vincent-mink#2.

Salvaged from trycua#3151

(cherry picked from commit 34f2286)

Co-authored-by: Spencer Bull <7035687+spencerbull@users.noreply.github.com>
(cherry picked from commit 26bbfef)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants