Discontinuing Complete: Why Per-App Coordinate Calculation Killed a macOS Autocomplete App

Discontinuing Complete: Why Per-App Coordinate Calculation Killed a macOS Autocomplete App

Today I am officially discontinuing development of Complete, a macOS system-wide spell autocomplete application triggered by a global hotkey. This post explains what the project was, what we achieved, and why the fundamental technical challenge of per-application coordinate calculation made it unsustainable to maintain.


What Was Complete?

Complete was a macOS background agent (LSUIElement) that provided TextEdit-quality spell completions in any application. Press Shift+Command+I anywhere on your Mac, and a floating completion window would appear near your text cursor with spelling suggestions powered by NSSpellChecker.

Key features that were fully implemented:

  • Global hotkey trigger (customizable, with dual hotkey support)
  • Floating completion window with smart positioning
  • Keyboard navigation (arrow keys, Ctrl+P/N, Enter, Escape)
  • Background agent with status bar menu (no dock icon)
  • Dark mode support
  • Settings persistence
  • Cross-app compatibility (TextEdit, VSCode, Chrome, Safari, Mail)
  • Comprehensive test suite (156 tests, >80% coverage)
  • Distribution-ready with Apple notarization workflow

The project reached v0.1.3 with 100 commits, 4 releases, and all 22 planned tasks completed.


The Performance Was Excellent

Before explaining why I stopped, I want to emphasize that technically the app performed remarkably well:

MetricTargetAchieved
Hotkey response<100ms20-50ms
Completion generation<50ms0.005-0.012ms (cached)
Memory usage<50MB13.5-20.6 MB
UI rendering60fps1000fps capable
Cache hit rate85-95%85-95%

The architecture was clean — 8 core components with dependency injection, protocol-based design for testability, and a comprehensive test suite including unit tests, integration tests, and visual screenshot regression tests.


The Killer Problem: Per-App Coordinate Calculation

The core workflow of Complete is straightforward:

  1. User presses the global hotkey
  2. The app extracts text at the cursor position via the macOS Accessibility API (AXUIElement)
  3. NSSpellChecker generates completions
  4. A floating NSPanel window appears near the text cursor with suggestions

Step 4 is where everything falls apart.

The Coordinate System Mismatch

macOS has two different coordinate systems at play:

  • Accessibility API: Uses a top-left origin coordinate system (0,0 is the top-left corner of the screen)
  • NSScreen / AppKit: Uses a bottom-left origin coordinate system (0,0 is the bottom-left corner of the screen)

This means every coordinate retrieved from the Accessibility API needs to be translated before it can be used to position an AppKit window. That translation alone is tricky but solvable — the real nightmare begins when you realize that every application reports cursor coordinates differently.

Every App Is a Special Case

When Complete asks the Accessibility API "where is the text cursor right now?", the answer depends entirely on how the target application implements its accessibility support:

  • TextEdit: Reports accurate cursor coordinates via standard AXUIElement attributes. The gold standard — simple, reliable, and consistent.
  • VSCode (Electron): Uses its own internal coordinate system. The accessibility tree structure is different from native apps, and the reported cursor position requires Electron-specific offset adjustments.
  • Chrome: The browser's accessibility implementation varies depending on whether the cursor is in the address bar, a form input, a contenteditable element, or a text area. Each context reports coordinates differently.
  • Safari: Similar to Chrome but with its own WebKit-specific accessibility quirks. The coordinate reporting differs from Chrome's Blink-based implementation.
  • Mail.app: Uses a mix of native and web-based rendering (for HTML emails), creating yet another variant of coordinate reporting.

For Complete to show its popup at the right position in every app, it would need app-specific coordinate calculation logic — essentially a growing collection of per-application heuristics and offset corrections.

Why This Is Unsustainable

The problem isn't just that the initial implementation is complex. The maintenance burden is the real killer:

  1. App updates break things: Every time Chrome, VSCode, or Safari updates their accessibility implementation, the coordinate adjustments could break silently. The popup would just appear in the wrong place.

  2. Infinite long tail: Beyond the 5 apps I tested, there are hundreds of macOS applications, each with their own accessibility quirks. Supporting "system-wide" autocomplete means supporting all of them.

  3. No standard to rely on: Apple's Accessibility API provides the framework, but there is no guarantee that apps will report cursor coordinates in a consistent way. The API specification is loose enough that widely different implementations are all technically "correct."

  4. Visual-only detection: Coordinate bugs cannot be caught by unit tests. The only way to verify correct popup positioning is through visual screenshot testing — automating TextEdit to 5 screen positions, triggering the popup, and comparing screenshots against baselines. This is extremely slow and fragile.

  5. Coordinate system edge cases: Screen rotation, multiple displays with different DPI scaling, Stage Manager, full-screen apps — each introduces additional coordinate transformation complexity.

I found myself spending more time maintaining per-app coordinate workarounds than building actual features. When the maintenance cost of a single aspect of the app exceeds the value of the entire product, it is time to stop.


What I Learned

1. System-Wide macOS Apps Are Hard

Building something that works in one app is straightforward. Building something that works system-wide via the Accessibility API is an order of magnitude harder. The API provides a common interface, but every app implements it differently under the hood.

2. Visual Testing Is Essential but Expensive

The coordinate bug (Accessibility API top-left origin vs. NSScreen bottom-left origin) was only caught through screenshot testing. Unit tests all passed. This taught me that for UI-positioning-critical apps, visual regression testing isn't optional — but it comes with significant CI/CD overhead.

3. Know When to Stop

Complete was "production ready" by every metric. 156 tests passing, sub-50ms response times, clean architecture, notarized distribution. But production-ready doesn't mean production-sustainable. The ongoing cost of per-app coordinate maintenance would have been a constant drag with no end in sight.

4. NSSpellChecker Is Surprisingly Good

One positive discovery: Apple's NSSpellChecker API is fast and accurate for spell completion. With aggressive NSCache (1000 entries, 10MB), cached lookups took 0.005-0.012ms. If you need spell completions in a macOS app, it is an excellent built-in option.


Project Status

The Complete repository remains public and archived. The code, documentation, and 156-test suite may be useful as reference material for anyone building macOS accessibility tools or global hotkey applications.

Final stats:

  • 100 commits, 4 releases (v0.1.0 - v0.1.3)
  • ~4,500 lines of Swift code across 21 source files
  • 156 tests with >80% coverage
  • Notarized DMG distribution workflow
  • Comprehensive documentation including Accessibility API research

Thank you to everyone who showed interest in the project. Sometimes the right engineering decision is to recognize when a problem's complexity exceeds the value of the solution.


The source code is available at github.com/laststance/complete