Skip to content

Releases: jhuebel/Automator

v2.5.1 — Fix stale test suite

Choose a tag to compare

@jhuebel jhuebel released this 17 Jul 22:17

Bugfix: stale test suite

No app behavior changes — this release fixes the test suite itself, which had drifted from the app over time. Root-caused all 23 previously-failing tests to two distinct issues rather than treating them as one bug:

What was wrong

  • UserFactory never set username — a required, unique column added when this app moved from Laravel's default email-based login to username-based login. Every test creating a user via the factory failed at the database insert before its actual logic ran.
  • Several auth tests still targeted pre-customization routes and components. This app replaced Breeze's self-service auth scaffold with admin-provisioned accounts (Settings → Users) and SSO: self-registration, self-service password reset, and self-service email verification were all deliberately removed, /profile was renamed to /my-account, and the navigation component was split into layout.header/layout.sidebar. The leftover scaffold tests were never updated to match.

What changed

  • Fixed UserFactory to set username.
  • Removed RegistrationTest, PasswordResetTest, and EmailVerificationTest outright — they exercised routes and components that no longer exist by design, not bugs to fix.
  • Updated AuthenticationTest and ProfileTest to match the app's actual current routes, component names, and behavior (including that login now authenticates by username, and the profile-email form no longer resets verification status, since that concept doesn't apply to admin/SSO-provisioned accounts).

Test suite: 52 tests / 29 passing / 23 failing → 41 tests / 41 passing.

v2.5.0 — Runner Groups

Choose a tag to compare

@jhuebel jhuebel released this 17 Jul 22:02

Runner Groups

Runners can now be grouped into named, many-to-many pools — by region, by proximity to the resources they automate, or any other grouping that makes sense for your fleet — so a script or scheduled job can target "whichever eligible runner in this group is available" instead of pinning to one specific runner.

Why

Routing was previously single-runner only: pin to one exact runner, or auto-pick the least-busy runner fleet-wide by tags and language. There was no way to say "run this against whichever of these particular runners is free" for a set of runners that don't necessarily have identical capabilities individually but collectively cover what a job needs.

What's new

  • Runner Groups — create named groups from Settings → Runner Groups and assign runners to them; a runner can belong to more than one group (e.g. a host that's both us-east and shared-terraform).
  • Aggregate eligibility — a group is eligible for a language or a set of required tags if any member runner qualifies, not all of them — since an execution always ends up running on one concrete runner, RunnerAssignmentService picks the least-busy eligible member of the targeted group at assignment time. The Settings tab shows this as aggregate language badges per group.
  • Group-aware pickers — the Run Script and Scheduled Jobs runner dropdowns now list both runner groups and individual runners (in separate sections), and scheduled jobs can be pinned to a group via preferred_runner_group_id, mutually exclusive with pinning to a single runner.
  • Cross-navigation — each runner's expandable detail row in Settings → Runners now shows which groups it belongs to.
  • Purely a management-plane concept — the Go runner binary is unchanged; groups are never sent to or evaluated by the runner itself.

Upgrading

Two new tables (runner_groups, runner_group_runner) and one new column
(preferred_runner_group_id on scheduled_jobs) — run php artisan migrate --force as usual.
No existing behavior changes until you create a group and start targeting it.

v2.4.0 — Runner self-update mechanism

Choose a tag to compare

@jhuebel jhuebel released this 17 Jul 21:05

Runner self-update mechanism

Runners can now check in with the management plane for newer released builds and update themselves in place, closing the last piece of fleet operations that still required manually rebuilding, copying, and restarting each runner by hand.

Why

As the runner fleet grows, keeping every host's binary current is real toil, and until now there was no visibility into which runners were running stale code beyond the version shown in Settings → Runners. This reuses the existing 15s heartbeat as the discovery channel and the runner's existing Sanctum bearer token for the download — no new polling loop, no new credential type.

What's new

  • Self-update over heartbeat — if Settings → Runners' "Automatically offer runner updates" toggle is on, a heartbeat response includes an update field whenever a newer released build exists for that runner's os/arch. The runner downloads it, verifies its sha256 checksum, replaces its own binary in place (atomic rename on Linux; rename-aside-then-write on Windows), and exits cleanly so the process supervisor (systemd/NSSM) relaunches it — never interrupting a script that's currently running.
  • Two-step publish → release, always — automator:publish-runner-binary stores a binary as a draft (checksum + size computed, never offered to the fleet). Only a separate, explicit automator:release-runner-binary makes it live. A bad build can never reach the fleet automatically and unattended. packaging/build.sh now publishes both cross-compiled binaries on every build, but never auto-releases.
  • Rollback is just re-releasing — releases are ordered by released_at, not semver, so shipping an older version again is the entire rollback procedure.
  • Settings visibility — the global toggle and a per-runner "(update to X.Y.Z available)" hint (shown independent of the toggle, so staleness is visible even with auto-update off) were added to Settings → Runners.
  • New automator-runner version subcommand for standalone on-host debugging.

Verified end-to-end against a live runner: idle-gate deferral while a job is running, successful update + supervisor restart once the job finishes, checksum-mismatch refusal leaving the running binary untouched, and rollback via re-release. The Windows replace/restart path is implemented and unit-tested but hasn't been exercised on a live Windows host yet.

Upgrading

One new table (runner_releases) and one new column (runner_auto_update_enabled on app_settings) — run php artisan migrate --force as usual. Auto-update is off by default; nothing changes for existing runners until you publish a build, release it, and turn the toggle on.

v2.3.0 — Runner selection, colored output, and capability reporting

Choose a tag to compare

@jhuebel jhuebel released this 17 Jul 02:38

Runner selection, colored output, and runner capability reporting

A cluster of related improvements to how scripts get routed to runners, what
you can see about a runner's actual capabilities, and how output is
displayed.

Why

With multiple runners in a fleet, "which runner will run this?" and "why did
this fail?" were both harder to answer than they should be — assignment was
always automatic, output with color codes rendered as literal escape-sequence
garbage, and there was no visibility into a runner's own health (version,
architecture, disk space) beyond whether it was online.

What's new

  • Manual runner selection — Run Script and Scheduled Jobs pages let you
    pick a specific runner instead of Auto (least-busy). The picker only lists
    runners that report the script's language as installed; RunnerAssignmentService
    enforces this server-side too, with a specific failure message
    (offline / at capacity / wrong language) instead of a generic one.
    Scheduled jobs can be permanently pinned to a runner via
    preferred_runner_id.
  • Real ANSI color rendering — script output now renders actual color and
    style (16-color palette, bold, dim, italic, underline, reverse, blink)
    instead of showing raw \x1b[...m escape codes as literal text. Applies to
    both the live Run Script terminal and the static History detail view. New
    resources/js/ansi.js (24 unit tests) plus three sample scripts
    (ANSI Color Palette (Bash), ANSI Color Palette (PowerShell),
    Colored Status Report (Bash)) to try it out immediately.
  • Runner capability visibility — History shows which runner ran each
    script (with live status), and Settings → Runners now has an expandable
    detail row showing per-language support, the runner's own binary version,
    CPU architecture, and free/total disk space on its temp directory — so a
    stale runner or one running low on disk is visible instead of silently
    failing later.
  • UI polish — Run Script's output terminal now fills the page instead of
    stopping at a fixed height, and correctly clears when switching between
    scripts instead of leaking the previous script's output underneath the
    newly-selected one.
  • Runner bugfix — fixed a PATH-resolution mismatch where the runner could
    report an interpreter (e.g. a Homebrew-installed pwsh) as available in
    its heartbeat, but actual script execution still failed to find it because
    it only checked the process's inherited PATH, not the same fallback
    search used for detection. Runner binary bumped to 1.2.0.

Upgrading

Two new migrations (preferred_runner_id on scheduled_jobs; version,
arch, disk_free_bytes, disk_total_bytes on runners) — run
php artisan migrate --force as usual. Existing runners will start
reporting the new capability fields on their next heartbeat after being
restarted with the updated binary; until then those fields just show as
unset, nothing breaks.

v2.2.0 — SSO login via Microsoft Entra ID and Google

Choose a tag to compare

@jhuebel jhuebel released this 08 Jul 14:07

SSO login via Microsoft Entra ID and Google

Automator now supports Single Sign-On as an additional login method — username/password
login is unchanged and still fully supported. Everything is configured from Settings →
Single Sign-On
; no .env changes or redeploys required.

Why

Rolling Automator out to a team usually means plugging into whatever identity provider
the organization already uses, rather than managing a separate set of local credentials.
Entra ID (Azure AD) and Google cover the two most common cases.

What's new

  • Settings → Single Sign-On tab: per-provider enable toggle, Client ID/Secret,
    Tenant ID (Entra), and an optional comma-separated allowed-email-domains restriction.
    Secrets are encrypted at rest and write-only in the UI, the same as the existing
    Anthropic API key field.
  • Admin-configurable account provisioning policy — choose whether a first-time SSO
    login automatically creates a new account (with a configurable default role), or is
    rejected until an admin has already created a matching-email account in Settings →
    Users.
  • Automatic account linking — if an admin already created an account with a matching
    email, the first SSO login for that email links it automatically; no manual linking
    step.
  • Accounts created via auto-provisioning have no local password (they can only sign in
    via SSO) — the My Account page now shows a clear message instead of a broken password
    form for those accounts.
  • New docs/SSO.md walks through Entra ID app registration and Google Cloud OAuth client
    setup end to end, including the exact redirect URIs to register.

Upgrading

Migrations add nullable entra_object_id/google_id columns to users (existing
accounts are unaffected) and new SSO settings columns to app_settings, all off by
default — SSO is inert until an admin enables a provider in Settings. Run
php artisan migrate --force as usual.

v2.1.0 — Distributed Go runner agents

Choose a tag to compare

@jhuebel jhuebel released this 08 Jul 14:08

Distributed Go runner agents

Script execution is no longer tied to the same host as the management plane. Automator
now dispatches every script run to a standalone runner — a small Go agent that can
live on any Linux or Windows host, registers securely, and streams output back in real
time. Multiple runners are supported, so a fleet can offer different capabilities
(Windows-only scripts, specific tool availability, network placement, etc.).

Why

The previous model ran scripts inline in the Laravel queue worker on whatever single
Linux host was hosting the app — cancellation even relied on the web request and the
executing process sharing a PID namespace. That made it impossible to run scripts
anywhere but the one box Automator itself was installed on.

What changed

  • New execution model: script runs are assigned to a registered Runner (least-busy
    among online runners, with tag-based routing via required_runner_tags) instead of
    running inline in a local queue worker.
  • Secure registration: a one-time enrollment token exchange issues each runner a
    Sanctum bearer token; revoking a runner from Settings → Runners immediately cuts it off.
  • Real-time job delivery: runners receive job assignment/cancellation over a private
    Laravel Reverb WebSocket channel — the same broadcasting layer already powering the
    browser's live output terminal — and report output/heartbeats back over authenticated
    HTTPS REST.
  • Heartbeat-based offline detection: a runner that misses its heartbeats is marked
    offline and any of its in-flight executions are automatically failed with a clear
    "runner disconnected" message — no silent hangs.
  • Full cancellation support: SIGTERM on Linux; CTRL_BREAK_EVENT with a
    hard-kill fallback on Windows.
  • No local execution fallback — every run, including on a single-box install, goes
    through a registered runner. Install scripts now auto-register a local runner on the
    same host during setup, so single-box installs still work out of the box.
  • Removed: RunScriptJob, the executions queue, automator-worker@.service, and
    the global max_concurrent_executions setting (replaced by per-runner
    max_concurrent_jobs).

See docs/ARCHITECTURE.md, docs/DATA_MODEL.md, and docs/RUNNER_PROTOCOL.md for the
full technical reference.

Upgrading

Existing installs should re-run the packaged install script (or pull the new
packaging/ scripts), which now provisions and registers a local runner automatically
during setup. Additional runners — Linux or Windows, on any host — can be registered at
any time from Settings → Runners.

v2.0.0 — Rewrite from .NET Blazor Server to Laravel

Choose a tag to compare

@jhuebel jhuebel released this 07 Jul 13:51

Major rewrite: .NET Blazor Server → Laravel

Automator has been completely rebuilt on a new stack. This is the same tool with the same feature set — script library, live-streamed script execution, cron scheduling, a Claude-powered AI assistant, role-based access, audit logging, and an admin dashboard — but the entire implementation has changed from the ground up.

Why

The previous ASP.NET Core 9 / Blazor Server implementation tied real-time UI updates directly to Blazor's SignalR circuit model and required a self-contained .NET runtime per platform. This release moves to a PHP/Laravel stack that's easier to self-host on standard Linux infrastructure (PHP-FPM + nginx), with an explicit WebSocket layer (Laravel Reverb) replacing Blazor's built-in circuit-based streaming.

What changed

  • Framework: ASP.NET Core 9 / Blazor Server → Laravel 13 with Livewire 3 + Volt
  • Real-time updates: Blazor Server's SignalR circuits → Laravel Reverb (WebSocket broadcasting) for live script output and AI token streaming
  • Auth & roles: ASP.NET Core Identity → spatie/laravel-permission (Admin / Developer / Operator / Viewer), username-based login with lockout
  • Script execution: in-process ScriptRunnerService → queued RunScriptJob (Symfony Process) on a dedicated executions queue, still supporting Bash, PowerShell, Python, Ansible, and Terraform (init + apply)
  • Scheduler: 15-second in-process background tick → cron-driven dispatch-due-jobs command on a systemd timer (60-second granularity)
  • AI assistant: Guzzle-based SSE streaming from the Anthropic API, broadcast token-by-token into a CodeMirror 6 editor (previously CodeMirror 5)
  • Dashboard: charts now rendered with Chart.js
  • Deployment: self-contained .NET binary + systemd + nginx → PHP-FPM + nginx, with new systemd units for queue workers, Reverb, and the scheduler tick
  • Windows/IIS packaging has been dropped — this release targets Linux (Ubuntu, RHEL/Rocky/AlmaLinux) only

Upgrading

This is a from-scratch application — there is no automatic data migration path from a v1.x SQLite database. Fresh installs seed default roles, users, and example scripts as before. See docs/INSTALL.md for the updated installation steps.

Default credentials (change immediately)

Username Password Role
admin Admin1234! Admin
operator Operator1234! Operator
viewer Viewer1234! Viewer

v1.7.0

Choose a tag to compare

@jhuebel jhuebel released this 04 Jul 23:43

Changes

  • Refreshed the Claude model lineup in AI Assistant settings: Haiku 4.5, Sonnet 5 (new recommended default), Opus 4.8, and Fable 5 (frontier reasoning, premium). Removes the retired Sonnet 4.6 / Opus 4.7 entries.
  • Added an Effort setting (Low / Medium / High / Max) controlling how much the model "thinks" before responding — trades quality against latency and token cost. Disabled for Haiku, which doesn't support the parameter.
  • Existing installs with a stale/retired model string in Settings are automatically rolled forward to the new default (claude-sonnet-5) on startup.

🤖 Generated with Claude Code

v1.6.0

Choose a tag to compare

@jhuebel jhuebel released this 21 May 03:13

What's New

Terraform Support

  • Execute Terraform scripts directly from Automator — runs terraform init then terraform apply -auto-approve in a temp working directory
  • HCL syntax highlighting in the script editor
  • Variables are automatically exposed via TF_VAR_<name> convention (var.name in your HCL)
  • Terraform runtime check in Settings → System Status
  • Sample "Hello World" Terraform script included

MudBlazor Charts

  • Replaced Chart.js with MudBlazor's built-in stacked bar chart on the Dashboard — no external JS dependency

Deployment Packages

  • Self-contained archives for Ubuntu, RHEL / Rocky / AlmaLinux, and Windows Server
  • Each Linux archive includes a hardened systemd unit, nginx reverse proxy config, and distro-specific install/uninstall scripts
  • Windows archive includes PowerShell scripts to install as a Windows Service with optional IIS ARR reverse proxy

Download

Platform Archive
Ubuntu / RHEL (x64) automator-1.6.0-linux-x64.tar.gz
Windows Server (x64) automator-1.6.0-win-x64.zip

See docs/INSTALL.md for installation instructions.