Skip to content
These pages describe Stewart 1.x. Read the docs for the latest release, and how to upgrade.

Upgrading

Stewart is one version for everything: the packages in composer.json, the runtime image, and the Home Assistant integration. Upgrade them together.

  1. Read the notes for every version between yours and the new one, below and in the changelog.
  2. On your machine, run make update for the newest release of your version, or make upgrade VERSION=x.y to move to another version. make upgrade also changes the image tags in Dockerfile and the compose files.
  3. Run make generate, make stan and make test, and follow the notes.
  4. Commit composer.lock and the changed files, and deploy as usual.
  5. If you use the Stewart integration in Home Assistant, update it to the same version.

Within a major version, such as 1.x, a new release does not break your apps. Notes appear here only when a release asks you to do something.

  1. Run make upgrade VERSION=1.8, then restart Stewart (make up, make deploy or a new image). The control and worker protocols are unchanged, and so is the Home Assistant integration’s.

  2. Run make generate. The generated classes of 1.7 and earlier call callService(), so until they are regenerated every generated call prints a deprecation line in the log, and make status says the classes are of an older format.

  3. Move your apps and tests to the action names. This rewrites the calls whose names are written out; make stan then points at the rest, such as names held in a variable:

    Terminal window
    grep -rlE 'callService|stubService|getServiceName' apps tests | xargs sed -i -E \
    -e "s/->callService(ForResponse)?\('([a-z0-9_]+)', *'([a-z0-9_]+)'/->callAction\1('\2.\3'/g" \
    -e "s/->stubService(Answer|Failure)\('([a-z0-9_]+)', *'([a-z0-9_]+)'/->stubAction\1('\2.\3'/g" \
    -e 's/->callService(ForResponse)?\(/->callAction\1(/g' \
    -e 's/->getServiceName\(\)/->getActionName()/g'
  4. To have make stan check entity IDs and action names, add the PHPStan extension from make sh; new projects from the skeleton have it:

    Terminal window
    composer config allow-plugins.phpstan/extension-installer true
    composer require --dev stewart-php/phpstan:^1.8 phpstan/extension-installer
  5. On Kubernetes with adminApi.podMonitor.enabled, switch to metrics.enabled: true and metrics.podMonitor.enabled: true, and turn adminApi.podMonitor off. If Prometheus was the only reason for adminApi.host: 0.0.0.0, set it back to 127.0.0.1.

  6. The TEMPLATE variable of make app reaches only new projects. To use it, copy the app target from the skeleton’s Makefile.

  1. Run make upgrade VERSION=1.7, then restart Stewart (make up, make deploy or a new image). The control protocol is now 33: until the daemon runs 1.7, make status and the other control targets refuse to talk to it. The Home Assistant integration’s protocol is unchanged.
  2. Stewart 1.7 needs PHP 8.5.12. The runtime image already runs it, so make pull is enough; a project that runs Stewart outside the image updates PHP first.
  3. Log lines name their source after the level, such as INFO [porch-light] …. Anything that parses line logs needs to allow for the tag; JSON logs only gain extra.source.
  4. The new Makefile variables reach only new projects. To use them, copy TRACE on run, watch and debug, and APP and WATCH on status, from the skeleton’s Makefile.
  1. Run make upgrade VERSION=1.6, then restart Stewart (make up, make deploy or a new image). The control protocol is now 30: until the daemon runs 1.6, make status and the other control targets refuse to talk to it. The Home Assistant integration’s protocol is unchanged.
  2. The new targets reach only new projects. To use them, copy reload and watch from the skeleton’s Makefile.
  3. docker compose kill -s HUP stewart now reloads Stewart instead of stopping it, also in Git mode.
  1. Apps without worker: can move to another worker once, so the worker label of their metrics changes. If dashboards or alerts rely on it, run make check before upgrading, note each app’s worker, and pin it with apps.<id>.worker.
  2. Run make upgrade VERSION=1.5. Protocols are unchanged, so a 1.4 daemon, stewart CLI and Home Assistant integration work with 1.5.
  3. Run make check. It now builds every app, so it can name a problem that used to show only when the app started, and a Git deploy rejects a commit until it passes.
  4. Delete the empty dispose() from your apps; make check names each app that still has one. Where dispose() does something, add implements Disposable (use Stewart\Contracts\Disposable;). An app that marks dispose() with #[\Override] does not load until you do one or the other.
  5. The new deploy and CI steps reach only new projects. To use them, copy the deploy target from the skeleton’s Makefile, and ci.yml and image.yml from its workflows. CI checks the settings in .env.example, so keep it listing every setting your apps need.
  1. Run make upgrade VERSION=1.4. Protocols are unchanged, so a 1.3 daemon, stewart CLI and Home Assistant integration work with 1.4.
  2. The new Makefile targets reach only new projects. To use them, copy check, app, app-pause, app-resume, app-reset, worker-restart and the required line from the skeleton’s Makefile; there, doctor runs with $(RUN_APP) and setup runs stewart doctor --offline.
  3. To make Valkey optional, first add COMPOSE_PROFILES=store to .env next to STEWART_PERSISTENCE__URL. Then add profiles: [store] to the valkey service and required: false under depends_on: valkey: in compose.yaml and in any deploy compose file you copied. With the profile but without the .env line, Valkey no longer starts.
  4. An existing HelloApp keeps working; nothing changes for it.
  1. Run make upgrade VERSION=1.3. Protocols are unchanged, so a 1.2 daemon, stewart CLI and Home Assistant integration work with 1.3.
  2. For host.docker.internal with make up, add extra_hosts: ["host.docker.internal:host-gateway"] to the stewart service in compose.yaml, and in any deploy compose file you copied.
  3. Memory now reads higher, since it counts the whole process; raise alerts on stewart_broker_memory_bytes and stewart_worker_memory_bytes to match.
  1. Run make upgrade VERSION=1.0. Protocols are unchanged, so a 0.11 daemon, stewart CLI and Home Assistant integration work with 1.0.
  2. Change the image tag in Dockerfile and the compose files from runtime:1.0 to runtime:1 (1-dev in compose.dev.yaml), so the image keeps getting PHP and Alpine fixes after 1.1. Copy bin/upgrade-stewart.sh from the skeleton so later upgrades do the same.

Each 0.x version could break apps; these notes are kept for old projects.

  1. Run make upgrade VERSION=0.11, then make generate. Upgrade the daemon, the stewart CLI and the Home Assistant integration together; older versions refuse to talk to 0.11.
  2. Replace ->whenChangedTo('on')->from('off') with ->whenChangedTo('on', from: 'off'), and ->fromAnyState() with fromAnyState: true.
  3. Replace runAtSunrise() and runAtSunset() with runAtSunEvent(SunEvent::Sunrise, …) or SunEvent::Sunset.
  4. Replace an injected StewartIdentity with $ha->wasCausedByStewart($change).
  5. Replace removed exception factories with createForReason(), fromWire() with restoreFromWire(), and removed collection factories such as fromIds() with fromList().
  6. Import classes that moved out of stewart-php/contracts from Stewart\Support\….
  7. Custom implementations of Timers, EventStream, HaContext or EntityExposure add the new methods.
  8. An app option variable ending in _FILE is now read as a file; set the option in stewart.yaml to keep passing the path itself.
  1. Run make upgrade VERSION=0.10. Control and IPC protocols are unchanged, but broker, workers and stewart commands should all run 0.10.
  2. Update the stewart integration to 0.10.0 in Home Assistant.
  3. Optionally take over the skeleton’s .github/workflows/*.yml and Dockerfile changes.
  1. Run make upgrade VERSION=0.9. Broker, workers and stewart commands must all run 0.9; stewart status against a 0.8 daemon is refused (control protocol 28).
  2. Install the stewart integration 0.9.0 in Home Assistant 2026.4 or newer before an app calls expose*(); without it, expose*() throws ExposureException. Apps that expose nothing need no integration.
  3. Daemons sharing one Home Assistant set a different expose.instance each.
  1. Run make upgrade VERSION=0.8. Broker, workers and stewart commands must all run 0.8; stewart status against a 0.7 daemon is refused (control protocol 24).
  2. A git deployment whose composer.lock still holds runtime 0.7 sets code.git.poll: off (or drops STEWART_DEPLOY__GIT__POLL from compose.git.yaml) until it upgrades; 0.7 stops on the unknown variable.
  3. A compose git volume from 0.7 is converted on the first start: the old checkout is removed and the release layout created, with one full dependency install.
  4. Code calling BrokerLifecycle::run() directly gets a BrokerStopOutcome back instead of nothing.
  1. Run make upgrade VERSION=0.7. Broker, workers and stewart commands must all run 0.7.
  2. Code that constructs StateChanges or StateTransitions directly now passes a CurrentStateReader.
  3. Custom Clock and Scheduler implementations add isWithin() and runAtEntityTime().
  4. Tests comparing whole EntityState objects from RecordingHaContext with assertEquals now see the stamped lastChangedAt and lastUpdatedAt.
  1. Run make upgrade VERSION=0.6. Broker, workers and stewart commands must all run 0.6.
  2. Rename any app whose id is longer than 100 characters.
  3. On Kubernetes, the chart now probes port 8080 (probes.port); set probes.mode: exec to keep exec probes.
  1. Run make upgrade VERSION=0.5. Broker and workers must both run 0.5 (IPC protocol 21).
  2. Run make generate.
  • Add ->fromAnyState() after any whenChangedTo() that must also fire when an entity comes back from unavailable or unknown.
  • Run make generate.
  1. Remove codegen.rename from stewart.yaml and any STEWART_CODEGEN__RENAME from .env; both are now refused.
  2. Run make generate.
  3. Replace $entities-><domain>-><entity> with $entities-><domain>->getEntity('<entity id>').

To make life easier in long term, I added an upgrade script, that script needs to be added manually, later on upgrades can be made by executing only one make target.

  1. Fetch the upgrade script and keep it out of the production image:

    Terminal window
    mkdir -p bin
    curl -fsSLo bin/upgrade-stewart.sh \
    https://raw.githubusercontent.com/stewart-php/skeleton/v0.2.0/bin/upgrade-stewart.sh
    echo bin >> .dockerignore
  2. Add the target to your Makefile, next to update; the recipe lines start with a tab:

    .PHONY: upgrade
    upgrade: ## Move to another Stewart release line, then pull its images and install it [VERSION=0.2]
    $(RUN) sh bin/upgrade-stewart.sh $(VERSION)
    $(DEV) pull
    $(RUN) composer update 'stewart-php/*' --with-all-dependencies --no-interaction
  3. To use MQTT, add "stewart-php/mqtt": "^0.2" to require in composer.json.

  4. Upgrade. This points every stewart-php/* requirement and runtime image tag at 0.2, pulls the images and installs:

    Terminal window
    make upgrade VERSION=0.2
  5. If you added MQTT, set STEWART_MQTT__URL in .env, such as mqtt://user:password@homeassistant.local:1883, and check the mqtt section with make config. Without the URL nothing changes.

  6. Check it with make doctor and make run. On the server, commit and push, then run make deploy.