Skip to content

build(installer): start the daemon before waired init so first-run takes the daemon path (waired#835 §11.2) - #119

Merged
gen16k merged 1 commit into
mainfrom
feat/835-installer-ordering-flip
Jul 20, 2026
Merged

gen16k merged 1 commit into
mainfrom
feat/835-installer-ordering-flip

Conversation

@gen16k

@gen16k gen16k commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Motivation

waired init attaches to a running local agent and drives the browser-based first-run onboarding only when the daemon is already up (the daemon-path guard in cmd/waired/main.go); otherwise it falls through to the legacy standalone terminal enroll.

Until now only macOS met that condition — its installer registers a RunAtLoad LaunchDaemon (darwin_register_agent) before darwin_maybe_init, so macOS init has always taken the daemon path. Linux and Windows ran waired init BEFORE starting the service, so init took the standalone path and the browser onboarding never engaged. This flips Linux + Windows to match macOS.

What changed

File Change
packaging/install/install.sh linux_apt_install and linux_apt_update call linux_service_up before linux_maybe_init
packaging/debian/waired/postinst Start the unit on a fresh install (was enable-only) so a plain apt install + manual sudo waired init also takes the daemon path. Upgrade behaviour unchanged — restart-on-upgrade stays gated on the captured enabled-state, so an operator-stopped unit is not revived
packaging/install/install.ps1 Ensure-AgentRunning moves ahead of Invoke-WairedInit, under the Background-service section
packaging/windows/waired-setup.iss GUI installer (does not run init itself): add a fresh-install waired-agent start [Run] step so a later waired init finds the daemon up; correct the stale "started by waired init" comment
packaging/install/README.md Reorder the documented install-flow steps

Safety / no-regression

Docs alignment

docs-site/getting-started/first-run.mdx already documents this behaviour — "a fresh install starts it first" and the browser-onboarding narrative. This PR brings the installer code into line with the already-published docs (and with macOS).

Verification

make install-script-lint              # shellcheck install.sh + postinst — exit 0
bash scripts/dev/installtest-dash.sh  # dash/bash/busybox matrix — 89 passed, 0 failed
bash scripts/ci/autostart-exec-guard.sh  # exit 0

The .iss change follows the existing [Run] pattern and is compiled by ISCC in the build job.

Deferred

The CI installtest leg that exercises the daemon path end-to-end is deferred to a follow-up issue: it needs out-of-band CP login completion (the daemon owns the OAuth session; every existing leg forces standalone via --bypass-mode/--google-sa-login and a service-stop) and edits scripts/dev/lib/installtest-enroll.sh, which is under concurrent modification in another session. Filing separately avoids clobbering that work and keeps this ordering flip small.

Refs waired-ai/waired#835

🤖 Generated with Claude Code

@gen16k

gen16k commented Jul 20, 2026

Copy link
Copy Markdown
Contributor Author

Follow-up for the deferred daemon-path installtest leg: #120 (blocked on the concurrent installtest-enroll.sh work landing).

…takes the daemon path (waired#835 §11.2)

`waired init` attaches to a running local agent and drives the browser-based
first-run onboarding only when the daemon is already up (the daemon-path
guard at cmd/waired/main.go); otherwise it falls through to the legacy
standalone terminal enroll. Until now only macOS met that condition — its
installer registers a RunAtLoad LaunchDaemon (darwin_register_agent) before
darwin_maybe_init, so macOS init has always taken the daemon path. Linux and
Windows ran `waired init` BEFORE starting the service, so init took the
standalone path and the browser onboarding never engaged.

Flip the order so all three OSes start the agent first:

- install.sh: linux_apt_install and linux_apt_update call linux_service_up
  before linux_maybe_init.
- debian postinst: start the unit on a FRESH install (was enable-only), so a
  plain `apt install` followed by a manual `sudo waired init` also takes the
  daemon path. Upgrade behaviour is unchanged — the restart-on-upgrade stays
  gated on the captured enabled-state, so an operator-stopped unit is not
  revived.
- install.ps1: Ensure-AgentRunning moves ahead of Invoke-WairedInit, under
  the Background-service section.
- waired-setup.iss (GUI installer, which does not run init itself): add a
  fresh-install `waired-agent start` [Run] step so a later `waired init`
  finds the daemon up, and correct the stale "started by waired init" note.

Safe before sign-in: the daemon boots identity-less and idles until
enrolment (#177). When the daemon is not reachable (non-systemd container,
start failure) init falls back to the standalone path, so nothing regresses.

On Linux the one-liner still pre-installs the engine (linux_install_ollama),
so the daemon-path engine install (already merged, #117) is a no-op there;
it is exercised on the `apt install` + manual-init path and on macOS.

docs-site/getting-started/first-run.mdx already documents this behaviour
("a fresh install starts it first"); this brings the installers into line.

The new CI installtest leg that exercises the daemon path end-to-end is
deferred to a follow-up: it needs out-of-band CP login completion and edits
scripts/dev/lib/installtest-enroll.sh, which is under concurrent
modification in another session.

Refs waired-ai/waired#835

Signed-off-by: gen16k <gen16k@gmail.com>
@gen16k
gen16k force-pushed the feat/835-installer-ordering-flip branch from 352ede3 to 2a08dd7 Compare July 20, 2026 17:34
@gen16k
gen16k merged commit f03cf55 into main Jul 20, 2026
14 checks passed
gen16k added a commit that referenced this pull request Jul 21, 2026
… (waired#835 §9/§11) (#127)

The waired#835 §9/§11 setup executor engine install — the resident
`sudo waired init` attaching a management-API lease and installing the
engine the daemon-path first-run needs — was covered only by unit tests.
No installtest leg exercised it end to end, because the two hands-free
enrol modes the harness uses (`--google-sa-login`, `--bypass-mode`) both
FORCE the standalone enrol path (cmd/waired/main.go gates the daemon path
on `!bypassMode && !googleSALogin && !renewing && daemonReachable`). Since
#119 the installer starts the daemon before `waired init`, so a real fresh
first-run now takes the DAEMON path — the exact path the harness never
drove.

New `--daemon-engine` / `-DaemonEngine` leg (its own mode; Tier 2) on all
three drivers, run nightly as a 3-OS job in installtest-inference.yml:

- Leaves the service RUNNING and installs with the engine ABSENT
  (install.sh/.ps1 keep --skip-ollama), so only the daemon-path executor
  can put an engine on the host.
- Runs `waired init` WITHOUT --google-sa-login (→ daemon path) and with
  --non-interactive (→ awaitBrowserSetup returns at once → the resident
  executor runs ensureDaemonPathEngine), inference on + a tiny pinned model
  so the trailing pull stays cheap.
- Completes the login hands-free by SCRAPING the login-session id from the
  init transcript (the login URL's last path segment) and POSTing the
  host-minted SA id_token to the CP's /v1/login/oidc-grant — which flips
  any waiting session, whatever created it. Scrape, not POST /login/start:
  the #838 writeGuard refuses mgmt writes on the TCP port (they must use
  the local IPC socket / named pipe), and reads dodge it.
- Asserts (via GET /waired/v1/setup/state — a read): the enrol took the
  daemon path, the OIDC completion succeeded, the executor lease went live
  (executor_attached) and claimed the ollama install (install_claimed), an
  engine is present afterward (the regression bar — pre-N3 it stayed
  engine-less forever), the subsystem left no_engine, and no install claim
  is stuck after init (§9-4).

Not asserting setup-progress engine_install=done / setup_state.engine_installed
here: those require a CP-served desired_engine (a browser-wizard / management
write the hands-free harness has no auth for), so that path stays unit-tested;
this leg proves the resident executor installs the engine on the real
daemon-path first-run.

Linux logic lives in the new scripts/dev/lib/installtest-daemon-engine.sh
(kept out of installtest-enroll.sh to avoid churn); macOS/Windows mirror it
inline. Cannot be validated locally (real-CP OIDC + a real engine install +
self-hosted Windows/macOS runners) — needs a nightly workflow_dispatch run.
shellcheck / pwsh-parse / actionlint all clean.

Refs waired-ai/waired#835

Signed-off-by: gen16k <gen16k@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gen16k added a commit that referenced this pull request Aug 1, 2026
…that decides it (#138)

Linux's install.sh ran `waired runtimes install ollama` from inside
linux_apt_install — before the daemon was up, and long before anyone was
asked whether this computer should run models. In the 0.0.2-rc7 install
review the ~1.4 GB engine landed under "AI engine (Ollama)" ahead of
"Sign in and set up", and the browser wizard opened with "Install the AI
software" already done.

macOS and Windows dropped their pre-install in #55/#73; Linux kept its
state-dir one on the assumption that init took the standalone path. #119
made the daemon path the default on all three OSes, #205 fixed the
PATH-only engine_installed probe that was the recorded blocker, and the
standalone path itself has since been deleted — so the carve-out has had
no basis for a while. packaging/install/README.md and docs-site already
described the target behaviour everywhere; only the code disagreed.

`waired init` now owns both the decision and the install on Linux too:
the wizard's executor step (runSetupEngineInstall), or
ensureDaemonPathEngine when no browser is driving. Both install into the
daemon-declared state dir, which is the same
/var/lib/waired/runtimes/ollama/bin/ollama the strict bundled resolver
requires. --skip-ollama / WAIRED_NO_OLLAMA keep working; they now only
tell init to stay out of it.

Also in this change:

* the done banner MEASURES the engine line instead of being told it by an
  earlier step — same three arms and strings as darwin_next_steps
* the pre-install summary lists sign-in first and says the download
  happens only if the operator opts into running models here (mirrored
  into install.ps1's Show-InstallSummary)
* a headless Linux install stops promising "opens your web browser": init
  prints a link there (login_gate.go resolveBrowserGate), so the summary
  says so
* zstd leaves the apt prerequisites. It was installed for the retired
  upstream ollama.com/install.sh; the engine tarball's zstd layer is
  decompressed in-process now (internal/runtime/ollama_install.go)

Hosts that never reach init (--no-init, no terminal, non-systemd) finish
with no engine until the first `sudo waired init` — the same contract as
Windows -SkipInit, and the point of the gate.

Regression cover: two installtest-dash cases assert the "AI engine
(Ollama)" section and the bundled-Ollama install log are absent from a
fresh install, next to positive asserts on the new summary and banner
lines so the negatives cannot pass vacuously.

Fixes #138

Signed-off-by: gen16k <gen16k@gmail.com>
gen16k added a commit that referenced this pull request Aug 1, 2026
…that decides it (#138) (#372)

Linux's install.sh ran `waired runtimes install ollama` from inside
linux_apt_install — before the daemon was up, and long before anyone was
asked whether this computer should run models. In the 0.0.2-rc7 install
review the ~1.4 GB engine landed under "AI engine (Ollama)" ahead of
"Sign in and set up", and the browser wizard opened with "Install the AI
software" already done.

macOS and Windows dropped their pre-install in #55/#73; Linux kept its
state-dir one on the assumption that init took the standalone path. #119
made the daemon path the default on all three OSes, #205 fixed the
PATH-only engine_installed probe that was the recorded blocker, and the
standalone path itself has since been deleted — so the carve-out has had
no basis for a while. packaging/install/README.md and docs-site already
described the target behaviour everywhere; only the code disagreed.

`waired init` now owns both the decision and the install on Linux too:
the wizard's executor step (runSetupEngineInstall), or
ensureDaemonPathEngine when no browser is driving. Both install into the
daemon-declared state dir, which is the same
/var/lib/waired/runtimes/ollama/bin/ollama the strict bundled resolver
requires. --skip-ollama / WAIRED_NO_OLLAMA keep working; they now only
tell init to stay out of it.

Also in this change:

* the done banner MEASURES the engine line instead of being told it by an
  earlier step — same three arms and strings as darwin_next_steps
* the pre-install summary lists sign-in first and says the download
  happens only if the operator opts into running models here (mirrored
  into install.ps1's Show-InstallSummary)
* a headless Linux install stops promising "opens your web browser": init
  prints a link there (login_gate.go resolveBrowserGate), so the summary
  says so
* zstd leaves the apt prerequisites. It was installed for the retired
  upstream ollama.com/install.sh; the engine tarball's zstd layer is
  decompressed in-process now (internal/runtime/ollama_install.go)

Hosts that never reach init (--no-init, no terminal, non-systemd) finish
with no engine until the first `sudo waired init` — the same contract as
Windows -SkipInit, and the point of the gate.

Regression cover: two installtest-dash cases assert the "AI engine
(Ollama)" section and the bundled-Ollama install log are absent from a
fresh install, next to positive asserts on the new summary and banner
lines so the negatives cannot pass vacuously.

Fixes #138

Signed-off-by: gen16k <gen16k@gmail.com>


Verified on a real host by dispatching installtest-inference.yml (os=linux)
against the branch: the done banner reports "installed by sign-in", init then
prints "Installing the AI engine (one-time download)", and the leg still finds
the bundled binary at /var/lib/waired/runtimes/ollama/bin/ollama with the model
ready in the :9475 store. Its one failing assert (benchmark throughput) fails
the same way on main's nightly (#300).
@gen16k
gen16k deleted the feat/835-installer-ordering-flip branch August 3, 2026 19:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant