Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ bash scripts/test-dmg.sh "dist/Agent-Job-Queue-Installer-$(cat VERSION)-universa

Apply the shared queue policy to broad tests, builds, analyzers, browser suites, and installers. Keep the Go package and test worker limits at two unless explicitly authorized otherwise. Do not nest queue wrappers. Persistent preview servers stay outside the queue.

Core and HTTPS acceptance tests launch temporary private daemons, directories, child processes, ports, and test credentials. They remove inherited queue overrides before creating their fixture. Browser tests use simulated jobs through the actual Go HTTP interface. Installer and agent integration tests use isolated user directories. They must never operate on the installed queue or real agent instructions. The installer artifact test installs the actual packaged Go binaries into a temporary home and exercises their private queue and scheduler.
Core and HTTPS acceptance tests launch temporary private daemons, directories, child processes, ports, and test credentials. They remove inherited queue overrides before creating their fixture. Browser tests use simulated jobs through the actual Go HTTP interface. Installer and agent integration tests use isolated user directories. They must never operate on the installed queue or real agent instructions. The installer artifact test installs the actual packaged Go binaries into a temporary home and exercises their private queue and scheduler. It also runs the actual outer managed installer, setup and removal with a parent-owned native lifecycle fixture; a private HOME alone cannot isolate real Service Management.

The disk-image check requires the DMG explicitly, mounts it read-only at a private mountpoint, and verifies the enclosed installer signatures, executable permissions, universal architectures, and build identities. A failed detach fails validation and retains its temporary directory. Packaging flushes staged files and disables indexing on its HFS+ image; verbose image-creation diagnostics remain available if macOS reports resource contention.

New disk images contain the self-contained `Agent Queue.app` and an `Applications` shortcut. The app embeds only the source support payload, with no recursive app bundle. First launch from the shared or user Applications folder installs its private backend in place. The installer ZIP retains its existing custom-installer layout for updater and Homebrew compatibility. Disk-image verification also supports retained legacy installer images. Validate a standalone app with `go run -p 2 ./cmd/queue-tool verify-app --app APP_PATH`.
New managed disk images contain the explicit installer app. The installed app carries its runnable helpers in `Contents/MacOS` and its three agent definitions in `Contents/Library/LaunchAgents`, using `BundleProgram`. Its support payload contains metadata and documents, with no recursive app or duplicate helper binaries. Normal launch performs readiness and authorization reads only. The ZIP retains its outer controller payload for updater and Homebrew compatibility. Homebrew delivers the explicit installer and links; the user opens it to install the runtime outside Homebrew's restricted hook sandbox. Homebrew upgrade or uninstall does not replace or remove the running runtime app. Disk-image and signature verification retain support for historical layouts. Validate a standalone app with `go run -p 2 ./cmd/queue-tool verify-app --app APP_PATH`.

Local installer builds use ad hoc development signatures by default. Main CI validates and retains the universal installer. A separate main-only distribution workflow consumes that exact build, requires Developer ID signing, payload-first Apple notarization, stapled app and DMG tickets, and fresh Apple Silicon and Intel acceptance before publication and Homebrew delivery. Distribution fixes can process a retained build with newer trusted main automation. PRs receive no Apple secrets. See [Apple signing and notarization](docs/apple-signing.md) for credential custody, recovery commands and acceptance evidence. Never remove quarantine to make a notarized release pass.

Expand All @@ -52,7 +52,7 @@ bash native/tests/run-menu-bar-ui-tests.sh build/menu-bar-verification.json

The runner builds a private fixture app and sends AppKit events through the actual status button, menus, and window handlers. It records `skippedChecks` when macOS declines foreground activation. `--require-foreground` fails those unavailable checks. It cleans up its own fixture and preserves the installed app and clipboard.

First-launch setup decisions, retries, and guided upgrade recovery are included in the headless native suite. The read-only preflight lists blockers together and offers bounded waiting, reviewed job cancellation, verified cleanup and service startup, phone access disablement, and guided configuration repairs. See [guided upgrade recovery](docs/upgrade-recovery.md) for the action and controller contracts. In a logged-in graphical session, verify the production setup window, failed setup, Disable phone access and continue action, ordinary Retry button, and transition to the simulated queue:
Read-only startup, explicit `--setup` decisions, retries, approval states and guided recovery are included in the headless native suite. Normal launch cannot enter installation or recovery. The explicit setup workflow retains read-only preflight and reviewed recovery actions. Service-management tests inject inert adapters and never register real services. A temporary HOME alone does not isolate macOS's per-user Service Management registry; live registration acceptance needs an isolated login session. See [guided upgrade recovery](docs/upgrade-recovery.md). In a logged-in graphical session, the private fixture verifies the explicit setup window and transition to the simulated queue:

```sh
agent-heavy run --label "First-launch UI checks" -- bash native/tests/run-bootstrap-ui-tests.sh build/bootstrap-ui-verification
Expand Down Expand Up @@ -88,7 +88,7 @@ Native screenshot capture uses artificial jobs and an inert action recorder. It

The CLI command names, JSON fields, SQLite schema and workload identities remain compatible with the Python implementation. Preserve lifecycle, cancellation, process ownership, crash recovery, authentication, scheduling, history and UI regression coverage. macOS resource observations use the same native Mach and libproc counters. Missing or stale telemetry cannot authorize adaptive work.

The first Pueue-to-embedded installation requires a fully drained private queue; migration from Python also requires disabled old remote access. When old phone access blocks first-launch setup, choose **Disable phone access and continue** to stop it through the bundled controller's ownership checks and resume installation. Credentials, configuration, and trusted certificates remain available; phone access can be enabled again in settings after setup. The CLI equivalent is the trailing `--disable-phone-access` option on `agent-heavy install --payload DIRECTORY` or `agent-heavy install --app-bundle ABSOLUTE_APP_PATH`. This recovery only disables phone access when it blocks Python migration. After ownership-checked shutdown, it imports completed tasks and the retained ID sequence into the new SQLite queue, then starts the independent Go daemon and resource controller. Later embedded queue upgrades retain active daemon jobs. An enabled Go remote service is restarted through its ownership-checked lifecycle to adopt the embedded gateway. Its existing bcrypt hash, CSRF secret, and Caddy storage remain in place, including the CA trusted by phones. Private state, history, lease settings, credentials, and the incomplete installation marker remain authoritative across failures and retries. Pueue and a separate Caddy executable are not required for development, installation, or acceptance tests.
Managed service migration, replacement and removal require a fully drained queue before service changes. Migration from Python also requires disabled old remote access. When old phone access blocks explicit setup, choose **Disable phone access and continue** to stop it through the bundled controller's ownership checks and resume installation. Credentials, configuration, and trusted certificates remain available; phone access can be enabled again in settings after setup. The CLI equivalent is the trailing `--disable-phone-access` option on `agent-heavy install --payload DIRECTORY` or `agent-heavy install --app-bundle ABSOLUTE_APP_PATH`. This recovery only disables phone access when it blocks Python migration. After ownership-checked shutdown, it imports completed tasks and the retained ID sequence into the new SQLite queue, then starts the independent Go daemon and resource controller. Later managed upgrades also require drained jobs before unregistering changed helpers; active work blocks changes. An enabled Go remote service is restarted through its ownership-checked lifecycle to adopt the embedded gateway. Its existing bcrypt hash, CSRF secret, and Caddy storage remain in place, including the CA trusted by phones. Private state, history, lease settings, credentials, and the incomplete installation marker remain authoritative across failures and retries. Pueue and a separate Caddy executable are not required for development, installation, or acceptance tests.

The command queue uses the existing pure Go SQLite driver. A durable attempt is claimed before process creation, and detached workers publish their own outcomes. Never automatically retry an attempt with an uncertain outcome. An unclean daemon restart pauses automatic dispatch; verified process ownership and explicit operator recovery remain required. Queue RPC handlers must not acquire backend filesystem locks already held by the scheduler or submitting process.

Expand Down
30 changes: 19 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ Screenshots use sample jobs. The Mac image uses the app's safe preview mode.

### Homebrew

On macOS 15 or later, install the app and CLI through the project's [Homebrew tap](https://github.com/Dunky13/homebrew-agent-job-queue):
On macOS 15 or later, obtain the installer and CLI links through the project's [Homebrew tap](https://github.com/Dunky13/homebrew-agent-job-queue):

```sh
brew install --cask dunky13/agent-job-queue/agent-job-queue
```

Homebrew installs the menu-bar app in your account's Applications folder and links `agent-heavy` and `agent-remote` into its bin directory. Open Agent Queue to complete its private queue setup; the command-line tools are ready once setup finishes. The app shows progress and lets you retry if setup fails. No Xcode or manual installer window is needed.
Open **Agent Job Queue Installer.app** in your account's Applications folder and choose **Install**. It completes queue setup and installs the menu app. Homebrew links `agent-heavy` and `agent-remote` into its bin directory; those links become ready after setup. Finish all queued and running jobs before installing or upgrading the runtime. If macOS requires background-service approval, review Agent Queue in System Settings, then finish installation. Opening the menu app checks readiness without installing or repairing files. No Xcode is needed.

New releases produced by the notarized release pipeline use Developer ID signatures and Apple notarization. Their Homebrew cask verifies the download's SHA-256 and retains quarantine for macOS assessment. It does not bypass Gatekeeper. Older published builds remain ad hoc signed; their historical casks are preserved until a newer release replaces them. See [Apple signing and notarization](docs/apple-signing.md) for the release requirements and verification limits.

Expand All @@ -43,24 +43,32 @@ The tap becomes installable after the first validated `main` installer release i
brew upgrade --cask dunky13/agent-job-queue/agent-job-queue
```

Each successfully published main installer triggers and verifies its Homebrew delivery. Scheduled reconciliation provides recovery. Maintainer setup, failure handling and trusted tap tooling synchronization are documented in [Verified Homebrew delivery](docs/homebrew-delivery.md).
After a Homebrew upgrade, open the updated installer and choose **Install** to upgrade Agent Queue. Homebrew's install-hook sandbox cannot access the private queue socket or manage native services, so Homebrew owns installer delivery while the explicit installer owns the runtime app. Each successfully published main installer triggers and verifies its Homebrew delivery. Scheduled reconciliation provides recovery. Maintainer setup, failure handling and trusted tap tooling synchronization are documented in [Verified Homebrew delivery](docs/homebrew-delivery.md).

Uninstalling the cask removes the menu app and Homebrew command links. It preserves the queue daemon, running jobs, private backend, data, credentials, and any enabled remote service. Disable remote access in settings or with `agent-remote disable` first if you want it stopped.
Homebrew uninstall removes its installer and command links. It leaves the installed Agent Queue app, its private command entry points and services in place. To remove a managed runtime, finish queued and running jobs, then run the following command before moving the app to Trash:

### Drag to Applications
```sh
agent-heavy install --app-bundle "$HOME/Applications/Agent Queue.app" --unregister-services
```

Use the app's actual absolute Applications path if it differs. Exit zero confirms service shutdown and retires generated command entry points. Queue history, configuration, credentials and certificate data are preserved. Quitting the menu app during ordinary use leaves the independent queue and enabled phone access running.

### Installer app

1. Use macOS 15 or later on an Apple Silicon or Intel Mac.
2. Download the DMG from [Releases](https://github.com/Dunky13/agent-job-queue/releases), then open it. Successful main CI builds trigger distribution; a prerelease appears after notarization and both architecture checks pass. CI runs also retain the installer as an artifact for 30 days.
3. Drag **Agent Queue.app** onto **Applications**, then open it from Applications. You can also copy it to your own Applications folder. Opening it from the disk image shows instructions to move it first.
4. On first launch, the app sets up your private queue and login services. It displays progress and lets you retry if setup fails. Once setup finishes, the app appears in your menu bar. Add your local bin directory to your shell's `PATH` to use `agent-heavy` by name.
3. Open **Agent Job Queue Installer.app** and choose **Install**. It verifies the package and queue, installs the app, and registers its background services. Finish all queued and running jobs before installing over an existing queue.
4. Complete any background-service approval requested in System Settings, then finish installation. The app appears in your menu bar once setup succeeds. Add your local bin directory to your shell's `PATH` to use `agent-heavy` by name.

The ZIP remains available for the updater, Homebrew, and per-user installation. Extract it, open **Agent Job Queue Installer.app**, and choose **Install**. Older disk images also contain this installer app.
The ZIP uses the same installer. Older drag-to-Applications images remain available, but copying a new managed app alone does not complete queue setup. Opening an incomplete app shows installation guidance and leaves the incomplete-installation marker intact.

The app includes prebuilt universal executables and a Go queue daemon. The Go remote service embeds Caddy's HTTPS and authentication modules. Homebrew, Pueue, Python, uv, Xcode, and a Go toolchain are not required on the installed Mac. Backend setup runs in your user account without `sudo`; Finder may ask for permission to copy the app into the shared Applications folder. The payload is self-contained, but first-launch Gatekeeper assessment can require Apple connectivity. Offline first launch of the standalone Go executables has not been verified.
The app includes prebuilt universal executables and a Go queue daemon. The Go remote service embeds Caddy's HTTPS and authentication modules. Homebrew, Pueue, Python, uv, Xcode, and a Go toolchain are not required on the installed Mac. Backend setup runs in your user account without `sudo` and defaults to your account's Applications folder. Executable locations must be protected from replacement by other accounts; a group-writable shared Applications folder is refused without changing its permissions. The payload is self-contained, but first-launch Gatekeeper assessment can require Apple connectivity. Offline first launch of the standalone Go executables has not been verified.

The notarized release pipeline signs the installer, menu app and executable payload with Developer ID, submits the release to Apple, and staples tickets to the app bundles and DMG. Historical releases and local development packages can remain ad hoc signed. Installer checksums identify the downloaded bytes; they do not establish notarization.

Upgrades of the embedded Go queue preserve queue configuration, job data, the running daemon, concurrency settings, and remote credentials. Quit the menu app before replacing it in Finder, then open the new copy to update its per-user backend. First-launch setup leaves that app bundle in place. The ZIP installer continues to replace the menu app atomically in your user Applications folder.
The executable helpers and service definitions remain inside the signed app bundle. Apple's Service Management framework registers the queue and resource controller, optional phone service, and app login preference. They are visible in System Settings under Login Items. The installer does not copy new executable helpers to a hidden support directory or create a login service through `open -a`.

Installations and upgrades preserve configuration, history, concurrency settings and remote credentials. They require a drained queue before unregistering or replacing services, because macOS unregisters running helpers before their code can be replaced safely. Active work causes a refusal before service changes; let it finish and run the explicit installer afterward. Normal app startup never retries a failed installation automatically. Keep incomplete-installation evidence until a verified installation succeeds. If endpoint protection quarantines files, obtain IT review before retrying; Developer ID and notarization do not establish acceptance by another security product.

For the first upgrade from Pueue, finish all running and waiting jobs first. If migrating from the Python backend, also disable remote access in the old app. The installer refuses an unsafe migration before replacing support files, then replaces the drained private daemon and resource controller. Completed job IDs, logs, learning history, operator settings, and remote credentials are retained. Previously installed Homebrew packages are left alone because other software may use them.

Expand All @@ -80,7 +88,7 @@ Do not clear quarantine to work around a failed verification of a release advert

## Version and updates

Choose **About and updates** from the queue's gear menu to see the running app and installed controller versions. **Check for updates** finds published builds, including builds with the same version number. **Download and open installer** verifies the selected build and opens the existing installer; choose **Install** there to finish. Running and queued jobs remain with the independent daemon.
Choose **About and updates** from the queue's gear menu to see the running app and installed controller versions. **Check for updates** finds published builds, including builds with the same version number. **Download and open installer** verifies the selected build and opens the installer. Finish queued and running jobs, then choose **Install** there to replace and register the bundle-owned services.

Legacy and local builds are labelled untracked and can explicitly choose a published installer. The updater does not install automatically. It preserves Gatekeeper policy and refuses tracked downgrades. CLI equivalents and verification details are in [Installed version and updates](docs/updates.md).

Expand Down
Loading
Loading