Skip to content

fix(observer): capture active window via NSWorkspace, not osascript (beat 20)#258

Merged
AVADSA25 merged 1 commit into
mainfrom
fix/observer-nsworkspace-collector
Jul 15, 2026
Merged

fix(observer): capture active window via NSWorkspace, not osascript (beat 20)#258
AVADSA25 merged 1 commit into
mainfrom
fix/observer-nsworkspace-collector

Conversation

@AVADSA25

Copy link
Copy Markdown
Owner

Bug

The observer (codec-observer) polled but captured nothing — ~/.codec/observer_buffer.json entries had active_window: {}, so beat 20 ("what was I doing?") could only honestly say it saw nothing.

Root cause (proven)

_get_active_window() used osascript → System Events (Automation permission). macOS TCC attributes that subprocess to the PM2/node launcher, not the granted python3.13, so the daemon's Framework Python got {} even after the operator granted Automation + Screen Recording. (_get_active_window() run as that exact python returned {}; a plain shell osascript returned the app.)

Fix

  • App + pid: NSWorkspace.sharedWorkspace().frontmostApplication() — public API, no TCC permission, works from a background daemon.
  • Title: Quartz.CGWindowListCopyWindowInfo — uses the already-granted Screen Recording permission (the observer's OCR path).
  • osascript kept as a headless/CI fallback (_get_active_window_osascript).

Verify

As the daemon's framework Python: {}{'app':'Google Chrome','title':'… - Gmail'}. py_compile + ruff clean, 52 observer tests pass. After merge + pm2 restart codec-observer + one poll, the buffer fills and "what was I doing?" returns a real timeline.

🤖 Generated with Claude Code

…beat 20)

The observer polled but captured nothing — active_window={}, so "what was I
doing?" could only say "saw nothing." Root cause: _get_active_window used
osascript/System Events (Automation permission), and macOS TCC attributes that
subprocess to the PM2/node launcher, not the granted python3.13 — so the daemon
never got a value even after the operator granted Automation.

Fix: get the app name + pid from NSWorkspace.frontmostApplication() (a public
API needing NO TCC permission — works from a background daemon) and the focused
window title from Quartz CGWindowList (uses the already-granted Screen Recording
permission the observer uses for OCR). osascript kept as a headless/CI fallback.
Verified as the daemon's framework Python: {} → {'app':'Claude','title':'Claude'}.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@AVADSA25
AVADSA25 merged commit 1cfb72a into main Jul 15, 2026
1 check passed
AVADSA25 added a commit that referenced this pull request Jul 16, 2026
)

DEMO_SCRIPT.md had been rewritten locally (the 15→22→25-beat seal, performance
reorder, name-drop moats table) but was never actually committed — it sat as
an uncommitted edit in the shared working tree since 2026-07-14. Committing the
full sealed version now, plus today's status refresh:

- #21 self-improve: now fully conversational (#257), no longer "fix in progress"
- #20 observer recall: fully fixed — routing (#256), real NSWorkspace capture
  (#258), honest on out-of-range clock-time asks (#260)
- #14 Pilot: navigation confirmed live; live-view click-through flagged as a
  rebuild in progress (was mis-marked READY)
- #19 Connector: OAuth sign-in itself confirmed working; connected/disconnect
  state + persistent tokens flagged as a rebuild in progress
- #18: note to set the CODEC connector to Always Allow in Claude's settings

Co-authored-by: Mickael Farina <farina.mickael@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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.

2 participants