Attention escalation: idle-aware presence, floating approval prompt, cross-device forward (goal 0023) - #8
Merged
Conversation
…rompt, alert guidance, cross-device forward (goal 0023)
Closes the twice-observed missed-decision failure ('background-ish
pattern, not user attention pattern'):
- internal/adapters/idletime (ioreg HIDIdleTime shell-out, zero cgo,
no TCC gate — research-verified; the clipboard.go pattern): presence
is now idle-aware. SettingsService.isAway is the ONE decision point:
away = unfocused OR idle >= threshold (default 300s, Teams' own
away default; a Settings knob). Fixes the focused-but-absent
suppression bug (document.hasFocus() alone said 'present' for an
unattended Mac). Idletime errors fail toward notifying.
- Floating approval prompt (the incoming-call/askpass pattern,
ADR-0033's second-window mechanism reused): a small always-on-top
window appears over whatever app is focused when a decision parks
while away — Approve/Deny inline for MCP writes, Open-in-Mill for
guardrail parks (typed input, never blind approval). Deliberately
no HideOnFocusLost: a decision prompt never auto-dismisses (the
VS Code severity rule); Escape is the explicit dismiss.
- notify.Start now actually requests notification authorization
(never called before — found reading the pinned source); Settings
copy documents the macOS Alerts-style toggle (Duo's documented ask).
- Cross-device forward (default off): pending decisions optionally
POST {kind,id,description,createdAt} through the user's OWN
configured HTTPRequest via the same transport tail Decision
webhooks use (never a second HTTP client) — the only layer that
reaches an owner at another machine; §1.1-clean. httptest-covered.
- e2e: approval-prompt.spec.ts (hash-route standalone render +
approve-executes); mcpTestClient.ts extracted as the shared
real-MCP-client helper. Window-level behaviors manual-only.
Goal 0023 archived; SPEC §3.7 + ADR-0032 Update in-change. Full gates
green (go -race, lint both tag sets, 178 vitest, 153 e2e).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FYwojT8GdUbYSoggbvEFft
alicoding
enabled auto-merge
August 12, 2026 01:31
7 tasks
alicoding
added a commit
that referenced
this pull request
Aug 13, 2026
…ld reap (BACKLOG Standing #8) (#52) Two mechanical fixes for the owner-hit THREE-concurrent-mill.dev.app incident (real crash risk on a 16GB machine): (a) Per-rebuild reap: build/config.yml's dev_mode.executes gains a `type: blocking` pkill step right before the `primary` `wails3 task run` step. Blocking steps re-run on every reload cycle (confirmed directly against the vendored github.com/atterpac/refresh engine source), backstopping refresh's own kill-then-restart regardless of whether it actually reaps the previous instance -- a live task dev session was caught, mid-investigation, with two concurrent mill.dev.app processes, one orphaned into a foreign process group refresh's own tracking never caught. Root cause not fully pinned to one line since it's inside a vendored third-party dependency; this reap is an independent, pattern-based backstop rather than a patch to code this repo doesn't own. (b) Concurrent-start guard: internal/devguard (a real Go package, unit-tested) runs as the first step of Taskfile.yml's `dev:` task, checks for an already-running `wails3 dev` process for this exact repo, and exits non-zero naming the conflicting PID before the existing destructive sweep steps can run -- which would otherwise silently kill a genuinely live first session's own vite/app instead of refusing to start. Verified live against a real running session (correctly detected and refused, naming the actual PID). Manual-only registry entry added (.claude/skills/run-mill/SKILL.md) for what CI structurally can't prove: real per-rebuild-orphan prevention across several live Go-triggered rebuilds, and a genuine second-terminal task dev invocation actually refusing to start. Claude-Session: https://claude.ai/code/session_018pkViCNAuZp2vBv2K9AbUh Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
alicoding
added a commit
that referenced
this pull request
Aug 13, 2026
…ld reap (BACKLOG Standing #8) Two mechanical fixes for the owner-hit THREE-concurrent-mill.dev.app incident (real crash risk on a 16GB machine): (a) Per-rebuild reap: build/config.yml's dev_mode.executes gains a `type: blocking` pkill step right before the `primary` `wails3 task run` step. Blocking steps re-run on every reload cycle (confirmed directly against the vendored github.com/atterpac/refresh engine source), backstopping refresh's own kill-then-restart regardless of whether it actually reaps the previous instance -- a live task dev session was caught, mid-investigation, with two concurrent mill.dev.app processes, one orphaned into a foreign process group refresh's own tracking never caught. Root cause not fully pinned to one line since it's inside a vendored third-party dependency; this reap is an independent, pattern-based backstop rather than a patch to code this repo doesn't own. (b) Concurrent-start guard: internal/devguard (a real Go package, unit-tested) runs as the first step of Taskfile.yml's `dev:` task, checks for an already-running `wails3 dev` process for this exact repo, and exits non-zero naming the conflicting PID before the existing destructive sweep steps can run -- which would otherwise silently kill a genuinely live first session's own vite/app instead of refusing to start. Verified live against a real running session (correctly detected and refused, naming the actual PID). Manual-only registry entry added (.claude/skills/run-mill/SKILL.md) for what CI structurally can't prove: real per-rebuild-orphan prevention across several live Go-triggered rebuilds, and a genuine second-terminal task dev invocation actually refusing to start. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018pkViCNAuZp2vBv2K9AbUh
alicoding
added a commit
that referenced
this pull request
Aug 13, 2026
…tion (#80) Both v0.1.0 release attempts hung the runner in darwin:run: the build task's closing echo used backticks around 'task package' and 'task run' inside a sh string -- command substitution, so printing the help message BUILT AND LAUNCHED the real app, which never exits headless. Plain quotes now. Likely also the source of phantom local Mill instances after any 'task build' (Standing #8's class). Claude-Session: https://claude.ai/code/session_01FJ8wStsHyu7XPLTspNjMnQ Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
alicoding
added a commit
that referenced
this pull request
Aug 15, 2026
…con (task #8) Wails3's own SystemTray API (app.SystemTray.New(), confirmed real and previously entirely unused by reading pkg/application/systemtray.go/ system_tray_manager.go directly -- zero new dependency, same tier of finding as the earlier updater/window-geometry discoveries) answers "is Mill running" the way Raycast/Alfred/1Password already do (docs/SPEC.md §3.7's own earlier research already converged on this: a persistent menu-bar icon IS the running-indicator pattern, not a separate status API). Uses the safer, reversible default this session's own goal named explicitly: coexists with the dock icon rather than replacing it -- ApplicationShouldTerminateAfterLastWindowClosed stays true, unchanged, this is not a menu-bar-only redesign. Clicking the tray icon (or its "Show Mill" menu item) reuses SettingsService.ShowWindow, a small extraction from the summon hotkey's own existing show/restore/focus sequence (bindSummon) rather than a second copy of the same three lines -- one behavior, two triggers now. A "Quit" menu item calls app.Quit(). Uses build/appicon.png (already existing, 1024x1024 full color) as the tray image via SetIcon, not SetTemplateIcon -- macOS's monochrome- template-icon convention needs a dedicated small alpha-only asset Mill doesn't have; named honestly as a real, minor polish gap rather than silently reaching for a mismatched asset. Verified: go vet, golangci-lint (0 issues), go build clean on both desktop and CGO_ENABLED=0 server-mode tags (SystemTray/Menu/Quit all resolve regardless of tag, matching how window creation itself is already unconditional), a real server-mode Playwright smoke run confirms no startup crash, full Go suite passes with -race, and a new test (TestShowWindow_NilWindow_DoesNotPanic) covers the nil-window guard now that ShowWindow has two callers instead of one. Not independently verified visually on the real macOS menu bar in this pass -- no screen access from this session; documented honestly in SPEC.md rather than claimed. Documented in docs/SPEC.md §3.7. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FYwojT8GdUbYSoggbvEFft
alicoding
added a commit
that referenced
this pull request
Aug 15, 2026
…14) Real empirical test, not assumed from the tool list: built a real go build -tags mcp . desktop binary, launched it, connected a genuine MCP client (the SDK's own client role), and exercised the built-in server's 16 tools -- app_info, windows_list, window_control, dom_query, call_bound_method, keyboard_press among them. The specific open question from task #14's own scoping (raised when this tool was first surfaced this session): does keyboard_press trigger a real OS-level global hotkey golang.design/x/hotkey's listener can see, or only a DOM-scoped KeyboardEvent? Answered definitively: called call_bound_method to bind a real summon hotkey (main.SettingsService.AssignSummonHotkey, an actual TCC/Accessibility- gated OS registration -- succeeded, no error), minimised the window, then sent keyboard_press with the identical combo. The press reached and was handled by the real DOM (its own response returned the genuine rendered page text), but a follow-up app_info call showed the window's minimised/visible state unchanged -- proving keyboard_press is DOM-scoped only, does not reach the OS-level listener. Verdict recorded in .claude/skills/run-mill/SKILL.md (not adopted into the standing workflow -- a one-off spike, not wired into CI/Lefthook): this tool closes part of run-mill's own already-documented desktop- only gap (window/tray state -- SetIcon'd tray from task #8, minimise/ show/focus -- is now agent-drivable via window_control/dom_query/ call_bound_method) but not hotkey-delivery verification specifically, which still needs the real desktop app checked by hand, exactly as SKILL.md already said before this spike. Real bug hit and fixed along the way, not glossed over: the SDK's call_bound_method tool takes a `name` argument (package.Service.Method), not `method` as first guessed -- the tool's own error message ("missing required argument: name") caught this immediately rather than silently no-op'ing. No permanent code shipped -- the spike client and its throwaway Go module were built in /tmp and discarded after use, matching this task's own framing as investigation, not a feature. docs/SPEC.md §3.7 carries a short pointer to the SKILL.md verdict rather than duplicating it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FYwojT8GdUbYSoggbvEFft
alicoding
added a commit
that referenced
this pull request
Aug 15, 2026
Attention escalation: idle-aware presence, floating approval prompt, cross-device forward (goal 0023)
alicoding
added a commit
that referenced
this pull request
Aug 15, 2026
…ld reap (BACKLOG Standing #8) (#52) Two mechanical fixes for the owner-hit THREE-concurrent-mill.dev.app incident (real crash risk on a 16GB machine): (a) Per-rebuild reap: build/config.yml's dev_mode.executes gains a `type: blocking` pkill step right before the `primary` `wails3 task run` step. Blocking steps re-run on every reload cycle (confirmed directly against the vendored github.com/atterpac/refresh engine source), backstopping refresh's own kill-then-restart regardless of whether it actually reaps the previous instance -- a live task dev session was caught, mid-investigation, with two concurrent mill.dev.app processes, one orphaned into a foreign process group refresh's own tracking never caught. Root cause not fully pinned to one line since it's inside a vendored third-party dependency; this reap is an independent, pattern-based backstop rather than a patch to code this repo doesn't own. (b) Concurrent-start guard: internal/devguard (a real Go package, unit-tested) runs as the first step of Taskfile.yml's `dev:` task, checks for an already-running `wails3 dev` process for this exact repo, and exits non-zero naming the conflicting PID before the existing destructive sweep steps can run -- which would otherwise silently kill a genuinely live first session's own vite/app instead of refusing to start. Verified live against a real running session (correctly detected and refused, naming the actual PID). Manual-only registry entry added (.claude/skills/run-mill/SKILL.md) for what CI structurally can't prove: real per-rebuild-orphan prevention across several live Go-triggered rebuilds, and a genuine second-terminal task dev invocation actually refusing to start. Claude-Session: https://claude.ai/code/session_018pkViCNAuZp2vBv2K9AbUh Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
alicoding
added a commit
that referenced
this pull request
Aug 15, 2026
…tion (#80) Both v0.1.0 release attempts hung the runner in darwin:run: the build task's closing echo used backticks around 'task package' and 'task run' inside a sh string -- command substitution, so printing the help message BUILT AND LAUNCHED the real app, which never exits headless. Plain quotes now. Likely also the source of phantom local Mill instances after any 'task build' (Standing #8's class). Claude-Session: https://claude.ai/code/session_01FJ8wStsHyu7XPLTspNjMnQ Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Delivers goal 0023 end to end — the ADR-0034 flow's first PR.
internal/adapters/idletime(ioreg HIDIdleTime, zero cgo, research-verified no TCC gate); away = unfocused OR idle ≥ 300s (Settings knob); fixes the observed focused-but-absent notification suppression; errors fail toward notifyingGoal archived; SPEC §3.7 + ADR-0032 Update ride the change. Full local gates green (go -race, lint both tag sets, 178 vitest, 153 e2e).
🤖 Generated with Claude Code
https://claude.ai/code/session_01FYwojT8GdUbYSoggbvEFft