Skip to content

Dev app: reload action and reporting an open launch that exits early #97

Open

Description

@iamnbutler

Status (Oct 15)

The original expectation of a per-lane helper identity running side by side with an installed Ace-dev is superseded by #123.

Remaining

Original report

A desktop build made from a lane cannot be exercised in isolation: every development build shares one helper identity, port, and data directory, so the new client connects to whichever older Ace-dev helper is already installed and running. Validating a UI change in the shipped desktop shell then requires replacing the user's installed development helper.

Reproduction (dogfooding #91 from Ace Canary 0.0.11)

  1. In a lane at origin/main (1ab91be, desktop 0.0.11) plus the Attach images pasted into the composer #91 UI change, run bun scripts/build.ts dev in apps/desktop. This builds apps/desktop/dist/dev-macos-arm64/Ace-dev.app (bundle id dev.ace.desktop.dev) and warns that native desktop inspection needs an Apple Development signature.
  2. open that bundle. The client process (PID 35146) exited before showing a window, with no dialog or log.
  3. Run its Contents/MacOS/launcher directly. The client (PID 35598) shows: "Could not connect to Ace Helper. Ace Helper on port 4141 uses an incompatible protocol; restart it".
  4. Port 4141 belongs to /Applications/Ace-dev.app/Contents/MacOS/Ace Helper (PID 2326, launchd dev.ace.desktop.dev.helper, running since the previous day), an older installed development build. Its host also listens on the tailnet.
  5. The only offered remedy is to restart that helper. That would replace the user's installed development helper and its channel host, so the lane build was never connected and the new UI code was not exercised.

During the same session the supervisor reported that Canary was trying to use an old Ace instance, and stopped validation.

Cause

apps/host/src/config.ts desktop() gives every dev build the same port (4141), ~/.local/state/ace-dev home, settings directory, and keychain service. apps/desktop/src/helper.ts connects to whatever answers on that port and registers the same launchd identifier. Nothing ties a client to the helper built from the same bundle or lane.

Blocks UI validation for #91. Related to #55 ("Keep a working installed Ace separate from the source build under development"). Part of #5.

Activity

  1. iamnbutler commented on Oct 5, 2026

    @iamnbutler
    ContributorAuthor

    Workaround used to unblock #91 validation from Ace Canary 0.0.11 without touching the installed Ace-dev helper (PID 2326 on 4141) or Canary (4142). No code changes were needed:

    1. Run a source host from the lane with disposable state: ACE_HOME=/tmp/ace-paste91/home ACE_CONFIG_HOME=/tmp/ace-paste91/settings ACE_KEYCHAIN_SERVICE=ace-paste91 ACE_PORT=4151 ACE_WEB_PORT=5151 ACE_APP_DIR=/tmp/ace-paste91/web bun apps/host/src/cli.ts serve --port 4151, where ACE_APP_DIR is vite build --outDir of the lane's apps/app.
    2. Copy the lane's dist/dev-macos-arm64/Ace-dev.app and run its Contents/MacOS/launcher directly with the same environment. desktop("dev") keeps explicit ACE_* values, finds the running host on 4151, skips helper registration, and loads the host's UI in its WebKit window.
    3. Verified: the client's WebKit Networking process connects only to 127.0.0.1:4151, and the served index.html and bundle match the lane build.

    Problems found while doing this, which still belong to this issue:

    • The UI in a desktop window is served by whichever host answers on the port (config.app), not by the bundle. A "lane build" therefore shows the lane's UI only if the host is also from the lane. Old helpers serve old UI even when the protocol matches.
    • The recipe needs a hand-built env, a separate vite build, and a manual launcher run. There is no supported command such as bun desktop dev --isolated that does this and cleans up afterwards.
    • A disposable source host always shares itself on the tailnet (100.x:4151 and :5151). There is no way to keep a test host on loopback only.
    • The dev app has no Reload menu item, so picking up a UI rebuild means relaunching the client, which changes its PID and window ID.
    • A background desktop_click at a point in the Ace-dev window was once refused with "occluded … resolved an element in a different window of the same app". Electrobun creates several invisible 30-pt windows per app. Element clicks were unaffected.
  2. iamnbutler commented on Oct 5, 2026

    @iamnbutler
    ContributorAuthor

    Validating the Issues/PRs row actions in an isolated lane runtime (source host on 4161, lane-built Ace-dev with explicit ACE_* env, as described above) turned up one more isolation gap.

    • Shared WebKit data. Every development bundle has the identifier dev.ace.desktop.dev, so a lane build and the installed /Applications/Ace-dev.app share ~/Library/WebKit/dev.ace.desktop.dev/WebsiteDataStore/<id>. Each test port leaves its own origin directory there (localStorage and IndexedDB for http://127.0.0.1:<port>). I found leftovers for 4151 (Attach images pasted into the composer #91), 4161 (this run), and older ports 4187/4189/4193 that I didn't create. After the test client exited, I removed only the 4151 and 4161 origin directories. An isolated run needs its own bundle identifier or data store so that cleanup doesn't mean editing the installed app's WebKit data.
    • Launching a lane build also takes focus and opens its window at a fixed frame (160,120), on top of Canary's window. While Canary covered it, WebKit stopped repainting it until the window was moved.
  3. iamnbutler commented on Oct 5, 2026

    @iamnbutler
    ContributorAuthor

    Diagnosis of today's dev Helper startup blocker (read-only; helper-recovery owns the repair). It is two problems, and Canary is not one of them.

    Canary plus Ace-dev is not the conflict. Canary and Ace-dev have separate bundle IDs, launchd labels, BTM items and launch constraints, ports (4142/4141), ACE_HOME, Keychain services and WebKit stores. sfltool dumpbtm shows both registrations side by side.

    1. The immediate macOS failure was an in-place bundle swap under a live registration.

    • /Applications/Ace-dev.app (an older build, helper PID 2326) was replaced with an Apple Development-signed lane build after the helper was killed rather than unregistered.
    • 13:42:37: backgroundtaskmanagementd: registerLaunchItem: found existing item: uuid=F482B0B0…, then xpcproxy exited due to OS_REASON_CODESIGNING | Launch Constraint Violation … (Constraint not matched) … failure proc [vc: 3], and launchd removed the service.
    • 13:43:26: the next registration used a new item (F59D93B3), and the helper started.
    • launchctl print gui/501/dev.ace.desktop.dev.helper now shows LWCR = { signing-identifier "Ace Helper", team-identifier 8S43JJMN6B, validation-category 3 }. Apple defines validation category 3 as development signing, 5 as ad-hoc and 6 as Developer ID.
    • The registration's constraint follows the signature of whatever build registered it. Changing the signature in place without unregistering first fails, as already recorded in docs/desktop.md, which gives the order to follow: Stop Ace Helper → quit → replace the whole bundle → lsregister → enable.

    2. The recurrence is a stale build, and it will come back.

    3. The underlying design flaw (this issue). Every dev build shares one bundle ID, label, BTM item, port, data, Keychain service and WebKit store.

    • The client attaches to whatever answers on 4141 and loads its UI from that helper.
    • If no helper answers, a lane bundle registers the shared label itself.
    • HostInfo carries no version or path, so the error can't name the stale install.

    Proposed fixes, smallest first:

    • (a) An isolated branch run command that runs a source host with per-run ACE_* values and a free port, launches the lane bundle with the same environment, and cleans up afterwards. This pattern already worked twice today for Attach images pasted into the composer #91 and Open GitHub items on GitHub or in a new channel from the Issues and PRs lists #107.
      • It needs a guard so an externally supplied host never triggers SMAppService registration.
      • It needs a per-run bundle identifier, because Electrobun 1.18.1's BrowserWindow does not forward partition.
      • Optionally, a loopback-only host flag.
    • (b) Add the version and bundle path to /health, and have the protocol error name the conflicting install and offer the isolated run.
    • (c) Until then, never install a lane build over /Applications/Ace-dev.app for validation. Upgrade it only from origin/main, with the same Apple Development identity and the documented unregister-first order. A small install script could enforce that order.
  4. iamnbutler commented on Oct 5, 2026

    @iamnbutler
    ContributorAuthor

    Fix for the default branch-run path: #112 (open, not merged).

    Root cause of Nate's recurring Ace-dev dialogs (Oct 5). Every development build, whether installed or in any lane's dist/, shared dev.ace.desktop.dev: bundle ID, launchd label with a bundle-relative BundleProgram, BTM item/LWCR, port 4141, ace-dev data, Keychain service and WebKit store.

    • A lane client hit the installed 0.0.8 helper ("incompatible protocol").
    • After that helper was stopped, the lane's ad-hoc copy kickstarted the shared label. launchd rejected it with OS_REASON_CODESIGNING | Launch Constraint Violation (vc 10).
    • The reused BTM item then rejected the Apple Development build in /Applications (vc 3).
    • Recovery required removing 17 other same-ID LaunchServices registrations and re-registering. Installed Ace-dev has been running since then (PID 55171, BTM F59D93B3).
    • Canary was not involved: it has 9 same-ID copies, all Developer ID signed, and works.

    #112

    • Each checkout's dev build gets dev.ace.desktop.dev.<hash>, with its own data, preferences, Keychain service, WebKit store and port (4200–4999). It ignores ambient profile variables.
    • It never registers, unregisters or kickstarts Ace Helper. With no host it says so and quits.
    • bun run dev starts the checkout's source host serving its fresh apps/app/dist, refuses any existing listener on its port, and stops host and app together.
    • The shared installed identity requires ACE_DEV_INSTALL=1 and an Apple Development signature.

    Validated live alongside Canary (4142) and installed Ace-dev (4141):

    • Correct protocol and source: the served index.html matches the lane build, and each WebKit process talks only to its own host.
    • Relaunch keeps the lane profile's channels. Ambient ACE_HOME=ace-dev etc. are ignored.
    • SIGINT, SIGTERM and host exit each leave no processes.
    • Host-down fails clearly with no launchd service.
    • Both installed helpers are unchanged (PID, BTM UUID, bundle version, /health).

    Still open here

    • Health doesn't name the bundle or path of a conflicting managed helper.
    • Test hosts still listen on the tailnet.
    • There's no reload menu item.
    • Builds made before the fix in older lanes still carry dev.ace.desktop.dev. LaunchServices re-registered one of them (image-paste-91/.../dist/dev-macos-arm64/Ace-dev.app) without anyone launching it. Delete apps/desktop/dist/dev-macos-arm64 in old checkouts, or rebuild them after rebasing on the fix.
  5. iamnbutler commented on Oct 5, 2026

    @iamnbutler
    ContributorAuthor

    Update: #112 is at 00f203f, open and unmerged. CI passes, and dev-ui-validation's read-only review found no blockers.

    Added since the last comment:

    • Startup-window cleanup. Signal handlers are installed before the build. Stopping the run during the build or before the host is healthy launches nothing and stops any host already started. Verified with SIGTERM mid-build.
    • Collision advice. The runner refuses ports 4140–4142. Collision errors say "Leave it running and set ACE_PORT"; they never say "restart it".
    • Local signing. Dev builds sign with ACE_CODESIGN_IDENTITY, else the untracked repository Git setting ace.codesignIdentity (shared by all worktrees and lanes), else ad hoc.
      • On Nate's Mac it's set to his valid Apple Development SHA-1.
      • Verified: the app, helper and desktop client are all team 8S43JJMN6B, the DR is the same across rebuilds, strict verify passes, and ACE_CODESIGN_IDENTITY=- still builds ad hoc.
      • Release/CI signing is unchanged.
    • Stale same-ID build quarantined. The pre-fix image-paste-91/apps/desktop/dist/dev-macos-arm64/Ace-dev.app (dev.ace.desktop.dev), which LaunchServices had re-registered on its own, was unregistered and moved, inert, to ~/.local/state/ace-quarantine/helper-recovery-2026-10-05/image-paste-91/Ace-dev.app.disabled. LaunchServices now lists dev.ace.desktop.dev only at /Applications. Other old checkouts' dist/dev-macos-arm64 builds should be deleted or rebuilt after rebasing on fix(desktop): isolate checkout development runs from installed helpers #112.

    Installed Ace-dev and Canary are unchanged after all runs:

    • dev.ace.desktop.dev.helper: PID 55171, BTM F59D93B3, 0.0.10, protocol 7 on 4141.
    • dev.ace.desktop.canary.helper: PID 9041, BTM 74FE912C, 0.0.12, protocol 8 on 4142.
    • ~/.local/state/ace-dev mtimes are unchanged.

    Still open here: health doesn't name a conflicting managed helper's bundle, test hosts still listen on the tailnet, and there's no reload menu item. A lane run's source host also doesn't wire ACE_DESKTOP_CLIENT, so agents in channels created inside a lane run lack native desktop tools. Installed Ace-dev remains 0.0.10/protocol 7 until it's deliberately upgraded from origin/main.

  6. iamnbutler commented on Oct 5, 2026

    @iamnbutler
    ContributorAuthor

    The missing native-client wiring is fixed and merged in #118. bun desktop dev now gives its source host/workers the signed client from the same checkout bundle, after filtering inherited Ace settings.

    Validated a signed build through the root dev command alongside Canary. With an intentionally wrong inherited ACE_DESKTOP_CLIENT, a real gateway-created channel worker used the correct isolated home/client and completed native app inventory through pi/OpenAI. Strict signatures, type/lint checks, independent review and CI passed. Root-runner termination removed its own host/app processes and listener; Canary remained healthy. No development app was installed, and no new OS grants were needed for inventory.

    The disposable channel's cleanup exposed a separate storage-close race, now #119. It does not affect the successful native-client check. The other diagnostic/reload/dev-host items in this issue remain open.

  7. iamnbutler commented on Oct 5, 2026

    @iamnbutler
    ContributorAuthor

    More dogfooding exposed confusing permission labels across isolated development builds:

    • desktop-actions: dev.ace.desktop.dev.c1a6b9d2
    • desktop-app-state: dev.ace.desktop.dev.4472239c

    Both appear as Ace-dev. After an Ace-dev entry was enabled, the current build still returned permissionDenied for Accessibility on read-only window inventory. System Settings' add-app chooser remembered the other checkout's path. We selected the exact desktop-app-state app for its grant; no permission was changed by the agent. The enabled row's bundle identity was not established, so this does not prove a stale grant or signing failure.

    Small UX follow-up: make each checkout's development app distinguishable using its existing short dev ID, and show its exact app path beside permission controls in This Mac. Preserve bundle identity, signing requirements, and profile isolation. Part of githubnext/desktop-tools#11 / #5.

    Separate tooling observation: Codex Computer Use inventories the current bundle ID but cannot select it by that ID; selecting its exact app path resolves to the old dev.ace.desktop.dev identity. Registration refresh and a tool-session reset did not change this. That is not evidence of an Ace registration bug and does not explain the permission denial.

  8. iamnbutler commented on Oct 5, 2026

    @iamnbutler
    ContributorAuthor

    Nate made this the sole priority: there must be one Ace-dev permission identity across all development runs. The earlier suggestion to distinguish checkout-specific permission labels is superseded; each checkout must not need a separate grant.

    Fix in draft #123:

    • One dev.ace.desktop.dev app identity and the configured Apple Development signature; missing/ad-hoc signing is refused before building.
    • Separate signed checkout profiles retain the existing channel data, settings, Keychain services, ports, persistent WebKit partitions, and per-profile native-client authorization. Source runs still cannot manage the installed helper.
    • Live validation found a second cause: directly spawning the launcher attributes TCC requests to the parent coding app. Actual tccd logs attributed the direct-launched GUI to Codex. Opening the exact signed app through LaunchServices attributed it to Ace-dev instead.

    Two real builds have identical app/launcher/GUI designated requirements and different profiles. With a single user grant, the LaunchServices-launched second checkout successfully completed window inventory and combined Accessibility/screenshot inspection, without a new request. A client from the other profile was correctly refused. Both persistent WebKit partitions exist separately. System Settings now shows exactly one enabled Ace-dev app-control entry and one enabled screen-recording entry. Three obsolete hashed-identity build bundles were unregistered and quarantined; their source and channel data were preserved. Canary's running helper is unchanged.

    The PR remains draft while the supported dev runner is updated to use LaunchServices and its exact-instance shutdown behavior is verified. No other githubnext/desktop-tools#11 feature work is proceeding until this is complete.

  9. iamnbutler commented on Oct 5, 2026

    @iamnbutler
    ContributorAuthor

    The development-permission fix is implemented and live-validated in #123 (head 4e8f89a; ready for review). Two independent causes were confirmed:

    • Each checkout used a different macOS bundle ID, producing indistinguishable Ace-dev permission entries. All dev apps now use dev.ace.desktop.dev and the same configured Apple Development signer; the separate checkout profile preserves data, credentials, ports, WebKit storage, and native-client routing. Missing/ad-hoc signing is refused before building.
    • Directly spawning the GUI executable caused macOS to attribute requests to the invoking coding app. TCC logs showed that attribution explicitly. The dev runner now opens the exact bundle through LaunchServices and supervises that instance.

    One shared grant successfully covered two real signed checkouts and a subsequent rebuild using the final standard dev runner. Native Accessibility and screenshot inspection passed without another prompt. System Settings has one enabled Ace-dev entry in each relevant privacy panel. A native client targeting the other checkout was rejected. Normal app Quit and SIGTERM to the dev runner cleaned up its app and source host; the other checkout and Canary stayed running during the isolation check. Type, lint/format, signature, and independent source reviews passed.

    The old duplicate permission rows were removed, obsolete dev bundles were quarantined recoverably, and all validation dev apps/hosts are stopped. Channel data is unchanged. The normal checkout has the fix; paused feature branches are receiving only this identity update, with their feature work still paused.

    Source dev runs should coexist with installed Canary, not an installed Ace-dev managed helper: launchd can resolve the shared dev service from another registered bundle. This limitation and the one-time grant migration are now documented. No dev app was installed in Applications.

    Merge is pending GitHub's required check, currently queued. GitHub reports an Actions runner-assignment incident: https://www.githubstatus.com/incidents/3q1yb5m7ltvb. Auto-merge is disabled for this repository; no checks were bypassed. Other work under githubnext/desktop-tools#11 remains paused.

  10. iamnbutler commented on Oct 5, 2026

    @iamnbutler
    ContributorAuthor

    Merged #123 as e6e5c369991a56054af0fbbc20a4ba4882d12b8a at Nate's explicit request to skip the queued CI check. The exact reviewed head was 4e8f89a; local checks and live permission-reuse validation had already passed. GitHub required a temporary bypass for the current user to merge this PR; the original CI ruleset was immediately restored and verified unchanged. Other githubnext/desktop-tools#11 feature work remains paused.

  11. changed the title [-]Run a lane's desktop build without reusing an installed Ace helper[/-] [+]Finish development-run isolation: helper conflict diagnostics, loopback test hosts, and reload[/+] on Oct 6, 2026
  12. iamnbutler commented on Oct 15, 2026

    @iamnbutler
    ContributorAuthor

    The overnight issue watcher is picking up two of the remaining items: helper-conflict errors that name the conflicting helper, and loopback-only test hosts. The dev-app reload and open launch reporting need a GUI, so they're left for later.

  13. iamnbutler commented on Oct 15, 2026

    @iamnbutler
    ContributorAuthor

    #386 (merged) covers two of the Remaining items.

    • Naming the Ace on a port. A protocol or data-directory conflict now names the listener from its PID, e.g. Port 4142 is used by Ace Canary 0.0.35 (/Applications/Ace Canary.app, PID 9041), which speaks a different host protocol than this Ace (10). For a command-line host it gives the working directory and command instead. Each caller (CLI, ace serve, desktop app, bun desktop dev) adds its own remedy, and only this app's own helper is offered a restart. Ace Helper also reports an optional version in /health. That field is outside the proof, so HOST_PROTOCOL stays 10.
    • Loopback-only hosts. ace serve --loopback binds only 127.0.0.1. It doesn't bind the tailnet, discover peers, or publish to the directory. Settings shows it, and bun desktop dev always uses it.

    The desktop dialogs and the bun desktop dev messages weren't exercised live, because they need a GUI. The reload action and the open launch report remain open.

  14. changed the title [-]Finish development-run isolation: helper conflict diagnostics, loopback test hosts, and reload[/-] [+]Dev app: reload action and reporting an open launch that exits early[/+] on Oct 15, 2026
  15. iamnbutler commented on Oct 15, 2026

    @iamnbutler
    ContributorAuthor

    Rescoped: with #112, #118, #123 and #386 merged, only the dev app's reload action and reporting an open launch that exits before showing a window remain. The title and Status now say so. From code on main (102fb15), the desktop menu in apps/desktop/src/index.ts still has no Reload item.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions