You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Explain and recover from a quarantined ScreenCaptureKit gate #16
Found in the Ace desktop tools study (githubnext/ace#427), D3c on Canary 0.0.46+684262d, 2026-10-15 at about 14:55 EDT.
Observed: in the middle of a run, after a desktop_menu File → New, every desktop_inspect failed with DESKTOP_ERROR: Capture failed: ScreenCaptureKit is quarantined after an abandoned SCShareableContent.fetchWindowForWindowID call.desktop_apps timed out against its 1.00 s observation budget, and another call returned The operation couldn't be completed. Operation timed out. The agent stopped safely and typed nothing. A few minutes later, inspect worked again through the CGWindowList engine (capture.window 770 ms), and apps took 955 ms, close to its 1 s budget.
Likely cause: Peekaboo coordinates ScreenCaptureKit across processes with a per-user lock at $TMPDIR/boo.peekaboo.sckit-capture.lock (ScreenCaptureKitCaptureGate). At the same time, a separate process on the Mac was running Peekaboo's AutomationKit tests (the patch test run for the pin bump), which do real captures. Any two Peekaboo users on one Mac share that gate and can starve or quarantine each other: Ace dev and Canary, Ace and a Peekaboo CLI, or tests.
Asks:
The refusal should say the problem is temporary and caused by another capture, and give a wait-and-retry hint. Today it reads like a broken desktop.
When ScreenCaptureKit is quarantined, inspection should fall back to the CGWindowList capture it already uses afterwards, rather than failing.
Consider giving the gate a host-specific lock, or one keyed to the host's identity, so separate embedding apps don't block each other. Possibly upstream.
The 1 s apps inventory budget leaves no headroom when the Mac is loaded (955 ms when healthy).
More evidence from the githubnext/ace#427 study: Peekaboo's own test runs on the same Mac block Ace's live desktop tools, not just screen capture.
While a swiftpm-testing-helper run of the bridge tests was in progress (most use stubbed services), it held ~/.peekaboo/global.turnstile.lock. An Ace Canary desktop call (desktop_apps) then failed with internalError: Timed out waiting for the desktop operation lane lock at ~/.peekaboo/global.turnstile.lock.
In the same window, an Ace agent's screenshot failed with "ScreenCaptureKit is quarantined after an abandoned SCShareableContent.fetchWindowForWindowID call".
Both locks are per-user and shared by every Peekaboo user (tests, dev builds, Ace's signed runtime), so anyone developing desktop-tools on their own machine disables Ace's desktop tools while their tests run.
Suggestion: namespace the turnstile and SCK gate per runtime or app (for example under Ace's state dir, or keyed by the host bundle ID), and have tests use a temporary lock root.
The refusal is clear now (fix: wait out a quarantined ScreenCaptureKit gate and explain the refusal #63, peekaboo-sck-quarantine.patch). A new capture waits up to 2 s for the abandoned SCK call before refusing. The refusal says the quarantine is temporary, usually comes from another busy capture, and clears by itself, so wait a few seconds and retry. A timed-out wait for another process's capture gets the same wording. Documented in docs/tools.md and native/patches/README.md.
Lock contention can now be traced (fix: name the processes holding a timed-out desktop lane lock #58, peekaboo-lock-holder.patch). A timed-out lane or turnstile lock lists the processes holding it open, such as a swiftpm-testing-helper. docs/build.md warns that Peekaboo tests take the real ~/.peekaboo locks, that HOME doesn't isolate them, and to run them with a narrow filter and a time limit.
Declined by design (reasons in #63 and #58, and in native/patches/README.md):
No CGWindowList fallback. Every other capture path also goes through ScreenCaptureKit, so a fallback would run next to the abandoned call, which upstream rules out.
The SCK gate stays per-user and the coordination root (~/.peekaboo) stays shared. Keying them per host would let separate apps overlap ScreenCaptureKit calls and desktop operations again.
Not done: the suggestion in the comment to give Peekaboo's tests a temporary lock root. Only the warning in docs/build.md exists. If that's still wanted, it's an upstream or test-harness change and could be its own issue.
Recommendation: keep open, waiting only on the live check, which #42 already lists. If the test lock root is still wanted, open it as a separate issue.
Closing: the code side is done. #63 makes a new capture wait out the quarantine, explains the refusal and widens the budgets; #58 names whoever holds a lock. The CGWindowList fallback and per-host locks were declined by design, for the reasons in the 07:29 triage above.
Activity
iamnbutler commentedon Oct 15, 2026
More evidence from the githubnext/ace#427 study: Peekaboo's own test runs on the same Mac block Ace's live desktop tools, not just screen capture.
swiftpm-testing-helperrun of the bridge tests was in progress (most use stubbed services), it held~/.peekaboo/global.turnstile.lock. An Ace Canary desktop call (desktop_apps) then failed withinternalError: Timed out waiting for the desktop operation lane lock at ~/.peekaboo/global.turnstile.lock.Both locks are per-user and shared by every Peekaboo user (tests, dev builds, Ace's signed runtime), so anyone developing desktop-tools on their own machine disables Ace's desktop tools while their tests run.
Suggestion: namespace the turnstile and SCK gate per runtime or app (for example under Ace's state dir, or keyed by the host bundle ID), and have tests use a temporary lock root.
fix: wait out a quarantined ScreenCaptureKit gate and explain the ref…
fix: wait out a quarantined ScreenCaptureKit gate and explain the ref…
fix: wait out a quarantined ScreenCaptureKit gate and explain the ref…
iamnbutler commentedon Oct 17, 2026
Triage against main (after 0.8.0).
Covered on main:
peekaboo-sck-quarantine.patch). A new capture waits up to 2 s for the abandoned SCK call before refusing. The refusal says the quarantine is temporary, usually comes from another busy capture, and clears by itself, so wait a few seconds and retry. A timed-out wait for another process's capture gets the same wording. Documented indocs/tools.mdandnative/patches/README.md.fetchWindowForWindowIDlookup now has 3 s instead of 1 s; that budget is what timed out in this run.peekaboo-lock-holder.patch). A timed-out lane or turnstile lock lists the processes holding it open, such as aswiftpm-testing-helper.docs/build.mdwarns that Peekaboo tests take the real~/.peekaboolocks, thatHOMEdoesn't isolate them, and to run them with a narrow filter and a time limit.Declined by design (reasons in #63 and #58, and in
native/patches/README.md):~/.peekaboo) stays shared. Keying them per host would let separate apps overlap ScreenCaptureKit calls and desktop operations again.Remaining:
global.lockand expecting the holder to be named.docs/build.mdexists. If that's still wanted, it's an upstream or test-harness change and could be its own issue.Recommendation: keep open, waiting only on the live check, which #42 already lists. If the test lock root is still wanted, open it as a separate issue.
iamnbutler commentedon Oct 17, 2026
Closing: the code side is done. #63 makes a new capture wait out the quarantine, explains the refusal and widens the budgets; #58 names whoever holds a lock. The CGWindowList fallback and per-host locks were declined by design, for the reasons in the 07:29 triage above.
npm run peekaboo-test. It runs Peekaboo's tests narrow and time-limited, in the foreground, and kills its own leftover helpers, so a test run no longer holds the shared locks for long. It doesn't move the tests to a separate lock root. That would be an upstream change, and could be its own issue if it's still wanted.