Last reviewed: 2026-08-12
This backlog favors small, native macOS improvements over new frameworks or broad feature expansion.
- Status: In progress — runtime menu and VoiceOver checks remain
- Priority: P1
- Dependencies: None
Users need a quick way to suspend global window handling without quitting the app.
- T1 — Add a checked
Enableditem at the top of the status menu. - T2 — Connect it to the existing
AppStateMachine.toggleEnabled()behavior. - T3 — Dim the status icon while paused or unavailable and keep permission messaging distinct.
- T4 — Keep pause temporary unless a persistent setting is explicitly needed later.
- AC1 — Toggling
Enabledimmediately starts or stops event tracking. - AC2 — The menu state and status icon always reflect the actual tracker state.
- AC3 — Re-enabling without Accessibility permission directs the user to the existing permission flow.
Evidence: state transitions and presentation policy are unit-tested; live menu presentation and VoiceOver remain unchecked.
- DOD1 — State transitions and menu presentation have focused tests.
- DOD2 — VoiceOver announces the status button and Enabled state clearly.
- Status: In progress — manual launch and permission-path checks remain
- Priority: P1
- Dependencies: None
Manual first launch should explain the utility briefly, while background login launch must remain silent.
- T1 — Use the existing first-launch value to open HyperWindow Settings on the first manual launch.
- T2 — Show the default move and resize modifier chords in clearly labeled shortcut groups.
- T3 — Add a
Grant Accessibility Accessaction that invokes the native system prompt with the current System Settings fallback. - T4 — Suppress modal permission alerts when launched as a login item.
- AC1 — First manual launch presents Settings and explains how to try the core interaction.
- AC2 — Granting permission activates tracking without requiring a restart when the event tap can be created.
- AC3 — Login-item launch never steals focus or presents a modal alert.
- AC4 — Missing permission remains visible through the status menu and Settings.
- DOD1 — Manual launch, login launch, permission grant, and permission revocation paths are tested.
- DOD2 — No onboarding wizard or additional framework is introduced.
Evidence: launch policy and UI wiring are covered statically and by focused tests. A live installed-build launch presented Settings, the permission warning, and the System Settings fallback correctly; login-item launch plus grant/revoke transitions remain unchecked.
- Status: In progress — keyboard, VoiceOver, and Accessibility Inspector checks remain
- Priority: P1
- Dependencies: None
The existing AppKit interface should follow current macOS naming, keyboard, and accessibility conventions.
- T1 — Rename
Preferences…toSettings…, wire the existing Command-Comma item, and title the windowHyperWindow Settings. - T2 — Remove irrelevant document-template menus and disable minimize for the Settings window.
- T3 — Display modifier keys as
⌘,⌥,⌃,⇧, andfnin clearly labeled Move and Resize groups. - T4 — Replace conflict-only beeps with the inline message
Move and Resize modifiers must differ. - T5 — Replace the mouse-only GitHub field with a keyboard- and VoiceOver-accessible link.
- T6 — Add standard
About HyperWindowandReport an Issue…commands using existing app metadata and URLs.
- AC1 — Command-Comma opens Settings from an active HyperWindow process.
- AC2 — Every Settings control and link is reachable and understandable with keyboard navigation and VoiceOver.
- AC3 — Invalid modifier combinations explain how to recover.
Evidence: a hosted-app test invokes the Command-Comma menu item and verifies the Settings window opens; both XIBs compile and Debug/Release builds pass. Live accessibility-tree inspection confirmed labels and help text for every control and link, and live modifier changes confirmed immediate shortcut-copy and inline-conflict updates. Keyboard traversal, VoiceOver, and Accessibility Inspector checks remain.
- DOD1 — The Settings window is checked with Accessibility Inspector.
- DOD2 — The README screenshot reflects the shipped interface.
- Status: Open
- Priority: P1
- Dependencies: None
HyperDock writes AXPosition/AXSize fire-and-forget and never reads the frame back mid-drag; it trusts its own computed rect and lets the next mouse event re-anchor (it computes from moveResizeInitialWindowRect + absolute displacement from drag start, so app-side clamping self-corrects on the next event). HyperWindow verifies every write with blocking reads: move(to:) does setOrigin → origin(); resize(delta:) does setSize → size() → setOrigin → origin() — up to four synchronous AX round-trips per commit. HyperWindow already computes from initialOrigin/initialLocation, so the read-backs buy nothing during an active drag.
- T1 — In the commit path (the timer tick after AR-011), drop the
window.origin()/window.size()read-backs; use the write'sAXError-backedBoolreturn as the only failure signal. - T2 — Keep
trackingInfo.origin/sizeadvancing from the requested (math) values, not applied values; remove theappliedOrigin/appliedSizeadjustment logic that only existed to honor read-back results. - T3 — Preserve the existing native-minimum-size clamp behavior: resizing a window with a minimum size must still stop at the clamp rather than jitter or run away (the clamp is enforced by the app's AX server; our requested rect may exceed it — confirm the visual result stays pinned).
- AC1 — No
AXUIElementCopyAttributeValuefor position/size occurs during an active drag. - AC2 — A failed write (non-
.success) still aborts the operation and resets state. - AC3 — Resizing a minimum-size window does not jitter or run away.
- DOD1 — Existing
TrackerTestsresize/clamp cases pass with read-back removed; tests asserting applied-vs-requested rect behavior are updated to the trust-and-commit contract.
- Status: Open
- Priority: P1
- Dependencies: None
HyperDock never calls AXUIElementCopyElementAtPosition. Its +[OCWindow windowUnderMouse] hit-tests with CGWindowListCopyWindowInfo (fast, pure CoreGraphics), then resolves the AX element once per drag: AXUIElementCreateApplication(ownerPID) → copy AXWindows → match candidates by position/size with a title fallback. HyperWindow's AXUIElement.window(at:) (HyperWindow/AXUIElement+ext.swift) uses the systemwide AXUIElementCopyElementAtPosition with a 0.5 s messaging timeout on the event-tap thread at every drag start — the slowest AX entry point and the one most prone to stalling on hung apps.
- T1 — Implement a CGWindowList hit-test:
CGWindowListCopyWindowInfo([.optionOnScreenOnly, .excludeDesktopElements], kCGNullWindowID), front-to-back order, layer 0, skip our own PID and windows without bounds; return the frontmost window containing the point. - T2 — Resolve the AX element from the CG result:
AXUIElementCreateApplication(pid), boundedAXUIElementSetMessagingTimeout(~0.5 s), copyAXWindows, match by frame equality within a small tolerance (±2 px); fall back to a title match, then to the currentAXUIElementCopyElementAtPositionpath only if both fail. - T3 — Surface the result as the existing
TrackingWindowsoTrackeris untouched; keep the current "unsupported window returns nil" behavior for non-participating apps (README's Known Limitations).
- AC1 — Drag start no longer calls
AXUIElementCopyElementAtPositionon the happy path. - AC2 — Starting a drag over a hung app fails fast (bounded by the explicit messaging timeout) instead of stalling the tap.
- AC3 — The matched window set matches today's (normal document/app windows); windows the current code rejects still return nil.
- DOD1 — CG→AX matching (tolerance, title fallback, nil cases) is unit-tested with synthetic window-info fixtures; the CGWindowList query is isolated behind a small function so tests can stub it.
- Status: In progress — release-workflow execution on the current revision remains
- Priority: P2
- Dependencies: None
Release artifacts should identify their contents correctly and support the widest macOS range the current APIs allow.
- T1 — Fail release workflows when the tag or manual release version differs from
MARKETING_VERSION. - T2 — Evaluate lowering the deployment target from macOS 15.2 to macOS 13.
- T3 — Smoke-test move, resize, Accessibility permission, and launch-at-login behavior on macOS 13 before changing the published requirement.
- AC1 — A mismatched release version cannot be published.
- AC2 — The app builds universally for the selected deployment target.
- AC3 — The README and release notes report the tested minimum macOS version.
- DOD1 — Tag, manual-release, and compatibility checks run in CI.
- DOD2 — Ventura runtime evidence is recorded before lowering the deployment target.
Evidence: tag/manual versions are gated before release; the current macOS 15.2 artifact builds for arm64 and x86_64. A macOS 14 target override fails because NSCursor.frameResize requires macOS 15+, so Ventura cannot run the current implementation. README and generated release notes consistently state macOS 15.2 or newer. Workflow YAML and version-gate behavior pass local validation; current-revision remote execution remains pending.
- Status: In progress — manual multi-display and cancellation checks remain
- Priority: P2
- Dependencies: None
Window manipulation should communicate its active mode and avoid leaving windows unreachable.
- T1 — Show a move cursor while moving and corner-appropriate resize cursors while resizing.
- T2 — Restore the prior cursor on every reset, failure, and permission transition.
- T3 — Keep enough of the title bar within a display's visible frame when moving.
- T4 — Prevent invalid negative or effectively unusable requested dimensions.
- AC1 — Cursor feedback matches the active operation and selected resize corner.
- AC2 — Cancelling or failing an operation never leaves a custom cursor active.
- AC3 — Moving across multiple displays cannot make the entire title bar unreachable.
- DOD1 — Multi-display, minimum-size, and cancellation behavior is manually verified.
- DOD2 — No snapping, tiling, or layout engine is added.
Evidence: deterministic tests cover cursor restoration, display-coordinate conversion, cross-display boundaries, native minimum clamping, and failure cancellation; live multi-display verification remains.
- Status: Open
- Priority: P2
- Dependencies: None
While HyperDock consumes drag events during an active operation, it reposts an equivalent mouseMoved (CGEventCreateMouseEvent + CGEventPost) so the target app keeps receiving hover and cursor updates. HyperWindow swallows consumed events (returns nil from myCGEventCallback), so hovered UI in the target app freezes mid-drag.
- T1 — When
handleEventabsorbs a*MouseDraggedevent during an active move/resize, post a syntheticmouseMovedat the same location (preserving relevant modifier flags) viaCGEventPost. - T2 — Guard against re-entry: the synthetic event flows through our own tap; it must not start a new tracking cycle or recurse (state is already active — verify
startTrackingcannot re-trigger, and add a regression test). - T3 — Post only while an operation is active; never when idle.
- AC1 — During a drag-activated resize, the target app's hover feedback (cursor shape, hover highlights) continues to update.
- AC2 — No event recursion or duplicate tracking starts; idle behavior unchanged.
- DOD1 — A
TrackerTestscase asserts the synthetic post occurs only in the active-absorb path (inject the post function throughTracker.Dependenciesfor testability).
Do not add a SwiftUI rewrite, window-snapping engine, updater framework, global-shortcut framework, app exclusion system, or preset system until a concrete user need justifies it.