Skip to main content

Butler Releases

Release history and changelog for the Butler Kubernetes-as-a-Service platform.

Component Versions​

ComponentLatestTypeReleased
CRD type definitions (the API contract)
0.22.0moduleJun 12, 2026
Core reconciliation controllers
0.28.4containerOct 27, 2026
HTTP/WS API server
0.24.0containerOct 27, 2026
Web console
0.16.1containerJul 10, 2026
CLI tools (butlerctl, butleradm)
0.18.0binaryJun 12, 2026
Management cluster bootstrap controller
0.5.6containerMay 20, 2026
Harvester HCI provider controller
0.2.3containerApr 26, 2026
Nutanix AHV provider controller
0.2.3containerApr 26, 2026
AWS provider controller
0.1.2containerApr 26, 2026
GCP provider controller
--container--
Azure provider controller
--container--
OS image building and hosting service
--container--
Backstage-based developer portal
0.7.0containerJul 30, 2026
Helm charts for deployment
0.24.0helmAug 31, 2026

Kubernetes Compatibility​

Butler VersionKubernetes Versions
v0.9.x1.28, 1.29, 1.30, 1.31
v0.8.x1.28, 1.29, 1.30, 1.31
v0.7.x1.28, 1.29, 1.30

Release History​

butler-server0.24.0Oct 27, 2026
  • chore: genericize environment-specific examples and fixtures by @atbagan in https://github.com/butlerdotdev/butler-server/pull/105
  • fix(auth): stop treating any-team admins as platform admins by @atbagan in https://github.com/butlerdotdev/butler-server/pull/97
  • fix(teams): gate team create, update and delete server-side by @atbagan in https://github.com/butlerdotdev/butler-server/pull/92
  • fix(auth): require platform admin for platform-level mutations by @atbagan in https://github.com/butlerdotdev/butler-server/pull/93
  • fix(auth): scope management and Steward reads by @atbagan in https://github.com/butlerdotdev/butler-server/pull/96
  • fix(clusters): require operate role for kubeconfig download and audit it by @atbagan in https://github.com/butlerdotdev/butler-server/pull/95
  • fix: gate team provider reads on team visibility by @atbagan in https://github.com/butlerdotdev/butler-server/pull/100
  • fix(audit): redact credential fields the scrubber missed and never store a raw body by @atbagan in https://github.com/butlerdotdev/butler-server/pull/102
  • fix(auth): team admin is never platform admin; gate env mutations; role-matrix tests by @atbagan in https://github.com/butlerdotdev/butler-server/pull/106
butler-controller0.28.4Oct 27, 2026
  • fix(team): least-privilege Kubernetes RBAC for team roles (viewer=view, operator=edit, admin=admin) by @atbagan in https://github.com/butlerdotdev/butler-controller/pull/115
butler-server0.23.0Aug 31, 2026
  • fix(server): accept 1..3 control plane replicas, not only 1 or 3 by @atbagan in https://github.com/butlerdotdev/butler-server/pull/103
  • fix(gitops): repository identity and complete repository listing by @atbagan in https://github.com/butlerdotdev/butler-server/pull/104
butler-controller0.28.3Aug 31, 2026
  • feat(controller): map konnectivity resources onto the StewardControlPlane addons by @atbagan in https://github.com/butlerdotdev/butler-controller/pull/114
butler-charts0.24.0butler-crdsAug 31, 2026
butler-charts0.23.0butler-crdsAug 30, 2026
butler-controller0.28.2Aug 30, 2026
  • feat: local provider CAPD support for the laptop path by @atbagan in https://github.com/butlerdotdev/butler-controller/pull/112
  • fix(controller): omit control plane replicas when the tenant omits them by @atbagan in https://github.com/butlerdotdev/butler-controller/pull/113
butler-portal0.7.0Jul 30, 2026
  • docs(#51): end-to-end 'Getting Started with Permissions' walkthrough by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/68
  • feat: config-gate the Google sign-in provider; keep Guest default with opt-out by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/69
butler-portal0.6.2Jul 17, 2026
  • feat(permissions): adopt @backstage-community/plugin-rbac-backend [BREAKING] by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/40
  • ci: compile-check TypeScript code samples in the permissions docs by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/54
  • docs: RBAC permission framework + updated plugin authoring guide by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/41
  • fix(#52): adopter-plugin reference installs + compiles; drop continue-on-error by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/57
  • docs: adopter-facing note on npm ERESOLVE workaround by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/58
  • chart: pluginsWithPermission guard (fail-loud on drift) + warn-loudly on opt-out by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/42
  • chart(0.6.1): ship #42's guard + #60's fatigue fix to adopters by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/63
  • feat(#59): runtime audit for pluginsWithPermission gaps + addPermissions convention by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/64
butler-portal0.6.0Jul 16, 2026
  • feat(permissions): adopt @backstage-community/plugin-rbac-backend [BREAKING] by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/40
butler-portal0.5.11Jul 15, 2026
  • fix(Dockerfile): bump base to node:22-bookworm-slim for isolated-vm 6.x by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/39
butler-charts0.14.2butler-consoleJul 12, 2026
butler-server0.22.0Jul 12, 2026

Enforces role-based access on the tenant cluster terminal.

Terminal access

The tenant terminal previously admitted any team member, so a viewer could open an interactive shell. Access is now resolved from Team CRDs and gated by role:

  • Write-capable roles (team admin, operator, platform admin) get the interactive shell, unchanged.
  • Viewers connect read-only: they stream output but their input is dropped server-side.
  • Non-members are refused before the connection upgrades.

Authorization boundary

Write-capable roles run the shell under the tenant cluster-admin credential. A scoped operator identity is possible later and would change only the credential selection seam. Because write-capable roles share that credential, each terminal session now logs the Butler user, role, team, cluster, and duration on open and close for attribution.

Deployment

Helm chart butler-console-v0.14.2 advances the pinned server image to 0.22.0.

butler-portal0.5.5Jul 10, 2026

New platform capability

Plugins can now gate their own authorization inside butler-portal without editing the central policy. The new AuthAdjudicatorExtensionPoint routes each authorize() call to a plugin-registered adjudicator by permission-name prefix; unclaimed namespaces fall through to ALLOW so core Backstage plugins (catalog, scaffolder, techdocs, search, kubernetes) keep working unchanged.

Authoring guide: https://github.com/butlerdotdev/butler-portal/blob/v0.5.5/docs/plugin-authoring/authorization.md

  • feat(permissions): namespace-delegated policy so plugins gate their own authz (#33)

Full Changelog: https://github.com/butlerdotdev/butler-portal/compare/v0.5.4...v0.5.5

butler-charts0.14.1butler-consoleJul 10, 2026
butler-console0.16.1Jul 10, 2026

Restores terminal and GitOps write parity for the team admin and operator roles.

Fix

In v0.16.0, users whose highest role was a per-team `admin` or `operator` lost write access to two cluster surfaces:

  • The cluster terminal was read-only. Operators and team admins could open the terminal and see output but could not type.
  • The GitOps Enable and Disable controls were hidden, so operators and team admins could not turn GitOps on or off for a cluster.

Both are now available to team admins and operators, matching the intended role model where `admin` and `operator` are write-capable and `viewer` is read-only. Viewer stays read-only, and platform admin behavior is unchanged.

Deployment

Helm chart `butler-console-v0.14.1` ships this frontend (0.16.1) alongside butler-server 0.21.1. The chart now pins both image tags explicitly.

butler-portal0.5.4Jul 8, 2026
  • fix(Dockerfile): downgrade node base image to node:20-bookworm-slim by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/32
butler-portal0.5.3Jun 22, 2026
  • app: generic sign-in copy for Google card by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/31
butler-portal0.5.2Jun 22, 2026
  • refactor(portal): document upgrade-handler attach window and add guard tests by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/15
  • ci(portal): dedupe push+pull_request runs and bound runner wedges by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/16
  • feat(portal): portal-JWT signing carrier, Stage 2 of the impersonation fix by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/17
  • chore(portal): bump chart 0.2.3 -> 0.3.0 for Stage 2 release by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/18
  • fix(portal): make signing-key mount readable by non-root node UID by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/19
  • feat(portal): runtime per-plugin gates for Butler-Labs-branded plugins by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/20
  • fix(portal): ship packages/app/config.d.ts in backend image (post-PR-#20 boot crashloop hotfix) by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/21
  • feat(portal): chart 0.5.0 dynamic plugins (backend + chart + frontend normalization + installer + boot-test green) by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/22
  • 0.5.1: real frontend dynamic-plugin loading + chart NODE_PATH + CLI wrapper by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/23
  • chart(0.5.3): ConfigMap checksum auto-rollout + postgresql.backup passthrough by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/24
  • chart(0.5.4): allowedSources default includes RHDH marketplace + butlerdotdev by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/25
  • chart(0.5.5): pin installer 0.1.1 (annotation-less OCI pull fix) by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/26
  • chart(0.5.6): pin installer 0.1.2 (auto-detect package.json wrapper dir) by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/27
  • chart(0.5.7): pin installer 0.1.3 (flatten scoped npm names) by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/28
  • app: render Microsoft sign-in card when configured by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/29
  • chart(0.5.8): bump for SignInPage microsoft conditional by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/30
butler-portal0.5.1Jun 14, 2026
  • refactor(portal): document upgrade-handler attach window and add guard tests by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/15
  • ci(portal): dedupe push+pull_request runs and bound runner wedges by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/16
  • feat(portal): portal-JWT signing carrier, Stage 2 of the impersonation fix by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/17
  • chore(portal): bump chart 0.2.3 -> 0.3.0 for Stage 2 release by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/18
  • fix(portal): make signing-key mount readable by non-root node UID by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/19
  • feat(portal): runtime per-plugin gates for Butler-Labs-branded plugins by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/20
  • fix(portal): ship packages/app/config.d.ts in backend image (post-PR-#20 boot crashloop hotfix) by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/21
  • feat(portal): chart 0.5.0 dynamic plugins (backend + chart + frontend normalization + installer + boot-test green) by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/22
  • 0.5.1: real frontend dynamic-plugin loading + chart NODE_PATH + CLI wrapper by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/23
butler-portal0.5.0Jun 14, 2026
  • refactor(portal): document upgrade-handler attach window and add guard tests by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/15
  • ci(portal): dedupe push+pull_request runs and bound runner wedges by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/16
  • feat(portal): portal-JWT signing carrier, Stage 2 of the impersonation fix by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/17
  • chore(portal): bump chart 0.2.3 -> 0.3.0 for Stage 2 release by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/18
  • fix(portal): make signing-key mount readable by non-root node UID by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/19
  • feat(portal): runtime per-plugin gates for Butler-Labs-branded plugins by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/20
  • fix(portal): ship packages/app/config.d.ts in backend image (post-PR-#20 boot crashloop hotfix) by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/21
  • feat(portal): chart 0.5.0 dynamic plugins (backend + chart + frontend normalization + installer + boot-test green) by @atbagan in https://github.com/butlerdotdev/butler-portal/pull/22
butler-cli0.18.0Jun 12, 2026

Changelog

  • feat(cluster): host-usable kubeconfig for local tenants + auto-derive lb-pool (#60)
  • fix(bootstrap): sync embedded CRDs from butler-api and guard against drift (#59)
  • fix(cluster): cross-platform process detach for the local port-forward (#61)
butler-cli0.17.0Jun 12, 2026

Changelog

  • feat: butleradm bootstrap local + TUI wizard for the laptop path (#58)
butler-charts0.22.0butler-crdsJun 12, 2026
butler-api0.22.0Jun 12, 2026

Local provider type for the laptop path

  • New `local` provider for ClusterBootstrap and ProviderConfig: installs Butler onto a kind-based management cluster and provisions tenant workers as containers via the Cluster API Docker provider (CAPD), for running Butler on a laptop with no hypervisor.
  • Adds `ProviderTypeLocal`, an optional `LocalProviderConfig` (`kindNodeImage` override), and `ClusterBootstrap.IsLocal()`.
  • `credentialsRef` is now optional on ProviderConfig (the local provider needs no credentials).

Validation

  • A CEL rule on ProviderConfig requires a non-empty `credentialsRef.name` for every non-local provider and exempts local, so a credential-less non-local config is rejected at admission.

Known follow-up

`ProviderConfig.CredentialsRef` should become `*SecretReference` (tracked in butlerdotdev/butler-api#47) so credential-less local configs round-trip cleanly. Until then a local ProviderConfig shows a cosmetic not-Ready status; provisioning is unaffected.

butler-cli0.16.1Jun 11, 2026

Fix: provider get/list read the correct scope and status paths

A display-path fix, found by exercising `provider get` against a real team-scoped provider.

  • **Scope showed the wrong value.** `provider get` and `provider list -o wide` read `spec.scope` as a string, but the ProviderConfig stores scope as an object (`spec.scope.type`). The string read was always empty, so the `platform` fallback fired and a team-scoped provider displayed as `platform`. They now read `spec.scope.type`, so team-scoped providers show `team` and unscoped providers still show `platform`.
  • **Validation error never displayed.** It was read from a `status.validationError` field that does not exist; a failed validation is recorded as the Ready condition's message, which is now where it is read from.
  • **Last-validation timestamp** was read from `status.lastValidatedAt`; the field is `status.lastValidationTime`.

Verified live on butler-beta with a throwaway team-scoped provider before and after the fix.

butler-server0.21.1Jun 11, 2026
  • feat(auth): log portal proof verification success at Info by @atbagan in https://github.com/butlerdotdev/butler-server/pull/89
butler-cli0.16.0Jun 11, 2026

Team member-role and group access rules (butleradm)

The `butleradm team` group gains four verbs, completing CLI parity with the console for Team access management. Previously the CLI could add and remove members but could not change a member's role or manage group access rules.

| Verb | What it does |

|---|---|

| `update-member-role` | Change an existing member's role |

| `add-group` | Add a group-to-role access rule |

| `update-group-role` | Change a group rule's role |

| `remove-group` | Remove a group rule |

CRD-direct, status-preserving

All four edit `Team.spec.access` directly, mirroring the existing add-member and remove-member: Get the Team, change the targeted entry in the users or groups list, and Update the same object. Because the Update carries the same fetched object, the controller-managed status and the resourceVersion are preserved without a separate merge step.

The user identifier in `spec.access.users` is the `name` field, which holds the email.

Group rules are identified by name plus optional identity provider

A group rule can be scoped to a single IdP with `--identity-provider`, or left unscoped to match a group name from any IdP. When more than one rule shares a name and no `--identity-provider` is given, `update-group-role` and `remove-group` error and ask which one to act on, rather than editing the wrong rule.

The referenced identity provider is not validated to exist when adding a rule (the apiserver does not require it); a convenience check may be added later.

Validation

The full lifecycle was exercised end to end against butler-beta: update-member-role (status conditions and resourceVersion preserved against the real apiserver), add-group, update-group-role, the multi-rule ambiguity guard (errored without mutating), remove-group, and cleanup to pre-state.

butler-charts0.14.0butler-consoleJun 11, 2026
butler-cli0.15.0Jun 10, 2026

P1 #6: IdentityProvider create/update + discovery test (butleradm)

The `butleradm idp` group gains four verbs, closing audit P1 #6 so an operator can stand up SSO from the CLI (previously list/get/delete only).

| Verb | Mechanism | What it does |

|---|---|---|

| `create` | CRD-direct | Create an IdentityProvider from a manifest |

| `update` | CRD-direct | Update the spec, preserving status conditions and resourceVersion |

| `test` | butler-server | Probe an issuer's OIDC discovery before creating a provider |

| `validate` | butler-server | Probe an existing provider's configured issuer |

create and update are CRD-direct

Both read and write the IdentityProvider directly (it is cluster-scoped, so no namespace flag), like the rest of the idp group. `update` does Get-then-merge-spec-then-Update and applies only the spec, so the controller-managed status conditions and the resourceVersion are preserved. A spec edit never clobbers status.

test and validate are read-only probes

Both go through butler-server, which fetches the issuer's `.well-known/openid-configuration` and reports whether discovery succeeds and which endpoints it found. Neither mutates anything, so neither needs a confirmation guard. `test` takes an issuer URL (pre-create); `validate` uses an existing provider's configured issuer.

Secret handling (v1 choice)

The client secret is supplied by reference: the manifest's `spec.oidc.clientSecretRef` points at a Secret created separately, consistent with `provider create`. The console takes the secret inline and creates it server-side; a `--client-secret-from-file` convenience is queued for later. In exchange, the manifest can set any spec field, including `spec.oidc.insecureSkipVerify` and `spec.oidc.googleWorkspace`, which neither client exposed before.

Also fixed

`idp get` and `idp list` read the pre-nesting field paths (`spec.issuerURL`, `spec.clientID`, `spec.scopes`, `spec.claims`), which are always empty on the current CRD because those fields live under `spec.oidc`. They now read `spec.oidc.*`, so the get detail view and the list ISSUER column render correctly. Found by the live lifecycle test.

Validation

The full lifecycle was exercised end to end against butler-beta: test (valid and clean-failure paths), create, get, update (status conditions and resourceVersion preserved against the real apiserver, no optimistic-concurrency conflict), validate, delete, and cleanup to pre-state.

v0.9.x Highlights​

The v0.9.x release cycle introduced cloud provider support and multi-OS workers:

  • butler-api v0.9.0/v0.9.1: LoadBalancerRequest CRD, cloud-aware bootstrap types, multi-OS worker fields, Azure vmSize/imageURN additions
  • butler-controller v0.9.0: Multi-OS kubeadm bootstrap for non-Talos workers (Rocky, Flatcar, Bottlerocket, Kairos)
  • butler-cli v0.5.0: Cloud bootstrap CLI with credential override flags for GCP, AWS, Azure
  • butler-bootstrap v0.3.0: Cloud bootstrap support, LoadBalancerRequest HA
  • butler-console v0.4.1: Images page and ImageSync management UI
  • butler-server v0.4.1: API dependency bump
  • butler-crds v0.8.0: 17 CRDs including LoadBalancerRequest
  • butler-provider-harvester v0.2.0: butler-api v0.9.0 dependency bump
  • butler-provider-nutanix v0.2.0: butler-api v0.9.0 dependency bump

Cloud Provider Initial Releases​

  • butler-provider-aws v0.1.0: AWS EC2 VM provisioning via MachineRequest
  • butler-provider-gcp v0.1.0: GCP Compute Engine VM provisioning via MachineRequest
  • butler-provider-azure v0.1.0: Azure VM provisioning via MachineRequest

Upgrade Guide​

From v0.8.x to v0.9.x​

  1. Update CRDs first -- helm upgrade butler-crds oci://ghcr.io/butlerdotdev/charts/butler-crds --version 0.8.0 -n butler-system
  2. Upgrade controller -- helm upgrade butler-controller oci://ghcr.io/butlerdotdev/charts/butler-controller --version 0.9.0 -n butler-system
  3. Upgrade console -- helm upgrade butler-console oci://ghcr.io/butlerdotdev/charts/butler-console --version 0.5.0 -n butler-system
  4. Verify -- Check controller logs and TenantCluster status